You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

577 lines
14 KiB
Go

/* 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 → funDecl | varDecl | statement ;
func (p *Parser) declaration() ast.Stmt {
if p.match(token.FUN) {
return p.function("function")
}
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 | forStmt | ifStmt | printStmt | returnStmt | whileStmt | block ;
func (p *Parser) statement() ast.Stmt {
if p.match(token.FOR) {
return p.forStatement()
}
if p.match(token.IF) {
return p.ifStatement()
}
if p.match(token.PRINT) {
return p.printStatement()
}
if p.match(token.RETURN) {
return p.returnStatement()
}
if p.match(token.WHILE) {
return p.whileStatement()
}
if p.match(token.LEFT_BRACE) {
return p.blockStatement()
}
return p.expressionStatement()
}
// forStmt → "for" "(" ( varDecl | exprStmt | ";" ) expression? ";" expression? ")" statement ;
func (p *Parser) forStatement() ast.Stmt {
err := p.consume(token.LEFT_PAREN, "Expect '(' after 'for'.")
if err != nil {
return p.fromErrorExpr(err)
}
var initializer ast.Stmt
if p.match(token.SEMICOLON) {
initializer = nil
} else if p.match(token.VAR) {
initializer = p.varDeclaration()
} else {
initializer = p.expressionStatement()
}
var condition ast.Expr
if !p.check(token.SEMICOLON) {
condition = p.expression()
}
err = p.consume(token.SEMICOLON, "Expect ';' after loop condition.")
if err != nil {
return p.fromErrorExpr(err)
}
var increment ast.Expr
if !p.check(token.RIGHT_PAREN) {
increment = p.expression()
}
err = p.consume(token.RIGHT_PAREN, "Expect ')' after for clauses.")
if err != nil {
return p.fromErrorExpr(err)
}
body := p.statement()
if increment != nil {
body = &ast.BlockStmt{Statements: []ast.Stmt{body, &ast.ExpressionStmt{Expression: increment}}}
}
if condition == nil {
condition = &ast.LiteralExpr{Value: true}
}
body = &ast.WhileStmt{Condition: condition, Body: body}
if initializer != nil {
body = &ast.BlockStmt{Statements: []ast.Stmt{initializer, body}}
}
return body
}
// ifStmt → "if" "(" expression ")" statement ( "else" statement )? ;
func (p *Parser) ifStatement() ast.Stmt {
err := p.consume(token.LEFT_PAREN, "Expect '(' after 'if'.")
if err != nil {
return p.fromErrorExpr(err)
}
condition := p.expression()
err = p.consume(token.RIGHT_PAREN, "Expect ')' after if condition.")
if err != nil {
return p.fromErrorExpr(err)
}
thenBranch := p.statement()
var elseBranch ast.Stmt
if p.match(token.ELSE) {
elseBranch = p.statement()
}
return &ast.IfStmt{Condition: condition, ThenBranch: thenBranch, ElseBranch: elseBranch}
}
// 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}
}
// returnStmt → "return" expression? ";" ;
func (p *Parser) returnStatement() ast.Stmt {
keyword := p.previous()
var value ast.Expr
if !p.check(token.SEMICOLON) {
value = p.expression()
}
err := p.consume(token.SEMICOLON, "Expect ';' after return value.")
if err != nil {
return p.fromErrorExpr(err)
}
return &ast.ReturnStmt{Keyword: keyword, Value: value}
}
// whileStmt → "while" "(" expression ")" statement ;
func (p *Parser) whileStatement() ast.Stmt {
err := p.consume(token.LEFT_PAREN, "Expect '(' after 'while'.")
if err != nil {
return p.fromErrorExpr(err)
}
condition := p.expression()
err = p.consume(token.RIGHT_PAREN, "Expect ')' after while condition.")
if err != nil {
return p.fromErrorExpr(err)
}
body := p.statement()
return &ast.WhileStmt{Condition: condition, Body: body}
}
// block → "{" declaration* "}" ;
func (p *Parser) blockStatement() ast.Stmt {
statements := []ast.Stmt{}
for !p.check(token.RIGHT_BRACE) && !p.isAtEnd() {
statements = append(statements, p.declaration())
}
err := p.consume(token.RIGHT_BRACE, "Expect '}' after block.")
if err != nil {
return p.fromErrorExpr(err)
}
return &ast.BlockStmt{Statements: statements}
}
// 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}
}
// function → "fun" IDENTIFIER "(" parameters? ")" block ;
func (p *Parser) function(kind string) ast.Stmt {
err := p.consume(token.IDENTIFIER, "Expect "+kind+" name.")
if err != nil {
return p.fromErrorExpr(err)
}
name := p.previous()
err = p.consume(token.LEFT_PAREN, "Expect '(' after "+kind+" name.")
if err != nil {
return p.fromErrorExpr(err)
}
parameters := []token.Token{}
if !p.check(token.RIGHT_PAREN) {
for {
if len(parameters) >= 255 {
p.newErrorExpr(p.peek(), "Cannot have more than 255 parameters.")
}
err = p.consume(token.IDENTIFIER, "Expect parameter name.")
if err != nil {
return p.fromErrorExpr(err)
}
parameters = append(parameters, p.previous())
if !p.match(token.COMMA) {
break
}
}
}
err = p.consume(token.RIGHT_PAREN, "Expect ')' after parameters.")
if err != nil {
return p.fromErrorExpr(err)
}
err = p.consume(token.LEFT_BRACE, "Expect '{' before "+kind+" body.")
if err != nil {
return p.fromErrorExpr(err)
}
if body, ok := p.blockStatement().(*ast.BlockStmt); ok {
return &ast.FunctionStmt{Name: name, Params: parameters, Body: body.Statements}
}
return p.newErrorStmt(p.peek(), "Expected block statement.")
}
// expression → assignment ;
func (p *Parser) expression() ast.Expr {
return p.assignment()
}
// assignment → IDENTIFIER "=" assignment | logic_or ;
func (p *Parser) assignment() ast.Expr {
expr := p.or()
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
}
// logic_or → logic_and ( "or" logic_and )* ;
func (p *Parser) or() ast.Expr {
expr := p.and()
for p.match(token.OR) {
operator := p.previous()
right := p.and()
expr = &ast.LogicalExpr{Left: expr, Operator: operator, Right: right}
}
return expr
}
// logic_and → equality ( "and" equality )* ;
func (p *Parser) and() ast.Expr {
expr := p.equality()
for p.match(token.AND) {
operator := p.previous()
right := p.equality()
expr = &ast.LogicalExpr{Left: expr, Operator: operator, Right: right}
}
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 | call ;
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.call()
}
// call → primary ( "(" arguments? ")" )* ;
func (p *Parser) call() ast.Expr {
expr := p.primary()
for {
if p.match(token.LEFT_PAREN) {
expr = p.finishCall(expr)
} else {
break
}
}
return expr
}
// finishCall finishes the call expression.
func (p *Parser) finishCall(callee ast.Expr) ast.Expr {
arguments := []ast.Expr{}
if !p.check(token.RIGHT_PAREN) {
for {
if len(arguments) >= 255 {
p.newErrorExpr(p.peek(), "Cannot have more than 255 arguments.")
}
arguments = append(arguments, p.expression())
if !p.match(token.COMMA) {
break
}
}
}
err := p.consume(token.RIGHT_PAREN, "Expect ')' after arguments.")
if err != nil {
return p.newErrorExpr(p.peek(), err.Value)
}
return &ast.CallExpr{Callee: callee, Paren: p.previous(), Arguments: arguments}
}
// 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}
}
// newErrorStmt creates a new ErrorStmt and reports the error.
func (p *Parser) newErrorStmt(t token.Token, message string) *ast.ErrorStmt {
p.errLogger.ErrorAtToken(t, message)
return &ast.ErrorStmt{Value: message}
}
// 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()
}
}