@@ -2,6 +2,7 @@ package expr
2
2
3
3
import (
4
4
"fmt"
5
+ "github.com/antonmedv/expr/file"
5
6
"reflect"
6
7
7
8
"github.com/antonmedv/expr/checker"
@@ -44,17 +45,18 @@ func Eval(input string, env interface{}) (interface{}, error) {
44
45
// as well as all fields of embedded structs and struct itself.
45
46
// If map is passed, all items will be treated as variables.
46
47
// Methods defined on this type will be available as functions.
47
- func Env (i interface {}) Option {
48
+ func Env (env interface {}) Option {
48
49
return func (c * conf.Config ) {
49
- if _ , ok := i .(map [string ]interface {}); ok {
50
+ if _ , ok := env .(map [string ]interface {}); ok {
50
51
c .MapEnv = true
51
52
} else {
52
- if reflect .ValueOf (i ).Kind () == reflect .Map {
53
- c .DefaultType = reflect .TypeOf (i ).Elem ()
53
+ if reflect .ValueOf (env ).Kind () == reflect .Map {
54
+ c .DefaultType = reflect .TypeOf (env ).Elem ()
54
55
}
55
56
}
56
57
c .Strict = true
57
- c .Types = conf .CreateTypesTable (i )
58
+ c .Types = conf .CreateTypesTable (env )
59
+ c .Env = env
58
60
}
59
61
}
60
62
@@ -75,6 +77,14 @@ func Operator(operator string, fn ...string) Option {
75
77
}
76
78
}
77
79
80
+ // ConstExpr defines func expression as constant. If all argument to this function is constants,
81
+ // then it can be replaced by result of this func call on compile step.
82
+ func ConstExpr (fn string ) Option {
83
+ return func (c * conf.Config ) {
84
+ c .ConstExpr (fn )
85
+ }
86
+ }
87
+
78
88
// AsBool tells the compiler to expect boolean result.
79
89
func AsBool () Option {
80
90
return func (c * conf.Config ) {
@@ -106,8 +116,9 @@ func Optimize(b bool) Option {
106
116
// Compile parses and compiles given input expression to bytecode program.
107
117
func Compile (input string , ops ... Option ) (* vm.Program , error ) {
108
118
config := & conf.Config {
109
- Operators : make (map [string ][]string ),
110
- Optimize : true ,
119
+ Operators : make (map [string ][]string ),
120
+ ConstExprFns : make (map [string ]reflect.Value ),
121
+ Optimize : true ,
111
122
}
112
123
113
124
for _ , op := range ops {
@@ -127,10 +138,18 @@ func Compile(input string, ops ...Option) (*vm.Program, error) {
127
138
if err != nil {
128
139
return nil , err
129
140
}
130
- checker .PatchOperators (tree , config )
141
+
142
+ // Patch operators before Optimize, as we may also mark it as ConstExpr.
143
+ compiler .PatchOperators (& tree .Node , config )
131
144
132
145
if config .Optimize {
133
- optimizer .Optimize (& tree .Node )
146
+ err = optimizer .Optimize (& tree .Node , config )
147
+ if err != nil {
148
+ if fileError , ok := err .(* file.Error ); ok {
149
+ return nil , fmt .Errorf ("%v" , fileError .Format (tree .Source ))
150
+ }
151
+ return nil , err
152
+ }
134
153
}
135
154
136
155
program , err := compiler .Compile (tree , config )
0 commit comments