q/src/build/expression/Expression.go

116 lines
2.5 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 {
Token token.Token
Parent *Expression
Children []*Expression
Precedence int
}
// New creates a new expression.
func New() *Expression {
return pool.Get().(*Expression)
}
// NewLeaf creates a new leaf node.
func NewLeaf(t token.Token) *Expression {
expr := New()
expr.Token = t
return expr
}
// NewBinary creates a new binary operator expression.
func NewBinary(left *Expression, operator token.Token, right *Expression) *Expression {
expr := New()
expr.Token = operator
expr.AddChild(left)
expr.AddChild(right)
return expr
}
// AddChild adds a child to the expression.
func (expr *Expression) AddChild(child *Expression) {
expr.Children = append(expr.Children, child)
child.Parent = expr
}
// Close puts the expression back into the memory pool.
func (expr *Expression) Close() {
for _, child := range expr.Children {
child.Close()
}
expr.Token.Reset()
expr.Parent = nil
expr.Children = expr.Children[:0]
expr.Precedence = 0
pool.Put(expr)
}
// 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() string {
builder := strings.Builder{}
expr.write(&builder)
return builder.String()
}
// write generates a textual representation of the expression.
func (expr *Expression) write(builder *strings.Builder) {
if expr.IsLeaf() {
builder.WriteString(expr.Token.Text())
return
}
builder.WriteByte('(')
builder.WriteString(expr.Token.Text())
builder.WriteByte(' ')
for i, child := range expr.Children {
child.write(builder)
if i != len(expr.Children)-1 {
builder.WriteByte(' ')
}
}
builder.WriteByte(')')
}