Section 15C: Literals & Operators
Goal: Implement string interpolation, spread operator, range step syntax, and pipe operator
Source:
docs/ori_lang/proposals/approved/
15C.1 String Interpolation
Proposal: proposals/approved/string-interpolation-proposal.md
Add template strings with backtick delimiters and {expr} interpolation.
let name = "Alice"
let age = 30
print(msg: `Hello, {name}! You are {age} years old.`)
Two string types:
"..."— regular strings, no interpolation, braces are literal`...`— template strings with{expr}interpolation
Lexer
-
Implement: Add template string literal tokenization (backtick delimited) [done] (verified 2026-03-29)
- Rust Tests:
oric/tests/phases/parse/lexer.rs—test_lex_template_literal,test_lex_template_full_content,test_lex_template_interpolation,test_lex_template_multiple_interpolations,test_lex_template_format_spec,test_lex_template_format_spec_complex - Ori Tests:
tests/spec/expressions/template_literals.ori(all pass) - LLVM Support: Format runtime in
ori_rt/src/format/withori_format_int/float/str/bool/char - LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— WEAK TESTS: this file does not exist (verified 2026-03-29) - AOT Tests: AOT spec tests in
ori_llvm/tests/aot/spec.rsinclude template literal tests
- Rust Tests:
-
Implement: Handle
{expr}interpolation boundaries (switch lexer modes) [done] (verified 2026-03-29)- LLVM Support: LLVM codegen for interpolation boundaries
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— interpolation boundaries codegen - AOT Tests: No AOT coverage yet
-
Implement: Handle
{{and}}escape for literal braces- Ori Tests:
tests/spec/lexical/template_brace_escape.ori - LLVM Support: LLVM codegen for brace escaping
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— brace escaping codegen - AOT Tests: No AOT coverage yet
- Ori Tests:
-
Implement: Handle
\`escape for literal backtick [done] (verified 2026-03-29)- Rust Tests:
ori_lexer/src/cook_escape/tests.rs—template_backtick_escapetest passes - Ori Tests:
tests/spec/lexical/template_backtick_escape.ori - LLVM Support: LLVM codegen for backtick escaping
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— backtick escaping codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Support escapes:
\\,\n,\t,\r,\0in template strings [done] (verified 2026-03-29)- Ori Tests:
tests/spec/lexical/template_escapes.ori - LLVM Support: LLVM codegen for template escapes
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— template escapes codegen - AOT Tests: No AOT coverage yet
- Ori Tests:
-
Implement: Multi-line template strings (preserve whitespace exactly)
- Ori Tests:
tests/spec/lexical/template_multiline.ori - LLVM Support: LLVM codegen for multiline template strings
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— multiline codegen - AOT Tests: No AOT coverage yet
- Ori Tests:
Parser
-
Implement: Parse template strings as sequence of
StringPart(Literal | Interpolation) [done] (verified 2026-03-29)- Rust Tests:
ori_parse/src/grammar/expr/primary/specials.rs—parse_template_literalproducesExprKind::TemplateStrwithTemplatePartsequence - Ori Tests:
tests/spec/expressions/interpolation.ori - LLVM Support: LLVM codegen for template string parsing
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— template string parsing codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Parse interpolated expressions (full expression grammar inside
{}) [done] (verified 2026-03-29)- Ori Tests:
tests/spec/expressions/interpolation_expressions.ori - LLVM Support: LLVM codegen for interpolated expressions
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— interpolated expressions codegen - AOT Tests: No AOT coverage yet
- Ori Tests:
-
Implement: Parse optional format specifiers
{expr:spec}[done] (verified 2026-03-29)- Rust Tests:
ori_ir/src/format_spec.rs— full format spec parser withParsedFormatSpecstruct - Ori Tests:
tests/spec/expressions/format_specifiers.ori - LLVM Support: LLVM codegen for format specifiers
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— format specifiers codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Parse format spec grammar:
[[fill]align][width][.precision][type][done] (verified 2026-03-29)- Ori Tests:
tests/spec/expressions/format_spec_grammar.ori - LLVM Support: LLVM codegen for format spec grammar
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— format spec grammar codegen - AOT Tests: No AOT coverage yet
- Ori Tests:
Type System
-
Implement: Interpolated expressions must implement
Printable[done] (verified 2026-03-29)- Rust Tests: Type checker validates via
to_str()call desugaring. Error E2034/E2035 for non-Printable interpolation. - Ori Tests:
tests/spec/types/printable_interpolation.ori - LLVM Support: LLVM codegen for Printable constraint
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— Printable constraint codegen - AOT Tests: No AOT coverage yet
- Rust Tests: Type checker validates via
-
Implement: Validate format spec type compatibility (e.g.,
x/X/b/oonly for int) [done] (verified 2026-03-29)- Rust Tests:
ori_eval/src/interpreter/format.rsvalidates format type against value type - Ori Tests:
tests/compile-fail/format_spec_type_mismatch.ori - LLVM Support: LLVM codegen for format spec type validation
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— format spec type validation codegen
- Rust Tests:
Standard Library
-
Implement:
Formattabletrait definition [done] (verified 2026-03-29)- Ori Tests:
tests/spec/traits/formattable.ori - LLVM Support: LLVM codegen for Formattable trait
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— Formattable trait codegen - AOT Tests: No AOT coverage yet
- Ori Tests:
-
Implement:
FormatSpectype definition [done] (verified 2026-03-29)- Ori Tests:
tests/spec/types/format_spec.ori - LLVM Support: LLVM codegen for FormatSpec type
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— FormatSpec type codegen - AOT Tests: No AOT coverage yet
- Ori Tests:
-
Implement:
AlignmentandFormatTypesum types [done] (verified 2026-03-29)- Ori Tests:
tests/spec/types/format_enums.ori - LLVM Support: LLVM codegen for format enums
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— format enums codegen - AOT Tests: No AOT coverage yet
- Ori Tests:
-
Implement: Blanket impl
T: FormattablewhereT: Printable[done] (verified 2026-03-29)- Ori Tests:
tests/spec/traits/formattable_blanket.ori - LLVM Support: LLVM codegen for blanket impl
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— blanket impl codegen - AOT Tests: No AOT coverage yet
- Ori Tests:
-
Implement:
apply_formathelper for width/alignment/padding [done] (verified 2026-03-29)- Ori Tests:
tests/spec/stdlib/apply_format.ori - LLVM Support: LLVM codegen for apply_format
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— apply_format codegen - AOT Tests: No AOT coverage yet
- Ori Tests:
Codegen
-
Implement: Desugar template strings to concatenation with
to_str()calls [done] (verified 2026-03-29)- Rust Tests:
ori_canon/src/desugar/mod.rs—desugar_template_literal(). Canon test atori_canon/src/desugar/tests.rs - Ori Tests:
tests/spec/expressions/interpolation_desugar.ori - LLVM Support: LLVM codegen for template string desugaring
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— template string desugaring codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Desugar format specifiers to
format(value, FormatSpec {...})calls [done] (verified 2026-03-29)- Rust Tests: Evaluator builds
FormatSpecstruct value and callsformat()inori_eval/src/interpreter/format.rs - Ori Tests:
tests/spec/expressions/format_spec_desugar.ori - LLVM Support: LLVM codegen for format spec desugaring
- LLVM Rust Tests:
ori_llvm/tests/interpolation_tests.rs— format spec desugaring codegen - AOT Tests: No AOT coverage yet
- Rust Tests: Evaluator builds
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (15C.1) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE/commit-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-15C.1 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 15C.1: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW. -
Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files.
15C.2 Spread Operator
Proposal: proposals/approved/spread-operator-proposal.md
NEEDS TESTS (verified 2026-03-29): Zero Ori spec tests exist for spread operator. Core impl is done (parser, typeck, desugar) but only 1 Rust unit test (
desugar_list_with_spread_simple) covers desugar. No AOT coverage. All planned Ori test files below are absent.
Add a spread operator ... for expanding collections and structs in literal contexts.
let combined = [...list1, ...list2]
let merged = {...defaults, ...overrides}
let updated = Point { ...original, x: 10 }
Lexer
- Implement: Add
...as a token (Ellipsis) [done] (verified 2026-03-29)- Rust Tests:
TokenKind::DotDotDotexists. Scanner handles.... - Ori Tests:
tests/spec/lexical/spread_token.ori - LLVM Support: LLVM codegen for ellipsis token
- LLVM Rust Tests:
ori_llvm/tests/spread_tests.rs— ellipsis token codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
Parser
-
Implement: Parse
...expressionin list literals [done] (verified 2026-03-29)- Rust Tests:
ori_parse/src/grammar/expr/primary/collections.rs— producesExprKind::ListWithSpread(ListElementRange) - Ori Tests:
tests/spec/expressions/list_spread.ori - LLVM Support: LLVM codegen for list spread
- LLVM Rust Tests:
ori_llvm/tests/spread_tests.rs— list spread codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Parse
...expressionin map literals [done] (verified 2026-03-29)- Rust Tests:
ori_parse/src/grammar/expr/primary/collections.rs— producesExprKind::MapWithSpread(MapElementRange) - Ori Tests:
tests/spec/expressions/map_spread.ori - LLVM Support: LLVM codegen for map spread
- LLVM Rust Tests:
ori_llvm/tests/spread_tests.rs— map spread codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Parse
...expressionin struct literals [done] (verified 2026-03-29)- Rust Tests:
ori_parse/src/grammar/expr/postfix.rs— producesExprKind::StructWithSpread - Ori Tests:
tests/spec/expressions/struct_spread.ori - LLVM Support: LLVM codegen for struct spread
- LLVM Rust Tests:
ori_llvm/tests/spread_tests.rs— struct spread codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
Type Checker
-
Implement: Verify list spread expression is
[T]matching container [done] (verified 2026-03-29)- Rust Tests:
ori_types/src/infer/expr/collections.rshandles spread type checking - Ori Tests:
tests/compile-fail/list_spread_type_mismatch.ori - LLVM Support: LLVM codegen for list spread type checking
- LLVM Rust Tests:
ori_llvm/tests/spread_tests.rs— list spread type checking codegen
- Rust Tests:
-
Implement: Verify map spread expression is
{K: V}matching container [done] (verified 2026-03-29)- Rust Tests:
ori_types/src/infer/expr/collections.rshandles map spread type checking - Ori Tests:
tests/compile-fail/map_spread_type_mismatch.ori - LLVM Support: LLVM codegen for map spread type checking
- LLVM Rust Tests:
ori_llvm/tests/spread_tests.rs— map spread type checking codegen
- Rust Tests:
-
Implement: Verify struct spread is same struct type (no subset/superset) [done] (verified 2026-03-29)
- Rust Tests:
ori_types/src/infer/expr/structs/mod.rshandles struct spread - Ori Tests:
tests/compile-fail/struct_spread_wrong_type.ori - LLVM Support: LLVM codegen for struct spread type checking
- LLVM Rust Tests:
ori_llvm/tests/spread_tests.rs— struct spread type checking codegen
- Rust Tests:
-
Implement: Track struct field coverage (spread + explicit must cover all fields) [done] (verified 2026-03-29)
- Rust Tests: Type checker validates field coverage
- Ori Tests:
tests/compile-fail/struct_spread_missing_fields.ori - LLVM Support: LLVM codegen for field coverage tracking
- LLVM Rust Tests:
ori_llvm/tests/spread_tests.rs— field coverage tracking codegen
Code Generation
-
Implement: Desugar list spread to concatenation (
[a] + b + [c]) [done] (verified 2026-03-29)- Rust Tests:
ori_canon/src/desugar/spread.rs—ListWithSpreadtoList + .concat() - Ori Tests:
tests/spec/expressions/list_spread_desugar.ori - LLVM Support: LLVM codegen for list spread desugaring
- LLVM Rust Tests:
ori_llvm/tests/spread_tests.rs— list spread desugaring codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Desugar map spread to merge calls [done] (verified 2026-03-29)
- Rust Tests:
ori_canon/src/desugar/spread.rs—MapWithSpreadtoMap + .merge() - Ori Tests:
tests/spec/expressions/map_spread_desugar.ori - LLVM Support: LLVM codegen for map spread desugaring
- LLVM Rust Tests:
ori_llvm/tests/spread_tests.rs— map spread desugaring codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Desugar struct spread to explicit field assignments [done] (verified 2026-03-29)
- Rust Tests:
ori_canon/src/desugar/spread.rs—StructWithSpreadtoStructwith all fields resolved - Ori Tests:
tests/spec/expressions/struct_spread_desugar.ori - LLVM Support: LLVM codegen for struct spread desugaring
- LLVM Rust Tests:
ori_llvm/tests/spread_tests.rs— struct spread desugaring codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
Edge Cases
-
Implement: Empty spread produces nothing (valid)
- Ori Tests:
tests/spec/expressions/spread_empty.ori - LLVM Support: LLVM codegen for empty spread
- LLVM Rust Tests:
ori_llvm/tests/spread_tests.rs— empty spread codegen - AOT Tests: No AOT coverage yet
- Ori Tests:
-
Implement: Spread preserves evaluation order (left-to-right)
- Ori Tests:
tests/spec/expressions/spread_eval_order.ori - LLVM Support: LLVM codegen for spread evaluation order
- LLVM Rust Tests:
ori_llvm/tests/spread_tests.rs— spread evaluation order codegen - AOT Tests: No AOT coverage yet
- Ori Tests:
-
Implement: Error for spread in function call arguments
- Rust Tests:
ori_types/src/check/call.rs— spread in call error - Ori Tests:
tests/compile-fail/spread_in_function_call.ori - LLVM Support: LLVM codegen for spread in call error
- LLVM Rust Tests:
ori_llvm/tests/spread_tests.rs— spread in call error codegen
- Rust Tests:
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (15C.2) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE/commit-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-15C.2 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 15C.2: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW. -
Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files.
15C.3 Range with Step
Proposal: proposals/approved/range-step-proposal.md
BUG-15C-001 (verified 2026-03-29): Dual-execution parity violation on zero step. Interpreter
range_len()inori_patterns/src/value/iterator/mod.rsline 24 returns 0 forstep==0(silent empty range), while LLVM panics with “range step cannot be zero”. These must agree. LLVM behavior (panic) is correct — zero step is a user error, not an empty range. Fix: change interpreterrange_lenfromreturn 0to panic on zero step.
Add a by keyword to range expressions for non-unit step values.
0..10 by 2 // 0, 2, 4, 6, 8
10..0 by -1 // 10, 9, 8, ..., 1
0..=10 by 2 // 0, 2, 4, 6, 8, 10
Lexer
- Implement: Add
byas contextual keyword token following range operators [done] (verified 2026-03-29)- Rust Tests:
TokenKind::Byexists.ori_lexer/src/keywords/mod.rshasby. - Ori Tests:
tests/spec/lexical/by_keyword.ori - LLVM Support: LLVM codegen for by keyword
- LLVM Rust Tests:
ori_llvm/tests/range_step_tests.rs— by keyword codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
Parser
- Implement: Extend
range_exprto accept[ "by" shift_expr ][done] (verified 2026-03-29)- Rust Tests:
ori_parse/src/grammar/expr/mod.rsline 313 —if matches!(self.cursor.current_kind(), TokenKind::By) - Ori Tests:
tests/spec/expressions/range_step.ori - LLVM Support: LLVM codegen for range step parsing
- LLVM Rust Tests:
ori_llvm/tests/range_step_tests.rs— range step parsing codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
Type Checker
-
Implement: Validate step expression has same type as range bounds [done] (verified 2026-03-29)
- Rust Tests:
ori_types/src/infer/expr/mod.rshandles range step type checking - Ori Tests:
tests/compile-fail/range_step_type_mismatch.ori - LLVM Support: LLVM codegen for step type checking
- LLVM Rust Tests:
ori_llvm/tests/range_step_tests.rs— step type checking codegen
- Rust Tests:
-
Implement: Restrict
byto integer ranges only (compile-time error for float)- Rust Tests:
ori_types/src/check/range.rs— int-only restriction - Ori Tests:
tests/compile-fail/range_step_float.ori - LLVM Support: LLVM codegen for int-only restriction
- LLVM Rust Tests:
ori_llvm/tests/range_step_tests.rs— int-only restriction codegen
- Rust Tests:
Code Generation / Evaluator
-
Implement: Extend Range type with optional step field (default 1) [done] (verified 2026-03-29)
- Rust Tests:
ExprKind::Range { start, end, step, inclusive }—step: ExprIdin AST - Ori Tests:
tests/spec/types/range_with_step.ori - LLVM Support:
ori_arc/src/lower/control_flow/for_loops/for_range.rshandles step - LLVM Rust Tests:
ori_llvm/tests/range_step_tests.rs— Range type extension codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Iterator for stepped ranges (ascending and descending) [done] (verified 2026-03-29)
- Rust Tests:
ori_patterns/src/value/iterator/mod.rs—IteratorValue::Range { current, end, step, inclusive }.range_len()handles step calculations. - Ori Tests:
tests/spec/expressions/range_step_iteration.ori - LLVM Support: LLVM codegen for stepped range iteration
- LLVM Rust Tests:
ori_llvm/tests/range_step_tests.rs— stepped range iteration codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Runtime panic for zero step — BUG-15C-001: interpreter returns 0 (silent empty range) instead of panic; LLVM correctly panics (verified 2026-03-29)
- LLVM: LLVM codegen panics with “range step cannot be zero” (3 AOT zero-step panic tests pass)
- Interpreter:
range_len()at line 24:if step == 0 { return 0; }— MUST change to panic to match LLVM - Ori Tests:
tests/spec/expressions/range_step_zero_panic.ori - LLVM Support: LLVM codegen for zero step panic
- LLVM Rust Tests:
ori_llvm/tests/range_step_tests.rs— zero step panic codegen - AOT Tests: No AOT coverage yet
-
Implement: Empty range for mismatched direction (no panic) [done] (verified 2026-03-29)
- Rust Tests:
range_len()handles direction mismatch by returning 0 - Ori Tests:
tests/spec/expressions/range_step_empty.ori - LLVM Support: LLVM codegen for direction mismatch
- LLVM Rust Tests:
ori_llvm/tests/range_step_tests.rs— direction mismatch codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (15C.3) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE/commit-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-15C.3 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 15C.3: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW. -
Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files.
15C.4 Computed Map Keys
Proposal: proposals/approved/computed-map-keys-proposal.md
Formalize map literal key semantics: bare identifiers are literal string keys (like TypeScript/JSON), and [expression] syntax enables computed keys.
{timeout: 30} // {"timeout": 30} - bare identifier is literal string
{[key]: 30} // computed key - evaluates key variable
{if: 1, type: "user"} // reserved keywords valid as literal keys
Lexer
- Implement: Recognize
[in map key position as start of computed key- Rust Tests:
ori_lexer/src/lib.rs— computed key bracket detection - Ori Tests:
tests/spec/lexical/computed_map_key.ori - LLVM Support: LLVM codegen for computed key tokenization
- LLVM Rust Tests:
ori_llvm/tests/computed_map_tests.rs - AOT Tests: No AOT coverage yet
- Rust Tests:
Parser
-
Implement: Parse bare identifier as literal string key in map context
- Rust Tests:
ori_parse/src/grammar/expr.rs— bare identifier key parsing - Ori Tests:
tests/spec/expressions/map_literal_keys.ori - LLVM Support: LLVM codegen for bare identifier keys
- LLVM Rust Tests:
ori_llvm/tests/computed_map_tests.rs - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Parse
[expression]as computed key in map context- Rust Tests:
ori_parse/src/grammar/expr.rs— computed key parsing - Ori Tests:
tests/spec/expressions/computed_map_key.ori - LLVM Support: LLVM codegen for computed key parsing
- LLVM Rust Tests:
ori_llvm/tests/computed_map_tests.rs - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Allow reserved keywords as bare literal keys
- Rust Tests:
ori_parse/src/grammar/expr.rs— keyword-as-key parsing - Ori Tests:
tests/spec/expressions/map_keyword_keys.ori - LLVM Support: LLVM codegen for keyword keys
- LLVM Rust Tests:
ori_llvm/tests/computed_map_tests.rs - AOT Tests: No AOT coverage yet
- Rust Tests:
Type Checker
-
Implement: Bare identifier keys always produce
strtype- Rust Tests:
ori_types/src/check/map_lit.rs— bare key type inference - Ori Tests:
tests/spec/types/map_key_types.ori - LLVM Support: LLVM codegen for bare key types
- LLVM Rust Tests:
ori_llvm/tests/computed_map_tests.rs - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Computed keys must match map key type
Kin{K: V}- Rust Tests:
ori_types/src/check/map_lit.rs— computed key type checking - Ori Tests:
tests/compile-fail/computed_key_type_mismatch.ori - LLVM Support: LLVM codegen for computed key type checking
- LLVM Rust Tests:
ori_llvm/tests/computed_map_tests.rs
- Rust Tests:
-
Implement: Error for bare literals in non-string-key maps
- Rust Tests:
ori_types/src/check/map_lit.rs— bare key in int-map error - Ori Tests:
tests/compile-fail/bare_key_non_string_map.ori - LLVM Support: LLVM codegen for bare key error
- LLVM Rust Tests:
ori_llvm/tests/computed_map_tests.rs
- Rust Tests:
Code Generation
-
Implement: Desugar bare identifier keys to string literals
- Rust Tests:
ori_llvm/src/codegen/map.rs— bare key desugaring - Ori Tests:
tests/spec/expressions/map_key_desugar.ori - LLVM Support: LLVM codegen for bare key desugaring
- LLVM Rust Tests:
ori_llvm/tests/computed_map_tests.rs - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Evaluate computed key expressions at runtime
- Rust Tests:
ori_llvm/src/codegen/map.rs— computed key evaluation - Ori Tests:
tests/spec/expressions/computed_key_eval.ori - LLVM Support: LLVM codegen for computed key evaluation
- LLVM Rust Tests:
ori_llvm/tests/computed_map_tests.rs - AOT Tests: No AOT coverage yet
- Rust Tests:
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (15C.4) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE/commit-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-15C.4 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 15C.4: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW. -
Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files.
15C.5 Floor Division (div) Operator Fix
Proposal: proposals/approved/grammar-sync-formalization-proposal.md
Fix parser discrepancy where div operator is in grammar but missing from parser.
Parser Fix
- Implement: Add
TokenKind::Divcase tomatch_multiplicative_op()[done] (verified 2026-03-29)- Rust Tests:
ori_parse/src/grammar/expr/operators.rsline 134:TokenKind::TAG_DIV, FloorDiv, bp::MULTIPLICATIVE, 1;—divin operator table at multiplicative precedence.BinaryOp::FloorDivwithtrait_method_name() -> "floor_divide",trait_name() -> "FloorDiv". Evaluator handles inori_eval/src/operators/mod.rs. LLVM handles inori_llvm/src/codegen/arc_emitter/operators/strategy.rs. - Ori Tests:
tests/spec/operators/div_floor.ori - LLVM Support: LLVM codegen for div operator
- LLVM Rust Tests:
ori_llvm/tests/operator_tests.rs— div codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
Operator Test Infrastructure
-
Implement: Create
tests/spec/operators/directory structure-
tests/spec/operators/precedence/— precedence relationship tests -
tests/spec/operators/associativity/— associativity tests -
tests/spec/operators/operators/— individual operator tests
-
-
Implement: Add precedence tests for adjacent levels
- Ori Tests:
tests/spec/operators/precedence/mul_over_add.ori - Ori Tests:
tests/spec/operators/precedence/add_over_shift.ori - Ori Tests:
tests/spec/operators/precedence/shift_over_range.ori
- Ori Tests:
-
Implement: Add associativity tests for binary operators
- Ori Tests:
tests/spec/operators/associativity/mul_left_assoc.ori - Ori Tests:
tests/spec/operators/associativity/add_left_assoc.ori
- Ori Tests:
15C.6 Decimal Duration and Size Literals
Proposal: proposals/approved/decimal-duration-size-literals-proposal.md
Allow decimal syntax in duration and size literals as compile-time sugar.
let t = 0.5s // 500,000,000 nanoseconds
let t = 1.56s // 1,560,000,000 nanoseconds
let s = 1.5kb // 1,500 bytes (SI units)
let s = 0.25mb // 250,000 bytes
Key changes:
- Decimal notation for duration/size literals (compile-time, no floats)
- Size units changed from binary (1024) to SI (1000)
- E0911 repurposed: “literal cannot be represented exactly”
Lexer
-
Implement: Parse decimal duration literals (
1.5s,0.25h, etc.) [done] (verified 2026-03-29)- Rust Tests:
ori_lexer/src/cooker/duration_size.rs—cook_duration()callsparse_decimal_unit_value(). Tests atori_lexer/src/cooker/tests.rs:decimal_duration_seconds,decimal_duration_milliseconds,decimal_duration_hours,decimal_duration_half_second,decimal_duration_many_digits,decimal_duration_nanoseconds_error,decimal_duration_overflow_is_error. Phase tests atoric/tests/phases/parse/lexer.rs. - Ori Tests:
tests/spec/lexical/decimal_duration.ori - LLVM Support: LLVM codegen for decimal duration literals
- LLVM Rust Tests:
ori_llvm/tests/literal_tests.rs— decimal duration codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Parse decimal size literals (
1.5kb,0.5mb, etc.) [done] (verified 2026-03-29)- Rust Tests:
ori_lexer/src/cooker/duration_size.rs—cook_size()withparse_decimal_unit_value(). Tests:decimal_size_kilobytes,decimal_size_megabytes,decimal_size_bytes_error,decimal_size_overflow_is_error. - Ori Tests:
tests/spec/lexical/decimal_size.ori - LLVM Support: LLVM codegen for decimal size literals
- LLVM Rust Tests:
ori_llvm/tests/literal_tests.rs— decimal size codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Integer arithmetic conversion (no floats involved) [done] (verified 2026-03-29)
- Rust Tests:
parse_decimal_unit_value()inori_lexer/src/cooker/duration_size.rs - Ori Tests:
tests/spec/lexical/decimal_precision.ori
- Rust Tests:
-
Implement: Validation for whole-number results [done] (verified 2026-03-29)
- Rust Tests: Returns
Noneif not whole number, triggersDecimalNotRepresentablelex error - Ori Tests:
tests/compile-fail/decimal_duration_not_whole.ori - Ori Tests:
tests/compile-fail/decimal_size_not_whole.ori
- Rust Tests: Returns
Token Changes
-
Implement: Remove
FloatDurationErrorandFloatSizeErrortoken types- Rust Tests:
ori_ir/src/token.rs— token type cleanup
- Rust Tests:
-
Implement: Store Duration/Size tokens as computed base unit value [done] (verified 2026-03-29)
- Rust Tests: Tokens store computed i64 value
Error Messages
- Implement: E0911 error for non-representable decimal literals [done] (verified 2026-03-29)
- Rust Tests:
ori_lexer/src/lex_error/mod.rs—DecimalNotRepresentableerror.oric/src/problem/lex.rsformats with note about whole numbers. - Ori Tests:
tests/compile-fail/e0911_decimal_precision.ori
- Rust Tests:
Size Unit Change
-
Implement: Change Size unit multipliers from 1024 to 1000 [done] (verified 2026-03-29)
- Rust Tests: SI units confirmed:
ori_ir/src/builtin_constants/mod.rscomment “Uses SI units (1000-based): 1kb = 1000 bytes”. AOT tests confirm:ori_llvm/tests/aot/spec.rsline 406:let kb_ok = 1kb == 1000b;. - Ori Tests:
tests/spec/types/size_si_units.ori - LLVM Support: LLVM codegen with SI units
- LLVM Rust Tests:
ori_llvm/tests/literal_tests.rs— SI unit codegen - AOT Tests: No AOT coverage yet
- Rust Tests: SI units confirmed:
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (15C.6) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE/commit-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-15C.6 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 15C.6: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW. -
Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files.
15C.7 Null Coalesce Operator (??)
Source: grammar.ebnf § coalesce_expr, spec/14-expressions.md § Operators
The null coalesce operator ?? provides a default value when an Option is None.
let name = maybe_name ?? "Anonymous"
let count = get_count() ?? 0
Status: Fully implemented including LLVM [done] (verified 2026-03-29). NEEDS TESTS: No AOT-specific coalesce tests despite LLVM emit_coalesce() existing.
Evaluator
- Implement: Evaluate
??forOption<T>— extract Some value or use default [done] (verified 2026-03-29)- Rust Tests:
ori_eval/src/interpreter/can_eval/operators.rsline 38:BinaryOp::CoalescehandlesSome(inner)extraction andNonedefault - Ori Tests:
tests/spec/expressions/coalesce.ori— 430-line test file with 30+ tests including short-circuit, chaining, Result coalescing, nested options, map lookups (all 4181 tests pass) - LLVM Support:
ori_llvm/src/codegen/arc_emitter/operators/strategy.rs—emit_coalesce()method - LLVM Rust Tests:
ori_llvm/tests/coalesce_tests.rs— coalesce codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
Type Checker
-
Implement: Infer type for
a ?? b— result isTwherea: Option<T>andb: T[done] (verified 2026-03-29)- Rust Tests:
ori_types/src/infer/expr/operators.rsline 285:BinaryOp::Coalescebranch - Ori Tests:
tests/spec/types/coalesce_inference.ori
- Rust Tests:
-
Implement: Error for non-Option left operand [done] (verified 2026-03-29)
- Rust Tests: Type checker produces E2038 for non-Option/Result left operand
- Ori Compile-Fail Tests:
tests/compile-fail/coalesce_non_option.ori
Edge Cases
-
Implement: Short-circuit evaluation — don’t evaluate right side if left is Some [done] (verified 2026-03-29)
- Ori Tests:
tests/spec/expressions/coalesce.ori— short-circuit tests pass
- Ori Tests:
-
Implement: Chained coalesce —
a ?? b ?? c[done] (verified 2026-03-29)- Ori Tests:
tests/spec/expressions/coalesce.ori— chain_all_none, chain_first_some, chain_middle_some, chain_last_some, chain_short_circuit tests pass
- Ori Tests:
15C.8 Compound Assignment Operators
Proposal: proposals/approved/compound-assignment-proposal.md
Add compound assignment operators (+=, -=, *=, /=, %=, @=, &=, |=, ^=, <<=, >>=, &&=, ||=) that desugar to x = x op y at the parser level.
let sum = 0;
for item in items {
sum += item.value;
}
Lexer
-
Implement: Add 13 new raw token tags to
ori_lexer_core/src/tag/mod.rs[done] (verified 2026-03-29)PlusEq(62),MinusEq(63),StarEq(64),SlashEq(65),PercentEq(66), plusAtEq,AmpEq,PipeEq,CaretEq,ShlEq,AmpAmpEq,PipePipeEq- Rust Tests:
ori_lexer_core/src/raw_scanner/tests.rsline 340-344 - Rust Tests:
ori_lexer_core/src/tag/tests.rs
-
Implement: Update raw scanner to scan compound assignment tokens [done] (verified 2026-03-29)
- Two-char:
+=,-=,*=,/=,%=,@=,&=,|=,^= - Three-char:
<<=,>>=,&&=,||= - Rust Tests:
ori_lexer_core/src/raw_scanner/operators.rshandles all compound ops
- Two-char:
-
Implement: Map raw tags to
TokenKindin cooker [done] (verified 2026-03-29)- Rust Tests: Cooker maps all compound assignment tokens to
TokenKindvariants
- Rust Tests: Cooker maps all compound assignment tokens to
Parser
-
Implement: Parse compound assignment and desugar to
Assign { target, value: Binary/And/Or }[done] (verified 2026-03-29)- Trait-based ops: map
PlusEqtoBinaryOp::Add, etc. - Logical ops: map
AmpAmpEqtoExprKind::And,PipePipeEqtoExprKind::Or - Rust Tests:
ori_parse/src/grammar/expr/operators.rs—compound_op_for_tag()maps all 12 tag-based operators.compound_assign_covers_all_tagstest verifies exhaustive coverage. - Ori Tests:
tests/spec/operators/compound_assignment/basic.ori - Ori Tests:
tests/spec/operators/compound_assignment/field_access.ori - Ori Tests:
tests/spec/operators/compound_assignment/subscript.ori - Ori Tests:
tests/spec/operators/compound_assignment/logical.ori
- Trait-based ops: map
-
Implement: Remove compound assignment from “common mistake” detection [done] (verified 2026-03-29)
-
ori_parse/src/error/mistakes.rsdoes NOT list compound assignment operators as mistakes. Only??=is listed. Hints even suggest using+=as replacement for++. - Rust Tests: Detection tests updated
-
Error Messages
-
Implement: Error for compound assignment on immutable binding (
$)- Message: “cannot use compound assignment on immutable binding
$y. Remove$for mutability:let y = ...” - Ori Tests:
tests/compile-fail/compound_assign_immutable.ori
- Message: “cannot use compound assignment on immutable binding
-
Implement: Error for compound assignment as expression
- Message: “compound assignment is a statement, not an expression”
- Ori Tests:
tests/compile-fail/compound_assign_as_expression.ori
LLVM Support
-
LLVM Support: No changes needed — parser desugars before reaching LLVM codegen [done] (verified 2026-03-29)
- LLVM Rust Tests:
ori_llvm/tests/compound_assign_tests.rs— verify desugared form compiles correctly - AOT Tests: No AOT coverage yet
- LLVM Rust Tests:
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (15C.8) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE/commit-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-15C.8 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 15C.8: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW. -
Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files.
15C.9 MatMul Operator (@)
Proposal: proposals/approved/matmul-operator-proposal.md
Add @ as a binary operator for matrix multiplication. Desugars to MatMul trait method matrix_multiply(). Same precedence as *///%/div (level 4, multiplicative). The @ token is disambiguated by syntactic context (item position = function declaration, expression position = matmul, pattern position = at-binding).
IR
- Implement: Add
MatMulvariant toBinaryOp+ arms inas_symbol(),precedence(),trait_method_name(),trait_name()- Rust Tests:
ori_ir/src/ast/tests.rs
- Rust Tests:
Parser
- Implement: Add
TokenKind::Atto multiplicative precedence level in expression parser- Rust Tests:
ori_parse/src/grammar/expr/tests.rs— matmul parsing - Ori Tests:
tests/spec/operators/matmul/basic.ori - Ori Tests:
tests/spec/operators/matmul/precedence.ori
- Rust Tests:
Evaluator
- Implement: Add
BinaryOp::MatMulerror arms to primitive type handlers (no primitive implementsMatMul)- Rust Tests:
ori_eval/src/tests/— matmul error on primitives
- Rust Tests:
Standard Library
- Implement: Add
MatMultrait definition tolibrary/std/prelude.ori- Ori Tests:
tests/spec/traits/operators/matmul_trait.ori
- Ori Tests:
LLVM
-
LLVM Support: Falls through via trait dispatch — no special-casing needed
- AOT Tests:
ori_llvm/tests/aot/operators.rs— matmul trait dispatch
- AOT Tests:
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (15C.9) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE/commit-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-15C.9 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 15C.9: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW. -
Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files.
15C.10 Power Operator (**)
Proposal: proposals/approved/power-operator-proposal.md
Add ** as a right-associative binary operator for exponentiation. Desugars to Pow trait method power(). Binds tighter than unary - (precedence level 2): -x ** 2 = -(x ** 2). Compound assignment **= included.
Lexer
- Implement: Add
StarStarandStarStarEqraw token tags toori_lexer_core/src/tag/mod.rs- Rust Tests:
ori_lexer_core/src/tag/tests.rs— lexeme and display tests
- Rust Tests:
- Implement: Update raw scanner to recognize
**and**=(longest-match:*→ peek*→ peek=)- Rust Tests:
ori_lexer_core/src/raw_scanner/tests.rs— power token scanning
- Rust Tests:
- Implement: Map
StarStar→TokenKind::PowandStarStarEq→ compound assignment in cooker- Rust Tests:
ori_lexer/src/cooker/tests.rs— power token cooking
- Rust Tests:
IR
- Implement: Add
Powvariant toBinaryOp+ arms inas_symbol(),precedence(),trait_method_name(),trait_name()- Rust Tests:
ori_ir/src/ast/tests.rs— BinaryOp::Pow methods
- Rust Tests:
Parser
- Implement: Add
parse_power_expr()betweenparse_unary_expr()andparse_postfix_expr()— right-associativeunary_exprcallspower_expr;power_exprcallspostfix_expr- Rust Tests:
ori_parse/src/grammar/expr/tests.rs— power expression parsing - Ori Tests:
tests/spec/operators/power/basic.ori - Ori Tests:
tests/spec/operators/power/right_assoc.ori—2 ** 3 ** 2 = 512 - Ori Tests:
tests/spec/operators/power/unary_minus.ori—-2 ** 2 = -4 - Ori Tests:
tests/spec/operators/power/precedence.ori—a * b ** 2 = a * (b ** 2)
- Implement: Parse
**=compound assignment (desugar tox = x ** y)- Ori Tests:
tests/spec/operators/power/compound_assign.ori
- Ori Tests:
Type Checker
- Implement: Falls through via
BinaryOp::trait_name()returning"Pow"— no special-casing- Ori Tests:
tests/compile-fail/power_no_impl.ori— “typestrdoes not implementPow”
- Ori Tests:
Evaluator
- Implement: Built-in
int ** intdispatch (binary exponentiation, panic on negative exponent)- Rust Tests:
ori_eval/src/tests/— int power evaluation - Ori Tests:
tests/spec/operators/power/int_power.ori - Ori Tests:
tests/spec/operators/power/negative_exponent_panic.ori - Ori Tests:
tests/spec/operators/power/zero_pow_zero.ori—0 ** 0 = 1
- Rust Tests:
- Implement: Built-in
float ** floatdispatch (delegates to libmpow())- Rust Tests:
ori_eval/src/tests/— float power evaluation - Ori Tests:
tests/spec/operators/power/float_power.ori
- Rust Tests:
- Implement: Mixed-type dispatch:
float ** int,int ** float→float- Ori Tests:
tests/spec/operators/power/mixed_types.ori
- Ori Tests:
- Implement: Overflow follows standard overflow behavior (panic in debug)
- Ori Tests:
tests/spec/operators/power/overflow.ori
- Ori Tests:
Standard Library
- Implement: Add
Powtrait definition tolibrary/std/prelude.ori- Trait:
trait Pow<Rhs = Self> { type Output = Self; @power (self, rhs: Rhs) -> Self.Output } - Built-in impls:
Pow for int,Pow for float,Pow<int> for float,Pow<float> for int - Ori Tests:
tests/spec/traits/operators/pow_trait.ori - Ori Tests:
tests/spec/traits/operators/pow_user_defined.ori
- Trait:
LLVM
-
LLVM Support: Primitive impls via
llvm.powintrinsic; user types via trait dispatch- AOT Tests:
ori_llvm/tests/aot/operators.rs— power operator codegen
- AOT Tests:
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (15C.10) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE/commit-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-15C.10 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 15C.10: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW. -
Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files.
15C.11 Pipe Operator (|>)
Proposal: proposals/approved/pipe-operator-proposal.md
Add |> for left-to-right function composition with implicit fill. The piped value fills the single parameter that has no default and is not provided in the call. Method calls on the piped value use .method() syntax. Lambda pipe steps (|> (x -> expr)) handle expression-level operations.
data
|> filter(predicate: x -> x > 0)
|> map(transform: x -> x * 2)
|> sum
Lexer
- Implement: Add
PipeArrowraw token tag toori_lexer_core/src/tag/mod.rs- Rust Tests:
ori_lexer_core/src/tag/tests.rs— lexeme and display tests
- Rust Tests:
- Implement: Update raw scanner to recognize
|>(disambiguate from|)- Rust Tests:
ori_lexer_core/src/raw_scanner/tests.rs— pipe token scanning
- Rust Tests:
- Implement: Map
PipeArrow→TokenKind::Pipein cooker- Rust Tests:
ori_lexer/src/cooker/tests.rs— pipe token cooking
- Rust Tests:
IR
- Implement: Add
Pipeexpression variant toExprKind(LHS expression + pipe step)- Pipe step variants: function call (implicit fill), method call (
.method), lambda - Rust Tests:
ori_ir/src/ast/tests.rs— Pipe expression AST node
- Pipe step variants: function call (implicit fill), method call (
Parser
- Implement: Parse
|>at precedence 16 (below??at 15); producePipeAST node- Grammar:
pipe_expr = coalesce_expr { "|>" pipe_step } . - Pipe step:
.method()|postfix_expr [call_args]|lambda - Rust Tests:
ori_parse/src/grammar/expr/tests.rs— pipe expression parsing - Ori Tests:
tests/spec/expressions/pipe/basic.ori— simple pipe chains - Ori Tests:
tests/spec/expressions/pipe/method_call.ori—.method()on piped value - Ori Tests:
tests/spec/expressions/pipe/lambda.ori— lambda pipe steps - Ori Tests:
tests/spec/expressions/pipe/precedence.ori—a + b |> f=(a + b) |> f - Ori Tests:
tests/spec/expressions/pipe/nested.ori—a |> f(x: b |> g)
- Grammar:
Type Checker
-
Implement: Resolve implicit fill — identify single unspecified param (no default, not in call)
- Desugar to let-binding + ordinary function call
- Rust Tests:
ori_types/src/infer/expr/tests.rs— pipe implicit fill resolution - Ori Tests:
tests/spec/expressions/pipe/implicit_fill.ori— fills correct param - Ori Tests:
tests/spec/expressions/pipe/defaults.ori— params with defaults excluded - Ori Tests:
tests/spec/expressions/pipe/punning.ori—x |> f(weight:, bias:)
-
Implement: Error diagnostics for pipe
- Zero unspecified: “all parameters already specified; nothing for pipe to fill”
- Multiple unspecified: “ambiguous pipe target; specify all parameters except one”
- Ori Tests:
tests/compile-fail/pipe_all_specified.ori - Ori Tests:
tests/compile-fail/pipe_ambiguous.ori - Ori Tests:
tests/compile-fail/pipe_zero_params.ori
-
Implement: Desugar
.method()pipe steps to__pipe.method(args)call- Ori Tests:
tests/spec/expressions/pipe/method_desugar.ori
- Ori Tests:
-
Implement: Desugar lambda pipe steps to
(lambda)(__pipe)call- Ori Tests:
tests/spec/expressions/pipe/lambda_desugar.ori
- Ori Tests:
-
Implement: Handle
?on pipe steps — applies to desugared call result- Ori Tests:
tests/spec/expressions/pipe/error_propagation.ori
- Ori Tests:
Formatter
- Implement: Format pipe chains with line-break-per-step, indented under first operand
- Rust Tests:
ori_fmt/src/formatter/tests.rs— pipe chain formatting
- Rust Tests:
LLVM
-
LLVM Support: No changes needed — type checker desugars before reaching LLVM codegen
- AOT Tests:
ori_llvm/tests/aot/pipe.rs— verify desugared form compiles correctly
- AOT Tests:
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (15C.11) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE/commit-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-15C.11 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 15C.11: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW. -
Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files.
15C.13 Byte Literals and Hex Escapes
Proposal: proposals/approved/byte-literals-proposal.md
Add b'x' byte literal syntax and \xHH hex escapes. Byte literals produce type byte (0–255). \xHH is also added to char literals (restricted to \x00–\x7F).
let space: byte = b' ';
let esc: byte = b'\x1B';
let max: byte = b'\xFF';
let tab_char: char = '\x09';
Raw Scanner
- Implement: Modify identifier dispatch in
ori_lexer_core/src/raw_scanner/mod.rs— peek for'afterbto start byte literal scanning- Rust Tests:
ori_lexer_core/src/raw_scanner/tests.rs— byte literal boundary detection
- Rust Tests:
- Implement: Add
RawTag::ByteLiteralandRawTag::UnterminatedByteLiteralvariants- Rust Tests:
ori_lexer_core/src/tag/tests.rs— lexeme and display tests
- Rust Tests:
- Implement: Add
scan_byte_literal()method instrings.rs— reuseskip_escape_body()with\xextension- Rust Tests:
ori_lexer_core/src/raw_scanner/tests.rs— byte literal scanning (escapes, unterminated, multi-char)
- Rust Tests:
- Implement: Extend
skip_escape_body()to handle\x— consume exactly 2 hex digits- Rust Tests:
ori_lexer_core/src/raw_scanner/tests.rs— hex escape boundary detection
- Rust Tests:
Cooker
- Implement: Add
cook_byte_literal()method inescape_cooking.rs— stripsb'...', callsunescape_byte_v2()- Rust Tests:
ori_lexer/src/cooker/tests.rs— byte literal cooking
- Rust Tests:
- Implement: Add
unescape_byte_v2()function incook_escape/mod.rs— handles\\\'\n\t\r\0\xHH; rejects\u{...}and\"; producesu8- Rust Tests:
ori_lexer/src/cook_escape/tests.rs— byte escape processing
- Rust Tests:
- Implement: Extend
unescape_char_v2()to handle\xHH— restricted to\x00–\x7F; error for\x80–\xFF- Rust Tests:
ori_lexer/src/cook_escape/tests.rs— char hex escape processing
- Rust Tests:
- Implement: Extend
unescape_with_context()to handle\xHHin string and template literals — add'x' =>arm in shared escape match (restricted to\x00–\x7F; error for\x80–\xFF). This is one new match arm thanks to the Section 02 DRY consolidation.- Rust Tests:
ori_lexer/src/cook_escape/tests.rs— string and template hex escape processing (valid ASCII, out-of-range error, mixed with other escapes)
- Rust Tests:
Token Kind
- Implement: Add
TokenKind::Byte(u8)variant toori_ir/src/token/kind.rs- Rust Tests:
ori_ir/src/token/tests.rs— display, discriminant
- Rust Tests:
Parser
- Implement: Parse
TokenKind::Byte(u8)as literal expression inori_parse- Rust Tests:
ori_parse/src/grammar/expr/tests.rs— byte literal parsing - Ori Tests:
tests/spec/literals/byte_literal.ori
- Rust Tests:
Type Checker
- Implement: Infer
bytetype for byte literal expressions inori_types- Rust Tests:
ori_types/src/infer/expr/tests.rs— byte literal type inference - Ori Tests:
tests/spec/types/byte_literal_type.ori
- Rust Tests:
Evaluator
- Implement: Evaluate byte literals to
Value::Byte(u8)inori_eval- Rust Tests:
ori_eval/src/interpreter/tests.rs— byte literal evaluation - Ori Tests:
tests/spec/literals/byte_literal_eval.ori
- Rust Tests:
LLVM Codegen
- LLVM Support: Emit byte literal as
i8constant inori_llvm- LLVM Rust Tests:
ori_llvm/tests/aot/literals.rs— byte literal codegen - AOT Tests:
tests/spec/literals/byte_literal_aot.ori
- LLVM Rust Tests:
Error Messages
-
Implement: Error for
\u{...}in byte literal — “byte literal cannot contain unicode escape”- Ori Tests:
tests/compile-fail/byte_literal_unicode_escape.ori
- Ori Tests:
-
Implement: Error for
\"in byte literal — “invalid escape in byte literal”- Ori Tests:
tests/compile-fail/byte_literal_double_quote_escape.ori
- Ori Tests:
-
Implement: Error for non-ASCII character in byte literal — “non-ASCII character in byte literal”
- Ori Tests:
tests/compile-fail/byte_literal_non_ascii.ori
- Ori Tests:
-
Implement: Error for
\x80–\xFFin char literal — “\x value exceeds ASCII range in char literal (use \u{…})”- Ori Tests:
tests/compile-fail/char_literal_hex_out_of_range.ori
- Ori Tests:
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (15C.13) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE/commit-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-15C.13 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 15C.13: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW. -
Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files.
15C.12 Section Completion Checklist
- All implementation items have checkboxes marked
[ ] - All spec docs updated
- CLAUDE.md updated with syntax changes
- Migration tools working
- All tests pass:
./test-all.sh -
/tpr-reviewpassed — independent Codex review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — implementation hygiene review clean (phase boundaries, SSOT, algorithmic DRY, naming). MUST run AFTER/tpr-reviewis clean. -
/improve-toolingretrospective completed — MANDATORY at section close, after both reviews are clean. Reflect on the section’s debugging journey (whichdiagnostics/scripts you ran, which command sequences you repeated, where you added ad-hocdbg!/tracingcalls, where output was hard to interpret) and identify any tool/log/diagnostic improvement that would have made this section materially easier OR that would help the next section touching this area. Implement every accepted improvement NOW (zero deferral) and commit each via SEPARATE/commit-push. The retrospective is mandatory even when nothing felt painful — that is exactly when blind spots accumulate. See.claude/skills/improve-tooling/SKILL.md“Retrospective Mode” for the full protocol.
Exit Criteria: Literal and operator syntax proposals implemented
- Subsection close-out (15C.12) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE/commit-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-15C.12 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 15C.12: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW. - Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files.