Commit | Line | Data |
---|---|---|
a04e7a78 DM |
1 | import .Env; |
2 | import .Printer; | |
3 | import .Reader; | |
4 | import .Readline; | |
5 | import .Types; | |
6 | ||
7 | Val READ(string str) | |
8 | { | |
9 | return read_str(str); | |
10 | } | |
11 | ||
12 | Val eval_ast(Val ast, Env env) | |
13 | { | |
14 | switch(ast.mal_type) | |
15 | { | |
16 | case MALTYPE_SYMBOL: | |
17 | return env.get(ast); | |
18 | case MALTYPE_LIST: | |
19 | return List(map(ast.data, lambda(Val e) { return EVAL(e, env); })); | |
20 | case MALTYPE_VECTOR: | |
21 | return Vector(map(ast.data, lambda(Val e) { return EVAL(e, env); })); | |
22 | case MALTYPE_MAP: | |
23 | array(Val) elements = ({ }); | |
24 | foreach(ast.data; Val k; Val v) | |
25 | { | |
26 | elements += ({ k, EVAL(v, env) }); | |
27 | } | |
28 | return Map(elements); | |
29 | default: | |
30 | return ast; | |
31 | } | |
32 | } | |
33 | ||
34 | Val EVAL(Val ast, Env env) | |
35 | { | |
36 | while(true) | |
37 | { | |
38 | if(ast.mal_type != MALTYPE_LIST) return eval_ast(ast, env); | |
39 | if(ast.emptyp()) return ast; | |
40 | if(ast.data[0].mal_type == MALTYPE_SYMBOL) { | |
41 | switch(ast.data[0].value) | |
42 | { | |
43 | case "def!": | |
44 | return env.set(ast.data[1], EVAL(ast.data[2], env)); | |
45 | case "let*": | |
46 | Env let_env = Env(env); | |
47 | Val ast1 = ast.data[1]; | |
48 | for(int i = 0; i < sizeof(ast1.data); i += 2) | |
49 | { | |
50 | let_env.set(ast1.data[i], EVAL(ast1.data[i + 1], let_env)); | |
51 | } | |
52 | env = let_env; | |
53 | ast = ast.data[2]; | |
54 | continue; // TCO | |
55 | case "do": | |
56 | Val result; | |
57 | foreach(ast.data[1..(sizeof(ast.data) - 2)], Val element) | |
58 | { | |
59 | result = EVAL(element, env); | |
60 | } | |
61 | ast = ast.data[-1]; | |
62 | continue; // TCO | |
63 | case "if": | |
64 | Val cond = EVAL(ast.data[1], env); | |
65 | if(cond.mal_type == MALTYPE_FALSE || cond.mal_type == MALTYPE_NIL) | |
66 | { | |
67 | if(sizeof(ast.data) > 3) | |
68 | ast = ast.data[3]; | |
69 | else | |
70 | return MAL_NIL; | |
71 | } | |
72 | else | |
73 | ast = ast.data[2]; | |
74 | continue; // TCO | |
75 | case "fn*": | |
76 | return Fn(ast.data[2], ast.data[1], env, | |
77 | lambda(Val ... a) { return EVAL(ast.data[2], Env(env, ast.data[1], List(a))); }); | |
78 | } | |
79 | } | |
80 | Val evaled_ast = eval_ast(ast, env); | |
81 | Val f = evaled_ast.data[0]; | |
82 | switch(f.mal_type) | |
83 | { | |
84 | case MALTYPE_BUILTINFN: | |
85 | return f(@evaled_ast.data[1..]); | |
86 | case MALTYPE_FN: | |
87 | ast = f.ast; | |
88 | env = Env(f.env, f.params, List(evaled_ast.data[1..])); | |
89 | continue; // TCO | |
90 | default: | |
91 | throw("Unknown function type"); | |
92 | } | |
93 | } | |
94 | } | |
95 | ||
96 | string PRINT(Val exp) | |
97 | { | |
98 | return pr_str(exp, true); | |
99 | } | |
100 | ||
101 | string rep(string str, Env env) | |
102 | { | |
103 | return PRINT(EVAL(READ(str), env)); | |
104 | } | |
105 | ||
106 | int main() | |
107 | { | |
108 | Env repl_env = Env(0); | |
109 | foreach(.Core.NS(); Val k; Val v) repl_env.set(k, v); | |
110 | rep("(def! not (fn* (a) (if a false true)))", repl_env); | |
111 | while(1) | |
112 | { | |
113 | string line = readline("user> "); | |
114 | if(!line) break; | |
115 | if(strlen(line) == 0) continue; | |
116 | if(mixed err = catch { write(({ rep(line, repl_env), "\n" })); } ) | |
117 | { | |
118 | if(arrayp(err)) err = err[0]; | |
119 | write(({ "Error: ", err, "\n" })); | |
120 | } | |
121 | } | |
122 | write("\n"); | |
123 | return 0; | |
124 | } |