roc/crates/repl_wasm
Richard Feldman bc0c9250f9
Convert unused dbg!()s to eprintln!()s
This makes it nicer to work with dbg! normally,
because grepping the code base for dbg!() reveals
only the usages of it that are currently active.
2024-12-01 23:10:35 -05:00
..
src Convert unused dbg!()s to eprintln!()s 2024-12-01 23:10:35 -05:00
architecture.png Move web REPL assets into www folder and build script into repl_wasm crate 2022-07-09 10:02:24 +01:00
build-www.sh update nix revision 2023-12-26 19:08:40 +01:00
build.rs clippy 2023-09-09 15:03:50 +01:00
Cargo.toml replace cargo deps with workspace in repl_*, reporting, roc_std 2024-11-29 11:01:42 +11:00
README.md update docs for wasm repl dev 2023-11-24 10:07:27 -05:00
screenshot.png Move web REPL assets into www folder and build script into repl_wasm crate 2022-07-09 10:02:24 +01:00

Web REPL

Running locally

1. Build the web REPL

This builds the compiler as a .wasm file, and generates JS glue code. It will cargo install the wasm-pack command line tool if you don't already have it.

crates/repl_wasm/build-www.sh
mkdir -p www/public/repl
cd www/public/repl
ln -s ../../../crates/repl_wasm/build/roc_repl_wasm_bg.wasm
ln -s ../../../crates/repl_wasm/build/roc_repl_wasm.js

These symlinks are ignored by Git.

This is a bit different from the production build, where we copy all the files to www/build/. But for development, it's convenient to have just one copy of files like www/public/repl/repl.js. You can make changes, reload your browser to see them, and commit them to Git, without getting mixed up between different copies of the same file.

3. Run a local HTTP server

Browsers won't load .wasm files over the file:// protocol, so you need to serve the files in ./www/build/ from a local web server. Any server will do, but this example should work on any system that has Python 3 installed:

cd www/public
python3 -m http.server

4. Open your browser

You should be able to find the Roc REPL at http://127.0.0.1:8000/repl (or whatever port your web server mentioned when it started up.)

Warning: This is work in progress! Not all language features are implemented yet, error messages don't look nice yet, up/down arrows don't work for history, etc.

Screenshot

How it works

  • User types text into the HTML <input /> tag
  • JS detects the onchange event and passes the input text to the Roc compiler WebAssembly module
  • Roc compiler WebAssembly module
    • Parses the text (currently just a single line)
    • Type checks
    • Monomorphizes
    • Generates WebAssembly using the development backend (not LLVM)
    • Returns a slice of bytes to JavaScript
  • JavaScript
    • Takes the slice of bytes and creates a WebAssembly.Instance
    • Runs the WebAssembly app
    • Gets the memory address of the result and makes a copy of the app's entire memory buffer
    • Passes the result address and the memory buffer to the compiler for analysis
  • Roc compiler WebAssembly module
    • Analyses the bytes of the result, based on the known return type from earlier
    • Traverses the copied memory buffer to find any child values
    • Produces a user-friendly String and passes it to JavaScript
  • JavaScript
    • Displays the input and output text on the web page

High-level diagram

There are several directories/packages involved here:

  • www/public/repl/index.html: The web page with its JavaScript and a build script
  • crates/repl_wasm: The Rust crate that becomes the "compiler" WebAssembly module
  • crates/repl_eval: REPL logic shared between crates/repl_cli and crates/repl_wasm