mighty

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

parser.go (3626B)



package parser

import (
	"fmt"
	"mighty/lexer"
)

type Pos struct {
	Filename  string
	Line, Col int
}

type Node interface {
	anode()
	Pos() Pos
}

func (FuncDeclNode) anode() {}

type FuncDeclNode struct {
}

type Program struct {
}

func (Program) anode() {}

type P struct {
	tokens   []lexer.Token
	filename string
	pos      int
	errs     []error
}

type Parameter struct {
	Type  AnyType
	Ident lexer.Token
}

type AnyType interface{ typeRef() }

func (*PointerType) typeRef() {}
func (*ArrayType) typeRef()   {}
func (*FuncType) typeRef()    {}
func (*NamedType) typeRef()   {}

type PointerType struct{ Inner AnyType }
type ArrayType struct{ Element AnyType }

type FuncType struct {
	Params []AnyType
	Return AnyType
}

type NamedType struct {
	Name lexer.Token
	Type AnyType
}

func Parse(filename string, tokens []lexer.Token) Node {
	return Program{}
	if len(tokens) < 1 {
		return Node{Filename: filename}
	}

	p := P{filename: filename, tokens: tokens}
	p.parse_root()

	// make program
	program := Program{}
	return program
}

func (p *P) parse_root() {
	// namespace, use, decl
	for p.pos < len(p.tokens) {
		//t := p.advance()
		// todo namespace, use
		p.parse_declaration()
	}
}

func (p *P) parse_declaration() {
	//t := p.peek()
	// TODO @next check for keyword being pub
	if p.match(lexer.KeywordPub) {
		// public declaration
		p.advance() // consume pub
		switch p.peek().Kind {
		case lexer.KeywordStruct:
			fmt.Println("struct parsing todo")
		case lexer.KeywordEnum:
			fmt.Println("enum parsing todo")
		case lexer.Ident:
			// function parsing
			t_type := p.advance()
			t_label := p.expect(lexer.Ident, "expected Ident for label of function decl")
			p.expect(lexer.LParen, "expected a ( after function decl label")
			if !p.check(lexer.RParen) {
				params := parse_param_list()
			}
		default:
			fmt.Println("undefined parsing")
		}
	}
}

func (p *P) parse_param_list() []Node {
	var nodes []Node
	is_array := false
	for p.pos < len(p.tokens) {
		switch p.peek().Kind {
		case lexer.LBracket:
			p.advance()
			p.expect(lexer.RBracket, "expect ] in type definition starting with [")
			is_array = true
			fallthrough
		case lexer.Ident:
			param_type := p.expect(lexer.Ident, "expected type of param")
			param_name := p.expect(lexer.Ident, "expected name of param")
			var t AnyType
			if is_array {
				t = &ArrayType{}
			} else {
				t = &NamedType{}
			}

			node := Parameter{
				Ident: param_name,
				Type:  &NamedType{Name: param_type, Type: t},
			}
			nodes = append(nodes, node)
			if !p.match(lexer.Comma) {
				break
			}
		}
		return nodes
	}
}

func (p *P) peek() lexer.Token {

	if p.pos >= len(p.tokens) {
		return p.tokens[len(p.tokens)-1]
	}

	return p.tokens[p.pos]
}

func (p *P) advance() lexer.Token {
	tok := p.peek()
	if p.pos < len(p.tokens) {
		p.pos++
	}
	return tok
}

func (p *P) check(kind lexer.Kind) bool {
	return p.peek().Kind == kind
}

func (p *P) match(kind lexer.Kind) bool {
	if !p.check(kind) {
		return false
	}
	p.advance()
	return true
}

func (p *P) 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 *P) err(tok lexer.Token, msg string) {
	p.errs = append(p.errs, fmt.Errorf("%d:%d %s", tok.Line, tok.Col, msg))
}

type NodeKind int

const (
	FuncDecl NodeKind = iota
	MethodDecl
	StructDecl
	Param
	FieldDecl
	Block
	CallExpr
	Return
	Ident
	Type
	BinaryExpr
	UnaryExpr
	SubscriptExpr
	If
	Else
	Use
	Namespace
	From
	Pre
	Post
	Where
	Result
	Error
)

type OpKind int

const (
	Plus = iota
	Minus
	Mul
	Div
	Equality
	Inequality
)