Skip to content

Commit e6958d3

Browse files
authored
Update Visitor-and-Patch.md
1 parent 3edd80d commit e6958d3

File tree

1 file changed

+54
-0
lines changed

1 file changed

+54
-0
lines changed

docs/Visitor-and-Patch.md

+54
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,60 @@ program, err := expr.Compile(code, expr.Patch(&visitor{}))
4848
```
4949

5050
This can be useful for some edge cases, there you want to extend functionality of **Expr** language.
51+
In next example we are going to replace expression `list[-1]` with `list[len(list)-1]`.
52+
53+
```go
54+
package main
55+
56+
import (
57+
"fmt"
58+
59+
"github.com/antonmedv/expr"
60+
"github.com/antonmedv/expr/ast"
61+
)
62+
63+
func main() {
64+
env := map[string]interface{}{
65+
"list": []int{1, 2, 3},
66+
}
67+
68+
code := `list[-1]` // will output 3
69+
70+
program, err := expr.Compile(code, expr.Env(env), expr.Patch(&patcher{}))
71+
if err != nil {
72+
panic(err)
73+
}
74+
75+
output, err := expr.Run(program, env)
76+
if err != nil {
77+
panic(err)
78+
}
79+
fmt.Print(output)
80+
}
81+
82+
type patcher struct{}
83+
84+
func (p *patcher) Enter(_ *ast.Node) {}
85+
func (p *patcher) Exit(node *ast.Node) {
86+
n, ok := (*node).(*ast.IndexNode)
87+
if !ok {
88+
return
89+
}
90+
unary, ok := n.Index.(*ast.UnaryNode)
91+
if !ok {
92+
return
93+
}
94+
if unary.Operator == "-" {
95+
ast.Patch(&n.Index, &ast.BinaryNode{
96+
Operator: "-",
97+
Left: &ast.BuiltinNode{Name: "len", Arguments: []ast.Node{n.Node}},
98+
Right: unary.Node,
99+
})
100+
}
101+
102+
}
103+
```
104+
51105
Type information is also available. Here is an example, there all `fmt.Stringer` interface automatically
52106
converted to `string` type.
53107

0 commit comments

Comments
 (0)