wasm: Convert to wam syntax using wamp.
authorJoel Martin <github@martintribe.org>
Sun, 14 Oct 2018 04:10:28 +0000 (23:10 -0500)
committerJoel Martin <github@martintribe.org>
Sat, 8 Dec 2018 23:02:09 +0000 (17:02 -0600)
- Convert sources to much more concise wam syntax supported by wamp.
- Rename sources from *.wast to *.wam and generate *.wast files by
  translating via wamp.

24 files changed:
.gitignore
wasm/Makefile
wasm/debug.wam [new file with mode: 0644]
wasm/debug.wast [deleted file]
wasm/env.wam [new file with mode: 0644]
wasm/env.wast [deleted file]
wasm/mem.wam [new file with mode: 0644]
wasm/mem.wast [deleted file]
wasm/printer.wam [new file with mode: 0644]
wasm/printer.wast [deleted file]
wasm/reader.wam [new file with mode: 0644]
wasm/reader.wast [deleted file]
wasm/step0_repl.wam [moved from wasm/step0_repl.wast with 52% similarity]
wasm/step1_read_print.wam [new file with mode: 0644]
wasm/step1_read_print.wast [deleted file]
wasm/step2_eval.wam [new file with mode: 0644]
wasm/step2_eval.wast [deleted file]
wasm/step3_env.wam [new file with mode: 0644]
wasm/step3_env.wast [deleted file]
wasm/types.wam [new file with mode: 0644]
wasm/types.wast [deleted file]
wasm/util.wam [new file with mode: 0644]
wasm/util.wast [deleted file]
wasm/wastpp.py [deleted file]

