fsharp: step 4: Added list and comparison functions.
[jackhill/mal.git] / fsharp / eval.fs
CommitLineData
8f1ee487
PS
1module Eval
2
3 open Types
4
5 type Env = Map<string, Node>
6
1e4687b4 7 let errExpected tok = EvalError(sprintf "expected %s" tok)
8f1ee487 8
a836d8f3 9 let iterPairs f (source : seq<_>) =
0756d620
PS
10 use iter = source.GetEnumerator()
11 let rec loop () =
12 if iter.MoveNext() then
13 let first = iter.Current
14 if not (iter.MoveNext()) then raise <| errExpected "even node count"
15 let second = iter.Current
16 f first second
17 loop ()
18 loop ()
19
8f1ee487 20 let rec eval_ast env = function
37bb752e 21 | Symbol(sym) -> Env.get env sym
8f1ee487
PS
22 | List(lst) -> lst |> List.map (eval env) |> List
23 | Vector(arr) -> arr |> Array.map (eval env) |> Vector
24 | Map(map) -> map |> Map.map (fun k v -> eval env v) |> Map
25 | node -> node
26
1e4687b4
PS
27 and defBang env = function
28 | sym::node::[] ->
29 match sym with
37bb752e
PS
30 | Symbol(sym) ->
31 let node = eval env node
32 Env.set env sym node
33 node
1e4687b4
PS
34 | _ -> raise <| errExpected "symbol"
35 | _ -> raise <| Core.errArity ()
36
0756d620
PS
37 and setBinding env first second =
38 let s = match first with
39 | Symbol(s) -> s
40 | _ -> raise <| errExpected "symbol"
41 let form = eval env second
42 Env.set env s form
1e4687b4
PS
43
44 and letStar env = function
45 | bindings::form::[] ->
46 let newEnv = Env.makeNew env
0756d620 47 let binder = setBinding newEnv
1e4687b4 48 match bindings with
a836d8f3
PS
49 | List(lst) -> lst |> iterPairs binder
50 | Vector(vec) -> vec |> iterPairs binder
1e4687b4
PS
51 | _ -> raise <| errExpected "list or vector"
52 eval newEnv form
53 | _ -> raise <| Core.errArity ()
37bb752e 54
8f1ee487 55 and eval env = function
1e4687b4
PS
56 | List(Symbol("def!")::rest) -> defBang env rest
57 | List(Symbol("let*")::rest) -> letStar env rest
8f1ee487
PS
58 | List(_) as node ->
59 let resolved = node |> eval_ast env
60 match resolved with
61 | List(Func({F = f})::rest) -> f rest
1e4687b4 62 | _ -> raise <| errExpected "function"
8f1ee487 63 | node -> node |> eval_ast env