stefanhts / wacket

A lisp inspired functional programming language which compiles to WebAssembly
MIT License
18 stars 1 forks source link

wacket

Running wacket

  1. Get everything installed (see this section)
  2. Write your program in program.wkt
  3. Run make
  4. Start your server (see Getting Server Running)
  5. Click the run button, or enter input (for readbyte programs) and then click run
  6. The output of the program should display under the run button

Prerequisites

Make sure you have the following installed:

Getting Server Running

  1. npm install
  2. cd server
  3. node index.js
  4. navigate to http://localhost:3000

Quick-start

  1. Write some wacket (for example, into program.wkt)
  2. make program.wat (optional)
  3. make program.wasm
  4. In the frontend, enter any input and click Run.

Compiling a test

Run make tests/{folder}/{number}.wasm to compile to main.wasm in the server/ folder, which can then be run from the frontend.

Errors

Kind of error What it means Who is most likely responsible
Compile errors that start with read: wacket syntax error programmer
Compile errors that start with WAT parse error: compiler has generated a poorly formed wat AST, or the pretty printer is non-comprehensive compiler writer
Compile errors that include contract violation (or other racket errors) compiler has an error in it compiler writer
Compile errors that cite .wat files (eg: ....wat:20:10: error:) wat generated by the pretty printer is malformed compiler writer
Runtime errors (the frontend says RUNTIME ERROR) the wacket code written has some error in it programmer
JavaScript runtime errors, that don't say RUNTIME ERROR in the frontend the wasm code generated an unexpected runtime error compiler writer

Target Language: WebAssembly

We need to write to .wat which is the WebAssembly Text format. From there we can use wat2wasm to turn that into the actual assembly code which can run in the browser.

WebAssembly Text Format (.wat)

Compiling from WebAssembly Text format (.wat) to WebAssembly Binary format (.wasm)

The Runtime system

Our runtime system is written in JavaScript, which can interface with compiled WASM bidirectionally. There is a minimal HTML file to act as an interface to the runtime system. This must be exposed to localhost with a web server, because modern browsers don't allow for accessing arbitrary files in the filesystem.

Source Language: wacket

We'll be aiming to implement all the features present in Loot, the reduced version of Racket created in class already. This should allow for the re-use of much of the compiler infrastructure, like the lexer, parser, and AST.

class github repo

note on .wkt files

They start with #lang wacket. This caused my syntax checker to tell me:

standard-module-name-resolver: collection not found
  for module path: wacket/lang/reader
  collection: "wacket/lang"
  in collection directories:
   /home/chris/.racket/8.4/collects
   /usr/share/racket/collects/

To fix this problem, I navigated to /usr/share/racket/collects/ and ran the command sudo ln -s racket/ wacket. This tricks the syntax checker because it looks at /usr/share/racket/collects/wacket, but it's really just a symbolic link to /usr/share/racket/collects/racket.

Alternatively, your syntax checker may fail to do anything at all, because of the unrecognized .wkt file extension.

TODO

Complete

wat AST

Note: [list of Things] may be empty in this representation.

Note 2: This is not up to date. See wat/ast.rkt for the most up to date AST.

type Module = (Module [list of Definitions])

type Definition = Import
                | Export
                | Func
                | Start

type Start = (Start funcname)

;; imports have a 2 level namespace: module then function
type Import = (Import modulename funcname FuncSignature)

;; name is what the RTS will see, ExportFuncSignature is what we use internally
type Export = (Export name ExportFuncSignature)

type ExportFuncSignature = (ExportFuncSignature name)

type Func = (Func FuncSignature [list of Locals] Body)

type FuncSignature = (FuncSignature name? [list of Params] Result?)

type Param = (Param name? Type)

type Result = (Result Type)

type Local = (Local name? Type)

type Type = i32
          | i64
          | f32
          | f64

type Body = (Body [list of Instructions])

type Instruction = (Inst name [list of Instructions])
                 | Const

type Const = (Const v)

Memory Accessing

An instance of memory in WASM is allocated in blocks of 64KB of storage, so a single block should be more than enough for Wacket.

I found this article to have the best (and really only) example of manipulating memory in .wat files.

Implementation

Instead of rbx, we will use the global variable defined by heap-name to store the next available address on the heap. This is a global variable with the internal name generated by (gensym 'heap).

Some specifics to note: