Skip to content

Commit ac80580

Browse files
authored
add Eval function (#338)
1 parent 50af716 commit ac80580

File tree

3 files changed

+114
-10
lines changed

3 files changed

+114
-10
lines changed

README.md

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
# The Tengo Language
66

7-
[![GoDoc](https://godoc.org/github.com/d5/tengo?status.svg)](https://godoc.org/github.com/d5/tengo)
7+
[![GoDoc](https://godoc.org/github.com/d5/tengo/v2?status.svg)](https://godoc.org/github.com/d5/tengo/v2)
88
![test](https://github.com/d5/tengo/workflows/test/badge.svg)
99
[![Go Report Card](https://goreportcard.com/badge/github.com/d5/tengo)](https://goreportcard.com/report/github.com/d5/tengo)
1010

@@ -93,21 +93,18 @@ import (
9393
)
9494

9595
func main() {
96-
// Tengo script code
97-
src := `
98-
each := func(seq, fn) {
96+
// create a new Script instance
97+
script := tengo.NewScript([]byte(
98+
`each := func(seq, fn) {
9999
for x in seq { fn(x) }
100100
}
101101
102102
sum := 0
103103
mul := 1
104104
each([a, b, c, d], func(x) {
105-
sum += x
106-
mul *= x
107-
})`
108-
109-
// create a new Script instance
110-
script := tengo.NewScript([]byte(src))
105+
sum += x
106+
mul *= x
107+
})`))
111108

112109
// set values
113110
_ = script.Add("a", 1)
@@ -128,6 +125,19 @@ each([a, b, c, d], func(x) {
128125
}
129126
```
130127

128+
Or, if you need to evaluate a simple expression, you can use [Eval](https://pkg.go.dev/github.com/d5/tengo/v2#Eval) function instead:
129+
130+
131+
```golang
132+
res, err := tengo.Eval(ctx,
133+
`input ? "success" : "fail"`,
134+
map[string]interface{}{"input": 1})
135+
if err != nil {
136+
panic(err)
137+
}
138+
fmt.Println(res) // "success"
139+
```
140+
131141
## References
132142

133143
- [Language Syntax](https://github.com/d5/tengo/blob/master/docs/tutorial.md)

eval.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package tengo
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
)
8+
9+
// Eval compiles and executes given expr with params, and returns an
10+
// evaluated value. expr must be an expression. Otherwise it will fail to
11+
// compile. Expression must not use or define variable "__res__" as it's
12+
// reserved for the internal usage.
13+
func Eval(
14+
ctx context.Context,
15+
expr string,
16+
params map[string]interface{},
17+
) (interface{}, error) {
18+
expr = strings.TrimSpace(expr)
19+
if expr == "" {
20+
return nil, fmt.Errorf("empty expression")
21+
}
22+
23+
script := NewScript([]byte(fmt.Sprintf("__res__ := (%s)", expr)))
24+
for pk, pv := range params {
25+
err := script.Add(pk, pv)
26+
if err != nil {
27+
return nil, fmt.Errorf("script add: %w", err)
28+
}
29+
}
30+
compiled, err := script.RunContext(ctx)
31+
if err != nil {
32+
return nil, fmt.Errorf("script run: %w", err)
33+
}
34+
return compiled.Get("__res__").Value(), nil
35+
}

eval_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package tengo_test
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/d5/tengo/v2"
8+
"github.com/d5/tengo/v2/require"
9+
)
10+
11+
func TestEval(t *testing.T) {
12+
eval := func(
13+
expr string,
14+
params map[string]interface{},
15+
expected interface{},
16+
) {
17+
ctx := context.Background()
18+
actual, err := tengo.Eval(ctx, expr, params)
19+
require.NoError(t, err)
20+
require.Equal(t, expected, actual)
21+
}
22+
23+
eval(`undefined`, nil, nil)
24+
eval(`1`, nil, int64(1))
25+
eval(`19 + 23`, nil, int64(42))
26+
eval(`"foo bar"`, nil, "foo bar")
27+
eval(`[1, 2, 3][1]`, nil, int64(2))
28+
29+
eval(
30+
`5 + p`,
31+
map[string]interface{}{
32+
"p": 7,
33+
},
34+
int64(12),
35+
)
36+
eval(
37+
`"seven is " + p`,
38+
map[string]interface{}{
39+
"p": 7,
40+
},
41+
"seven is 7",
42+
)
43+
eval(
44+
`"" + a + b`,
45+
map[string]interface{}{
46+
"a": 7,
47+
"b": " is seven",
48+
},
49+
"7 is seven",
50+
)
51+
52+
eval(
53+
`a ? "success" : "fail"`,
54+
map[string]interface{}{
55+
"a": 1,
56+
},
57+
"success",
58+
)
59+
}

0 commit comments

Comments
 (0)