Merge ocaml-vm: document VM debugging tools in CLAUDE.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
66
CLAUDE.md
66
CLAUDE.md
@@ -385,3 +385,69 @@ Python-based MCP server for understanding the microservice topology. Static anal
|
||||
| `svc_stop` | Stop all services |
|
||||
| `svc_queries` | List all defquery definitions from queries.sx files |
|
||||
| `svc_actions` | List all defaction definitions from actions.sx files |
|
||||
### VM / Bytecode Debugging Tools
|
||||
|
||||
These are OCaml server commands sent via the epoch protocol (`printf '(epoch N)\n(command args)\n' | sx_server.exe`). They're available in any context where the OCaml kernel is running (dev server, CLI, tests).
|
||||
|
||||
```bash
|
||||
# Full build pipeline — OCaml + JS browser + JS test + run tests
|
||||
./scripts/sx-build-all.sh
|
||||
|
||||
# WASM boot test — verify sx_browser.bc.js loads in Node.js without a browser
|
||||
bash hosts/ocaml/browser/test_boot.sh
|
||||
```
|
||||
|
||||
#### `(vm-trace "<sx-source>")`
|
||||
Step through bytecode execution. Returns a list of trace entries, each with:
|
||||
- `:opcode` — instruction name (CONST, CALL, JUMP_IF_FALSE, etc.)
|
||||
- `:stack` — top 5 values on the stack at that point
|
||||
- `:depth` — frame nesting depth
|
||||
|
||||
Requires the compiler to be loaded (`lib/compiler.sx`). Use this to debug unexpected VM behavior — it shows exactly what the bytecode does step by step.
|
||||
|
||||
```bash
|
||||
printf '(epoch 1)\n(load "lib/compiler.sx")\n(epoch 2)\n(vm-trace "(+ 1 2)")\n' | sx_server.exe
|
||||
```
|
||||
|
||||
#### `(bytecode-inspect "<function-name>")`
|
||||
Disassemble a compiled function's bytecode. Returns a dict with:
|
||||
- `:arity` — number of parameters
|
||||
- `:num_locals` — stack frame size
|
||||
- `:constants` — constant pool (strings, numbers, symbols)
|
||||
- `:bytecode` — list of instructions, each with `:offset`, `:opcode`, `:operands`
|
||||
|
||||
Only works on functions that have been JIT-compiled (have a `vm_closure`). Use this to verify the compiler emits correct bytecode.
|
||||
|
||||
```bash
|
||||
printf '(epoch 1)\n(bytecode-inspect "my-function")\n' | sx_server.exe
|
||||
```
|
||||
|
||||
#### `(deps-check "<sx-source>")`
|
||||
Strict symbol resolution checker. Parses the source, walks the AST, and checks every symbol reference against:
|
||||
- Environment bindings (defines, let bindings)
|
||||
- Primitive functions table
|
||||
- Special form names (if, when, cond, let, define, etc.)
|
||||
|
||||
Returns `{:resolved (...) :unresolved (...)}`. Run this on `.sx` files before compilation to catch typos and missing imports (e.g., `extract-verb-info` vs `get-verb-info`).
|
||||
|
||||
```bash
|
||||
printf '(epoch 1)\n(deps-check "(defcomp ~my-comp () (div (frobnicate x)))")\n' | sx_server.exe
|
||||
# => {:resolved ("defcomp" "div") :unresolved ("frobnicate" "x")}
|
||||
```
|
||||
|
||||
#### `(prim-check "<function-name>")`
|
||||
Scan compiled bytecode for `CALL_PRIM` instructions and verify each primitive name exists in the runtime. Returns `{:valid (...) :invalid (...)}`. Catches mismatches like `length` vs `len` that would crash at runtime.
|
||||
|
||||
```bash
|
||||
printf '(epoch 1)\n(prim-check "my-compiled-fn")\n' | sx_server.exe
|
||||
# => {:valid ("+" "len" "first") :invalid ("length")}
|
||||
```
|
||||
|
||||
### SX Island Authoring Rules
|
||||
|
||||
Key patterns discovered from the reactive runtime demos (see `sx/sx/reactive-runtime.sx`):
|
||||
|
||||
1. **Multi-expression bodies need `(do ...)`** — `fn`, `let`, and `when` bodies evaluate only the last expression. Wrap multiples in `(do expr1 expr2 expr3)`.
|
||||
2. **`let` is parallel, not sequential** — bindings in the same `let` can't reference each other. Use nested `let` blocks when functions need to reference signals defined earlier.
|
||||
3. **Reactive text needs `(deref (computed ...))`** — bare `(len (deref items))` is NOT reactive. Wrap in `(deref (computed (fn () (len (deref items)))))`.
|
||||
4. **Effects go in inner `let`** — signals in outer `let`, functions and effects in inner `let`. The OCaml SSR evaluator can't resolve outer `let` bindings from same-`let` lambdas.
|
||||
|
||||
Reference in New Issue
Block a user