diff options
Diffstat (limited to 'libgo/go/text/template/exec.go')
-rw-r--r-- | libgo/go/text/template/exec.go | 47 |
1 files changed, 42 insertions, 5 deletions
diff --git a/libgo/go/text/template/exec.go b/libgo/go/text/template/exec.go index c7c6d504900..89d3e379b4b 100644 --- a/libgo/go/text/template/exec.go +++ b/libgo/go/text/template/exec.go @@ -173,20 +173,26 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) // execution stops, but partial results may already have been written to // the output writer. // A template may be executed safely in parallel. +// +// If data is a reflect.Value, the template applies to the concrete +// value that the reflect.Value holds, as in fmt.Print. func (t *Template) Execute(wr io.Writer, data interface{}) error { return t.execute(wr, data) } func (t *Template) execute(wr io.Writer, data interface{}) (err error) { defer errRecover(&err) - value := reflect.ValueOf(data) + value, ok := data.(reflect.Value) + if !ok { + value = reflect.ValueOf(data) + } state := &state{ tmpl: t, wr: wr, vars: []variable{{"$", value}}, } if t.Tree == nil || t.Root == nil { - state.errorf("%q is an incomplete or empty template%s", t.Name(), t.DefinedTemplates()) + state.errorf("%q is an incomplete or empty template", t.Name()) } state.walk(value, t.Root) return @@ -537,6 +543,9 @@ func (s *state) evalFunction(dot reflect.Value, node *parse.IdentifierNode, cmd // value of the pipeline, if any. func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, args []parse.Node, final, receiver reflect.Value) reflect.Value { if !receiver.IsValid() { + if s.tmpl.option.missingKey == mapError { // Treat invalid value as missing map key. + s.errorf("nil data; no entry for key %q", fieldName) + } return zero } typ := receiver.Type() @@ -598,8 +607,9 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, } var ( - errorType = reflect.TypeOf((*error)(nil)).Elem() - fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() + errorType = reflect.TypeOf((*error)(nil)).Elem() + fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() + reflectValueType = reflect.TypeOf((*reflect.Value)(nil)).Elem() ) // evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so @@ -663,7 +673,11 @@ func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, a s.at(node) s.errorf("error calling %s: %s", name, result[1].Interface().(error)) } - return result[0] + v := result[0] + if v.Type() == reflectValueType { + v = v.Interface().(reflect.Value) + } + return v } // canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero. @@ -671,6 +685,8 @@ func canBeNil(typ reflect.Type) bool { switch typ.Kind() { case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: return true + case reflect.Struct: + return typ == reflectValueType } return false } @@ -684,6 +700,9 @@ func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Valu } s.errorf("invalid value; expected %s", typ) } + if typ == reflectValueType && value.Type() != typ { + return reflect.ValueOf(value) + } if typ != nil && !value.Type().AssignableTo(typ) { if value.Kind() == reflect.Interface && !value.IsNil() { value = value.Elem() @@ -745,6 +764,10 @@ func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) refle if typ.NumMethod() == 0 { return s.evalEmptyInterface(dot, n) } + case reflect.Struct: + if typ == reflectValueType { + return reflect.ValueOf(s.evalEmptyInterface(dot, n)) + } case reflect.String: return s.evalString(typ, n) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: @@ -856,6 +879,20 @@ func indirect(v reflect.Value) (rv reflect.Value, isNil bool) { return v, false } +// indirectInterface returns the concrete value in an interface value, +// or else the zero reflect.Value. +// That is, if v represents the interface value x, the result is the same as reflect.ValueOf(x): +// the fact that x was an interface value is forgotten. +func indirectInterface(v reflect.Value) reflect.Value { + if v.Kind() != reflect.Interface { + return v + } + if v.IsNil() { + return reflect.Value{} + } + return v.Elem() +} + // printValue writes the textual representation of the value to the output of // the template. func (s *state) printValue(n parse.Node, v reflect.Value) { |