expr/ast.go

133 lines
2.5 KiB
Go

// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// ast.go
package expr
import (
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
)
//-------- ast
type ast struct {
forest []*term
root *term
}
func NewAst() *ast {
return &ast{}
}
func (ast *ast) TypeName() string {
return "Expression"
}
func (ast *ast) ToForest() {
if ast.root != nil {
if ast.forest == nil {
ast.forest = make([]*term, 0)
}
ast.forest = append(ast.forest, ast.root)
ast.root = nil
}
}
func (ast *ast) String() string {
var sb strings.Builder
if ast.root == nil {
sb.WriteString("(nil)")
} else {
ast.root.toString(&sb)
}
return sb.String()
}
func (ast *ast) addTokens(tokens ...*Token) (err error) {
for _, tk := range tokens {
if _, err = ast.addToken(tk); err != nil {
break
}
}
return
}
// func (expr *ast) addToken(tk *Token) (err error) {
// _, err = expr.addToken2(tk)
// return
// }
func (ast *ast) addToken(tk *Token) (t *term, err error) {
if t = newTerm(tk); t != nil {
err = ast.addTerm(t)
} else {
err = tk.Errorf("unexpected token %q", tk.String())
}
return
}
func (ast *ast) addTerm(node *term) (err error) {
if ast.root == nil {
ast.root = node
} else {
ast.root, err = ast.insert(ast.root, node)
}
return
}
func (ast *ast) insert(tree, node *term) (root *term, err error) {
if tree.getPriority() < node.getPriority() {
root = tree
if tree.isComplete() {
var subRoot *term
last := tree.removeLastChild()
if subRoot, err = ast.insert(last, node); err == nil {
subRoot.setParent(tree)
}
} else {
node.setParent(tree)
}
} else if !node.isLeaf() {
root = node
tree.setParent(node)
} else {
err = node.Errorf("two adjacent operators: %q and %q", tree, node)
}
return
}
func (ast *ast) Finish() {
if ast.root == nil && ast.forest != nil && len(ast.forest) >= 1 {
ast.root = ast.forest[len(ast.forest)-1]
ast.forest = ast.forest[0 : len(ast.forest)-1]
}
}
func (ast *ast) Eval(ctx kern.ExprContext) (result any, err error) {
ast.Finish()
if ast.root != nil {
// initDefaultVars(ctx)
if ast.forest != nil {
for _, root := range ast.forest {
if result, err = root.Compute(ctx); err == nil {
ctx.UnsafeSetVar(kern.ControlLastResult, result)
} else {
//err = fmt.Errorf("error in expression nr %d: %v", i+1, err)
break
}
}
}
if err == nil {
if result, err = ast.root.Compute(ctx); err == nil {
ctx.UnsafeSetVar(kern.ControlLastResult, result)
}
}
// } else {
// err = errors.New("empty expression")
}
return
}