2017-07-05 17:35:07 +02:00
|
|
|
package evaluator
|
2017-06-27 22:02:05 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Call applies a function to arguments, converting them as necessary.
|
|
|
|
// The conversion follows Liquid semantics, which are more aggressive than
|
|
|
|
// Go conversion. The function should return one or two values; the second value,
|
|
|
|
// if present, should be an error.
|
|
|
|
func Call(fn reflect.Value, args []interface{}) (interface{}, error) {
|
|
|
|
in := convertArguments(fn, args)
|
|
|
|
outs := fn.Call(in)
|
|
|
|
if len(outs) > 1 && outs[1].Interface() != nil {
|
|
|
|
switch e := outs[1].Interface().(type) {
|
|
|
|
case error:
|
|
|
|
return nil, e
|
|
|
|
default:
|
|
|
|
panic(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return outs[0].Interface(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert args to match the input types of function fn.
|
|
|
|
func convertArguments(fn reflect.Value, in []interface{}) []reflect.Value {
|
|
|
|
rt := fn.Type()
|
|
|
|
out := make([]reflect.Value, rt.NumIn())
|
|
|
|
for i, arg := range in {
|
|
|
|
if i < rt.NumIn() {
|
|
|
|
if arg == nil {
|
|
|
|
out[i] = reflect.Zero(rt.In(i))
|
|
|
|
} else {
|
2017-06-29 14:42:24 +02:00
|
|
|
out[i] = reflect.ValueOf(MustConvert(arg, rt.In(i)))
|
2017-06-27 22:02:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for i := len(in); i < rt.NumIn(); i++ {
|
|
|
|
out[i] = reflect.Zero(rt.In(i))
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|