From a45f947c34004bca8002b85a13cfe1902a4f89c8 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 4 Nov 2008 22:54:11 -0800 Subject: [PATCH] type strings through the reflection library. R=rsc DELTA=187 (107 added, 28 deleted, 52 changed) OCL=18510 CL=18510 --- src/lib/reflect/test.go | 55 +++++++++++++++++++++++ src/lib/reflect/type.go | 97 ++++++++++++++++++++++++---------------- src/lib/reflect/value.go | 61 +++++++++++++------------ 3 files changed, 146 insertions(+), 67 deletions(-) diff --git a/src/lib/reflect/test.go b/src/lib/reflect/test.go index d057251905c..54fd5ac4d68 100644 --- a/src/lib/reflect/test.go +++ b/src/lib/reflect/test.go @@ -88,9 +88,11 @@ export type empty interface {} export type T struct { a int; b float64; c string; d *int } func main() { +//NOTE: INTERFACES PARSE INCORRECTLY: parser's Fields() stops at '(' var s string; var t reflect.Type; + // Types typedump("missing", "$missing$"); typedump("int", "int"); typedump("int8", "int8"); @@ -126,6 +128,7 @@ func main() { typedump("struct {a int8 \"hi \\x00there\\t\\n\\\"\\\\\"; }", "struct{a int8 \"hi \\x00there\\t\\n\\\"\\\\\"}"); typedump("struct {f *(args ...)}", "struct{f *(args ...)}"); + // Values valuedump("int8", "8"); valuedump("int16", "16"); valuedump("int32", "32"); @@ -191,4 +194,56 @@ func main() { value.(reflect.PtrValue).Sub().(reflect.ArrayValue).Elem(4).(reflect.IntValue).Put(123); assert(reflect.ValueToString(value.(reflect.PtrValue).Sub()), "main.AA·test{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}"); } + + var pt reflect.PtrType; + var st reflect.StructType; + var mt reflect.MapType; + var at reflect.ArrayType; + var ct reflect.ChanType; + var name string; + var typ reflect.Type; + var tag string; + var offset uint64; + + // Type strings + t = reflect.ParseTypeString("", "int8"); + assert(t.String(), "int8"); + + t = reflect.ParseTypeString("", "*int8"); + assert(t.String(), "*int8"); + pt = t.(reflect.PtrType); + assert(pt.Sub().String(), "int8"); + + t = reflect.ParseTypeString("", "*struct {c *chan *int32; d float32}"); + assert(t.String(), "*struct {c *chan *int32; d float32}"); + pt = t.(reflect.PtrType); + assert(pt.Sub().String(), "struct {c *chan *int32; d float32}"); + st = pt.Sub().(reflect.StructType); + name, typ, tag, offset = st.Field(0); + assert(typ.String(), "*chan *int32"); + name, typ, tag, offset = st.Field(1); + assert(typ.String(), "float32"); + + //TODO! this is bad - can't put a method in an interface! + t = reflect.ParseTypeString("", "interface {a int}"); + assert(t.String(), "interface {a int}"); + + t = reflect.ParseTypeString("", "*(a int8, b int32)"); + assert(t.String(), "*(a int8, b int32)"); + + t = reflect.ParseTypeString("", "[32]int32"); + assert(t.String(), "[32]int32"); + at = t.(reflect.ArrayType); + assert(at.Elem().String(), "int32"); + + t = reflect.ParseTypeString("", "map[string]*int32"); + assert(t.String(), "map[string]*int32"); + mt = t.(reflect.MapType); + assert(mt.Key().String(), "string"); + assert(mt.Elem().String(), "*int32"); + + t = reflect.ParseTypeString("", "chan<-string"); + assert(t.String(), "chan<-string"); + ct = t.(reflect.ChanType); + assert(ct.Elem().String(), "string"); } diff --git a/src/lib/reflect/type.go b/src/lib/reflect/type.go index 8d5d2bde1ae..64405765b57 100644 --- a/src/lib/reflect/type.go +++ b/src/lib/reflect/type.go @@ -50,22 +50,33 @@ var DotDotDotString = "..." export type Type interface { Kind() int; Name() string; + String() string; + SetString(string); // TODO: remove when no longer needed Size() uint64; } // Fields and methods common to all types type Common struct { kind int; + str string; name string; size uint64; } +func (c *Common) Kind() int { + return c.kind +} + func (c *Common) Name() string { return c.name } -func (c *Common) Kind() int { - return c.kind +func (c *Common) String() string { + return c.str +} + +func (c *Common) SetString(s string) { + c.str = s } func (c *Common) Size() uint64 { @@ -79,7 +90,7 @@ type BasicType struct { } func NewBasicType(name string, kind int, size uint64) Type { - return &BasicType{ Common{kind, name, size} } + return &BasicType{ Common{kind, name, name, size} } } // Prebuilt basic types @@ -134,8 +145,8 @@ type PtrTypeStruct struct { sub *StubType; } -func NewPtrTypeStruct(name string, sub *StubType) *PtrTypeStruct { - return &PtrTypeStruct{ Common{PtrKind, name, ptrsize}, sub} +func NewPtrTypeStruct(name, typestring string, sub *StubType) *PtrTypeStruct { + return &PtrTypeStruct{ Common{PtrKind, typestring, name, ptrsize}, sub} } func (t *PtrTypeStruct) Sub() Type { @@ -157,8 +168,8 @@ type ArrayTypeStruct struct { len uint64; } -func NewArrayTypeStruct(name string, open bool, len uint64, elem *StubType) *ArrayTypeStruct { - return &ArrayTypeStruct{ Common{ArrayKind, name, 0}, elem, open, len} +func NewArrayTypeStruct(name, typestring string, open bool, len uint64, elem *StubType) *ArrayTypeStruct { + return &ArrayTypeStruct{ Common{ArrayKind, typestring, name, 0}, elem, open, len} } func (t *ArrayTypeStruct) Size() uint64 { @@ -194,8 +205,8 @@ type MapTypeStruct struct { elem *StubType; } -func NewMapTypeStruct(name string, key, elem *StubType) *MapTypeStruct { - return &MapTypeStruct{ Common{MapKind, name, 0}, key, elem} +func NewMapTypeStruct(name, typestring string, key, elem *StubType) *MapTypeStruct { + return &MapTypeStruct{ Common{MapKind, typestring, name, 0}, key, elem} } func (t *MapTypeStruct) Size() uint64 { @@ -230,8 +241,8 @@ type ChanTypeStruct struct { dir int; } -func NewChanTypeStruct(name string, dir int, elem *StubType) *ChanTypeStruct { - return &ChanTypeStruct{ Common{ChanKind, name, 0}, elem, dir} +func NewChanTypeStruct(name, typestring string, dir int, elem *StubType) *ChanTypeStruct { + return &ChanTypeStruct{ Common{ChanKind, typestring, name, 0}, elem, dir} } func (t *ChanTypeStruct) Size() uint64 { @@ -267,8 +278,8 @@ type StructTypeStruct struct { field *[]Field; } -func NewStructTypeStruct(name string, field *[]Field) *StructTypeStruct { - return &StructTypeStruct{ Common{StructKind, name, 0}, field} +func NewStructTypeStruct(name, typestring string, field *[]Field) *StructTypeStruct { + return &StructTypeStruct{ Common{StructKind, typestring, name, 0}, field} } // TODO: not portable; depends on 6g @@ -318,8 +329,8 @@ type InterfaceTypeStruct struct { field *[]Field; } -func NewInterfaceTypeStruct(name string, field *[]Field) *InterfaceTypeStruct { - return &InterfaceTypeStruct{ Common{InterfaceKind, name, interfacesize}, field } +func NewInterfaceTypeStruct(name, typestring string, field *[]Field) *InterfaceTypeStruct { + return &InterfaceTypeStruct{ Common{InterfaceKind, typestring, name, interfacesize}, field } } func (t *InterfaceTypeStruct) Field(i int) (name string, typ Type, tag string, offset uint64) { @@ -343,8 +354,8 @@ type FuncTypeStruct struct { out *StructTypeStruct; } -func NewFuncTypeStruct(name string, in, out *StructTypeStruct) *FuncTypeStruct { - return &FuncTypeStruct{ Common{FuncKind, name, 0}, in, out } +func NewFuncTypeStruct(name, typestring string, in, out *StructTypeStruct) *FuncTypeStruct { + return &FuncTypeStruct{ Common{FuncKind, typestring, name, 0}, in, out } } func (t *FuncTypeStruct) Size() uint64 { @@ -543,6 +554,7 @@ func unescape(s string, backslash bool) string { type Parser struct { str string; // string being parsed token string; // the token being parsed now + tokstart int; // starting position of token index int; // next character position in str } @@ -551,6 +563,7 @@ func (p *Parser) Next() { token := ""; for ; p.index < len(p.str) && p.str[p.index] == ' '; p.index++ { } + p.tokstart = p.index; if p.index >= len(p.str) { p.token = ""; return; @@ -608,7 +621,7 @@ func (p *Parser) Next() { func (p *Parser) Type(name string) *StubType -func (p *Parser) Array(name string) *StubType { +func (p *Parser) Array(name string, tokstart int) *StubType { size := uint64(0); open := true; if p.token != "]" { @@ -628,10 +641,10 @@ func (p *Parser) Array(name string) *StubType { } p.Next(); elemtype := p.Type(""); - return NewStubType(name, NewArrayTypeStruct(name, open, size, elemtype)); + return NewStubType(name, NewArrayTypeStruct(name, p.str[tokstart:p.index], open, size, elemtype)); } -func (p *Parser) Map(name string) *StubType { +func (p *Parser) Map(name string, tokstart int) *StubType { if p.token != "[" { return MissingStub } @@ -642,10 +655,10 @@ func (p *Parser) Map(name string) *StubType { } p.Next(); elemtype := p.Type(""); - return NewStubType(name, NewMapTypeStruct(name, keytype, elemtype)); + return NewStubType(name, NewMapTypeStruct(name, p.str[tokstart:p.index], keytype, elemtype)); } -func (p *Parser) Chan(name string, dir int) *StubType { +func (p *Parser) Chan(name string, tokstart, dir int) *StubType { if p.token == "<-" { if dir != BothDir { return MissingStub @@ -654,7 +667,7 @@ func (p *Parser) Chan(name string, dir int) *StubType { dir = SendDir; } elemtype := p.Type(""); - return NewStubType(name, NewChanTypeStruct(name, dir, elemtype)); + return NewStubType(name, NewChanTypeStruct(name, p.str[tokstart:p.index], dir, elemtype)); } // Parse array of fields for struct, interface, and func arguments @@ -685,59 +698,65 @@ func (p *Parser) Fields(sep string) *[]Field { return a[0:nf]; } -func (p *Parser) Struct(name string) *StubType { +func (p *Parser) Struct(name string, tokstart int) *StubType { f := p.Fields(";"); if p.token != "}" { return MissingStub; } + ts := p.str[tokstart:p.index]; p.Next(); - return NewStubType(name, NewStructTypeStruct(name, f)); + return NewStubType(name, NewStructTypeStruct(name, ts, f)); } -func (p *Parser) Interface(name string) *StubType { +func (p *Parser) Interface(name string, tokstart int) *StubType { f := p.Fields(";"); if p.token != "}" { return MissingStub; } + ts := p.str[tokstart:p.index]; p.Next(); - return NewStubType(name, NewInterfaceTypeStruct(name, f)); + return NewStubType(name, NewInterfaceTypeStruct(name, ts, f)); } -func (p *Parser) Func(name string) *StubType { +func (p *Parser) Func(name string, tokstart int) *StubType { // may be 1 or 2 parenthesized lists - f1 := NewStructTypeStruct("", p.Fields(",")); + f1 := NewStructTypeStruct("", "", p.Fields(",")); if p.token != ")" { return MissingStub; } + end := p.index; p.Next(); if p.token != "(" { // 1 list: the in parameters only - return NewStubType(name, NewFuncTypeStruct(name, f1, nil)); + return NewStubType(name, NewFuncTypeStruct(name, p.str[tokstart:end], f1, nil)); } p.Next(); - f2 := NewStructTypeStruct("", p.Fields(",")); + f2 := NewStructTypeStruct("", "", p.Fields(",")); if p.token != ")" { return MissingStub; } + end = p.index; p.Next(); // 2 lists: the in and out parameters are present - return NewStubType(name, NewFuncTypeStruct(name, f1, f2)); + return NewStubType(name, NewFuncTypeStruct(name, p.str[tokstart:end], f1, f2)); } func (p *Parser) Type(name string) *StubType { dir := BothDir; + tokstart := p.tokstart; switch { case p.token == "": return nil; case p.token == "*": p.Next(); - return NewStubType(name, NewPtrTypeStruct(name, p.Type(""))); + sub := p.Type(""); + return NewStubType(name, NewPtrTypeStruct(name, p.str[tokstart:p.index], sub)); case p.token == "[": p.Next(); - return p.Array(name); + return p.Array(name, tokstart); case p.token == "map": p.Next(); - return p.Map(name); + return p.Map(name, tokstart); case p.token == "<-": p.Next(); dir = RecvDir; @@ -747,24 +766,24 @@ func (p *Parser) Type(name string) *StubType { fallthrough; case p.token == "chan": p.Next(); - return p.Chan(name, dir); + return p.Chan(name, tokstart, dir); case p.token == "struct": p.Next(); if p.token != "{" { return MissingStub } p.Next(); - return p.Struct(name); + return p.Struct(name, tokstart); case p.token == "interface": p.Next(); if p.token != "{" { return MissingStub } p.Next(); - return p.Interface(name); + return p.Interface(name, tokstart); case p.token == "(": p.Next(); - return p.Func(name); + return p.Func(name, tokstart); case isdigit(p.token[0]): p.Next(); return MissingStub; diff --git a/src/lib/reflect/value.go b/src/lib/reflect/value.go index 5c9c727f8ed..527f1ff0050 100644 --- a/src/lib/reflect/value.go +++ b/src/lib/reflect/value.go @@ -11,34 +11,8 @@ import ( "reflect"; ) - type Addr uint64 // TODO: where are ptrint/intptr etc? -export type Value interface { - Kind() int; - Type() Type; -} - -// Common fields and functionality for all values - -type Common struct { - kind int; - typ Type; - addr Addr; -} - -func (c *Common) Kind() int { - return c.kind -} - -func (c *Common) Type() Type { - return c.typ -} - -func NewValueAddr(typ Type, addr Addr) Value - -type Creator *(typ Type, addr Addr) Value - // Conversion functions, implemented in assembler func AddrToPtrAddr(Addr) *Addr func AddrToPtrInt(Addr) *int @@ -60,6 +34,39 @@ func AddrToPtrFloat80(Addr) *float80 func AddrToPtrString(Addr) *string func AddrToPtrBool(Addr) *bool +export type Empty interface {} // TODO(r): Delete when no longer needed? + +export type Value interface { + Kind() int; + Type() Type; + Unreflect() Empty; +} + +// Common fields and functionality for all values + +type Common struct { + kind int; + typ Type; + addr Addr; +} + +func (c *Common) Kind() int { + return c.kind +} + +func (c *Common) Type() Type { + return c.typ +} + +func (c *Common) Unreflect() Empty { + return sys.unreflect(*AddrToPtrAddr(c.addr), c.typ.String()); +} + +func NewValueAddr(typ Type, addr Addr) Value + +type Creator *(typ Type, addr Addr) Value + + // -- Missing export type MissingValue interface { @@ -743,8 +750,6 @@ export func NewInitValue(typ Type) Value { return NewValueAddr(typ, PtrUint8ToAddr(&data[0])); } -export type Empty interface {} - export func NewValue(e Empty) Value { value, typestring := sys.reflect(e); typ := ParseTypeString("", typestring);