diff --git a/ast.go b/ast.go index bf2215c..6d1bb35 100644 --- a/ast.go +++ b/ast.go @@ -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" ) diff --git a/helpers.go b/helpers.go index d524e2c..3fbdf68 100644 --- a/helpers.go +++ b/helpers.go @@ -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 } diff --git a/parser_test.go b/parser_test.go index 7ba3368..dfa6421 100644 --- a/parser_test.go +++ b/parser_test.go @@ -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) { diff --git a/term.go b/term.go index 0352390..7703cef 100644 --- a/term.go +++ b/term.go @@ -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())