expr.WithContext requires expr.Env?
When using the expr.WithContext option, the named variable must also be provided at compilation time using expr.Env, otherwise the patch seems to fail to correctly update calls to functions that require a context. (I'm not exactly sure why this happens, but if it's necessary, perhaps we should document it?)
Reproduction:
env := map[string]any{
`cancelled`: func(ctx context.Context) bool {
return ctx.Err() != nil
},
`ctx`: context.Background(),
}
program, err := expr.Compile(`cancelled()`,
expr.WithContext(`ctx`),
// expr.Env(env),
)
if err != nil {
panic(err)
}
output, err := expr.Run(program, env)
if err != nil {
panic(err)
}
fmt.Println(output)
With the expr.Env line commented out, this will fail (see playground), and with it uncommented, it succeeds (see playground). The error produced at runtime is:
reflect: Call with too few input arguments (1:1)
| cancelled()
| ^
Since this error also happens if cancelled is not bound at compilation but is bound at run, playground, I assume the problem is that Patch cannot figure out the argument of the function at compilation time.
Yes, exactly. If patcher is not able to figure out the types, it will not add context arg.
But there is a way without a patcher: https://go.dev/play/p/zKG4Ro4jlo4
package main
import (
"context"
"fmt"
"github.com/expr-lang/expr"
)
type Env struct {
ctx context.Context
Var string
}
func (e Env) Fn(s string) (string, error) {
if e.ctx.Err() != nil {
return "", e.ctx.Err()
}
return s, nil
}
func main() {
code := `Fn(Var)`
program, err := expr.Compile(code, expr.Env(Env{}))
if err != nil {
panic(err)
}
ctx, cancel := context.WithCancel(context.Background())
env := Env{
ctx: ctx,
Var: "foo",
}
output, err := expr.Run(program, env)
if err != nil {
panic(err)
}
fmt.Println(output)
cancel()
_, err = expr.Run(program, env)
if err != nil {
panic(err)
}
}