Skip to content

Commit 16e2929

Browse files
committed
Add expr.Patch func
1 parent 9a1c8f7 commit 16e2929

File tree

4 files changed

+68
-0
lines changed

4 files changed

+68
-0
lines changed

ast/node.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ import (
77
"github.com/antonmedv/expr/file"
88
)
99

10+
func Patch(node *Node, newNode Node) {
11+
newNode.SetType((*node).Type())
12+
newNode.SetLocation((*node).Location())
13+
*node = newNode
14+
}
15+
1016
// Node represents items of abstract syntax tree.
1117
type Node interface {
1218
Location() file.Location

expr.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package expr
22

33
import (
44
"fmt"
5+
"github.com/antonmedv/expr/ast"
56
"github.com/antonmedv/expr/file"
67
"reflect"
78

@@ -113,6 +114,13 @@ func Optimize(b bool) Option {
113114
}
114115
}
115116

117+
// TODO
118+
func Patch(visitor ast.Visitor) Option {
119+
return func(c *conf.Config) {
120+
c.Visitors = append(c.Visitors, visitor)
121+
}
122+
}
123+
116124
// Compile parses and compiles given input expression to bytecode program.
117125
func Compile(input string, ops ...Option) (*vm.Program, error) {
118126
config := &conf.Config{
@@ -142,6 +150,10 @@ func Compile(input string, ops ...Option) (*vm.Program, error) {
142150
// Patch operators before Optimize, as we may also mark it as ConstExpr.
143151
compiler.PatchOperators(&tree.Node, config)
144152

153+
for _, v := range config.Visitors {
154+
ast.Walk(&tree.Node, v)
155+
}
156+
145157
if config.Optimize {
146158
err = optimizer.Optimize(&tree.Node, config)
147159
if err != nil {

expr_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package expr_test
22

33
import (
44
"fmt"
5+
"github.com/antonmedv/expr/ast"
56
"strings"
67
"testing"
78
"time"
@@ -943,6 +944,53 @@ func TestConstExpr_error_no_env(t *testing.T) {
943944
require.Equal(t, "no environment for const expression: divide", err.Error())
944945
}
945946

947+
func TestPatch(t *testing.T) {
948+
env := map[string]interface{}{
949+
"x": map[string]interface{}{
950+
"foo": map[string]interface{}{
951+
"bar": "hello",
952+
},
953+
},
954+
}
955+
956+
program, err := expr.Compile(
957+
`x.foo.bar`,
958+
expr.Env(env),
959+
expr.Patch(&patcher{}),
960+
)
961+
require.NoError(t, err)
962+
963+
env = map[string]interface{}{
964+
"x": map[string]interface{}{
965+
"Foo": func() interface{} {
966+
return map[string]interface{}{
967+
"Bar": func() string {
968+
return "patched"
969+
},
970+
}
971+
},
972+
},
973+
}
974+
975+
out, err := expr.Run(program, env)
976+
require.NoError(t, err)
977+
require.Equal(t, "patched", out)
978+
}
979+
980+
type patcher struct {
981+
}
982+
983+
func (p *patcher) Enter(_ *ast.Node) {}
984+
func (p *patcher) Exit(node *ast.Node) {
985+
switch n := (*node).(type) {
986+
case *ast.PropertyNode:
987+
ast.Patch(node, &ast.MethodNode{
988+
Node: n.Node,
989+
Method: strings.Title(n.Property),
990+
})
991+
}
992+
}
993+
946994
//
947995
// Mock types
948996
//

internal/conf/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package conf
22

33
import (
44
"fmt"
5+
"github.com/antonmedv/expr/ast"
56
"github.com/antonmedv/expr/vm"
67
"reflect"
78
)
@@ -16,6 +17,7 @@ type Config struct {
1617
Strict bool
1718
DefaultType reflect.Type
1819
ConstExprFns map[string]reflect.Value
20+
Visitors []ast.Visitor
1921
err error
2022
}
2123

0 commit comments

Comments
 (0)