aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/exp/template/exec.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/exp/template/exec.go')
-rw-r--r--src/pkg/exp/template/exec.go26
1 files changed, 24 insertions, 2 deletions
diff --git a/src/pkg/exp/template/exec.go b/src/pkg/exp/template/exec.go
index 3ea54eafaa..befb2ded9a 100644
--- a/src/pkg/exp/template/exec.go
+++ b/src/pkg/exp/template/exec.go
@@ -10,6 +10,8 @@ import (
"os"
"reflect"
"strings"
+ "unicode"
+ "utf8"
)
// state represents the state of an execution. It's not part of the
@@ -69,16 +71,20 @@ func (s *state) walk(data reflect.Value, n node) {
s.walk(data, node)
}
case *ifNode:
+ s.line = n.line
s.walkIfOrWith(nodeIf, data, n.pipeline, n.list, n.elseList)
case *rangeNode:
+ s.line = n.line
s.walkRange(data, n)
case *textNode:
if _, err := s.wr.Write(n.text); err != nil {
s.error(err)
}
case *templateNode:
+ s.line = n.line
s.walkTemplate(data, n)
case *withNode:
+ s.line = n.line
s.walkIfOrWith(nodeWith, data, n.pipeline, n.list, n.elseList)
default:
s.errorf("unknown node: %s", n)
@@ -230,6 +236,12 @@ func (s *state) evalFieldNode(data reflect.Value, field *fieldNode, args []node,
return s.evalFieldOrCall(data, field.ident[n-1], args, final)
}
+// Is this an exported - upper case - name?
+func isExported(name string) bool {
+ rune, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(rune)
+}
+
func (s *state) evalField(data reflect.Value, fieldName string) reflect.Value {
for data.Kind() == reflect.Ptr {
data = reflect.Indirect(data)
@@ -240,7 +252,7 @@ func (s *state) evalField(data reflect.Value, fieldName string) reflect.Value {
field := data.FieldByName(fieldName)
// TODO: look higher up the tree if we can't find it here. Also unexported fields
// might succeed higher up, as map keys.
- if field.IsValid() && field.Type().PkgPath() == "" { // valid and exported
+ if field.IsValid() && isExported(fieldName) { // valid and exported
return field
}
s.errorf("%s has no field %s", data.Type(), fieldName)
@@ -260,7 +272,7 @@ func (s *state) evalFieldOrCall(data reflect.Value, fieldName string, args []nod
ptr, data = data, reflect.Indirect(data)
}
// Is it a method? We use the pointer because it has value methods too.
- if method, ok := ptr.Type().MethodByName(fieldName); ok {
+ if method, ok := methodByName(ptr.Type(), fieldName); ok {
return s.evalCall(ptr, method.Func, fieldName, true, args, final)
}
if len(args) > 1 || final.IsValid() {
@@ -275,6 +287,16 @@ func (s *state) evalFieldOrCall(data reflect.Value, fieldName string, args []nod
panic("not reached")
}
+// TODO: delete when reflect's own MethodByName is released.
+func methodByName(typ reflect.Type, name string) (reflect.Method, bool) {
+ for i := 0; i < typ.NumMethod(); i++ {
+ if typ.Method(i).Name == name {
+ return typ.Method(i), true
+ }
+ }
+ return reflect.Method{}, false
+}
+
var (
osErrorType = reflect.TypeOf(new(os.Error)).Elem()
)