ast: now supports espression forest (multi expressions)

This commit is contained in:
Celestino Amoroso 2024-03-31 05:57:02 +02:00
parent aa705e68bf
commit 4e361f938e
4 changed files with 41 additions and 8 deletions

37
ast.go
View File

@ -13,6 +13,7 @@ import (
//-------- ast
type ast struct {
forest []*term
root *term
}
@ -20,6 +21,16 @@ func NewAst() *ast {
return &ast{}
}
func (self *ast) ToForest() {
if self.root != nil {
if self.forest == nil {
self.forest = make([]*term, 0)
}
self.forest = append(self.forest, self.root)
self.root = nil
}
}
func (self *ast) String() string {
var sb strings.Builder
if self.root == nil {
@ -77,10 +88,31 @@ func (self *ast) insert(tree, node *term) (root *term, err error) {
return
}
func (self *ast) eval(ctx exprContext) (result any, err error) {
func (self *ast) Finish() {
if self.root == nil && self.forest != nil && len(self.forest) >= 1 {
self.root = self.forest[len(self.forest)-1]
self.forest = self.forest[0:len(self.forest) - 1]
}
}
func (self *ast) Eval(ctx exprContext) (result any, err error) {
self.Finish()
if self.root != nil {
initDefaultVars(ctx)
result, err = self.root.compute(ctx)
if self.forest != nil {
for i, root := range self.forest {
if result, err = root.compute(ctx); err == nil {
ctx.SetValue(preset_last_result, result)
} else {
err = fmt.Errorf("error in expression nr %d: %v", i+1, err)
break
}
}
}
if err == nil {
result, err = self.root.compute(ctx)
}
} else {
err = errors.New("empty expression")
}
@ -89,6 +121,7 @@ func (self *ast) eval(ctx exprContext) (result any, err error) {
// Preset variables
const (
preset_last_result = "_last"
preset_bool_shortcut = "_bool_shortcut"
)

View File

@ -14,7 +14,7 @@ func EvalString(ctx exprContext, source string) (result any, err error) {
parser := NewParser(ctx)
if tree, err = parser.parse(scanner); err == nil {
result, err = tree.eval(ctx)
result, err = tree.Eval(ctx)
}
return
}

View File

@ -65,7 +65,7 @@ func TestParser(t *testing.T) {
/* 39 */ {`(((1)))`, int64(1), nil},
/* 40 */ {`"uno_" + var2`, `uno_abc`, nil},
/* 41 */ {`0 || 0.0 && "hello"`, false, nil},
/* 42 */ {`"s" + true`, nil, errors.New(`left operand 's' [string] is not compatible with right operand 'true' [bool] with respect to operator "+"`)},
/* 42 */ {`"s" + true`, nil, errors.New(`left operand 's' [string] and right operand 'true' [bool] are not compatible with operator "+"`)},
/* 43 */ {`+false`, nil, errors.New(`prefix/postfix operator "+" do not support operand 'false' [bool]`)},
/* 44 */ {`false // very simple expression`, false, nil},
/* 45 */ {`1 + // Missing right operator`, nil, errors.New(`infix operator "+" requires two operands, got 1`)},
@ -108,7 +108,7 @@ func TestParser(t *testing.T) {
/* 82 */ {`5 % 2`, int64(1), nil},
/* 83 */ {`5 % (-2)`, int64(1), nil},
/* 84 */ {`-5 % 2`, int64(-1), nil},
/* 85 */ {`5 % 2.0`, nil, errors.New(`left operand '5' [int64] is not compatible with right operand '2' [float64] with respect to operator "%"`)},
/* 85 */ {`5 % 2.0`, nil, errors.New(`left operand '5' [int64] and right operand '2' [float64] are not compatible with operator "%"`)},
/* 86 */ {`"a" < "b" AND NOT (2 < 1)`, true, nil},
/* 87 */ {`"a" < "b" AND NOT (2 == 1)`, true, nil},
/* 88 */ {`"a" < "b" AND ~ 2 == 1`, true, nil},
@ -147,7 +147,7 @@ func TestParser(t *testing.T) {
good := true
if expr, gotErr = parser.parse(scanner); gotErr == nil {
gotResult, gotErr = expr.eval(ctx)
gotResult, gotErr = expr.Eval(ctx)
}
if gotResult != input.wantResult {
@ -221,7 +221,7 @@ func NoTestListParser(t *testing.T) {
good := true
if expr, gotErr = parser.parse(scanner); gotErr == nil {
gotResult, gotErr = expr.eval(ctx)
gotResult, gotErr = expr.Eval(ctx)
}
if (gotResult == nil && input.wantResult != nil) || (gotResult != nil && input.wantResult == nil) {

View File

@ -188,7 +188,7 @@ func (self *term) compute(ctx exprContext) (v any, err error) {
func (self *term) errIncompatibleTypes(leftValue, rightValue any) error {
return fmt.Errorf(
"left operand '%v' [%T] is not compatible with right operand '%v' [%T] with respect to operator %q",
"left operand '%v' [%T] and right operand '%v' [%T] are not compatible with operator %q",
leftValue, leftValue,
rightValue, rightValue,
self.source())