]> Cypherpunks repositories - gostls13.git/commitdiff
add type in not-found error messages.
authorRuss Cox <rsc@golang.org>
Tue, 14 Apr 2009 08:12:20 +0000 (01:12 -0700)
committerRuss Cox <rsc@golang.org>
Tue, 14 Apr 2009 08:12:20 +0000 (01:12 -0700)
delay indirection so that values passed to
formatters preserve pointer-ness.

R=r
OCL=27410
CL=27414

src/lib/template/template.go
src/lib/template/template_test.go

index 231ab37b9c0b6c04b38d87d2dc7a0f452b53c410..6fa8a0d6334e579d48465acc6fd9ccbf82353567 100644 (file)
@@ -268,17 +268,22 @@ func (t *Template) analyze(item []byte, st *state) (tok int, w []string) {
 }
 
 // If the data for this template is a struct, find the named variable.
-func (st *state) findVar(s string) (int, int) {
-       typ, ok := st.data.Type().(reflect.StructType);
+// The special name "@" denotes the current data.
+func (st *state) findVar(s string) reflect.Value {
+       if s == "@" {
+               return st.data
+       }
+       data := reflect.Indirect(st.data);
+       typ, ok := data.Type().(reflect.StructType);
        if ok {
                for i := 0; i < typ.Len(); i++ {
                        name, ftyp, tag, offset := typ.Field(i);
                        if name == s {
-                               return i, ftyp.Kind()
+                               return data.(reflect.StructValue).Field(i)
                        }
                }
        }
-       return -1, -1
+       return nil
 }
 
 // Is there no data to look at?
@@ -301,18 +306,13 @@ func (t *Template) executeRepeated(w []string, st *state) {
        if w[1] != "section" {
                st.error(ErrSyntax, `: .repeated must have "section"`)
        }
+
        // Find driver array/struct for this section.  It must be in the current struct.
-       // The special name "@" leaves us at this level.
-       var field reflect.Value;
-       if w[2] == "@" {
-               field = st.data
-       } else {
-               i, kind := st.findVar(w[1]);
-               if i < 0 {
-                       st.error(ErrNoVar, ": ", w[2]);
-               }
-               field = reflect.Indirect(st.data.(reflect.StructValue).Field(i));
+       field := st.findVar(w[2]);
+       if field == nil {
+               st.error(ErrNoVar, ": .repeated ", w[2], " in ", reflect.Indirect(st.data).Type());
        }
+
        // Must be an array/slice
        if field != nil && field.Kind() != reflect.ArrayKind {
                st.error(ErrBadType, " in .repeated: ", w[2], " ", field.Type().String());
@@ -349,24 +349,17 @@ Loop:
                array := field.(reflect.ArrayValue);
                for i := 0; i < array.Len(); i++ {
                        tmp := childTemplate(t, t.buf[start:end]);
-                       tmp.execute(&state{st, st.errorchan, reflect.Indirect(array.Elem(i)), st.wr});
+                       tmp.execute(&state{st, st.errorchan, array.Elem(i), st.wr});
                }
        }
 }
 
 // Execute a ".section"
 func (t *Template) executeSection(w []string, st *state) {
-       // Find driver array/struct for this section.  It must be in the current struct.
-       // The special name "@" leaves us at this level.
-       var field reflect.Value;
-       if w[1] == "@" {
-               field = st.data
-       } else {
-               i, kind := st.findVar(w[1]);
-               if i < 0 {
-                       st.error(ErrNoVar, ": ", w[1]);
-               }
-               field = st.data.(reflect.StructValue).Field(i);
+       // Find driver data for this section.  It must be in the current struct.
+       field := st.findVar(w[1]);
+       if field == nil {
+               st.error(ErrNoVar, ": .section ", w[1], " in ", reflect.Indirect(st.data).Type());
        }
        // Scan section, remembering slice of text we must execute.
        orFound := false;
@@ -424,14 +417,14 @@ Loop:
 
 // Look up a variable, up through the parent if necessary.
 func (t *Template) varValue(name string, st *state) reflect.Value {
-       i, kind := st.findVar(name);
-       if i < 0 {
+       field := st.findVar(name);
+       if field == nil {
                if st.parent == nil {
                        st.error(ErrNoVar, ": ", name)
                }
                return t.varValue(name, st.parent);
        }
-       return st.data.(reflect.StructValue).Field(i);
+       return field;
 }
 
 // Evaluate a variable, looking up through the parent if necessary.
@@ -517,12 +510,8 @@ func Parse(s string, fmap FormatterMap) (*Template, *os.Error, int) {
 }
 
 func (t *Template) Execute(data interface{}, wr io.Write) *os.Error {
-       // Extract the driver struct.
-       val := reflect.Indirect(reflect.NewValue(data));
-       sval, ok1 := val.(reflect.StructValue);
-       if !ok1 {
-               return ErrNotStruct
-       }
+       // Extract the driver data.
+       val := reflect.NewValue(data);
        ch := make(chan *os.Error);
        go func() {
                t.execute(&state{nil, ch, val, wr});
index 9c4fd20cce2cb161bb34a7a916427e2ed63aef7f..090a0913653067b83b32322a2b19bca2bc96514e 100644 (file)
@@ -161,7 +161,7 @@ var tests = []*Test {
                "HEADER=78\n"
                "Header=77\n"
        },
-       
+
 }
 
 func TestAll(t *testing.T) {
@@ -192,13 +192,15 @@ func TestAll(t *testing.T) {
        }
 }
 
-func TestBadDriverType(t *testing.T) {
-       tmpl, err, line := Parse("hi", nil);
+func TestStringDriverType(t *testing.T) {
+       tmpl, err, line := Parse("template: {@}", nil);
        if err != nil {
                t.Error("unexpected parse error:", err)
        }
-       err = tmpl.Execute("hi", nil);
-       if err == nil {
-               t.Error("failed to detect string as driver type")
+       var b io.ByteBuffer;
+       err = tmpl.Execute("hello", &b);
+       s := string(b.Data());
+       if s != "template: hello" {
+               t.Errorf("failed passing string as data: expected %q got %q", "template: hello", s)
        }
 }