backend: quoted expressions in the native back end (WEB F4) #106

Closed
opened 2026-10-05 21:07:21 +00:00 by orion · 14 comments
Collaborator

Context

Expression.value and Expression.captures are planned natives.

Source

Acceptance criteria

  • Both natives in the C back end
  • Typed form bindings work natively

Dependencies

None known.

Notes

Adds or changes a native, syntax or a name the compiler looks up: land it in two commits (teach both forms, refresh the seed, then migrate), as CLAUDE.md "Seed and breaking changes" says.

Moved from the planning lists of the docs; the design record stays the specification.

## Context `Expression.value` and `Expression.captures` are planned natives. ## Source - [WEB.md F4](https://git.torb.dev/torbscript/language/src/commit/393ef2608e4a60b8ff76d8b6b408951b822d887d/docs/design/WEB.md#L926) ## Acceptance criteria - [ ] Both natives in the C back end - [ ] Typed form bindings work natively ## Dependencies None known. ## Notes Adds or changes a native, syntax or a name the compiler looks up: land it in two commits (teach both forms, refresh the seed, then migrate), as `CLAUDE.md` "Seed and breaking changes" says. _Moved from the planning lists of the docs; the design record stays the specification._
Author
Collaborator

[loop:torbscript] intake: in scope (author orion, label loop), source WEB.md F4, not a duplicate. Adds natives, so it needs the two-commit rule (part 1, seed publish, part 2). No dependencies; ready buffer full: #4, #163, #164, #223 are ready. next: waiting (refine queued, ready buffer full) until 2026-10-10T04:00:00Z

[loop:torbscript] intake: in scope (author orion, label loop), source WEB.md F4, not a duplicate. Adds natives, so it needs the two-commit rule (part 1, seed publish, part 2). No dependencies; ready buffer full: #4, #163, #164, #223 are ready. next: waiting (refine queued, ready buffer full) until 2026-10-10T04:00:00Z
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261026 until 2026-10-26T08:00:00Z

[loop:torbscript] claim refine by session:loop-torbscript-20261026 until 2026-10-26T08:00:00Z
Author
Collaborator

[loop:torbscript] refine: the issue text is stale; only Expression.captures() and the typed-binding proof are open, next: ready

Verified on main (c72cabec)

  • Expression.value() is done: both back ends build an Expression<Value> as a record (tree, source, location, lazy value cell), compiler/src/ir/lower/quoted.trb, value() is an intrinsic in ir/lower/call.trb (no C native), held by tests/conformance/quotation-values.trb. WEB.md problem 5 is marked closed for that part; only the plannedRuntimeOf("Expression.value"/"Expression.captures", ...) rows in compiler/src/backend/c/natives.trb still read "planned".
  • Open: captures() (quoted.trb header: "is not built"; docs/language/functions/quoted-expressions.md banner). The checker already requires every capture to be Encode (semantics/checker/quote.trb, encodedCaptures), so each capture can become an EncodedValue through EncodedValue.of (std/encoding/src/values.trb).
  • Dependencies: none open. F2, F3, F5, F6 of WEB.md are done; std/web does not exist yet, so "typed form bindings" is proven with a user-defined fn input(bind: Expression<String>) in a conformance test.

decided by the loop: captures() stays an intrinsic (like value()), not a new C native: no runtime/ change, no new driver flag, no syntax, std/expression declarations unchanged. The two-commit rule therefore does not apply (single commit feat(backend): build Expression.captures natively). If the worker finds it must change a std/ declaration the compiler's own build reads, it stops and comments instead of going on. assert keeps its own special lowering (ir/lower/quote.trb) and is not touched. The captures list is a second lazy cell next to value, so a program that never calls captures() pays no run time; the extra Encode instances per captured type are measured in forge CI (binary size of the compiler/test targets) and accepted if the growth is small.

