@@ -47,17 +47,31 @@ Specify a visitor to modify the AST with `expr.Patch` function.
47
47
program , err := expr.Compile (code, expr.Patch (&visitor{}))
48
48
```
49
49
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:
51
51
52
52
``` 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
+
53
64
func main () {
54
65
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 (),
56
70
}
57
71
58
- code := ` list[-1] ` // will output 3
72
+ code := ` foo(42) ` // will be converted to foo(ctx, 42)
59
73
60
- program , err := expr.Compile (code, expr.Env (env), expr.Patch (& patcher{}))
74
+ program , err := expr.Compile (code, expr.Env (env), expr.Patch (patcher{}))
61
75
if err != nil {
62
76
panic (err)
63
77
}
@@ -71,75 +85,14 @@ func main() {
71
85
72
86
type patcher struct {}
73
87
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 )
80
92
if !ok {
81
93
return
82
94
}
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 ...)
91
96
}
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.
96
97
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
- }
145
98
```
0 commit comments