package main type parseError interface { Error() string Token() *token } type syntaxError struct { token *token message string } func newSyntaxError(token *token, message string) *syntaxError { return &syntaxError{token, message} } func (s *syntaxError) Token() *token { return s.token } func (s *syntaxError) Error() string { return s.message } type operandFunc func() (expr, error) type parser struct { tokens []*token current int } func newParser(tokens []*token) *parser { return &parser{ tokens: tokens, current: 0, } } func (p *parser) Parse() (expr, error) { e, err := p.expression() if err != nil { return e, err } return e, err } // expression -> equality func (p *parser) expression() (expr, error) { return p.equality() } func (p *parser) parseLeftAssocBinOps(operand operandFunc, tokenTypes ...tokenType) (expr, error) { e, err := operand() if err != nil { return e, err } for p.match(tokenTypes...) { op := p.previous() r, err := operand() if err != nil { return e, err } e = &binaryExpr{e, op, r} } return e, nil } // eqality -> comparison ( ("!=" | "==") comparison )* func (p *parser) equality() (expr, error) { return p.parseLeftAssocBinOps( p.comparison, tokenTypeBangEq, tokenTypeEqualEqual, ) } // comparison -> term ( ( ">" | ">=" | "<" | "<=" ) term )* func (p *parser) comparison() (expr, error) { return p.parseLeftAssocBinOps( p.term, tokenTypeGreater, tokenTypeGreaterEq, tokenTypeLess, tokenTypeLessEq, ) } // term -> factor ( ( "-" | "+" ) factor )* func (p *parser) term() (expr, error) { return p.parseLeftAssocBinOps( p.factor, tokenTypeMinus, tokenTypePlus, ) } // factor -> unary ( ( "*" | "/" ) unary )* func (p *parser) factor() (expr, error) { return p.parseLeftAssocBinOps( p.unary, tokenTypeSlash, tokenTypeStar, ) } // unary -> ( "!" | "-" ) unary | primary; func (p *parser) unary() (expr, error) { if p.match(tokenTypeBang, tokenTypeMinus) { op := p.previous() r, err := p.unary() return &unaryExpr{op, r}, err } return p.primary() } // primary -> STRING | NUMBER | "true" | "false" | "nil" | "(" expression ")" func (p *parser) primary() (expr, error) { if p.match(tokenTypeTrue) { return &literalExpr{true}, nil } if p.match(tokenTypeFalse) { return &literalExpr{false}, nil } if p.match(tokenTypeNil) { return &literalExpr{nil}, nil } if p.match(tokenTypeString, tokenTypeNumber) { return &literalExpr{p.previous().Literal}, nil } if p.match(tokenTypeLeftParen) { e, err := p.expression() if err != nil { return nil, err } _, err = p.consume(tokenTypeRightParen, "expected ')' after expression") return &groupingExpr{e}, err } return nil, newSyntaxError(p.peek(), "expected expression") } func (p *parser) consume(tokenType tokenType, msg string) (*token, error) { if p.check(tokenType) { return p.advance(), nil } return nil, newSyntaxError(p.peek(), msg) } func (p *parser) synchronize() { p.advance() for !p.isAtEnd() { if p.previous().Type == tokenTypeSemicolon { return } if isKeyword(p.peek()) { return } p.advance() } } func (p *parser) match(tokenTypes ...tokenType) bool { for _, t := range tokenTypes { if p.check(t) { p.advance() return true } } return false } func (p *parser) check(t tokenType) bool { if p.isAtEnd() { return false } return p.peek().Type == t } func (p *parser) advance() *token { if !p.isAtEnd() { p.current += 1 } return p.previous() } func (p *parser) isAtEnd() bool { return p.peek().Type == tokenTypeEOF } func (p *parser) peek() *token { return p.tokens[p.current] } func (p *parser) previous() *token { return p.tokens[p.current-1] }