mighty

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

commit 252c23a24cd4a9ce71a96fa16f08cf4116654e3a
parent 550c7d05253cdd6115d417c1c31e510e54222435
Author: citbl <citbl@citbl.org>
Date:   Sat, 16 May 2026 22:26:20 +1000

parser wip

Diffstat:
Mmtc/lexer/lexer.go | 2+-
Mmtc/main.go | 8+++++---
Mmtc/parser/parser.go | 219+++++++++++++++++++------------------------------------------------------------
Amtc/parser/parser.go.old | 180+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aparsing.md | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 315 insertions(+), 171 deletions(-)

diff --git a/mtc/lexer/lexer.go b/mtc/lexer/lexer.go @@ -38,7 +38,7 @@ type Token struct { Line, Col int } -func Lex(src string) []Token { +func Lex(filename string, src string) []Token { var res []Token i := 0 line := 1 diff --git a/mtc/main.go b/mtc/main.go @@ -15,13 +15,15 @@ func main() { return } - data, err := os.ReadFile(args[0]) + filename := args[0] + + data, err := os.ReadFile(filename) if err != nil { panic(err) } - tokens := lexer.Lex(string(data)) + tokens := lexer.Lex(filename, string(data)) lexer.Print_tokens(tokens) - parser.ParseExpr(tokens) + parser.Parse(filename, tokens) } diff --git a/mtc/parser/parser.go b/mtc/parser/parser.go @@ -1,180 +1,65 @@ 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) { +import "mighty/lexer" - p := Parser{tokens: tokens} - expr := p.expr(0) - - return expr, p.errs +type Node struct { + kind NodeKind + Next *Node + Filename string + Line, Col int } -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} +func Parse(filename string, tokens []lexer.Token) Node { + if len(tokens) < 1 { + return Node{Filename: filename} } - - return left - + // make program + program := Node{Filename: filename} + return program } -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 -} +type NodeKind int + +const ( + Program NodeKind = iota + FuncDecl + MethodDecl + StructDecl + Param + FieldDecl + Block + CallExpr + Return + Ident + Type + BinaryExpr + UnaryExpr + SubscriptExpr + If + Else + Use + Namespace + From + Pre + Post + Where + Result + Error +) -func (p *Parser) check(kind lexer.Kind) bool { - return p.peek().Kind == kind -} +type OpKind int -func (p *Parser) match(kind lexer.Kind) bool { - if !p.check(kind) { - return false - } - p.advance() - return true -} +const ( + Plus = iota + Minus + Mul + Div + Equality + Inequality +) -func (p *Parser) expect(kind lexer.Kind, msg string) lexer.Token { - if p.check(kind) { - return p.advance() +func make_program_node(filename string) Node { + return Node{ + Filename: filename, } - - 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)) -} - -// -// -// -// -// -// -// -// -// diff --git a/mtc/parser/parser.go.old b/mtc/parser/parser.go.old @@ -0,0 +1,180 @@ +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)) +} + +// +// +// +// +// +// +// +// +// diff --git a/parsing.md b/parsing.md @@ -0,0 +1,77 @@ +Parse order +----------- + +``` +expr +conditional +pipe +logic +compare +range +add +mul +pow +unary +postfix +primary +``` + + +```yaml + +parseExpr + calls parseConditional + + parseConditional + parses parsePipe + optionally parses: if parseExpr else parseExpr + +parsePipe + parses parseLogic + loops pipe stages: | expr or | @(expr) + +parseLogic + parses parseCompare + loops and / or + +parseCompare + parses parseRange + loops == != < <= > >= + +parseRange + parses parseAdd + optionally parses .. parseAdd + +parseAdd + parses parseMul + loops + - + +parseMul + parses parsePow + loops * / + +parsePow + parses parseUnary + loops or recurses on ^ + +parseUnary + handles - and # + handles reduce/scan prefixes like +/xs, +\xs + otherwise calls parsePostfix + +parsePostfix + parses parsePrimary + loops: + call (...) + selector [...] + field .name + +parsePrimary + parses: + literal + path + subject . + array [...] + record Type(...) + grouped (expr) +```