Browser-based live demo for the sw-cor24-ocaml integer-subset OCaml interpreter.
Live demo: https://sw-embed.github.io/web-sw-cor24-ocaml/
Part of the Software Wrighter COR24 Tools Project.
The interpreter is written in Pascal, compiled to p-code, and runs on
the canonical COR24 p-code VM (pvm.s); this project assembles
pvm.s with the COR24 emulator at build time and runs it inside the
browser via WebAssembly. No backend.
Same architecture as the rest of the web-sw-cor24-* family
(pascal, snobol4, forth, ...): one Yew SPA, one Trunk build,
one cor24-emulator running real COR24 native code under Rust.
# 1. Refresh vendored sources (asm/pvm.s + assets/ocaml.p24m) from
# sibling repos. Required first time, then any time the upstream
# interpreter or VM changes.
./scripts/vendor-artifacts.sh
# 2. Run the dev server (port 9735, exclusive dist/ lock).
./scripts/serve.sh
# 3. Open http://localhost:9735/Pick a demo from the dropdown and hit Run (or Cmd/Ctrl-Enter). Esc stops a running session. Reset reloads the demo source. Clear wipes the output panel.
23 OCaml programs ship with the build (22 mirrored from
../sw-cor24-ocaml/tests/ via scripts/sync-demos.sh, 1 hand-written):
| Demo | Description |
|---|---|
factorial |
Recursive factorial via let rec; computes 5!. |
function-form-let |
Sugared let f x y = body form (curried function definitions). |
function-keyword |
function keyword: shorthand for fun x -> match x with .... |
function-pattern-args |
Destructuring patterns directly in function arguments. |
functions |
First-class functions and let bindings. |
hello |
Smallest possible program: print the integer 42. |
higher-order-lists |
List.map, List.filter, List.fold_left, List.iter with inline lambdas. |
led-blink |
Drive the COR24 LED via led_on / led_off. Browser stubs the LED. |
led-toggle |
Read the COR24 switch and reflect it on the LED. |
let-destructure |
Destructuring let (a, b) = ..., let h :: t = ..., and friends. |
list-module |
List.length, List.rev, qualified-name lookups. |
lists |
List literals, cons, head/tail, is_empty. |
lists-pairs-demo |
Sum, length, map, swap, countdown -- lists + pairs in one program. |
multi-arg |
Multi-argument curried function via fun x y -> .... |
named-adts |
Sum types via type T = C1 | C2 | ... and match expressions. |
options |
The built-in option type: None and Some x. |
pairs |
Tuple construction with fst / snd accessors. |
patterns |
Pattern matching across lists, tuples, options, and literals. |
print |
print_int and putc writing through the UART. |
repl-session |
Multi-expression REPL session -- type more lines after the seed runs. |
sequencing |
Semicolon-sequenced expressions evaluated left-to-right. |
strings |
String literals, ^ concatenation, print_endline, String.length. |
when-guards |
match ... when <guard> clauses for conditional pattern arms. |
See docs/demos.md for annotated source and expected
output for each.
To add a new demo: drop the .ml file in
../sw-cor24-ocaml/tests/, add a mapping line to
scripts/sync-demos.sh, append an entry to src/demos.rs, and rerun
the sync script.
asm/pvm.s-- vendored copy of the canonical p-code VM from../sw-cor24-pcode/vm/pvm.s.build.rs-- assemblespvm.sviacor24_emulator::Assembler, captures thecode_ptrlabel address, and bakesassets/ocaml.p24mintoOUT_DIR.src/runner.rs-- 270-lineSessionoverEmulatorCore. Loadspvm.binat address 0, places the OCaml interpreter image at0x010000, patchescode_ptrso pvm'sinit_p24mpath picks it up on boot, and ticks viaemu.run_batch(). Source bytes flow into the UART RX queue terminated by EOT (0x04).src/lib.rs-- YewApp: demo dropdown, source editor, output pane, status bar with a budget escalator, REPL input row, octocat corner, footer with build stamp.src/demos.rs-- static catalog (include_str!fromexamples/).examples/-- demo.mlsources synced from the CLI repo.scripts/serve.sh-- dev server on port 9735 with an exclusivedist/lock.scripts/build-pages.sh-- release build intopages/for GitHub Pages, same lock.
./scripts/build-pages.sh
git add pages/
git commit -m "Release: deploy <date>"
git pushThe --public-url is /web-sw-cor24-ocaml/ so paths resolve under
https://sw-embed.github.io/web-sw-cor24-ocaml/.
cargo test --lib4 unit tests:
runner::tests::print_int_42_runs_to_completion_with_42_in_output-- end-to-end: source bytes -> UART -> pvm boot -> OCaml interp ->42in cleaned output. Confirms the whole stack including multi-unit XCall / IRT through the realpvm.s.demos::tests::default_is_hello,demos::tests::names_are_unique,demos::tests::only_repl_session_is_interactive-- catalog invariants.
- sw-cor24-ocaml -- the OCaml interpreter (Pascal -> p-code) that this demo runs.
- sw-cor24-pcode --
canonical p-code VM (
pvm.s), assembler (pa24r), linker (p24-load), tracer (pv24t). - sw-cor24-emulator
-- COR24 native CPU emulator. Hosts
pvm.shere. - web-sw-cor24-pascal, web-sw-cor24-snobol4, web-sw-cor24-basic -- sibling browser demos in the same family.
- Blog: Software Wrighter Lab
- Discord: Join the community
- YouTube: Software Wrighter
Copyright (c) 2026 Michael A. Wright
MIT. (C) 2026 Michael A Wright. See LICENSE.
