Open
Description
Short description: expr.ConstExpr
requires that the given function was defined in the environment and does not take into account those functions defined with expr.Function
.
Why it matters: This prevents usage of structs as environment in many cases, since it's impractical to define all the functions in the environment struct so we resort to add functionality with expr.Function
.
Workaround: It is possible to directly define the signature in the configuration if we directly set the value for the function in the expr/conf.(*Config).ConstFns
.
Limitations: a ConstExpr function can have a single signature because for each function name, we can only assign one value in ConstFns
. Maybe worth creating a Feature Request issue?
Example (Go Playground)
package main
import (
"fmt"
"github.com/expr-lang/expr"
)
type MyEnv struct {
Value string
}
func identity(x any) any {
return x
}
func main() {
code := `[identity(1), identity(Value)]`
options := []expr.Option{
expr.Env(MyEnv{}),
expr.Function(
"identity",
func(params ...any) (any, error) {
return identity(params[0]), nil
},
identity,
),
expr.ConstExpr("identity"), // Mark identity func as constant expression.
}
program, err := expr.Compile(code, options...)
if err != nil {
panic(err)
}
env := MyEnv{
Value: "thing",
}
output, err := expr.Run(program, env)
if err != nil {
panic(err)
}
fmt.Println(output)
}
Workaround for single-signature (Go Playground)
package main
import (
"fmt"
"reflect"
"github.com/expr-lang/expr"
"github.com/expr-lang/expr/conf"
)
type MyEnv struct {
Value string
}
func identity(x any) any {
return x
}
func main() {
code := `[identity(1), identity(Value)]`
options := []expr.Option{
expr.Env(MyEnv{}),
expr.Function(
"identity",
func(params ...any) (any, error) {
return identity(params[0]), nil
},
identity,
),
func(c *conf.Config) {
c.ConstFns["identity"] = reflect.ValueOf(identity) // Mark identity func as constant expression.
},
}
program, err := expr.Compile(code, options...)
if err != nil {
panic(err)
}
env := MyEnv{
Value: "thing",
}
output, err := expr.Run(program, env)
if err != nil {
panic(err)
}
fmt.Println(output)
}