add Eval function (#338)
This commit is contained in:
parent
50af716288
commit
ac805806f8
3 changed files with 114 additions and 10 deletions
30
README.md
30
README.md
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
# The Tengo Language
|
# The Tengo Language
|
||||||
|
|
||||||
[![GoDoc](https://godoc.org/github.com/d5/tengo?status.svg)](https://godoc.org/github.com/d5/tengo)
|
[![GoDoc](https://godoc.org/github.com/d5/tengo/v2?status.svg)](https://godoc.org/github.com/d5/tengo/v2)
|
||||||
![test](https://github.com/d5/tengo/workflows/test/badge.svg)
|
![test](https://github.com/d5/tengo/workflows/test/badge.svg)
|
||||||
[![Go Report Card](https://goreportcard.com/badge/github.com/d5/tengo)](https://goreportcard.com/report/github.com/d5/tengo)
|
[![Go Report Card](https://goreportcard.com/badge/github.com/d5/tengo)](https://goreportcard.com/report/github.com/d5/tengo)
|
||||||
|
|
||||||
|
@ -93,21 +93,18 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Tengo script code
|
// create a new Script instance
|
||||||
src := `
|
script := tengo.NewScript([]byte(
|
||||||
each := func(seq, fn) {
|
`each := func(seq, fn) {
|
||||||
for x in seq { fn(x) }
|
for x in seq { fn(x) }
|
||||||
}
|
}
|
||||||
|
|
||||||
sum := 0
|
sum := 0
|
||||||
mul := 1
|
mul := 1
|
||||||
each([a, b, c, d], func(x) {
|
each([a, b, c, d], func(x) {
|
||||||
sum += x
|
sum += x
|
||||||
mul *= x
|
mul *= x
|
||||||
})`
|
})`))
|
||||||
|
|
||||||
// create a new Script instance
|
|
||||||
script := tengo.NewScript([]byte(src))
|
|
||||||
|
|
||||||
// set values
|
// set values
|
||||||
_ = script.Add("a", 1)
|
_ = script.Add("a", 1)
|
||||||
|
@ -128,6 +125,19 @@ each([a, b, c, d], func(x) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
|
||||||
|
```golang
|
||||||
|
res, err := tengo.Eval(ctx,
|
||||||
|
`input ? "success" : "fail"`,
|
||||||
|
map[string]interface{}{"input": 1})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Println(res) // "success"
|
||||||
|
```
|
||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
- [Language Syntax](https://github.com/d5/tengo/blob/master/docs/tutorial.md)
|
- [Language Syntax](https://github.com/d5/tengo/blob/master/docs/tutorial.md)
|
||||||
|
|
35
eval.go
Normal file
35
eval.go
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package tengo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Eval compiles and executes given expr with params, and returns an
|
||||||
|
// evaluated value. expr must be an expression. Otherwise it will fail to
|
||||||
|
// compile. Expression must not use or define variable "__res__" as it's
|
||||||
|
// reserved for the internal usage.
|
||||||
|
func Eval(
|
||||||
|
ctx context.Context,
|
||||||
|
expr string,
|
||||||
|
params map[string]interface{},
|
||||||
|
) (interface{}, error) {
|
||||||
|
expr = strings.TrimSpace(expr)
|
||||||
|
if expr == "" {
|
||||||
|
return nil, fmt.Errorf("empty expression")
|
||||||
|
}
|
||||||
|
|
||||||
|
script := NewScript([]byte(fmt.Sprintf("__res__ := (%s)", expr)))
|
||||||
|
for pk, pv := range params {
|
||||||
|
err := script.Add(pk, pv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("script add: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compiled, err := script.RunContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("script run: %w", err)
|
||||||
|
}
|
||||||
|
return compiled.Get("__res__").Value(), nil
|
||||||
|
}
|
59
eval_test.go
Normal file
59
eval_test.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package tengo_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/d5/tengo/v2"
|
||||||
|
"github.com/d5/tengo/v2/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEval(t *testing.T) {
|
||||||
|
eval := func(
|
||||||
|
expr string,
|
||||||
|
params map[string]interface{},
|
||||||
|
expected interface{},
|
||||||
|
) {
|
||||||
|
ctx := context.Background()
|
||||||
|
actual, err := tengo.Eval(ctx, expr, params)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
eval(`undefined`, nil, nil)
|
||||||
|
eval(`1`, nil, int64(1))
|
||||||
|
eval(`19 + 23`, nil, int64(42))
|
||||||
|
eval(`"foo bar"`, nil, "foo bar")
|
||||||
|
eval(`[1, 2, 3][1]`, nil, int64(2))
|
||||||
|
|
||||||
|
eval(
|
||||||
|
`5 + p`,
|
||||||
|
map[string]interface{}{
|
||||||
|
"p": 7,
|
||||||
|
},
|
||||||
|
int64(12),
|
||||||
|
)
|
||||||
|
eval(
|
||||||
|
`"seven is " + p`,
|
||||||
|
map[string]interface{}{
|
||||||
|
"p": 7,
|
||||||
|
},
|
||||||
|
"seven is 7",
|
||||||
|
)
|
||||||
|
eval(
|
||||||
|
`"" + a + b`,
|
||||||
|
map[string]interface{}{
|
||||||
|
"a": 7,
|
||||||
|
"b": " is seven",
|
||||||
|
},
|
||||||
|
"7 is seven",
|
||||||
|
)
|
||||||
|
|
||||||
|
eval(
|
||||||
|
`a ? "success" : "fail"`,
|
||||||
|
map[string]interface{}{
|
||||||
|
"a": 1,
|
||||||
|
},
|
||||||
|
"success",
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in a new issue