diff options
Diffstat (limited to 'libgo/go/text/template/funcs.go')
-rw-r--r-- | libgo/go/text/template/funcs.go | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/libgo/go/text/template/funcs.go b/libgo/go/text/template/funcs.go index d6e4bf1a216..525179cb499 100644 --- a/libgo/go/text/template/funcs.go +++ b/libgo/go/text/template/funcs.go @@ -24,6 +24,7 @@ type FuncMap map[string]interface{} var builtins = FuncMap{ "and": and, + "call": call, "html": HTMLEscaper, "index": index, "js": JSEscaper, @@ -151,6 +152,53 @@ func length(item interface{}) (int, error) { return 0, fmt.Errorf("len of type %s", v.Type()) } +// Function invocation + +// call returns the result of evaluating the the first argument as a function. +// The function must return 1 result, or 2 results, the second of which is an error. +func call(fn interface{}, args ...interface{}) (interface{}, error) { + v := reflect.ValueOf(fn) + typ := v.Type() + if typ.Kind() != reflect.Func { + return nil, fmt.Errorf("non-function of type %s", typ) + } + if !goodFunc(typ) { + return nil, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut()) + } + numIn := typ.NumIn() + var dddType reflect.Type + if typ.IsVariadic() { + if len(args) < numIn-1 { + return nil, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1) + } + dddType = typ.In(numIn - 1).Elem() + } else { + if len(args) != numIn { + return nil, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn) + } + } + argv := make([]reflect.Value, len(args)) + for i, arg := range args { + value := reflect.ValueOf(arg) + // Compute the expected type. Clumsy because of variadics. + var argType reflect.Type + if !typ.IsVariadic() || i < numIn-1 { + argType = typ.In(i) + } else { + argType = dddType + } + if !value.Type().AssignableTo(argType) { + return nil, fmt.Errorf("arg %d has type %s; should be %s", i, value.Type(), argType) + } + argv[i] = reflect.ValueOf(arg) + } + result := v.Call(argv) + if len(result) == 2 { + return result[0].Interface(), result[1].Interface().(error) + } + return result[0].Interface(), nil +} + // Boolean logic. func truth(a interface{}) bool { |