/* 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: * 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.Expr { return p.expression() } // expression → equality ; func (p *Parser) expression() ast.Expr { return p.equality() } // 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 ")" ; 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.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} } // synchronize synchronizes the parser after an error. 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() } }