summaryrefslogtreecommitdiff
path: root/libgo/go/text/template/exec.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/text/template/exec.go')
-rw-r--r--libgo/go/text/template/exec.go47
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) {