fix if blocks, remove braces for blocks

This commit is contained in:
Sky Johnson 2025-05-06 15:24:49 -05:00
parent 5fc3f19c35
commit 67d586c789
2 changed files with 37 additions and 41 deletions

View File

@ -91,12 +91,11 @@ func (c *compiler) compileStatement(stmt parser.Statement) {
c.compileExpression(s.Value) c.compileExpression(s.Value)
c.emit(types.OpEcho, 0) c.emit(types.OpEcho, 0)
// BlockStatement now should only be used for keyword blocks like if-then-else-end
case *parser.BlockStatement: case *parser.BlockStatement:
c.enterScope()
for _, blockStmt := range s.Statements { for _, blockStmt := range s.Statements {
c.compileStatement(blockStmt) c.compileStatement(blockStmt)
} }
c.exitScope()
case *parser.ExpressionStatement: case *parser.ExpressionStatement:
c.compileExpression(s.Expression) c.compileExpression(s.Expression)

View File

@ -62,8 +62,9 @@ func New(l *lexer.Lexer) *Parser {
p.registerPrefix(lexer.TokenMinus, p.parsePrefixExpression) p.registerPrefix(lexer.TokenMinus, p.parsePrefixExpression)
p.registerPrefix(lexer.TokenLeftParen, p.parseGroupedExpression) p.registerPrefix(lexer.TokenLeftParen, p.parseGroupedExpression)
p.registerPrefix(lexer.TokenIf, p.parseIfExpression) p.registerPrefix(lexer.TokenIf, p.parseIfExpression)
p.registerPrefix(lexer.TokenElse, p.parseErrorToken) p.registerPrefix(lexer.TokenElse, p.parseUnexpectedToken)
p.registerPrefix(lexer.TokenEnd, p.parseErrorToken) p.registerPrefix(lexer.TokenEnd, p.parseUnexpectedToken)
p.registerPrefix(lexer.TokenThen, p.parseUnexpectedToken)
p.registerPrefix(lexer.TokenTrue, p.parseBooleanLiteral) p.registerPrefix(lexer.TokenTrue, p.parseBooleanLiteral)
p.registerPrefix(lexer.TokenFalse, p.parseBooleanLiteral) p.registerPrefix(lexer.TokenFalse, p.parseBooleanLiteral)
@ -167,8 +168,6 @@ func (p *Parser) parseStatement() Statement {
return p.parseExpressionStatement() return p.parseExpressionStatement()
case lexer.TokenEcho: case lexer.TokenEcho:
return p.parseEchoStatement() return p.parseEchoStatement()
case lexer.TokenLeftBrace:
return p.parseBlockStatement()
default: default:
return p.parseExpressionStatement() return p.parseExpressionStatement()
} }
@ -337,7 +336,7 @@ func (p *Parser) parseNumberLiteral() Expression {
func (p *Parser) parseTableLiteral() Expression { func (p *Parser) parseTableLiteral() Expression {
table := &TableLiteral{ table := &TableLiteral{
Token: p.curToken, Token: p.curToken, // This should be '{'
Pairs: make(map[Expression]Expression), Pairs: make(map[Expression]Expression),
} }
@ -461,54 +460,46 @@ func (p *Parser) parseIfExpression() Expression {
// Expect 'then' after condition // Expect 'then' after condition
if !p.expectPeek(lexer.TokenThen) { if !p.expectPeek(lexer.TokenThen) {
p.errors = append(p.errors, "expected 'then' after if condition")
return nil return nil
} }
p.nextToken() // Skip 'then' p.nextToken() // Skip 'then'
// Parse consequence (then block) // Create a block statement for the consequence
if p.curTokenIs(lexer.TokenLeftBrace) { consequence := &BlockStatement{Token: p.curToken}
expression.Consequence = p.parseBlockStatement() consequence.Statements = []Statement{}
} else {
// For single statement without braces // Parse statements until we hit 'else' or 'end'
stmt := &BlockStatement{Token: p.curToken} for !p.curTokenIs(lexer.TokenElse) && !p.curTokenIs(lexer.TokenEnd) && !p.curTokenIs(lexer.TokenEOF) {
stmt.Statements = []Statement{p.parseStatement()} stmt := p.parseStatement()
expression.Consequence = stmt consequence.Statements = append(consequence.Statements, stmt)
p.nextToken()
} }
expression.Consequence = consequence
// Check for 'else' // Check for 'else'
if p.peekTokenIs(lexer.TokenElse) { if p.curTokenIs(lexer.TokenElse) {
p.nextToken() // Move to 'else'
p.nextToken() // Skip 'else' p.nextToken() // Skip 'else'
// Parse alternative (else block) // Create a block statement for the alternative
if p.curTokenIs(lexer.TokenLeftBrace) { alternative := &BlockStatement{Token: p.curToken}
expression.Alternative = p.parseBlockStatement() alternative.Statements = []Statement{}
} else {
// For single statement without braces
stmt := &BlockStatement{Token: p.curToken}
stmt.Statements = []Statement{p.parseStatement()}
expression.Alternative = stmt
}
}
// Check for 'end' // Parse statements until we hit 'end'
if p.peekTokenIs(lexer.TokenEnd) { for !p.curTokenIs(lexer.TokenEnd) && !p.curTokenIs(lexer.TokenEOF) {
p.nextToken() // Consume 'end' stmt := p.parseStatement()
} else if !p.curTokenIs(lexer.TokenRightBrace) { alternative.Statements = append(alternative.Statements, stmt)
// Missing 'end'
p.errors = append(p.errors, fmt.Sprintf("line %d: expected 'end' to close if expression",
p.curToken.Line))
// Skip tokens until we find something that could be a valid statement start
for !p.curTokenIs(lexer.TokenEOF) &&
!p.curTokenIs(lexer.TokenSemicolon) &&
!p.curTokenIs(lexer.TokenIdentifier) &&
!p.curTokenIs(lexer.TokenEcho) {
p.nextToken() p.nextToken()
} }
expression.Alternative = alternative
}
// We should now be at the 'end' token
if !p.curTokenIs(lexer.TokenEnd) {
p.errors = append(p.errors, fmt.Sprintf("line %d: expected 'end' to close if expression",
p.curToken.Line))
return nil return nil
} }
@ -520,3 +511,9 @@ func (p *Parser) parseErrorToken() Expression {
p.errors = append(p.errors, msg) p.errors = append(p.errors, msg)
return nil return nil
} }
func (p *Parser) parseUnexpectedToken() Expression {
p.errors = append(p.errors, fmt.Sprintf("line %d: unexpected token: %s",
p.curToken.Line, p.curToken.Value))
return nil
}