Acceptance criteria (replace the issue's)

  1. expression.captures() answers List<EncodedValue> in Captured.index order, natively and in the VM (torb run, torb test), for scalars, String, a record and a list capture; a quotation without captures answers [].
  2. A user-defined fn input(bind: Expression<String>) called as input bind: form.email builds natively and answers nameOf(bind), bind.value() and bind.captures() (the typed form binding of WEB.md 3.5).
  3. captures() is lazy: not evaluated unless asked; capture values are the ones at the quotation site, read once.
  4. plannedRuntimeOf("Expression.value"/"Expression.captures") rows gone from natives.trb (value is an intrinsic); docs banner and WEB.md problem 5 / F4 updated, skills/ regenerated.

Steps (one PR, each step one worker session)

  1. compiler/src/ir/lower/quoted.trb (+ ir/instantiate.trb layout of Expression, treeBuilderOf field count): add the hidden fifth field, a lazy cell of List<EncodedValue> built from quotation.captures via a monomorphised EncodedValue.of<T> per capture type (see lowerLazyArgument, listOfValues); fix the fields.length() != 4 check.
  2. compiler/src/ir/lower/call.trb: owner == "Expression" && name == "captures" next to value, forcing the new cell (lowerQuotedValue pattern); drop the two planned rows in backend/c/natives.trb; check the VM path through the IR (no VM change expected).
  3. Tests and docs: new tests/conformance/quotation-captures.trb (+ .expected, .exit, .allocations), a typed-binding case from criterion 2, extend compiler/tests/quotations.test.trb only if lowering text is asserted; update docs/language/functions/quoted-expressions.md (remove the captures part of the banner, keep the other unsupported nodes listed: map literal, range, implicit-self field, non-constant top-level const), docs/standard-library/expression.md, WEB.md problem 5 and F4 row, ENCODING.md slice 5 row; regenerate skills/.
    Out of scope (no issue yet, just in time): the four unsupported node kinds above.
    Gates run in forge CI only; locally torb format --check on touched files and one conformance test.
[loop:torbscript] refine: the issue text is stale; only `Expression.captures()` and the typed-binding proof are open, next: ready **Verified on main (c72cabec)** - `Expression.value()` is done: both back ends build an `Expression<Value>` as a record (tree, source, location, `lazy` value cell), `compiler/src/ir/lower/quoted.trb`, `value()` is an intrinsic in `ir/lower/call.trb` (no C native), held by `tests/conformance/quotation-values.trb`. WEB.md problem 5 is marked closed for that part; only the `plannedRuntimeOf("Expression.value"/"Expression.captures", ...)` rows in `compiler/src/backend/c/natives.trb` still read "planned". - Open: `captures()` (`quoted.trb` header: "is not built"; `docs/language/functions/quoted-expressions.md` banner). The checker already requires every capture to be `Encode` (`semantics/checker/quote.trb`, `encodedCaptures`), so each capture can become an `EncodedValue` through `EncodedValue.of` (`std/encoding/src/values.trb`). - Dependencies: none open. F2, F3, F5, F6 of WEB.md are done; `std/web` does not exist yet, so "typed form bindings" is proven with a user-defined `fn input(bind: Expression<String>)` in a conformance test. **decided by the loop:** `captures()` stays an intrinsic (like `value()`), not a new C native: no `runtime/` change, no new driver flag, no syntax, `std/expression` declarations unchanged. The two-commit rule therefore does not apply (single commit `feat(backend): build Expression.captures natively`). If the worker finds it must change a `std/` declaration the compiler's own build reads, it stops and comments instead of going on. `assert` keeps its own special lowering (`ir/lower/quote.trb`) and is not touched. The captures list is a second `lazy` cell next to `value`, so a program that never calls `captures()` pays no run time; the extra `Encode` instances per captured type are measured in forge CI (binary size of the compiler/test targets) and accepted if the growth is small. **Acceptance criteria (replace the issue's)** 1. `expression.captures()` answers `List<EncodedValue>` in `Captured.index` order, natively and in the VM (`torb run`, `torb test`), for scalars, `String`, a record and a list capture; a quotation without captures answers `[]`. 2. A user-defined `fn input(bind: Expression<String>)` called as `input bind: form.email` builds natively and answers `nameOf(bind)`, `bind.value()` and `bind.captures()` (the typed form binding of WEB.md 3.5). 3. `captures()` is lazy: not evaluated unless asked; capture values are the ones at the quotation site, read once. 4. `plannedRuntimeOf("Expression.value"/"Expression.captures")` rows gone from `natives.trb` (value is an intrinsic); docs banner and WEB.md problem 5 / F4 updated, `skills/` regenerated. **Steps (one PR, each step one worker session)** 1. `compiler/src/ir/lower/quoted.trb` (+ `ir/instantiate.trb` layout of `Expression`, `treeBuilderOf` field count): add the hidden fifth field, a `lazy` cell of `List<EncodedValue>` built from `quotation.captures` via a monomorphised `EncodedValue.of<T>` per capture type (see `lowerLazyArgument`, `listOfValues`); fix the `fields.length() != 4` check. 2. `compiler/src/ir/lower/call.trb`: `owner == "Expression" && name == "captures"` next to `value`, forcing the new cell (`lowerQuotedValue` pattern); drop the two planned rows in `backend/c/natives.trb`; check the VM path through the IR (no VM change expected). 3. Tests and docs: new `tests/conformance/quotation-captures.trb` (+ `.expected`, `.exit`, `.allocations`), a typed-binding case from criterion 2, extend `compiler/tests/quotations.test.trb` only if lowering text is asserted; update `docs/language/functions/quoted-expressions.md` (remove the captures part of the banner, keep the other unsupported nodes listed: map literal, range, implicit-`self` field, non-constant top-level `const`), `docs/standard-library/expression.md`, WEB.md problem 5 and F4 row, ENCODING.md slice 5 row; regenerate `skills/`. Out of scope (no issue yet, just in time): the four unsupported node kinds above. Gates run in forge CI only; locally `torb format --check` on touched files and one conformance test.
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261026 until 2026-10-26T08:00:00Z

