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