From d7fc7c653c16859f2837f91ff51bd0f762048d28 Mon Sep 17 00:00:00 2001 From: Senthilnathan Date: Tue, 7 Jul 2026 14:18:42 +0530 Subject: [PATCH 1/2] Fix parser failing on comments inside ternary expressions --- core/odin/parser/parser.odin | 3 +++ src/parser.cpp | 3 +++ tests/core/odin/test_parser.odin | 38 ++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 5e681728d..319c05836 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -381,6 +381,9 @@ advance_token :: proc(p: ^Parser) -> tokenizer.Token { #partial switch p.curr_tok.kind { case .Comment: consume_comment_groups(p, prev) + if p.curr_tok.kind == .Semicolon && p.expr_level > 0 && p.curr_tok.text == "\n" { + advance_token(p) + } case .Semicolon: if p.expr_level > 0 && p.curr_tok.text == "\n" { advance_token(p) diff --git a/src/parser.cpp b/src/parser.cpp index 03e9073ca..c4dc2c0bc 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1529,6 +1529,9 @@ gb_internal Token advance_token(AstFile *f) { switch (f->curr_token.kind) { case Token_Comment: consume_comment_groups(f, prev); + if (f->curr_token.kind == Token_Semicolon && ignore_newlines(f) && f->curr_token.string == "\n") { + advance_token(f); + } break; case Token_Semicolon: if (ignore_newlines(f) && f->curr_token.string == "\n") { diff --git a/tests/core/odin/test_parser.odin b/tests/core/odin/test_parser.odin index 3fb15d893..4a1fdbfb4 100644 --- a/tests/core/odin/test_parser.odin +++ b/tests/core/odin/test_parser.odin @@ -131,3 +131,41 @@ my_func :: proc (cond: bool, a: string, b: string) -> string { testing.expect(t, ok, "bad parse") testing.expect(t, file.syntax_error_count == 0, "should contain zero errors") } + + +@test +test_parse_multiline_ternary_with_comment :: proc(t: ^testing.T) { + context.allocator = context.temp_allocator + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + file := ast.File{ + fullpath = "test.odin", + src = ` + package main + + my_func :: proc (cond: bool, a: string, b: string) -> string { + out := ( + cond + ? a // This is a comment! + : b + ) + return out + } + `, + } + + p := parser.default_parser() + + p.err = proc(pos: tokenizer.Pos, format: string, args: ..any) { + message := fmt.tprintf(format, ..args) + log.errorf("%s(%d:%d): %s", pos.file, pos.line, pos.column, message) + } + + p.warn = proc(pos: tokenizer.Pos, format: string, args: ..any) { + message := fmt.tprintf(format, ..args) + log.warnf("%s(%d:%d): %s", pos.file, pos.line, pos.column, message) + } + + ok := parser.parse_file(&p, &file) + testing.expect(t, ok, "bad parse") + testing.expect(t, file.syntax_error_count == 0, "should contain zero errors") +} From a880c1abfab992126a1a53d4b435150517bf654c Mon Sep 17 00:00:00 2001 From: Senthilnathan Date: Tue, 7 Jul 2026 14:30:59 +0530 Subject: [PATCH 2/2] Fix parser failing on comments inside if/when ternary --- core/odin/parser/parser.odin | 4 +++- src/parser.cpp | 4 +++- tests/core/odin/test_parser.odin | 39 +++++++++++++++++++++++++++++++- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 319c05836..2ad291aef 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -3625,7 +3625,9 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr { case .If, .When: if p.prev_tok.pos.line < op.pos.line { // NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition - break loop + if p.expr_level <= 0 { + break loop + } } } diff --git a/src/parser.cpp b/src/parser.cpp index c4dc2c0bc..0e7ec1d60 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3585,7 +3585,9 @@ gb_internal Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) { case Token_when: if (prev.pos.line < op.pos.line) { // NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition - goto loop_end; + if (f->expr_level <= 0) { + goto loop_end; + } } break; } diff --git a/tests/core/odin/test_parser.odin b/tests/core/odin/test_parser.odin index 4a1fdbfb4..e60a9f8f0 100644 --- a/tests/core/odin/test_parser.odin +++ b/tests/core/odin/test_parser.odin @@ -134,7 +134,7 @@ my_func :: proc (cond: bool, a: string, b: string) -> string { @test -test_parse_multiline_ternary_with_comment :: proc(t: ^testing.T) { +test_parse_multiline_ternary_infix_with_comment :: proc(t: ^testing.T) { context.allocator = context.temp_allocator runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() file := ast.File{ @@ -169,3 +169,40 @@ test_parse_multiline_ternary_with_comment :: proc(t: ^testing.T) { testing.expect(t, ok, "bad parse") testing.expect(t, file.syntax_error_count == 0, "should contain zero errors") } + +@test +test_parse_ternary_if_statements_with_comment :: proc(t: ^testing.T) { + context.allocator = context.temp_allocator + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + file := ast.File{ + fullpath = "test.odin", + src = ` + package main + + my_func :: proc (cond: bool, a: string, b: string) -> string { + out := ( + cond + if a // This is a comment! + else b + ) + return out + } + `, + } + + p := parser.default_parser() + + p.err = proc(pos: tokenizer.Pos, format: string, args: ..any) { + message := fmt.tprintf(format, ..args) + log.errorf("%s(%d:%d): %s", pos.file, pos.line, pos.column, message) + } + + p.warn = proc(pos: tokenizer.Pos, format: string, args: ..any) { + message := fmt.tprintf(format, ..args) + log.warnf("%s(%d:%d): %s", pos.file, pos.line, pos.column, message) + } + + ok := parser.parse_file(&p, &file) + testing.expect(t, ok, "bad parse") + testing.expect(t, file.syntax_error_count == 0, "should contain zero errors") +}