2022-01-11 00:45:25 +09:00
|
|
|
open Printf
|
2022-02-08 00:46:43 +09:00
|
|
|
open Eval
|
2022-01-11 00:45:25 +09:00
|
|
|
|
2022-01-13 00:54:40 +09:00
|
|
|
let version = "%%VERSION%%"
|
2022-02-08 16:05:33 +09:00
|
|
|
let debug = ref false
|
2022-01-13 00:54:40 +09:00
|
|
|
|
2022-01-11 00:45:25 +09:00
|
|
|
let error_to_string e =
|
|
|
|
try raise e with
|
2022-02-12 03:17:26 +09:00
|
|
|
| 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
|
2022-02-17 02:51:56 +09:00
|
|
|
| Parser.Fatal e -> raise e
|
|
|
|
| Parser.End_of_tokens -> "expression ended abruptly"
|
2022-02-15 00:28:29 +09:00
|
|
|
| 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
|
2022-02-08 01:00:31 +09:00
|
|
|
| Type.Invalid t -> sprintf "invalid type %s" (Type.to_string t)
|
|
|
|
| Eval.Unbound v -> sprintf "unbound value %s" v
|
2022-02-01 21:38:00 +09:00
|
|
|
| Eval.Too_many_arguments -> "applied too many arguments"
|
2022-01-13 00:54:40 +09:00
|
|
|
| Failure f -> sprintf "error on %s" f
|
2022-01-11 00:45:25 +09:00
|
|
|
| Division_by_zero -> "cannot divide by zero"
|
|
|
|
| _ -> raise e
|
|
|
|
|
|
|
|
let print_error e =
|
|
|
|
printf "error: %s\n" @@ error_to_string e
|
|
|
|
|
2022-02-01 21:38:00 +09:00
|
|
|
let stdlib = [
|
|
|
|
"sin"; "cos"; "tan";
|
|
|
|
"deg"; "rad";
|
2022-02-20 03:35:11 +09:00
|
|
|
"get_op_pre"; "set_op_pre";
|
|
|
|
"get_op_assoc"; "set_op_assoc";
|
2022-02-01 21:38:00 +09:00
|
|
|
]
|
|
|
|
|> List.to_seq
|
2022-02-08 00:46:43 +09:00
|
|
|
|> Seq.map (fun v -> v, External v)
|
2022-02-01 21:38:00 +09:00
|
|
|
|
2022-02-12 03:18:00 +09:00
|
|
|
(* global environment *)
|
2022-02-01 21:38:00 +09:00
|
|
|
let g =
|
2022-02-12 03:18:00 +09:00
|
|
|
ref @@ Env.bind_seq stdlib Env.empty
|
2022-01-20 01:35:18 +09:00
|
|
|
|
2022-01-13 00:54:40 +09:00
|
|
|
(* read-eval-print *)
|
2022-02-01 02:13:14 +09:00
|
|
|
let rep env : unit =
|
2022-01-11 00:45:25 +09:00
|
|
|
printf "> ";
|
2022-01-10 01:31:47 +09:00
|
|
|
let line = read_line () in
|
2022-01-13 00:54:40 +09:00
|
|
|
if line = "quit" then raise Exit;
|
2022-02-08 16:05:33 +09:00
|
|
|
let ast = line |> Lex.tokenize |> Parser.parse in
|
|
|
|
if !debug then Ast.print ast;
|
2022-02-10 01:37:01 +09:00
|
|
|
let var, v = Eval.eval_top env ast in
|
2022-01-19 14:17:04 +09:00
|
|
|
match v with
|
2022-01-18 16:52:33 +09:00
|
|
|
| Nop -> ()
|
2022-01-19 14:17:04 +09:00
|
|
|
| _ ->
|
2022-02-12 03:18:00 +09:00
|
|
|
g := Env.bind ("ans", v) !g;
|
2022-02-08 01:22:49 +09:00
|
|
|
printf "%s: %s = %s\n"
|
|
|
|
var (Type.to_string @@ Value.typeof v) (Value.to_string v)
|
2022-01-13 00:54:40 +09:00
|
|
|
|
2022-01-28 01:52:57 +09:00
|
|
|
exception Reset_line (* used to indicate ^C is pressed *)
|
|
|
|
|
2022-01-13 00:54:40 +09:00
|
|
|
let init_repl () =
|
2022-02-12 03:18:00 +09:00
|
|
|
g := Env.bind ("ans", Int 0) !g;
|
2022-01-20 01:35:18 +09:00
|
|
|
(* treat Ctrl-C as to reset line *)
|
2022-01-28 01:52:57 +09:00
|
|
|
let reset_line _ = raise Reset_line in
|
|
|
|
Sys.(set_signal sigint (Signal_handle reset_line))
|
2022-01-13 00:54:40 +09:00
|
|
|
|
|
|
|
(* simple REPL with error handling *)
|
2022-02-01 02:13:14 +09:00
|
|
|
let rec repl env : unit =
|
|
|
|
try rep env; repl env with
|
2022-01-28 01:52:57 +09:00
|
|
|
| Exit | End_of_file (* Ctrl-D *) -> ()
|
2022-02-01 02:13:14 +09:00
|
|
|
| Reset_line -> printf "\n"; repl env
|
|
|
|
| e -> print_error e; repl env
|
2022-01-13 00:54:40 +09:00
|
|
|
|
2022-02-11 15:05:21 +09:00
|
|
|
let speclist = [
|
|
|
|
"--debug", Arg.Set debug, "print debug infos";
|
|
|
|
]
|
|
|
|
|
2022-01-13 00:54:40 +09:00
|
|
|
let () =
|
2022-02-11 15:05:21 +09:00
|
|
|
Arg.parse speclist (fun _ -> ()) "";
|
2022-01-13 00:54:40 +09:00
|
|
|
init_repl ();
|
|
|
|
printf "Configurable Evaluator %s\n" version; (* banner *)
|
2022-02-01 02:13:14 +09:00
|
|
|
repl g
|