[loop:torbscript] claim implement by session:loop-torbscript-20261026 until 2026-10-26T08:00:00Z
Author
Collaborator

[loop:torbscript] implement: checkpoint, design explored, no code written yet (context guard), no PR yet, next: implement (re-dispatch; the claim stays live)

Findings for the next worker (all on main c72cabec, compiler/src/ir/):

  • Layout: ir/instantiate.trb ~l.431 appends the hidden value cell field to Expression<Value>; add a second field captures with cellType program, checker, instantiation, <List<EncodedValue> TypeId>, <its IrType>. Then fix the fields.length() != 4 checks (lower/quoted.trb treeBuilderOf, lowerQuotedValue) to 5, and Construct fields in lowerQuotation (add the second cell).
  • Thunk for the cell: lower/closure.trb lowerLazyArgument takes an AST Expression (ClosureSource.Thunk), so a captures thunk needs a third ClosureSource case (e.g. Captures(quotation)) handled in lowerClosureBody (l.1276), loweredClosureBody (taskValue match, l.~1157) and the parameter-binding match (l.~1350). Split lowerLazyArgument so the cell building (cellTypeFor, emptyOptionSlot, Construct) is shared; call closureValueOf with at = the quotation span (plans come from lowering.quotedCaptures.get(at), already set in lowerQuotation, same order as Captured.index).
  • Body of that thunk: after bindCaptures, for each quotation.captures binding read its slot (lowering.slots.get(declared), or bindingReferenceOf for boxed) and emit a call to EncodedValue.of<T>: lookupStaticMember(checker, encodedValueType, "of") -> .Method(_, symbol); mapping = memberMappingOf(...) (ir/witness.trb) plus mapping.set(signature.generics.last(), captureType) for Value; instanceFor lowering, symbol, mapping (ir/instances.trb); emitCall with operands [value, bool false] (the default privateFields must be passed explicitly; StaticContents.Literal(LiteralValue.Boolean(false)) via constantSlot). Pattern to copy: emitWithCapacity in lower/collection.trb l.285. Collect the results with listOfValues(lowering, builder, slots, encodedValueTypeId, listIrType, at) and return it. EncodedValue TypeId via preludeType(lowering, "EncodedValue", []) (report unsupported if absent).
  • captures() call: lower/call.trb, next to the Expression.value intrinsic; add lowerQuotedCaptures in quoted.trb mirroring lowerQuotedValue (field 4 instead of 3, lowerForcedRead).
  • Then: drop the planned Expression.value/Expression.captures rows in backend/c/natives.trb; tests tests/conformance/quotation-captures.trb (+ .expected/.exit/.allocations) and the input bind: form.email case; docs banner, docs/standard-library/expression.md, WEB.md problem 5/F4, ENCODING.md slice 5, regenerate skills/. Single commit feat(backend): build Expression.captures natively. Gates in forge CI only.
    Worktree removed (nothing was written); recreate with ws wt new torbscript/language 106 expression-captures --branch loop/106-expression-captures.
