DISABLE FDs (REMOVE ME).
[jackhill/mal.git] / wasm / step9_try.wam
CommitLineData
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 ;; PRINT
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