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.Fatal e -> raise e | Parser.End_of_tokens -> "expression ended abruptly" | Parser.Expected (col, t) -> sprintf "expected %s at col %d" t col | Parser.Unexpected_token (col, t) -> sprintf "unexpected token \"%s\" at col %d" t col | Type.Invalid t -> sprintf "invalid type %s" (Type.to_string t) | Eval.Unbound v -> sprintf "unbound value %s" v | Eval.No_such_method (m, t) -> sprintf "no such method %s matching type %s" m (Type.to_string t) | 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"; "get_op_pre"; "set_op_pre"; "get_op_assoc"; "set_op_assoc"; "print"; "println"; ] |> List.to_seq |> Seq.map (fun v -> v, External v) (* global environment *) let g = let g = Hashtbl.create 100 in Hashtbl.add_seq g stdlib; g (* read-eval-print *) let rep () : 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 g ast in Hashtbl.replace g "ans" v; 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 () = (* 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 () : unit = try rep (); repl () with | Exit | End_of_file (* Ctrl-D *) -> () | Noop -> repl () | Reset_line -> printf "\n"; repl () | e -> print_error e; repl () let speclist = [ "--debug", Arg.Set debug, "print debug infos"; ] let () = Arg.parse speclist (fun _ -> ()) ""; init_repl (); printf "Configurable Evaluator %s\n" version; (* banner *) repl ()