fix(parser): ignore newlines instead of using them as statement terminators

This commit is contained in:
2026-02-06 20:58:00 +01:00
parent 14341471b7
commit dde5453e75

View File

@@ -12,7 +12,7 @@ from src.token import Token, TokenType
class Parser: class Parser:
IGNORE: set[TokenType] = { IGNORE: set[TokenType] = {
TokenType.WHITESPACE, TokenType.COMMENT TokenType.WHITESPACE, TokenType.COMMENT, TokenType.NEWLINE
} }
STATEMENT_BOUNDARY: set[TokenType] = { STATEMENT_BOUNDARY: set[TokenType] = {
@@ -31,16 +31,10 @@ class Parser:
def parse(self) -> list[Stmt]: def parse(self) -> list[Stmt]:
statements: list[Stmt] = [] statements: list[Stmt] = []
self.skip_newlines()
while not self.is_at_end(): while not self.is_at_end():
statements.append(self.declaration()) statements.append(self.declaration())
self.skip_newlines()
return statements return statements
def skip_newlines(self):
while self.check(TokenType.NEWLINE):
self.advance()
def is_at_end(self) -> bool: def is_at_end(self) -> bool:
return self.peek().type == TokenType.EOF return self.peek().type == TokenType.EOF
@@ -122,7 +116,6 @@ class Parser:
initializer: Optional[Expr] = None initializer: Optional[Expr] = None
if self.match(TokenType.EQUAL): if self.match(TokenType.EQUAL):
initializer = self.expression() initializer = self.expression()
self.expect_eol("Expected end of line after variable initialization")
return LetStmt(name, initializer) return LetStmt(name, initializer)
def statement(self) -> Stmt: def statement(self) -> Stmt:
@@ -208,19 +201,22 @@ class Parser:
def return_stmt(self) -> Stmt: def return_stmt(self) -> Stmt:
keyword: Token = self.previous() keyword: Token = self.previous()
value: Optional[Expr] = None value: Optional[Expr] = None
if not self.check(TokenType.NEWLINE) and not self.is_at_end(): if not self.check(TokenType.RIGHT_BRACE) and not self.is_at_end():
value = self.expression() value = self.expression()
self.expect_eol("Expected end of line after return statement.") if not self.is_at_end() and not self.check(TokenType.RIGHT_BRACE):
self.error(keyword, "Return must be the last statement in a function.")
return ReturnStmt(keyword, value) return ReturnStmt(keyword, value)
def break_stmt(self) -> Stmt: def break_stmt(self) -> Stmt:
keyword: Token = self.previous() keyword: Token = self.previous()
self.expect_eol("Expected end of line after break statement.") if not self.is_at_end() and not self.check(TokenType.RIGHT_BRACE):
self.error(keyword, "Break must be the last statement in a block.")
return BreakStmt(keyword) return BreakStmt(keyword)
def continue_stmt(self) -> Stmt: def continue_stmt(self) -> Stmt:
keyword: Token = self.previous() keyword: Token = self.previous()
self.expect_eol("Expected end of line after continue statement.") if not self.is_at_end() and not self.check(TokenType.RIGHT_BRACE):
self.error(keyword, "Continue must be the last statement in a block.")
return ContinueStmt(keyword) return ContinueStmt(keyword)
def while_stmt(self) -> Stmt: def while_stmt(self) -> Stmt:
@@ -230,9 +226,7 @@ class Parser:
def block_stmt(self) -> list[Stmt]: def block_stmt(self) -> list[Stmt]:
statements: list[Stmt] = [] statements: list[Stmt] = []
self.skip_newlines()
while not self.check(TokenType.RIGHT_BRACE) and not self.is_at_end(): while not self.check(TokenType.RIGHT_BRACE) and not self.is_at_end():
self.skip_newlines()
statements.append(self.declaration()) statements.append(self.declaration())
self.consume(TokenType.RIGHT_BRACE, "Expected '}' after block.") self.consume(TokenType.RIGHT_BRACE, "Expected '}' after block.")
@@ -240,7 +234,6 @@ class Parser:
def expression_stmt(self) -> Stmt: def expression_stmt(self) -> Stmt:
value: Expr = self.expression() value: Expr = self.expression()
self.expect_eol("Expected end of line after expression")
return ExpressionStmt(value) return ExpressionStmt(value)
def expression(self) -> Expr: def expression(self) -> Expr: