q/src/build/expression/Expression.go
2024-07-21 14:35:06 +02:00

146 lines
3.1 KiB
Go

package expression
import (
"strings"
"git.akyoto.dev/cli/q/src/build/token"
)
// Expression is a binary tree with an operator on each node.
type Expression struct {
Parent *Expression
Children []*Expression
Token token.Token
Precedence int8
}
// New creates a new expression.
func New() *Expression {
return &Expression{}
}
// NewLeaf creates a new leaf node.
func NewLeaf(t token.Token) *Expression {
return &Expression{
Token: t,
}
}
// 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
}
// Count counts how often the given token appears in the expression.
func (expr *Expression) Count(buffer []byte, kind token.Kind, name string) int {
count := 0
expr.EachLeaf(func(leaf *Expression) error {
if leaf.Token.Kind == kind && leaf.Token.Text(buffer) == name {
count++
}
return nil
})
return count
}
// Reset resets all values to the default.
func (expr *Expression) Reset() {
for _, child := range expr.Children {
child.Reset()
}
expr.Token.Reset()
expr.Parent = nil
expr.Children = expr.Children[:0]
expr.Precedence = 0
}
// EachLeaf iterates through all leaves in the tree.
func (expr *Expression) EachLeaf(call func(*Expression) error) error {
if expr.IsLeaf() {
return call(expr)
}
for _, child := range expr.Children {
err := child.EachLeaf(call)
if err != nil {
return err
}
}
return nil
}
// 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
}
}
}
// Replace replaces the tree with the new expression and adds the previous expression to it.
func (expr *Expression) Replace(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]
}
// String generates a textual representation of the expression.
func (expr *Expression) String(data []byte) string {
builder := strings.Builder{}
expr.write(&builder, data)
return builder.String()
}
// write generates a textual representation of the expression.
func (expr *Expression) write(builder *strings.Builder, data []byte) {
if expr.IsLeaf() {
builder.WriteString(expr.Token.Text(data))
return
}
builder.WriteByte('(')
switch expr.Token.Kind {
case token.Call:
builder.WriteString("λ")
case token.Array:
builder.WriteString("@")
default:
builder.WriteString(expr.Token.Text(data))
}
for _, child := range expr.Children {
builder.WriteByte(' ')
child.write(builder, data)
}
builder.WriteByte(')')
}