v3 Capstone: Full Pipeline

Lesson, slides, and applied problem sets.

View Slides

Lesson

v3 Capstone: closures, collections, and GC in end-to-end execution

Why this module exists

At v3, features only “work” if the entire toolchain is correct:

  • parser and analyzer must agree on scope/capture rules
  • compiler must emit closure and collection instructions consistently
  • serializer/deserializer must preserve runtime semantics
  • VM must interpret those instructions with correct object behavior

This module is the first where feature interactions dominate single-module complexity.


1) Integration contract, not just stage order

The pipeline is still:

Lex -> Parse -> Analyze -> Compile -> Encode -> Decode -> Run

But now each edge has a contract:

  • parser/analyzer output is input shape-compatible with compiler
  • compiler output is serializable BC artifact
  • encoded bytes deserialize into equivalent executable object graph
  • VM executes only decoded artifact, never compiler internals

If any boundary contract breaks, the capstone test should fail at that boundary, not later in unrelated code.


2) Fresh execution context per invocation

CompileAndRun should instantiate a fresh VM state for each call:

  • new operand stack
  • new frame stack
  • new scopes/globals
  • fresh heap metadata

This prevents hidden cross-run coupling and makes outputs deterministic:

  • repeat same source
  • get same result
  • avoid leak of globals, closures, or prior heap history

3) Closure correctness through boundaries

For closure programs, two invariants must hold across stages:

  1. Compile-time: nested function references and captured names are resolved in scope chain
  2. Runtime: closure object carries capture information and callable identity

Failure signatures:

  • unresolved identifier in nested function => analyzer/compile failure before emit
  • emitted call to non-closure value => runtime call error
  • missing capture info => function observes wrong values at runtime

The point is to explicitly test closure boundaries, not just lexical syntax.


4) Collection semantics in capstone runs

Arrays and maps now pass through every stage:

  • literal syntax parsed into AST nodes
  • lowered into bytecode (MAKE_ARRAY, MAKE_MAP)
  • serialized as part of BC artifacts
  • deserialized back into runtime object-producing instructions
  • executed with index read/write opcodes

This tests three contracts simultaneously:

  • instruction selection
  • serializer fidelity
  • runtime object identity/alias behavior

5) Error phase discipline

Keep strict error phase order:

  • lex/parse first
  • analyzer second
  • compile/encode third
  • decode before run
  • runtime errors last

This avoids confusing learners with cascaded failures: runtime panic from malformed source is a sign that an earlier contract leaked.

When multiple analyzer diagnostics exist, return deterministic first error to preserve stable grading.


6) Determinism and golden artifacts

A practical capstone quality measure:

  • same source text produces same serialized artifact (within canonical formatting)
  • decode->run is deterministic for return value and side effects
  • failures are stable across repeated invocation

This allows strong end-to-end tests and future optimization tests that only change one stage at a time.


7) Practice checkpoints (almost solved)

1) Closure capture flow + Program: +let x = 10; fn makeAdder(y) { return y + x; } makeAdder(2); + Expected: +- capture of x preserved through compile and runtime +- final result 12 + +2) Collection pressure + +Program: +let a = [1, 2, 3]; a[1] = 9; let b = {"k": 1}; + +Expected: +- compiler emits array/map ops and index assignment opcodes +- runtime executes on heap-backed objects + +3) Analyzer gate + +Program: let x = unknown + 1; + +Expected: +- analyzer error is returned +- no encode/decode/run + +4) Serialization boundary + +If encode output is malformed, expect decode error before VM invocation. + +5) Idempotent run + +Run same valid program twice with CompileAndRun. +- same BC artifact shape +- same decoded behavior +- no leftover state across runs + +6) Non-callable call + +Program that computes an array( ) style invalid call path where callee is not callable. + +Expected: +- runtime call error, not silent no-op.

This module is where all previously learned pieces are tested together under one deterministic execution contract.


Module Items

  • Compile and Run v3 (Capstone)

    Connect v3 lexing, parsing, analysis, compilation, IO, and VM execution.

    hard Upgrade to Pro to access hard problems
Join Discord