mirror of
https://github.com/remko/waforth
synced 2025-01-17 18:11:39 +01:00
parent
fed7aa5389
commit
76b1975ff6
5 changed files with 52 additions and 10 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)))
|
||||
|
||||
|
|
|
@ -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", () => {
|
||||
|
|
Loading…
Reference in a new issue