@@ -2,6 +2,7 @@ package expr
22
33import (
44 "fmt"
5+ "github.com/antonmedv/expr/file"
56 "reflect"
67
78 "github.com/antonmedv/expr/checker"
@@ -44,17 +45,18 @@ func Eval(input string, env interface{}) (interface{}, error) {
4445// as well as all fields of embedded structs and struct itself.
4546// If map is passed, all items will be treated as variables.
4647// Methods defined on this type will be available as functions.
47- func Env (i interface {}) Option {
48+ func Env (env interface {}) Option {
4849 return func (c * conf.Config ) {
49- if _ , ok := i .(map [string ]interface {}); ok {
50+ if _ , ok := env .(map [string ]interface {}); ok {
5051 c .MapEnv = true
5152 } 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 ()
5455 }
5556 }
5657 c .Strict = true
57- c .Types = conf .CreateTypesTable (i )
58+ c .Types = conf .CreateTypesTable (env )
59+ c .Env = env
5860 }
5961}
6062
@@ -75,6 +77,14 @@ func Operator(operator string, fn ...string) Option {
7577 }
7678}
7779
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+
7888// AsBool tells the compiler to expect boolean result.
7989func AsBool () Option {
8090 return func (c * conf.Config ) {
@@ -106,8 +116,9 @@ func Optimize(b bool) Option {
106116// Compile parses and compiles given input expression to bytecode program.
107117func Compile (input string , ops ... Option ) (* vm.Program , error ) {
108118 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 ,
111122 }
112123
113124 for _ , op := range ops {
@@ -127,10 +138,18 @@ func Compile(input string, ops ...Option) (*vm.Program, error) {
127138 if err != nil {
128139 return nil , err
129140 }
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 )
131144
132145 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+ }
134153 }
135154
136155 program , err := compiler .Compile (tree , config )
0 commit comments