57 lines
1.5 KiB
OCaml
57 lines
1.5 KiB
OCaml
open Printf
|
|
|
|
exception Reset_line (* used to indicate ^C is pressed *)
|
|
|
|
let version = "%%VERSION%%"
|
|
|
|
let error_to_string e =
|
|
try raise e with
|
|
| Lex.Token_not_found -> sprintf "invalid token"
|
|
| Lex.Unclosed_quote -> sprintf "string not closed"
|
|
| Parser.Expected t -> sprintf "expected %s" t
|
|
| Parser.Unexpected_token t -> sprintf "unexpected token \"%s\"" t
|
|
| Ast.Invalid_type t -> sprintf "invalid type %s" (Ast.Type.to_string t)
|
|
| Eval.No_such_variable v -> sprintf "no such variable %s" v
|
|
| Failure f -> sprintf "error on %s" f
|
|
| Division_by_zero -> "cannot divide by zero"
|
|
| _ -> raise e
|
|
|
|
let print_error e =
|
|
printf "error: %s\n" @@ error_to_string e
|
|
|
|
let vars = Hashtbl.create 100
|
|
|
|
(* read-eval-print *)
|
|
let rep vars : unit =
|
|
printf "> ";
|
|
let line = read_line () in
|
|
if line = "quit" then raise Exit;
|
|
let v =
|
|
line
|
|
|> Lex.tokenize
|
|
|> Parser.parse
|
|
|> Eval.eval vars
|
|
in
|
|
match v with
|
|
| Nop -> ()
|
|
| _ ->
|
|
Hashtbl.replace vars "ans" v;
|
|
printf "%s\n" @@ Ast.Value.to_string v
|
|
|
|
let init_repl () =
|
|
Hashtbl.replace vars "ans" (Ast.Value.Int 0);
|
|
(* treat Ctrl-C as to reset line *)
|
|
let sigintf _ = raise Reset_line in
|
|
Sys.(set_signal sigint (Signal_handle sigintf))
|
|
|
|
(* simple REPL with error handling *)
|
|
let rec repl vars : unit =
|
|
try rep vars; repl vars with
|
|
| Exit | End_of_file -> ()
|
|
| Reset_line -> printf "\n"; repl vars
|
|
| e -> print_error e; repl vars
|
|
|
|
let () =
|
|
init_repl ();
|
|
printf "Configurable Evaluator %s\n" version; (* banner *)
|
|
repl vars
|