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)
- 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 - 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)- 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- 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- 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)- 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
{})- 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}- 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]- 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- 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)- 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- 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- 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- 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- 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- 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- 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- 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: 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)- 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- 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- 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- 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- 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-
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:
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: 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])-
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:
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
-
-
Implement: Desugar struct spread to explicit field assignments
- 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
-
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
-
15C.3 Range with Step
Proposal: proposals/approved/range-step-proposal.md
BUG-15C-001: 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- 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 ]- 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
-
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 -
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)
- 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)
- 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
- 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)
- 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:
-
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
-
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:
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:
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
Type Checker
-
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:
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:
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
Code Generation
-
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:
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
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()- 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 structuretests/spec/operators/precedence/— precedence relationship teststests/spec/operators/associativity/— associativity teststests/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.)- 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.)- 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)
- 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
- 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
- Rust Tests: Tokens store computed i64 value
Error Messages
- 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
Size Unit Change
-
Implement: Change Size unit multipliers from 1024 to 1000
- 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:
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. NEEDS TESTS: No AOT-specific coalesce tests despite LLVM emit_coalesce() existing.
Evaluator
-
Implement: Evaluate
??forOption<T>— extract Some value or use default- 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- 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
- 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
- Ori Tests:
tests/spec/expressions/coalesce.ori— short-circuit tests pass
- Ori Tests:
-
Implement: Chained coalesce —
a ?? b ?? c- 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.rsPlusEq(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
- 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- 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 }- 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
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: “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
- LLVM Rust Tests:
ori_llvm/tests/compound_assign_tests.rs— verify desugared form compiles correctly - AOT Tests: No AOT coverage yet
- LLVM Rust Tests:
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
- Rust Tests:
ori_ir/src/ast/tests.rs
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
Evaluator
- Rust Tests:
ori_eval/src/tests/— matmul error on primitives
Standard Library
- Ori Tests:
tests/spec/traits/operators/matmul_trait.ori
LLVM
- AOT Tests:
ori_llvm/tests/aot/operators.rs— matmul trait dispatch
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
-
Rust Tests:
ori_lexer_core/src/tag/tests.rs— lexeme and display tests -
Rust Tests:
ori_lexer_core/src/raw_scanner/tests.rs— power token scanning -
Rust Tests:
ori_lexer/src/cooker/tests.rs— power token cooking
IR
- Rust Tests:
ori_ir/src/ast/tests.rs— BinaryOp::Pow methods
Parser
-
unary_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) -
Ori Tests:
tests/spec/operators/power/compound_assign.ori
Type Checker
- Ori Tests:
tests/compile-fail/power_no_impl.ori— “typestrdoes not implementPow”
Evaluator
-
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:
ori_eval/src/tests/— float power evaluation -
Ori Tests:
tests/spec/operators/power/float_power.ori -
Ori Tests:
tests/spec/operators/power/mixed_types.ori -
Ori Tests:
tests/spec/operators/power/overflow.ori
Standard Library
- 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
LLVM
- AOT Tests:
ori_llvm/tests/aot/operators.rs— power operator codegen
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
-
Rust Tests:
ori_lexer_core/src/tag/tests.rs— lexeme and display tests -
Rust Tests:
ori_lexer_core/src/raw_scanner/tests.rs— pipe token scanning -
Rust Tests:
ori_lexer/src/cooker/tests.rs— pipe token cooking
IR
- Pipe step variants: function call (implicit fill), method call (
.method), lambda - Rust Tests:
ori_ir/src/ast/tests.rs— Pipe expression AST node
Parser
- 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)
Type Checker
-
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:) -
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 -
Ori Tests:
tests/spec/expressions/pipe/method_desugar.ori -
Ori Tests:
tests/spec/expressions/pipe/lambda_desugar.ori -
Ori Tests:
tests/spec/expressions/pipe/error_propagation.ori
Formatter
- Rust Tests:
ori_fmt/src/formatter/tests.rs— pipe chain formatting
LLVM
- AOT Tests:
ori_llvm/tests/aot/pipe.rs— verify desugared form compiles correctly
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
-
Rust Tests:
ori_lexer_core/src/raw_scanner/tests.rs— byte literal boundary detection -
Rust Tests:
ori_lexer_core/src/tag/tests.rs— lexeme and display tests -
Rust Tests:
ori_lexer_core/src/raw_scanner/tests.rs— byte literal scanning (escapes, unterminated, multi-char) -
Rust Tests:
ori_lexer_core/src/raw_scanner/tests.rs— hex escape boundary detection
Cooker
-
Rust Tests:
ori_lexer/src/cooker/tests.rs— byte literal cooking -
Rust Tests:
ori_lexer/src/cook_escape/tests.rs— byte escape processing -
Rust Tests:
ori_lexer/src/cook_escape/tests.rs— char hex escape processing -
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)
Token Kind
- Rust Tests:
ori_ir/src/token/tests.rs— display, discriminant
Parser
- Rust Tests:
ori_parse/src/grammar/expr/tests.rs— byte literal parsing - Ori Tests:
tests/spec/literals/byte_literal.ori
Type Checker
- Rust Tests:
ori_types/src/infer/expr/tests.rs— byte literal type inference - Ori Tests:
tests/spec/types/byte_literal_type.ori
Evaluator
- Rust Tests:
ori_eval/src/interpreter/tests.rs— byte literal evaluation - Ori Tests:
tests/spec/literals/byte_literal_eval.ori
LLVM Codegen
- LLVM Rust Tests:
ori_llvm/tests/aot/literals.rs— byte literal codegen - AOT Tests:
tests/spec/literals/byte_literal_aot.ori
Error Messages
-
Ori Tests:
tests/compile-fail/byte_literal_unicode_escape.ori -
Ori Tests:
tests/compile-fail/byte_literal_double_quote_escape.ori -
Ori Tests:
tests/compile-fail/byte_literal_non_ascii.ori -
Ori Tests:
tests/compile-fail/char_literal_hex_out_of_range.ori
15C.12 Section Completion Checklist
Exit Criteria: Literal and operator syntax proposals implemented
Diagnostic-question log
- 2026-06-12 tooling — Retrospective 15C.1: no tooling gaps. Release-binary friction (
./target/release/oricleaned by a parallel cargo session → opaque “No such file or directory” on manualori test --backend=llvmruns) was a transient parallel-session artifact, not a recurring gap. Binary resolution is already covered:ori_binary()(Rust AOT helper resolves debug-or-release), sanitizer scripts emit a clear “Build with: cargo build —release” message, andtest-all.shbuilds the release binary in a prior phase before its LLVM-backend leg. A freshness-preflight wrapper would be over-tooling pertooling-first.md §5(counter-trigger + Brooks toolsmith caveat).