summaryrefslogtreecommitdiff
path: root/parser/parser.go
diff options
context:
space:
mode:
authorMichael Tews <michael@tews.dev>2024-12-13 07:16:00 +0100
committerMichael Tews <michael@tews.dev>2026-04-12 11:11:02 +0200
commit68ff1414130b7bdd9cbfe0e5c1fc60278f9a48fd (patch)
tree5baeea833552b3f60f2c9f5dbf7d82492e066358 /parser/parser.go
parent0f51131eedb73d371bcf4d4868cb784f3592d08c (diff)
feat(parser): expressions, literalsHEADmain
Signed-off-by: Michael Tews <michael@tews.dev>
Diffstat (limited to 'parser/parser.go')
-rw-r--r--parser/parser.go111
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)
+}