From 765ac6f004e8ca7d76d95add109e44acf8b96398 Mon Sep 17 00:00:00 2001 From: Hyeonung Baek Date: Tue, 1 Feb 2022 02:13:14 +0900 Subject: [PATCH] Add Env module --- env.ml | 33 +++++++++++++++++++++++++++++++++ eval.ml | 6 +++--- main.ml | 20 ++++++++++---------- 3 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 env.ml diff --git a/env.ml b/env.ml new file mode 100644 index 0000000..b86cfae --- /dev/null +++ b/env.ml @@ -0,0 +1,33 @@ +module Value = Ast.Value + +type t = { + vars : (string, Value.t) Hashtbl.t; + parent : t option; +} + +let init_global () = { + vars = Hashtbl.create 100; + parent = None; +} + +let make parent = { + vars = Hashtbl.create 100; + parent = Some parent; +} + +exception Not_found + +let rec get e name = + match Hashtbl.find_opt e.vars name with + | None -> begin match e.parent with + | None -> raise Not_found + | Some p -> get p name + end + | Some value -> value + +let get_opt e name = + try Some (get e name) + with Not_found -> None + +let set e name value = + Hashtbl.replace e.vars name value diff --git a/eval.ml b/eval.ml index 10347e5..db51bab 100644 --- a/eval.ml +++ b/eval.ml @@ -57,10 +57,10 @@ let apply f args = | "rad", [n] -> floatfun rad n | _ -> raise @@ No_such_function f -let eval vars ast = +let eval env ast = let rec aux = function | Value v -> v - | Var v -> begin match Hashtbl.find_opt vars v with + | Var v -> begin match Env.get_opt env v with | None -> raise @@ No_such_variable v | Some v -> v end @@ -73,7 +73,7 @@ let eval vars ast = binop op l r | Let (var, e) -> let v = aux e in - Hashtbl.replace vars var v; + Env.set env var v; v | Apply (v, args) -> let args = List.map aux args in diff --git a/main.ml b/main.ml index 6b2f113..10f0498 100644 --- a/main.ml +++ b/main.ml @@ -18,10 +18,10 @@ let error_to_string e = let print_error e = printf "error: %s\n" @@ error_to_string e -let vars = Hashtbl.create 100 +let g = Env.init_global () (* read-eval-print *) -let rep vars : unit = +let rep env : unit = printf "> "; let line = read_line () in if line = "quit" then raise Exit; @@ -29,30 +29,30 @@ let rep vars : unit = line |> Lex.tokenize |> Parser.parse - |> Eval.eval vars + |> Eval.eval env in match v with | Nop -> () | _ -> - Hashtbl.replace vars "ans" v; + Env.set env "ans" v; printf "%s\n" @@ Ast.Value.to_string v exception Reset_line (* used to indicate ^C is pressed *) let init_repl () = - Hashtbl.replace vars "ans" (Ast.Value.Int 0); + Env.set g "ans" (Ast.Value.Int 0); (* 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 vars : unit = - try rep vars; repl vars with +let rec repl env : unit = + try rep env; repl env with | Exit | End_of_file (* Ctrl-D *) -> () - | Reset_line -> printf "\n"; repl vars - | e -> print_error e; repl vars + | Reset_line -> printf "\n"; repl env + | e -> print_error e; repl env let () = init_repl (); printf "Configurable Evaluator %s\n" version; (* banner *) - repl vars + repl g