Alpha equivalence checker for arbitrary lambda terms
7

Configure Feed

Select the types of activity you want to include in your feed.

ego / ocaml / lib / syntax.ml
3.5 kB 125 lines
1type token = 2 | TBackslash 3 | TDot 4 | TLParen 5 | TRParen 6 | TLBrack 7 | TRBrack 8 | TColonEq 9 | TVar of string 10 11exception Parse_error of string 12 13let is_var_start c = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') 14 15let is_var_char c = 16 is_var_start c || (c >= '0' && c <= '9') || c = '_' || c = '\'' || c = '-' 17 18let lex s = 19 let n = String.length s in 20 let rec go i acc = 21 if i >= n then List.rev acc 22 else 23 match s.[i] with 24 | ' ' | '\t' | '\n' | '\r' -> go (i + 1) acc 25 | '\\' -> go (i + 1) (TBackslash :: acc) 26 | '.' -> go (i + 1) (TDot :: acc) 27 | '(' -> go (i + 1) (TLParen :: acc) 28 | ')' -> go (i + 1) (TRParen :: acc) 29 | '[' -> go (i + 1) (TLBrack :: acc) 30 | ']' -> go (i + 1) (TRBrack :: acc) 31 | ':' -> 32 if i + 1 < n && s.[i + 1] = '=' then go (i + 2) (TColonEq :: acc) 33 else raise (Parse_error ("unexpected ':' at position " ^ string_of_int i)) 34 | c when is_var_start c -> 35 let j = ref (i + 1) in 36 while !j < n && is_var_char s.[!j] do 37 incr j 38 done; 39 go !j (TVar (String.sub s i (!j - i)) :: acc) 40 | c -> 41 raise 42 (Parse_error 43 (Printf.sprintf "unexpected character %C at position %d" c i)) 44 in 45 go 0 [] 46 47let parse s = 48 let toks = Array.of_list (lex s) in 49 let n = Array.length toks in 50 let pos = ref 0 in 51 let peek () = if !pos < n then Some toks.(!pos) else None in 52 let next () = 53 let t = peek () in 54 incr pos; 55 t 56 in 57 let expect tok what = 58 match next () with 59 | Some t when t = tok -> () 60 | _ -> raise (Parse_error ("expected " ^ what)) 61 in 62 let starts_atom = function 63 | Some (TVar _) | Some TLParen | Some TBackslash | Some TLBrack -> true 64 | _ -> false 65 in 66 let rec term () = 67 match peek () with 68 | Some TBackslash -> lam () 69 | Some TLBrack -> subst () 70 | _ -> app () 71 and lam () = 72 ignore (next ()); 73 match next () with 74 | Some (TVar v) -> 75 expect TDot "'.'"; 76 let body = term () in 77 Named.Lam (v, body) 78 | _ -> raise (Parse_error "expected variable after '\\'") 79 and subst () = 80 ignore (next ()); 81 match next () with 82 | Some (TVar v) -> 83 expect TColonEq "':='"; 84 let s = term () in 85 expect TRBrack "']'"; 86 let body = term () in 87 Named.Subst (v, s, body) 88 | _ -> raise (Parse_error "expected variable after '['") 89 and app () = 90 let lhs = atom () in 91 let rec args lhs = 92 if starts_atom (peek ()) then args (Named.App (lhs, atom ())) else lhs 93 in 94 args lhs 95 and atom () = 96 match next () with 97 | Some (TVar v) -> Named.Var v 98 | Some TLParen -> 99 let t = term () in 100 expect TRParen "')'"; 101 t 102 | Some TBackslash -> begin 103 match next () with 104 | Some (TVar v) -> 105 expect TDot "'.'"; 106 Named.Lam (v, term ()) 107 | _ -> raise (Parse_error "expected variable after '\\'") 108 end 109 | Some TLBrack -> begin 110 match next () with 111 | Some (TVar v) -> 112 expect TColonEq "':='"; 113 let s = term () in 114 expect TRBrack "']'"; 115 Named.Subst (v, s, term ()) 116 | _ -> raise (Parse_error "expected variable after '['") 117 end 118 | _ -> raise (Parse_error "expected a term") 119 in 120 let t = term () in 121 if !pos <> n then raise (Parse_error "trailing input"); 122 t 123 124let parse_result s = 125 match parse s with t -> Ok t | exception Parse_error m -> Error m