Commit | Line | Data |
---|---|---|
50eea9ad | 1 | (module $step9_try |
3ea09886 JM |
2 | |
3 | (global $repl_env (mut i32) (i32.const 0)) | |
4 | ||
5 | ;; READ | |
6 | (func $READ (param $str i32) (result i32) | |
7 | ($read_str $str) | |
8 | ) | |
9 | ||
10 | ;; EVAL | |
11 | (func $is_pair (param $ast i32) (result i32) | |
349faa83 | 12 | (LET $type ($TYPE $ast)) |
0a19c2f1 JM |
13 | (AND (OR (i32.eq $type (global.get $LIST_T)) |
14 | (i32.eq $type (global.get $VECTOR_T))) | |
3ea09886 JM |
15 | (i32.ne ($VAL0 $ast) 0)) |
16 | ) | |
17 | ||
18 | (func $QUASIQUOTE (param $ast i32) (result i32) | |
349faa83 | 19 | (LET $res 0 $sym 0 $second 0 $third 0) |
3ea09886 JM |
20 | (if (i32.eqz ($is_pair $ast)) ;; QQ_QUOTE |
21 | (then | |
0a19c2f1 | 22 | (local.set $sym ($STRING (global.get $SYMBOL_T) "quote")) |
3ea09886 | 23 | ;; ['quote ast] |
0a19c2f1 | 24 | (local.set $res ($LIST2 $sym $ast)) |
3ea09886 JM |
25 | ($RELEASE $sym)) |
26 | (else | |
0a19c2f1 JM |
27 | (local.set $res ($MEM_VAL1_ptr $ast)) |
28 | (if (AND (i32.eq ($TYPE $res) (global.get $SYMBOL_T)) | |
3ea09886 JM |
29 | (i32.eqz ($strcmp "unquote" ($to_String $res)))) |
30 | (then | |
31 | ;; ast[1] | |
0a19c2f1 | 32 | (local.set $res ($INC_REF ($MEM_VAL1_ptr ($MEM_VAL0_ptr $ast))))) |
3ea09886 JM |
33 | (else (if (AND ($is_pair $res) |
34 | (i32.eq ($TYPE ($MEM_VAL1_ptr $res)) | |
0a19c2f1 | 35 | (global.get $SYMBOL_T)) |
3ea09886 JM |
36 | (i32.eqz ($strcmp "splice-unquote" |
37 | ($to_String ($MEM_VAL1_ptr $res))))) | |
38 | (then | |
39 | ;; ['concat, ast[0][1], quasiquote(ast[1..])] | |
0a19c2f1 JM |
40 | (local.set $sym ($STRING (global.get $SYMBOL_T) "concat")) |
41 | (local.set $second | |
3ea09886 | 42 | ($MEM_VAL1_ptr ($MEM_VAL0_ptr ($MEM_VAL1_ptr $ast)))) |
0a19c2f1 JM |
43 | (local.set $third ($QUASIQUOTE ($MEM_VAL0_ptr $ast))) |
44 | (local.set $res ($LIST3 $sym $second $third)) | |
3ea09886 JM |
45 | ;; release inner quasiquoted since outer list take ownership |
46 | ($RELEASE $third) | |
47 | ($RELEASE $sym)) | |
48 | (else | |
49 | ;; ['cons, quasiquote(ast[0]), quasiquote(ast[1..])] | |
0a19c2f1 JM |
50 | (local.set $sym ($STRING (global.get $SYMBOL_T) "cons")) |
51 | (local.set $second ($QUASIQUOTE ($MEM_VAL1_ptr $ast))) | |
52 | (local.set $third ($QUASIQUOTE ($MEM_VAL0_ptr $ast))) | |
53 | (local.set $res ($LIST3 $sym $second $third)) | |
3ea09886 JM |
54 | ;; release inner quasiquoted since outer list takes ownership |
55 | ($RELEASE $third) | |
56 | ($RELEASE $second) | |
57 | ($RELEASE $sym))))))) | |
58 | $res | |
59 | ) | |
60 | ||
50eea9ad JM |
61 | (global $mac_stack (mut i32) (i32.const 0)) |
62 | (global $mac_stack_top (mut i32) (i32.const -1)) | |
3ea09886 JM |
63 | |
64 | (func $MACROEXPAND (param $orig_ast i32 $env i32) (result i32) | |
349faa83 JM |
65 | (local $mac_env i64) |
66 | (LET $ast $orig_ast | |
67 | $mac 0) | |
6c4cc8ad | 68 | (global.set $mac_stack (STATIC_ARRAY 2048)) ;; 512 * 4, TODO: move to init |
3ea09886 JM |
69 | (block $done |
70 | (loop $loop | |
349faa83 | 71 | (br_if $done |
0a19c2f1 | 72 | (OR (i32.ne ($TYPE $ast) (global.get $LIST_T)) ;; a list |
349faa83 JM |
73 | (i32.eqz ($VAL0 $ast)) ;; non-empty |
74 | (i32.ne ($TYPE ($MEM_VAL1_ptr $ast)) ;; leading symbol | |
0a19c2f1 JM |
75 | (global.get $SYMBOL_T)))) |
76 | (local.set $mac_env ($ENV_FIND $env ($MEM_VAL1_ptr $ast))) | |
77 | (local.set $mac (i32.wrap_i64 (i64.shr_u $mac_env (i64.const 32)))) | |
78 | (br_if $done (OR (i32.eqz (i32.wrap_i64 $mac_env)) ;; defined in env | |
349faa83 | 79 | (i32.ne ($TYPE $mac) ;; a macro |
0a19c2f1 | 80 | (global.get $MACRO_T)))) |
3ea09886 | 81 | |
0a19c2f1 | 82 | (local.set $ast ($APPLY $mac ($MEM_VAL0_ptr $ast))) |
3ea09886 JM |
83 | ;; PEND_A_LV |
84 | ;; if ast is not the first ast that was passed in, then add it | |
85 | ;; to the pending release list. | |
86 | (if (i32.ne $ast $orig_ast) | |
87 | (then | |
0a19c2f1 JM |
88 | (global.set $mac_stack_top |
89 | (i32.add (global.get $mac_stack_top) 1)) | |
6c4cc8ad | 90 | (if (i32.ge_s (i32.mul (global.get $mac_stack_top) 4) 2048) ;; 512 * 4 |
50eea9ad | 91 | ($fatal 7 "Exhausted mac_stack!\n")) |
3ea09886 | 92 | (i32.store (i32.add |
0a19c2f1 JM |
93 | (global.get $mac_stack) |
94 | (i32.mul (global.get $mac_stack_top) 4)) | |
3ea09886 | 95 | $ast))) |
0a19c2f1 | 96 | (br_if $done (global.get $error_type)) |
3ea09886 | 97 | |
50eea9ad | 98 | (br $loop) |
3ea09886 JM |
99 | ) |
100 | ) | |
101 | $ast | |
102 | ) | |
103 | ||
104 | (func $EVAL_AST (param $ast i32 $env i32 $skiplast i32) (result i32) | |
349faa83 JM |
105 | (LET $res 0 $val2 0 $val3 0 $type 0 $found 0 |
106 | $ret 0 $empty 0 $current 0) | |
3ea09886 | 107 | |
0a19c2f1 JM |
108 | (if (global.get $error_type) (return 0)) |
109 | (local.set $type ($TYPE $ast)) | |
3ea09886 JM |
110 | |
111 | ;;($PR_VALUE ">>> EVAL_AST ast: '%s'\n" $ast) | |
112 | ||
113 | ;;; switch(type) | |
114 | (block $done | |
115 | (block $default (block (block | |
116 | (br_table 2 2 2 2 2 0 1 1 1 2 2 2 2 2 2 2 $type)) | |
117 | ;; symbol | |
118 | ;; found/res returned as hi 32/lo 32 of i64 | |
0a19c2f1 | 119 | (local.set $res ($ENV_GET $env $ast)) |
3ea09886 JM |
120 | (br $done)) |
121 | ;; list, vector, hashmap | |
122 | ;; MAP_LOOP_START | |
0a19c2f1 | 123 | (local.set $res ($MAP_LOOP_START $type)) |
3ea09886 JM |
124 | ;; push MAP_LOOP stack |
125 | ;;; empty = current = ret = res | |
0a19c2f1 JM |
126 | (local.set $ret $res) |
127 | (local.set $current $res) | |
128 | (local.set $empty $res) | |
3ea09886 JM |
129 | |
130 | (block $done | |
131 | (loop $loop | |
132 | ;; check if we are done evaluating the source sequence | |
349faa83 | 133 | (br_if $done (i32.eq ($VAL0 $ast) 0)) |
3ea09886 JM |
134 | |
135 | (if $skiplast | |
77bf4e61 | 136 | (br_if $done (i32.eqz ($VAL0 ($MEM_VAL0_ptr $ast))))) |
3ea09886 | 137 | |
0a19c2f1 | 138 | (if (i32.eq $type (global.get $HASHMAP_T)) |
3ea09886 | 139 | (then |
0a19c2f1 | 140 | (local.set $res ($EVAL ($MEM_VAL2_ptr $ast) $env))) |
3ea09886 | 141 | (else |
0a19c2f1 JM |
142 | (local.set $res ($EVAL ($MEM_VAL1_ptr $ast) $env)))) |
143 | (local.set $val2 $res) | |
3ea09886 JM |
144 | |
145 | ;; if error, release the unattached element | |
0a19c2f1 | 146 | (if (global.get $error_type) |
3ea09886 JM |
147 | (then |
148 | ($RELEASE $res) | |
0a19c2f1 | 149 | (local.set $res 0) |
3ea09886 JM |
150 | (br $done))) |
151 | ||
152 | ;; for hash-maps, copy the key (inc ref since we are going | |
153 | ;; to release it below) | |
0a19c2f1 | 154 | (if (i32.eq $type (global.get $HASHMAP_T)) |
3ea09886 | 155 | (then |
0a19c2f1 JM |
156 | (local.set $val3 $val2) |
157 | (local.set $val2 ($MEM_VAL1_ptr $ast)) | |
3ea09886 JM |
158 | (drop ($INC_REF $val2)))) |
159 | ||
160 | ;; MAP_LOOP_UPDATE | |
0a19c2f1 JM |
161 | (local.set $res ($MAP_LOOP_UPDATE $type $empty $current $val2 $val3)) |
162 | (if (i32.le_u $current (global.get $EMPTY_HASHMAP)) | |
3ea09886 | 163 | ;; if first element, set return to new element |
0a19c2f1 | 164 | (local.set $ret $res)) |
3ea09886 | 165 | ;; update current to point to new element |
0a19c2f1 | 166 | (local.set $current $res) |
3ea09886 | 167 | |
0a19c2f1 | 168 | (local.set $ast ($MEM_VAL0_ptr $ast)) |
3ea09886 JM |
169 | |
170 | (br $loop) | |
171 | ) | |
172 | ) | |
173 | ;; MAP_LOOP_DONE | |
0a19c2f1 | 174 | (local.set $res $ret) |
3ea09886 JM |
175 | ;; EVAL_AST_RETURN: nothing to do |
176 | (br $done)) | |
177 | ;; default | |
0a19c2f1 | 178 | (local.set $res ($INC_REF $ast)) |
3ea09886 JM |
179 | ) |
180 | ||
181 | $res | |
182 | ) | |
183 | ||
184 | (func $MAL_GET_A1 (param $ast i32) (result i32) | |
185 | ($MEM_VAL1_ptr ($MEM_VAL0_ptr $ast))) | |
186 | (func $MAL_GET_A2 (param $ast i32) (result i32) | |
187 | ($MEM_VAL1_ptr ($MEM_VAL0_ptr ($MEM_VAL0_ptr $ast)))) | |
188 | (func $MAL_GET_A3 (param $ast i32) (result i32) | |
189 | ($MEM_VAL1_ptr ($MEM_VAL0_ptr ($MEM_VAL0_ptr ($MEM_VAL0_ptr $ast))))) | |
190 | ||
191 | (func $EVAL (param $orig_ast i32 $orig_env i32) (result i32) | |
349faa83 JM |
192 | (LET $ast $orig_ast |
193 | $env $orig_env | |
0a19c2f1 | 194 | $orig_mac_stack_top (global.get $mac_stack_top) |
349faa83 JM |
195 | $prev_ast 0 $prev_env 0 $res 0 $el 0 |
196 | $ftype 0 $f_args 0 $f 0 $args 0 | |
197 | $a0 0 $a0sym 0 $a1 0 $a2 0 | |
198 | $err 0) | |
3ea09886 JM |
199 | |
200 | (block $EVAL_return | |
201 | (loop $TCO_loop | |
202 | ||
0a19c2f1 JM |
203 | (local.set $f_args 0) |
204 | (local.set $f 0) | |
205 | (local.set $args 0) | |
3ea09886 | 206 | |
0a19c2f1 | 207 | (if (global.get $error_type) |
3ea09886 | 208 | (then |
0a19c2f1 | 209 | (local.set $res 0) |
3ea09886 JM |
210 | (br $EVAL_return))) |
211 | ||
50eea9ad JM |
212 | ;;($PR_VALUE ">>> EVAL ast: '%s'\n" $ast) |
213 | ||
0a19c2f1 | 214 | (if (i32.ne ($TYPE $ast) (global.get $LIST_T)) |
3ea09886 | 215 | (then |
0a19c2f1 | 216 | (local.set $res ($EVAL_AST $ast $env 0)) |
3ea09886 JM |
217 | (br $EVAL_return))) |
218 | ||
219 | ;; APPLY_LIST | |
0a19c2f1 | 220 | (local.set $ast ($MACROEXPAND $ast $env)) |
3ea09886 JM |
221 | ;;($PR_VALUE ">>> >>> EVAL ast: '%s'\n" $ast) |
222 | ||
0a19c2f1 | 223 | (if (i32.ne ($TYPE $ast) (global.get $LIST_T)) |
3ea09886 | 224 | (then |
0a19c2f1 | 225 | (local.set $res ($EVAL_AST $ast $env 0)) |
3ea09886 JM |
226 | (br $EVAL_return))) |
227 | ||
228 | (if ($EMPTY_Q $ast) | |
229 | (then | |
0a19c2f1 | 230 | (local.set $res ($INC_REF $ast)) |
3ea09886 JM |
231 | (br $EVAL_return))) |
232 | ||
0a19c2f1 JM |
233 | (local.set $a0 ($MEM_VAL1_ptr $ast)) |
234 | (local.set $a0sym "") | |
235 | (if (i32.eq ($TYPE $a0) (global.get $SYMBOL_T)) | |
236 | (local.set $a0sym ($to_String $a0))) | |
3ea09886 JM |
237 | |
238 | (if (i32.eqz ($strcmp "def!" $a0sym)) | |
239 | (then | |
0a19c2f1 JM |
240 | (local.set $a1 ($MAL_GET_A1 $ast)) |
241 | (local.set $a2 ($MAL_GET_A2 $ast)) | |
242 | (local.set $res ($EVAL $a2 $env)) | |
243 | (br_if $EVAL_return (global.get $error_type)) | |
3ea09886 JM |
244 | |
245 | ;; set a1 in env to a2 | |
0a19c2f1 | 246 | (local.set $res ($ENV_SET $env $a1 $res)) |
3ea09886 JM |
247 | (br $EVAL_return)) |
248 | (else (if (i32.eqz ($strcmp "let*" $a0sym)) | |
249 | (then | |
0a19c2f1 JM |
250 | (local.set $a1 ($MAL_GET_A1 $ast)) |
251 | (local.set $a2 ($MAL_GET_A2 $ast)) | |
3ea09886 JM |
252 | |
253 | ;; create new environment with outer as current environment | |
0a19c2f1 JM |
254 | (local.set $prev_env $env) ;; save env for later release |
255 | (local.set $env ($ENV_NEW $env)) | |
3ea09886 JM |
256 | |
257 | (block $done | |
258 | (loop $loop | |
349faa83 | 259 | (br_if $done (i32.eqz ($VAL0 $a1))) |
3ea09886 | 260 | ;; eval current A1 odd element |
0a19c2f1 | 261 | (local.set $res ($EVAL ($MEM_VAL1_ptr ($MEM_VAL0_ptr $a1)) $env)) |
3ea09886 | 262 | |
0a19c2f1 | 263 | (br_if $done (global.get $error_type)) |
3ea09886 JM |
264 | |
265 | ;; set key/value in the let environment | |
0a19c2f1 | 266 | (local.set $res ($ENV_SET $env ($MEM_VAL1_ptr $a1) $res)) |
3ea09886 JM |
267 | ;; release our use, ENV_SET took ownership |
268 | ($RELEASE $res) | |
269 | ||
270 | ;; skip to the next pair of a1 elements | |
0a19c2f1 | 271 | (local.set $a1 ($MEM_VAL0_ptr ($MEM_VAL0_ptr $a1))) |
3ea09886 JM |
272 | (br $loop) |
273 | ) | |
274 | ) | |
275 | ||
276 | ;; release previous environment if not the current EVAL env | |
277 | (if (i32.ne $prev_env $orig_env) | |
278 | (then | |
279 | ($RELEASE $prev_env) | |
0a19c2f1 | 280 | (local.set $prev_env 0))) |
3ea09886 | 281 | |
0a19c2f1 | 282 | (local.set $ast $a2) |
3ea09886 JM |
283 | (br $TCO_loop)) |
284 | (else (if (i32.eqz ($strcmp "do" $a0sym)) | |
285 | (then | |
286 | ;; EVAL the rest through second to last | |
0a19c2f1 JM |
287 | (local.set $el ($EVAL_AST ($MEM_VAL0_ptr $ast) $env 1)) |
288 | (local.set $ast ($LAST $ast)) | |
50eea9ad | 289 | ($RELEASE $ast) ;; we already own it via ast |
3ea09886 JM |
290 | ($RELEASE $el) |
291 | (br $TCO_loop)) | |
292 | (else (if (i32.eqz ($strcmp "quote" $a0sym)) | |
293 | (then | |
0a19c2f1 | 294 | (local.set $res ($INC_REF ($MEM_VAL1_ptr ($MEM_VAL0_ptr $ast)))) |
3ea09886 JM |
295 | (br $EVAL_return)) |
296 | (else (if (i32.eqz ($strcmp "quasiquote" $a0sym)) | |
297 | (then | |
0a19c2f1 | 298 | (local.set $ast ($QUASIQUOTE ($MEM_VAL1_ptr ($MEM_VAL0_ptr $ast)))) |
3ea09886 JM |
299 | |
300 | ;; if we have already been here via TCO, release previous ast | |
301 | (if $prev_ast ($RELEASE $prev_ast)) | |
0a19c2f1 | 302 | (local.set $prev_ast $ast) |
3ea09886 JM |
303 | (br $TCO_loop)) |
304 | (else (if (i32.eqz ($strcmp "defmacro!" $a0sym)) | |
305 | (then | |
0a19c2f1 JM |
306 | (local.set $a1 ($MAL_GET_A1 $ast)) |
307 | (local.set $a2 ($MAL_GET_A2 $ast)) | |
308 | (local.set $res ($EVAL $a2 $env)) | |
309 | ($SET_TYPE $res (global.get $MACRO_T)) | |
310 | (br_if $EVAL_return (global.get $error_type)) | |
3ea09886 JM |
311 | |
312 | ;; set a1 in env to a2 | |
0a19c2f1 | 313 | (local.set $res ($ENV_SET $env $a1 $res)) |
3ea09886 JM |
314 | (br $EVAL_return)) |
315 | (else (if (i32.eqz ($strcmp "macroexpand" $a0sym)) | |
316 | (then | |
317 | ;; since we are returning it unevaluated, inc the ref cnt | |
0a19c2f1 | 318 | (local.set $res ($INC_REF ($MACROEXPAND |
3ea09886 JM |
319 | ($MEM_VAL1_ptr ($MEM_VAL0_ptr $ast)) |
320 | $env)))) | |
321 | (else (if (i32.eqz ($strcmp "try*" $a0sym)) | |
322 | (then | |
0a19c2f1 JM |
323 | (local.set $a1 ($MAL_GET_A1 $ast)) |
324 | (local.set $res ($EVAL $a1 $env)) | |
3ea09886 JM |
325 | |
326 | ;; if there is no error, return | |
0a19c2f1 | 327 | (br_if $EVAL_return (i32.eqz (global.get $error_type))) |
3ea09886 | 328 | ;; if there is an error and res is set, we need to free it |
3ea09886 JM |
329 | ($RELEASE $res) |
330 | ;; if there is no catch block then return | |
349faa83 JM |
331 | (br_if $EVAL_return |
332 | (i32.eqz ($VAL0 ($MEM_VAL0_ptr ($MEM_VAL0_ptr $ast))))) | |
3ea09886 JM |
333 | |
334 | ;; save the current environment for release | |
0a19c2f1 | 335 | (local.set $prev_env $env) |
3ea09886 | 336 | ;; create environment for the catch block eval |
0a19c2f1 | 337 | (local.set $env ($ENV_NEW $env)) |
3ea09886 JM |
338 | |
339 | ;; set a1 and a2 from the catch block | |
0a19c2f1 JM |
340 | (local.set $a1 ($MAL_GET_A1 ($MAL_GET_A2 $ast))) |
341 | (local.set $a2 ($MAL_GET_A2 ($MAL_GET_A2 $ast))) | |
3ea09886 JM |
342 | |
343 | ;; create object for string errors | |
0a19c2f1 | 344 | (if (i32.eq (global.get $error_type) 1) |
3ea09886 | 345 | (then |
0a19c2f1 JM |
346 | (local.set $err ($STRING (global.get $STRING_T) |
347 | (global.get $error_str)))) | |
3ea09886 | 348 | (else |
0a19c2f1 | 349 | (local.set $err (global.get $error_val)))) |
3ea09886 JM |
350 | ;; bind the catch symbol to the error object |
351 | (drop ($ENV_SET $env $a1 $err)) | |
352 | ;; release our use, env took ownership | |
353 | ($RELEASE $err) | |
354 | ||
355 | ;; unset error for catch eval | |
0a19c2f1 JM |
356 | (global.set $error_type 0) |
357 | (i32.store (global.get $error_str) (CHR "\x00")) | |
3ea09886 JM |
358 | |
359 | ;; release previous environment if not the current EVAL env | |
360 | (if (i32.ne $prev_env $orig_env) | |
361 | (then | |
362 | ($RELEASE $prev_env) | |
0a19c2f1 | 363 | (local.set $prev_env 0))) |
3ea09886 | 364 | |
0a19c2f1 | 365 | (local.set $ast $a2) |
3ea09886 JM |
366 | (br $TCO_loop)) |
367 | (else (if (i32.eqz ($strcmp "if" $a0sym)) | |
368 | (then | |
0a19c2f1 JM |
369 | (local.set $a1 ($MAL_GET_A1 $ast)) |
370 | (local.set $res ($EVAL $a1 $env)) | |
3ea09886 | 371 | |
0a19c2f1 | 372 | (if (global.get $error_type) |
3ea09886 | 373 | (then (nop)) |
0a19c2f1 JM |
374 | (else (if (OR (i32.eq $res (global.get $NIL)) |
375 | (i32.eq $res (global.get $FALSE))) | |
3ea09886 JM |
376 | (then |
377 | ($RELEASE $res) | |
378 | ;; if no false case (A3), return nil | |
379 | (if (i32.lt_u ($COUNT $ast) 4) | |
380 | (then | |
0a19c2f1 | 381 | (local.set $res ($INC_REF (global.get $NIL))) |
3ea09886 JM |
382 | (br $EVAL_return)) |
383 | (else | |
0a19c2f1 | 384 | (local.set $ast ($MAL_GET_A3 $ast))))) |
3ea09886 JM |
385 | (else |
386 | ($RELEASE $res) | |
0a19c2f1 | 387 | (local.set $ast ($MAL_GET_A2 $ast)))))) |
3ea09886 JM |
388 | (br $TCO_loop)) |
389 | (else (if (i32.eqz ($strcmp "fn*" $a0sym)) | |
390 | (then | |
0a19c2f1 JM |
391 | (local.set $a1 ($MAL_GET_A1 $ast)) |
392 | (local.set $a2 ($MAL_GET_A2 $ast)) | |
393 | (local.set $res ($MALFUNC $a2 $a1 $env)) | |
3ea09886 JM |
394 | (br $EVAL_return)) |
395 | (else | |
396 | ;; EVAL_INVOKE | |
0a19c2f1 JM |
397 | (local.set $res ($EVAL_AST $ast $env 0)) |
398 | (local.set $f_args $res) | |
3ea09886 JM |
399 | |
400 | ;; if error, return f/args for release by caller | |
0a19c2f1 | 401 | (if (global.get $error_type) |
3ea09886 | 402 | (then |
0a19c2f1 | 403 | (local.set $res $f_args) |
3ea09886 JM |
404 | (br $EVAL_return))) |
405 | ||
0a19c2f1 JM |
406 | (local.set $args ($MEM_VAL0_ptr $f_args)) ;; rest |
407 | (local.set $f ($MEM_VAL1_ptr $f_args)) ;; value | |
3ea09886 | 408 | |
0a19c2f1 JM |
409 | (local.set $ftype ($TYPE $f)) |
410 | (if (i32.eq $ftype (global.get $FUNCTION_T)) | |
3ea09886 JM |
411 | (then |
412 | (if (i32.eq ($VAL0 $f) 0) ;; eval | |
413 | (then | |
0a19c2f1 JM |
414 | (local.set $res ($EVAL ($MEM_VAL1_ptr $args) |
415 | (global.get $repl_env)))) | |
3ea09886 | 416 | (else |
0a19c2f1 | 417 | (local.set $res (call_indirect (type $fnT) $args ($VAL0 $f))))) |
3ea09886 JM |
418 | ;; release f/args |
419 | ($RELEASE $f_args) | |
420 | (br $EVAL_return)) | |
0a19c2f1 | 421 | (else (if (i32.eq $ftype (global.get $MALFUNC_T)) |
3ea09886 JM |
422 | (then |
423 | ;; save the current environment for release | |
0a19c2f1 | 424 | (local.set $prev_env $env) |
3ea09886 | 425 | ;; create new environment using env and params stored in function |
0a19c2f1 | 426 | (local.set $env ($ENV_NEW_BINDS ($MEM_VAL2_ptr $f) |
3ea09886 JM |
427 | ($MEM_VAL1_ptr $f) $args)) |
428 | ||
429 | ;; release previous environment if not the current EVAL env | |
430 | ;; because our new env refers to it and we no longer need to | |
431 | ;; track it (since we are TCO recurring) | |
432 | (if (i32.ne $prev_env $orig_env) | |
433 | (then | |
434 | ($RELEASE $prev_env) | |
0a19c2f1 | 435 | (local.set $prev_env 0))) |
3ea09886 JM |
436 | |
437 | ;; claim the AST before releasing the list containing it | |
0a19c2f1 | 438 | (local.set $ast ($MEM_VAL0_ptr $f)) |
3ea09886 JM |
439 | (drop ($INC_REF $ast)) |
440 | ||
441 | ;; if we have already been here via TCO, release previous | |
442 | ;; ast | |
443 | ;; PEND_A_LV | |
444 | (if $prev_ast ($RELEASE $prev_ast)) | |
0a19c2f1 | 445 | (local.set $prev_ast $ast) |
3ea09886 JM |
446 | |
447 | ;; release f/args | |
448 | ($RELEASE $f_args) | |
449 | ||
450 | (br $TCO_loop)) | |
451 | (else | |
452 | ($THROW_STR_1 "apply of non-function type: %d\n" $ftype) | |
0a19c2f1 | 453 | (local.set $res 0) |
3ea09886 JM |
454 | ($RELEASE $f_args) |
455 | (br $EVAL_return))))))))))))))))))))))))) | |
456 | ||
457 | ) ;; end of TCO_loop | |
458 | ) ;; end of EVAL_return | |
459 | ||
460 | ;; EVAL_RETURN | |
461 | (if (i32.ne $env $orig_env) ($RELEASE $env)) | |
462 | (if $prev_ast ($RELEASE $prev_ast)) | |
463 | ||
50eea9ad JM |
464 | ;; release memory from MACROEXPAND |
465 | ;; TODO: needs to happen here so self-hosting doesn't leak | |
466 | (block $done | |
467 | (loop $loop | |
0a19c2f1 | 468 | (br_if $done (i32.le_s (global.get $mac_stack_top) $orig_mac_stack_top)) |
50eea9ad | 469 | ($RELEASE (i32.load (i32.add |
0a19c2f1 JM |
470 | (global.get $mac_stack) |
471 | (i32.mul (global.get $mac_stack_top) 4)))) | |
472 | (global.set $mac_stack_top | |
473 | (i32.sub (global.get $mac_stack_top) 1)) | |
50eea9ad JM |
474 | (br $loop) |
475 | ) | |
476 | ) | |
477 | ||
3ea09886 JM |
478 | $res |
479 | ) | |
480 | ||
481 | ||
482 | (func $PRINT (param $ast i32) (result i32) | |
483 | ($pr_str $ast 1) | |
484 | ) | |
485 | ||
486 | ;; REPL | |
487 | (func $RE (param $line i32 $env i32) (result i32) | |
349faa83 JM |
488 | (LET $mv1 0 $res 0) |
489 | (block $done | |
0a19c2f1 JM |
490 | (local.set $mv1 ($READ $line)) |
491 | (br_if $done (global.get $error_type)) | |
3ea09886 | 492 | |
0a19c2f1 | 493 | (local.set $res ($EVAL $mv1 $env)) |
3ea09886 JM |
494 | ) |
495 | ||
496 | ;; release memory from MAL_READ | |
497 | ($RELEASE $mv1) | |
3ea09886 JM |
498 | $res |
499 | ) | |
500 | ||
501 | (func $REP (param $line i32 $env i32) (result i32) | |
349faa83 JM |
502 | (LET $mv2 0 $ms 0) |
503 | (block $done | |
0a19c2f1 JM |
504 | (local.set $mv2 ($RE $line $env)) |
505 | (br_if $done (global.get $error_type)) | |
3ea09886 JM |
506 | |
507 | ;; ($PR_MEMORY -1 -1) | |
0a19c2f1 | 508 | (local.set $ms ($PRINT $mv2)) |
3ea09886 JM |
509 | ) |
510 | ||
511 | ;; release memory from RE | |
512 | ($RELEASE $mv2) | |
513 | $ms | |
514 | ) | |
515 | ||
516 | (func $main (param $argc i32 $argv i32) (result i32) | |
349faa83 | 517 | (LET $line (STATIC_ARRAY 201) |
dd7a4f55 | 518 | $res 0 $repl_env 0 $ms 0 |
349faa83 | 519 | ;; argument processing |
dd7a4f55 | 520 | $i 0 $ret 0 $empty 0 $current 0 $val2 0) |
3ea09886 JM |
521 | |
522 | ;; DEBUG | |
523 | ;; ($printf_1 "argc: 0x%x\n" $argc) | |
0a19c2f1 JM |
524 | ;; ($printf_1 "memoryBase: 0x%x\n" (global.get $memoryBase)) |
525 | ;; ($printf_1 "heap_start: 0x%x\n" (global.get $heap_start)) | |
526 | ;; ($printf_1 "heap_end: 0x%x\n" (global.get $heap_end)) | |
527 | ;; ($printf_1 "mem: 0x%x\n" (global.get $mem)) | |
528 | ;; ($printf_1 "string_mem: %d\n" (global.get $string_mem)) | |
3ea09886 | 529 | |
0a19c2f1 JM |
530 | (global.set $repl_env ($ENV_NEW (global.get $NIL))) |
531 | (local.set $repl_env (global.get $repl_env)) | |
3ea09886 JM |
532 | |
533 | ;; core.EXT: defined in wasm | |
534 | ($add_core_ns $repl_env) | |
535 | (drop ($ENV_SET_S $repl_env "eval" ($FUNCTION 0))) | |
536 | ||
50eea9ad | 537 | ($checkpoint_user_memory) |
3ea09886 JM |
538 | |
539 | ;; core.mal: defined using the language itself | |
540 | ($RELEASE ($RE "(def! not (fn* (a) (if a false true)))" $repl_env)) | |
e6d41de4 | 541 | ($RELEASE ($RE "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))" $repl_env)) |
3ea09886 | 542 | ($RELEASE ($RE "(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))" $repl_env)) |
3ea09886 JM |
543 | |
544 | ||
545 | ;; Command line arguments | |
0a19c2f1 | 546 | (local.set $res ($MAP_LOOP_START (global.get $LIST_T))) |
3ea09886 JM |
547 | ;; push MAP_LOP stack |
548 | ;; empty = current = ret = res | |
0a19c2f1 JM |
549 | (local.set $ret $res) |
550 | (local.set $current $res) | |
551 | (local.set $empty $res) | |
3ea09886 | 552 | |
0a19c2f1 | 553 | (local.set $i 2) |
3ea09886 JM |
554 | (block $done |
555 | (loop $loop | |
349faa83 | 556 | (br_if $done (i32.ge_u $i $argc)) |
3ea09886 | 557 | |
0a19c2f1 | 558 | (local.set $val2 ($STRING (global.get $STRING_T) |
0c62f14e | 559 | (i32.load (i32.add $argv (i32.mul $i 4))))) |
3ea09886 JM |
560 | |
561 | ;; MAP_LOOP_UPDATE | |
0a19c2f1 JM |
562 | (local.set $res ($MAP_LOOP_UPDATE |
563 | (global.get $LIST_T) $empty $current $val2 0)) | |
564 | (if (i32.le_u $current (global.get $EMPTY_HASHMAP)) | |
3ea09886 | 565 | ;; if first element, set return to new element |
0a19c2f1 | 566 | (local.set $ret $res)) |
3ea09886 | 567 | ;; update current to point to new element |
0a19c2f1 | 568 | (local.set $current $res) |
3ea09886 | 569 | |
0a19c2f1 | 570 | (local.set $i (i32.add $i 1)) |
3ea09886 JM |
571 | (br $loop) |
572 | ) | |
573 | ) | |
574 | (drop ($ENV_SET_S $repl_env "*ARGV*" $ret)) | |
575 | ||
576 | ||
577 | ;;($PR_MEMORY -1 -1) | |
578 | ||
579 | (if (i32.gt_u $argc 1) | |
580 | (then | |
581 | (drop ($ENV_SET_S $repl_env | |
0a19c2f1 | 582 | "*FILE*" ($STRING (global.get $STRING_T) |
3ea09886 JM |
583 | (i32.load (i32.add $argv 4))))) |
584 | ($RELEASE ($RE "(load-file *FILE*)" $repl_env)) | |
0a19c2f1 | 585 | (if (global.get $error_type) |
3ea09886 | 586 | (then |
0a19c2f1 | 587 | ($printf_1 "Error: %s\n" (global.get $error_str)) |
3ea09886 JM |
588 | (return 1)) |
589 | (else | |
590 | (return 0))))) | |
591 | ||
592 | ;; Start REPL | |
593 | (block $repl_done | |
594 | (loop $repl_loop | |
50eea9ad JM |
595 | (br_if $repl_done (i32.eqz ($readline "user> " $line))) |
596 | (br_if $repl_loop (i32.eq (i32.load8_u $line) 0)) | |
0a19c2f1 JM |
597 | (local.set $res ($REP $line $repl_env)) |
598 | (if (global.get $error_type) | |
3ea09886 | 599 | (then |
0a19c2f1 | 600 | (if (i32.eq 2 (global.get $error_type)) |
dd7a4f55 | 601 | (then |
0a19c2f1 | 602 | (local.set $ms ($pr_str (global.get $error_val) 1)) |
dd7a4f55 JM |
603 | ($printf_1 "Error: %s\n" ($to_String $ms)) |
604 | ($RELEASE $ms) | |
0a19c2f1 | 605 | ($RELEASE (global.get $error_val))) |
dd7a4f55 | 606 | (else |
0a19c2f1 JM |
607 | ($printf_1 "Error: %s\n" (global.get $error_str)))) |
608 | (global.set $error_type 0)) | |
3ea09886 JM |
609 | (else |
610 | ($printf_1 "%s\n" ($to_String $res)))) | |
611 | ($RELEASE $res) | |
50eea9ad JM |
612 | ;;($PR_MEMORY_SUMMARY_SMALL) |
613 | (br $repl_loop) | |
614 | ) | |
615 | ) | |
3ea09886 JM |
616 | |
617 | ($print "\n") | |
618 | ;;($PR_MEMORY -1 -1) | |
619 | 0 | |
620 | ) | |
621 | ||
3ea09886 JM |
622 | ) |
623 |