index d5c41ff..aa4aa49 100644 (file)
@@ -144,5 +144,5 @@ elm/elm-stuff
 elm/*.js
 !elm/node_readline.js
 !elm/bootstrap.js
-wasm/*.wat
+wasm/*.wast
 wasm/*.wasm
dissimilarity index 61%
index 46650e4..aeac222 100644 (file)
@@ -1,24 +1,24 @@
-STEP0_DEPS = util.wast
-STEP1_DEPS = $(STEP0_DEPS) types.wast mem.wast debug.wast reader.wast printer.wast
-STEP2_DEPS = $(STEP1_DEPS)
-STEP3_DEPS = $(STEP2_DEPS) env.wast
-
-STEPS = step0_repl step1_read_print step2_eval step3_env \
-        step4_if_fn_do step5_tco step6_file step7_quote \
-        step8_macros step9_try stepA_mal
-
-all: $(foreach s,$(STEPS),$(s).wasm)
-
-%.wasm:
-       ./wastpp.py $^ > $*.wat
-       wasm-as $*.wat -o $@
-
-step0_repl.wasm: $(STEP0_DEPS) step0_repl.wast
-step1_read_print.wasm: $(STEP1_DEPS) step1_read_print.wast
-step2_eval.wasm: $(STEP2_DEPS) step2_eval.wast
-step3_env.wasm: $(STEP3_DEPS) step3_env.wast
-
-.PHONY: clean
-
-clean:
-       rm -f *.wat *.wasm
+STEP0_DEPS = util.wam
+STEP1_DEPS = $(STEP0_DEPS) types.wam mem.wam debug.wam reader.wam printer.wam
+STEP2_DEPS = $(STEP1_DEPS)
+STEP3_DEPS = $(STEP2_DEPS) env.wam
+
+STEPS = step0_repl step1_read_print step2_eval step3_env \
+        step4_if_fn_do step5_tco step6_file step7_quote \
+        step8_macros step9_try stepA_mal
+
+all: $(foreach s,$(STEPS),$(s).wasm)
+
+%.wasm:
+       wamp $^ > $*.wast
+       wasm-as $*.wast -o $@
+
+step0_repl.wasm: $(STEP0_DEPS) step0_repl.wam
+step1_read_print.wasm: $(STEP1_DEPS) step1_read_print.wam
+step2_eval.wasm: $(STEP2_DEPS) step2_eval.wam
+step3_env.wasm: $(STEP3_DEPS) step3_env.wam
+
+.PHONY: clean
+
+clean:
+       rm -f *.wast *.wasm
diff --git a/wasm/debug.wam b/wasm/debug.wam
new file mode 100644 (file)
index 0000000..7eb0795
--- /dev/null
@@ -0,0 +1,186 @@
+(module $debug
+
+  (func $PR_VALUE (param $fmt i32) (param $mv i32)
+    (local $temp i32)
+    (set_local $temp ($pr_str $mv))
+    ($printf_1 $fmt ($to_String $temp))
+    ($RELEASE $temp)
+  )
+
+  (func $PR_MEMORY_VALUE (param $idx i32) (result i32)
+    (local $mv i32)
+    (local $type i32)
+    (local $size i32)
+    (local $val0 i32)
+    ;;; mv = mem + idx
+    (set_local $mv ($MalVal_ptr $idx))
+    (set_local $type ($TYPE $mv))
+    (set_local $size ($MalVal_size $mv))
+    (set_local $val0 ($MalVal_val $idx 0))
+
+    ;;; printf(" %3d: type: %2d", idx, type)
+    ($printf_2 " 0x%x: type: %d" $idx $type)
+
+    (if (i32.eq $type 15)
+      (then
+        ;;; printf(", size: %2d", size)
+        ($printf_1 ", size: %d" $size))
+      (else
+        ;;;  printf(", refs: %2d", (mv->refcnt_type - type)>>5)
+        ($printf_1 ", refs: %d" ($REFS $mv))))
+
+    ;;; printf(", [ %3d | %3d", mv->refcnt_type, val0)
+    ($printf_2 ", [ 0x%x | 0x%x" ($MalVal_refcnt_type $idx) $val0)
+
+    (if (i32.eq $size 2)
+      (then
+        ($print " | --- | --- ]"))
+      (else
+        ;;; printf(" | %3d", mv->val[1])
+        ($printf_1 " | 0x%x" ($MalVal_val $idx 1))
+        (if (i32.eq $size 3)
+          (then
+            ($print " | --- ]"))
+          (else
+            ;;; printf(" | %3d ]", mv->val[2])
+            ($printf_1 " | 0x%x ]" ($MalVal_val $idx 2))))))
+
+    ;;; printf(" >> ")
+    ($print " >> ")
+
+    (block $done (block $unknown
+      (block (block (block (block (block (block (block (block
+      (block (block (block (block (block (block (block (block
+        (br_table 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+                  $unknown $type))
+      ;; 0: nil
+      ($print "nil")
+      (br $done))
+      ;; 1: boolean
+      (if (i32.eq $val0 0)
+        ;; true
+        ($print "false")
+        ;; false
+        ($print "true"))
+      (br $done))
+      ;; 2: integer
+      ($printf_1 "%d" $val0)
+      (br $done))
+      ;; 3: float/ERROR
+      ($print " *** GOT FLOAT *** ")
+      (br $done))
+      ;; 4: string/kw
+      ($printf_1 "'%s'" ($to_String $mv))
+      (br $done))
+      ;; 5: symbol
+      ($print ($to_String $mv))
+      (br $done))
+      ;; 6: list
+      (if (i32.le_u $mv (get_global $EMPTY_HASHMAP))
+        (then
+          ($print "()"))
+        (else
+          ;;; printf("(... %d ...), next: %d\n", mv->val[1], mv->val[0])
+          ($printf_2 "(... 0x%x ...), next: 0x%x"
+                     ($MalVal_val $idx 1)
+                     ($MalVal_val $idx 0))))
+      (br $done))
+      ;; 7: vector
+      (if (i32.le_u $mv (get_global $EMPTY_HASHMAP))
+        (then
+          ($print "[]"))
+        (else
+          ;;; printf("[... %d ...], next: %d\n", mv->val[1], mv->val[0])val
+          ($printf_2 "[... %d ...], next: %d"
+                     ($MalVal_val $idx 1)
+                     ($MalVal_val $idx 0))))
+      (br $done))
+      ;; 8: hashmap
+      (if (i32.le_u $mv (get_global $EMPTY_HASHMAP))
+        (then
+          ($print "{}"))
+        (else
+          ;;; printf("{... '%s'(%d) : %d ...}\n",
+          ;;         to_String(mem + mv->val[1]), mv->val[1], mv->val[2])
+          ($printf_3 "{... '%s'(%d) : %d ...}"
+                     ($to_String ($MalVal_ptr ($MalVal_val $idx 1)))
+                     ($MalVal_val $idx 1)
+                     ($MalVal_val $idx 2))))
+      (br $done))
+      ;; 9: function
+      ($print "function")
+      (br $done))
+      ;; 10: mal function
+      ($print "mal function")
+      (br $done))
+      ;; 11: macro fn
+      ($print "macro fn")
+      (br $done))
+      ;; 12: atom
+      ($print "atom")
+      (br $done))
+      ;; 13: environment
+      ($print "environment")
+      (br $done))
+      ;; 14: metadata
+      ($print "metadata")
+      (br $done))
+      ;; 15: FREE
+      ($printf_1 "FREE next: 0x%x" $val0)
+      (if (i32.eq $idx (get_global $mem_free_list))
+        ($print " (free start)"))
+      (if (i32.eq $val0 (get_global $mem_unused_start))
+        ($print " (free end)"))
+      (br $done))
+      ;; 16: unknown
+      ($print "unknown")
+    )
+
+    (drop ($putchar 0xA))
+
+    (i32.add $size $idx)
+  )
+
+  (func $PR_MEMORY (param $start i32) (param $end i32)
+    (local $idx i32)
+    (if (i32.lt_s $start 0)
+      (set_local $start (get_global $mem_user_start)))
+    (if (i32.lt_s $end 0)
+      (set_local $end (get_global $mem_unused_start)))
+    ;;; printf("Values - (mem) showing %d -> %d", start, end)
+    ;;; printf(" (unused start: %d, free list: %d):\n",
+    ;;;        mem_unused_start, mem_free_list)
+    ($printf_4 "Values - (mem) showing 0x%x -> 0x%x (unused start: 0x%x, free list: 0x%x):\n"
+          $start
+          $end
+          (get_global $mem_unused_start)
+          (get_global $mem_free_list))
+
+    (if (i32.le_s $end $start)
+      (then
+        ($print "  ---\n")
+        (set_local $end (get_global $mem_unused_start)))
+      (else
+        (set_local $idx $start)
+        ;;; while (idx < end)
+        (block $loopvals_exit
+          (loop $loopvals
+            (if (i32.ge_s $idx $end)
+              (br $loopvals_exit))
+            (set_local $idx ($PR_MEMORY_VALUE $idx))
+            (br $loopvals)
+          )
+        )))
+  )
+
+  (func $PR_MEMORY_RAW (param $start i32) (param $end i32)
+    (block $loop_exit
+      (loop $loop
+        (if (i32.ge_u $start $end) (br $loop_exit))
+        ($printf_2 "0x%x 0x%x\n" $start (i32.load $start))
+        (set_local $start (i32.add 4 $start))
+        (br $loop)
+      )
+    )
+  )
+)
diff --git a/wasm/debug.wast b/wasm/debug.wast
deleted file mode 100644 (file)
index 18e5fa1..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-(module $debug
-
-  (func $PR_VALUE (param $fmt i32) (param $mv i32)
-    (local $temp i32)
-    (set_local $temp (call $pr_str (get_local $mv)))
-    (call $printf_1 (get_local $fmt) (call $to_String (get_local $temp)))
-    (call $RELEASE (get_local $temp))
-  )
-
-  (func $PR_MEMORY_VALUE (param $idx i32) (result i32)
-    (local $mv i32)
-    (local $type i32)
-    (local $size i32)
-    (local $val0 i32)
-    ;;; mv = mem + idx
-    (set_local $mv (call $MalVal_ptr (get_local $idx)))
-    (set_local $type (call $TYPE (get_local $mv)))
-    (set_local $size (call $MalVal_size (get_local $mv)))
-    (set_local $val0 (call $MalVal_val (get_local $idx) (i32.const 0)))
-
-    ;;; printf(" %3d: type: %2d", idx, type)
-    (call $printf_2 (STRING " 0x%x: type: %d")
-          (get_local $idx) (get_local $type))
-
-    (if (i32.eq (get_local $type) (i32.const 15))
-      (then
-        ;;; printf(", size: %2d", size)
-        (call $printf_1 (STRING ", size: %d") (get_local $size)))
-      (else
-        ;;;  printf(", refs: %2d", (mv->refcnt_type - type)>>5)
-        (call $printf_1 (STRING ", refs: %d") (call $REFS (get_local $mv)))))
-
-    ;;; printf(", [ %3d | %3d", mv->refcnt_type, val0)
-    (call $printf_2 (STRING ", [ 0x%x | 0x%x")
-          (call $MalVal_refcnt_type (get_local $idx))
-          (get_local $val0))
-
-    (if (i32.eq (get_local $size) (i32.const 2))
-      (then
-        (call $print (STRING " | --- | --- ]")))
-      (else
-        ;;; printf(" | %3d", mv->val[1])
-        (call $printf_1 (STRING " | 0x%x")
-              (call $MalVal_val (get_local $idx) (i32.const 1)))
-        (if (i32.eq (get_local $size) (i32.const 3))
-          (then
-            (call $print (STRING " | --- ]")))
-          (else
-            ;;; printf(" | %3d ]", mv->val[2])
-            (call $printf_1 (STRING " | 0x%x ]")
-                  (call $MalVal_val (get_local $idx) (i32.const 2)))))))
-
-    ;;; printf(" >> ")
-    (call $print (STRING " >> "))
-
-    (block $done (block $unknown
-    (block (block (block (block (block (block (block (block
-    (block (block (block (block (block (block (block (block
-      (br_table 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 $unknown (get_local $type)))
-    ;; 0: nil
-    (call $print (STRING "nil"))
-    (br $done))
-    ;; 1: boolean
-    (if (i32.eq (get_local $val0) (i32.const 0))
-      ;; true
-      (call $print (STRING "false"))
-      ;; false
-      (call $print (STRING "true")))
-    (br $done))
-    ;; 2: integer
-    (call $printf_1 (STRING "%d") (get_local $val0))
-    (br $done))
-    ;; 3: float/ERROR
-    (call $print (STRING " *** GOT FLOAT *** "))
-    (br $done))
-    ;; 4: string/kw
-    (call $printf_1 (STRING "'%s'") (call $to_String (get_local $mv)))
-    (br $done))
-    ;; 5: symbol
-    (call $print (call $to_String (get_local $mv)))
-    (br $done))
-    ;; 6: list
-    (if (i32.le_u (get_local $mv) (get_global $EMPTY_HASHMAP))
-      (then
-        (call $print (STRING "()")))
-      (else
-        ;;; printf("(... %d ...), next: %d\n", mv->val[1], mv->val[0])
-        (call $printf_2 (STRING "(... 0x%x ...), next: 0x%x")
-              (call $MalVal_val (get_local $idx) (i32.const 1))
-              (call $MalVal_val (get_local $idx) (i32.const 0)))))
-    (br $done))
-    ;; 7: vector
-    (if (i32.le_u (get_local $mv) (get_global $EMPTY_HASHMAP))
-      (then
-        (call $print (STRING "[]")))
-      (else
-        ;;; printf("[... %d ...], next: %d\n", mv->val[1], mv->val[0])val
-        (call $printf_2 (STRING "[... %d ...], next: %d")
-              (call $MalVal_val (get_local $idx) (i32.const 1))
-              (call $MalVal_val (get_local $idx) (i32.const 0)))))
-    (br $done))
-    ;; 8: hashmap
-    (if (i32.le_u (get_local $mv) (get_global $EMPTY_HASHMAP))
-      (then
-        (call $print (STRING "{}")))
-      (else
-        ;;; printf("{... '%s'(%d) : %d ...}\n",
-        ;;         to_String(mem + mv->val[1]), mv->val[1], mv->val[2])
-        (call $printf_3 (STRING "{... '%s'(%d) : %d ...}")
-              (call $to_String
-                    (call $MalVal_ptr
-                          (call $MalVal_val (get_local $idx) (i32.const 1))))
-              (call $MalVal_val (get_local $idx) (i32.const 1))
-              (call $MalVal_val (get_local $idx) (i32.const 2)))))
-    (br $done))
-    ;; 9: function
-    (call $print (STRING "function"))
-    (br $done))
-    ;; 10: mal function
-    (call $print (STRING "mal function"))
-    (br $done))
-    ;; 11: macro fn
-    (call $print (STRING "macro fn"))
-    (br $done))
-    ;; 12: atom
-    (call $print (STRING "atom"))
-    (br $done))
-    ;; 13: environment
-    (call $print (STRING "environment"))
-    (br $done))
-    ;; 14: metadata
-    (call $print (STRING "metadata"))
-    (br $done))
-    ;; 15: FREE
-    (call $printf_1 (STRING "FREE next: 0x%x") (get_local $val0))
-    (if (i32.eq (get_local $idx) (get_global $mem_free_list))
-      (call $print (STRING " (free start)")))
-    (if (i32.eq (get_local $val0) (get_global $mem_unused_start))
-      (call $print (STRING " (free end)")))
-    (br $done))
-    ;; 16: unknown
-    (call $print (STRING "unknown"))
-    )
-
-    (drop (call $putchar (i32.const 0xA)))
-
-    (i32.add (get_local $size) (get_local $idx))
-  )
-
-  (func $PR_MEMORY (param $start i32) (param $end i32)
-    (local $idx i32)
-    (if (i32.lt_s (get_local $start) (i32.const 0))
-      (set_local $start (get_global $mem_user_start)))
-    (if (i32.lt_s (get_local $end) (i32.const 0))
-      (set_local $end (get_global $mem_unused_start)))
-    ;;; printf("Values - (mem) showing %d -> %d", start, end)
-    ;;; printf(" (unused start: %d, free list: %d):\n",
-    ;;;        mem_unused_start, mem_free_list)
-    (call $printf_4 (STRING "Values - (mem) showing 0x%x -> 0x%x (unused start: 0x%x, free list: 0x%x):\n")
-          (get_local $start)
-          (get_local $end)
-          (get_global $mem_unused_start)
-          (get_global $mem_free_list))
-
-    (if (i32.le_s (get_local $end) (get_local $start))
-      (then
-        (call $print (STRING "  ---\n"))
-        (set_local $end (get_global $mem_unused_start)))
-      (else
-        (set_local $idx (get_local $start))
-        ;;; while (idx < end)
-        (block $loopvals_exit
-          (loop $loopvals
-            (if (i32.ge_s (get_local $idx) (get_local $end))
-              (br $loopvals_exit))
-            (set_local $idx (call $PR_MEMORY_VALUE (get_local $idx)))
-            (br $loopvals)
-          )
-        )))
-  )
-
-  (func $PR_MEMORY_RAW (param $start i32) (param $end i32)
-    (block $loop_exit
-      (loop $loop
-        (if (i32.ge_u (get_local $start) (get_local $end))
-          (br $loop_exit))
-        (call $printf_2 (STRING "0x%x 0x%x\n")
-              (get_local $start) (i32.load (get_local $start)))
-        (set_local $start (i32.add (i32.const 4) (get_local $start)))
-        (br $loop)
-      )
-    )
-  )
-)
diff --git a/wasm/env.wam b/wasm/env.wam
new file mode 100644 (file)
index 0000000..88945ff
--- /dev/null
@@ -0,0 +1,79 @@
+(module $env
+
+  (func $ENV_NEW (param $outer i32) (result i32)
+    (local $data i32)
+    (local $env i32)
+
+    ;; allocate the data hashmap
+    (set_local $data ($HASHMAP))
+
+    (set_local $env ($ALLOC (get_global $ENVIRONMENT_T) $data $outer 0))
+    ;; environment takes ownership
+    ($RELEASE $data)
+    $env
+  )
+
+  (func $ENV_SET (param $env i32) (param $key i32) (param $value i32)
+        (result i32)
+    (local $data i32)
+    (set_local $data ($MEM_VAL0_ptr $env))
+    (i32.store ($VAL0_ptr $env) ($MalVal_index ($ASSOC1 $data $key $value)))
+    $value
+  )
+
+  (func $ENV_SET_S (param $env i32) (param $key i32) (param $value i32)
+        (result i32)
+    (local $data i32)
+    (set_local $data ($MEM_VAL0_ptr $env))
+    (i32.store ($VAL0_ptr $env) ($MalVal_index ($ASSOC1_S $data $key $value)))
+    $value
+  )
+
+  (func $ENV_FIND (param $env i32) (param $key i32) (result i64)
+    (local $res i32)
+    (local $data i32)
+    (local $found_res i64)
+
+    (set_local $res 0)
+
+    (block $done
+      (loop $loop
+        (set_local $data ($MEM_VAL0_ptr $env))
+        (set_local $found_res ($HASHMAP_GET $data
+                                    $key))
+        ;;; if (found)
+        (if (i32.wrap/i64 (i64.shr_u $found_res (i64.const 32)))
+          (then
+            (set_local $res (i32.wrap/i64 $found_res))
+            (br $done)))
+        (set_local $env ($MEM_VAL1_ptr $env))
+        (if (i32.eq $env (get_global $NIL))
+          (then
+            (set_local $env 0)
+            (br $done)))
+        (br $loop)
+      )
+    )
+
+    ;; combine res/env as hi 32/low 32 of i64
+    (i64.or
+      (i64.shl_u (i64.extend_u/i32 $res) (i64.const 32))
+      (i64.extend_u/i32 $env))
+  )
+
+  (func $ENV_GET (param $env i32) (param $key i32) (result i32)
+    (local $res i32)
+    (local $res_env i64)
+    (set_local $res 0)
+
+    (set_local $res_env ($ENV_FIND $env $key))
+    (set_local $env (i32.wrap/i64 $res_env))
+    (set_local $res (i32.wrap/i64 (i64.shr_u $res_env (i64.const 32))))
+
+    (if (i32.eqz $env)
+      (then
+        ($THROW_STR_1 "'%s' not found" ($to_String $key))
+        (return $res)))
+    (return ($INC_REF $res))
+  )
+)
diff --git a/wasm/env.wast b/wasm/env.wast
deleted file mode 100644 (file)
index 9e36586..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-(module $env
-
-  (func $ENV_NEW (param $outer i32) (result i32)
-    (local $data i32)
-    (local $env i32)
-
-    ;; allocate the data hashmap
-    (set_local $data (call $HASHMAP))
-
-    (set_local $env (call $ALLOC (get_global $ENVIRONMENT_T)
-                          (get_local $data) (get_local $outer) (i32.const 0)))
-    ;; environment takes ownership
-    (call $RELEASE (get_local $data))
-    (get_local $env)
-  )
-
-  (func $ENV_SET (param $env i32) (param $key i32) (param $value i32)
-        (result i32)
-    (local $data i32)
-    (set_local $data (call $MEM_VAL0_ptr (get_local $env)))
-    (i32.store (call $VAL0_ptr (get_local $env))
-               (call $MalVal_index
-                     (call $ASSOC1 (get_local $data)
-                           (get_local $key) (get_local $value))))
-    (get_local $value)
-  )
-
-  (func $ENV_SET_S (param $env i32) (param $key i32) (param $value i32)
-        (result i32)
-    (local $data i32)
-    (set_local $data (call $MEM_VAL0_ptr (get_local $env)))
-    (i32.store (call $VAL0_ptr (get_local $env))
-               (call $MalVal_index
-                     (call $ASSOC1_S (get_local $data)
-                           (get_local $key) (get_local $value))))
-    (get_local $value)
-  )
-
-  (func $ENV_FIND (param $env i32) (param $key i32) (result i64)
-    (local $res i32)
-    (local $data i32)
-    (local $found_res i64)
-
-    (set_local $res (i32.const 0))
-
-    (block $done
-      (loop $loop
-        (set_local $data (call $MEM_VAL0_ptr (get_local $env)))
-        (set_local $found_res (call $HASHMAP_GET (get_local $data)
-                                    (get_local $key)))
-        ;;; if (found)
-        (if (i32.wrap/i64 (i64.shr_u (get_local $found_res)
-                                     (i64.const 32)))
-          (then
-            (set_local $res (i32.wrap/i64 (get_local $found_res)))
-            (br $done)))
-        (set_local $env (call $MEM_VAL1_ptr (get_local $env)))
-        (if (i32.eq (get_local $env) (get_global $NIL))
-          (then
-            (set_local $env (i32.const 0))
-            (br $done)))
-        (br $loop)
-      )
-    )
-
-    ;; combine res/env as hi 32/low 32 of i64
-    (i64.or
-      (i64.shl_u (i64.extend_u/i32 (get_local $res))
-                 (i64.const 32))
-      (i64.extend_u/i32 (get_local $env)))
-  )
-
-  (func $ENV_GET (param $env i32) (param $key i32) (result i32)
-    (local $res i32)
-    (local $res_env i64)
-    (set_local $res (i32.const 0))
-
-    (set_local $res_env (call $ENV_FIND (get_local $env) (get_local $key)))
-    (set_local $env (i32.wrap/i64 (get_local $res_env)))
-    (set_local $res (i32.wrap/i64 (i64.shr_u (get_local $res_env)
-                                              (i64.const 32))))
-
-    (if (i32.eqz (get_local $env))
-      (then
-        (call $THROW_STR_1 (STRING "'%s' not found")
-              (call $to_String (get_local $key)))
-        (return (get_local $res))))
-    (return (call $INC_REF (get_local $res)))
-  )
-)
diff --git a/wasm/mem.wam b/wasm/mem.wam
new file mode 100644 (file)
index 0000000..1134ae1
--- /dev/null
@@ -0,0 +1,401 @@
+(module $mem
+  (global $MEM_SIZE               i32 1048576)
+  (global $STRING_MEM_SIZE        i32 1048576)
+
+  (global $heap_start             (mut i32) 0)
+  (global $heap_end               (mut i32) 0)
+
+  (global $mem                    (mut i32) 0)
+  (global $mem_unused_start       (mut i32) 0)
+  (global $mem_free_list          (mut i32) 0)
+  (global $mem_user_start         (mut i32) 0)
+
+;;  (global $string_mem             (mut i32) 0)
+;;  (global $string_mem_next        (mut i32) 0)
+;;  (global $string_mem_user_start  (mut i32) 0)
+
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+  ;; General type storage/pointer functions
+
+  (func $VAL0_ptr (param $mv i32) (result i32)
+    (i32.add $mv 4))
+  (func $VAL1_ptr (param $mv i32) (result i32)
+    (i32.add $mv 8))
+
+  (func $VAL0 (param $mv i32) (result i32)
+    (i32.load (i32.add $mv 4)))
+  (func $VAL1 (param $mv i32) (result i32)
+    (i32.load (i32.add $mv 8)))
+
+
+  (func $MEM_VAL0_ptr (param $mv i32) (result i32)
+    (i32.add (get_global $mem)
+             (i32.mul_u (i32.load (i32.add $mv 4)) 8)))
+  (func $MEM_VAL1_ptr (param $mv i32) (result i32)
+    (i32.add (get_global $mem)
+             (i32.mul_u (i32.load (i32.add $mv 8)) 8)))
+  (func $MEM_VAL2_ptr (param $mv i32) (result i32)
+    (i32.add (get_global $mem)
+             (i32.mul_u (i32.load (i32.add $mv 12)) 8)))
+
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+  ;; Returns the address of 'mem[mv_idx]'
+  (func $MalVal_ptr (param $mv_idx i32) (result i32)
+    ;; MalVal memory 64 bit (2 * i32) aligned
+    ;;; mem[mv_idx].refcnt_type
+    (i32.add (get_global $mem) (i32.mul_u $mv_idx 8)))
+
+  ;; Returns the memory index mem of mv
+  ;; Will usually be used with a load or store by the caller
+  (func $MalVal_index (param $mv i32) (result i32)
+    ;; MalVal memory 64 bit (2 * i32) aligned
+    (i32.div_u (i32.sub_u $mv (get_global $mem)) 8))
+
+  ;; Returns the address of 'mem[mv_idx].refcnt_type'
+  (func $MalVal_refcnt_type (param $mv_idx i32) (result i32)
+    (i32.load ($MalVal_ptr $mv_idx)))
+
+  (func $TYPE (param $mv i32) (result i32)
+    ;;; type = mv->refcnt_type & 31
+    (i32.and (i32.load $mv) 0x1f)) ;; 0x1f == 31
+
+  (func $REFS (param $mv i32) (result i32)
+    ;;; type = mv->refcnt_type & 31
+    (i32.shr_u (i32.load $mv) 5)) ;; / 32
+
+  ;; Returns the address of 'mem[mv_idx].val[val]'
+  ;; Will usually be used with a load or store by the caller
+  (func $MalVal_val_ptr (param $mv_idx i32) (param $val i32) (result i32)
+    (i32.add (i32.add ($MalVal_ptr $mv_idx) 4)
+             (i32.mul_u $val 4)))
+
+  ;; Returns the value of 'mem[mv_idx].val[val]'
+  (func $MalVal_val (param $mv_idx i32) (param $val i32) (result i32)
+    (i32.load ($MalVal_val_ptr $mv_idx $val)))
+
+  (func $MalType_size (param $type i32) (result i32)
+    ;;; if (type <= 5 || type == 9 || type == 12)
+    (if i32 (i32.or (i32.le_u $type 5)
+                    (i32.or (i32.eq $type 9)
+                            (i32.eq $type 12)))
+      (then 2)
+      (else
+        ;;; else if (type == 8 || type == 10 || type == 11)
+        (if i32 (i32.or (i32.eq $type 8)
+                        (i32.or (i32.eq $type 10)
+                                (i32.eq $type 11)))
+          (then 4)
+          (else 3)))))
+
+  (func $MalVal_size (param $mv i32) (result i32)
+    (local $type i32)
+    (set_local $type ($TYPE $mv))
+    ;; if (type == FREE_T)
+    (if i32 (i32.eq $type (get_global $FREE_T))
+      (then
+        ;;; return (mv->refcnt_type & 0xffe0)>>5
+        (i32.shr_u (i32.and (i32.load $mv) 0xffe0) 5)) ;;; / 32
+      (else
+        ;;; return MalType_size(type)
+        ($MalType_size $type))))
+
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+  ;; init_memory
+
+  (func $init_memory
+    (local $heap_size i32)
+
+;;    ($print ">>> init_memory\n")
+
+    ($init_sprintf_mem)
+
+    ;; 100 character error_str static buffer
+    (set_global $error_str "                                                                                                    ")
+    ;; 256 character token static buffer
+    (set_global $token "                                                                                                                                                                                                                                                                ")
+
+    (set_local $heap_size (i32.add (get_global $MEM_SIZE)
+                                   (get_global $STRING_MEM_SIZE)))
+    (set_global $heap_start (i32.add (get_global $memoryBase)
+                                     (get_global $S_STRING_END)))
+    (set_global $heap_end (i32.add (get_global $heap_start)
+                                   $heap_size))
+
+    (set_global $mem (get_global $heap_start))
+    (set_global $mem_unused_start 0)
+    (set_global $mem_free_list 0)
+
+;;    (set_global $string_mem (i32.add (get_global $heap_start)
+;;                                     (get_global $MEM_SIZE)))
+;;    (set_global $string_mem_next (get_global $string_mem))
+
+    ;; Empty values
+    (set_global $NIL
+                ($ALLOC_SCALAR (get_global $NIL_T) 0))
+    (set_global $FALSE
+                ($ALLOC_SCALAR (get_global $BOOLEAN_T) 0))
+    (set_global $TRUE
+                ($ALLOC_SCALAR (get_global $BOOLEAN_T) 1))
+    (set_global $EMPTY_LIST
+                ($ALLOC (get_global $LIST_T)
+                      (get_global $NIL) (get_global $NIL) (get_global $NIL)))
+    (set_global $EMPTY_VECTOR
+                ($ALLOC (get_global $VECTOR_T)
+                      (get_global $NIL) (get_global $NIL) (get_global $NIL)))
+    (set_global $EMPTY_HASHMAP
+                ($ALLOC (get_global $HASHMAP_T)
+                      (get_global $NIL) (get_global $NIL) (get_global $NIL)))
+
+;;    ($print "<<< init_memory\n")
+
+  )
+
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+  ;; memory management
+
+  (func $ALLOC_INTERNAL (param $type i32) (param $val1 i32)
+               (param $val2 i32) (param $val3 i32) (result i32)
+    (local $prev i32)
+    (local $res i32)
+    (local $size i32)
+    (set_local $prev (get_global $mem_free_list))
+    (set_local $res (get_global $mem_free_list))
+    (set_local $size ($MalType_size $type))
+
+    (block $loop_done
+      (loop $loop
+        ;; res == mem_unused_start
+        (if (i32.eq $res (get_global $mem_unused_start))
+          (then
+            ;; ALLOC_UNUSED
+            ;;; if (res + size > MEM_SIZE)
+            (if (i32.gt_u (i32.add $res $size) (get_global $MEM_SIZE))
+              (then
+                ;; Out of memory, exit
+                ($print "Out of mal memory!\n")
+                ($exit 1)))
+            ;;; if (mem_unused_start += size)
+            (set_global $mem_unused_start
+                        (i32.add (get_global $mem_unused_start) $size))
+            ;;; if (prev == res)
+            (if (i32.eq $prev $res)
+              (then
+                (set_global $mem_free_list (get_global $mem_unused_start)))
+              (else
+                ;;; mem[prev].val[0] = mem_unused_start
+                (i32.store
+                  ($MalVal_val_ptr $prev 0)
+                  (get_global $mem_unused_start))))
+            (br $loop_done)))
+        ;; if (MalVal_size(mem+res) == size)
+        (if (i32.eq ($MalVal_size ($MalVal_ptr $res))
+                    $size)
+          (then
+            ;; ALLOC_MIDDLE
+            ;;; if (res == mem_free_list)
+            (if (i32.eq $res (get_global $mem_free_list))
+              ;; set free pointer (mem_free_list) to next free
+              ;;; mem_free_list = mem[res].val[0];
+              (set_global $mem_free_list ($MalVal_val $res 0)))
+            ;;  if (res != mem_free_list)
+            (if (i32.ne $res (get_global $mem_free_list))
+              ;; set previous free to next free
+              ;;; mem[prev].val[0] = mem[res].val[0]
+              (i32.store ($MalVal_val_ptr $prev 0) ($MalVal_val $res 0)))
+            (br $loop_done)))
+        ;;; prev = res
+        (set_local $prev $res)
+        ;;; res = mem[res].val[0]
+        (set_local $res ($MalVal_val $res 0))
+        (br $loop)
+      )
+    )
+    ;; ALLOC_DONE
+    ;;; mem[res].refcnt_type = type + 32
+    (i32.store ($MalVal_ptr $res) (i32.add $type 32))
+    ;; set val to default val1
+    ;;; mem[res].val[0] = val1
+    (i32.store ($MalVal_val_ptr $res 0) $val1)
+    ;;; if (type > 5 && type != 9)
+    (if (i32.and (i32.gt_u $type 5) (i32.ne $type 9))
+      (then
+        ;; inc refcnt of referenced value
+        ;;; mem[val1].refcnt_type += 32
+        (i32.store ($MalVal_ptr $val1)
+                   (i32.add ($MalVal_refcnt_type $val1) 32))))
+    ;;; if (size > 2)
+    (if (i32.gt_u $size 2)
+      (then
+        ;; inc refcnt of referenced value
+        ;;; mem[val2].refcnt_type += 32
+        (i32.store ($MalVal_ptr $val2)
+                   (i32.add ($MalVal_refcnt_type $val2) 32))
+        ;;; mem[res].val[1] = val2
+        (i32.store ($MalVal_val_ptr $res 1) $val2)))
+    ;;; if (size > 3)
+    (if (i32.gt_u $size 3)
+      (then
+        ;; inc refcnt of referenced value
+        ;;; mem[val3].refcnt_type += 32
+        (i32.store ($MalVal_ptr $val3)
+                   (i32.add ($MalVal_refcnt_type $val3) 32))
+        ;;; mem[res].val[2] = val3
+        (i32.store ($MalVal_val_ptr $res 2) $val3)))
+
+    ;;; return mem + res
+    ($MalVal_ptr $res)
+  )
+
+  (func $ALLOC_SCALAR (param $type i32) (param $val1 i32) (result i32)
+    ($ALLOC_INTERNAL $type $val1 0 0)
+  )
+
+  (func $ALLOC (param $type i32) (param $val1 i32)
+               (param $val2 i32) (param $val3 i32) (result i32)
+    ($ALLOC_INTERNAL $type
+                     ($MalVal_index $val1)
+                     ($MalVal_index $val2)
+                     ($MalVal_index $val3))
+  )
+
+  (func $RELEASE (param $mv i32)
+    (local $idx i32)
+    (local $type i32)
+    (local $size i32)
+
+    ;; Ignore NULLs
+    ;;; if (mv == NULL) { return; }
+    (if (i32.eqz $mv) (return))
+    ;;; idx = mv - mem
+    (set_local $idx ($MalVal_index $mv))
+    ;;; type = mv->refcnt_type & 31
+    (set_local $type (i32.and (i32.load $mv) 0x1f)) ;; 0x1f == 31
+    ;;; size = MalType_size(type)
+    (set_local $size ($MalType_size $type))
+
+    ;; DEBUG
+    ;;; printf(">>> RELEASE idx: %d, type: %d, size: %d\n", idx, type, size)
+
+    (if (i32.eq 0 $mv)
+      (then
+        ($print "RELEASE of NULL!\n")
+        ($exit 1)))
+
+    (if (i32.eq (get_global $FREE_T) $type)
+      (then
+        ($printf_2 "RELEASE of already free mv: 0x%x, idx: 0x%x\n" $mv $idx)
+        ($exit 1)))
+    (if (i32.lt_u ($MalVal_refcnt_type $idx) 15)
+      (then
+        ($printf_2 "RELEASE of unowned mv: 0x%x, idx: 0x%x\n" $mv $idx)
+        ($exit 1)))
+
+    ;; decrease reference count by one
+    (i32.store ($MalVal_ptr $idx)
+               (i32.sub_u ($MalVal_refcnt_type $idx) 32))
+
+    ;; nil, false, true, empty sequences
+    (if (i32.le_u $mv (get_global $EMPTY_HASHMAP))
+      (then
+        (if (i32.lt_u ($MalVal_refcnt_type $idx) 32)
+          (then
+            ($printf_2 "RELEASE of unowned mv: 0x%x, idx: 0x%x\n" $mv $idx)
+            ($exit 1)))
+        (return)))
+
+    ;; our reference count is not 0, so don't release
+    (if (i32.ge_u ($MalVal_refcnt_type $idx) 32)
+      (return))
+
+    (block $done
+      (block (block (block (block (block (block
+      (br_table 0 0 0 0 1 1 2 2 3 5 5 5 5 4 5 5 5 $type))
+      ;; nil, boolean, integer, float
+      (br $done))
+      ;; string, kw, symbol
+      ;; release string, then FREE reference
+      ($RELEASE_STRING $mv)
+      (br $done))
+      ;; list, vector
+      (if (i32.ne ($MalVal_val $idx 0) 0)
+        (then
+          ;; release next element and value
+          ($RELEASE ($MEM_VAL0_ptr $mv))
+          ($RELEASE ($MEM_VAL1_ptr $mv))))
+      (br $done))
+      ;; hashmap
+      (if (i32.ne ($MalVal_val $idx 0) 0)
+        (then
+          ;; release next element, value, and key
+          ($RELEASE ($MEM_VAL0_ptr $mv))
+          ($RELEASE ($MEM_VAL2_ptr $mv))
+          ($RELEASE ($MEM_VAL1_ptr $mv))))
+      (br $done))
+      ;; env
+      ;; if outer is set then release outer
+      (if (i32.ne ($MalVal_val $idx 1) 0)
+        ($RELEASE ($MEM_VAL1_ptr $mv)))
+      ;; release the hashmap data
+      ($RELEASE ($MEM_VAL0_ptr $mv))
+      (br $done))
+      ;; default/unknown
+    )
+
+    ;; FREE, free the current element
+
+    ;; set type(FREE/15) and size
+    ;;; mv->refcnt_type = size*32 + FREE_T
+    (i32.store $mv (i32.add (i32.mul_u $size 32) (get_global $FREE_T)))
+    (i32.store ($MalVal_val_ptr $idx 0) (get_global $mem_free_list))
+    (set_global $mem_free_list $idx)
+    (if (i32.ge_u $size 3) (i32.store ($MalVal_val_ptr $idx 1) 0))
+    (if (i32.eq $size 4) (i32.store ($MalVal_val_ptr $idx 2) 0))
+  )
+
+  ;; Allocate a string as follows:
+  ;; refcnt (i32 set to 1), string data, NULL byte
+  (func $STRING_DUPE (param $str i32) (result i32)
+    (local $len i32)
+    (local $cur i32)
+    (local $new i32)
+    (local $idx i32)
+
+    ;; Calculate length of string needed
+    (set_local $len ($STRING_LEN $str))
+
+    ;; leading i32 refcnt + trailing NULL
+    (set_local $new ($malloc (i32.add 5 $len)))
+
+    ;; set initial refcnt to 1
+    (i32.store $new 1)
+    ;; skip refcnt
+    (set_local $cur (i32.add $new 4))
+    ;; Set NULL terminator
+    (i32.store8_u (i32.add $cur $len) 0)
+
+    ;; Copy the characters
+    ($MEM_COPY $cur $str $len)
+    $new
+  )
+
+  ;; Duplicate regular character array string into a Mal string and
+  ;; return the MalVal pointer
+  (func $STRING (param $type i32) (param $str i32) (result i32)
+    ($ALLOC_SCALAR
+          $type
+          ($STRING_DUPE $str))
+  )
+
+  (func $RELEASE_STRING (param $mv i32)
+    (local $str i32)
+    (set_local $str ($MalVal_val
+                          ($MalVal_index $mv)
+                          0))
+
+    ;; DEBUG
+;;    ($printf_1 "RELEASE_STRING - calling free on: %d" $str)
+
+    ($free $str)
+  )
+)
diff --git a/wasm/mem.wast b/wasm/mem.wast
deleted file mode 100644 (file)
index 43464cd..0000000
+++ /dev/null
@@ -1,461 +0,0 @@
-(module $mem
-  (global $MEM_SIZE               i32 (i32.const 1048576))
-  (global $STRING_MEM_SIZE        i32 (i32.const 1048576))
-
-  (global $heap_start             (mut i32) (i32.const 0))
-  (global $heap_end               (mut i32) (i32.const 0))
-
-  (global $mem                    (mut i32) (i32.const 0))
-  (global $mem_unused_start       (mut i32) (i32.const 0))
-  (global $mem_free_list          (mut i32) (i32.const 0))
-  (global $mem_user_start         (mut i32) (i32.const 0))
-
-;;  (global $string_mem             (mut i32) (i32.const 0))
-;;  (global $string_mem_next        (mut i32) (i32.const 0))
-;;  (global $string_mem_user_start  (mut i32) (i32.const 0))
-
-  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-  ;; General type storage/pointer functions
-
-  (func $VAL0_ptr (param $mv i32) (result i32)
-    (i32.add (get_local $mv) (i32.const 4)))
-  (func $VAL1_ptr (param $mv i32) (result i32)
-    (i32.add (get_local $mv) (i32.const 8)))
-
-  (func $VAL0 (param $mv i32) (result i32)
-    (i32.load (i32.add (get_local $mv) (i32.const 4))))
-  (func $VAL1 (param $mv i32) (result i32)
-    (i32.load (i32.add (get_local $mv) (i32.const 8))))
-
-
-  (func $MEM_VAL0_ptr (param $mv i32) (result i32)
-    (i32.add (get_global $mem)
-             (i32.mul_u (i32.load (i32.add (get_local $mv) (i32.const 4)))
-                        (i32.const 8))))
-  (func $MEM_VAL1_ptr (param $mv i32) (result i32)
-    (i32.add (get_global $mem)
-             (i32.mul_u (i32.load (i32.add (get_local $mv) (i32.const 8)))
-                        (i32.const 8))))
-  (func $MEM_VAL2_ptr (param $mv i32) (result i32)
-    (i32.add (get_global $mem)
-             (i32.mul_u (i32.load (i32.add (get_local $mv) (i32.const 12)))
-                        (i32.const 8))))
-
-  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-  ;; Returns the address of 'mem[mv_idx]'
-  (func $MalVal_ptr (param $mv_idx i32) (result i32)
-    ;; MalVal memory 64 bit (2 * i32) aligned
-    ;;; mem[mv_idx].refcnt_type
-    (i32.add (get_global $mem)
-             (i32.mul_u (get_local $mv_idx) (i32.const 8))))
-
-  ;; Returns the memory index mem of mv
-  ;; Will usually be used with a load or store by the caller
-  (func $MalVal_index (param $mv i32) (result i32)
-    ;; MalVal memory 64 bit (2 * i32) aligned
-    (i32.div_u (i32.sub_u (get_local $mv) (get_global $mem))
-               (i32.const 8)))
-
-  ;; Returns the address of 'mem[mv_idx].refcnt_type'
-  (func $MalVal_refcnt_type (param $mv_idx i32) (result i32)
-    (i32.load (call $MalVal_ptr (get_local $mv_idx))))
-
-  (func $TYPE (param $mv i32) (result i32)
-    ;;; type = mv->refcnt_type & 31
-    (i32.and (i32.load (get_local $mv))
-             (i32.const 0x1f))) ;; 0x1f == 31
-
-  (func $REFS (param $mv i32) (result i32)
-    ;;; type = mv->refcnt_type & 31
-    (i32.shr_u (i32.load (get_local $mv))
-               (i32.const 5))) ;; / 32
-
-  ;; Returns the address of 'mem[mv_idx].val[val]'
-  ;; Will usually be used with a load or store by the caller
-  (func $MalVal_val_ptr (param $mv_idx i32) (param $val i32) (result i32)
-    (i32.add (i32.add (call $MalVal_ptr (get_local $mv_idx))
-                      (i32.const 4))
-             (i32.mul_u (get_local $val)
-                        (i32.const 4))))
-
-  ;; Returns the value of 'mem[mv_idx].val[val]'
-  (func $MalVal_val (param $mv_idx i32) (param $val i32) (result i32)
-    (i32.load (call $MalVal_val_ptr (get_local $mv_idx) (get_local $val))))
-
-  (func $MalType_size (param $type i32) (result i32)
-    ;;; if (type <= 5 || type == 9 || type == 12)
-    (if i32 (i32.or (i32.le_u (get_local $type) (i32.const 5))
-                    (i32.or (i32.eq (get_local $type) (i32.const 9))
-                            (i32.eq (get_local $type) (i32.const 12))))
-      (then (i32.const 2))
-      (else
-        ;;; else if (type == 8 || type == 10 || type == 11)
-        (if i32 (i32.or (i32.eq (get_local $type) (i32.const 8))
-                        (i32.or (i32.eq (get_local $type) (i32.const 10))
-                                (i32.eq (get_local $type) (i32.const 11))))
-          (then (i32.const 4))
-          (else (i32.const 3))))))
-
-  (func $MalVal_size (param $mv i32) (result i32)
-    (local $type i32)
-    (set_local $type (call $TYPE (get_local $mv)))
-    ;; if (type == FREE_T)
-    (if i32 (i32.eq (get_local $type) (get_global $FREE_T))
-      (then
-        ;;; return (mv->refcnt_type & 0xffe0)>>5
-        (i32.shr_u
-          (i32.and
-            (i32.load (get_local $mv))
-            (i32.const 0xffe0))
-          (i32.const 5)))  ;;; / 32
-      (else
-        ;;; return MalType_size(type)
-        (call $MalType_size (get_local $type)))))
-
-  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-  ;; init_memory
-
-  (func $init_memory
-    (local $heap_size i32)
-
-;;    (call $print (STRING ">>> init_memory\n"))
-
-    (call $init_sprintf_mem)
-
-    ;; 100 character error_str static buffer
-    (set_global $error_str (STRING "                                                                                                    "))
-    ;; 256 character token static buffer
-    (set_global $token (STRING "                                                                                                                                                                                                                                                                "))
-
-    (set_local $heap_size (i32.add (get_global $MEM_SIZE)
-                                   (get_global $STRING_MEM_SIZE)))
-    (set_global $heap_start (i32.add (get_global $memoryBase)
-                                     (get_global $S_STRING_END)))
-    (set_global $heap_end (i32.add (get_global $heap_start)
-                                   (get_local $heap_size)))
-
-    (set_global $mem (get_global $heap_start))
-    (set_global $mem_unused_start (i32.const 0))
-    (set_global $mem_free_list (i32.const 0))
-
-;;    (set_global $string_mem (i32.add (get_global $heap_start)
-;;                                     (get_global $MEM_SIZE)))
-;;    (set_global $string_mem_next (get_global $string_mem))
-
-    ;; Empty values
-    (set_global $NIL
-                (call $ALLOC_SCALAR (get_global $NIL_T) (i32.const 0)))
-    (set_global $FALSE
-                (call $ALLOC_SCALAR (get_global $BOOLEAN_T) (i32.const 0)))
-    (set_global $TRUE
-                (call $ALLOC_SCALAR (get_global $BOOLEAN_T) (i32.const 1)))
-    (set_global $EMPTY_LIST
-                (call $ALLOC (get_global $LIST_T)
-                      (get_global $NIL) (get_global $NIL) (get_global $NIL)))
-    (set_global $EMPTY_VECTOR
-                (call $ALLOC (get_global $VECTOR_T)
-                      (get_global $NIL) (get_global $NIL) (get_global $NIL)))
-    (set_global $EMPTY_HASHMAP
-                (call $ALLOC (get_global $HASHMAP_T)
-                      (get_global $NIL) (get_global $NIL) (get_global $NIL)))
-
-;;    (call $print (STRING "<<< init_memory\n"))
-
-  )
-
-  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-  ;; memory management
-
-  (func $ALLOC_INTERNAL (param $type i32) (param $val1 i32)
-               (param $val2 i32) (param $val3 i32) (result i32)
-    (local $prev i32)
-    (local $res i32)
-    (local $size i32)
-    (set_local $prev (get_global $mem_free_list))
-    (set_local $res (get_global $mem_free_list))
-    (set_local $size (call $MalType_size (get_local $type)))
-
-    (block $loop_done
-      (loop $loop
-        ;; res == mem_unused_start
-        (if (i32.eq (get_local $res) (get_global $mem_unused_start))
-          (then
-            ;; ALLOC_UNUSED
-            ;;; if (res + size > MEM_SIZE)
-            (if (i32.gt_u (i32.add (get_local $res) (get_local $size))
-                          (get_global $MEM_SIZE))
-              (then
-                ;; Out of memory, exit
-                (call $print (STRING "Out of mal memory!\n"))
-                (call $exit (i32.const 1))))
-            ;;; if (mem_unused_start += size)
-            (set_global $mem_unused_start
-                        (i32.add (get_global $mem_unused_start)
-                                 (get_local $size)))
-            ;;; if (prev == res)
-            (if (i32.eq (get_local $prev) (get_local $res))
-              (then
-                (set_global $mem_free_list (get_global $mem_unused_start)))
-              (else
-                ;;; mem[prev].val[0] = mem_unused_start
-                (i32.store
-                  (call $MalVal_val_ptr (get_local $prev) (i32.const 0))
-                  (get_global $mem_unused_start))))
-            (br $loop_done)))
-        ;; if (MalVal_size(mem+res) == size)
-        (if (i32.eq (call $MalVal_size (call $MalVal_ptr (get_local $res)))
-                    (get_local $size))
-          (then
-            ;; ALLOC_MIDDLE
-            ;;; if (res == mem_free_list)
-            (if (i32.eq (get_local $res) (get_global $mem_free_list))
-              ;; set free pointer (mem_free_list) to next free
-              ;;; mem_free_list = mem[res].val[0];
-              (set_global $mem_free_list
-                          (call $MalVal_val (get_local $res) (i32.const 0))))
-            ;;  if (res != mem_free_list)
-            (if (i32.ne (get_local $res) (get_global $mem_free_list))
-              ;; set previous free to next free
-              ;;; mem[prev].val[0] = mem[res].val[0]
-              (i32.store (call $MalVal_val_ptr (get_local $prev) (i32.const 0))
-                         (call $MalVal_val (get_local $res) (i32.const 0))))
-            (br $loop_done)))
-        ;;; prev = res
-        (set_local $prev (get_local $res))
-        ;;; res = mem[res].val[0]
-        (set_local $res (call $MalVal_val (get_local $res) (i32.const 0)))
-        (br $loop)
-      )
-    )
-    ;; ALLOC_DONE
-    ;;; mem[res].refcnt_type = type + 32
-    (i32.store (call $MalVal_ptr (get_local $res))
-               (i32.add (get_local $type) (i32.const 32)))
-    ;; set val to default val1
-    ;;; mem[res].val[0] = val1
-    (i32.store (call $MalVal_val_ptr (get_local $res) (i32.const 0))
-               (get_local $val1))
-    ;;; if (type > 5 && type != 9)
-    (if (i32.and (i32.gt_u (get_local $type) (i32.const 5))
-                 (i32.ne (get_local $type) (i32.const 9)))
-      (then
-        ;; inc refcnt of referenced value
-        ;;; mem[val1].refcnt_type += 32
-        (i32.store (call $MalVal_ptr (get_local $val1))
-                   (i32.add (call $MalVal_refcnt_type (get_local $val1))
-                            (i32.const 32)))))
-    ;;; if (size > 2)
-    (if (i32.gt_u (get_local $size) (i32.const 2))
-      (then
-        ;; inc refcnt of referenced value
-        ;;; mem[val2].refcnt_type += 32
-        (i32.store (call $MalVal_ptr (get_local $val2))
-                   (i32.add (call $MalVal_refcnt_type (get_local $val2))
-                            (i32.const 32)))
-        ;;; mem[res].val[1] = val2
-        (i32.store (call $MalVal_val_ptr (get_local $res) (i32.const 1))
-                   (get_local $val2))))
-    ;;; if (size > 3)
-    (if (i32.gt_u (get_local $size) (i32.const 3))
-      (then
-        ;; inc refcnt of referenced value
-        ;;; mem[val3].refcnt_type += 32
-        (i32.store (call $MalVal_ptr (get_local $val3))
-                   (i32.add (call $MalVal_refcnt_type (get_local $val3))
-                            (i32.const 32)))
-        ;;; mem[res].val[2] = val3
-        (i32.store (call $MalVal_val_ptr (get_local $res) (i32.const 2))
-                   (get_local $val3))))
-
-    ;;; return mem + res
-    (call $MalVal_ptr (get_local $res))
-  )
-
-  (func $ALLOC_SCALAR (param $type i32) (param $val1 i32)
-                      (result i32)
-    (call $ALLOC_INTERNAL
-          (get_local $type)
-          (get_local $val1)
-          (i32.const 0)
-          (i32.const 0))
-  )
-
-  (func $ALLOC (param $type i32) (param $val1 i32)
-               (param $val2 i32) (param $val3 i32) (result i32)
-    (call $ALLOC_INTERNAL
-          (get_local $type)
-          (call $MalVal_index (get_local $val1))
-          (call $MalVal_index (get_local $val2))
-          (call $MalVal_index (get_local $val3)))
-  )
-
-  (func $RELEASE (param $mv i32)
-    (local $idx i32)
-    (local $type i32)
-    (local $size i32)
-
-    ;; Ignore NULLs
-    ;;; if (mv == NULL) { return; }
-    (if (i32.eqz (get_local $mv)) (return))
-    ;;; idx = mv - mem
-    (set_local $idx (call $MalVal_index (get_local $mv)))
-    ;;; type = mv->refcnt_type & 31
-    (set_local $type (i32.and (i32.load (get_local $mv))
-                              (i32.const 0x1f))) ;; 0x1f == 31
-    ;;; size = MalType_size(type)
-    (set_local $size (call $MalType_size (get_local $type)))
-
-    ;; DEBUG
-    ;;; printf(">>> RELEASE idx: %d, type: %d, size: %d\n", idx, type, size)
-;;    (call $print (STRING ">>> RELEASE idx: "))
-;;    (call $printhex (get_local $idx))
-;;    (call $print (STRING ", type: "))
-;;    (call $printnum (get_local $type) (i32.const 10))
-;;    (call $print (STRING ", size: "))
-;;    (call $printnum (get_local $size) (i32.const 10))
-;;    (call $print (STRING "\n"))
-
-    (if (i32.eq (i32.const 0) (get_local $mv))
-      (then
-        (call $print (STRING "RELEASE of NULL!\n"))
-        (call $exit (i32.const 1))))
-
-    (if (i32.eq (get_global $FREE_T) (get_local $type))
-      (then
-        (call $printf_2 (STRING "RELEASE of already free mv: 0x%x, idx: 0x%x\n")
-              (get_local $mv) (get_local $idx))
-        (call $exit (i32.const 1))))
-    (if (i32.lt_u (call $MalVal_refcnt_type (get_local $idx))
-                  (i32.const 15))
-      (then
-        (call $printf_2 (STRING "RELEASE of unowned mv: 0x%x, idx: 0x%x\n")
-              (get_local $mv) (get_local $idx))
-        (call $exit (i32.const 1))))
-
-    ;; decrease reference count by one
-    (i32.store (call $MalVal_ptr (get_local $idx))
-               (i32.sub_u (call $MalVal_refcnt_type (get_local $idx))
-                          (i32.const 32)))
-
-    ;; nil, false, true, empty sequences
-    (if (i32.le_u (get_local $mv) (get_global $EMPTY_HASHMAP))
-      (then
-        (if (i32.lt_u (call $MalVal_refcnt_type (get_local $idx))
-                      (i32.const 32))
-          (then
-            (call $printf_2 (STRING "RELEASE of unowned mv: 0x%x, idx: 0x%x\n")
-                  (get_local $mv) (get_local $idx))
-            (call $exit (i32.const 1))))
-        (return)))
-
-    ;; our reference count is not 0, so don't release
-    (if (i32.ge_u (call $MalVal_refcnt_type (get_local $idx))
-                  (i32.const 32))
-      (return))
-
-    (block $done
-      (block (block (block (block (block (block
-      (br_table 0 0 0 0 1 1 2 2 3 5 5 5 5 4 5 5 5 (get_local $type)))
-      ;; nil, boolean, integer, float
-      (br $done))
-      ;; string, kw, symbol
-      ;; release string, then FREE reference
-      (call $RELEASE_STRING (get_local $mv))
-      (br $done))
-      ;; list, vector
-      (if (i32.ne (call $MalVal_val (get_local $idx) (i32.const 0))
-                  (i32.const 0))
-        (then
-          ;; release next element and value
-          (call $RELEASE (call $MEM_VAL0_ptr (get_local $mv)))
-          (call $RELEASE (call $MEM_VAL1_ptr (get_local $mv)))))
-      (br $done))
-      ;; hashmap
-      (if (i32.ne (call $MalVal_val (get_local $idx) (i32.const 0))
-                  (i32.const 0))
-        (then
-          ;; release next element, value, and key
-          (call $RELEASE (call $MEM_VAL0_ptr (get_local $mv)))
-          (call $RELEASE (call $MEM_VAL2_ptr (get_local $mv)))
-          (call $RELEASE (call $MEM_VAL1_ptr (get_local $mv)))))
-      (br $done))
-      ;; env
-      ;; if outer is set then release outer
-      (if (i32.ne (call $MalVal_val (get_local $idx) (i32.const 1))
-                  (i32.const 0))
-        (call $RELEASE (call $MEM_VAL1_ptr (get_local $mv))))
-      ;; release the hashmap data
-      (call $RELEASE (call $MEM_VAL0_ptr (get_local $mv)))
-      (br $done))
-      ;; default/unknown
-    )
-
-    ;; FREE, free the current element
-
-    ;; set type(FREE/15) and size
-    ;;; mv->refcnt_type = size*32 + FREE_T
-    (i32.store (get_local $mv)
-               (i32.add (i32.mul_u (get_local $size)
-                                   (i32.const 32))
-                        (get_global $FREE_T)))
-    (i32.store (call $MalVal_val_ptr (get_local $idx) (i32.const 0))
-               (get_global $mem_free_list))
-    (set_global $mem_free_list (get_local $idx))
-    (if (i32.ge_u (get_local $size) (i32.const 3))
-      (i32.store (call $MalVal_val_ptr (get_local $idx) (i32.const 1))
-                 (i32.const 0)))
-    (if (i32.eq (get_local $size) (i32.const 4))
-      (i32.store (call $MalVal_val_ptr (get_local $idx) (i32.const 2))
-                 (i32.const 0)))
-  )
-
-  ;; Allocate a string as follows:
-  ;; refcnt (i32 set to 1), string data, NULL byte
-  (func $STRING_DUPE (param $str i32) (result i32)
-    (local $len i32)
-    (local $cur i32)
-    (local $new i32)
-    (local $idx i32)
-
-    ;; Calculate length of string needed
-    (set_local $len (call $STRING_LEN (get_local $str)))
-
-    ;; leading i32 refcnt + trailing NULL
-    (set_local $new (call $malloc (i32.add (i32.const 5) (get_local $len))))
-
-    ;; DEBUG
-;;    (call $debug (STRING "STRING_DUPE - malloc returned: ") (get_local $new))
-
-    ;; set initial refcnt to 1
-    (i32.store (get_local $new) (i32.const 1))
-    ;; skip refcnt
-    (set_local $cur (i32.add (get_local $new) (i32.const 4)))
-    ;; Set NULL terminator
-    (i32.store8_u (i32.add (get_local $cur) (get_local $len)) (i32.const 0))
-
-    ;; Copy the characters
-    (call $MEM_COPY (get_local $cur) (get_local $str) (get_local $len))
-    (get_local $new)
-  )
-
-  ;; Duplicate regular character array string into a Mal string and
-  ;; return the MalVal pointer
-  (func $STRING (param $type i32) (param $str i32) (result i32)
-    (call $ALLOC_SCALAR
-          (get_local $type)
-          (call $STRING_DUPE (get_local $str)))
-  )
-
-  (func $RELEASE_STRING (param $mv i32)
-    (local $str i32)
-    (set_local $str (call $MalVal_val
-                          (call $MalVal_index (get_local $mv))
-                          (i32.const 0)))
-
-    ;; DEBUG
-;;    (call $debug (STRING "RELEASE_STRING - calling free on: ") (get_local $str))
-
-    (call $free (get_local $str))
-  )
-)
diff --git a/wasm/printer.wam b/wasm/printer.wam
new file mode 100644 (file)
index 0000000..28e9e1a
--- /dev/null
@@ -0,0 +1,139 @@
+(module $printer
+
+  (func $pr_str_val (param $res i32) (param $mv i32) (result i32)
+    (local $type i32)
+    (local $val0 i32)
+    (local $sval i32)
+    (set_local $type ($TYPE $mv))
+    (set_local $val0 ($MalVal_val ($MalVal_index $mv)
+                           0))
+
+    ;;; switch(type)
+    (block $done
+      (block $default
+      (block (block (block (block (block (block (block (block
+      (block (block (block (block (block (block (block (block
+      (br_table 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $type))
+      ;; 0: nil
+      ($MEM_COPY $res "nil" 4)
+      (set_local $res (i32.add 3 $res))
+      (br $done))
+      ;; 1: boolean
+      (if (i32.eq $val0 0)
+        (then
+          ;; false
+          ($MEM_COPY $res "false" 5)
+          (set_local $res (i32.add 5 $res)))
+        (else
+          ;; true
+          ($MEM_COPY $res "true" 4)
+          (set_local $res (i32.add 4 $res))))
+      (br $done))
+      ;; 2: integer
+      (set_local $res ($sprintf_1 $res "%d" $val0))
+      (br $done))
+      ;; 3: float/ERROR
+      (set_local $res ($sprintf_1 $res "%d" " *** GOT FLOAT *** "))
+      (br $done))
+      ;; 4: string/kw
+      (set_local $sval ($to_String $mv))
+      (if (i32.eq (i32.load8_u $sval) (CHR "\x7f"))
+        (then
+          (set_local $res ($sprintf_1 $res ":%s" (i32.add $sval 1))))
+        (else
+          (set_local $res ($sprintf_1 $res "\"%s\"" ($to_String $mv)))))
+      (br $done))
+      ;; 5: symbol
+      (set_local $res ($sprintf_1 $res "%s" ($to_String $mv)))
+      (br $done))
+      ;; 6: list, fallthrouogh
+      )
+      ;; 7: vector, fallthrough
+      )
+      ;; 8: hashmap
+      (set_local
+        $res ($sprintf_1 $res "%c"
+                         (if i32 (i32.eq $type (get_global $LIST_T))
+                           (CHR "(")
+                           (else (if i32 (i32.eq $type (get_global $VECTOR_T))
+                                   (CHR "[")
+                                   (else (CHR "{")))))))
+      ;; PR_SEQ_LOOP
+      ;;; while (VAL0(mv) != 0)
+      (block $done_seq
+        (loop $seq_loop
+          (if (i32.eq ($VAL0 $mv) 0)
+            (br $done_seq))
+          ;;; res = pr_str_val(res, MEM_VAL1(mv), print_readably)
+          (set_local $res ($pr_str_val $res ($MEM_VAL1_ptr $mv)))
+
+          ;; if this is a hash-map, print the next element
+          (if (i32.eq $type (get_global $HASHMAP_T))
+            (then
+              ;;; res += snprintf(res, 2, " ")
+              (set_local $res ($sprintf_1 $res " " 0))
+              (set_local $res ($pr_str_val $res ($MEM_VAL2_ptr $mv)))))
+          ;;; mv = MEM_VAL0(mv)
+          (set_local $mv ($MEM_VAL0_ptr $mv))
+          ;;; if (VAL0(mv) != 0)
+          (if (i32.ne ($VAL0 $mv) 0)
+            ;;; res += snprintf(res, 2, " ")
+            (set_local $res ($sprintf_1 $res " " 0)))
+          ;;($print "here4\n")
+          (br $seq_loop)
+        )
+      )
+
+      (set_local
+        $res ($sprintf_1 $res "%c"
+                         (if i32 (i32.eq $type (get_global $LIST_T))
+                           (CHR ")")
+                           (else (if i32 (i32.eq $type (get_global $VECTOR_T))
+                                   (CHR "]")
+                                   (else (CHR "}")))))))
+      (br $done))
+      ;; 9: function
+      ($MEM_COPY $res "#<fn ...>" 10)
+      (set_local $res (i32.add 9 $res))
+      (br $done))
+      ;; 10: mal function
+      ($MEM_COPY $res "(fn* ...)" 10)
+      (set_local $res (i32.add 9 $res))
+      (br $done))
+      ;; 11: macro fn
+      ($print "macro fn")
+      ($MEM_COPY $res "#<macro ...>" 13)
+      (set_local $res (i32.add 12 $res))
+      (br $done))
+      ;; 12: atom
+      ($MEM_COPY $res "(atom ...)" 11)
+      (set_local $res (i32.add 10 $res))
+      (br $done))
+      ;; 13: environment
+      ($MEM_COPY $res "#<mem ...>" 11)
+      (set_local $res (i32.add 10 $res))
+      (br $done))
+      ;; 14: metadata
+      ($MEM_COPY $res "#<meta ...>" 12)
+      (set_local $res (i32.add 11 $res))
+      (br $done))
+      ;; 15: FREE
+      ($MEM_COPY $res "#<free ...>" 12)
+      (set_local $res (i32.add 11 $res))
+      (br $done))
+      ;; 16: default
+      ($MEM_COPY $res "#<unknown>" 11)
+      (set_local $res (i32.add 10 $res))
+    )
+
+    $res
+  )
+
+  (func $pr_str (param $mv i32) (result i32)
+    (drop ($pr_str_val (get_global $sprintf_buf) $mv))
+    ($STRING (get_global $STRING_T) (get_global $sprintf_buf))
+  )
+
+  (export "pr_str" (func $pr_str))
+
+)
diff --git a/wasm/printer.wast b/wasm/printer.wast
deleted file mode 100644 (file)
index 7f88ded..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-(module $printer
-
-  (func $pr_str_val (param $res i32) (param $mv i32) (result i32)
-    (local $type i32)
-    (local $val0 i32)
-    (local $sval i32)
-    (set_local $type (call $TYPE (get_local $mv)))
-    (set_local $val0 (call $MalVal_val (call $MalVal_index (get_local $mv))
-                           (i32.const 0)))
-
-    ;;; switch(type)
-    (block $done
-      (block $default
-      (block (block (block (block (block (block (block (block
-      (block (block (block (block (block (block (block (block
-      (br_table 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 (get_local $type)))
-      ;; 0: nil
-      (call $MEM_COPY (get_local $res) (STRING "nil") (i32.const 4))
-      (set_local $res (i32.add (i32.const 3) (get_local $res)))
-      (br $done))
-      ;; 1: boolean
-      (if (i32.eq (get_local $val0) (i32.const 0))
-        (then
-          ;; false
-          (call $MEM_COPY (get_local $res) (STRING "false") (i32.const 5))
-          (set_local $res (i32.add (i32.const 5) (get_local $res))))
-        (else
-          ;; true
-          (call $MEM_COPY (get_local $res) (STRING "true") (i32.const 4))
-          (set_local $res (i32.add (i32.const 4) (get_local $res)))))
-      (br $done))
-      ;; 2: integer
-      (set_local $res (call $sprintf_1 (get_local $res) (STRING "%d")
-                            (get_local $val0)))
-      (br $done))
-      ;; 3: float/ERROR
-      (set_local $res (call $sprintf_1 (get_local $res) (STRING "%d")
-                            (STRING " *** GOT FLOAT *** ")))
-      (br $done))
-      ;; 4: string/kw
-      (set_local $sval (call $to_String (get_local $mv)))
-      (if (i32.eq (i32.load8_u (get_local $sval)) (CHAR "\x7f"))
-        (then
-          (set_local $res (call $sprintf_1 (get_local $res) (STRING ":%s")
-                                (i32.add (get_local $sval) (i32.const 1)))))
-        (else
-          (set_local $res (call $sprintf_1 (get_local $res) (STRING "\"%s\"")
-                                (call $to_String (get_local $mv))))))
-      (br $done))
-      ;; 5: symbol
-      (set_local $res (call $sprintf_1 (get_local $res) (STRING "%s")
-                            (call $to_String (get_local $mv))))
-      (br $done))
-      ;; 6: list, fallthrouogh
-      )
-      ;; 7: vector, fallthrough
-      )
-      ;; 8: hashmap
-      (set_local
-        $res (call $sprintf_1 (get_local $res) (STRING "%c")
-                   (if i32 (i32.eq (get_local $type) (get_global $LIST_T))
-                     (CHAR "(")
-                     (else (if i32 (i32.eq (get_local $type) (get_global $VECTOR_T))
-                       (CHAR "[")
-                       (else (CHAR "{")))))))
-      ;; PR_SEQ_LOOP
-      ;;; while (VAL0(mv) != 0)
-      (block $done_seq
-        (loop $seq_loop
-          (if (i32.eq (call $VAL0 (get_local $mv)) (i32.const 0))
-            (br $done_seq))
-          ;;; res = pr_str_val(res, MEM_VAL1(mv), print_readably)
-          (set_local $res (call $pr_str_val (get_local $res)
-                                (call $MEM_VAL1_ptr (get_local $mv))))
-
-          ;; if this is a hash-map, print the next element
-          (if (i32.eq (get_local $type) (get_global $HASHMAP_T))
-            (then
-              ;;; res += snprintf(res, 2, " ")
-              (set_local $res (call $sprintf_1 (get_local $res) (STRING " ")
-                                    (i32.const 0)))
-              (set_local $res (call $pr_str_val (get_local $res)
-                                    (call $MEM_VAL2_ptr (get_local $mv))))))
-          ;;; mv = MEM_VAL0(mv)
-          (set_local $mv (call $MEM_VAL0_ptr (get_local $mv)))
-          ;;; if (VAL0(mv) != 0)
-          (if (i32.ne (call $VAL0 (get_local $mv)) (i32.const 0))
-            ;;; res += snprintf(res, 2, " ")
-            (set_local $res (call $sprintf_1 (get_local $res) (STRING " ")
-                                  (i32.const 0))))
-          ;;(call $print (STRING "here4\n"))
-          (br $seq_loop)
-        )
-      )
-
-      (set_local
-        $res (call $sprintf_1 (get_local $res) (STRING "%c")
-                   (if i32 (i32.eq (get_local $type) (get_global $LIST_T))
-                     (CHAR ")")
-                     (else (if i32 (i32.eq (get_local $type) (get_global $VECTOR_T))
-                       (CHAR "]")
-                       (else (CHAR "}")))))))
-      (br $done))
-      ;; 9: function
-      (call $MEM_COPY (get_local $res) (STRING "#<fn ...>") (i32.const 10))
-      (set_local $res (i32.add (i32.const 9) (get_local $res)))
-      (br $done))
-      ;; 10: mal function
-      (call $MEM_COPY (get_local $res) (STRING "(fn* ...)") (i32.const 10))
-      (set_local $res (i32.add (i32.const 9) (get_local $res)))
-      (br $done))
-      ;; 11: macro fn
-      (call $print (STRING "macro fn"))
-      (call $MEM_COPY (get_local $res) (STRING "#<macro ...>") (i32.const 13))
-      (set_local $res (i32.add (i32.const 12) (get_local $res)))
-      (br $done))
-      ;; 12: atom
-      (call $MEM_COPY (get_local $res) (STRING "(atom ...)") (i32.const 11))
-      (set_local $res (i32.add (i32.const 10) (get_local $res)))
-      (br $done))
-      ;; 13: environment
-      (call $MEM_COPY (get_local $res) (STRING "#<mem ...>") (i32.const 11))
-      (set_local $res (i32.add (i32.const 10) (get_local $res)))
-      (br $done))
-      ;; 14: metadata
-      (call $MEM_COPY (get_local $res) (STRING "#<meta ...>") (i32.const 12))
-      (set_local $res (i32.add (i32.const 11) (get_local $res)))
-      (br $done))
-      ;; 15: FREE
-      (call $MEM_COPY (get_local $res) (STRING "#<free ...>") (i32.const 12))
-      (set_local $res (i32.add (i32.const 11) (get_local $res)))
-      (br $done))
-      ;; 16: default
-      (call $MEM_COPY (get_local $res) (STRING "#<unknown>") (i32.const 11))
-      (set_local $res (i32.add (i32.const 10) (get_local $res)))
-    )
-
-    (get_local $res)
-  )
-
-  (func $pr_str (param $mv i32) (result i32)
-    (drop (call $pr_str_val (get_global $sprintf_buf) (get_local $mv)))
-    (call $STRING (get_global $STRING_T) (get_global $sprintf_buf))
-  )
-
-  (export "pr_str" (func $pr_str))
-
-)
diff --git a/wasm/reader.wam b/wasm/reader.wam
new file mode 100644 (file)
index 0000000..af13e90
--- /dev/null
@@ -0,0 +1,287 @@
+(module $reader
+
+  ;; TODO: global warning
+  (global $token       (mut i32) 0)
+  (global $read_index  (mut i32) 0)
+
+  (func $skip_spaces (param $str i32) (result i32)
+    (local $found i32)
+    (local $c i32)
+    (set_local $found 0)
+    (set_local $c (i32.load8_u (i32.add $str (get_global $read_index))))
+    (block $done
+      (loop $loop
+        ;;; while (c == ' ' || c == ',' || c == '\n')
+        (if (i32.and (i32.and
+                       (i32.ne $c (CHR " "))
+                       (i32.ne $c (CHR ",")))
+                     (i32.ne $c (CHR "\n")))
+          (br $done))
+        (set_local $found 1)
+        ;;; c=str[++(*index)]
+        (set_global $read_index (i32.add (get_global $read_index) 1))
+        (set_local $c (i32.load8_u (i32.add $str (get_global $read_index))))
+        (br $loop)
+      )
+    )
+;;    ($debug ">>> skip_spaces:" $found)
+    $found
+  )
+
+  (func $skip_to_eol (param $str i32) (result i32)
+    (local $found i32)
+    (local $c i32)
+    (set_local $found 0)
+    (set_local $c (i32.load8_c (i32.add $str (get_global $read_index))))
+    (if (i32.eq $c (CHR ";"))
+      (then
+        (set_local $found 1)
+        (block $done
+          (loop $loop
+            ;;; c=str[++(*index)]
+            (set_global $read_index (i32.add (get_global $read_index) 1))
+            (set_local $c (i32.load8_u (i32.add $str
+                                                (get_global $read_index))))
+            ;;; while (c != '\0' && c != '\n')
+            (if (i32.and (i32.ne $c (CHR "\x00")) (i32.ne $c (CHR "\n")))
+              (br $loop))
+          )
+        )))
+;;    ($debug ">>> skip_to_eol:" $found)
+    $found
+  )
+
+  (func $skip_spaces_comments (param $str i32)
+    (loop $loop
+      ;; skip spaces
+      (if ($skip_spaces $str) (br $loop))
+      ;; skip comments
+      (if ($skip_to_eol $str) (br $loop))
+    )
+  )
+
+  (func $read_token (param $str i32) (result i32)
+    (local $token_index i32)
+    (local $instring i32)
+    (local $escaped i32)
+    (local $c i32)
+    (set_local $token_index 0)
+    (set_local $instring 0)
+    (set_local $escaped 0)
+
+    ($skip_spaces_comments $str)
+
+    ;; read first character
+    ;;; c=str[++(*index)]
+    (set_local $c (i32.load8_u (i32.add $str (get_global $read_index))))
+    (set_global $read_index (i32.add (get_global $read_index) 1))
+    ;; read first character
+    ;;; token[token_index++] = c
+    (i32.store8_u (i32.add (get_global $token) $token_index) $c)
+    (set_local $token_index (i32.add $token_index 1))
+    ;; single/double character token
+    (if (i32.or (i32.eq $c (CHR "("))
+        (i32.or (i32.eq $c (CHR ")"))
+        (i32.or (i32.eq $c (CHR "["))
+        (i32.or (i32.eq $c (CHR "]"))
+        (i32.or (i32.eq $c (CHR "{"))
+        (i32.or (i32.eq $c (CHR "}"))
+        (i32.or (i32.eq $c (CHR "'"))
+        (i32.or (i32.eq $c (CHR "`"))
+        (i32.or (i32.eq $c (CHR "@"))
+        (i32.and (i32.eq $c (CHR "~"))
+                 (i32.eq (i32.load8_u (i32.add $str (get_global $read_index)))
+                         (CHR "@"))))))))))))
+
+      (then
+        ;; continue
+        (nop))
+      (else
+        ;;; if (c == '"') instring = true
+        (set_local $instring (i32.eq $c (CHR "\"")))
+        (block $done
+          (loop $loop
+            ;; peek at next character
+            ;;; c = str[*index]
+            (set_local $c (i32.load8_u
+                            (i32.add $str (get_global $read_index))))
+            ;;; if (c == '\0') break
+            (if (i32.eq $c 0) (br $done))
+            ;;; if (!instring)
+            (if (i32.eqz $instring)
+              (then
+                ;; next character is token delimiter
+                (if (i32.or (i32.eq $c (CHR "("))
+                    (i32.or (i32.eq $c (CHR ")"))
+                    (i32.or (i32.eq $c (CHR "["))
+                    (i32.or (i32.eq $c (CHR "]"))
+                    (i32.or (i32.eq $c (CHR "{"))
+                    (i32.or (i32.eq $c (CHR "}"))
+                    (i32.or (i32.eq $c (CHR " "))
+                    (i32.or (i32.eq $c (CHR ","))
+                            (i32.eq $c (CHR "\n"))))))))))
+                  (br $done))))
+            ;; read next character
+            ;;; token[token_index++] = str[(*index)++]
+            (i32.store8_u (i32.add (get_global $token) $token_index)
+                          (i32.load8_u
+                            (i32.add $str (get_global $read_index))))
+            (set_local $token_index (i32.add $token_index 1))
+            (set_global $read_index (i32.add (get_global $read_index) 1))
+            ;;; if (token[0] == '~' && token[1] == '@') break
+            (if (i32.and (i32.eq (i32.load8_u (i32.add (get_global $token) 0))
+                                 (CHR "~"))
+                         (i32.eq (i32.load8_u (i32.add (get_global $token) 1))
+                                 0x40))
+              (br $done))
+
+            ;;; if ((!instring) || escaped)
+            (if (i32.or (i32.eqz $instring) $escaped)
+              (then
+                (set_local $escaped 0)
+                (br $loop)))
+            (if (i32.eq $c (CHR "\\"))
+              (set_local $escaped 1))
+            (if (i32.eq $c (CHR "\""))
+              (br $done))
+            (br $loop)
+          )
+        )))
+
+    ;;; token[token_index] = '\0'
+    (i32.store8_u (i32.add (get_global $token) $token_index) 0)
+    (get_global $token)
+  )
+
+  (func $read_seq (param $str i32) (param $type i32) (param $end i32)
+        (result i32)
+    (local $res i32)
+    (local $val2 i32)
+    (local $val3 i32)
+    (local $c i32)
+
+    ;; MAP_LOOP stack
+    (local $ret i32)
+    (local $empty i32)
+    (local $current i32)
+
+    ;; MAP_LOOP_START
+    (set_local $res ($MAP_LOOP_START $type))
+    ;; push MAP_LOOP stack
+    ;;; empty = current = ret = res
+    (set_local $ret $res)
+    (set_local $current $res)
+    (set_local $empty $res)
+
+    ;; READ_SEQ_LOOP
+    (block $done
+      (loop $loop
+        ($skip_spaces_comments $str)
+
+        ;; peek at next character
+        ;;; c = str[*index]
+        (set_local $c (i32.load8_u (i32.add $str (get_global $read_index))))
+        (if (i32.eq $c (CHR "\x00"))
+          (then
+            ($THROW_STR_0 "unexpected EOF")
+            (br $done)))
+        (if (i32.eq $c $end)
+          (then
+            ;; read next character
+            ;;; c = str[(*index)++]
+            (set_local $c (i32.load8_u (i32.add $str (get_global $read_index))))
+            (set_global $read_index (i32.add (get_global $read_index) 1))
+            (br $done)))
+
+        ;; value (or key for hash-maps)
+        (set_local $val2 ($read_form $str))
+
+        ;; if error, release the unattached element
+        (if (get_global $error_type)
+          (then
+            ($RELEASE $val2)
+            (br $done)))
+
+        ;; if this is a hash-map, READ_FORM again
+        (if (i32.eq $type (get_global $HASHMAP_T))
+          (set_local $val3 ($read_form $str)))
+
+        ;; update the return sequence structure
+        ;; MAP_LOOP_UPDATE
+        (set_local $res ($MAP_LOOP_UPDATE $type $empty $current $val2 $val3))
+        (if (i32.le_u $current (get_global $EMPTY_HASHMAP))
+          ;; if first element, set return to new element
+          (set_local $ret $res))
+        ;; update current to point to new element
+        (set_local $current $res)
+
+        (br $loop)
+      )
+    )
+
+    ;; MAP_LOOP_DONE
+    $ret
+  )
+
+  (func $read_form (param $str i32) (result i32)
+    ;;($STRING (get_global $STRING_T) $str)
+    (local $tok i32)
+    (local $c0 i32)
+    (local $c1 i32)
+    (local $res i32)
+
+    (if (get_global $error_type) (return 0))
+
+    (set_local $tok ($read_token $str))
+;;    ($debug ">>> read_form 1:" $tok)
+    ;;; c0 = token[0]
+    (set_local $c0 (i32.load8_u $tok))
+    (set_local $c1 (i32.load8_u (i32.add $tok 1)))
+
+    (if (i32.eq $c0 0)
+      (then
+        (return ($INC_REF (get_global $NIL))))
+      (else (if (i32.or (i32.and (i32.ge_u $c0 (CHR "0"))
+                                 (i32.le_u $c0 (CHR "9")))
+                        (i32.and (i32.eq $c0 (CHR "-"))
+                                 (i32.and (i32.ge_u $c1 (CHR "0"))
+                                          (i32.le_u $c1 (CHR "9")))))
+      (then
+        (return ($INTEGER ($ATOI $tok))))
+    (else (if (i32.eq $c0 (CHR ":"))
+      (then
+        (i32.store8_u $tok (CHR "\x7f"))
+        (return ($STRING (get_global $STRING_T) $tok)))
+    (else (if (i32.eq $c0 (CHR "\""))
+      (then
+        ;; TODO: unescape
+        (i32.store8_u (i32.sub_u (i32.add $tok ($STRING_LEN $tok)) 1)
+                      (CHR "\x00"))
+        (return ($STRING (get_global $STRING_T) (i32.add $tok 1))))
+    (else (if (i32.eq $c0 (CHR "("))
+      (then
+        (return ($read_seq $str (get_global $LIST_T) (CHR ")"))))
+    (else (if (i32.eq $c0 (CHR "["))
+      (then
+        (return ($read_seq $str (get_global $VECTOR_T) (CHR "]"))))
+    (else (if (i32.eq $c0 (CHR "{"))
+      (then
+        (return ($read_seq $str (get_global $HASHMAP_T) (CHR "}"))))
+    (else (if (i32.or (i32.eq $c0 (CHR ")"))
+                      (i32.or (i32.eq $c0 (CHR "]"))
+                              (i32.eq $c0 (CHR "}"))))
+      (then
+        ($THROW_STR_1 "unexpected '%c'" $c0)
+        (return 0))
+    (else
+      (return ($STRING (get_global $SYMBOL_T) $tok))))))))))))))))))
+  )
+
+  (func $read_str (param $str i32) (result i32)
+    (set_global $read_index 0)
+    ($read_form $str)
+  )
+
+  (export "read_str" (func $read_str))
+
+)
diff --git a/wasm/reader.wast b/wasm/reader.wast
deleted file mode 100644 (file)
index 3b16df3..0000000
+++ /dev/null
@@ -1,321 +0,0 @@
-(module $reader
-
-  ;; TODO: global warning
-  (global $token       (mut i32) (i32.const 0))
-  (global $read_index  (mut i32) (i32.const 0))
-
-  (func $skip_spaces (param $str i32) (result i32)
-    (local $found i32)
-    (local $c i32)
-    (set_local $found (i32.const 0))
-    (set_local $c (i32.load8_u (i32.add (get_local $str)
-                                        (get_global $read_index))))
-    (block $done
-      (loop $loop
-        ;;; while (c == ' ' || c == ',' || c == '\n')
-        (if (i32.and (i32.and
-                       (i32.ne (get_local $c) (CHAR " "))
-                       (i32.ne (get_local $c) (CHAR ",")))
-                     (i32.ne (get_local $c) (CHAR "\n")))
-          (br $done))
-        (set_local $found (i32.const 1))
-        ;;; c=str[++(*index)]
-        (set_global $read_index (i32.add (get_global $read_index)
-                                         (i32.const 1)))
-        (set_local $c (i32.load8_u (i32.add (get_local $str)
-                                            (get_global $read_index))))
-        (br $loop)
-      )
-    )
-;;    (call $debug (STRING ">>> skip_spaces:") (get_local $found))
-    (get_local $found)
-  )
-
-  (func $skip_to_eol (param $str i32) (result i32)
-    (local $found i32)
-    (local $c i32)
-    (set_local $found (i32.const 0))
-    (set_local $c (i32.load8_c (i32.add (get_local $str)
-                                        (get_global $read_index))))
-    (if (i32.eq (get_local $c) (CHAR ";"))
-      (then
-        (set_local $found (i32.const 1))
-        (block $done
-          (loop $loop
-            ;;; c=str[++(*index)]
-            (set_global $read_index (i32.add (get_global $read_index)
-                                             (i32.const 1)))
-            (set_local $c (i32.load8_u (i32.add (get_local $str)
-                                                (get_global $read_index))))
-            ;;; while (c != '\0' && c != '\n')
-            (if (i32.and (i32.ne (get_local $c) (CHAR "\x00"))
-                         (i32.ne (get_local $c) (CHAR "\n")))
-              (br $loop))
-          )
-        )))
-;;    (call $debug (STRING ">>> skip_to_eol:") (get_local $found))
-    (get_local $found)
-  )
-
-  (func $skip_spaces_comments (param $str i32)
-    (loop $loop
-      ;; skip spaces
-      (if (call $skip_spaces (get_local $str)) (br $loop))
-      ;; skip comments
-      (if (call $skip_to_eol (get_local $str)) (br $loop))
-    )
-  )
-
-  (func $read_token (param $str i32) (result i32)
-    (local $token_index i32)
-    (local $instring i32)
-    (local $escaped i32)
-    (local $c i32)
-    (set_local $token_index (i32.const 0))
-    (set_local $instring (i32.const 0))
-    (set_local $escaped (i32.const 0))
-
-    (call $skip_spaces_comments (get_local $str))
-
-    ;; read first character
-    ;;; c=str[++(*index)]
-    (set_local $c (i32.load8_u (i32.add (get_local $str)
-                                        (get_global $read_index))))
-    (set_global $read_index (i32.add (get_global $read_index)
-                                     (i32.const 1)))
-    ;; read first character
-    ;;; token[token_index++] = c
-    (i32.store8_u (i32.add (get_global $token) (get_local $token_index))
-                  (get_local $c))
-    (set_local $token_index (i32.add (get_local $token_index)
-                                     (i32.const 1)))
-    ;; single/double character token
-    (if (i32.or (i32.eq (get_local $c) (CHAR "("))
-        (i32.or (i32.eq (get_local $c) (CHAR ")"))
-        (i32.or (i32.eq (get_local $c) (CHAR "["))
-        (i32.or (i32.eq (get_local $c) (CHAR "]"))
-        (i32.or (i32.eq (get_local $c) (CHAR "{"))
-        (i32.or (i32.eq (get_local $c) (CHAR "}"))
-        (i32.or (i32.eq (get_local $c) (CHAR "'"))
-        (i32.or (i32.eq (get_local $c) (CHAR "`"))
-        (i32.or (i32.eq (get_local $c) (CHAR "@"))
-        (i32.and (i32.eq (get_local $c) (CHAR "~"))
-                 (i32.eq (i32.load8_u (i32.add (get_local $str)
-                                               (get_global $read_index)))
-                         (CHAR "@"))))))))))))
-
-      (then
-        ;; continue
-        (nop))
-      (else
-        ;;; if (c == '"') instring = true
-        (set_local $instring (i32.eq (get_local $c) (CHAR "\"")))
-        (block $done
-          (loop $loop
-            ;; peek at next character
-            ;;; c = str[*index]
-            (set_local $c (i32.load8_u (i32.add (get_local $str)
-                                                (get_global $read_index))))
-            ;;; if (c == '\0') break
-            (if (i32.eq (get_local $c) (i32.const 0)) (br $done))
-            ;;; if (!instring)
-            (if (i32.eqz (get_local $instring))
-              (then
-                ;; next character is token delimiter
-                (if (i32.or (i32.eq (get_local $c) (CHAR "("))
-                    (i32.or (i32.eq (get_local $c) (CHAR ")"))
-                    (i32.or (i32.eq (get_local $c) (CHAR "["))
-                    (i32.or (i32.eq (get_local $c) (CHAR "]"))
-                    (i32.or (i32.eq (get_local $c) (CHAR "{"))
-                    (i32.or (i32.eq (get_local $c) (CHAR "}"))
-                    (i32.or (i32.eq (get_local $c) (CHAR " "))
-                    (i32.or (i32.eq (get_local $c) (CHAR ","))
-                            (i32.eq (get_local $c) (CHAR "\n"))))))))))
-                  (br $done))))
-            ;; read next character
-            ;;; token[token_index++] = str[(*index)++]
-            (i32.store8_u (i32.add (get_global $token)
-                                   (get_local $token_index))
-                          (i32.load8_u (i32.add (get_local $str)
-                                                (get_global $read_index))))
-            (set_local $token_index (i32.add (get_local $token_index)
-                                             (i32.const 1)))
-            (set_global $read_index (i32.add (get_global $read_index)
-                                             (i32.const 1)))
-            ;;; if (token[0] == '~' && token[1] == '@') break
-            (if (i32.and (i32.eq (i32.load8_u (i32.add (get_global $token)
-                                                       (i32.const 0)))
-                                 (CHAR "~"))
-                         (i32.eq (i32.load8_u (i32.add (get_global $token)
-                                                       (i32.const 1)))
-                                 (i32.const 0x40)))
-              (br $done))
-
-            ;;; if ((!instring) || escaped)
-            (if (i32.or (i32.eqz (get_local $instring))
-                        (get_local $escaped))
-              (then
-                (set_local $escaped (i32.const 0))
-                (br $loop)))
-            (if (i32.eq (get_local $c) (CHAR "\\"))
-              (set_local $escaped (i32.const 1)))
-            (if (i32.eq (get_local $c) (CHAR "\""))
-              (br $done))
-            (br $loop)
-          )
-        )))
-
-    ;;; token[token_index] = '\0'
-    (i32.store8_u (i32.add (get_global $token) (get_local $token_index))
-                  (i32.const 0))
-    (get_global $token)
-  )
-
-  (func $read_seq (param $str i32) (param $type i32) (param $end i32)
-        (result i32)
-    (local $res i32)
-    (local $val2 i32)
-    (local $val3 i32)
-    (local $c i32)
-
-    ;; MAP_LOOP stack
-    (local $ret i32)
-    (local $empty i32)
-    (local $current i32)
-
-    ;; MAP_LOOP_START
-    (set_local $res (call $MAP_LOOP_START (get_local $type)))
-    ;; push MAP_LOOP stack
-    ;;; empty = current = ret = res
-    (set_local $ret (get_local $res))
-    (set_local $current (get_local $res))
-    (set_local $empty (get_local $res))
-
-    ;; READ_SEQ_LOOP
-    (block $done
-      (loop $loop
-        (call $skip_spaces_comments (get_local $str))
-
-        ;; peek at next character
-        ;;; c = str[*index]
-        (set_local $c (i32.load8_u (i32.add (get_local $str)
-                                            (get_global $read_index))))
-        (if (i32.eq (get_local $c) (CHAR "\x00"))
-          (then
-            (call $THROW_STR_0 (STRING "unexpected EOF"))
-            (br $done)))
-        (if (i32.eq (get_local $c) (get_local $end))
-          (then
-            ;; read next character
-            ;;; c = str[(*index)++]
-            (set_local $c (i32.load8_u (i32.add (get_local $str)
-                                                (get_global $read_index))))
-            (set_global $read_index (i32.add (get_global $read_index)
-                                             (i32.const 1)))
-            (br $done)))
-
-        ;; value (or key for hash-maps)
-        (set_local $val2 (call $read_form (get_local $str)))
-
-        ;; if error, release the unattached element
-        (if (get_global $error_type)
-          (then
-            (call $RELEASE (get_local $val2))
-            (br $done)))
-
-        ;; if this is a hash-map, READ_FORM again
-        (if (i32.eq (get_local $type) (get_global $HASHMAP_T))
-          (set_local $val3 (call $read_form (get_local $str))))
-
-        ;; update the return sequence structure
-        ;; MAP_LOOP_UPDATE
-        (set_local $res (call $MAP_LOOP_UPDATE (get_local $type)
-                              (get_local $empty) (get_local $current)
-                              (get_local $val2) (get_local $val3)))
-        (if (i32.le_u (get_local $current) (get_global $EMPTY_HASHMAP))
-          ;; if first element, set return to new element
-          (set_local $ret (get_local $res)))
-        ;; update current to point to new element
-        (set_local $current (get_local $res))
-
-        (br $loop)
-      )
-    )
-
-    ;; MAP_LOOP_DONE
-    (get_local $ret)
-  )
-
-  (func $read_form (param $str i32) (result i32)
-    ;;(call $STRING (get_global $STRING_T) (get_local $str))
-    (local $tok i32)
-    (local $c0 i32)
-    (local $c1 i32)
-    (local $res i32)
-
-    (if (get_global $error_type) (return (i32.const 0)))
-
-    (set_local $tok (call $read_token (get_local $str)))
-;;    (call $debug (STRING ">>> read_form 1:") (get_local $tok))
-    ;;; c0 = token[0]
-    (set_local $c0 (i32.load8_u (get_local $tok)))
-    (set_local $c1 (i32.load8_u (i32.add (get_local $tok) (i32.const 1))))
-
-    (if (i32.eq (get_local $c0) (i32.const 0))
-      (then
-        (return (call $INC_REF (get_global $NIL))))
-    (else (if (i32.or
-                (i32.and
-                  (i32.ge_u (get_local $c0) (CHAR "0"))
-                  (i32.le_u (get_local $c0) (CHAR "9")))
-                (i32.and
-                  (i32.eq (get_local $c0) (CHAR "-"))
-                  (i32.and (i32.ge_u (get_local $c1) (CHAR "0"))
-                           (i32.le_u (get_local $c1) (CHAR "9")))))
-      (then
-        (return (call $INTEGER (call $ATOI (get_local $tok)))))
-    (else (if (i32.eq (get_local $c0) (CHAR ":"))
-      (then
-        (i32.store8_u (get_local $tok) (CHAR "\x7f"))
-        (return (call $STRING (get_global $STRING_T) (get_local $tok))))
-    (else (if (i32.eq (get_local $c0) (CHAR "\""))
-      (then
-        ;; TODO: unescape
-        (i32.store8_u (i32.sub_u
-                        (i32.add (get_local $tok)
-                                 (call $STRING_LEN (get_local $tok)))
-                        (i32.const 1))
-                      (CHAR "\x00"))
-        (return (call $STRING (get_global $STRING_T) (i32.add (get_local $tok)
-                                                              (i32.const 1)))))
-    (else (if (i32.eq (get_local $c0) (CHAR "("))
-      (then
-        (return (call $read_seq (get_local $str)
-                      (get_global $LIST_T) (CHAR ")"))))
-    (else (if (i32.eq (get_local $c0) (CHAR "["))
-      (then
-        (return (call $read_seq (get_local $str)
-                      (get_global $VECTOR_T) (CHAR "]"))))
-    (else (if (i32.eq (get_local $c0) (CHAR "{"))
-      (then
-        (return (call $read_seq (get_local $str)
-                      (get_global $HASHMAP_T) (CHAR "}"))))
-    (else (if (i32.or (i32.eq (get_local $c0) (CHAR ")"))
-                      (i32.or (i32.eq (get_local $c0) (CHAR "]"))
-                              (i32.eq (get_local $c0) (CHAR "}"))))
-      (then
-        (call $THROW_STR_1 (STRING "unexpected '%c'") (get_local $c0))
-        (return (i32.const 0)))
-    (else
-      (return (call $STRING (get_global $SYMBOL_T)
-                    (get_local $tok)))))))))))))))))))
-  )
-
-  (func $read_str (param $str i32) (result i32)
-    (set_global $read_index (i32.const 0))
-    (call $read_form (get_local $str))
-  )
-
-  (export "read_str" (func $read_str))
-
-)
similarity index 52%
rename from wasm/step0_repl.wast
rename to wasm/step0_repl.wam
index 652bb56..fd663b6 100644 (file)
@@ -2,20 +2,24 @@
   (import "env" "memory" (memory $0 256))
   (import "env" "memoryBase" (global $memoryBase i32))
 
+  ;; READ
   (func $READ (param $str i32) (result i32)
-    (get_local $str))
+    $str
+  )
 
   (func $EVAL (param $ast i32) (param $env i32) (result i32)
-    (get_local $ast))
+    $ast
+  )
 
+  ;; PRINT
   (func $PRINT (param $ast i32) (result i32)
-    (get_local $ast))
+    $ast
+  )
 
-  (func $rep (param $str i32) (result i32)
-    (call $PRINT
-          (call $EVAL
-                (call $READ (get_local $str))
-                (i32.const 0))))
+  ;; REPL
+  (func $rep (param $line i32) (result i32)
+    ($PRINT ($EVAL ($READ $line) 0))
+  )
 
   (func $main (result i32)
     ;; Constant location/value definitions
     ;; Start
     (block $repl_done
       (loop $repl_loop
-        (set_local $line (call $readline (STRING "user> ")))
-        (if (i32.eqz (get_local $line)) (br $repl_done))
-        (call $printf_1 (STRING "%s\n") (call $rep (get_local $line)))
-        (call $free (get_local $line))
+        (set_local $line ($readline "user> "))
+        (if (i32.eqz $line) (br $repl_done))
+        ($printf_1 "%s\n" ($rep $line))
+        ($free $line)
         (br $repl_loop)))
 
-    (call $print (STRING "\n"))
-    (i32.const 0)
+    ($print "\n")
+    0
   )
 
 
diff --git a/wasm/step1_read_print.wam b/wasm/step1_read_print.wam
new file mode 100644 (file)
index 0000000..2253021
--- /dev/null
@@ -0,0 +1,88 @@
+(module $step1_read_print
+  (import "env" "memory" (memory $0 256))
+  (import "env" "memoryBase" (global $memoryBase i32))
+
+  ;; READ
+  (func $READ (param $str i32) (result i32)
+    ($read_str $str)
+  )
+
+  ;; EVAL
+  (func $EVAL (param $ast i32) (param $env i32) (result i32)
+    $ast
+  )
+
+  ;; PRINT
+  (func $PRINT (param $ast i32) (result i32)
+    ($pr_str $ast)
+  )
+
+  ;; REPL
+  (func $rep (param $line i32) (param $env i32) (result i32)
+    (local $mv1 i32)
+    (local $mv2 i32)
+    (local $ms i32)
+    (block $rep_done
+      (set_local $mv1 ($READ $line))
+      (if (get_global $error_type) (br $rep_done))
+
+      (set_local $mv2 ($EVAL $mv1 $env))
+      (if (get_global $error_type) (br $rep_done))
+
+;;      ($PR_MEMORY -1 -1)
+      (set_local $ms ($PRINT $mv2))
+    )
+
+;;    ($PR_MEMORY -1 -1)
+    ($RELEASE $mv1)
+    $ms
+  )
+
+  (func $main (result i32)
+    ;; Constant location/value definitions
+    (local $line i32)
+    (local $res i32)
+
+    ;; DEBUG
+    ($printf_1 "memoryBase: 0x%x\n" (get_global $memoryBase))
+    ($printf_1 "heap_start: 0x%x\n" (get_global $heap_start))
+    ($printf_1 "heap_end: 0x%x\n" (get_global $heap_end))
+    ($printf_1 "mem: 0x%x\n" (get_global $mem))
+;;    ($printf_1 "string_mem: %d\n" (get_global $string_mem))
+    ($PR_MEMORY -1 -1)
+;;    ($PR_MEMORY_RAW (get_global $mem)
+;;          (i32.add (get_global $mem)
+;;                   (i32.mul_u (get_global $mem_unused_start)
+;;                              8)))
+
+    ;; Start
+    (block $repl_done
+      (loop $repl_loop
+        (set_local $line ($readline "user> "))
+        (if (i32.eqz $line) (br $repl_done))
+        (if (i32.eq (i32.load8_u $line) 0)
+          (then
+            ($free $line)
+            (br $repl_loop)))
+        (set_local $res ($rep $line 0))
+        (if (get_global $error_type)
+          (then
+            ($printf_1 "Error: %s\n" (get_global $error_str))
+            (set_global $error_type 0))
+          (else
+            ($printf_1 "%s\n" ($to_String $res))))
+        ($RELEASE $res)
+;;        ($PR_MEMORY -1 -1)
+        ($free $line)
+        (br $repl_loop)))
+
+    ($print "\n")
+    ($PR_MEMORY -1 -1)
+    0
+  )
+
+
+  (export "_main" (func $main))
+  (export "__post_instantiate" (func $init_memory))
+)
+
diff --git a/wasm/step1_read_print.wast b/wasm/step1_read_print.wast
deleted file mode 100644 (file)
index 51fcb41..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-(module $step1_read_print
-  (import "env" "memory" (memory $0 256))
-  (import "env" "memoryBase" (global $memoryBase i32))
-
-  (func $READ (param $str i32) (result i32)
-    (call $read_str (get_local $str)))
-
-  (func $EVAL (param $ast i32) (param $env i32) (result i32)
-    (get_local $ast))
-
-  (func $PRINT (param $ast i32) (result i32)
-    (call $pr_str (get_local $ast)))
-
-  (func $rep (param $line i32) (param $env i32) (result i32)
-    (local $mv1 i32)
-    (local $mv2 i32)
-    (local $ms i32)
-    (block $rep_done
-      (set_local $mv1 (call $READ (get_local $line)))
-      (if (get_global $error_type) (br $rep_done))
-
-      (set_local $mv2 (call $EVAL (get_local $mv1) (get_local $env)))
-      (if (get_global $error_type) (br $rep_done))
-
-;;      (call $PR_MEMORY (i32.const -1) (i32.const -1))
-      (set_local $ms (call $PRINT (get_local $mv2)))
-    )
-
-;;    (call $PR_MEMORY (i32.const -1) (i32.const -1))
-    (call $RELEASE (get_local $mv1))
-    (get_local $ms)
-  )
-
-  (func $main (result i32)
-    ;; Constant location/value definitions
-    (local $line i32)
-    (local $res i32)
-
-    ;; DEBUG
-    (call $printf_1 (STRING "memoryBase: %d\n") (get_global $memoryBase))
-    (call $printf_1 (STRING "heap_start: %d\n") (get_global $heap_start))
-    (call $printf_1 (STRING "heap_end: %d\n") (get_global $heap_end))
-    (call $printf_1 (STRING "mem: %d\n") (get_global $mem))
-;;    (call $printf_1 (STRING "string_mem: %d\n") (get_global $string_mem))
-    (call $PR_MEMORY (i32.const -1) (i32.const -1))
-;;    (call $PR_MEMORY_RAW (get_global $mem)
-;;          (i32.add (get_global $mem)
-;;                   (i32.mul_u (get_global $mem_unused_start)
-;;                              (i32.const 8))))
-
-    ;; Start
-    (block $repl_done
-      (loop $repl_loop
-        (set_local $line (call $readline (STRING "user> ")))
-        (if (i32.eqz (get_local $line)) (br $repl_done))
-        (if (i32.eq (i32.load8_u (get_local $line)) (i32.const 0))
-          (then
-            (call $free (get_local $line))
-            (br $repl_loop)))
-        (set_local $res (call $rep (get_local $line) (i32.const 0)))
-        (if (get_global $error_type)
-          (then
-            (call $printf_1 (STRING "Error: %s\n") (get_global $error_str))
-            (set_global $error_type (i32.const 0)))
-          (else
-            (call $printf_1 (STRING "%s\n") (call $to_String (get_local $res)))))
-        (call $RELEASE (get_local $res))
-;;        (call $PR_MEMORY (i32.const -1) (i32.const -1))
-        (call $free (get_local $line))
-        (br $repl_loop)))
-
-    (call $print (STRING "\n"))
-    (call $PR_MEMORY (i32.const -1) (i32.const -1))
-    (i32.const 0)
-  )
-
-
-  (export "_main" (func $main))
-  (export "__post_instantiate" (func $init_memory))
-)
-
diff --git a/wasm/step2_eval.wam b/wasm/step2_eval.wam
new file mode 100644 (file)
index 0000000..ca9a24a
--- /dev/null
@@ -0,0 +1,255 @@
+(module $step1_read_print
+  (import "env" "memory" (memory $0 256))
+  (import "env" "memoryBase" (global $memoryBase i32))
+
+  ;; READ
+  (func $READ (param $str i32) (result i32)
+    ($read_str $str)
+  )
+
+  ;; EVAL
+  (func $EVAL_AST (param $ast i32) (param $env i32) (result i32)
+    (local $res i32)
+    (local $val2 i32)
+    (local $val3 i32)
+    (local $ret i32)
+    (local $empty i32)
+    (local $current i32)
+    (local $type i32)
+    (local $res2 i64)
+    (local $found i32)
+
+    (if (get_global $error_type) (return 0))
+    (set_local $type ($TYPE $ast))
+
+    ;;; switch(type)
+    (block $done
+      (block $default (block (block
+      (br_table 2 2 2 2 2 0 1 1 1 2 2 2 2 2 2 2 $type))
+      ;; symbol
+      ;; found/res returned as hi 32/lo 32 of i64
+      (set_local $res2 ($HASHMAP_GET $env $ast))
+      (set_local $res (i32.wrap/i64 $res2))
+      (set_local $found (i32.wrap/i64 (i64.shr_u $res2
+                                                 (i64.const 32))))
+      (if (i32.eqz $found)
+          ($THROW_STR_1 "'%s' not found"
+                ($to_String $ast)))
+      (set_local $res ($INC_REF $res))
+
+      (br $done))
+      ;; list, vector, hashmap
+      ;; MAP_LOOP_START
+      (set_local $res ($MAP_LOOP_START $type))
+      ;; push MAP_LOOP stack
+      ;;; empty = current = ret = res
+      (set_local $ret $res)
+      (set_local $current $res)
+      (set_local $empty $res)
+
+      (block $done
+        (loop $loop
+          ;; check if we are done evaluating the source sequence
+          (if (i32.eq ($VAL0 $ast) 0)
+            (br $done))
+
+          (if (i32.eq $type (get_global $HASHMAP_T))
+            (then
+              (set_local $res ($EVAL ($MEM_VAL2_ptr $ast) $env)))
+            (else
+              (set_local $res ($EVAL ($MEM_VAL1_ptr $ast) $env))))
+          (set_local $val2 $res)
+
+          ;; if error, release the unattached element
+          (if (get_global $error_type)
+            (then
+              ($RELEASE $res)
+              (set_local $res 0)
+              (br $done)))
+
+          ;; for hash-maps, copy the key (inc ref since we are going
+          ;; to release it below)
+          (if (i32.eq $type (get_global $HASHMAP_T))
+            (then
+              (set_local $val3 $val2)
+              (set_local $val2 ($MEM_VAL1_ptr $ast))
+              (drop ($INC_REF $ast))))
+
+          ;; MAP_LOOP_UPDATE
+          (set_local $res ($MAP_LOOP_UPDATE $type $empty $current $val2 $val3))
+          (if (i32.le_u $current (get_global $EMPTY_HASHMAP))
+            ;; if first element, set return to new element
+            (set_local $ret $res))
+          ;; update current to point to new element
+          (set_local $current $res)
+
+          (set_local $ast ($MEM_VAL0_ptr $ast))
+
+          (br $loop)
+        )
+      )
+      ;; MAP_LOOP_DONE
+      (set_local $res $ret)
+      ;; EVAL_AST_RETURN: nothing to do
+      (br $done))
+      ;; default
+      (set_local $res ($INC_REF $ast))
+    )
+
+    $res
+  )
+
+  (type $fnT (func (param i32) (result i32)))
+
+  (table anyfunc
+    (elem
+      $add $subtract $multiply $divide))
+
+  (func $EVAL (param $ast i32) (param $env i32) (result i32)
+    (local $res i32)
+    (local $f_args i32)
+    (local $f i32)
+    (local $args i32)
+    (local $type i32)
+    (local $ftype i32)
+
+    (set_local $res 0)
+    (set_local $f_args 0)
+    (set_local $f 0)
+    (set_local $args 0)
+    (set_local $type ($TYPE $ast))
+
+    (if (get_global $error_type) (return 0))
+
+    (if (i32.ne $type (get_global $LIST_T))
+      (return ($EVAL_AST $ast $env)))
+
+    ;; APPLY_LIST
+    (if ($EMPTY_Q $ast) (return ($INC_REF $ast)))
+
+      ;; EVAL_INVOKE
+      (set_local $res ($EVAL_AST $ast $env))
+      (set_local $f_args $res)
+
+      ;; if error, return f/args for release by caller
+      (if (get_global $error_type) (return $f_args))
+
+      ;; rest
+      (set_local $args ($MEM_VAL0_ptr $f_args))
+      ;; value
+      (set_local $f ($MEM_VAL1_ptr $f_args))
+
+      (set_local $ftype ($TYPE $f))
+      (if (i32.eq $ftype (get_global $FUNCTION_T))
+        (then
+          (set_local $res (call_indirect (type $fnT) $args ($VAL0 $f))))
+        (else
+          ($THROW_STR_1 "apply of non-function type: %d\n" $type)
+          (set_local $res 0)))
+
+      ($RELEASE $f_args)
+
+    $res
+  )
+
+  ;; PRINT
+  (func $PRINT (param $ast i32) (result i32)
+    ($pr_str $ast)
+  )
+
+  ;; REPL
+  (func $rep (param $line i32) (param $env i32) (result i32)
+    (local $mv1 i32)
+    (local $mv2 i32)
+    (local $ms i32)
+    (block $rep_done
+      (set_local $mv1 ($READ $line))
+      (if (get_global $error_type) (br $rep_done))
+
+      (set_local $mv2 ($EVAL $mv1 $env))
+      (if (get_global $error_type) (br $rep_done))
+
+;;      ($PR_MEMORY -1 -1)
+      (set_local $ms ($PRINT $mv2))
+    )
+
+    ;; release memory from MAL_READ and EVAL
+    ($RELEASE $mv2)
+    ($RELEASE $mv1)
+    $ms
+  )
+
+  (func $add (param $args i32) (result i32)
+    ($INTEGER
+      (i32.add ($VAL0 ($MEM_VAL1_ptr $args))
+               ($VAL0 ($MEM_VAL1_ptr ($MEM_VAL0_ptr $args))))))
+  (func $subtract (param $args i32) (result i32)
+    ($INTEGER
+      (i32.sub_s ($VAL0 ($MEM_VAL1_ptr $args))
+                 ($VAL0 ($MEM_VAL1_ptr ($MEM_VAL0_ptr $args))))))
+  (func $multiply (param $args i32) (result i32)
+    ($INTEGER
+      (i32.mul_s ($VAL0 ($MEM_VAL1_ptr $args))
+                 ($VAL0 ($MEM_VAL1_ptr ($MEM_VAL0_ptr $args))))))
+  (func $divide (param $args i32) (result i32)
+    ($INTEGER
+      (i32.div_s ($VAL0 ($MEM_VAL1_ptr $args))
+                 ($VAL0 ($MEM_VAL1_ptr ($MEM_VAL0_ptr $args))))))
+
+  (func $main (result i32)
+    ;; Constant location/value definitions
+    (local $line i32)
+    (local $res i32)
+    (local $repl_env i32)
+
+    ;; DEBUG
+    ($printf_1 "memoryBase: 0x%x\n" (get_global $memoryBase))
+    ($printf_1 "heap_start: 0x%x\n" (get_global $heap_start))
+    ($printf_1 "heap_end: 0x%x\n" (get_global $heap_end))
+    ($printf_1 "mem: 0x%x\n" (get_global $mem))
+;;    ($printf_1 "string_mem: %d\n" (get_global $string_mem))
+
+    (set_local $repl_env ($HASHMAP))
+
+    (set_local $repl_env ($ASSOC1_S $repl_env "+" ($FUNCTION 0)))
+    (set_local $repl_env ($ASSOC1_S $repl_env "-" ($FUNCTION 1)))
+    (set_local $repl_env ($ASSOC1_S $repl_env "*" ($FUNCTION 2)))
+    (set_local $repl_env ($ASSOC1_S $repl_env "/" ($FUNCTION 3)))
+
+    ($PR_MEMORY -1 -1)
+;;    ($PR_MEMORY_RAW (get_global $mem)
+;;          (i32.add (get_global $mem)
+;;                   (i32.mul_u (get_global $mem_unused_start)
+;;                              8)))
+
+    ;; Start
+    (block $repl_done
+      (loop $repl_loop
+        (set_local $line ($readline "user> "))
+        (if (i32.eqz $line) (br $repl_done))
+        (if (i32.eq (i32.load8_u $line) 0)
+          (then
+            ($free $line)
+            (br $repl_loop)))
+        (set_local $res ($rep $line $repl_env))
+        (if (get_global $error_type)
+          (then
+            ($printf_1 "Error: %s\n" (get_global $error_str))
+            (set_global $error_type 0))
+          (else
+            ($printf_1 "%s\n" ($to_String $res))))
+        ($RELEASE $res)
+;;        ($PR_MEMORY -1 -1)
+        ($free $line)
+        (br $repl_loop)))
+
+    ($print "\n")
+    ($PR_MEMORY -1 -1)
+    0
+  )
+
+
+  (export "_main" (func $main))
+  (export "__post_instantiate" (func $init_memory))
+)
+
diff --git a/wasm/step2_eval.wast b/wasm/step2_eval.wast
deleted file mode 100644 (file)
index ac30da4..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-(module $step1_read_print
-  (import "env" "memory" (memory $0 256))
-  (import "env" "memoryBase" (global $memoryBase i32))
-
-  ;; READ
-  (func $READ (param $str i32) (result i32)
-    (call $read_str (get_local $str))
-  )
-
-  ;; EVAL
-  (func $EVAL_AST (param $ast i32) (param $env i32) (result i32)
-    (local $res i32)
-    (local $val2 i32)
-    (local $val3 i32)
-    (local $ret i32)
-    (local $empty i32)
-    (local $current i32)
-    (local $type i32)
-    (local $res2 i64)
-    (local $found i32)
-
-    (if (get_global $error_type) (return (i32.const 0)))
-    (set_local $type (call $TYPE (get_local $ast)))
-
-    ;;; switch(type)
-    (block $done
-      (block $default (block (block
-      (br_table 2 2 2 2 2 0 1 1 1 2 2 2 2 2 2 2 (get_local $type)))
-      ;; symbol
-      ;; found/res returned as hi 32/lo 32 of i64
-      (set_local $res2 (call $HASHMAP_GET (get_local $env) (get_local $ast)))
-      (set_local $res (i32.wrap/i64 (get_local $res2)))
-      (set_local $found (i32.wrap/i64 (i64.shr_u (get_local $res2)
-                                                 (i64.const 32))))
-      (if (i32.eqz (get_local $found))
-          (call $THROW_STR_1 (STRING "'%s' not found")
-                (call $to_String (get_local $ast))))
-      (set_local $res (call $INC_REF (get_local $res)))
-
-      (br $done))
-      ;; list, vector, hashmap
-      ;; MAP_LOOP_START
-      (set_local $res (call $MAP_LOOP_START (get_local $type)))
-      ;; push MAP_LOOP stack
-      ;;; empty = current = ret = res
-      (set_local $ret (get_local $res))
-      (set_local $current (get_local $res))
-      (set_local $empty (get_local $res))
-
-      (block $done
-        (loop $loop
-          ;; check if we are done evaluating the source sequence
-          (if (i32.eq (call $VAL0 (get_local $ast)) (i32.const 0))
-            (br $done))
-
-          (if (i32.eq (get_local $type) (get_global $HASHMAP_T))
-            (then
-              (set_local $res (call $EVAL (call $MEM_VAL2_ptr (get_local $ast))
-                                                (get_local $env))))
-            (else
-              (set_local $res (call $EVAL (call $MEM_VAL1_ptr (get_local $ast))
-                                                (get_local $env)))))
-          (set_local $val2 (get_local $res))
-
-          ;; if error, release the unattached element
-          (if (get_global $error_type)
-            (then
-              (call $RELEASE (get_local $res))
-              (set_local $res (i32.const 0))
-              (br $done)))
-
-          ;; for hash-maps, copy the key (inc ref since we are going
-          ;; to release it below)
-          (if (i32.eq (get_local $type) (get_global $HASHMAP_T))
-            (then
-              (set_local $val3 (get_local $val2))
-              (set_local $val2 (call $MEM_VAL1_ptr (get_local $ast)))
-              (drop (call $INC_REF (get_local $ast)))))
-
-          ;; MAP_LOOP_UPDATE
-          (set_local $res (call $MAP_LOOP_UPDATE (get_local $type)
-                                (get_local $empty) (get_local $current)
-                                (get_local $val2) (get_local $val3)))
-          (if (i32.le_u (get_local $current) (get_global $EMPTY_HASHMAP))
-            ;; if first element, set return to new element
-            (set_local $ret (get_local $res)))
-          ;; update current to point to new element
-          (set_local $current (get_local $res))
-
-          (set_local $ast (call $MEM_VAL0_ptr (get_local $ast)))
-  
-          (br $loop)
-        )
-      )
-      ;; MAP_LOOP_DONE
-      (set_local $res (get_local $ret))
-      ;; EVAL_AST_RETURN: nothing to do
-      (br $done))
-      ;; default
-      (set_local $res (call $INC_REF (get_local $ast)))
-    )
-
-    (get_local $res)
-  )
-
-  (type $fnT (func (param i32) (result i32)))
-
-  (table anyfunc
-    (elem
-      $add $subtract $multiply $divide))
-
-  (func $EVAL (param $ast i32) (param $env i32) (result i32)
-    (local $res i32)
-    (local $f_args i32)
-    (local $f i32)
-    (local $args i32)
-    (local $type i32)
-    (local $ftype i32)
-
-    (set_local $res (i32.const 0))
-    (set_local $f_args (i32.const 0))
-    (set_local $f (i32.const 0))
-    (set_local $args (i32.const 0))
-    (set_local $type (call $TYPE (get_local $ast)))
-
-    (if (get_global $error_type) (return (i32.const 0)))
-
-    (if (i32.ne (get_local $type) (get_global $LIST_T))
-      (return (call $EVAL_AST (get_local $ast) (get_local $env))))
-
-    ;; APPLY_LIST
-    (if (call $EMPTY_Q (get_local $ast))
-      (return (call $INC_REF (get_local $ast))))
-
-    ;; EVAL_INVOKE
-    (set_local $res (call $EVAL_AST (get_local $ast) (get_local $env)))
-    (set_local $f_args (get_local $res))
-
-    ;; if error, return f/args for release by caller
-    (if (get_global $error_type) (return (get_local $f_args)))
-
-    ;; rest
-    (set_local $args (call $MEM_VAL0_ptr (get_local $f_args)))
-    ;; value
-    (set_local $f (call $MEM_VAL1_ptr (get_local $f_args)))
-
-    (set_local $ftype (call $TYPE (get_local $f)))
-    (if (i32.eq (get_local $ftype) (get_global $FUNCTION_T))
-      (then
-        (set_local $res (call_indirect (type $fnT) (get_local $args)
-                                       (call $VAL0 (get_local $f)))))
-      (else
-        (call $THROW_STR_1 (STRING "apply of non-function type: %d\n")
-              (get_local $type))
-        (set_local $res (i32.const 0))))
-
-    (call $RELEASE (get_local $f_args))
-
-    (get_local $res)
-  )
-
-  (func $PRINT (param $ast i32) (result i32)
-    (call $pr_str (get_local $ast))
-  )
-
-  ;; REPL
-  (func $rep (param $line i32) (param $env i32) (result i32)
-    (local $mv1 i32)
-    (local $mv2 i32)
-    (local $ms i32)
-    (block $rep_done
-      (set_local $mv1 (call $READ (get_local $line)))
-      (if (get_global $error_type) (br $rep_done))
-
-      (set_local $mv2 (call $EVAL (get_local $mv1) (get_local $env)))
-      (if (get_global $error_type) (br $rep_done))
-
-;;      (call $PR_MEMORY (i32.const -1) (i32.const -1))
-      (set_local $ms (call $PRINT (get_local $mv2)))
-    )
-
-    ;; release memory from MAL_READ and EVAL
-    (call $RELEASE (get_local $mv2))
-    (call $RELEASE (get_local $mv1))
-    (get_local $ms)
-  )
-
-  (func $add (param $args i32) (result i32)
-    (call $INTEGER
-      (i32.add (call $VAL0 (call $MEM_VAL1_ptr (get_local $args)))
-               (call $VAL0 (call $MEM_VAL1_ptr
-                                 (call $MEM_VAL0_ptr (get_local $args)))))))
-  (func $subtract (param $args i32) (result i32)
-    (call $INTEGER
-      (i32.sub_s (call $VAL0 (call $MEM_VAL1_ptr (get_local $args)))
-                 (call $VAL0 (call $MEM_VAL1_ptr
-                                   (call $MEM_VAL0_ptr (get_local $args)))))))
-  (func $multiply (param $args i32) (result i32)
-    (call $INTEGER
-      (i32.mul_s (call $VAL0 (call $MEM_VAL1_ptr (get_local $args)))
-                 (call $VAL0 (call $MEM_VAL1_ptr
-                                   (call $MEM_VAL0_ptr (get_local $args)))))))
-  (func $divide (param $args i32) (result i32)
-    (call $INTEGER
-      (i32.div_s (call $VAL0 (call $MEM_VAL1_ptr (get_local $args)))
-                 (call $VAL0 (call $MEM_VAL1_ptr
-                                   (call $MEM_VAL0_ptr (get_local $args)))))))
-
-  (func $main (result i32)
-    ;; Constant location/value definitions
-    (local $line i32)
-    (local $res i32)
-    (local $repl_env i32)
-
-    ;; DEBUG
-    (call $printf_1 (STRING "memoryBase: %d\n") (get_global $memoryBase))
-    (call $printf_1 (STRING "heap_start: %d\n") (get_global $heap_start))
-    (call $printf_1 (STRING "heap_end: %d\n") (get_global $heap_end))
-    (call $printf_1 (STRING "mem: %d\n") (get_global $mem))
-;;    (call $printf_1 (STRING "string_mem: %d\n") (get_global $string_mem))
-
-    (set_local $repl_env (call $HASHMAP))
-
-    (set_local $repl_env (call $ASSOC1_S (get_local $repl_env)
-                               (STRING "+") (call $FUNCTION (i32.const 0))))
-    (set_local $repl_env (call $ASSOC1_S (get_local $repl_env)
-                               (STRING "-") (call $FUNCTION (i32.const 1))))
-    (set_local $repl_env (call $ASSOC1_S (get_local $repl_env)
-                               (STRING "*") (call $FUNCTION (i32.const 2))))
-    (set_local $repl_env (call $ASSOC1_S (get_local $repl_env)
-                               (STRING "/") (call $FUNCTION (i32.const 3))))
-
-    (call $PR_MEMORY (i32.const -1) (i32.const -1))
-;;    (call $PR_MEMORY_RAW (get_global $mem)
-;;          (i32.add (get_global $mem)
-;;                   (i32.mul_u (get_global $mem_unused_start)
-;;                              (i32.const 8))))
-
-    ;; Start
-    (block $repl_done
-      (loop $repl_loop
-        (set_local $line (call $readline (STRING "user> ")))
-        (if (i32.eqz (get_local $line)) (br $repl_done))
-        (if (i32.eq (i32.load8_u (get_local $line)) (i32.const 0))
-          (then
-            (call $free (get_local $line))
-            (br $repl_loop)))
-        (set_local $res (call $rep (get_local $line) (get_local $repl_env)))
-        (if (get_global $error_type)
-          (then
-            (call $printf_1 (STRING "Error: %s\n") (get_global $error_str))
-            (set_global $error_type (i32.const 0)))
-          (else
-            (call $printf_1 (STRING "%s\n") (call $to_String (get_local $res)))))
-        (call $RELEASE (get_local $res))
-;;        (call $PR_MEMORY (i32.const -1) (i32.const -1))
-        (call $free (get_local $line))
-        (br $repl_loop)))
-
-    (call $print (STRING "\n"))
-    (call $PR_MEMORY (i32.const -1) (i32.const -1))
-    (i32.const 0)
-  )
-
-
-  (export "_main" (func $main))
-  (export "__post_instantiate" (func $init_memory))
-)
-
diff --git a/wasm/step3_env.wam b/wasm/step3_env.wam
new file mode 100644 (file)
index 0000000..8044dff
--- /dev/null
@@ -0,0 +1,308 @@
+(module $step1_read_print
+  (import "env" "memory" (memory $0 256))
+  (import "env" "memoryBase" (global $memoryBase i32))
+
+  ;; READ
+  (func $READ (param $str i32) (result i32)
+    ($read_str $str)
+  )
+
+  ;; EVAL
+  (func $EVAL_AST (param $ast i32) (param $env i32) (result i32)
+    (local $res i32)
+    (local $val2 i32)
+    (local $val3 i32)
+    (local $ret i32)
+    (local $empty i32)
+    (local $current i32)
+    (local $type i32)
+    (local $found i32)
+
+    (if (get_global $error_type) (return 0))
+    (set_local $type ($TYPE $ast))
+
+    ;;; switch(type)
+    (block $done
+      (block $default (block (block
+      (br_table 2 2 2 2 2 0 1 1 1 2 2 2 2 2 2 2 $type))
+      ;; symbol
+      ;; found/res returned as hi 32/lo 32 of i64
+      (set_local $res ($ENV_GET $env $ast))
+      (br $done))
+      ;; list, vector, hashmap
+      ;; MAP_LOOP_START
+      (set_local $res ($MAP_LOOP_START $type))
+      ;; push MAP_LOOP stack
+      ;;; empty = current = ret = res
+      (set_local $ret $res)
+      (set_local $current $res)
+      (set_local $empty $res)
+
+      (block $done
+        (loop $loop
+          ;; check if we are done evaluating the source sequence
+          (if (i32.eq ($VAL0 $ast) 0)
+            (br $done))
+
+          (if (i32.eq $type (get_global $HASHMAP_T))
+            (then
+              (set_local $res ($EVAL ($MEM_VAL2_ptr $ast) $env)))
+            (else
+              (set_local $res ($EVAL ($MEM_VAL1_ptr $ast) $env))))
+          (set_local $val2 $res)
+
+          ;; if error, release the unattached element
+          (if (get_global $error_type)
+            (then
+              ($RELEASE $res)
+              (set_local $res 0)
+              (br $done)))
+
+          ;; for hash-maps, copy the key (inc ref since we are going
+          ;; to release it below)
+          (if (i32.eq $type (get_global $HASHMAP_T))
+            (then
+              (set_local $val3 $val2)
+              (set_local $val2 ($MEM_VAL1_ptr $ast))
+              (drop ($INC_REF $ast))))
+
+          ;; MAP_LOOP_UPDATE
+          (set_local $res ($MAP_LOOP_UPDATE $type $empty $current $val2 $val3))
+          (if (i32.le_u $current (get_global $EMPTY_HASHMAP))
+            ;; if first element, set return to new element
+            (set_local $ret $res))
+          ;; update current to point to new element
+          (set_local $current $res)
+
+          (set_local $ast ($MEM_VAL0_ptr $ast))
+
+          (br $loop)
+        )
+      )
+      ;; MAP_LOOP_DONE
+      (set_local $res $ret)
+      ;; EVAL_AST_RETURN: nothing to do
+      (br $done))
+      ;; default
+      (set_local $res ($INC_REF $ast))
+    )
+
+    $res
+  )
+
+  (type $fnT (func (param i32) (result i32)))
+
+  (table anyfunc
+    (elem
+      $add $subtract $multiply $divide))
+
+  (func $MAL_GET_A1 (param $ast i32) (result i32)
+    ($MEM_VAL1_ptr ($MEM_VAL0_ptr $ast)))
+  (func $MAL_GET_A2 (param $ast i32) (result i32)
+    ($MEM_VAL1_ptr ($MEM_VAL0_ptr ($MEM_VAL0_ptr $ast))))
+  (func $MAL_GET_A3 (param $ast i32) (result i32)
+    ($MEM_VAL1_ptr ($MEM_VAL0_ptr ($MEM_VAL0_ptr ($MEM_VAL0_ptr $ast)))))
+
+  (func $EVAL (param $ast i32) (param $env i32) (result i32)
+    (local $res i32)
+    (local $f_args i32)
+    (local $f i32)
+    (local $args i32)
+    (local $type i32)
+    (local $ftype i32)
+    (local $a0 i32)
+    (local $a0sym i32)
+    (local $a1 i32)
+    (local $a2 i32)
+    (local $let_env i32)
+
+    (set_local $res 0)
+    (set_local $f_args 0)
+    (set_local $f 0)
+    (set_local $args 0)
+    (set_local $type ($TYPE $ast))
+
+    ;;($PR_VALUE ">>> EVAL ast: '%s'\n" $ast)
+
+    (if (get_global $error_type) (return 0))
+
+    (if (i32.ne $type (get_global $LIST_T))
+      (return ($EVAL_AST $ast $env)))
+
+    ;; APPLY_LIST
+    (if ($EMPTY_Q $ast) (return ($INC_REF $ast)))
+
+    (set_local $a0 ($MEM_VAL1_ptr $ast))
+    (set_local $a0sym "")
+    (if (i32.eq ($TYPE $a0) (get_global $SYMBOL_T))
+      (set_local $a0sym ($to_String $a0)))
+
+    (if (i32.eqz ($strcmp "def!" $a0sym))
+      (then
+        (set_local $a1 ($MAL_GET_A1 $ast))
+        (set_local $a2 ($MAL_GET_A2 $ast))
+        (set_local $res ($EVAL $a2 $env))
+        (if (get_global $error_type) (return $res))
+
+        ;; set a1 in env to a2
+        (set_local $res ($ENV_SET $env $a1 $res)))
+    (else (if (i32.eqz ($strcmp "let*" $a0sym))
+      (then
+        (set_local $a1 ($MAL_GET_A1 $ast))
+        (set_local $a2 ($MAL_GET_A2 $ast))
+
+        ;; create new environment with outer as current environment
+        (set_local $let_env ($ENV_NEW $env))
+
+        (block $done
+          (loop $loop
+            (if (i32.eqz ($VAL0 $a1))
+              (br $done))
+            ;; eval current A1 odd element
+            (set_local $res ($EVAL ($MEM_VAL1_ptr ($MEM_VAL0_ptr $a1))
+                                   $let_env))
+
+            (if (get_global $error_type) (br $done))
+
+            ;; set key/value in the let environment
+            (set_local $res ($ENV_SET $let_env ($MEM_VAL1_ptr $a1) $res))
+            ;; release our use, ENV_SET took ownership
+            ($RELEASE $res)
+
+            ;; skip to the next pair of a1 elements
+            (set_local $a1 ($MEM_VAL0_ptr ($MEM_VAL0_ptr $a1)))
+            (br $loop)
+          )
+        )
+        (set_local $res ($EVAL $a2 $let_env))
+        ;; EVAL_RETURN
+        ($RELEASE $let_env))
+    (else
+      ;; EVAL_INVOKE
+      (set_local $res ($EVAL_AST $ast $env))
+      (set_local $f_args $res)
+
+      ;; if error, return f/args for release by caller
+      (if (get_global $error_type) (return $f_args))
+
+      ;; rest
+      (set_local $args ($MEM_VAL0_ptr $f_args))
+      ;; value
+      (set_local $f ($MEM_VAL1_ptr $f_args))
+
+      (set_local $ftype ($TYPE $f))
+      (if (i32.eq $ftype (get_global $FUNCTION_T))
+        (then
+          (set_local $res (call_indirect (type $fnT) $args ($VAL0 $f))))
+        (else
+          ($THROW_STR_1 "apply of non-function type: %d\n" $type)
+          (set_local $res 0)))
+
+      ($RELEASE $f_args)))))
+
+    $res
+  )
+
+  (func $PRINT (param $ast i32) (result i32)
+    ($pr_str $ast)
+  )
+
+  ;; REPL
+  (func $rep (param $line i32) (param $env i32) (result i32)
+    (local $mv1 i32)
+    (local $mv2 i32)
+    (local $ms i32)
+    (block $rep_done
+      (set_local $mv1 ($READ $line))
+      (if (get_global $error_type) (br $rep_done))
+
+      (set_local $mv2 ($EVAL $mv1 $env))
+      (if (get_global $error_type) (br $rep_done))
+
+;;      ($PR_MEMORY -1 -1)
+      (set_local $ms ($PRINT $mv2))
+    )
+
+    ;; release memory from MAL_READ and EVAL
+    ($RELEASE $mv2)
+    ($RELEASE $mv1)
+    $ms
+  )
+
+  (func $add (param $args i32) (result i32)
+    ($INTEGER
+      (i32.add ($VAL0 ($MEM_VAL1_ptr $args))
+               ($VAL0 ($MEM_VAL1_ptr ($MEM_VAL0_ptr $args))))))
+  (func $subtract (param $args i32) (result i32)
+    ($INTEGER
+      (i32.sub_s ($VAL0 ($MEM_VAL1_ptr $args))
+                 ($VAL0 ($MEM_VAL1_ptr ($MEM_VAL0_ptr $args))))))
+  (func $multiply (param $args i32) (result i32)
+    ($INTEGER
+      (i32.mul_s ($VAL0 ($MEM_VAL1_ptr $args))
+                 ($VAL0 ($MEM_VAL1_ptr ($MEM_VAL0_ptr $args))))))
+  (func $divide (param $args i32) (result i32)
+    ($INTEGER
+      (i32.div_s ($VAL0 ($MEM_VAL1_ptr $args))
+                 ($VAL0 ($MEM_VAL1_ptr ($MEM_VAL0_ptr $args))))))
+  (func $pr_memory (param $args i32) (result i32)
+    ($PR_MEMORY -1 -1)
+    ($INC_REF (get_global $NIL)))
+
+  (func $main (result i32)
+    ;; Constant location/value definitions
+    (local $line i32)
+    (local $res i32)
+    (local $repl_env i32)
+
+    ;; DEBUG
+    ($printf_1 "memoryBase: 0x%x\n" (get_global $memoryBase))
+    ($printf_1 "heap_start: 0x%x\n" (get_global $heap_start))
+    ($printf_1 "heap_end: 0x%x\n" (get_global $heap_end))
+    ($printf_1 "mem: 0x%x\n" (get_global $mem))
+;;    ($printf_1 "string_mem: %d\n" (get_global $string_mem))
+
+    (set_local $repl_env ($ENV_NEW (get_global $NIL)))
+
+    (drop ($ENV_SET_S $repl_env "+" ($FUNCTION 0)))
+    (drop ($ENV_SET_S $repl_env "-" ($FUNCTION 1)))
+    (drop ($ENV_SET_S $repl_env "*" ($FUNCTION 2)))
+    (drop ($ENV_SET_S $repl_env "/" ($FUNCTION 3)))
+
+    ($PR_MEMORY -1 -1)
+;;    ($PR_MEMORY_RAW (get_global $mem)
+;;          (i32.add (get_global $mem)
+;;                   (i32.mul_u (get_global $mem_unused_start)
+;;                              8)))
+
+    ;; Start
+    (block $repl_done
+      (loop $repl_loop
+        (set_local $line ($readline "user> "))
+        (if (i32.eqz $line) (br $repl_done))
+        (if (i32.eq (i32.load8_u $line) 0)
+          (then
+            ($free $line)
+            (br $repl_loop)))
+        (set_local $res ($rep $line $repl_env))
+        (if (get_global $error_type)
+          (then
+            ($printf_1 "Error: %s\n" (get_global $error_str))
+            (set_global $error_type 0))
+          (else
+            ($printf_1 "%s\n" ($to_String $res))))
+        ($RELEASE $res)
+;;        ($PR_MEMORY -1 -1)
+        ($free $line)
+        (br $repl_loop)))
+
+    ($print "\n")
+    ($PR_MEMORY -1 -1)
+    0
+  )
+
+
+  (export "_main" (func $main))
+  (export "__post_instantiate" (func $init_memory))
+)
+
diff --git a/wasm/step3_env.wast b/wasm/step3_env.wast
deleted file mode 100644 (file)
index 21afa31..0000000
+++ /dev/null
@@ -1,329 +0,0 @@
-(module $step1_read_print
-  (import "env" "memory" (memory $0 256))
-  (import "env" "memoryBase" (global $memoryBase i32))
-
-  ;; READ
-  (func $READ (param $str i32) (result i32)
-    (call $read_str (get_local $str))
-  )
-
-  ;; EVAL
-  (func $EVAL_AST (param $ast i32) (param $env i32) (result i32)
-    (local $res i32)
-    (local $val2 i32)
-    (local $val3 i32)
-    (local $ret i32)
-    (local $empty i32)
-    (local $current i32)
-    (local $type i32)
-    (local $found i32)
-
-    (if (get_global $error_type) (return (i32.const 0)))
-    (set_local $type (call $TYPE (get_local $ast)))
-
-    ;;; switch(type)
-    (block $done
-      (block $default (block (block
-      (br_table 2 2 2 2 2 0 1 1 1 2 2 2 2 2 2 2 (get_local $type)))
-      ;; symbol
-      ;; found/res returned as hi 32/lo 32 of i64
-      (set_local $res (call $ENV_GET (get_local $env) (get_local $ast)))
-      (br $done))
-      ;; list, vector, hashmap
-      ;; MAP_LOOP_START
-      (set_local $res (call $MAP_LOOP_START (get_local $type)))
-      ;; push MAP_LOOP stack
-      ;;; empty = current = ret = res
-      (set_local $ret (get_local $res))
-      (set_local $current (get_local $res))
-      (set_local $empty (get_local $res))
-
-      (block $done
-        (loop $loop
-          ;; check if we are done evaluating the source sequence
-          (if (i32.eq (call $VAL0 (get_local $ast)) (i32.const 0))
-            (br $done))
-
-          (if (i32.eq (get_local $type) (get_global $HASHMAP_T))
-            (then
-              (set_local $res (call $EVAL (call $MEM_VAL2_ptr (get_local $ast))
-                                                (get_local $env))))
-            (else
-              (set_local $res (call $EVAL (call $MEM_VAL1_ptr (get_local $ast))
-                                                (get_local $env)))))
-          (set_local $val2 (get_local $res))
-
-          ;; if error, release the unattached element
-          (if (get_global $error_type)
-            (then
-              (call $RELEASE (get_local $res))
-              (set_local $res (i32.const 0))
-              (br $done)))
-
-          ;; for hash-maps, copy the key (inc ref since we are going
-          ;; to release it below)
-          (if (i32.eq (get_local $type) (get_global $HASHMAP_T))
-            (then
-              (set_local $val3 (get_local $val2))
-              (set_local $val2 (call $MEM_VAL1_ptr (get_local $ast)))
-              (drop (call $INC_REF (get_local $ast)))))
-
-          ;; MAP_LOOP_UPDATE
-          (set_local $res (call $MAP_LOOP_UPDATE (get_local $type)
-                                (get_local $empty) (get_local $current)
-                                (get_local $val2) (get_local $val3)))
-          (if (i32.le_u (get_local $current) (get_global $EMPTY_HASHMAP))
-            ;; if first element, set return to new element
-            (set_local $ret (get_local $res)))
-          ;; update current to point to new element
-          (set_local $current (get_local $res))
-
-          (set_local $ast (call $MEM_VAL0_ptr (get_local $ast)))
-
-          (br $loop)
-        )
-      )
-      ;; MAP_LOOP_DONE
-      (set_local $res (get_local $ret))
-      ;; EVAL_AST_RETURN: nothing to do
-      (br $done))
-      ;; default
-      (set_local $res (call $INC_REF (get_local $ast)))
-    )
-
-    (get_local $res)
-  )
-
-  (type $fnT (func (param i32) (result i32)))
-
-  (table anyfunc
-    (elem
-      $add $subtract $multiply $divide))
-
-  (func $MAL_GET_A1 (param $ast i32) (result i32)
-    (call $MEM_VAL1_ptr (call $MEM_VAL0_ptr (get_local $ast))))
-  (func $MAL_GET_A2 (param $ast i32) (result i32)
-    (call $MEM_VAL1_ptr (call $MEM_VAL0_ptr (call $MEM_VAL0_ptr (get_local $ast)))))
-  (func $MAL_GET_A3 (param $ast i32) (result i32)
-    (call $MEM_VAL1_ptr (call $MEM_VAL0_ptr (call $MEM_VAL0_ptr (call $MEM_VAL0_ptr (get_local $ast))))))
-
-  (func $EVAL (param $ast i32) (param $env i32) (result i32)
-    (local $res i32)
-    (local $f_args i32)
-    (local $f i32)
-    (local $args i32)
-    (local $type i32)
-    (local $ftype i32)
-    (local $a0 i32)
-    (local $a0sym i32)
-    (local $a1 i32)
-    (local $a2 i32)
-    (local $let_env i32)
-
-    (set_local $res (i32.const 0))
-    (set_local $f_args (i32.const 0))
-    (set_local $f (i32.const 0))
-    (set_local $args (i32.const 0))
-    (set_local $type (call $TYPE (get_local $ast)))
-
-    ;;(call $PR_VALUE (STRING ">>> EVAL ast: '%s'\n") (get_local $ast))
-
-    (if (get_global $error_type) (return (i32.const 0)))
-
-    (if (i32.ne (get_local $type) (get_global $LIST_T))
-      (return (call $EVAL_AST (get_local $ast) (get_local $env))))
-
-    ;; APPLY_LIST
-    (if (call $EMPTY_Q (get_local $ast))
-      (return (call $INC_REF (get_local $ast))))
-
-    (set_local $a0 (call $MEM_VAL1_ptr (get_local $ast)))
-    (set_local $a0sym (STRING ""))
-    (if (i32.eq (call $TYPE (get_local $a0)) (get_global $SYMBOL_T))
-      (set_local $a0sym (call $to_String (get_local $a0))))
-
-    (if (i32.eqz (call $strcmp (STRING "def!") (get_local $a0sym)))
-      (then
-        (set_local $a1 (call $MAL_GET_A1 (get_local $ast)))
-        (set_local $a2 (call $MAL_GET_A2 (get_local $ast)))
-        (set_local $res (call $EVAL (get_local $a2) (get_local $env)))
-        (if (get_global $error_type) (return (get_local $res)))
-
-        ;; set a1 in env to a2
-        (set_local $res (call $ENV_SET (get_local $env)
-                              (get_local $a1) (get_local $res))))
-    (else (if (i32.eqz (call $strcmp (STRING "let*") (get_local $a0sym)))
-      (then
-        (set_local $a1 (call $MAL_GET_A1 (get_local $ast)))
-        (set_local $a2 (call $MAL_GET_A2 (get_local $ast)))
-
-        ;; create new environment with outer as current environment
-        (set_local $let_env (call $ENV_NEW (get_local $env)))
-
-        (block $done
-          (loop $loop
-            (if (i32.eqz (call $VAL0 (get_local $a1)))
-              (br $done))
-            ;; eval current A1 odd element
-            (set_local $res (call $EVAL (call $MEM_VAL1_ptr
-                                              (call $MEM_VAL0_ptr
-                                                    (get_local $a1)))
-                                  (get_local $let_env)))
-
-            (if (get_global $error_type) (br $done))
-
-            ;; set key/value in the let environment
-            (set_local $res (call $ENV_SET (get_local $let_env)
-                                  (call $MEM_VAL1_ptr (get_local $a1))
-                                  (get_local $res)))
-            ;; release our use, ENV_SET took ownership
-            (call $RELEASE (get_local $res))
-
-            ;; skip to the next pair of a1 elements
-            (set_local $a1 (call $MEM_VAL0_ptr
-                                 (call $MEM_VAL0_ptr (get_local $a1))))
-            (br $loop)
-          )
-        )
-        (set_local $res (call $EVAL (get_local $a2) (get_local $let_env)))
-        ;; EVAL_RETURN
-        (call $RELEASE (get_local $let_env)))
-    (else
-      ;; EVAL_INVOKE
-      (set_local $res (call $EVAL_AST (get_local $ast) (get_local $env)))
-      (set_local $f_args (get_local $res))
-
-      ;; if error, return f/args for release by caller
-      (if (get_global $error_type) (return (get_local $f_args)))
-
-      ;; rest
-      (set_local $args (call $MEM_VAL0_ptr (get_local $f_args)))
-      ;; value
-      (set_local $f (call $MEM_VAL1_ptr (get_local $f_args)))
-
-      (set_local $ftype (call $TYPE (get_local $f)))
-      (if (i32.eq (get_local $ftype) (get_global $FUNCTION_T))
-        (then
-          (set_local $res (call_indirect (type $fnT) (get_local $args)
-                                         (call $VAL0 (get_local $f)))))
-        (else
-          (call $THROW_STR_1 (STRING "apply of non-function type: %d\n")
-                (get_local $type))
-          (set_local $res (i32.const 0))))
-
-      (call $RELEASE (get_local $f_args))))))
-
-    (get_local $res)
-  )
-
-  (func $PRINT (param $ast i32) (result i32)
-    (call $pr_str (get_local $ast))
-  )
-
-  ;; REPL
-  (func $rep (param $line i32) (param $env i32) (result i32)
-    (local $mv1 i32)
-    (local $mv2 i32)
-    (local $ms i32)
-    (block $rep_done
-      (set_local $mv1 (call $READ (get_local $line)))
-      (if (get_global $error_type) (br $rep_done))
-
-      (set_local $mv2 (call $EVAL (get_local $mv1) (get_local $env)))
-      (if (get_global $error_type) (br $rep_done))
-
-;;      (call $PR_MEMORY (i32.const -1) (i32.const -1))
-      (set_local $ms (call $PRINT (get_local $mv2)))
-    )
-
-    ;; release memory from MAL_READ and EVAL
-    (call $RELEASE (get_local $mv2))
-    (call $RELEASE (get_local $mv1))
-    (get_local $ms)
-  )
-
-  (func $add (param $args i32) (result i32)
-    (call $INTEGER
-      (i32.add (call $VAL0 (call $MEM_VAL1_ptr (get_local $args)))
-               (call $VAL0 (call $MEM_VAL1_ptr
-                                 (call $MEM_VAL0_ptr (get_local $args)))))))
-  (func $subtract (param $args i32) (result i32)
-    (call $INTEGER
-      (i32.sub_s (call $VAL0 (call $MEM_VAL1_ptr (get_local $args)))
-                 (call $VAL0 (call $MEM_VAL1_ptr
-                                   (call $MEM_VAL0_ptr (get_local $args)))))))
-  (func $multiply (param $args i32) (result i32)
-    (call $INTEGER
-      (i32.mul_s (call $VAL0 (call $MEM_VAL1_ptr (get_local $args)))
-                 (call $VAL0 (call $MEM_VAL1_ptr
-                                   (call $MEM_VAL0_ptr (get_local $args)))))))
-  (func $divide (param $args i32) (result i32)
-    (call $INTEGER
-      (i32.div_s (call $VAL0 (call $MEM_VAL1_ptr (get_local $args)))
-                 (call $VAL0 (call $MEM_VAL1_ptr
-                                   (call $MEM_VAL0_ptr (get_local $args)))))))
-  (func $pr_memory (param $args i32) (result i32)
-    (call $PR_MEMORY (i32.const -1) (i32.const -1))
-    (call $INC_REF (get_global $NIL)))
-
-  (func $main (result i32)
-    ;; Constant location/value definitions
-    (local $line i32)
-    (local $res i32)
-    (local $repl_env i32)
-
-    ;; DEBUG
-    (call $printf_1 (STRING "memoryBase: 0x%x\n") (get_global $memoryBase))
-    (call $printf_1 (STRING "heap_start: 0x%x\n") (get_global $heap_start))
-    (call $printf_1 (STRING "heap_end: 0x%x\n") (get_global $heap_end))
-    (call $printf_1 (STRING "mem: 0x%x\n") (get_global $mem))
-;;    (call $printf_1 (STRING "string_mem: %d\n") (get_global $string_mem))
-
-    (set_local $repl_env (call $ENV_NEW (get_global $NIL)))
-
-    (drop (call $ENV_SET_S (get_local $repl_env)
-                (STRING "+") (call $FUNCTION (i32.const 0))))
-    (drop (call $ENV_SET_S (get_local $repl_env)
-                (STRING "-") (call $FUNCTION (i32.const 1))))
-    (drop (call $ENV_SET_S (get_local $repl_env)
-                (STRING "*") (call $FUNCTION (i32.const 2))))
-    (drop (call $ENV_SET_S (get_local $repl_env)
-                (STRING "/") (call $FUNCTION (i32.const 3))))
-
-    (call $PR_MEMORY (i32.const -1) (i32.const -1))
-;;    (call $PR_MEMORY_RAW (get_global $mem)
-;;          (i32.add (get_global $mem)
-;;                   (i32.mul_u (get_global $mem_unused_start)
-;;                              (i32.const 8))))
-
-    ;; Start
-    (block $repl_done
-      (loop $repl_loop
-        (set_local $line (call $readline (STRING "user> ")))
-        (if (i32.eqz (get_local $line)) (br $repl_done))
-        (if (i32.eq (i32.load8_u (get_local $line)) (i32.const 0))
-          (then
-            (call $free (get_local $line))
-            (br $repl_loop)))
-        (set_local $res (call $rep (get_local $line) (get_local $repl_env)))
-        (if (get_global $error_type)
-          (then
-            (call $printf_1 (STRING "Error: %s\n") (get_global $error_str))
-            (set_global $error_type (i32.const 0)))
-          (else
-            (call $printf_1 (STRING "%s\n") (call $to_String (get_local $res)))))
-        (call $RELEASE (get_local $res))
-;;        (call $PR_MEMORY (i32.const -1) (i32.const -1))
-        (call $free (get_local $line))
-        (br $repl_loop)))
-
-    (call $print (STRING "\n"))
-    (call $PR_MEMORY (i32.const -1) (i32.const -1))
-    (i32.const 0)
-  )
-
-
-  (export "_main" (func $main))
-  (export "__post_instantiate" (func $init_memory))
-)
-
diff --git a/wasm/types.wam b/wasm/types.wam
new file mode 100644 (file)
index 0000000..2e80953
--- /dev/null
@@ -0,0 +1,186 @@
+;; Mal value memory layout
+;;   type           words
+;;   ----------     ----------
+;;   nil            ref/ 0 |  0           |               |
+;;   false          ref/ 1 |  0           |               |
+;;   true           ref/ 1 |  1           |               |
+;;   integer        ref/ 2 | int          |               |
+;;   float          ref/ 3 | ???          |               |
+;;   string/kw      ref/ 4 | string ptr   |               |
+;;   symbol         ref/ 5 | string ptr   |               |
+;;   list           ref/ 6 | next mem idx | val mem idx   |
+;;   vector         ref/ 7 | next mem idx | val mem idx   |
+;;   hashmap        ref/ 8 | next mem idx | key mem idx   | val mem idx
+;;   function       ref/ 9 | fn idx       |               |
+;;   mal function   ref/10 | body mem idx | param mem idx | env mem idx
+;;   macro fn       ref/11 | body mem idx | param mem idx | env mem idx
+;;   atom           ref/12 | val mem idx  |               |
+;;   environment    ref/13 | hmap mem idx | outer mem idx |
+;;   metadata       ref/14 | obj mem idx  | meta mem idx  |
+;;   FREE            sz/15 | next mem idx |               |
+
+(module $types
+
+  (global $NIL_T                  i32 0)
+  (global $BOOLEAN_T              i32 1)
+  (global $INTEGER_T              i32 2)
+  (global $FLOAT_T                i32 3)
+  (global $STRING_T               i32 4)
+  (global $SYMBOL_T               i32 5)
+  (global $LIST_T                 i32 6)
+  (global $VECTOR_T               i32 7)
+  (global $HASHMAP_T              i32 8)
+  (global $FUNCTION_T             i32 9)
+  (global $MALFUNC_T              i32 10)
+  (global $MACRO_T                i32 11)
+  (global $ATOM_T                 i32 12)
+  (global $ENVIRONMENT_T          i32 13)
+  (global $METADATA_T             i32 14)
+  (global $FREE_T                 i32 15)
+
+  (global $error_type             (mut i32) 0)
+  (global $error_val              (mut i32) 0)
+  ;; Index into static string memory (static.wast)
+  (global $error_str              (mut i32) 0)
+
+  (global $NIL                    (mut i32) 0)
+  (global $FALSE                  (mut i32) 0)
+  (global $TRUE                   (mut i32) 0)
+  (global $EMPTY_LIST             (mut i32) 0)
+  (global $EMPTY_VECTOR           (mut i32) 0)
+  (global $EMPTY_HASHMAP          (mut i32) 0)
+
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+  ;; General functions
+
+  (func $INC_REF (param $mv i32) (result i32)
+    (i32.store $mv (i32.add (i32.load $mv) 32))
+    $mv)
+
+  (func $THROW_STR_0 (param $fmt i32)
+    (drop ($sprintf_1 (get_global $error_str) $fmt ""))
+    (set_global $error_type 1))
+
+  (func $THROW_STR_1 (param $fmt i32) (param $v0 i32)
+    (drop ($sprintf_1 (get_global $error_str) $fmt $v0))
+    (set_global $error_type 1))
+
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+  ;; numeric functions
+
+  (func $INTEGER (param $val i32) (result i32)
+    ($ALLOC_SCALAR (get_global $INTEGER_T) $val))
+
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+  ;; sequence functions
+
+  (func $MAP_LOOP_START (param $type i32) (result i32)
+    (local $res i32)
+    (set_local $res (if i32 (i32.eq $type (get_global $LIST_T))
+                      (get_global $EMPTY_LIST)
+                    (else (if i32 (i32.eq $type (get_global $VECTOR_T))
+                      (get_global $EMPTY_VECTOR)
+                    (else (if i32 (i32.eq $type (get_global $HASHMAP_T))
+                      (get_global $EMPTY_HASHMAP)
+                    (else
+                      ($THROW_STR_1 "read_seq invalid type %d" $type)
+                      0)))))))
+
+    ($INC_REF $res)
+  )
+
+  (func $MAP_LOOP_UPDATE (param $type i32) (param $empty i32)
+        (param $current i32) (param $val2 i32) (param $val3 i32)
+        (result i32)
+    (local $res i32)
+
+    (set_local $res ($ALLOC $type $empty $val2 $val3))
+    ;; sequence took ownership
+    ($RELEASE $empty)
+    ($RELEASE $val2)
+    (if (i32.eq $type (get_global $HASHMAP_T))
+      ($RELEASE $val3))
+    (if (i32.gt_u $current (get_global $EMPTY_HASHMAP))
+      ;; if not first element, set current next to point to new element
+      (i32.store ($VAL0_ptr $current) ($MalVal_index $res)))
+
+    $res
+  )
+
+  (func $EMPTY_Q (param $mv i32) (result i32)
+    (i32.eq ($VAL0 $mv) 0)
+  )
+
+  (func $HASHMAP (result i32)
+    ;; just point to static empty hash-map
+    ($INC_REF (get_global $EMPTY_HASHMAP))
+  )
+
+  (func $ASSOC1 (param $hm i32) (param $k i32) (param $v i32) (result i32)
+    (local $res i32)
+    (set_local $res ($ALLOC (get_global $HASHMAP_T) $hm $k $v))
+    ;; we took ownership of previous release
+    ($RELEASE $hm)
+    $res
+  )
+
+  (func $ASSOC1_S (param $hm i32) (param $k i32) (param $v i32) (result i32)
+    (local $kmv i32)
+    (local $res i32)
+    (set_local $kmv ($STRING (get_global $STRING_T) $k))
+    (set_local $res ($ASSOC1 $hm $kmv $v))
+    ;; map took ownership of key
+    ($RELEASE $kmv)
+    $res
+  )
+
+  (func $HASHMAP_GET (param $hm i32) (param $key_mv i32) (result i64)
+    (local $res i32)
+    (local $found i32)
+    (local $key i32)
+    (local $test_key_mv i32)
+
+    (set_local $key ($to_String $key_mv))
+    (set_local $found 0)
+
+
+    (block $done
+      (loop $loop
+        ;;; if (VAL0(hm) == 0)
+        (if (i32.eq ($VAL0 $hm) 0)
+          (then
+            (set_local $res (get_global $NIL))
+            (br $done)))
+        ;;; test_key_mv = MEM_VAL1(hm)
+        (set_local $test_key_mv ($MEM_VAL1_ptr $hm))
+        ;;; if (strcmp(key, to_String(test_key_mv)) == 0)
+        (if (i32.eq ($strcmp $key ($to_String $test_key_mv)) 0)
+          (then
+            (set_local $found 1)
+            (set_local $res ($MEM_VAL2_ptr $hm))
+            (br $done)))
+        (set_local $hm ($MEM_VAL0_ptr $hm))
+
+        (br $loop)
+      )
+    )
+
+    ;; combine found/res as hi 32/low 32 of i64
+    (i64.or (i64.shl_u (i64.extend_u/i32 $found) (i64.const 32))
+            (i64.extend_u/i32 $res))
+  )
+
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+  ;; function functions
+
+  (func $FUNCTION (param $index i32) (result i32)
+    ($ALLOC_SCALAR (get_global $FUNCTION_T) $index)
+  )
+
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+  ;; string functions
+
+  (func $to_String (param $mv i32) (result i32)
+    ;; skip string refcnt
+    (i32.add 4 ($MalVal_val ($MalVal_index $mv) 0)))
+)
diff --git a/wasm/types.wast b/wasm/types.wast
deleted file mode 100644 (file)
index cd1212c..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-;; Mal value memory layout
-;;   type           words
-;;   ----------     ----------
-;;   nil            ref/ 0 |  0           |               |
-;;   false          ref/ 1 |  0           |               |
-;;   true           ref/ 1 |  1           |               |
-;;   integer        ref/ 2 | int          |               |
-;;   float          ref/ 3 | ???          |               |
-;;   string/kw      ref/ 4 | string ptr   |               |
-;;   symbol         ref/ 5 | string ptr   |               |
-;;   list           ref/ 6 | next mem idx | val mem idx   |
-;;   vector         ref/ 7 | next mem idx | val mem idx   |
-;;   hashmap        ref/ 8 | next mem idx | key mem idx   | val mem idx
-;;   function       ref/ 9 | fn idx       |               |
-;;   mal function   ref/10 | body mem idx | param mem idx | env mem idx
-;;   macro fn       ref/11 | body mem idx | param mem idx | env mem idx
-;;   atom           ref/12 | val mem idx  |               |
-;;   environment    ref/13 | hmap mem idx | outer mem idx |
-;;   metadata       ref/14 | obj mem idx  | meta mem idx  |
-;;   FREE            sz/15 | next mem idx |               |
-
-(module $types
-
-  (global $NIL_T                  i32 (i32.const 0))
-  (global $BOOLEAN_T              i32 (i32.const 1))
-  (global $INTEGER_T              i32 (i32.const 2))
-  (global $FLOAT_T                i32 (i32.const 3))
-  (global $STRING_T               i32 (i32.const 4))
-  (global $SYMBOL_T               i32 (i32.const 5))
-  (global $LIST_T                 i32 (i32.const 6))
-  (global $VECTOR_T               i32 (i32.const 7))
-  (global $HASHMAP_T              i32 (i32.const 8))
-  (global $FUNCTION_T             i32 (i32.const 9))
-  (global $MALFUNC_T              i32 (i32.const 10))
-  (global $MACRO_T                i32 (i32.const 11))
-  (global $ATOM_T                 i32 (i32.const 12))
-  (global $ENVIRONMENT_T          i32 (i32.const 13))
-  (global $METADATA_T             i32 (i32.const 14))
-  (global $FREE_T                 i32 (i32.const 15))
-
-  (global $error_type             (mut i32) (i32.const 0))
-  (global $error_val              (mut i32) (i32.const 0))
-  ;; Index into static string memory (static.wast)
-  (global $error_str              (mut i32) (i32.const 0))
-
-  (global $NIL                    (mut i32) (i32.const 0))
-  (global $FALSE                  (mut i32) (i32.const 0))
-  (global $TRUE                   (mut i32) (i32.const 0))
-  (global $EMPTY_LIST             (mut i32) (i32.const 0))
-  (global $EMPTY_VECTOR           (mut i32) (i32.const 0))
-  (global $EMPTY_HASHMAP          (mut i32) (i32.const 0))
-
-  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-  ;; General functions
-
-  (func $INC_REF (param $mv i32) (result i32)
-    (i32.store (get_local $mv)
-               (i32.add (i32.load (get_local $mv))
-                        (i32.const 32)))
-    (get_local $mv))
-
-  (func $THROW_STR_0 (param $fmt i32)
-    (drop (call $sprintf_1 (get_global $error_str) (get_local $fmt) (STRING "")))
-    (set_global $error_type (i32.const 1)))
-
-  (func $THROW_STR_1 (param $fmt i32) (param $v0 i32)
-    (drop (call $sprintf_1 (get_global $error_str) (get_local $fmt) (get_local $v0)))
-    (set_global $error_type (i32.const 1)))
-
-  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-  ;; numeric functions
-
-  (func $INTEGER (param $val i32) (result i32)
-    (call $ALLOC_SCALAR (get_global $INTEGER_T) (get_local $val)))
-
-  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-  ;; sequence functions
-
-  (func $MAP_LOOP_START (param $type i32) (result i32)
-    (local $res i32)
-    (set_local $res (if i32 (i32.eq (get_local $type)
-                                    (get_global $LIST_T))
-                      (get_global $EMPTY_LIST)
-                    (else (if i32 (i32.eq (get_local $type)
-                                            (get_global $VECTOR_T))
-                      (get_global $EMPTY_VECTOR)
-                    (else (if i32 (i32.eq (get_local $type)
-                                          (get_global $HASHMAP_T))
-                      (get_global $EMPTY_HASHMAP)
-                    (else
-                      (call $THROW_STR_1 (STRING "read_seq invalid type %d")
-                            (get_local $type))
-                      (i32.const 0))))))))
-
-    (call $INC_REF (get_local $res))
-  )
-
-  (func $MAP_LOOP_UPDATE (param $type i32) (param $empty i32)
-        (param $current i32) (param $val2 i32) (param $val3 i32)
-        (result i32)
-    (local $res i32)
-
-    (set_local $res (call $ALLOC (get_local $type) (get_local $empty)
-                          (get_local $val2) (get_local $val3)))
-    ;; sequence took ownership
-    (call $RELEASE (get_local $empty))
-    (call $RELEASE (get_local $val2))
-    (if (i32.eq (get_local $type) (get_global $HASHMAP_T))
-      (call $RELEASE (get_local $val3)))
-    (if (i32.gt_u (get_local $current) (get_global $EMPTY_HASHMAP))
-      ;; if not first element, set current next to point to new element
-      (i32.store (call $VAL0_ptr (get_local $current))
-                 (call $MalVal_index (get_local $res))))
-
-    (get_local $res)
-  )
-
-  (func $EMPTY_Q (param $mv i32) (result i32)
-    (i32.eq (call $VAL0 (get_local $mv)) (i32.const 0))
-  )
-
-  (func $HASHMAP (result i32)
-    ;; just point to static empty hash-map
-    (call $INC_REF (get_global $EMPTY_HASHMAP))
-  )
-
-  (func $ASSOC1 (param $hm i32) (param $k i32) (param $v i32) (result i32)
-    (local $res i32)
-    (set_local $res (call $ALLOC (get_global $HASHMAP_T) (get_local $hm)
-                          (get_local $k) (get_local $v)))
-    ;; we took ownership of previous release
-    (call $RELEASE (get_local $hm))
-    (get_local $res)
-  )
-
-  (func $ASSOC1_S (param $hm i32) (param $k i32) (param $v i32) (result i32)
-    (local $kmv i32)
-    (local $res i32)
-    (set_local $kmv (call $STRING (get_global $STRING_T) (get_local $k)))
-    (set_local $res (call $ASSOC1 (get_local $hm)
-                          (get_local $kmv) (get_local $v)))
-    ;; map took ownership of key
-    (call $RELEASE (get_local $kmv))
-    (get_local $res)
-  )
-
-  (func $HASHMAP_GET (param $hm i32) (param $key_mv i32) (result i64)
-    (local $res i32)
-    (local $found i32)
-    (local $key i32)
-    (local $test_key_mv i32)
-
-    (set_local $key (call $to_String (get_local $key_mv)))
-    (set_local $found (i32.const 0))
-
-
-    (block $done
-      (loop $loop
-        ;;; if (VAL0(hm) == 0)
-        (if (i32.eq (call $VAL0 (get_local $hm)) (i32.const 0))
-          (then
-            (set_local $res (get_global $NIL))
-            (br $done)))
-        ;;; test_key_mv = MEM_VAL1(hm)
-        (set_local $test_key_mv (call $MEM_VAL1_ptr (get_local $hm)))
-        ;;; if (strcmp(key, to_String(test_key_mv)) == 0)
-        (if (i32.eq (call $strcmp (get_local $key)
-                          (call $to_String (get_local $test_key_mv)))
-                    (i32.const 0))
-          (then
-            (set_local $found (i32.const 1))
-            (set_local $res (call $MEM_VAL2_ptr (get_local $hm)))
-            (br $done)))
-        (set_local $hm (call $MEM_VAL0_ptr (get_local $hm)))
-
-        (br $loop)
-      )
-    )
-
-    ;; combine found/res as hi 32/low 32 of i64
-    (i64.or
-      (i64.shl_u (i64.extend_u/i32 (get_local $found))
-                 (i64.const 32))
-      (i64.extend_u/i32 (get_local $res)))
-  )
-
-  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-  ;; function functions
-
-  (func $FUNCTION (param $index i32) (result i32)
-    (call $ALLOC_SCALAR (get_global $FUNCTION_T) (get_local $index))
-  )
-
-  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-  ;; string functions
-
-  (func $to_String (param $mv i32) (result i32)
-    (i32.add (i32.const 4) ;; skip string refcnt
-             (call $MalVal_val
-                   (call $MalVal_index (get_local $mv))
-                   (i32.const 0))))
-)
diff --git a/wasm/util.wam b/wasm/util.wam
new file mode 100644 (file)
index 0000000..e663d4a
--- /dev/null
@@ -0,0 +1,254 @@
+(module $util
+  (import "env" "malloc" (func $malloc (param i32) (result i32)))
+  (import "env" "free" (func $free (param i32)))
+  (import "env" "exit" (func $exit (param i32)))
+
+  (import "env" "stdout" (global $stdout i32))
+  (import "env" "putchar" (func $putchar (param i32) (result i32)))
+  (import "env" "fputs" (func $fputs (param i32 i32) (result i32)))
+  ;;(import "env" "readline" (func $readline (param i32) (result i32)))
+  (import "libedit.so" "readline" (func $readline (param i32) (result i32)))
+  ;;(import "libreadline.so" "readline" (func $readline (param i32) (result i32)))
+
+  (global $sprintf_buf (mut i32) 0)
+
+  (func $init_sprintf_mem
+    ;; 256 character sprintf static buffer
+    (set_global $sprintf_buf "                                                                                                                                                                                                                                                                ")
+    )
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+  ;; Copy len chatacters from src to dst
+  ;; Returns len
+  (func $MEM_COPY (param $dst i32) (param $src i32) (param $len i32)
+    (local $idx i32)
+    (set_local $idx 0)
+    (loop $copy
+          (i32.store8_u (i32.add $idx $dst)
+                        (i32.load8_u (i32.add $idx $src)))
+      (set_local $idx (i32.add 1 $idx))
+      (br_if $copy (i32.lt_u $idx $len))
+    )
+  )
+
+  (func $STRING_LEN (param $str i32) (result i32)
+    (local $cur i32)
+    (set_local $cur $str)
+    (loop $count
+      (if (i32.ne 0 (i32.load8_u $cur))
+        (then
+          (set_local $cur (i32.add $cur 1))
+          (br $count)))
+    )
+    (i32.sub_u $cur $str)
+  )
+
+  (func $ATOI (param $str i32) (result i32)
+    (local $acc i32)
+    (local $i i32)
+    (local $neg i32)
+    (local $ch i32)
+    (set_local $acc 0)
+    (set_local $i 0)
+    (set_local $neg 0)
+    (block $done
+      (loop $loop
+        (set_local $ch (i32.load8_u (i32.add $str $i)))
+        (if (i32.and (i32.ne $ch (CHR "-"))
+                     (i32.or (i32.lt_u $ch (CHR "0"))
+                             (i32.gt_u $ch (CHR "9"))))
+          (br $done))
+        (set_local $i (i32.add $i 1))
+        (if (i32.eq $ch (CHR "-"))
+          (then
+            (set_local $neg 1))
+          (else
+            (set_local $acc (i32.add (i32.mul_u $acc 10)
+                                     (i32.sub_u $ch (CHR "0"))))))
+        (br $loop)
+      )
+    )
+    (if i32 $neg
+      (then (i32.sub_s 0 $acc))
+      (else $acc))
+  )
+
+  (func $strcmp (param $s1 i32) (param $s2 i32) (result i32)
+    (block $done
+      (loop $loop
+        (if (i32.or (i32.eqz (i32.load8_u $s1))
+                    (i32.eqz (i32.load8_u $s2)))
+          (br $done))
+        (if (i32.ne (i32.load8_u $s1)
+                    (i32.load8_u $s2))
+          (br $done))
+        (set_local $s1 (i32.add $s1 1))
+        (set_local $s2 (i32.add $s2 1))
+        (br $loop)
+      )
+    )
+    (if i32 (i32.eq (i32.load8_u $s1)
+                    (i32.load8_u $s2))
+      (then 0)
+      (else
+        (if i32 (i32.lt_u (i32.load8_u $s1)
+                          (i32.load8_u $s2))
+          (then -1)
+          (else 1))))
+  )
+
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+  (func $print (param $addr i32)
+    (drop ($fputs $addr (get_global $stdout))))
+
+  (func $printf_1 (param $fmt i32)
+        (param $v0 i32)
+    (drop ($sprintf_6 (get_global $sprintf_buf) $fmt $v0 0 0 0 0 0))
+    ($print (get_global $sprintf_buf))
+  )
+
+  (func $printf_2 (param $fmt i32)
+        (param $v0 i32) (param $v1 i32)
+    (drop ($sprintf_6 (get_global $sprintf_buf) $fmt $v0 $v1 0 0 0 0))
+    ($print (get_global $sprintf_buf))
+  )
+
+  (func $printf_3 (param $fmt i32)
+        (param $v0 i32) (param $v1 i32) (param $v2 i32)
+    (drop ($sprintf_6 (get_global $sprintf_buf) $fmt $v0 $v1 $v2 0 0 0))
+    ($print (get_global $sprintf_buf))
+  )
+
+  (func $printf_4 (param $fmt i32)
+        (param $v0 i32) (param $v1 i32) (param $v2 i32)
+        (param $v3 i32)
+    (drop ($sprintf_6 (get_global $sprintf_buf) $fmt $v0 $v1 $v2 $v3 0 0))
+    ($print (get_global $sprintf_buf))
+  )
+
+  (func $printf_5 (param $fmt i32)
+        (param $v0 i32) (param $v1 i32) (param $v2 i32)
+        (param $v3 i32) (param $v4 i32)
+    (drop ($sprintf_6 (get_global $sprintf_buf) $fmt $v0 $v1 $v2 $v3 $v4 0))
+    ($print (get_global $sprintf_buf))
+  )
+
+  (func $printf_6 (param $fmt i32)
+        (param $v0 i32) (param $v1 i32) (param $v2 i32)
+        (param $v3 i32) (param $v4 i32) (param $v5 i32)
+    (drop ($sprintf_6 (get_global $sprintf_buf) $fmt $v0 $v1 $v2 $v3 $v4 $v5))
+    ($print (get_global $sprintf_buf))
+  )
+
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+  (func $_sprintdigit (param $str i32) (param $num i32) (param $base i32)
+    (local $n i32)
+    (local $ch i32)
+    (set_local $n (i32.rem_u $num $base))
+    (set_local $ch (if (result i32) (i32.lt_u $n 10)
+                     48
+                     55))
+    (i32.store8_u $str (i32.add $n $ch))
+  )
+
+  ;; TODO: switch to snprint* (add buffer len)
+  (func $_sprintnum (param $str i32) (param $num i32) (param $base i32)
+                  (result i32)
+    (if (i32.and (i32.eq $base 10)
+                 (i32.lt_s $num 0))
+      (then
+        ;; Print '-' if negative
+        (i32.store8_u $str (CHR "-"))
+        (set_local $str (i32.add $str 1))
+        ;; Reverse the sign
+        (set_local $num (i32.sub_s 0 $num))))
+    (if (i32.gt_u (i32.div_u $num $base) 0)
+      (set_local
+        $str
+        ($_sprintnum $str (i32.div_u $num $base) $base)))
+    ($_sprintdigit $str $num $base)
+    (i32.add 1 $str)
+  )
+
+  ;; TODO: switch to snprint* (add buffer len)
+  (func $sprintf_1 (param $str i32) (param $fmt i32)
+        (param $v0 i32) (result i32)
+    ($sprintf_6 $str $fmt $v0 0 0 0 0 0)
+  )
+
+  (func $sprintf_6 (param $str i32) (param $fmt i32)
+        (param $v0 i32) (param $v1 i32) (param $v2 i32)
+        (param $v3 i32) (param $v4 i32) (param $v5 i32)
+        (result i32)
+    (local $ch i32)
+    (local $pstr i32)
+    (local $v i32)
+    (local $vidx i32)
+    (local $len i32)
+    (set_local $pstr $str)
+    (set_local $vidx 0)
+
+    (block $done
+      (loop $loop
+        (block $after_v
+          (block (block (block (block (block (block
+          (br_table 0 1 2 3 4 5 0 $vidx))
+          (; 0 ;) (set_local $v $v0) (br $after_v))
+          (; 1 ;) (set_local $v $v1) (br $after_v))
+          (; 2 ;) (set_local $v $v2) (br $after_v))
+          (; 3 ;) (set_local $v $v3) (br $after_v))
+          (; 4 ;) (set_local $v $v4) (br $after_v))
+          (; 5 ;) (set_local $v $v5) (br $after_v)
+        )
+
+        ;;; while ((ch=*(fmt++)))
+        (set_local $ch (i32.load8_u $fmt))
+        (set_local $fmt (i32.add 1 $fmt))
+        (if (i32.eqz $ch) (br $done))
+        ;; TODO: check buffer length
+
+        (if (i32.ne $ch (CHR "%"))
+          (then
+            ;; TODO: check buffer length
+            (i32.store8_u $pstr $ch)
+            (set_local $pstr (i32.add 1 $pstr))
+            (br $loop)))
+
+        ;;; ch=*(fmt++)
+        (set_local $ch (i32.load8_u $fmt))
+        (set_local $fmt (i32.add 1 $fmt))
+
+        (if (i32.eq (CHR "d") $ch)
+          (then
+            (set_local $pstr ($_sprintnum $pstr $v 10)))
+        (else (if (i32.eq (CHR "x") $ch)
+          (then
+            (set_local $pstr ($_sprintnum $pstr $v 10)))
+        (else (if (i32.eq (CHR "s") $ch)
+          (then
+            (set_local $len ($STRING_LEN $v))
+            ($MEM_COPY $pstr $v $len)
+            (set_local $pstr (i32.add $pstr $len)))
+        (else (if (i32.eq (CHR "c") $ch)
+          (then
+            (i32.store8_u $pstr $v)
+            (set_local $pstr (i32.add $pstr 1)))
+        (else
+          ($print "Illegal format character: ")
+          (drop ($putchar $ch))
+          (drop ($putchar (CHR "\n")))
+          ($exit 3)))))))))
+
+        (set_local $vidx (i32.add 1 $vidx))
+        (br $loop)
+      )
+    )
+
+    (i32.store8_u $pstr (CHR "\x00"))
+    $pstr
+  )
+
+)
+
diff --git a/wasm/util.wast b/wasm/util.wast
deleted file mode 100644 (file)
index acbe122..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-(module $util
-  (import "env" "malloc" (func $malloc (param i32) (result i32)))
-  (import "env" "free" (func $free (param i32)))
-  (import "env" "exit" (func $exit (param i32)))
-
-  (import "env" "stdout" (global $stdout i32))
-  (import "env" "putchar" (func $putchar (param i32) (result i32)))
-  (import "env" "fputs" (func $fputs (param i32 i32) (result i32)))
-  ;;(import "env" "readline" (func $readline (param i32) (result i32)))
-  (import "libedit.so" "readline" (func $readline (param i32) (result i32)))
-  ;;(import "libreadline.so" "readline" (func $readline (param i32) (result i32)))
-
-  (global $sprintf_buf (mut i32) (i32.const 0))
-
-  (func $init_sprintf_mem
-    ;; 256 character sprintf static buffer
-    (set_global $sprintf_buf (STRING "                                                                                                                                                                                                                                                                "))
-    )
-  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-  ;; Copy len chatacters from src to dst
-  ;; Returns len
-  (func $MEM_COPY (param $dst i32) (param $src i32) (param $len i32)
-    (local $idx i32)
-    (set_local $idx (i32.const 0))
-    (loop $copy
-          (i32.store8_u (i32.add (get_local $idx) (get_local $dst))
-                        (i32.load8_u (i32.add (get_local $idx)
-                                              (get_local $src))))
-      (set_local $idx (i32.add (i32.const 1) (get_local $idx)))
-      (br_if $copy (i32.lt_u (get_local $idx) (get_local $len)))
-    )
-  )
-
-  (func $STRING_LEN (param $str i32) (result i32)
-    (local $cur i32)
-    (set_local $cur (get_local $str))
-    (loop $count
-      (if (i32.ne (i32.const 0) (i32.load8_u (get_local $cur)))
-        (then
-          (set_local $cur (i32.add (get_local $cur) (i32.const 1)))
-          (br $count)))
-    )
-    (i32.sub_u (get_local $cur) (get_local $str))
-  )
-
-  (func $ATOI (param $str i32) (result i32)
-    (local $acc i32)
-    (local $i i32)
-    (local $neg i32)
-    (local $ch i32)
-    (set_local $acc (i32.const 0))
-    (set_local $i (i32.const 0))
-    (set_local $neg (i32.const 0))
-    (block $done
-      (loop $loop
-        (set_local $ch (i32.load8_u (i32.add (get_local $str)
-                                             (get_local $i))))
-        (if (i32.and (i32.ne (get_local $ch) (CHAR '-'))
-                     (i32.or (i32.lt_u (get_local $ch) (CHAR '0'))
-                             (i32.gt_u (get_local $ch) (CHAR '9'))))
-          (br $done))
-        (set_local $i (i32.add (get_local $i) (i32.const 1)))
-        (if (i32.eq (get_local $ch) (CHAR '-'))
-          (then
-            (set_local $neg (i32.const 1)))
-          (else
-            (set_local $acc (i32.add (i32.mul_u (get_local $acc) (i32.const 10))
-                                     (i32.sub_u (get_local $ch) (CHAR '0'))))))
-        (br $loop)
-      )
-    )
-    (if i32 (get_local $neg)
-      (then (i32.sub_s (i32.const 0) (get_local $acc)))
-      (else (get_local $acc)))
-  )
-
-  (func $strcmp (param $s1 i32) (param $s2 i32) (result i32)
-    (block $done
-      (loop $loop
-        (if (i32.or (i32.eqz (i32.load8_u (get_local $s1)))
-                    (i32.eqz (i32.load8_u (get_local $s2))))
-          (br $done))
-        (if (i32.ne (i32.load8_u (get_local $s1))
-                    (i32.load8_u (get_local $s2)))
-          (br $done))
-        (set_local $s1 (i32.add (get_local $s1) (i32.const 1)))
-        (set_local $s2 (i32.add (get_local $s2) (i32.const 1)))
-        (br $loop)
-      )
-    )
-    (if i32 (i32.eq (i32.load8_u (get_local $s1))
-                    (i32.load8_u (get_local $s2)))
-      (then (i32.const 0))
-      (else
-        (if i32 (i32.lt_u (i32.load8_u (get_local $s1))
-                          (i32.load8_u (get_local $s2)))
-          (then (i32.const -1))
-          (else (i32.const 1)))))
-  )
-
-  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-  (func $print (param $addr i32)
-    (drop (call $fputs (get_local $addr) (get_global $stdout))))
-
-  (func $printf_1 (param $fmt i32)
-        (param $v0 i32)
-    (drop (call $sprintf_6 (get_global $sprintf_buf) (get_local $fmt)
-                (get_local $v0) (i32.const 0) (i32.const 0)
-                (i32.const 0) (i32.const 0) (i32.const 0)))
-    (call $print (get_global $sprintf_buf))
-  )
-
-  (func $printf_2 (param $fmt i32)
-        (param $v0 i32) (param $v1 i32)
-    (drop (call $sprintf_6 (get_global $sprintf_buf) (get_local $fmt)
-                (get_local $v0) (get_local $v1) (i32.const 0)
-                (i32.const 0) (i32.const 0) (i32.const 0)))
-    (call $print (get_global $sprintf_buf))
-  )
-
-  (func $printf_3 (param $fmt i32)
-        (param $v0 i32) (param $v1 i32) (param $v2 i32)
-    (drop (call $sprintf_6 (get_global $sprintf_buf) (get_local $fmt)
-                (get_local $v0) (get_local $v1) (get_local $v2)
-                (i32.const 0) (i32.const 0) (i32.const 0)))
-    (call $print (get_global $sprintf_buf))
-  )
-
-  (func $printf_4 (param $fmt i32)
-        (param $v0 i32) (param $v1 i32) (param $v2 i32)
-        (param $v3 i32)
-    (drop (call $sprintf_6 (get_global $sprintf_buf) (get_local $fmt)
-                (get_local $v0) (get_local $v1) (get_local $v2)
-                (get_local $v3) (i32.const 0) (i32.const 0)))
-    (call $print (get_global $sprintf_buf))
-  )
-
-  (func $printf_5 (param $fmt i32)
-        (param $v0 i32) (param $v1 i32) (param $v2 i32)
-        (param $v3 i32) (param $v4 i32)
-    (drop (call $sprintf_6 (get_global $sprintf_buf) (get_local $fmt)
-                (get_local $v0) (get_local $v1) (get_local $v2)
-                (get_local $v3) (get_local $v4) (i32.const 0)))
-    (call $print (get_global $sprintf_buf))
-  )
-
-  (func $printf_6 (param $fmt i32)
-        (param $v0 i32) (param $v1 i32) (param $v2 i32)
-        (param $v3 i32) (param $v4 i32) (param $v5 i32)
-    (drop (call $sprintf_6 (get_global $sprintf_buf) (get_local $fmt)
-                (get_local $v0) (get_local $v1) (get_local $v2)
-                (get_local $v3) (get_local $v4) (get_local $v5)))
-    (call $print (get_global $sprintf_buf))
-  )
-
-  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-  (func $_sprintdigit (param $str i32) (param $num i32) (param $base i32)
-    (local $n i32)
-    (local $ch i32)
-    (set_local $n (i32.rem_u (get_local $num) (get_local $base)))
-    (set_local $ch (if (result i32) (i32.lt_u (get_local $n) (i32.const 10))
-                     (i32.const 48)
-                     (i32.const 55)))
-    (i32.store8_u (get_local $str) (i32.add (get_local $n) (get_local $ch)))
-  )
-
-  ;; TODO: switch to snprint* (add buffer len)
-  (func $_sprintnum (param $str i32) (param $num i32) (param $base i32)
-                  (result i32)
-    (if (i32.and (i32.eq (get_local $base) (i32.const 10))
-                 (i32.lt_s (get_local $num) (i32.const 0)))
-      (then
-        ;; Print '-' if negative
-        (i32.store8_u (get_local $str) (CHAR '-'))
-        (set_local $str (i32.add (get_local $str) (i32.const 1)))
-        ;; Reverse the sign
-        (set_local $num (i32.sub_s (i32.const 0) (get_local $num)))))
-    (if (i32.gt_u (i32.div_u (get_local $num) (get_local $base))
-                  (i32.const 0))
-      (set_local
-        $str
-        (call $_sprintnum (get_local $str)
-              (i32.div_u (get_local $num) (get_local $base))
-              (get_local $base))))
-    (call $_sprintdigit (get_local $str) (get_local $num) (get_local $base))
-    (i32.add (i32.const 1) (get_local $str))
-  )
-
-  ;; TODO: switch to snprint* (add buffer len)
-  (func $sprintf_1 (param $str i32) (param $fmt i32)
-        (param $v0 i32) (result i32)
-    (call $sprintf_6 (get_local $str) (get_local $fmt)
-          (get_local $v0) (i32.const 0) (i32.const 0)
-          (i32.const 0) (i32.const 0) (i32.const 0))
-  )
-
-  (func $sprintf_6 (param $str i32) (param $fmt i32)
-        (param $v0 i32) (param $v1 i32) (param $v2 i32)
-        (param $v3 i32) (param $v4 i32) (param $v5 i32)
-        (result i32)
-    (local $ch i32)
-    (local $pstr i32)
-    (local $v i32)
-    (local $vidx i32)
-    (local $len i32)
-    (set_local $pstr (get_local $str))
-    (set_local $vidx (i32.const 0))
-
-    (block $done
-      (loop $loop
-        (block $after_v
-          (block (block (block (block (block (block
-          (br_table 0 1 2 3 4 5 0 (get_local $vidx)))
-          (; 0 ;) (set_local $v (get_local $v0)) (br $after_v))
-          (; 1 ;) (set_local $v (get_local $v1)) (br $after_v))
-          (; 2 ;) (set_local $v (get_local $v2)) (br $after_v))
-          (; 3 ;) (set_local $v (get_local $v3)) (br $after_v))
-          (; 4 ;) (set_local $v (get_local $v4)) (br $after_v))
-          (; 5 ;) (set_local $v (get_local $v5)) (br $after_v)
-        )
-
-        ;;; while ((ch=*(fmt++)))
-        (set_local $ch (i32.load8_u (get_local $fmt)))
-        (set_local $fmt (i32.add (i32.const 1) (get_local $fmt)))
-        (if (i32.eqz (get_local $ch)) (br $done))
-        ;; TODO: check buffer length
-
-        (if (i32.ne (get_local $ch) (CHAR '%'))
-          (then
-            ;; TODO: check buffer length
-            (i32.store8_u (get_local $pstr) (get_local $ch))
-            (set_local $pstr (i32.add (i32.const 1) (get_local $pstr)))
-            (br $loop)))
-
-        ;;; ch=*(fmt++)
-        (set_local $ch (i32.load8_u (get_local $fmt)))
-        (set_local $fmt (i32.add (i32.const 1) (get_local $fmt)))
-
-        (if (i32.eq (CHAR 'd') (get_local $ch))
-          (then
-            (set_local $pstr (call $_sprintnum (get_local $pstr)
-                                   (get_local $v) (i32.const 10))))
-        (else (if (i32.eq (CHAR 'x') (get_local $ch))
-          (then
-            (set_local $pstr (call $_sprintnum (get_local $pstr)
-                                   (get_local $v) (i32.const 16))))
-        (else (if (i32.eq (CHAR 's') (get_local $ch))
-          (then
-            (set_local $len (call $STRING_LEN (get_local $v)))
-            (call $MEM_COPY (get_local $pstr) (get_local $v) (get_local $len))
-            (set_local $pstr (i32.add (get_local $pstr) (get_local $len))))
-        (else (if (i32.eq (CHAR 'c') (get_local $ch))
-          (then
-            (i32.store8_u (get_local $pstr) (get_local $v))
-            (set_local $pstr (i32.add (get_local $pstr) (i32.const 1))))
-        (else
-          (call $print (STRING "Illegal format character: "))
-          (drop (call $putchar (get_local $ch)))
-          (drop (call $putchar (CHAR '\n')))
-          (call $exit (i32.const 3))))))))))
-
-        (set_local $vidx (i32.add (i32.const 1) (get_local $vidx)))
-        (br $loop)
-      )
-    )
-
-    (i32.store8_u (get_local $pstr) (CHAR '\x00'))
-    (get_local $pstr)
-  )
-
-)
-
diff --git a/wasm/wastpp.py b/wasm/wastpp.py
deleted file mode 100755 (executable)
index 22266df..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-#!/usr/bin/env python3
-
-from itertools import tee
-from ast import literal_eval
-import os
-import pprint
-import re
-import sys
-
-def pairwise(iterable):
-    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
-    a, b = tee(iterable)
-    next(b, None)
-    return zip(a, b)
-
-def _escape(s):
-    return s.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n')
-
-
-tokre = re.compile(r"""([\s][\s]*|[(];|;[)]|[\[\]{}()`~^@]|'(?:[\\].|[^\\'])*'?|"(?:[\\].|[^\\"])*"?|;;.*|[^\s\[\]{}()'"`@,;]+)""")
-
-file_tokens = []
-strings = []
-string_map = {}
-
-depth = 0
-module = None
-type = None
-
-for f in sys.argv[1:]:
-    content = open(f).read()
-    tokens = [t for t in re.findall(tokre, content)]
-    #print(tokens[0:100], file=sys.stderr)
-    pairs = ["".join(p) for p in pairwise(tokens)]
-    pairs.append("")
-
-    index = 0
-    while index < len(tokens):
-        token = tokens[index]
-        pair = pairs[index]
-        if pair in ["(STRING", "(CHAR"]:
-            arg = tokens[index+3]
-            #print("arg: %s" % arg, file=sys.stderr)
-            if tokens[index+4] != ')':
-                raise Exception("Invalid %s) macro, too many/few args" % pair)
-            if arg.startswith('"') and arg.endswith('"'):
-                pass
-            elif arg.startswith("'") and arg.endswith("'"):
-                pass
-            else:
-                raise Exception ("Invalid %s) macro, invalid string arg" % pair)
-            if pair == "(STRING":
-                str = literal_eval(arg)
-                if str in string_map:
-                    # Duplicate string, re-use address
-                    file_tokens.append("(i32.add (get_global $memoryBase) (get_global %s))" % string_map[str])
-                else:
-                    str_name = "$S_STRING_%d" % len(strings)
-                    file_tokens.append("(i32.add (get_global $memoryBase) (get_global %s))" % str_name)
-                    strings.append(str)
-                    string_map[str] = str_name
-            if pair == "(CHAR":
-                c = literal_eval(arg)
-                if len(c) != 1:
-                    raise Exception ("Invalid (CHAR) macro, must be 1 character")
-                file_tokens.append("(i32.const 0x%x (; %s ;))" % (ord(c), arg))
-            # Skip the rest of the macro
-            index += 5
-            continue
-        index += 1
-        if token == '(':
-            depth += 1
-        if token == ')':
-            depth -= 1
-        if depth == 0:
-            module = None
-            if token == ')': continue
-        if depth == 1:
-            type = None
-            if pair == '(module':
-                index += 1
-                continue
-            if token.startswith('$'):
-                module = token[1:]
-                #print("module:", module, file=sys.stderr)
-                file_tokens.append('\n  ;;\n  ;; module "%s"\n  ;;\n' % module)
-                continue
-        if depth == 2:
-            if token == '(':
-                type = tokens[index]
-                if type == 'data':
-                    raise Exception("User data section not supported")
-                #print("  type:", type, file=sys.stderr)
-        file_tokens.append(token)
-
-# TODO: remove duplicates
-# Create data section with static strings
-string_tokens = []
-if strings:
-    string_tokens.append("  (data\n    (get_global $memoryBase)\n")
-    string_offset = 0
-    for string in strings:
-        string_tokens.append('    %-30s ;; %d\n' % (
-            '"'+_escape(string)+'\\00"', string_offset))
-        string_offset += len(string)+1
-    string_tokens.append("  )\n\n")
-
-    # Create string names/pointers
-    string_offset = 0
-    for index, string in enumerate(strings):
-        string_tokens.append('  (global $S_STRING_%d  i32 (i32.const %d))\n' % (
-            index, string_offset))
-        string_offset += len(string)+1
-    # Terminator so we know how much memory we took
-    string_tokens.append('  (global $S_STRING_END  i32 (i32.const %d))\n' % (
-        string_offset))
-
-all_tokens = ["(module\n"]
-all_tokens.extend(string_tokens)
-all_tokens.extend(file_tokens)
-all_tokens.append("\n)")
-
-print("".join(all_tokens))