v3 Capstone: Full Pipeline

Work through examples, try the reasoning yourself, then put it into practice.

View Slides

Before you start

  • Finish v3 parsing, analysis, compilation, VM/GC, and BC2.

What you will practice

  • Trace returned closures and container aliases through every stage.
  • Classify static name errors versus dynamic call/index errors.
  • Construct observable assertions and repeat-run isolation checks.
In this lesson

Lesson

3 min read

v3 Capstone: Full Pipeline

The v3 integration path is Lex → Parse → Analyze → Compile → Encode → Decode → NewVM().Run. Compile and Encode return direct values; Analyze returns an ordered diagnostic list. Return immediately on the first failing boundary. Modules and linking have not been introduced.

Worked reconstruction

fn make(start) {
  var n=start;
  fn next(){ n=n+1; return n; }
  return next;
}
let c=make(10);
let values=[c(),c()];
if (values[0]!=11) { 1/0; }
if (values[1]!=12) { 1/0; }

Parsing represents c() with a callee expression. Analysis resolves n through the nested scopes, and permits c to hold a callable value. Compilation reserves function IDs and emits closure creation; BC2 transports code and IDs, not live environment pointers. The VM creates environments when executing make and next. The two calls share one captured n and construct array [11,12]. Both assertion branches are skipped, and ordinary top-level completion returns nil.

The same source called again through CompileAndRun creates a fresh VM and starts again at n=10. Reusing the previous global environment would violate this invocation boundary. A standalone GC test is still needed to prove reclamation and transitive retention; capstone success alone does not do so.

Failure classification

Program idea Earliest relevant failure
Missing ] Parsing
Captured name declared only later Analysis
Known function called with wrong arity Analysis
Variable containing number used as callee Runtime
Array indexed outside its bounds Runtime
Unknown opcode in a supplied artifact Decode

The artifact boundary must be exercised even when direct execution of the compiler result appears correct. A closure's environment is runtime state; trying to serialize a Go Env pointer into BC2 would confuse code with one particular execution instance.

Integration gate

Retain the counter test, a container alias mutation, and one dynamic error. For each, identify the AST shape and bytecode instruction responsible for the behavior. Run two independent invocations, then inspect a decoded artifact. This is the preparation for v4's additional control-flow paths.

Debugging lab

The counter returns 11 twice after a compiler/runtime refactor, while its BC2 still contains the same function IDs. List the environment evidence needed before changing the parser.

Compare your diagnosis after attempting the lab

Check where MAKE_CLOSURE captured its environment, whether CALL parents the new environment to that capture, and whether STORE updates the existing n binding. Stable IDs prove code identity only, not correct shared mutable capture.

Transfer task

Create two independent returned closures stored in a map. Invoke one twice and the other once; assert their distinct histories using conditional division-by-zero failures. Predict the result of running the complete program twice.

Carry forward

Carry verified callable-value and heap behavior into v4. The next milestone changes branches and loop exits, so preserve these earlier regression programs while adding new path tests.

Build compile-and-run-v3. Keep a before/after trace of one failing test. Use the checkpoint to diagnose specific skills; passing it does not replace implementing and testing the artifact.


Practice sequence

Use the order below for a guided path, or choose an item to revisit. A pass records a successful attempt; try a fresh example later to check what you can reconstruct.

Join Discord