[loop:torbscript] implement: checkpoint, design explored, no code written yet (context guard), no PR yet, next: implement (re-dispatch; the claim stays live) Findings for the next worker (all on main c72cabec, `compiler/src/ir/`): - Layout: `ir/instantiate.trb` ~l.431 appends the hidden `value` cell field to `Expression<Value>`; add a second field `captures` with `cellType program, checker, instantiation, <List<EncodedValue> TypeId>, <its IrType>`. Then fix the `fields.length() != 4` checks (`lower/quoted.trb` `treeBuilderOf`, `lowerQuotedValue`) to 5, and `Construct` fields in `lowerQuotation` (add the second cell). - Thunk for the cell: `lower/closure.trb` `lowerLazyArgument` takes an AST `Expression` (`ClosureSource.Thunk`), so a captures thunk needs a third `ClosureSource` case (e.g. `Captures(quotation)`) handled in `lowerClosureBody` (l.1276), `loweredClosureBody` (`taskValue` match, l.~1157) and the parameter-binding match (l.~1350). Split `lowerLazyArgument` so the cell building (cellTypeFor, emptyOptionSlot, Construct) is shared; call `closureValueOf` with `at` = the quotation span (plans come from `lowering.quotedCaptures.get(at)`, already set in `lowerQuotation`, same order as `Captured.index`). - Body of that thunk: after `bindCaptures`, for each `quotation.captures` binding read its slot (`lowering.slots.get(declared)`, or `bindingReferenceOf` for boxed) and emit a call to `EncodedValue.of<T>`: `lookupStaticMember(checker, encodedValueType, "of")` -> `.Method(_, symbol)`; `mapping = memberMappingOf(...)` (ir/witness.trb) plus `mapping.set(signature.generics.last(), captureType)` for `Value`; `instanceFor lowering, symbol, mapping` (ir/instances.trb); `emitCall` with operands [value, bool false] (the default `privateFields` must be passed explicitly; `StaticContents.Literal(LiteralValue.Boolean(false))` via `constantSlot`). Pattern to copy: `emitWithCapacity` in `lower/collection.trb` l.285. Collect the results with `listOfValues(lowering, builder, slots, encodedValueTypeId, listIrType, at)` and return it. `EncodedValue` TypeId via `preludeType(lowering, "EncodedValue", [])` (report unsupported if absent). - `captures()` call: `lower/call.trb`, next to the `Expression.value` intrinsic; add `lowerQuotedCaptures` in `quoted.trb` mirroring `lowerQuotedValue` (field 4 instead of 3, `lowerForcedRead`). - Then: drop the planned `Expression.value`/`Expression.captures` rows in `backend/c/natives.trb`; tests `tests/conformance/quotation-captures.trb` (+ .expected/.exit/.allocations) and the `input bind: form.email` case; docs banner, `docs/standard-library/expression.md`, WEB.md problem 5/F4, ENCODING.md slice 5, regenerate `skills/`. Single commit `feat(backend): build Expression.captures natively`. Gates in forge CI only. Worktree removed (nothing was written); recreate with `ws wt new torbscript/language 106 expression-captures --branch loop/106-expression-captures`.
Author
Collaborator

[loop:torbscript] implement: re-dispatched from checkpoint #6732 (continuation 2 of 3, light bootstrap to stay under the context guard), claim stays live, next: implement (worker running)

[loop:torbscript] implement: re-dispatched from checkpoint #6732 (continuation 2 of 3, light bootstrap to stay under the context guard), claim stays live, next: implement (worker running)
Author
Collaborator

[loop:torbscript] implement: checkpoint 2, branch loop/106-expression-captures pushed (WIP commit 53ba5a4d, amend it, keep one commit), no PR yet, next: implement (continuation 3 of 3; the claim stays live)

Done (in 53ba5a4d)

  • compiler/src/ir/instantiate.trb: buildNominalLayout appends a 5th field captures (cell of List<EncodedValue>) after value; new public fn capturesTypeOf(var checker: Checker): TypeId? = TypeForm.Traits([nominal(List, [nominal(EncodedValue, [])])]) (the same interned TypeId std/expression declares as the result of captures()). Not compiled yet: check checker.types.intern / checker.wellKnown.symbolNamed are callable from there (symbolNamed is fn on WellKnown l.137).

