Download Game! Currently 107 players and visitors. Last logged in:BrogTenuTohvuCaitline

Blitzer's Blog >> 72254

Back to blogs index
Posted: 10 Sep 2026 16:10 [ permalink ]
Spot on. Option 2 strikes the perfect balance. By using a record, the AST
remains entirely unambiguous and self-documenting. Anyone (or any AI) reading
the raw JSON immediately understands the routing intent without having to
memorize argument positions, and you gain the flexibility to add keys like
retries, headers, or abort_signal later without breaking older compilers.
Here is exactly how this integrates into your JL-AST architecture.
1. The AST Standard Update
If you are keeping your AST_REFERENCE.md up to date, you can append this block
to define the new primitive:
## 6. Asynchronous Dispatch (CPS)
To perform host-level I/O without blocking the VM, use the `dispatch` command.
It takes a target name, an array of arguments, and a configuration record for
routing callbacks.

**Syntax:** `["dispatch", target_name, args_array, config_record]`

**Example:**
```json
[
  "dispatch", "mesh_fetch", ["array", "[https://api.mesh](https://api.mesh)"],
  ["record", 
    "on_success", "handle_ok",
    "on_timeout", "handle_err",
    "timeout_ms", 5000
  ]
]

2. Implementation Roadmap
To wire this up in your current codebase, we need to make four surgical
updates.
A. Core Opcodes (src/core/opcodes.js)
Add DISPATCH: 'OP_DISPATCH' to your freeze object.
B. Compiler (src/compiler/compiler.js)
Add the compilation rule. Its wonderfully simple because it just relies on
your existing array and record logic:
if (op === 'dispatch') {
  compile(args[0], bytecode, options); // Push target (e.g., "mesh_fetch")
  compile(args[1], bytecode, options); // Push arguments array
  compile(args[2], bytecode, options); // Push config record
  bytecode.push({ op: Opcodes.DISPATCH });
  return bytecode;
}

C. The VM Loop (src/vm/vm.js)
Here is a crucial architectural shift: Your SharedArrayBuffer is 12 bytes
(perfect for fast integer status polling), but a dispatch requires sending
strings and objects to the host.
Instead of writing to the StateBuffer, the VM will use Node's native message
passing to seamlessly bridge the pure logic and the host environment:
case Opcodes.DISPATCH: {
  const config = dataStack.pop();
  const argsArr = dataStack.pop();
  const target = dataStack.pop();
  
  // Ask the host to perform the I/O
  const { parentPort } = require('worker_threads');
  parentPort.postMessage({ 
    type: 'DISPATCH', 
    target, 
    args: argsArr, 
    config 
  });
  break;
}

D. The Host / Gateway (src/runtime/main.js)
The main thread listens for this message, executes the native code (or passes
it to your Cloudflare Worker edge tunnels), sets up the timeout race, and
posts an INVOKE message back to the worker to trigger the callback.
Because this shifts the VM from a simple "run once and exit" script into a
persistent, event-driven microkernel, we will need to wrap your while
(callStack.length > 0) loop in a function that can be re-triggered whenever a
callback arrives from the host.
Would you like the shell snippets to apply these exact updates to your
compiler and VM files via the Android terminal?