Something went wrong. Try again.
🌱 A minimal programming language and compiler. git.urbach.dev/cli/q
high-performance programming-language compiler
Something went wrong. Try again.
3.3 kB · 137 lines
Go
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137package expression
import ( "iter" "strings"
"git.urbach.dev/cli/q/src/token")
// Expression is a tree that can represent a mathematical expression with precedence levels.type Expression struct { Parent *Expression Children []*Expression Token token.Token precedence int8}
// AddChild adds a child to the expression.func (expr *Expression) AddChild(child *Expression) { if expr.Children == nil { expr.Children = make([]*Expression, 0, 2) }
expr.Children = append(expr.Children, child) child.Parent = expr}
// EachLeaf iterates through all leaves in the tree.func (expr *Expression) EachLeaf(yield func(*Expression) bool) bool { if expr.IsLeaf() { return yield(expr) }
for _, child := range expr.Children { if !child.EachLeaf(yield) { return false } }
return true}
// Index returns the position of the child or `-1` if it's not a child of this expression.func (expr *Expression) Index(child *Expression) int { for i, c := range expr.Children { if c == child { return i } }
return -1}
// InsertAbove replaces this expression in its parent's children with the given new parent,// and attaches this expression as a child of the new parent. Effectively, it promotes the// given tree above the current node. It assumes that the caller is the last child.func (expr *Expression) InsertAbove(tree *Expression) { if expr.Parent != nil { expr.Parent.Children[len(expr.Parent.Children)-1] = tree tree.Parent = expr.Parent }
tree.AddChild(expr)}
// IsLeaf returns true if the expression has no children.func (expr *Expression) IsLeaf() bool { return len(expr.Children) == 0}
// LastChild returns the last child.func (expr *Expression) LastChild() *Expression { return expr.Children[len(expr.Children)-1]}
// Leaves iterates through all leaves in the tree.func (expr *Expression) Leaves() iter.Seq[*Expression] { return func(yield func(*Expression) bool) { expr.EachLeaf(yield) }}
// RemoveChild removes a child from the expression.func (expr *Expression) RemoveChild(child *Expression) { for i, c := range expr.Children { if c == child { expr.Children = append(expr.Children[:i], expr.Children[i+1:]...) child.Parent = nil return } }}
// Reset resets all values to the default.func (expr *Expression) Reset() { expr.Parent = nil
if expr.Children != nil { expr.Children = expr.Children[:0] }
expr.Token.Reset() expr.precedence = 0}
// Source returns the start and end positions in the source file.func (expr *Expression) Source() token.Source { start := expr.Token.Position end := expr.Token.End()
for _, child := range expr.Children { source := child.Source()
if source.Start() < start { start = source.Start() }
if source.End() > end { end = source.End() } }
return token.NewSource(start, end)}
// SourceString returns the string that was parsed in this expression.func (expr *Expression) SourceString(source []byte) string { region := expr.Source() return string(source[region.Start():region.End()])}
// String generates a textual representation of the expression.func (expr *Expression) String(source []byte) string { builder := strings.Builder{} expr.write(&builder, source) return builder.String()}