uLisp is a programming language for microcontrollers and embedded devices. This project ulisp-wasm is a port of uLisp to C99 and WebAssembly that runs in the browser, on servers and the terminal command line.
See the Playground page and introduction post on the forum.
Early stage but the basics are working.
- Parse and evaluate a Lisp expression. The runtime on Wasm has its own process thread with 64K of memory, and an event loop that optionally yields control to the host on every instruction.
- Pass the entire test suite in the uLisp builder.
- Run uLisp interpreter and REPL across platforms: plain C build, Wasm runtimes, Node, Bun, browser; Linux laptop, Raspberry Pi, ESP32.
Based on uLisp builder, uLisp ESP32, BL602 RISC-V fork
- Rewrite and upgrade from uLisp 3.6 to 4.6b, 4.7, 4.8d
- Load code and step through each instruction
- Replace devices with host events for emulation
- Analog port read/write
- Digital port read/write
- Serial interface
- Graphics
- Audio
- LittleFS
- EPROM read/write
- Load/save/autorun image
- I2C interface - See function
with-i2c - SD card
- Extended RAM - Define
BOARD_HAS_PSRAM
- REPL (read-eval-print loop) in web interface
- REPL on server side
- REPL and line editor in uLisp using serial interface
- CLI on server side to run uLisp programs
- Run in the browser
- Run on JavaScript runtimes: Node, Bun, Deno
- Run on WASM runtimes with WASI support
- Standalone executable
- WebAssembly Standalone
- Or maybe
wasm-micro-runtime
- Documentation
- Web interface
- Code editor with syntax highlight
- Console output
- Canvas
- SVG
- Web Audio
Prerequisites:
- Docker to run Emscripten in a container; or directly use
emccfrom Emscripten SDK (install options) - Bun - JS runtime and build tool
- Clang - Optional: Compile to local platform
- Zig - Optional: Cross-compile to all supported platforms
See package.json for available CLI commands.
git clone https://github.com/eliot-akira/ulisp-wasm
cd ulisp-wasm
bun installBuild frontend app as static site, watch files for changes, rebuild and reload page.
bun run startTo run the above and develop/rebuild the C source in parallel:
bun run devBuild for production with minified assets.
bun run buildBelow scripts are ways to run functions in build.ts.
bun build.ts [command] (...options)bun build:node # Node.js target: Wasm library and CLI
bun build:site # Web playground site
bun build:web # Web targetRequires Bun. Optionally Clang for native build, Zig to cross-compile.
bun build:bun # Single-file executable with Bun runtime
bun build:cli # CLI/REPL as native C binaryThese produce binaries in the build folder for the following targets.
- linux-arm64
- linux-x64
- macos-arm64
- macos-x64
- windows-x64 *
- windows-arm64 *
* Windows support is partial: only Bun build on x64. REPL uses a readline library with terminal I/O, which doesn't exist on Windows. Possibly CLI could exclude the feature based on build target.
bun build:wasi # Wasm target with WASI (WebAssembly System Interface)
bun build:zig # Zig port of ulisp-cThe project is a monorepo with a number of subprojects. The main ones are c99, site, and web.
- arm - uLisp for ARM processors
- arm-assembler - ARM assembler
- arm-compiler - ARM compiler
- avr - uLisp for AVR processors
- bignums - Arbitrary-precision extension
- builder - Original builder using Common Lisp
- c99 - C99 port of uLisp
- cli - Command-line interface
- esp - uLisp for ESP32
- examples - Example code collection
- node - Node.js version using uLisp Wasm
- riscv - uLisp for RISC-V processors
- riscv-assembler - RISC-V assembler
- riscv-compiler - RISC-V compiler
- site - Web playground site
- tests - Test suite
- wasi - Wasm port for runtimes with WASI (WebAssembly System Interface)
- web - Web version based on uLisp Wasm
- zero - uLisp Zero is a minimal Lisp implementation for reference
- zig - Zig port of uLisp automatically translated from C
From documentation of uLisp builder
preface.lisp- the C macros and constant definitionsutilities.lisp- the C typedefs, global variables, and utility functionssaveload.lisp- the definitions for save-image, load-image, and autorunassembler.lisp- the assembler for the ARM and RISC-V platformsprettyprint.lisp- the prettyprinterpostscript.lisp- the definitions for the function table lookup, eval, read, print, and the REPL
- The source file preamble
- The platform-specific settings: WORKSPACESIZE, etc.
- The stream definitions: I2C, SPI, serial, etc.
- The analogread and analogwrite I/O pin definitions
- Definitions for note, sleep, and keywords
From ulisp-builder/build.lisp
- Header
- Workspace
- Macros
- Constants
- Typedefs
- Enum declarations
- Global variables
- Error handling
- Setup workspace
- Make objects
- Utilities
- Feature list
- Garbage collection
- Compact image
- Make filename
- Save image
- Tracing
- Helper functions
- Association lists
- Array utilities
- String utilities
- Closures
- In place
- I2C interface
- Stream interface
- Note
- Sleep
- Pretty print
- Assembler
- Interrupts
- Function definitions
- Symbol names
- Documentation strings
- Built-in symbol lookup table
- Eval
- Print functions
- Read functions
- Setup 1 & 2
- REPL
- Loop
See the article on Streams on the uLisp site.
| Stream | Streamtype | Description |
|---|---|---|
| SERIALSTREAM | 0 | Reading from and writing to a Serial interface |
| I2CSTREAM | 1 | Reading from and writing to an I2C device |
| SPISTREAM | 2 | Reading from and writing to an SPI device |
| SDSTREAM | 3 | Reading from and writing to SD cards |
| WIFISTREAM | 4 | Reading from and writing to Wi-Fi protocols |
| STRINGSTREAM | 5 | Reading from or writing to a Lisp string |
| GFXSTREAM | 6 | Writing text to a TFT colour display |
uLisp has graphics methods that use the Adafruit GFX Library with TFT LCD displays.
// Color definitions
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFFdrawBitmap(x, y, canvas.getBuffer(), 128, 32, foreground, background)(draw-char x y char [colour background size]) Draws the character char with its top left corner at (x,y). The character is drawn in a 5 x 7 pixel font in colour against background, which default to white and black respectively. The character can optionally be scaled by size.
void drawPixel(uint16_t x, uint16_t y, uint16_t color);getTextBounds(string, x, y, &x1, &y1, &w, &h)Sets the display orientation for subsequent graphics commands; values are 0, 1, 2, or 3.
- I2Cinit
- I2Cread
- I2Cwrite
- I2Cstart
- I2Crestart
- I2Cstop
