mighty

The mighty programming language, compiler and tools (WIP)
Log | Files | Refs

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))
}

//
//
//
//
//
//
//
//
//