1
0
mirror of https://github.com/danog/liquid.git synced 2024-12-02 16:57:50 +01:00
liquid/evaluator/call.go

43 lines
1.1 KiB
Go
Raw Normal View History

2017-07-05 17:35:07 +02:00
package evaluator
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 {
out[i] = reflect.ValueOf(MustConvert(arg, rt.In(i)))
}
}
}
for i := len(in); i < rt.NumIn(); i++ {
out[i] = reflect.Zero(rt.In(i))
}
return out
}