diff options
Diffstat (limited to 'modal/ocaml/_build/default/src/parse.ml')
-rw-r--r-- | modal/ocaml/_build/default/src/parse.ml | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/modal/ocaml/_build/default/src/parse.ml b/modal/ocaml/_build/default/src/parse.ml new file mode 100644 index 0000000..a415a80 --- /dev/null +++ b/modal/ocaml/_build/default/src/parse.ml @@ -0,0 +1,50 @@ +(* Minimal s-expression parser for Modal syntax *) + +open Ast + +exception Parse_error of string + +let is_space = function ' ' | '\n' | '\t' | '\r' -> true | _ -> false + +let tokenize s = + let buf = Buffer.create 16 in + let tokens = ref [] in + let flush () = + if Buffer.length buf > 0 then ( + tokens := Buffer.contents buf :: !tokens; + Buffer.clear buf) + in + String.iter + (fun c -> + match c with + | '(' | ')' -> flush (); tokens := (String.make 1 c) :: !tokens + | _ when is_space c -> flush () + | _ -> Buffer.add_char buf c) + s; + flush (); List.rev !tokens + +let parse_tokens tokens = + let rec parse_list i = + match List.nth_opt tokens i with + | Some ")" -> ([], i + 1) + | None -> raise (Parse_error "Unclosed list") + | _ -> + let (node, i') = parse_node i in + let (rest, j) = parse_list i' in + (node :: rest, j) + and parse_node i = + match List.nth_opt tokens i with + | Some "(" -> + let (nodes, j) = parse_list (i + 1) in + (List nodes, j) + | Some ")" -> raise (Parse_error "Unexpected )") + | Some tok -> (Atom tok, i + 1) + | None -> raise (Parse_error "Unexpected end") + in + let (node, i) = parse_node 0 in + if i <> List.length tokens then raise (Parse_error "Trailing tokens"); + node + +let parse s = parse_tokens (tokenize s) + + |