DISABLE FDs (REMOVE ME).
[jackhill/mal.git] / io / step5_tco.io
1 MalTypes
2 MalReader
3
4 READ := method(str, MalReader read_str(str))
5
6 eval_ast := method(ast, env,
7 (ast type) switch(
8 "MalSymbol", env get(ast),
9 "MalList", MalList with(ast map(a, EVAL(a, env))),
10 "MalVector", MalVector with(ast map(a, EVAL(a, env))),
11 "MalMap",
12 m := MalMap clone
13 ast foreach(k, v,
14 keyObj := MalMap keyToObj(k)
15 m atPut(MalMap objToKey(EVAL(keyObj, env)), EVAL(v, env))
16 )
17 m,
18 ast
19 )
20 )
21
22 EVAL := method(ast, env,
23 loop(
24 if(ast type != "MalList", return(eval_ast(ast, env)))
25 if(ast isEmpty, return ast)
26 if(ast at(0) type == "MalSymbol",
27 ast at(0) val switch(
28 "def!",
29 return(env set(ast at(1), EVAL(ast at(2), env))),
30 "do",
31 eval_ast(ast slice(1,-1), env)
32 ast = ast last
33 continue, // TCO
34 "if",
35 ast = if(EVAL(ast at(1), env), ast at(2), ast at(3))
36 continue, // TCO
37 "fn*",
38 return(MalFunc with(ast at(2), ast at(1), env, block(a, EVAL(ast at(2), Env with(env, ast at(1), a))))),
39 "let*",
40 letEnv := Env with(env)
41 varName := nil
42 ast at(1) foreach(i, e,
43 if(i % 2 == 0,
44 varName := e,
45 letEnv set(varName, EVAL(e, letEnv))
46 )
47 )
48 ast = ast at(2)
49 env = letEnv
50 continue // TCO
51 )
52 )
53
54 // Apply
55 el := eval_ast(ast, env)
56 f := el at(0)
57 args := el rest
58 f type switch(
59 "Block",
60 return(f call(args)),
61 "MalFunc",
62 ast = f ast
63 env = Env with(f env, f params, args)
64 continue, // TCO
65 Exception raise("Unknown function type")
66 )
67 )
68 )
69
70 PRINT := method(exp, exp malPrint(true))
71
72 RE := method(str, EVAL(READ(str), repl_env))
73
74 REP := method(str, PRINT(RE(str)))
75
76 repl_env := Env with(nil)
77 MalCore NS foreach(k, v, repl_env set(MalSymbol with(k), v))
78
79 // core.mal: defined using the language itself
80 RE("(def! not (fn* (a) (if a false true)))")
81
82 loop(
83 line := MalReadline readLine("user> ")
84 if(line isNil, break)
85 if(line isEmpty, continue)
86 e := try(REP(line) println)
87 e catch(Exception,
88 if(e type == "MalException",
89 ("Error: " .. ((e val) malPrint(true))) println,
90 ("Error: " .. (e error)) println
91 )
92 )
93 )