v4 Capstone: Full Pipeline

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

View Slides

Before you start

  • Complete v4 lexical, parsing, semantic, and lowering changes.
  • Retain v3 callable-value and heap regression cases.

What you will practice

  • Validate lazy evaluation and loop cleanup through BC2 transport.
  • Make internal loop state observable despite nil program results.
  • Enforce semantic failure before runtime side effects.
In this lesson

Lesson

3 min read

v4 Capstone: Full Pipeline

The v4 integration path is still Lex → Parse → Analyze → Compile → Encode → Decode → NewVM().Run. It handles one Program; linking and module initialization begin in v5. The helper return shapes match v3: Compile and Encode return their artifacts directly; other failing helpers return errors, and Analyze returns a diagnostic slice whose first entry is surfaced.

Worked reconstruction

let total=0;
for (let i=0; i<4; i=i+1) {
  if (i==1) { continue; }
  total=total+i;
}
if (total!=5) { 1/0; }
false && (1/0);

The loop adds 0, 2, and 3. Continue still executes post, so i advances past 1. The assertion observes total without exposing the VM's private environment. The last expression compiles both operands but skips its division at runtime; its boolean result is popped as an expression statement. Success returns nil, not total=5 and not the final false value.

Separate three kinds of skipping

The parser still reads the RHS of &&/||. The analyzer still visits it. Only runtime evaluation is skipped on the selected branch. Therefore replacing the last RHS with missing() changes success into a semantic error. Replacing it with malformed syntax fails even earlier. Bytecode inspection can confirm that valid skipped RHS code is present but not executed.

Integration gate

Exercise a for continue with post, a for without post, a while continue, a break in a nested block, and an inner loop break that leaves the outer loop alive. Also retain the earlier closure/collection tests: adding path cleanup must not lose captured environments. A nested function containing an unscoped break must fail analysis even when its declaration occurs inside an outer loop.

Run the decoded BC2 object, not the original compiler object as a fallback. Return earlier failures immediately, and create a fresh VM per invocation. When debugging a failed assertion, inspect the AST clauses, target addresses, and scope exits before changing arithmetic operations.

Debugging lab

A program with top-level break and a later 1/0 returns division-by-zero. Another returns the final expression’s boolean after false && (1/0);. Locate the wrong boundary in each implementation.

Compare your diagnosis after attempting the lab

The first ignored the analyzer gate and executed invalid source. The second omitted expression-statement POP or invented an implicit program-result convention. Correct ordinary top-level completion returns nil.

Transfer task

Create a nested-loop program with a returned closure capturing an outer binding. Add independent assertions for its loop total and closure result, then insert an undefined name in a skipped RHS and predict the new first failure.

Carry forward

Carry the single-program BC2 baseline into v5. The new risk will be relocating separately compiled artifacts, not reinterpreting existing boolean or loop semantics.

Build compile-and-run-v4. 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