@@ -47,17 +47,31 @@ Specify a visitor to modify the AST with `expr.Patch` function.
4747program , err := expr.Compile (code, expr.Patch (&visitor{}))
4848```
4949
50- For example, we are going to replace the expression ` list[-1] ` with the ` list[len(list)-1] ` .
50+ For example, let's pass a context to every function call:
5151
5252``` go
53+ package main
54+
55+ import (
56+ " context"
57+ " fmt"
58+ " reflect"
59+
60+ " github.com/antonmedv/expr"
61+ " github.com/antonmedv/expr/ast"
62+ )
63+
5364func main () {
5465 env := map [string ]interface {}{
55- " list" : []int {1 , 2 , 3 },
66+ " foo" : func (ctx context.Context , arg int ) any {
67+ // ...
68+ },
69+ " ctx" : context.Background (),
5670 }
5771
58- code := ` list[-1] ` // will output 3
72+ code := ` foo(42) ` // will be converted to foo(ctx, 42)
5973
60- program , err := expr.Compile (code, expr.Env (env), expr.Patch (& patcher{}))
74+ program , err := expr.Compile (code, expr.Env (env), expr.Patch (patcher{}))
6175 if err != nil {
6276 panic (err)
6377 }
@@ -71,75 +85,14 @@ func main() {
7185
7286type patcher struct {}
7387
74- func (p *patcher ) Visit (node *ast .Node ) {
75- n , ok := (*node).(*ast.IndexNode )
76- if !ok {
77- return
78- }
79- unary , ok := n.Index .(*ast.UnaryNode )
88+ var contextType = reflect.TypeOf ((*context.Context )(nil )).Elem ()
89+
90+ func (patcher ) Visit (node *ast .Node ) {
91+ callNode , ok := (*node).(*ast.CallNode )
8092 if !ok {
8193 return
8294 }
83- if unary.Operator == " -" {
84- ast.Patch (&n.Index , &ast.BinaryNode {
85- Operator: " -" ,
86- Left: &ast.BuiltinNode {Name: " len" , Arguments: []ast.Node {n.Node }},
87- Right: unary.Node ,
88- })
89- }
90-
95+ callNode.Arguments = append ([]ast.Node {&ast.IdentifierNode {Value: " ctx" }}, callNode.Arguments ...)
9196}
92- ```
93-
94- Type information is also available. In the following example, any struct
95- implementing the ` fmt.Stringer ` interface is automatically converted to ` string ` type.
9697
97- ``` go
98- func main () {
99- code := ` Price == "$100"`
100-
101- program , err := expr.Compile (code, expr.Env (Env{}), expr.Patch (&stringerPatcher{}))
102- if err != nil {
103- panic (err)
104- }
105-
106- env := Env{100_00}
107-
108- output , err := expr.Run (program, env)
109- if err != nil {
110- panic (err)
111- }
112- fmt.Print (output)
113- }
114-
115- type Env struct {
116- Price Price
117- }
118-
119- type Price int
120-
121- func (p Price ) String () string {
122- return fmt.Sprintf (" $%v " , int (p)/100 )
123- }
124-
125- var stringer = reflect.TypeOf ((*fmt.Stringer )(nil )).Elem ()
126-
127- type stringerPatcher struct {}
128-
129- func (p *stringerPatcher ) Visit (node *ast .Node ) {
130- t := (*node).Type ()
131- if t == nil {
132- return
133- }
134- if t.Implements (stringer) {
135- ast.Patch (node, &ast.CallNode {
136- Callee: &ast.MemberNode {
137- Node: *node,
138- Field: " String" ,
139- Property: &ast.StringNode {Value: " String" },
140- },
141- })
142- }
143-
144- }
14598```
0 commit comments