ce/main.ml

73 lines
1.9 KiB
OCaml

open Printf
open Eval
let version = "%%VERSION%%"
let debug = ref false
let error_to_string e =
try raise e with
| Lex.Invalid_character (col, c) ->
sprintf "invalid character %c at col %d" c col
| Lex.Expected (col, c) -> sprintf "expected %c at col %d" c col
| Parser.Expected t -> sprintf "expected %s" t
| Parser.Unexpected_token t -> sprintf "unexpected token \"%s\"" t
| Type.Invalid t -> sprintf "invalid type %s" (Type.to_string t)
| Eval.Unbound v -> sprintf "unbound value %s" v
| Eval.Too_many_arguments -> "applied too many arguments"
| 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 stdlib = [
"sin"; "cos"; "tan";
"deg"; "rad";
]
|> List.to_seq
|> Seq.map (fun v -> v, External v)
(* global environment *)
let g =
ref @@ Env.bind_seq stdlib Env.empty
(* read-eval-print *)
let rep env : unit =
printf "> ";
let line = read_line () in
if line = "quit" then raise Exit;
let ast = line |> Lex.tokenize |> Parser.parse in
if !debug then Ast.print ast;
let var, v = Eval.eval_top env ast in
match v with
| Nop -> ()
| _ ->
g := Env.bind ("ans", v) !g;
printf "%s: %s = %s\n"
var (Type.to_string @@ Value.typeof v) (Value.to_string v)
exception Reset_line (* used to indicate ^C is pressed *)
let init_repl () =
g := Env.bind ("ans", Int 0) !g;
(* treat Ctrl-C as to reset line *)
let reset_line _ = raise Reset_line in
Sys.(set_signal sigint (Signal_handle reset_line))
(* simple REPL with error handling *)
let rec repl env : unit =
try rep env; repl env with
| Exit | End_of_file (* Ctrl-D *) -> ()
| Reset_line -> printf "\n"; repl env
| e -> print_error e; repl env
let speclist = [
"--debug", Arg.Set debug, "print debug infos";
]
let () =
Arg.parse speclist (fun _ -> ()) "";
init_repl ();
printf "Configurable Evaluator %s\n" version; (* banner *)
repl g