diff --git a/README.md b/README.md index e0a478e..10b5361 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,11 @@ As WebAssembly doesn't support unstructured jumps, control flow words (`IF/ELSE/ However, since Forth only requires structured jumps, the compiler can easily be implemented using the loop and branch instructions available in WebAssembly. +Finally, the compiler adds minimal debug information about the compiled word in +the [name section](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#name-section), making it easier for doing some debugging in the browser. + +![Debugger view of a compiled word](https://el-tramo.be/blog/waforth/debugger.png "Debugger view of a compiled word") + ### The Loader diff --git a/src/shell/WAForth.js b/src/shell/WAForth.js index 5eb8392..6260251 100644 --- a/src/shell/WAForth.js +++ b/src/shell/WAForth.js @@ -60,12 +60,7 @@ class WAForth { if (index >= table.length) { table.grow(table.length); // Double size } - // console.log( - // "Load", - // index, - // new Uint8Array(data), - // arrayToBase64(data) - // ); + // console.log("Load", index, new Uint8Array(data), arrayToBase64(data)); var module = new WebAssembly.Module(data); new WebAssembly.Instance(module, { env: { table, tableBase: index, memory, tos: -1 } diff --git a/src/tools/quadruple.wat b/src/tools/quadruple.wat index ed4ed31..ddac34a 100644 --- a/src/tools/quadruple.wat +++ b/src/tools/quadruple.wat @@ -1,6 +1,6 @@ ;; Template for defining 'word' modules ;; Used to 'reverse engineer' the binary code to emit from the compiler -(module +(module $quadruple (import "env" "table" (table 4 anyfunc)) (import "env" "tableBase" (global $tableBase i32)) (import "env" "memory" (memory 1)) diff --git a/src/waforth.wat b/src/waforth.wat index dc77795..c5fb0dd 100644 --- a/src/waforth.wat +++ b/src/waforth.wat @@ -298,12 +298,12 @@ ;; 6.1.0460 (func $semicolon (param i32) (local $bodySize i32) + (local $nameLength i32) (call $emitEnd) - (set_local $bodySize (i32.sub (get_global $cp) (i32.const !moduleHeaderBase))) - ;; Update code size + (set_local $bodySize (i32.sub (get_global $cp) (i32.const !moduleHeaderBase))) (i32.store (i32.const !moduleHeaderCodeSizeBase) (call $leb128-4p @@ -322,8 +322,46 @@ (i32.const !moduleHeaderLocalCountBase) (call $leb128-4p (get_global $localsCount))) + ;; Write a name section + (set_local $nameLength (i32.and (i32.load8_u (i32.add (get_global $latest) (i32.const 4))) + (i32.const !lengthMask))) + (i32.store8 (get_global $cp) (i32.const 0)) + (i32.store8 (i32.add (get_global $cp) (i32.const 1)) + (i32.add (i32.const 13) (i32.mul (i32.const 2) + (get_local $nameLength)))) + (i32.store8 (i32.add (get_global $cp) (i32.const 2)) (i32.const 0x04)) + (i32.store8 (i32.add (get_global $cp) (i32.const 3)) (i32.const 0x6e)) + (i32.store8 (i32.add (get_global $cp) (i32.const 4)) (i32.const 0x61)) + (i32.store8 (i32.add (get_global $cp) (i32.const 5)) (i32.const 0x6d)) + (i32.store8 (i32.add (get_global $cp) (i32.const 6)) (i32.const 0x65)) + (set_global $cp (i32.add (get_global $cp) (i32.const 7))) + + (i32.store8 (get_global $cp) (i32.const 0x00)) + (i32.store8 (i32.add (get_global $cp) (i32.const 1)) + (i32.add (i32.const 1) (get_local $nameLength))) + (i32.store8 (i32.add (get_global $cp) (i32.const 2)) (get_local $nameLength)) + (set_global $cp (i32.add (get_global $cp) (i32.const 3))) + (call $memcpy (get_global $cp) + (i32.add (get_global $latest) (i32.const 5)) + (get_local $nameLength)) + (set_global $cp (i32.add (get_global $cp) (get_local $nameLength))) + + (i32.store8 (get_global $cp) (i32.const 0x01)) + (i32.store8 (i32.add (get_global $cp) (i32.const 1)) + (i32.add (i32.const 3) (get_local $nameLength))) + (i32.store8 (i32.add (get_global $cp) (i32.const 2)) (i32.const 0x01)) + (i32.store8 (i32.add (get_global $cp) (i32.const 3)) (i32.const 0x00)) + (i32.store8 (i32.add (get_global $cp) (i32.const 4)) (get_local $nameLength)) + (set_global $cp (i32.add (get_global $cp) (i32.const 5))) + (call $memcpy (get_global $cp) + (i32.add (get_global $latest) (i32.const 5)) + (get_local $nameLength)) + (set_global $cp (i32.add (get_global $cp) (get_local $nameLength))) + ;; Load the code and store the index - (call $shell_load (i32.const !moduleHeaderBase) (get_local $bodySize) (get_global $nextTableIndex)) + (call $shell_load (i32.const !moduleHeaderBase) + (i32.sub (get_global $cp) (i32.const !moduleHeaderBase)) + (get_global $nextTableIndex)) (i32.store (call $body (get_global $latest)) (get_global $nextTableIndex)) (set_global $nextTableIndex (i32.add (get_global $nextTableIndex) (i32.const 1))) diff --git a/tests/index.js b/tests/index.js index 89d858f..5f6e459 100644 --- a/tests/index.js +++ b/tests/index.js @@ -1012,6 +1012,10 @@ describe("WAForth", () => { expect(stack[1]).to.eql(4); expect(stack[2]).to.eql(5); }); + + it("should compile a name with an illegal WASM character", () => { + run(': F" 3 0 DO 2 LOOP ;'); + }); }); describe("VARIABLE", () => {