Skip to content

LunaAmora/4orth

Repository files navigation

GitHub Workflow Status GitHub release (latest by date including pre-releases) GitHub all releases GitHub

4orth

4orth is a Porth compiler with WASM, WASI and WASM-4 targets.

Most of the code in this repository was written by Tsoding and other contributors to the original Porth compiler. 4orth was created as an alternative compiler for WASM, and reuses a lot of its codebase.

Quick Start

You can download the latest release or bootstrap it yourself.

Bootstrapping

Since Porth is self-hosted you will need to bootstrap it first. Follow Porth bootstrapping instructions on how to do that. (4orth includes the original porth compiler with the -porth option, so you can use the 4orth executable instead to bootstrap/update itself)

Secondly you will need to install:

$ ./porth/porth com 4orth.porth
              <or>
$ ./4orth -porth com 4orth.porth 

Then, you are ready to compile and run your Porth programs using the runtime of your choice:

Compilation

Compilation generates WAT and converts it to a WebAssembly Binary Format .wasm file with WABT. So make sure you have it available in your $PATH.

$ ./4orth com main.porth
$ w4 run main.wasm
        <or>
$ ./4orth com -wasm main.porth
$ wasmtime main.wasm

With Wasm-4, you can use the subcommands -b and -r to bundle and run after the compilation. (As porth only supports Linux, -b creates a Linux executable. For other options, check w4 bundle --help or Wasm-4 distribution docs)

./4orth com -b -r main.porth

Tip: Add _4ORTH environment variable to automatically have the std libraries available in 4orth include path.

Running options and subcommands

$ ./4orth [OPTIONS] <SUBCOMMAND>

OPTIONS:
    -porth               Use the original porth compiler and CLI instead of 4orth
    -unsafe              Disable type checking
    -I <path>            Add <path> to the include paths list
SUBCOMMANDS:
    com [OPTIONS] <file> Compile the program
        -r               Run the program after successful compilation
        -b               Bundles the program to a linux executable. (If with -r, executes the bundle)
        -opt             Optimize the program with wasm-opt
        -wat             Transforms the stripped program back from the final `.wasm` to `.wat`
        -wasm            Target WASM instead of Wasm-4 (doesn't support -b or -r)
        -s               Silent mode. Don't print any info about compilation phases
        -o  <file>       File to write the result to
    help                 Print this help to stdout and exit with 0 code

Status

4orth currently only supports 32 bit integers.

Changes

4orth implements some temporary features not available in Porth to facilitate Wasm integration:

  • Hexadecimal numbers (as 0x format on numbers, and as \\ plus 2 digits on strings)
  • Null terminated string support in const evaluation (evaluates to a pointer to the string)

Importing and exporting procs

4orth introduces two new keywords allowing Porth to interact with the WASM module system:

  • Import
import proc trace ptr in end

This adds the ability to call the Wasm-4 trace function via the defined proc contract. Imported procs must have an empty body. (Porth's print intrinsic calls this imported proc, you can use either of them to log to the console)

  • Export
export main "start"
export update "update"

This exports the desired procs to be called by Wasm-4 or other Wasm runtimes.

Inline WASM code

4orth allows you to inline WASM code into your program by using the wasm keyword. Any string inside the code block will be inlined in the compiled program.

wasm 
  "\n;; Inlined global rng seed for a Pseudo random number generator."
  "(global $random-state (mut i32) (i32.const 69420))" 
end

When inside a procedure, inline WASM blocks have to define a contract to be used in type checking.

inline proc xor int int -- int in
  wasm int int -- int in
    " call $pop"
    " call $pop"
    " i32.xor"
    " call $push"
  end
end

This implements a xor procedure utilizing the WASM i32.xor instruction. (This proc is available at wasm-core.porth)

Importing modules (for raw WASM and WASI)

The default module imported by 4orth is dev. You can include other modules in your program by using the import keyword followed by module and the module name.

import module "my_module"

This line changes the current module context to my_module. Every imported proc defined after this line will use this context until a new module is imported.

Others

All available functions, constants and the memory map from Wasm-4 are in the wasm4.porth library.

The wasi.porth library contains a minimal WASI setup and a imported proc that prints to stdout.

Huge thanks to Tsoding for all the educational content and for (being in the process of) creating such a fun language to experiment with.
And Thanks Aduros for the fantastic fantasy console Wasm-4.

The two projects just seemed so compatible to me that I had to try a way to play with both at the same time!