/* Description: This file contains the recursivde descent parser implementation. * The parser is responsible for parsing the tokens generated by the scanner. * * The grammar is as follows: * program → statement* EOF ; * statement → exprStmt * | printStmt ; * exprStmt → expression ";" ; * printStmt → "print" expression ";" ; * expression → equality ; * equality → comparison ( ( "!=" | "==" ) comparison )* ; * comparison → term ( ( ">" | ">=" | "<" | "<=" ) term )* ; * term → factor ( ( "-" | "+" ) factor )* ; * factor → unary ( ( "/" | "*" ) unary )* ; * unary → ( "!" | "-" ) unary * | primary ; * primary → NUMBER | STRING | "true" | "false" | "nil" * | "(" expression ")" ; */ package parser import ( "golox/ast" "golox/errors" "golox/token" ) // Parser is a recursive descent parser. type Parser struct { tokens []token.Token current int errLogger errors.Logger } // New creates a new Parser. func New(tokens []token.Token, el errors.Logger) *Parser { return &Parser{tokens: tokens, current: 0, errLogger: el} } // Parse parses the tokens and returns the AST. func (p *Parser) Parse() []ast.Stmt { stmts := []ast.Stmt{} for !p.isAtEnd() { stmt := p.declaration() if _, ok := stmt.(*ast.ErrorStmt); ok { p.synchronize() } else { stmts = append(stmts, stmt) } } return stmts } // declaration → varDecl | statement ; func (p *Parser) declaration() ast.Stmt { if p.match(token.VAR) { return p.varDeclaration() } return p.statement() } // varDecl → "var" IDENTIFIER ( "=" expression )? ";" ; func (p *Parser) varDeclaration() ast.Stmt { err := p.consume(token.IDENTIFIER, "Expect variable name.") if err != nil { return p.fromErrorExpr(err) } name := p.previous() var initializer ast.Expr if p.match(token.EQUAL) { initializer = p.expression() } err = p.consume(token.SEMICOLON, "Expect ';' after variable declaration.") if err != nil { return p.fromErrorExpr(err) } return &ast.VarStmt{Name: name, Initializer: initializer} } // statement → exprStmt | printStmt ; func (p *Parser) statement() ast.Stmt { if p.match(token.PRINT) { return p.printStatement() } return p.expressionStatement() } // exprStmt → expression ";" ; func (p *Parser) expressionStatement() ast.Stmt { expr := p.expression() err := p.consume(token.SEMICOLON, "Expect ';' after expression.") if err != nil { return p.fromErrorExpr(err) } return &ast.ExpressionStmt{Expression: expr} } // printStmt → "print" expression ";" ; func (p *Parser) printStatement() ast.Stmt { expr := p.expression() err := p.consume(token.SEMICOLON, "Expect ';' after value.") if err != nil { return p.fromErrorExpr(err) } return &ast.PrintStmt{Expression: expr} } // expression → assignment ; func (p *Parser) expression() ast.Expr { return p.assignment() } // assignment → IDENTIFIER "=" assignment | equality ; func (p *Parser) assignment() ast.Expr { expr := p.equality() if p.match(token.EQUAL) { equals := p.previous() value := p.assignment() if v, ok := expr.(*ast.VariableExpr); ok { return &ast.AssignExpr{Name: v.Name, Value: value} } p.newErrorExpr(equals, "Invalid assignment target.") } return expr } // equality → comparison ( ( "!=" | "==" ) comparison )* ; func (p *Parser) equality() ast.Expr { expr := p.comparison() for p.match(token.BANG_EQUAL, token.EQUAL_EQUAL) { operator := p.previous() right := p.comparison() expr = &ast.BinaryExpr{Left: expr, Operator: operator, Right: right} } return expr } // comparison → term ( ( ">" | ">=" | "<" | "<=" ) term )* ; func (p *Parser) comparison() ast.Expr { expr := p.term() for p.match(token.GREATER, token.GREATER_EQUAL, token.LESS, token.LESS_EQUAL) { operator := p.previous() right := p.term() expr = &ast.BinaryExpr{Left: expr, Operator: operator, Right: right} } return expr } // term → factor ( ( "-" | "+" ) factor )* ; func (p *Parser) term() ast.Expr { expr := p.factor() for p.match(token.MINUS, token.PLUS) { operator := p.previous() right := p.factor() expr = &ast.BinaryExpr{Left: expr, Operator: operator, Right: right} } return expr } // factor → unary ( ( "/" | "*" ) unary )* ; func (p *Parser) factor() ast.Expr { expr := p.unary() for p.match(token.SLASH, token.STAR) { operator := p.previous() right := p.unary() expr = &ast.BinaryExpr{Left: expr, Operator: operator, Right: right} } return expr } // unary → ( "!" | "-" ) unary | primary ; func (p *Parser) unary() ast.Expr { if p.match(token.BANG, token.MINUS) { operator := p.previous() right := p.unary() return &ast.UnaryExpr{Operator: operator, Right: right} } return p.primary() } // primary → NUMBER | STRING | "true" | "false" | "nil" | "(" expression ")" | IDENTIFIER; func (p *Parser) primary() ast.Expr { switch { case p.match(token.FALSE): return &ast.LiteralExpr{Value: false} case p.match(token.TRUE): return &ast.LiteralExpr{Value: true} case p.match(token.NIL): return &ast.LiteralExpr{Value: nil} case p.match(token.NUMBER, token.STRING): return &ast.LiteralExpr{Value: p.previous().Literal} case p.match(token.IDENTIFIER): return &ast.VariableExpr{Name: p.previous()} case p.match(token.LEFT_PAREN): expr := p.expression() err := p.consume(token.RIGHT_PAREN, "Expect ')' after expression.") if err != nil { return err } return &ast.GroupingExpr{Expression: expr} } return p.newErrorExpr(p.peek(), "Expect expression.") } // match checks if the current token is any of the given types. func (p *Parser) match(types ...token.TokenType) bool { for _, t := range types { if p.check(t) { p.advance() return true } } return false } // consume consumes the current token if it is of the given type. func (p *Parser) consume(tt token.TokenType, message string) *ast.ErrorExpr { if p.check(tt) { p.advance() return nil } return p.newErrorExpr(p.peek(), message) } // check checks if the current token is of the given type. func (p *Parser) check(tt token.TokenType) bool { if p.isAtEnd() { return false } return p.peek().Type == tt } // advance advances the current token and returns the previous token. func (p *Parser) advance() token.Token { if !p.isAtEnd() { p.current++ } return p.previous() } // isAtEnd checks if the parser has reached the end of the tokens. func (p *Parser) isAtEnd() bool { return p.peek().Type == token.EOF } // peek returns the current token. func (p *Parser) peek() token.Token { return p.tokens[p.current] } // previous returns the previous token. func (p *Parser) previous() token.Token { return p.tokens[p.current-1] } // newErrorExpr creates a new ErrorExpr and reports the error. func (p *Parser) newErrorExpr(t token.Token, message string) *ast.ErrorExpr { p.errLogger.ErrorAtToken(t, message) return &ast.ErrorExpr{Value: message} } // fromErrorExpr creates an ErrorStmt from an ErrorExpr. func (p *Parser) fromErrorExpr(ee *ast.ErrorExpr) *ast.ErrorStmt { return &ast.ErrorStmt{Value: ee.Value} } // synchronize synchronizes the parser after an error. // It skips tokens until it finds a statement boundary. func (p *Parser) synchronize() { p.advance() for !p.isAtEnd() { if p.previous().Type == token.SEMICOLON { return } switch p.peek().Type { case token.CLASS, token.FUN, token.VAR, token.FOR, token.IF, token.WHILE, token.PRINT, token.RETURN: return } p.advance() } }