Skip to content

Conversation

@jmecom
Copy link
Owner

@jmecom jmecom commented Jan 2, 2026

No description provided.

Jordan Mecom and others added 30 commits December 30, 2025 20:04
Implements break and continue for while loops:
- Lexer: Break/Continue tokens
- Parser: parse_break/parse_continue functions
- AST/HIR: BreakStmt/ContinueStmt nodes
- Type checker: validates break/continue are inside loops
- Codegen: LoopTarget struct tracks header/exit blocks for jumps

Includes positive and negative test cases.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, nested matches where all arms terminate would panic with
"you cannot add an instruction to a block already filled".

Example that crashed:
```
fn test(x: i32) -> i32 {
  match (x > 0) {
    true => {
      match (x > 5) {
        true => { return 2 }
        false => { return 1 }
      }
    }
    false => { return 0 }
  }
}
```

The issue: after the inner match terminates all paths (adds trap to
merge_block), the outer match still thinks control continues and tries
to add a `jump` to the already-terminated block.

The fix has two parts:

1. emit_hir_match_stmt now returns `Result<bool, Error>` where the bool
   indicates whether all paths diverged (no arm continues to merge_block)

2. HirStmt::Expr special-cases unit-type match expressions - calls
   emit_hir_match_stmt directly and returns Flow::Terminated if diverged

This approach is pragmatic: the clean solution would have all expressions
return divergence info, but that requires updating ~50 call sites. Since
match is currently the only expression type that can diverge, special-casing
it in HirStmt::Expr is reasonable.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Now that break is supported, replace the `j = 0 // break` workaround
with an actual break statement.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement for loops with the syntax `for i in start..end { body }`:

- Lexer: Add For, In, DotDot tokens
- AST: Add ForStmt struct
- Parser: Add parse_for() function
- HIR: Add HirForStmt struct
- Type checker: Validate range bounds are i32, check affine moves
- Lowering: Lower ForStmt to HirForStmt with fresh local for loop var
- Monomorphization: Handle for loop monomorphization
- Codegen: Generate loop with separate increment block for proper
  continue semantics (increment before jumping to header)

Add comprehensive tests:
- Runtime: for_basic, for_break, for_continue, for_nested, for_sum,
  for_empty_range, for_break_nested, for_continue_nested
- Typecheck: for_non_i32_start, for_non_i32_end, for_loop_move

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add capable_rt_string_eq runtime function for byte-by-byte comparison
- Add emit_string_eq helper in codegen to call the runtime function
- Add match cases for BinaryOp::Eq/Neq with ValueRepr::Pair (strings)
- Add string_compare test program

Strings can now be compared directly with == and != operators instead
of requiring the .eq() method call.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add string indexing with str[i] syntax (returns u8)
- Add Slice/MutSlice indexing support
- Change generic syntax from [] to <> (e.g., Result<T, E>, Box<i32>)
- [] now unambiguously means indexing
- Add heuristic to distinguish <> generics from < comparison
- Update all stdlib and test .cap files to new syntax
- Add string_index and generic_and_index test programs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit adds several improvements to the language:

## Parser fix for for-loop ranges

Fixed a bug where `for i in 0..n { ... }` would fail to parse when
using a variable as the range bound. The issue was that `parse_primary`
would see `n {` and try to parse it as a struct literal `n { ... }`.

Added a new `parse_range_bound` function that accepts only:
- Integer literals
- Boolean literals (for type error at check time, not parse time)
- Simple paths (identifiers, possibly with :: separators)

This prevents struct literal ambiguity while still allowing variables
in range bounds.

## Vec indexing with [] syntax

Added support for indexing VecString, VecI32, and VecU8 with bracket
syntax:

- `lines[i]` now works and returns `Result<string, VecErr>`
- `indices[j]` returns `Result<i32, VecErr>`
- `bytes[k]` returns `Result<u8, VecErr>`

Implementation:
- Type checker recognizes Vec types and returns appropriate Result type
- Lowering phase desugars `vec[i]` to `vec.get(i)` call
- Reuses existing runtime functions, no codegen changes needed

## Updated examples

All examples now use idiomatic Capable with new language features:
- For loops with variable bounds (`for i in 0..n`)
- Vec indexing with `[]` syntax
- `is_ok()`, `is_err()`, `ok()`, `err()` Result methods
- `break` and `continue` in loops

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Result is now defined as a regular generic enum in stdlib/sys/result.cap
instead of being a compiler-hardcoded type.

Changes:
- Remove "Result" from RESERVED_TYPE_PARAMS
- Add stdlib/sys/result.cap with Result<T, E> enum definition
- Update all path checks from "Result" to "sys.result.Result" in:
  - typeck/mod.rs (type capability/kind checks)
  - typeck/check.rs (pattern matching, ? operator, Vec indexing)
  - typeck/lower.rs (pattern lowering, try operator)
  - typeck/monomorphize.rs (type monomorphization, ABI handling)
  - codegen/emit.rs (code generation for Result patterns)
- Fix parser error messages with broken format strings

The is_ok/is_err/ok/err/unwrap_or methods are still compiler special-cased
and will be moved to stdlib in a follow-up change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Progress:
- Added panic() intrinsic that lowers to HirTrap
- Fixed parser bug: struct literals in match/if/while scrutinee positions
  - Added parse_expr_no_struct() to prevent `x {` being parsed as struct literal
  - Applied consistently to match, if, while conditions
- Added impl block support for enums (was only structs before)
- Added Result methods to stdlib/sys/result.cap:
  - is_ok(), is_err(), unwrap_or(), unwrap_err_or()
- Removed Result method special-casing from check.rs (~115 lines)
- Removed Result method desugaring from lower.rs (~295 lines)
- Fixed pattern matching for qualified paths like Result::Ok(_)

Remaining issues:
- ok() and err() methods cannot be implemented yet because panic()
  is typed as unit, not "never" (a diverging type)
- Need to add a "never" type that can unify with any type to properly
  support panic() in expression contexts
- The test should_pass_result_ok_err.cap uses .ok() and .err() which
  are now missing - this test will fail until never type is added

The stdlib Result now has 4 working methods. The .ok() and .err()
methods require panic() to have a proper never/diverging type.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Only applies to non-opaque structs and Result payloads; no inline struct ABI yet.
@jmecom jmecom merged commit cf000d1 into main Jan 2, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants