Mako/parser/parser.go
2025-06-09 09:58:47 -05:00

240 lines
5.1 KiB
Go

package parser
import (
"fmt"
"strconv"
)
// Parser implements a recursive descent Pratt parser
type Parser struct {
lexer *Lexer
curToken Token
peekToken Token
prefixParseFns map[TokenType]func() Expression
infixParseFns map[TokenType]func(Expression) Expression
errors []string
}
// NewParser creates a new parser instance
func NewParser(lexer *Lexer) *Parser {
p := &Parser{
lexer: lexer,
errors: []string{},
}
p.prefixParseFns = make(map[TokenType]func() Expression)
p.registerPrefix(IDENT, p.parseIdentifier)
p.registerPrefix(NUMBER, p.parseNumberLiteral)
p.registerPrefix(STRING, p.parseStringLiteral)
p.registerPrefix(TRUE, p.parseBooleanLiteral)
p.registerPrefix(FALSE, p.parseBooleanLiteral)
p.registerPrefix(NIL, p.parseNilLiteral)
p.registerPrefix(LPAREN, p.parseGroupedExpression)
p.infixParseFns = make(map[TokenType]func(Expression) Expression)
p.registerInfix(PLUS, p.parseInfixExpression)
p.registerInfix(MINUS, p.parseInfixExpression)
p.registerInfix(SLASH, p.parseInfixExpression)
p.registerInfix(STAR, p.parseInfixExpression)
// Read two tokens, so curToken and peekToken are both set
p.nextToken()
p.nextToken()
return p
}
// registerPrefix registers a prefix parse function
func (p *Parser) registerPrefix(tokenType TokenType, fn func() Expression) {
p.prefixParseFns[tokenType] = fn
}
// registerInfix registers an infix parse function
func (p *Parser) registerInfix(tokenType TokenType, fn func(Expression) Expression) {
p.infixParseFns[tokenType] = fn
}
// nextToken advances to the next token
func (p *Parser) nextToken() {
p.curToken = p.peekToken
p.peekToken = p.lexer.NextToken()
}
// ParseProgram parses the entire program
func (p *Parser) ParseProgram() *Program {
program := &Program{}
program.Statements = []Statement{}
for !p.curTokenIs(EOF) {
stmt := p.parseStatement()
if stmt != nil {
program.Statements = append(program.Statements, stmt)
}
p.nextToken()
}
return program
}
// parseStatement parses a statement
func (p *Parser) parseStatement() Statement {
if p.curTokenIs(IDENT) && p.peekTokenIs(ASSIGN) {
return p.parseAssignStatement()
}
// Skip unknown statements for now
return nil
}
// parseAssignStatement parses variable assignment
func (p *Parser) parseAssignStatement() *AssignStatement {
stmt := &AssignStatement{}
if !p.curTokenIs(IDENT) {
return nil
}
stmt.Name = &Identifier{Value: p.curToken.Literal}
if !p.expectPeek(ASSIGN) {
return nil
}
p.nextToken()
stmt.Value = p.parseExpression(LOWEST)
return stmt
}
// parseExpression parses expressions using Pratt parsing
func (p *Parser) parseExpression(precedence Precedence) Expression {
prefix := p.prefixParseFns[p.curToken.Type]
if prefix == nil {
p.noPrefixParseFnError(p.curToken.Type)
return nil
}
leftExp := prefix()
for !p.peekTokenIs(EOF) && precedence < p.peekPrecedence() {
infix := p.infixParseFns[p.peekToken.Type]
if infix == nil {
return leftExp
}
p.nextToken()
leftExp = infix(leftExp)
}
return leftExp
}
// Expression parsing functions
func (p *Parser) parseIdentifier() Expression {
return &Identifier{Value: p.curToken.Literal}
}
func (p *Parser) parseNumberLiteral() Expression {
lit := &NumberLiteral{}
value, err := strconv.ParseFloat(p.curToken.Literal, 64)
if err != nil {
msg := fmt.Sprintf("could not parse %q as float", p.curToken.Literal)
p.errors = append(p.errors, msg)
return nil
}
lit.Value = value
return lit
}
func (p *Parser) parseStringLiteral() Expression {
return &StringLiteral{Value: p.curToken.Literal}
}
func (p *Parser) parseBooleanLiteral() Expression {
return &BooleanLiteral{Value: p.curTokenIs(TRUE)}
}
func (p *Parser) parseNilLiteral() Expression {
return &NilLiteral{}
}
func (p *Parser) parseGroupedExpression() Expression {
p.nextToken()
exp := p.parseExpression(LOWEST)
if !p.expectPeek(RPAREN) {
return nil
}
return exp
}
func (p *Parser) parseInfixExpression(left Expression) Expression {
expression := &InfixExpression{
Left: left,
Operator: p.curToken.Literal,
}
precedence := p.curPrecedence()
p.nextToken()
expression.Right = p.parseExpression(precedence)
return expression
}
// Helper methods
func (p *Parser) curTokenIs(t TokenType) bool {
return p.curToken.Type == t
}
func (p *Parser) peekTokenIs(t TokenType) bool {
return p.peekToken.Type == t
}
func (p *Parser) expectPeek(t TokenType) bool {
if p.peekTokenIs(t) {
p.nextToken()
return true
} else {
p.peekError(t)
return false
}
}
func (p *Parser) peekError(t TokenType) {
msg := fmt.Sprintf("expected next token to be %v, got %v instead",
t, p.peekToken.Type)
p.errors = append(p.errors, msg)
}
func (p *Parser) noPrefixParseFnError(t TokenType) {
msg := fmt.Sprintf("no prefix parse function for %v found", t)
p.errors = append(p.errors, msg)
}
func (p *Parser) peekPrecedence() Precedence {
if p, ok := precedences[p.peekToken.Type]; ok {
return p
}
return LOWEST
}
func (p *Parser) curPrecedence() Precedence {
if p, ok := precedences[p.curToken.Type]; ok {
return p
}
return LOWEST
}
// Errors returns all parsing errors
func (p *Parser) Errors() []string {
return p.errors
}