commit 252c23a24cd4a9ce71a96fa16f08cf4116654e3a
parent 550c7d05253cdd6115d417c1c31e510e54222435
Author: citbl <citbl@citbl.org>
Date: Sat, 16 May 2026 22:26:20 +1000
parser wip
Diffstat:
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)
+```