Skip to content

Extend test evaluator: enums, match, shapes, borrows, mutref writeback#60

Open
dragonlightintl wants to merge 2 commits into
vercel-labs:mainfrom
dragonlightintl:dragonlight/compiled-test-backend
Open

Extend test evaluator: enums, match, shapes, borrows, mutref writeback#60
dragonlightintl wants to merge 2 commits into
vercel-labs:mainfrom
dragonlightintl:dragonlight/compiled-test-backend

Conversation

@dragonlightintl
Copy link
Copy Markdown

@dragonlightintl dragonlightintl commented May 17, 2026

Summary

The zero test direct-frontend evaluator previously only handled expressions composed of integer/bool literals, if statements, and same-file function calls with primitive-only bodies. This PR extends the evaluator in two commits to handle the constructs needed for real-world test coverage:

First commit — enums, match, arrays, choices:

  • Qualified enum access: Stage.testing resolves to the case index integer
  • Match statements: dispatches on enum discriminant, including _ fallback
  • Choice constructors: both nullary (GateOutcome.passed) and with payload (HandoffValidation.invalid("reason"))
  • Array literals and indexing: [Stage.testing, Stage.coding] and arr[0]
  • Variable assignment and while loops
  • Null literals and type casts

Second commit — borrow expressions and shape mutation:

  • EXPR_BORROW support: &x (ref) and &mut x (mutref) expressions evaluate to their underlying value in the test runner
  • EXPR_MEMBER field assignment: shape.field = value updates the field in-place in the test environment (STMT_ASSIGN with EXPR_MEMBER target)
  • mutref writeback: functions with mutref<T> parameters propagate field modifications back to the caller's binding via test_eval_function_with_caller

Motivation

Without these constructs, only functions with primitive-only bodies (no match, no enums, no shapes, no borrows) can be tested through zero test. In practice, most real pipeline logic — which uses enums, match for exhaustive dispatch, and shapes with mutable methods — can only be verified via zero check (type-correctness) but not execution-tested.

This change enables tests like:

shape Point {
  x: i32,
  y: i32,
}

fun move_point(p: mutref<Point>, dx: i32, dy: i32) -> Void {
  p.x = p.x + dx
  p.y = p.y + dy
}

test "mutref writeback propagates field changes" {
  let mut p = Point { x: 1, y: 2 }
  move_point(&mut p, 10, 20)
  expect(p.x == 11)
  expect(p.y == 22)
}

Approach

Extends the existing AST interpreter rather than introducing a compiled-test backend. The evaluator already handled if, let, return, expect, binary operators, shape literals, shape field access, and function calls. This PR adds handlers for the remaining common AST node types.

All changes are in native/zero-c/src/main.c (+350 lines total across both commits).

What's NOT included

  • Choice match dispatch (matching on choice type discriminants) — the STMT_MATCH handler currently only resolves enum types
  • Cross-module function resolution in test scope — functions from imported modules still fail; separate issue

Test plan

  • All existing conformance test fixtures produce identical results (test-blocks.0, test-expected-fail.0, test-expect-runtime-fail.0, test-unexpected-pass.0, test-expect-non-bool.0)
  • Builds cleanly with -Wall -Wextra -Wpedantic (no new warnings)
  • Enum access, match dispatch, shape construction, array literals, and choice constructors evaluate correctly in test blocks
  • ref<T> and mutref<T> borrow expressions evaluate to their operand in the test runner
  • shape.field = value assignment updates the field in-place in the test environment
  • Functions with mutref<T> params write modified field state back to the caller's binding after the call returns
  • Existing zero check behavior unchanged for all example files

@vercel
Copy link
Copy Markdown

vercel Bot commented May 17, 2026

@dragonlightintl is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

…pressions

The direct-frontend test backend was an AST-level interpreter that only
supported primitives and if statements. Any test whose call chain touched
match, qualified enum access (Stage.testing), shape construction with
enum fields, array literals, or index expressions would fail with
"unknown identifier", "does not support this expression yet", or
"does not support this statement yet".

This extends the interpreter to handle the missing constructs:
- Qualified enum access (Stage.testing) resolves to the case index
- Match statements evaluate the discriminant and dispatch to the
  matching arm, including fallback (_) arms
- Choice constructors (ChoiceName.variant(payload)) in both nullary
  member-access form and call form
- Array literal expressions (EXPR_ARRAY_LITERAL)
- Array index expressions (EXPR_INDEX)
- Variable assignment statements (STMT_ASSIGN)
- While loop statements (STMT_WHILE)
- Null literals (EXPR_NULL)
- Cast expressions (EXPR_CAST) pass through to the inner value
- EXPR_BORROW: &x and &mut x evaluate to their operand in the test
  runner; mutref writeback is handled at call boundaries
- EXPR_MEMBER assignment: shape.field = value updates the field
  in-place in the test environment
- mutref writeback: functions with mutref<T> params propagate
  modified field state back to the caller's binding via
  test_eval_function_with_caller
@dragonlightintl dragonlightintl force-pushed the dragonlight/compiled-test-backend branch from cdf526c to 19a5200 Compare May 18, 2026 07:52
@dragonlightintl dragonlightintl changed the title Extend test evaluator to support enums, match, arrays, and choices Extend test evaluator: enums, match, shapes, borrows, mutref writeback May 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant