[in an interactive Forth console](https://mko.re/waforth/), in [a Logo-like Turtle graphics language](https://mko.re/thurtle/), and in [an interactive notebook](https://mko.re/wafnb/drawing-with-forth).
<figcaption><em>WAForth integrated in <ahref="https://mko.re/thurtle/">Thurtle</a>, a <ahref="https://en.wikipedia.org/wiki/Turtle_graphics">turtle graphics</a> programming environment using Forth</em></figcaption>
Besides just-in-time compilation (in a browser or native), WAForth can also be used to compile Forth ahead-of-time.
[`waforthc`](https://github.com/remko/waforth/tree/master/src/waforthc) is a tool that uses WAForth to compile a Forth program into a native executable.
A [simple example](https://github.com/remko/waforth/blob/master/src/web/examples/prompt/prompt.ts) ([CodePen](https://codepen.io/mko-re/pen/gOzzmXZ)) to illustrate starting WAForth, and binding JavaScript functions:
For asynchronous bindings, use `bindAsync` instead of `bind`.
`bindAsync` expects an execution token on the stack, which is
to be called with a success flag after the bound function is called. This is illustrated in [the fetch example](https://github.com/remko/waforth/blob/master/src/web/examples/fetch/fetch.ts):
```typescript
forth.bindAsync("ip?", async () => {
const result = await (
await fetch("https://api.ipify.org?format=json")
).json();
forth.pushString(result.ip);
});
forth.interpret(`
( IP? callback. Called after IP address was received )
WAForth supports directly writing WebAssembly in Forth using the [`CODE`](https://forth-standard.org/standard/tools/CODE) word.
For example, the following snippet defines a raw WebAssembly version of [`DUP`](https://forth-standard.org/standard/core/DUP):
```forth
CODE DUP' ( n -- n n )
\ Put pointer to top of Forth stack (local_0) on the
\ Wasm operand stack (for use later)
[ 0 ] $LOCAL.GET
\ Load the number at the top of the Forth stack
\ (local_0 - 4) on the Wasm operand stack
[ 0 ] $LOCAL.GET
[ 4 ] $I32.CONST
$I32.SUB
$I32.LOAD
\ Store the number on the Wasm operand stack on
\ top of the Forth stack. The first operand (Forth
\ stack pointer) was put on the Wasm operand stack
\ at the beginning of this snippet
$I32.STORE
\ Increment the Forth top of stack pointer (local_0),
\ and leave it on the Wasm operand stack as return value
[ 0 ] $LOCAL.GET
[ 4 ] $I32.CONST
$I32.ADD
;CODE
```
This creates a word with the specified WebAssembly:
```wasm
(func $DUP' (param $tos i32) (result i32)
local.get $tos
local.get $tos
i32.const 4
i32.sub
i32.load
i32.store
local.get $tos
i32.const 4
i32.add
)
```
Note that support for writing WebAssembly is still experimental.
The assembly words used in the above snippet (`$LOCAL.GET`, `$I32.*`, ...) aren't available in the WAForth core,
and have to be manually defined using the low-level `$U,` and `$S,` words that append ([LEB128](https://en.wikipedia.org/wiki/LEB128)-encoded) bytes directly to the WebAssembly module. For example, the code above relies on the following assembly word definitions:
[the WebAssembly spec](https://webassembly.github.io/spec/core/binary/instructions.html). In the future, I'll probably make all WebAssembly assembly instructions available somewhere. Using WebAssembly locals also currently isn't possible, although this can
Because it is powered by WebAssembly, this extension works both in the desktop version of Visual Studio Code and in [the browser version of Visual Studio Code](https://code.visualstudio.com/docs/editor/vscode-web) (e.g. https://github.dev, https://vscode.dev).
You can also convert the notebook into a lightweight self-contained page using [`wafnb2html`](https://github.com/remko/waforth/tree/master/src/web/notebook).
An example can be seen [here](https://mko.re/wafnb/drawing-with-forth).
- ✅ **WebAssembly-first**: Implement as much as possible in (raw) WebAssembly. Only call out to JavaScript (or whatever the host language is) for functionality that is not available in WebAssembly (I/O, loading compiled WebAssembly code).
- ✅ **Simplicity**: Keep the code as simple and clean as possible. Raw WebAssembly requires more effort to maintain than code in a high level language, so avoid complexity if you can.
- ✅ **Completeness**: Implement a complete (and correct) Forth system, following the [ANS Standard](http://lars.nocrew.org/dpans/dpans.htm), including all [ANS Core words](http://lars.nocrew.org/dpans/dpans6.htm#6.1).
- ❓ **Speed**: If some speed gains can be gotten without paying much in simplicity (e.g. better design of the system, more efficient implementation of words, simple compiler improvements, ...), then I do it. However, generating the most efficient code would require a smart compiler, and a smart compiler would introduce a lot of complexity if implemented in raw WebAssembly, so speed is not an ultimate goal. Although the low level of WebAssembly gives some speed advantages, the design of the system will cause execution to consist almost exclusively of indirect calls to small functions, so there will be languages targeting WebAssembly that run faster.
- ❓ **Binary size**: Since the entire system is written in raw WebAssembly, and since one of the main goals is simplicity, the resulting binary size is naturally quite small (±12k). However, I don't do any special efforts to save bytes here and there in the code (or the generated code) if it makes things more complex.
- ❓ **Ease of use**: Like most Forths, I currently don't do much effort to provide functionality to make Forth programming easy and safe (helpful errors, stacktraces, strict bounds checks, ...). However, the compiler emits debug information to help step through the WebAssembly code of words, and I hope to add more debugging aids to the compiler in the future (if it doesn't add too much complexity)