-
Notifications
You must be signed in to change notification settings - Fork 1
/
eval_test.go
86 lines (73 loc) · 1.88 KB
/
eval_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package goexp
import (
"fmt"
"math"
"reflect"
"testing"
"github.com/svstanev/goexp/types"
)
func reduce(values []types.Integer, f func(x, y types.Integer) types.Integer, init types.Integer) types.Integer {
res := init
for _, n := range values {
res = f(res, n)
}
return res
}
func max(x, y types.Integer) types.Integer {
if x > y {
return x
}
return y
}
func TestEval(t *testing.T) {
ctx := NewEvalContext(nil)
ctx.AddName("x", types.Integer(1))
ctx.AddName("y", types.Integer(2))
ctx.AddMethod("max", func(values ...types.Integer) (types.Integer, error) {
return reduce(values, max, math.MinInt64), nil
})
tests := []struct {
expr string
result interface{}
err error
}{
{"1 + 2", types.Integer(3), nil},
{"max(x + y, 5, 3 * x * y)", types.Integer(6), nil},
{"2 ** 3", types.Integer(8), nil},
{"2.5 ** 3", types.Float(15.625), nil},
{"1 < 'foo'", nil, binaryOpNotSupportedError(types.Integer(1), types.String("foo"), "cmp")},
}
for i, test := range tests {
t.Run(fmt.Sprintf("#%v %v", i, test.expr), func(t *testing.T) {
res, err := eval(test.expr, ctx)
if !reflect.DeepEqual(err, test.err) {
t.Fatalf(`Expected "%v" error but got "%v" error`, test.err, err)
}
if err == nil && test.err == nil && !reflect.DeepEqual(res, test.result) {
t.Fatalf(`Expected %v but got %v`, test.result, res)
}
})
}
// res, err := eval("max(x + y, 5, 3 * x * y)", ctx)
// if err != nil {
// t.Fatal(err)
// }
// expected := types.Integer(6)
// if res != expected {
// t.Fatalf("Expected %#v but got %#v", expected, res)
// }
}
func eval(expr string, context Context) (interface{}, error) {
scanner := newScanner(expr)
tokens, err := scanner.scan()
if err != nil {
return nil, err
}
parser := newParser(tokens)
x, err := parser.parse()
if err != nil {
return nil, err
}
interpreter := newInterpreter(context)
return interpreter.eval(x)
}