Skip to content

Build the RBS parser as a WebAssembly module (JRuby support, step 1)#2998

Open
soutaro wants to merge 1 commit into
masterfrom
claude/practical-mendel-hnqws8
Open

Build the RBS parser as a WebAssembly module (JRuby support, step 1)#2998
soutaro wants to merge 1 commit into
masterfrom
claude/practical-mendel-hnqws8

Conversation

@soutaro

@soutaro soutaro commented Jun 16, 2026

Copy link
Copy Markdown
Member

Why

This is the first step toward running RBS on Ruby implementations that cannot load the MRI C extension — notably JRuby — using WebAssembly instead of an FFI/dylib.

The parser under src/ is plain, self-contained C with no dependency on the Ruby C API, so it can be compiled to WebAssembly as-is. The plan is to compile the parser to a .wasm module, run it on a JVM WebAssembly runtime under JRuby, and reconstruct RBS::AST objects on the Ruby side.

Plan (split into PRs)

  1. This PR — WASM build of the parser. Prove the toolchain end to end: compile src/*.c to wasm32-wasip1, expose a minimal stable ABI, build it from Rake, and smoke-test it in CI.
  2. AST serialization. A compact binary serializer (generated from config.yml, alongside the existing ast_translation.c) plus a pure-Ruby deserializer. Validated on CRuby first via a round-trip against the existing C → Ruby translation, so the hardest part is de-risked without any WASM involved.
  3. JRuby integration. Load rbs_parser.wasm with Chicory (a pure-JVM WASM runtime, zero native deps), run the serializer entry point, feed the result to the step-2 deserializer, and branch lib/rbs.rb on RUBY_ENGINE. Adds a JRuby CI job.

(Runtime = Chicory, format = compact binary — confirmed up front.)

What this PR does

  • wasm/rbs_wasm.c — a reactor-model entry shim exposing a small, stable ABI:
    Export Signature Description
    rbs_wasm_alloc (i32) -> i32 Allocate N bytes in linear memory, return the offset
    rbs_wasm_free (i32) -> () Free a region from rbs_wasm_alloc
    rbs_wasm_parse_signature (i32 ptr, i32 len) -> i32 Parse UTF-8 source; 0 = ok, 1 = parse error
    rbs_wasm_selftest () -> i32 Parse a fixed sample; 0 = ok
  • rake wasm:build / rake wasm:check — driven by the WASI SDK (WASI_SDK_PATH) and wasmtime (WASMTIME).
  • .github/workflows/wasm.yml — installs the WASI SDK + wasmtime and runs rake wasm:check.
  • src/util/rbs_allocator.c — drop unused <sys/mman.h> / <fcntl.h> / <sys/types.h> includes (only sysconf() is used) so the arena allocator compiles cleanly against wasi-libc. WASI has no mmap, and the code never called it; this is the only change needed to the shared C source.

No AST is serialized back to the host yet — that's step 2.

Testing

Verified locally with wasi-sdk-33 (clang 22) and wasmtime 45:

$ export WASI_SDK_PATH=/path/to/wasi-sdk
$ rake wasm:check
Built .../wasm/rbs_parser.wasm
WebAssembly selftest passed.

Also confirmed:

  • valid RBS → rbs_wasm_selftest returns 0; malformed RBS → 1;
  • the native C extension still builds and test/rbs/parser_test.rb passes (42 tests, 395 assertions, 0 failures) after the rbs_allocator.c change.

The compiled rbs_parser.wasm is a build artifact and is gitignored.

https://claude.ai/code/session_01LTveMt3NLbYHEboXuzAKpA


Generated by Claude Code

The parser under src/ is plain, self-contained C with no dependency on
the Ruby C API, so it can be compiled to WebAssembly as-is. This is the
foundation for running RBS on Ruby implementations that cannot load the
MRI C extension (notably JRuby).

- Add wasm/rbs_wasm.c: a reactor-model entry shim exposing a small,
  stable ABI (alloc/free, parse_signature, and a selftest).
- Add `rake wasm:build` and `rake wasm:check` tasks driven by the WASI
  SDK (WASI_SDK_PATH) and wasmtime.
- Add a WebAssembly CI workflow that builds and smoke-tests the module.
- Drop unused <sys/mman.h>/<fcntl.h>/<sys/types.h> includes from
  rbs_allocator.c (only sysconf() is used) so the arena allocator
  compiles cleanly against wasi-libc.

Serializing the parsed AST back to the host and wiring this into RBS on
JRuby come in follow-up steps.

https://claude.ai/code/session_01LTveMt3NLbYHEboXuzAKpA
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants