Files
expr/conf/config.go
T

79 lines
1.8 KiB
Go

package conf
import (
"fmt"
"reflect"
"github.com/antonmedv/expr/ast"
"github.com/antonmedv/expr/vm/runtime"
)
type Config struct {
Env interface{}
Types TypesTable
MapEnv bool
DefaultType reflect.Type
Operators OperatorsTable
Expect reflect.Kind
Optimize bool
Strict bool
ConstFns map[string]reflect.Value
Visitors []ast.Visitor
}
func New(env interface{}) *Config {
c := &Config{
Operators: make(map[string][]string),
ConstFns: make(map[string]reflect.Value),
Optimize: true,
}
c.WithEnv(env)
return c
}
func (c *Config) WithEnv(env interface{}) {
var mapEnv bool
var mapValueType reflect.Type
if _, ok := env.(map[string]interface{}); ok {
mapEnv = true
} else {
if reflect.ValueOf(env).Kind() == reflect.Map {
mapValueType = reflect.TypeOf(env).Elem()
}
}
c.Env = env
c.Types = CreateTypesTable(env)
c.MapEnv = mapEnv
c.DefaultType = mapValueType
c.Strict = true
}
func (c *Config) Operator(operator string, fns ...string) {
c.Operators[operator] = append(c.Operators[operator], fns...)
for _, fn := range fns {
fnType, ok := c.Types[fn]
if !ok || fnType.Type.Kind() != reflect.Func {
panic(fmt.Errorf("function %s for %s operator does not exist in the environment", fn, operator))
}
requiredNumIn := 2
if fnType.Method {
requiredNumIn = 3 // As first argument of method is receiver.
}
if fnType.Type.NumIn() != requiredNumIn || fnType.Type.NumOut() != 1 {
panic(fmt.Errorf("function %s for %s operator does not have a correct signature", fn, operator))
}
}
}
func (c *Config) ConstExpr(name string) {
if c.Env == nil {
panic("no environment is specified for ConstExpr()")
}
fn := reflect.ValueOf(runtime.Fetch(c.Env, name))
if fn.Kind() != reflect.Func {
panic(fmt.Errorf("const expression %q must be a function", name))
}
c.ConstFns[name] = fn
}