Commit | Line | Data |
---|---|---|
674e1c56 VS |
1 | // @import types/boxed/*.ck |
2 | // @import types/MalObject.ck | |
3 | // @import types/mal/*.ck | |
4 | // @import util/*.ck | |
5 | // @import reader.ck | |
6 | // @import printer.ck | |
aa0ac94f | 7 | // @import env.ck |
674e1c56 VS |
8 | // @import types/MalSubr.ck |
9 | // @import types/subr/*.ck | |
674e1c56 VS |
10 | // @import core.ck |
11 | // @import func.ck | |
12 | ||
13 | fun MalObject READ(string input) | |
14 | { | |
15 | return Reader.read_str(input); | |
16 | } | |
17 | ||
18 | fun MalObject EVAL(MalObject m, Env env) | |
19 | { | |
20 | if( m.type == "list" ) | |
21 | { | |
22 | if( (m$MalList).value().size() == 0 ) | |
23 | { | |
24 | return m; | |
25 | } | |
26 | ||
27 | (m$MalList).value() @=> MalObject ast[]; | |
28 | ||
29 | if( ast[0].type == "symbol" ) | |
30 | { | |
31 | (ast[0]$MalSymbol).value() => string a0; | |
32 | ||
33 | if( a0 == "def!" ) | |
34 | { | |
35 | (ast[1]$MalSymbol).value() => string a1; | |
36 | ||
37 | EVAL(ast[2], env) @=> MalObject value; | |
38 | if( value.type == "error" ) | |
39 | { | |
40 | return value; | |
41 | } | |
42 | ||
43 | env.set(a1, value); | |
44 | return value; | |
45 | } | |
46 | else if( a0 == "let*" ) | |
47 | { | |
48 | Env.create(env) @=> Env let_env; | |
49 | Util.sequenceToMalObjectArray(ast[1]) @=> MalObject bindings[]; | |
50 | ||
51 | for( 0 => int i; i < bindings.size(); 2 +=> i) | |
52 | { | |
53 | (bindings[i]$MalSymbol).value() => string symbol; | |
54 | EVAL(bindings[i+1], let_env) @=> MalObject value; | |
55 | ||
56 | if( value.type == "error" ) | |
57 | { | |
58 | return value; | |
59 | } | |
60 | ||
61 | let_env.set(symbol, value); | |
62 | } | |
63 | ||
64 | return EVAL(ast[2], let_env); | |
65 | } | |
66 | else if( a0 == "do" ) | |
67 | { | |
68 | MalObject.slice(ast, 1) @=> MalObject forms[]; | |
69 | eval_ast(MalList.create(forms), env) @=> MalObject value; | |
70 | ||
71 | if( value.type == "error" ) | |
72 | { | |
73 | return value; | |
74 | } | |
75 | ||
76 | (value$MalList).value() @=> MalObject values[]; | |
77 | ||
78 | return values[values.size()-1]; | |
79 | } | |
80 | else if( a0 == "if" ) | |
81 | { | |
82 | EVAL(ast[1], env) @=> MalObject condition; | |
83 | ||
84 | if( condition.type == "error" ) | |
85 | { | |
86 | return condition; | |
87 | } | |
88 | ||
89 | if( !(condition.type == "nil") && !(condition.type == "false") ) | |
90 | { | |
91 | return EVAL(ast[2], env); | |
92 | } | |
93 | else | |
94 | { | |
95 | if( ast.size() < 4 ) | |
96 | { | |
f823ec25 | 97 | return Constants.NIL; |
674e1c56 VS |
98 | } |
99 | else | |
100 | { | |
101 | return EVAL(ast[3], env); | |
102 | } | |
103 | } | |
104 | } | |
105 | else if( a0 == "fn*" ) | |
106 | { | |
107 | (ast[1]$MalList).value() @=> MalObject arg_values[]; | |
108 | string args[arg_values.size()]; | |
109 | ||
110 | for( 0 => int i; i < arg_values.size(); i++ ) | |
111 | { | |
112 | (arg_values[i]$MalSymbol).value() => args[i]; | |
113 | } | |
114 | ||
115 | ast[2] @=> MalObject _ast; | |
116 | ||
117 | return Func.create(env, args, _ast); | |
118 | } | |
119 | } | |
120 | ||
121 | eval_ast(m, env) @=> MalObject result; | |
122 | if( result.type == "error" ) | |
123 | { | |
124 | return result; | |
125 | } | |
126 | ||
127 | (result$MalList).value() @=> MalObject values[]; | |
128 | values[0].type => string type; | |
129 | MalObject.slice(values, 1) @=> MalObject args[]; | |
130 | ||
131 | if( type == "subr" ) | |
132 | { | |
133 | values[0]$MalSubr @=> MalSubr subr; | |
134 | return subr.call(args); | |
135 | } | |
136 | else // type == "func" | |
137 | { | |
138 | values[0]$Func @=> Func func; | |
139 | Env.create(func.env, func.args, args) @=> Env eval_env; | |
140 | return EVAL(func.ast, eval_env); | |
141 | } | |
142 | } | |
143 | else | |
144 | { | |
145 | eval_ast(m, env) @=> MalObject result; | |
146 | return result; | |
147 | } | |
148 | } | |
149 | ||
150 | fun MalObject eval_ast(MalObject m, Env env) | |
151 | { | |
152 | m.type => string type; | |
153 | ||
154 | if( type == "symbol" ) | |
155 | { | |
156 | (m$MalSymbol).value() => string symbol; | |
157 | return env.get(symbol); | |
158 | } | |
159 | else if( type == "list" || type == "vector" || type == "hashmap" ) | |
160 | { | |
161 | (m$MalList).value() @=> MalObject values[]; | |
162 | MalObject results[values.size()]; | |
163 | ||
164 | if( type != "hashmap" ) | |
165 | { | |
166 | for( 0 => int i; i < values.size(); i++ ) | |
167 | { | |
168 | EVAL(values[i], env) @=> MalObject result; | |
169 | ||
170 | if( result.type == "error" ) | |
171 | { | |
172 | return result; | |
173 | } | |
174 | ||
175 | result @=> results[i]; | |
176 | } | |
177 | } | |
178 | else | |
179 | { | |
180 | for( 0 => int i; i < values.size(); i++ ) | |
181 | { | |
182 | if( i % 2 == 0 ) | |
183 | { | |
184 | values[i] @=> results[i]; | |
185 | } | |
186 | else | |
187 | { | |
188 | EVAL(values[i], env) @=> results[i]; | |
189 | } | |
190 | } | |
191 | } | |
192 | ||
193 | if( type == "list" ) | |
194 | { | |
195 | return MalList.create(results); | |
196 | } | |
197 | else if( type == "vector" ) | |
198 | { | |
199 | return MalVector.create(results); | |
200 | } | |
201 | else if( type == "hashmap" ) | |
202 | { | |
203 | return MalHashMap.create(results); | |
204 | } | |
205 | } | |
206 | else | |
207 | { | |
208 | return m; | |
209 | } | |
210 | } | |
211 | ||
212 | fun string PRINT(MalObject m) | |
213 | { | |
214 | return Printer.pr_str(m, true); | |
215 | } | |
216 | ||
217 | Env.create(null) @=> Env repl_env; | |
218 | for( 0 => int i; i < Core.names.size(); i++ ) | |
219 | { | |
220 | Core.names[i] => string name; | |
221 | repl_env.set(name, Core.ns[name]); | |
222 | } | |
223 | ||
224 | fun string rep(string input) | |
225 | { | |
226 | READ(input) @=> MalObject m; | |
227 | ||
228 | if( m.type == "error" ) | |
229 | { | |
230 | return Status.toMessage(m$MalError); | |
231 | } | |
232 | ||
233 | EVAL(m, repl_env) @=> MalObject result; | |
234 | if( result.type == "error" ) | |
235 | { | |
236 | return Status.toMessage(result$MalError); | |
237 | } | |
238 | ||
239 | return PRINT(result); | |
240 | } | |
241 | ||
242 | rep("(def! not (fn* (a) (if a false true)))"); | |
243 | ||
244 | fun void main() | |
245 | { | |
246 | ConsoleInput stdin; | |
247 | string input; | |
248 | ||
249 | while( true ) | |
250 | { | |
251 | stdin.prompt("user>") => now; | |
252 | stdin.getLine() => input; | |
253 | rep(input) => string output; | |
254 | ||
255 | if( output == "empty input" ) | |
256 | { | |
257 | // proceed immediately with prompt | |
258 | } | |
259 | else | |
260 | { | |
261 | Util.println(output); | |
262 | } | |
263 | } | |
264 | } | |
265 | ||
266 | main(); |