expr/ast.go

123 lines
2.2 KiB
Go
Raw Normal View History

2024-03-26 08:45:18 +01:00
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
2024-03-26 07:00:53 +01:00
// ast.go
package expr
import (
"errors"
"fmt"
"strings"
)
//-------- ast
type ast struct {
root *term
}
func NewAst() *ast {
return &ast{}
}
func (self *ast) String() string {
var sb strings.Builder
if self.root == nil {
sb.WriteString("(nil)")
} else {
self.root.toString(&sb)
}
return sb.String()
}
func (self *ast) addTokens(tokens ...*Token) (err error) {
for _, tk := range tokens {
if err = self.addToken(tk); err != nil {
break
}
}
return
}
func (self *ast) addToken(tk *Token) (err error) {
if t := newTerm(tk, nil); t != nil {
err = self.addTerm(t)
} else {
err = fmt.Errorf("No term constructor for token %q", tk.String())
}
return
}
func (self *ast) addTerm(node *term) (err error) {
if self.root == nil {
self.root = node
} else {
self.root, err = self.insert(self.root, node)
}
return
}
func (self *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()
subRoot, err = self.insert(last, node)
subRoot.setParent(tree)
} else {
node.setParent(tree)
}
} else if !node.isLeaf() {
root = node
tree.setParent(node)
} else {
err = fmt.Errorf("two adjacent operators: %q and %q", tree, node)
}
return
}
func (self *ast) eval(ctx exprContext) (result any, err error) {
if self.root != nil {
initDefaultVars(ctx)
2024-03-26 07:00:53 +01:00
result, err = self.root.compute(ctx)
} else {
err = errors.New("empty expression")
}
return
}
// Preset variables
const (
preset_bool_shortcut = "_bool_shortcut"
)
func initDefaultVars(ctx exprContext) {
ctx.SetValue(preset_bool_shortcut, true)
}
func enable(ctx exprContext, name string) {
if strings.HasPrefix(name, "_") {
ctx.SetValue(name, true)
} else {
ctx.SetValue("_"+name, true)
}
}
func disable(ctx exprContext, name string) {
if strings.HasPrefix(name, "_") {
ctx.SetValue(name, false)
} else {
ctx.SetValue("_"+name, false)
}
}
func isEnabled(ctx exprContext, name string) (status bool) {
if v, exists := ctx.GetValue(name); exists {
if b, ok := v.(bool); ok {
status = b
}
}
return
}