Commit 12a34358 authored by Rob Pike's avatar Rob Pike

reflection support for tag strings

R=rsc
DELTA=86  (77 added, 0 deleted, 9 changed)
OCL=18201
CL=18203
parent 57804f1d
......@@ -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");
......
......@@ -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 + " ";
}
......
......@@ -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;
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment