p.go.old (2666B)
package parser
import (
"fmt"
"mighty/lexer"
)
type Expr interface{ expr_node() }
type Ident struct{ Name string }
func (Ident) expr_node() {}
type LitInt struct{ Value string }
func (LitInt) expr_node() {}
type LitStr struct{ Value string }
func (LitStr) expr_node() {}
type Binary struct {
Op lexer.Kind
Left Expr
Right Expr
}
func (Binary) expr_node() {}
type Call struct {
Callee Expr
Args []Expr
}
func (Call) expr_node() {}
type Parser struct {
tokens []lexer.Token
pos int
errs []error
}
func ParseExpr(tokens []lexer.Token) (Expr, []error) {
p := Parser{tokens: tokens}
expr := p.expr(0)
return expr, p.errs
}
func (p *Parser) expr(minPrec int) Expr {
left := p.postfix()
for {
op := p.peek().Kind
prec := precedence(op)
if prec < minPrec {
break
}
p.advance()
right := p.expr(prec + 1)
left = Binary{Op: op, Left: left, Right: right}
}
return left
}
func (p *Parser) postfix() Expr {
left := p.primary()
for p.match(lexer.LParen) {
var args []Expr
if !p.check(lexer.RParen) {
for {
args = append(args, p.expr(0))
if !p.match(lexer.Comma) {
break
}
}
}
p.expect(lexer.RParen, "expected ')' after call arguments")
left = Call{Callee: left, Args: args}
}
return left
}
func (p *Parser) primary() Expr {
tok := p.advance()
switch tok.Kind {
case lexer.Ident:
return Ident{Name: tok.Value}
case lexer.LiteralInt:
return LitInt{Value: tok.Value}
case lexer.LiteralString:
return LitStr{Value: tok.Value}
case lexer.LParen:
expr := p.expr(0)
p.expect(lexer.RParen, "expected ')' after expression")
return expr
default:
p.err(tok, "expected expression")
return Ident{Name: "<error>"}
}
}
func precedence(kind lexer.Kind) int {
switch kind {
case lexer.Plus, lexer.Minus:
return 10
case lexer.Star, lexer.Slash:
return 20
default:
return -1
}
}
func (p *Parser) peek() lexer.Token {
if p.pos >= len(p.tokens) {
return p.tokens[len(p.tokens)-1]
}
return p.tokens[p.pos]
}
func (p *Parser) advance() lexer.Token {
tok := p.peek()
if p.pos < len(p.tokens) {
p.pos++
}
return tok
}
func (p *Parser) check(kind lexer.Kind) bool {
return p.peek().Kind == kind
}
func (p *Parser) match(kind lexer.Kind) bool {
if !p.check(kind) {
return false
}
p.advance()
return true
}
func (p *Parser) expect(kind lexer.Kind, msg string) lexer.Token {
if p.check(kind) {
return p.advance()
}
p.err(p.peek(), msg)
return lexer.Token{Kind: kind}
}
func (p *Parser) err(tok lexer.Token, msg string) {
p.errs = append(p.errs, fmt.Errorf("%d:%d %s", tok.Line, tok.Col, msg))
}
//
//
//
//
//
//
//
//
//