116 lines
2.5 KiB
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(')')
|
|
}
|