Skip to content

Commit 7ab997b

Browse files
rtfeldmanclaude
andcommitted
Fix panic when lookahead hits EOF before finding close paren
When skipping a parenthesized expression at top level, the lookahead loop might hit EndOfFile before finding the matching close paren. In this case, we should not try to advance past the EOF token as that would cause an assertion failure in peek(). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent f739ede commit 7ab997b

1 file changed

Lines changed: 28 additions & 22 deletions

File tree

src/parse/Parser.zig

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1702,32 +1702,38 @@ fn parseStmtByType(self: *Parser, statementType: StatementType) Error!AST.Statem
17021702
} else if (statementType == .top_level) {
17031703
// At top level, a parenthesized expression like (x + 1) or (x = 5).foo()
17041704
// is not valid. Skip past the parentheses and any suffix to produce a single error.
1705-
self.pos = lookahead_pos + 1; // Move past the closing paren
1706-
// Skip any suffix operators (e.g., .foo(), !(), etc.)
1707-
while (true) {
1708-
switch (self.peek()) {
1709-
.NoSpaceDotLowerIdent, .NoSpaceDotUpperIdent => {
1710-
self.advance();
1711-
},
1712-
.NoSpaceOpenRound => {
1713-
self.advance();
1714-
// Skip to matching close paren
1715-
var paren_depth: u32 = 1;
1716-
while (paren_depth > 0 and self.peek() != .EndOfFile) {
1717-
switch (self.peek()) {
1718-
.OpenRound, .NoSpaceOpenRound => paren_depth += 1,
1719-
.CloseRound => paren_depth -= 1,
1720-
else => {},
1705+
// Check if we found a matching close paren or hit EOF
1706+
const tok_at_lookahead = self.tok_buf.tokens.items(.tag)[lookahead_pos];
1707+
if (tok_at_lookahead == .CloseRound) {
1708+
self.pos = lookahead_pos + 1; // Move past the closing paren
1709+
// Skip any suffix operators (e.g., .foo(), !(), etc.)
1710+
while (self.peek() != .EndOfFile) {
1711+
switch (self.peek()) {
1712+
.NoSpaceDotLowerIdent, .NoSpaceDotUpperIdent => {
1713+
self.advance();
1714+
},
1715+
.NoSpaceOpenRound => {
1716+
self.advance();
1717+
// Skip to matching close paren
1718+
var paren_depth: u32 = 1;
1719+
while (paren_depth > 0 and self.peek() != .EndOfFile) {
1720+
switch (self.peek()) {
1721+
.OpenRound, .NoSpaceOpenRound => paren_depth += 1,
1722+
.CloseRound => paren_depth -= 1,
1723+
else => {},
1724+
}
1725+
self.advance();
17211726
}
1727+
},
1728+
.OpBang => {
17221729
self.advance();
1723-
}
1724-
},
1725-
.OpBang => {
1726-
self.advance();
1727-
},
1728-
else => break,
1730+
},
1731+
else => break,
1732+
}
17291733
}
17301734
}
1735+
// If we didn't find matching close paren, just consume the open paren
1736+
// and fall through to produce an error at start position
17311737
return try self.pushMalformed(AST.Statement.Idx, .statement_unexpected_token, start);
17321738
}
17331739
},

0 commit comments

Comments
 (0)