Skip to content

Commit d513f65

Browse files
fix: IfExpr parser double-consumes RBrace; add test_if_expr.omc
parse_block() already consumes the closing `}`, so the IfExpr handler in parse_primary was calling expect(RBrace) a second time, leaving Token::Else as the current token and producing "Expected RBrace, got Else" on any `if cond { val } else { val }` in expression position (e.g. as a function argument like `str_concat("x=", if b { "y" } else { "z" })`). Fix: remove the redundant expect(RBrace) calls in both the then-branch and else-branch paths of the IfExpr parser arm. Mirrors parse_if_stmt which has the same contract. Add examples/tests/test_if_expr.omc (6 tests) covering: - basic true/false branch selection - if-expr as function argument (regression test for the double-consume bug) - no-else returns null on false path - chained else-if - single-expression lambda `fn(p) expr` - dict bare-ident keys `{name: val}` Suite: 1132/1132 passing (77 files). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent c88cdde commit d513f65

2 files changed

Lines changed: 56 additions & 4 deletions

File tree

examples/tests/test_if_expr.omc

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
fn assert_eq(actual, expected, msg) {
2+
if actual != expected {
3+
test_record_failure(str_concat(msg, ": expected ", to_string(expected), " got ", to_string(actual)));
4+
}
5+
}
6+
7+
fn assert_true(cond, msg) { if !cond { test_record_failure(msg); } }
8+
9+
fn test_if_expr_basic() {
10+
h x = if true { 1 } else { 2 }
11+
assert_eq(x, 1, "true branch")
12+
h y = if false { 1 } else { 2 }
13+
assert_eq(y, 2, "false branch")
14+
}
15+
16+
fn test_if_expr_in_call() {
17+
h s = str_concat("mode=", if true { "on" } else { "off" })
18+
assert_eq(s, "mode=on", "if-expr as fn arg")
19+
h t = str_concat("x=", to_string(if false { 10 } else { 20 }))
20+
assert_eq(t, "x=20", "if-expr nested in to_string")
21+
}
22+
23+
fn test_if_expr_no_else() {
24+
h z = if false { 42 }
25+
assert_eq(z, null, "no-else false → null")
26+
h w = if true { 99 }
27+
assert_eq(w, 99, "no-else true → value")
28+
}
29+
30+
fn test_if_expr_chained() {
31+
h grade = 85
32+
h letter = if grade >= 90 { "A" } else if grade >= 80 { "B" } else { "C" }
33+
assert_eq(letter, "B", "chained if-expr")
34+
h letter2 = if grade >= 90 { "A" } else if grade >= 95 { "S" } else { "C" }
35+
assert_eq(letter2, "C", "chained if-expr fall-through")
36+
}
37+
38+
fn test_single_expr_lambda() {
39+
h doubled = arr_map([1, 2, 3], fn(x) (x * 2))
40+
assert_eq(doubled[0], 2, "lambda result[0]")
41+
assert_eq(doubled[1], 4, "lambda result[1]")
42+
assert_eq(doubled[2], 6, "lambda result[2]")
43+
h evens = arr_filter([1, 2, 3, 4, 5], fn(n) ((n % 2) == 0))
44+
assert_eq(arr_len(evens), 2, "filter count")
45+
assert_eq(evens[0], 2, "filter first")
46+
}
47+
48+
fn test_dict_bare_ident_keys() {
49+
h d = {name: "Alice", age: 30}
50+
assert_eq(d["name"], "Alice", "bare-ident string key")
51+
assert_eq(d["age"], 30, "bare-ident int key")
52+
h e = {x: 1, y: 2, z: 3}
53+
assert_eq((e["x"] + e["y"] + e["z"]), 6, "sum of bare-ident keys")
54+
}

omnimcode-core/src/parser.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1899,8 +1899,8 @@ impl Parser {
18991899
self.advance();
19001900
let condition = self.parse_expression()?;
19011901
self.expect(Token::LBrace)?;
1902+
// parse_block() consumes the closing `}` itself.
19021903
let then_body = self.parse_block()?;
1903-
self.expect(Token::RBrace)?;
19041904
let else_body = if self.current() == Token::Else {
19051905
self.advance();
19061906
// else if → wrap in a nested IfExpr as the else branch
@@ -1909,9 +1909,7 @@ impl Parser {
19091909
Some(vec![Statement::Expression(nested)])
19101910
} else {
19111911
self.expect(Token::LBrace)?;
1912-
let body = self.parse_block()?;
1913-
self.expect(Token::RBrace)?;
1914-
Some(body)
1912+
Some(self.parse_block()?)
19151913
}
19161914
} else {
19171915
None

0 commit comments

Comments
 (0)