Ocaml: Add read, print for vector, map
[jackhill/mal.git] / ocaml / step4_if_fn_do.ml
CommitLineData
9115534d
C
1let repl_env = Env.make (Some Core.ns)
2
3let rec eval_ast ast env =
4 match ast with
5 | Types.Symbol s -> Env.get env ast
f2f11f62 6 | Types.List xs -> Types.List (List.map (fun x -> eval x env) xs)
9115534d
C
7 | _ -> ast
8and eval ast env =
9 match ast with
f2f11f62 10 | Types.List [(Types.Symbol "def!"); key; expr] ->
9115534d
C
11 let value = (eval expr env) in
12 Env.set env key value; value
f2f11f62 13 | Types.List [(Types.Symbol "let*"); (Types.List bindings); body] ->
9115534d
C
14 (let sub_env = Env.make (Some env) in
15 let rec bind_pairs = (function
16 | sym :: expr :: more ->
17 Env.set sub_env sym (eval expr sub_env);
18 bind_pairs more
19 | _::[] -> raise (Invalid_argument "let* bindings must be an even number of forms")
20 | [] -> ())
21 in bind_pairs bindings;
22 eval body sub_env)
f2f11f62 23 | Types.List ((Types.Symbol "do") :: body) ->
9115534d 24 List.fold_left (fun x expr -> eval expr env) Types.Nil body
f2f11f62 25 | Types.List [Types.Symbol "if"; test; then_expr; else_expr] ->
9115534d 26 if Types.to_bool (eval test env) then (eval then_expr env) else (eval else_expr env)
f2f11f62 27 | Types.List [Types.Symbol "if"; test; then_expr] ->
9115534d 28 if Types.to_bool (eval test env) then (eval then_expr env) else Types.Nil
f2f11f62 29 | Types.List [Types.Symbol "fn*"; Types.List arg_names; expr] ->
9115534d
C
30 Types.Fn
31 (function args ->
32 let sub_env = Env.make (Some env) in
de04357c 33 let rec bind_args a b =
9115534d 34 (match a, b with
f2f11f62 35 | [Types.Symbol "&"; name], args -> Env.set sub_env name (Types.List args);
9115534d
C
36 | (name :: names), (arg :: args) ->
37 Env.set sub_env name arg;
38 bind_args names args;
39 | [], [] -> ()
de04357c
C
40 | _ -> raise (Invalid_argument "Bad param count in fn call"))
41 in bind_args arg_names args;
9115534d 42 eval expr sub_env)
f2f11f62 43 | Types.List _ ->
9115534d 44 (match eval_ast ast env with
f2f11f62 45 | Types.List ((Types.Fn f) :: args) -> f args
9115534d
C
46 | _ -> raise (Invalid_argument "Cannot invoke non-function"))
47 | _ -> eval_ast ast env
48
49let read str = Reader.read_str str
de04357c 50let print exp = Printer.pr_str exp true
9115534d
C
51let rep str env = print (eval (read str) env)
52
53let rec main =
54 try
55 Core.init Core.ns;
56 ignore (rep "(def! not (fn* (a) (if a false true)))" repl_env);
57 while true do
58 print_string "user> ";
59 let line = read_line () in
60 try
61 print_endline (rep line repl_env);
62 with End_of_file -> ()
63 | Invalid_argument x ->
64 output_string stderr ("Invalid_argument exception: " ^ x ^ "\n");
65 flush stderr
66 done
67 with End_of_file -> ()