Skip to content

A Scheme to WAT/WASM compiler in spirit of SICP exercises 5.49-52

License

Notifications You must be signed in to change notification settings

samirose/sicp-compiler-project

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Scheme to WAT/Wasm compiler

In spirit of SICP exercises 5.49-52.

Goals

  • Implement the compiler in R7RS-small Scheme, using GNU Guile and GNU Emacs as the development platform. (N.B. this project originally used R6RS Scheme and Racket for development)
  • Learn about Scheme and compilation of functional languages in general
  • Get familiar with WebAssembly as an execution environment and compiler target
  • Stay in the spirit of simple Scheme and target initially to support a subset of R7RS-small Scheme
  • Compile Scheme forms directly to as idiomatic Wasm as feasible
  • Use only basic, standardised Wasm core features initially
  • Implement as much of the required run-time support in Scheme as possible
  • Write the required native run-time support in WAT
  • Compile a Scheme interpreter to Wasm using the compiler (see also SICP exercise 5.52)
  • If the interpreter works, host it on a web page with minimal JavaScript-driven REPL
  • Maybe try to bootstrap the compiler at some point as an interesting exercise

Non-goals

  • Build a full-blown implementation with robust error reporting, tooling, full Scheme libarary support etc.
  • Good interoperability with JavaScript is not critical, except where it helps in testing the compiler or hosting an interpreter or the compiler on the Web
  • Do not aim to replace JavaScript on the Web

Running

Required tools:

  • GNU Make for build and test orchestration
  • GNU Guile for running the compiler on the host
  • WABT for assembling the WAT files produced by the compiler to Wasm binaries and for running the compiler tests as defined in the Makefile. Compiler's output can be tested with any Wasm tooling that provides a WAT to Wasm assembler and a Wasm runtime.

Run GNU make or make help to list the build targets with short explanations.

GNU Emacs with Geiser forms a good development platform for working with the code.

Implemented features

  • Compilation of 32-bit integer values and open-coded application of + - * / = operators
  • comparison operators = < > <= >= for 32-bit integers
  • Scheme if statement to Wasm if statement
  • Scheme lambda expressions to Wasm functions and values that can be applied to arguments
  • Port the compiler from Racket #lang sicp to standard R6RS Scheme (still using Racket as the development platform)
  • A simple compiler "driver" that can be given a Scheme program from standard input and that emits a Wasm module to standard output in WAT format
  • Makefile for building the compiler and regression test execution
  • Regression tests for the implemented features
    • Tests are specified in WAST and executed with WABT's spectest-interp tool
    • The tests invoke the compiler with a Scheme library, compile it and check the executed WebAssembly's result with WAST assertions
    • See test-compiler for the tests. They also give an overall idea of what works and has been implemented in the compiler.
  • Compilation of Scheme R7RS library to a Wasm module with the top-level code in an exported func "main"
  • Top-level define of values and procedures
  • set! top-level and in-scope binding values
  • Support for exported top-level procedure definitions with R7RS libary syntax
  • Basic syntax and semantic error detection and tests for error handling
  • Implement let and let* with Wasm locals instead of lambda, if possible. (Using the bindings in closures will need further work)
  • and and or expressions with short circuit using Wasm block structure and conditional branch instructions
  • not expression
  • Compile cond to Wasm block structure and conditional branch instructions
  • Special form symbols and inlined procedures can be overridden with local bindings
  • Add a way to raise errors from compiled code. Needed for halting the program when a type error is detected.
  • Convert the source code R7RS-small Scheme and switch to Guile as the host Scheme implementation. (It would have been natural to use MIT Scheme for this project because of its SICP origins, but it does not support the M1 Apple Silicon Mac I am using as my main machine.)
  • Add bit tagged typing to values and type predicates: number?, boolean?, procedure? and uninitialized and unspecified values and add type checking to generated code.
  • Literal symbols
  • Literal strings
  • eqv? implementation for supported types (6.1 [R7RS]). Equivalent to eq? with the currently supported types.

Features currently under work

Known issues

  • Numeric computations are not checked for over- or underflow. WebAssembly semantics apply in case of over- or underflow

Backlog

  • Implement support for programs (5.1 [R7RS])
  • Implement basic output facility with WASI (6.13.3 [R7RS])
  • Add run-time support for rudimentary heap-based values: vectors, pairs
  • Implement simple garbage collection using SICP section 5.3 as a guideline in WAT
  • Implement lexical closures with function activation records as vector lists on the heap
  • Implement letrec form. It does not make sense to implement it before closure support to enable common use case of recursion and procedures calling each other.
  • Scan out (see SICP chapter 4.16) internal definitions and implement the bindings with letrec*
  • Come up with a name for this project
  • Add high-level design documentation with guide to the source code of the compiler
  • More R7RS-small features, prioritisation TBD.

References

Essential

Supporting

Scheme classics

Similar projects

About

A Scheme to WAT/WASM compiler in spirit of SICP exercises 5.49-52

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published