]> Cypherpunks repositories - gostls13.git/commitdiff
reflection support for tag strings
authorRob Pike <r@golang.org>
Fri, 31 Oct 2008 00:29:53 +0000 (17:29 -0700)
committerRob Pike <r@golang.org>
Fri, 31 Oct 2008 00:29:53 +0000 (17:29 -0700)
R=rsc
DELTA=86  (77 added, 0 deleted, 9 changed)
OCL=18201
CL=18203

src/lib/reflect/test.go
src/lib/reflect/tostring.go
src/lib/reflect/type.go
src/lib/reflect/value.go

index 34acbda6e0cc4bc87890b1b088e64e23b9a13c37..0ed53a3ac4e65bc7ce869bc12a46e8f545b73ccc 100644 (file)
@@ -118,6 +118,8 @@ func main() {
        typedump("struct {a int8; b int8; c int8; b int32}", "struct{a int8; b int8; c int8; b int32}");
        typedump("struct {a int8; b int8; c int8; d int8; b int32}", "struct{a int8; b int8; c int8; d int8; b int32}");
        typedump("struct {a int8; b int8; c int8; d int8; e int8; b int32}", "struct{a int8; b int8; c int8; d int8; e int8; b int32}");
+       typedump("struct {a int8 \"hi there\"; }", "struct{a int8 \"hi there\"}");
+       typedump("struct {a int8 \"hi \\0there\\t\\n\\\"\\\\\"; }", "struct{a int8 \"hi \\0there\\t\\n\\\"\\\\\"}");
 
        valuedump("int8", "8");
        valuedump("int16", "16");
index 767886a759dc2283342779d721b975f26b84778d..c57e1995f5759b79b5e3a0e147722ecaa8a5b606 100644 (file)
@@ -15,16 +15,42 @@ import (
 export func TypeToString(typ Type, expand bool) string
 export func ValueToString(val Value) string
 
+func DoubleQuote(s string) string {
+       out := "\"";
+       for i := 0; i < len(s); i++ {
+               c := s[i];
+               switch c {
+               case '\n':
+                       out += `\n`;
+               case '\t':
+                       out += `\t`;
+               case '\x00':
+                       out += `\0`;
+               case '"':
+                       out += `\"`;
+               case '\\':
+                       out += `\\`;
+               default:
+                       out += string(c);
+               }
+       }
+       out += "\"";
+       return out;
+}
+
 type HasFields interface {
-       Field(i int)    (name string, typ Type, offset uint64);
+       Field(i int)    (name string, typ Type, tag string, offset uint64);
        Len()   int;
 }
 
 func TypeFieldsToString(t HasFields, sep string) string {
        var str string;
        for i := 0; i < t.Len(); i++ {
-               str1, typ, offset := t.Field(i);
+               str1, typ, tag, offset := t.Field(i);
                str1 +=  " " + TypeToString(typ, false);
+               if tag != "" {
+                       str1 += " " + DoubleQuote(tag);
+               }
                if i < t.Len() - 1 {
                        str1 += sep + " ";
                }
index 987c17138d387b10d52b1e3ee111609ae0b6d8b0..06fab4be55dec8db59d70d45637bd632e2401ca0 100644 (file)
@@ -245,13 +245,14 @@ func (t *ChanTypeStruct) Elem() Type {
 // -- Struct
 
 export type StructType interface {
-       Field(int)      (name string, typ Type, offset uint64);
+       Field(int)      (name string, typ Type, tag string, offset uint64);
        Len()   int;
 }
 
 type Field struct {
        name    string;
        typ     *StubType;
+       tag     string;
        size    uint64;
        offset  uint64;
 }
@@ -289,11 +290,11 @@ func (t *StructTypeStruct) Size() uint64 {
        return size;
 }
 
-func (t *StructTypeStruct) Field(i int) (name string, typ Type, offset uint64) {
+func (t *StructTypeStruct) Field(i int) (name string, typ Type, tag string, offset uint64) {
        if t.field[i].offset == 0 {
                t.Size();       // will compute offsets
        }
-       return t.field[i].name, t.field[i].typ.Get(), t.field[i].offset
+       return t.field[i].name, t.field[i].typ.Get(), t.field[i].tag, t.field[i].offset
 }
 
 func (t *StructTypeStruct) Len() int {
@@ -303,7 +304,7 @@ func (t *StructTypeStruct) Len() int {
 // -- Interface
 
 export type InterfaceType interface {
-       Field(int)      (name string, typ Type, offset uint64);
+       Field(int)      (name string, typ Type, tag string, offset uint64);
        Len()   int;
 }
 
@@ -316,8 +317,8 @@ func NewInterfaceTypeStruct(name string, field *[]Field) *InterfaceTypeStruct {
        return &InterfaceTypeStruct{ Common{InterfaceKind, name, interfacesize}, field }
 }
 
-func (t *InterfaceTypeStruct) Field(i int) (name string, typ Type, offset uint64) {
-       return t.field[i].name, t.field[i].typ.Get(), 0
+func (t *InterfaceTypeStruct) Field(i int) (name string, typ Type, tag string, offset uint64) {
+       return t.field[i].name, t.field[i].typ.Get(), "", 0
 }
 
 func (t *InterfaceTypeStruct) Len() int {
@@ -489,6 +490,33 @@ func special(c uint8) bool {
        return false;
 }
 
+// Process backslashes.  String known to be well-formed.
+// Initial double-quote is left in, as an indication this token is a string.
+func unescape(s string, backslash bool) string {
+       if !backslash {
+               return s
+       }
+       out := "\"";
+       for i := 1; i < len(s); i++ {
+               c := s[i];
+               if c == '\\' {
+                       i++;
+                       c = s[i];
+                       switch c {
+                       case 'n':
+                               c = '\n';
+                       case 't':
+                               c = '\t';
+                       case '0':       // it's not a legal go string but \0 means NUL
+                               c = '\x00';
+                       // default is correct already; \\ is \; \" is "
+                       }
+               }
+               out += string(c);
+       }
+       return out;
+}
+
 // Simple parser for type strings
 type Parser struct {
        str     string; // string being parsed
@@ -525,6 +553,23 @@ func (p *Parser) Next() {
                }
                p.token = p.str[start : p.index];
                return;
+       case c == '"':  // double-quoted string for struct field annotation
+               backslash := false;
+               for p.index < len(p.str) && p.str[p.index] != '"' {
+                       if p.str[p.index] == '\\' {
+                               if p.index+1 == len(p.str) {    // bad final backslash
+                                       break;
+                               }
+                               p.index++;      // skip (and accept) backslash
+                               backslash = true;
+                       }
+                       p.index++
+               }
+               p.token = unescape(p.str[start : p.index], backslash);
+               if p.index < len(p.str) {       // properly terminated string
+                       p.index++;      // skip the terminating double-quote
+               }
+               return;
        }
        for p.index < len(p.str) && p.str[p.index] != ' ' && !special(p.str[p.index]) {
                p.index++
@@ -598,6 +643,10 @@ func (p *Parser) Fields(sep string) *[]Field {
                a[nf].name = p.token;
                p.Next();
                a[nf].typ = p.Type("");
+               if p.token != "" && p.token[0] == '"' {
+                       a[nf].tag = p.token[1:len(p.token)];
+                       p.Next();
+               }
                nf++;
                if p.token != sep {
                        break;
index c39b1cb3e6a39b1bbe7d33c2d7331bce013d4378..9f3e4ab7df6771ba20d177e5a90c1326147e36ae 100644 (file)
@@ -609,7 +609,7 @@ func StructCreator(typ Type, addr Addr) Value {
        nfield := t.Len();
        v := &StructValueStruct{ CommonV{StructKind, typ, addr}, new([]Value, nfield) };
        for i := 0; i < nfield; i++ {
-               name, ftype, offset := t.Field(i);
+               name, ftype, str, offset := t.Field(i);
                v.field[i] = NewValueAddr(ftype, addr + offset);
        }
        v.typ = typ;