v3 Capstone: Full Pipeline
Lesson, slides, and applied problem sets.
View SlidesLesson
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:
- Compile-time: nested function references and captured names are resolved in scope chain
- 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)