Left, exact recipe (all verified against main, no more exploring needed)

  1. ir/lower/closure.trb: type ClosureSource (l.261) add case Captures(quotation: Quotation, at: Span) (+ use Quotation from "../../semantics/checker/context"). Matches: loweredClosureBody taskValue (l.~1157) .Thunk(_) | .Captures(_, _) => None; bindClosureParameters (l.~1350) same, return; lowerClosureBody (l.1276) .Captures(quotation, at) => call capturesListOf(lowering, builder, quotation, result, at) (new, in quoted.trb), return unless supported, finishBlock Terminator.Return(borrowed(slot)). Split lowerLazyArgument (l.307) into a private lazyCellOf(lowering, builder, source: ClosureSource, item: TypeId, at: Span): Slot? (all of its current body, value.span -> at) and add public fn lowerCapturesCell(lowering, builder, quotation, item, at) = lazyCellOf(..., ClosureSource.Captures(quotation, at), ...). capturePlansOf already finds the plans through lowering.quotedCaptures.get(at) (set in lowerQuotation, not removed).
  2. ir/lower/quoted.trb: new public fn capturesListOf(var lowering, var builder, quotation: Quotation, annotation: IrTypeId, at: Span): Slot?: encoded = preludeTypeOrReport(lowering, "EncodedValue", at)?; lookupStaticMember(lowering.checker, encoded, "of") (semantics/checker/member) -> .Method(_, symbol); parameter = lowering.checker.signature(signatureOf(lowering.checker, symbol)).generics.last(); privateFields = constantSlot(lowering, builder, None, StaticContents.Literal(LiteralValue.Boolean(false)), booleanTypeOf(lowering)); per capture in quotation.captures: declared = lowering.checker.binding(capture.binding).at; slot = lowering.slots.get(declared), else bindingReferenceOf(lowering, builder, declared) (closure.trb l.249) + Read into a temporary; mapping = memberMappingOf(lowering, symbol, encoded, encoded) (../witness), mapping.set parameter, substituted(lowering, capture.type); function = instanceFor(lowering, symbol, mapping)? (../instances); emitCall lowering, builder, None, function, [slot, privateFields], irTypeOfClosed(lowering, encoded), at (./call, l.1060). End: listOfValues lowering, builder, values, encoded, annotation, at.
    In lowerQuotation after the value cell: item = capturesTypeOf(lowering.checker) (report unsupported if None), lowerCapturesCell lowering, builder, quotation, item, at, add borrowed(capturesCell) as 5th Construct field. treeBuilderOf (l.142) and lowerQuotedValue (l.803): != 4 -> != 5 (+ message "... value and captures"). Add lowerQuotedCaptures = lowerQuotedValue with field 4 (factor both into one forcedFieldOf(..., index, what)). Update the module doc comment (l.1-17: captures() is now built, second lazy cell).
  3. ir/lower/call.trb l.373: next to value, if owner == "Expression" && name == "captures" && operands.length() == 1 { return lowerQuotedCaptures ... } (+ import l.57).
  4. Finding: do NOT just delete the planned rows: value/captures are native fn in std/expression, and compiler/tests/natives-audit.test.trb requires a manifest entry per std native. Replace the two plannedRuntimeOf(...) rows in backend/c/natives.trb l.1988-1989 with loweredOf("Expression.value") / loweredOf("Expression.captures") (target .Lowered, like spawn); in docs/design/NATIVES.md l.850-851 set Target Lowered (verdict keep, group compiler unchanged, so the Counts section stays). Also docs/BACKEND.md l.3562 says they are .Planned("5.11"): fix.
  5. Tests/docs per refine #6713 step 3: tests/conformance/quotation-captures.trb (+ .expected/.exit/.allocations, copy the shape of quotation-values.*), fn input(bind: Expression<String>) case; docs/language/functions/quoted-expressions.md banner, docs/standard-library/expression.md, WEB.md problem 5/F4, ENCODING.md l.937 slice 5 row; regenerate skills/ (a nightly torb exists at /tmp/torb110/x/torb-nightly-20261025-linux-x64/bin/torb: torb docs skill docs skills, torb format --check <files>).
  6. Amend the single commit feat(backend): build Expression.captures natively, force-push the branch, open the PR (Closes #106), one blocking CI wait.

Worktree: /home/node/workspaces/orion/code/wt/torbscript-language-106-expression-captures (kept). Worker usage: ~90k prompt tokens (context guard at 80k).

[loop:torbscript] implement: checkpoint 2, branch `loop/106-expression-captures` pushed (WIP commit 53ba5a4d, amend it, keep one commit), no PR yet, next: implement (continuation 3 of 3; the claim stays live) **Done (in 53ba5a4d)** - `compiler/src/ir/instantiate.trb`: `buildNominalLayout` appends a 5th field `captures` (cell of `List<EncodedValue>`) after `value`; new `public fn capturesTypeOf(var checker: Checker): TypeId?` = `TypeForm.Traits([nominal(List, [nominal(EncodedValue, [])])])` (the same interned TypeId `std/expression` declares as the result of `captures()`). Not compiled yet: check `checker.types.intern` / `checker.wellKnown.symbolNamed` are callable from there (`symbolNamed` is `fn` on WellKnown l.137). **Left, exact recipe (all verified against main, no more exploring needed)** 1. `ir/lower/closure.trb`: `type ClosureSource` (l.261) add `case Captures(quotation: Quotation, at: Span)` (+ `use Quotation from "../../semantics/checker/context"`). Matches: `loweredClosureBody` taskValue (l.~1157) `.Thunk(_) | .Captures(_, _) => None`; `bindClosureParameters` (l.~1350) same, `return`; `lowerClosureBody` (l.1276) `.Captures(quotation, at) =>` call `capturesListOf(lowering, builder, quotation, result, at)` (new, in quoted.trb), return unless supported, `finishBlock Terminator.Return(borrowed(slot))`. Split `lowerLazyArgument` (l.307) into a private `lazyCellOf(lowering, builder, source: ClosureSource, item: TypeId, at: Span): Slot?` (all of its current body, `value.span` -> `at`) and add `public fn lowerCapturesCell(lowering, builder, quotation, item, at) = lazyCellOf(..., ClosureSource.Captures(quotation, at), ...)`. `capturePlansOf` already finds the plans through `lowering.quotedCaptures.get(at)` (set in `lowerQuotation`, not removed). 2. `ir/lower/quoted.trb`: new `public fn capturesListOf(var lowering, var builder, quotation: Quotation, annotation: IrTypeId, at: Span): Slot?`: `encoded = preludeTypeOrReport(lowering, "EncodedValue", at)?`; `lookupStaticMember(lowering.checker, encoded, "of")` (`semantics/checker/member`) -> `.Method(_, symbol)`; `parameter = lowering.checker.signature(signatureOf(lowering.checker, symbol)).generics.last()`; `privateFields = constantSlot(lowering, builder, None, StaticContents.Literal(LiteralValue.Boolean(false)), booleanTypeOf(lowering))`; per `capture in quotation.captures`: `declared = lowering.checker.binding(capture.binding).at`; slot = `lowering.slots.get(declared)`, else `bindingReferenceOf(lowering, builder, declared)` (closure.trb l.249) + `Read` into a temporary; `mapping = memberMappingOf(lowering, symbol, encoded, encoded)` (`../witness`), `mapping.set parameter, substituted(lowering, capture.type)`; `function = instanceFor(lowering, symbol, mapping)?` (`../instances`); `emitCall lowering, builder, None, function, [slot, privateFields], irTypeOfClosed(lowering, encoded), at` (`./call`, l.1060). End: `listOfValues lowering, builder, values, encoded, annotation, at`. In `lowerQuotation` after the value cell: `item = capturesTypeOf(lowering.checker)` (report unsupported if None), `lowerCapturesCell lowering, builder, quotation, item, at`, add `borrowed(capturesCell)` as 5th Construct field. `treeBuilderOf` (l.142) and `lowerQuotedValue` (l.803): `!= 4` -> `!= 5` (+ message "... value and captures"). Add `lowerQuotedCaptures` = `lowerQuotedValue` with field 4 (factor both into one `forcedFieldOf(..., index, what)`). Update the module doc comment (l.1-17: `captures()` is now built, second lazy cell). 3. `ir/lower/call.trb` l.373: next to `value`, `if owner == "Expression" && name == "captures" && operands.length() == 1 { return lowerQuotedCaptures ... }` (+ import l.57). 4. **Finding:** do NOT just delete the planned rows: `value`/`captures` are `native fn` in `std/expression`, and `compiler/tests/natives-audit.test.trb` requires a manifest entry per std native. Replace the two `plannedRuntimeOf(...)` rows in `backend/c/natives.trb` l.1988-1989 with `loweredOf("Expression.value")` / `loweredOf("Expression.captures")` (target `.Lowered`, like `spawn`); in `docs/design/NATIVES.md` l.850-851 set Target `Lowered` (verdict `keep`, group `compiler` unchanged, so the Counts section stays). Also `docs/BACKEND.md` l.3562 says they are `.Planned("5.11")`: fix. 5. Tests/docs per refine #6713 step 3: `tests/conformance/quotation-captures.trb` (+ `.expected/.exit/.allocations`, copy the shape of `quotation-values.*`), `fn input(bind: Expression<String>)` case; `docs/language/functions/quoted-expressions.md` banner, `docs/standard-library/expression.md`, WEB.md problem 5/F4, ENCODING.md l.937 slice 5 row; regenerate `skills/` (a nightly torb exists at `/tmp/torb110/x/torb-nightly-20261025-linux-x64/bin/torb`: `torb docs skill docs skills`, `torb format --check <files>`). 6. Amend the single commit `feat(backend): build Expression.captures natively`, force-push the branch, open the PR (`Closes #106`), one blocking CI wait. Worktree: `/home/node/workspaces/orion/code/wt/torbscript-language-106-expression-captures` (kept). Worker usage: ~90k prompt tokens (context guard at 80k).
Author
Collaborator

[loop:torbscript] implement: Expression.captures built natively (hidden 5th captures field and lazy cell, capturesListOf, intrinsic in call.trb, loweredOf manifest rows, NATIVES/BACKEND/ENCODING/WEB/quoted-expressions docs, skills regenerated, conformance quotation-captures), PR #495 (single commit 661fb742, Argus review requested), next: waiting (forge CI run 1826 pending after 10 min)

Remainder, to be fixed in the same commit once CI reports

  • Nothing was compiled or run locally: the first CI run may show compile errors in ir/lower/quoted.trb / closure.trb (the nightly torb could not parse them, so torb format --check is unchecked for both), fix on the same branch.
  • tests/conformance/quotation-captures.allocations is missing (CI prints the count; unbudgeted only with a reason) and quotation-values.allocations (302) will rise by the cells of its quotations: set both from the CI counts, with a commit message line saying why.
  • quotation-captures.expected was written by hand: the order 100, 18 for base + minimum + base and "Grace" for a String capture are assumptions; correct them from the CI diff.

Worktree code/wt/torbscript-language-106-expression-captures is pushed and kept for the fix round.

[loop:torbscript] implement: Expression.captures built natively (hidden 5th `captures` field and lazy cell, `capturesListOf`, intrinsic in call.trb, `loweredOf` manifest rows, NATIVES/BACKEND/ENCODING/WEB/quoted-expressions docs, skills regenerated, conformance `quotation-captures`), PR https://git.torb.dev/torbscript/language/pulls/495 (single commit 661fb742, Argus review requested), next: waiting (forge CI run 1826 pending after 10 min) **Remainder, to be fixed in the same commit once CI reports** - Nothing was compiled or run locally: the first CI run may show compile errors in `ir/lower/quoted.trb` / `closure.trb` (the nightly torb could not parse them, so `torb format --check` is unchecked for both), fix on the same branch. - `tests/conformance/quotation-captures.allocations` is missing (CI prints the count; `unbudgeted` only with a reason) and `quotation-values.allocations` (302) will rise by the cells of its quotations: set both from the CI counts, with a commit message line saying why. - `quotation-captures.expected` was written by hand: the order `100, 18` for `base + minimum + base` and `"Grace"` for a `String` capture are assumptions; correct them from the CI diff. Worktree `code/wt/torbscript-language-106-expression-captures` is pushed and kept for the fix round.
Author
Collaborator

[loop:torbscript] claim fix by session:loop-torbscript-20261026 until 2026-10-26T08:00:00Z (PR 495 bootstrap red)

[loop:torbscript] claim fix by session:loop-torbscript-20261026 until 2026-10-26T08:00:00Z (PR 495 bootstrap red)
Author
Collaborator

[loop:torbscript] fix: the bootstrap compile errors are fixed in the single commit (now bbeba43b, force-pushed): closure.trb called the enum case ClosureSource.Thunk value without parentheses, quoted.trb had match capturesTypeOf lowering.checker { (needs parentheses) and used type as a binding name (keyword, now capturedType); the nightly torb parses both files and torb format --check is clean; check-commits.sh clean; Argus review re-requested. next: waiting (forge CI run 1841 still queued after 11 min, no job started)

Remainder, to be fixed in the same commit once CI reports

  • The first run that actually compiles may show further type errors in ir/lower/quoted.trb / closure.trb / instantiate.trb (never compiled before; the nightly torb is too old to check them): fix on the same branch.
  • tests/conformance/quotation-captures.allocations is still missing (CI prints the count; unbudgeted only with a reason) and quotation-values.allocations (302) will rise: set both from the CI counts, with a commit message line saying why.
  • quotation-captures.expected was written by hand (order 100, 18 for base + minimum + base, "Grace" for the String capture): correct it from the CI diff.

Worktree code/wt/torbscript-language-106-expression-captures is removed; recreate it from loop/106-expression-captures.

[loop:torbscript] fix: the bootstrap compile errors are fixed in the single commit (now bbeba43b, force-pushed): `closure.trb` called the enum case `ClosureSource.Thunk value` without parentheses, `quoted.trb` had `match capturesTypeOf lowering.checker {` (needs parentheses) and used `type` as a binding name (keyword, now `capturedType`); the nightly torb parses both files and `torb format --check` is clean; `check-commits.sh` clean; Argus review re-requested. next: waiting (forge CI run 1841 still queued after 11 min, no job started) **Remainder, to be fixed in the same commit once CI reports** - The first run that actually compiles may show further type errors in `ir/lower/quoted.trb` / `closure.trb` / `instantiate.trb` (never compiled before; the nightly torb is too old to check them): fix on the same branch. - `tests/conformance/quotation-captures.allocations` is still missing (CI prints the count; `unbudgeted` only with a reason) and `quotation-values.allocations` (302) will rise: set both from the CI counts, with a commit message line saying why. - `quotation-captures.expected` was written by hand (order `100, 18` for `base + minimum + base`, `"Grace"` for the `String` capture): correct it from the CI diff. Worktree `code/wt/torbscript-language-106-expression-captures` is removed; recreate it from `loop/106-expression-captures`.
Author
Collaborator

[loop:torbscript] claim fix by session:loop-torbscript-20261026-0724 until 2026-10-26T13:16:00Z (PR 495: not mergeable after main moved to 4f8e15cf, rebase and fix CI findings)

[loop:torbscript] claim fix by session:loop-torbscript-20261026-0724 until 2026-10-26T13:16:00Z (PR 495: not mergeable after main moved to 4f8e15cf, rebase and fix CI findings)
Author
Collaborator

[loop:torbscript] fix (checkpoint): rebased the single commit onto main 4f8e15cf (one conflict in compiler/src/ir/lower/call.trb, resolved by keeping both the Expression.captures case and main's nativeEntryOf call), new head 3a0c2f56, tools/check-commits.sh clean, force-pushed to loop/106-expression-captures. Forge CI of the new head: bootstrap (linux-x64) is green (the earlier compile errors are gone); tier B is red on three gates, all from this change: (1) tests/conformance/quotation-captures.trb:15 does not compile, "{nameOf bind} = {bind.value()}" reports Cannot infer Value of nameOf plus Expected } after the expression (command-call inside an interpolation; write {nameOf(bind)} and check whether nameOf needs a type argument), failing in the native build and in both VM lanes; (2) tests/conformance/quotation-values.trb allocates 330 blocks against its budget of 302 (+28), so either the captures cell is built eagerly where it should be lazy, or the budget needs sh tools/conformance.sh --update-budgets --filter quotation-values after checking the cause. gates, tier A and the other jobs were still pending. Argus review not re-requested yet (CI red). Queue wait was about 55 min before the first job started. Token usage of this worker: about 100k. next: fix round continues in worktree torbscript-language-106 (waiting for a continuation worker)

[loop:torbscript] fix (checkpoint): rebased the single commit onto main 4f8e15cf (one conflict in `compiler/src/ir/lower/call.trb`, resolved by keeping both the `Expression.captures` case and main's `nativeEntryOf` call), new head 3a0c2f56, `tools/check-commits.sh` clean, force-pushed to `loop/106-expression-captures`. Forge CI of the new head: `bootstrap (linux-x64)` is green (the earlier compile errors are gone); `tier B` is red on three gates, all from this change: (1) `tests/conformance/quotation-captures.trb:15` does not compile, `"{nameOf bind} = {bind.value()}"` reports `Cannot infer Value of nameOf` plus `Expected } after the expression` (command-call inside an interpolation; write `{nameOf(bind)}` and check whether `nameOf` needs a type argument), failing in the native build and in both VM lanes; (2) `tests/conformance/quotation-values.trb` allocates 330 blocks against its budget of 302 (+28), so either the captures cell is built eagerly where it should be lazy, or the budget needs `sh tools/conformance.sh --update-budgets --filter quotation-values` after checking the cause. `gates`, `tier A` and the other jobs were still pending. Argus review not re-requested yet (CI red). Queue wait was about 55 min before the first job started. Token usage of this worker: about 100k. next: fix round continues in worktree `torbscript-language-106` (waiting for a continuation worker)
Author
Collaborator

Checkpoint (Orion loop): head e3248733 on loop/106-expression-captures, PR 495. Fixed the two tier B failures: (1) quotation-captures.trb now writes {nameOf(bind)} (a command call is not valid inside an interpolation); (2) quotation-values allocated 330 vs 302 because every quotation got a memo cell (+ an environment when it captures) for captures() whether asked or not. captures() is now a plain thunk field with no cell: a capture-free quotation makes no block for it, a capturing one only its environment. Budget untouched; if the count still differs, CI names it and I adjust. CI is queued on the shared runners (gates/pdisc pending), tier A/B/bootstrap not started yet. Next: wait for full green, then re-request Argus.

Checkpoint (Orion loop): head e3248733 on loop/106-expression-captures, PR 495. Fixed the two tier B failures: (1) quotation-captures.trb now writes `{nameOf(bind)}` (a command call is not valid inside an interpolation); (2) quotation-values allocated 330 vs 302 because every quotation got a memo cell (+ an environment when it captures) for `captures()` whether asked or not. `captures()` is now a plain thunk field with no cell: a capture-free quotation makes no block for it, a capturing one only its environment. Budget untouched; if the count still differs, CI names it and I adjust. CI is queued on the shared runners (gates/pdisc pending), tier A/B/bootstrap not started yet. Next: wait for full green, then re-request Argus.
Author
Collaborator

[loop:torbscript] release fix: the fix worker pushed e3248733 (quotation-captures interpolation fix, captures() thunk without a memo cell) and ended while forge CI of that head was still queued; remainder per the checkpoint above (adjust quotation-values.allocations if tier B reports a count above 302, then re-request Argus). next: waiting (CI on PR 495 head e3248733)

[loop:torbscript] release fix: the fix worker pushed e3248733 (quotation-captures interpolation fix, captures() thunk without a memo cell) and ended while forge CI of that head was still queued; remainder per the checkpoint above (adjust quotation-values.allocations if tier B reports a count above 302, then re-request Argus). next: waiting (CI on PR 495 head e3248733)
argus closed this issue 2026-10-26 12:16:02 +00:00
Sign in to join this conversation.
No labels
loop
ready
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#106
No description provided.