diff options
Diffstat (limited to 'parser/parser.go')
| -rw-r--r-- | parser/parser.go | 111 |
1 files changed, 110 insertions, 1 deletions
diff --git a/parser/parser.go b/parser/parser.go index 936d58a..a9c381a 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -2,18 +2,46 @@ package parser import ( "fmt" + "strconv" "github.com/mewsen/interpreter/ast" "github.com/mewsen/interpreter/lexer" "github.com/mewsen/interpreter/token" ) +const ( + _ int = iota + LOWEST + EQUALS + LESSGREATER + SUM + PRODUCT + PREFIX + CALL +) + +type ( + prefixParseFn func() ast.Expression + infixParseFn func(ast.Expression) ast.Expression +) + type Parser struct { l *lexer.Lexer errors []string curToken token.Token peekToken token.Token + + prefixParseFns map[token.TokenType]prefixParseFn + infixParseFns map[token.TokenType]infixParseFn +} + +func (p *Parser) registerPrefix(tokenType token.TokenType, fn prefixParseFn) { + p.prefixParseFns[tokenType] = fn +} + +func (p *Parser) registerInfix(tokenType token.TokenType, fn infixParseFn) { + p.infixParseFns[tokenType] = fn } func (p *Parser) peekError(t token.TokenType) { @@ -34,12 +62,35 @@ func (p *Parser) Errors() []string { func New(l *lexer.Lexer) *Parser { p := &Parser{l: l, errors: []string{}} + p.prefixParseFns = make(map[token.TokenType]prefixParseFn) + p.registerPrefix(token.IDENT, p.parseIdentifier) + p.registerPrefix(token.INT, p.parseIntegerLiteral) + p.registerPrefix(token.BANG, p.parsePrefixExpression) + p.registerPrefix(token.MINUS, p.parsePrefixExpression) + p.NextToken() p.NextToken() return p } +func (p *Parser) parsePrefixExpression() ast.Expression { + expression := &ast.PrefixExpression{ + Token: p.curToken, + Operator: p.curToken.Literal, + } + + p.NextToken() + + expression.Right = p.parseExpression(PREFIX) + + return expression +} + +func (p *Parser) parseIdentifier() ast.Expression { + return &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal} +} + func (p *Parser) ParseProgram() *ast.Program { program := &ast.Program{} program.Statements = []ast.Statement{} @@ -59,9 +110,25 @@ func (p *Parser) parseStatement() ast.Statement { switch p.curToken.Type { case token.LET: return p.parseLetStatement() + case token.RETURN: + return p.parseReturnStatement() default: - return nil + return p.parseExpressionStatement() + } +} + +func (p *Parser) parseReturnStatement() *ast.ReturnStatement { + stmt := &ast.ReturnStatement{Token: p.curToken} + + p.NextToken() + + // TODO: We're skipping the expressions until + // we encounter a semicolon + for !p.curTokenIs(token.SEMICOLON) { + p.NextToken() } + + return stmt } func (p *Parser) parseLetStatement() *ast.LetStatement { @@ -85,6 +152,43 @@ func (p *Parser) parseLetStatement() *ast.LetStatement { return stmt } +func (p *Parser) parseExpressionStatement() *ast.ExpressionStatement { + stmt := &ast.ExpressionStatement{Token: p.curToken} + + stmt.Expression = p.parseExpression(LOWEST) + + if p.peekTokenIs(token.SEMICOLON) { + p.NextToken() + } + + return stmt +} + +func (p *Parser) parseExpression(precedence int) ast.Expression { + prefix := p.prefixParseFns[p.curToken.Type] + if prefix == nil { + p.noPrefixParseFnError(p.curToken.Type) + return nil + } + leftExp := prefix() + return leftExp +} + +func (p *Parser) parseIntegerLiteral() ast.Expression { + lit := &ast.IntegerLiteral{Token: p.curToken} + + value, err := strconv.ParseInt(p.curToken.Literal, 0, 64) + if err != nil { + msg := fmt.Sprintf("could not parse %q as integer", p.curToken.Literal) + p.errors = append(p.errors, msg) + return nil + } + + lit.Value = value + + return lit +} + func (p *Parser) curTokenIs(t token.TokenType) bool { return p.curToken.Type == t } @@ -101,3 +205,8 @@ func (p *Parser) expectPeek(t token.TokenType) bool { return false } } + +func (p *Parser) noPrefixParseFnError(t token.TokenType) { + msg := fmt.Sprintf("no prefix parse function for %s found", t) + p.errors = append(p.errors, msg) +} |
