]> Cypherpunks repositories - gostls13.git/commitdiff
type string parser; now handles all types
authorRob Pike <r@golang.org>
Fri, 17 Oct 2008 01:09:38 +0000 (18:09 -0700)
committerRob Pike <r@golang.org>
Fri, 17 Oct 2008 01:09:38 +0000 (18:09 -0700)
R=rsc
DELTA=253  (153 added, 81 deleted, 19 changed)
OCL=17331
CL=17331

usr/r/reflect/main.go
usr/r/reflect/tostring.go
usr/r/reflect/type.go

index 9e8897ad30b6f8db2e0732fcf8928dd0a13ed015..f46b6d81eacfb7edf4223b1daa22efdab2362db9 100644 (file)
@@ -10,29 +10,6 @@ import (
 
 func main() {
        var s string;
-
-       if false {
-               s = reflect.ToString(reflect.Int8); print(s, "\n");
-               s = reflect.ToString(reflect.Int16); print(s, "\n");
-               s = reflect.ToString(reflect.Int32); print(s, "\n");
-               s = reflect.ToString(reflect.Int64); print(s, "\n");
-               s = reflect.ToString(reflect.Uint8); print(s, "\n");
-               s = reflect.ToString(reflect.Uint16); print(s, "\n");
-               s = reflect.ToString(reflect.Uint32); print(s, "\n");
-               s = reflect.ToString(reflect.Uint64); print(s, "\n");
-               s = reflect.ToString(reflect.Float32); print(s, "\n");
-               s = reflect.ToString(reflect.Float64); print(s, "\n");
-               s = reflect.ToString(reflect.Float80); print(s, "\n");
-               s = reflect.ToString(reflect.String); print(s, "\n");
-
-               s = reflect.ToString(reflect.PtrInt8); print(s, "\n");
-               s = reflect.ToString(reflect.PtrPtrInt8); print(s, "\n");
-               s = reflect.ToString(reflect.ArrayFloat32); print(s, "\n");
-               s = reflect.ToString(reflect.MapStringInt16); print(s, "\n");
-               s = reflect.ToString(reflect.ChanArray); print(s, "\n");
-               s = reflect.ToString(reflect.Structure); print(s, "\n");
-               s = reflect.ToString(reflect.Function); print(s, "\n");
-       }
        var t reflect.Type;
 
        t = reflect.ParseTypeString("int8");
@@ -52,4 +29,16 @@ func main() {
 
        t = reflect.ParseTypeString("map[string]int32");
        s = reflect.ToString(t); print(s, "\n");
+
+       t = reflect.ParseTypeString("*chan<-string");
+       s = reflect.ToString(t); print(s, "\n");
+
+       t = reflect.ParseTypeString("struct {c *chan *int32; d float32}");
+       s = reflect.ToString(t); print(s, "\n");
+
+       t = reflect.ParseTypeString("*(a int8, b int32)");
+       s = reflect.ToString(t); print(s, "\n");
+
+       t = reflect.ParseTypeString("struct {c *(? *chan *int32, ? *int8)}");
+       s = reflect.ToString(t); print(s, "\n");
 }
index 60fb9f6f8153233616006da06bd3d721fa74958a..09b6945a2a31b31c07852abfd0dbfd49caa60bde 100644 (file)
@@ -14,14 +14,14 @@ import (
 
 export func ToString(typ Type) string
 
-func FieldsToString(t Type) string {
+func FieldsToString(t Type, sep string) string {
        s := t.(StructType);
        var str string;
        for i := 0; i < s.Len(); i++ {
                str1, t := s.Field(i);
                str1 +=  " " + ToString(t);
                if i < s.Len() - 1 {
-                       str1 += "; ";
+                       str1 += sep + " ";
                }
                str += str1;
        }
@@ -86,16 +86,15 @@ func ToString(typ Type) string {
                }
                return str + ToString(c.Elem());
        case StructKind:
-               return "struct{" + FieldsToString(typ) + "}";
+               return "struct{" + FieldsToString(typ, ";") + "}";
+       case InterfaceKind:
+               return "interface{" + FieldsToString(typ, ";") + "}";
        case FuncKind:
                f := typ.(FuncType);
                str = "func";
-               if f.Receiver() != nil {
-                       str += "(" + FieldsToString(f.Receiver()) + ")";
-               }
-               str += "(" + FieldsToString(f.In()) + ")";
+               str += "(" + FieldsToString(f.In(), ",") + ")";
                if f.Out() != nil {
-                       str += "(" + FieldsToString(f.Out()) + ")";
+                       str += "(" + FieldsToString(f.Out(), ",") + ")";
                }
                return str;
        default:
index abec5c11ed71d59ab6cc62388cca928c6048e730..4eda9f407174ddb5240916e031a10c9c6fd334f7 100644 (file)
@@ -25,6 +25,7 @@ export const (
        Int32Kind;
        Int64Kind;
        Int8Kind;
+       InterfaceKind;
        MapKind;
        PtrKind;
        StringKind;
@@ -241,26 +242,45 @@ func (t *StructTypeStruct) Len() int {
        return len(t.field)
 }
 
-func Struct(field *[]Field) *StructTypeStruct {
+func NewStructTypeStruct(field *[]Field) *StructTypeStruct {
        t := new(StructTypeStruct);
        t.field = field;
        return t;
 }
 
-func NewStructTypeStruct(field *[]Field) *StructTypeStruct {
-       t := new(StructTypeStruct);
+export type InterfaceType interface {
+       Field(int)      (name string, typ Type);
+       Len()   int;
+}
+
+type InterfaceTypeStruct struct {
+       field   *[]Field;
+}
+
+func (t *InterfaceTypeStruct) Field(i int) (name string, typ Type) {
+       return t.field[i].name, t.field[i].typ.Get()
+}
+
+func (t *InterfaceTypeStruct) Len() int {
+       return len(t.field)
+}
+
+func NewInterfaceTypeStruct(field *[]Field) *InterfaceTypeStruct {
+       t := new(InterfaceTypeStruct);
        t.field = field;
        return t;
 }
 
+func (t *InterfaceTypeStruct) Kind() int {
+       return InterfaceKind
+}
+
 export type FuncType interface {
-       Receiver()      StructType;
        In()    StructType;
        Out()   StructType;
 }
 
 type FuncTypeStruct struct {
-       receiver        *StructTypeStruct;
        in      *StructTypeStruct;
        out     *StructTypeStruct;
 }
@@ -269,45 +289,24 @@ func (t *FuncTypeStruct) Kind() int {
        return FuncKind
 }
 
-func (t *FuncTypeStruct) Receiver() StructType {
-       return t.receiver
-}
-
 func (t *FuncTypeStruct) In() StructType {
        return t.in
 }
 
 func (t *FuncTypeStruct) Out() StructType {
+       if t.out == nil {       // nil.(StructType) != nil so make sure caller sees real nil
+               return nil
+       }
        return t.out
 }
 
-func NewFuncTypeStruct(receiver, in, out *StructTypeStruct) *FuncTypeStruct {
+func NewFuncTypeStruct(in, out *StructTypeStruct) *FuncTypeStruct {
        t := new(FuncTypeStruct);
-       t.receiver = receiver;
        t.in = in;
        t.out = out;
        return t;
 }
 
-////////////////////////
-//helpers for early bootstrap and debugging
-func Stub(n string, t Type) *StubType {
-       s := new(StubType);
-       s.name = n;
-       s.typ = t;
-       return s;
-}
-export var PtrInt8 Type = NewPtrTypeStruct(Stub("i", Int8));
-export var PtrPtrInt8 Type = NewPtrTypeStruct(Stub("i", PtrInt8));
-export var ArrayFloat32 Type = NewArrayTypeStruct(100, Stub("f", Float32));
-export var MapStringInt16 Type = NewMapTypeStruct(Stub("s", String), Stub("i", Int16));
-export var ChanArray Type = NewChanTypeStruct(RecvDir, Stub("a", ArrayFloat32));
-var F1 = Field{"i", Stub("i", Int64)};
-var Fields = []Field{F1};
-export var Structure = NewStructTypeStruct(&Fields);
-export var Function Type = NewFuncTypeStruct(Structure, Structure, Structure);
-////////////////////////
-
 // Cache of expanded types keyed by type name.
 var types *map[string] *Type   // BUG TODO: should be Type not *Type
 // List of typename, typestring pairs
@@ -380,7 +379,7 @@ func init() {
        typename =
                name '.' name
        fieldlist =
-               [ field { ',' field } ]
+               [ field { [ ',' | ';' ] field } ]
        field =
                identifier stubtype
        arraytype =
@@ -402,12 +401,13 @@ func init() {
 
 */
 
+// Helper functions for token scanning
 func isdigit(c uint8) bool {
        return '0' <= c && c <= '9'
 }
 
 func special(c uint8) bool {
-       s := "*[](){}<";        // Note: '.' is not in this list.  "P.T" is an identifer, as is "?".
+       s := "*[](){}<;,";      // Note: '.' is not in this list.  "P.T" is an identifer, as is "?".
        for i := 0; i < len(s); i++ {
                if c == s[i] {
                        return true
@@ -416,12 +416,14 @@ func special(c uint8) bool {
        return false;
 }
 
+// Simple parser for type strings
 type Parser struct {
-       str     string;
-       index   int;
-       token   string;
+       str     string; // string being parsed
+       token   string; // the token being parsed now
+       index   int;    // next character position in str
 }
 
+// Load next token into p.token
 func (p *Parser) Next() {
        token := "";
        for ; p.index < len(p.str) && p.str[p.index] == ' '; p.index++ {
@@ -434,28 +436,15 @@ func (p *Parser) Next() {
        c, w := sys.stringtorune(p.str, p.index);
        p.index += w;
        switch {
-       case c == '*':
-               p.token = "*";
-               return;
-       case c == '[':
-               p.token = "[";
-               return;
-       case c == ']':
-               p.token = "]";
-               return;
-       case c == '(':
-               p.token = "(";
-               return;
-       case c == ')':
-               p.token = ")";
-               return;
        case c == '<':
-               if p.index < len(p.str) && p.str[p.index+1] == '-' {
+               if p.index < len(p.str) && p.str[p.index] == '-' {
                        p.index++;
                        p.token = "<-";
                        return;
                }
-               p.token = "<";  // shouldn't happen but let the parser figure it out
+               fallthrough;    // shouldn't happen but let the parser figure it out
+       case special(uint8(c)):
+               p.token = string(c);
                return;
        case isdigit(uint8(c)):
                for p.index < len(p.str) && isdigit(p.str[p.index]) {
@@ -464,7 +453,7 @@ func (p *Parser) Next() {
                p.token = p.str[start : p.index];
                return;
        }
-       for p.index < len(p.str) && !special(p.str[p.index]) {
+       for p.index < len(p.str) && p.str[p.index] != ' ' && !special(p.str[p.index]) {
                p.index++
        }
        p.token = p.str[start : p.index];
@@ -507,27 +496,127 @@ func (p *Parser) Map() *StubType {
        return NewStubType(NewMapTypeStruct(keytype, elemtype));
 }
 
-func (p *Parser) Simple() *StubType {
+func (p *Parser) Chan(dir int) *StubType {
+       if p.token == "<-" {
+               if dir != BothDir {
+                       return MissingStub
+               }
+               p.Next();
+               dir = SendDir;
+       }
+       elemtype := p.Type();
+       return NewStubType(NewChanTypeStruct(dir, elemtype));
+}
+
+// Parse array of fields for struct, interface, and func arguments
+func (p *Parser) Fields(sep string) *[]Field {
+       a := new([]Field, 10);
+       nf := 0;
+       for p.token != "" && !special(p.token[0]) {
+               if nf == len(a) {
+                       a1 := new([]Field, 2*nf);
+                       for i := 0; i < nf; i++ {
+                               a1[i] = a[i];
+                       }
+                       a = a1;
+               }
+               a[nf].name = p.token;
+               p.Next();
+               a[nf].typ = p.Type();
+               nf++;
+               if p.token != sep {
+                       break;
+               }
+               p.Next();       // skip separator
+       }
+       return a[0:nf];
+}
+
+func (p *Parser) Struct() *StubType {
+       f := p.Fields(";");
+       if p.token != "}" {
+               return MissingStub;
+       }
+       p.Next();
+       return NewStubType(NewStructTypeStruct(f));
+}
+
+func (p *Parser) Interface() *StubType {
+       f := p.Fields(";");
+       if p.token != "}" {
+               return MissingStub;
+       }
+       p.Next();
+       return NewStubType(NewInterfaceTypeStruct(f));
+}
+
+func (p *Parser) Func() *StubType {
+       // may be 1 or 2 parenthesized lists
+       f1 := NewStructTypeStruct(p.Fields(","));
+       if p.token != ")" {
+               return MissingStub;
+       }
+       p.Next();
+       if p.token != "(" {
+               // 1 list: the in parameters only
+               return NewStubType(NewFuncTypeStruct(f1, nil));
+       }
+       p.Next();
+       f2 := NewStructTypeStruct(p.Fields(","));
+       if p.token != ")" {
+               return MissingStub;
+       }
+       p.Next();
+       // 2 lists: the in and out parameters are present
+       return NewStubType(NewFuncTypeStruct(f1, f2));
+}
+
+func (p *Parser) Type() *StubType {
+       dir := BothDir;
        switch {
        case p.token == "":
                return nil;
        case p.token == "*":
                p.Next();
-               return NewStubType(NewPtrTypeStruct(p.Simple()));
+               return NewStubType(NewPtrTypeStruct(p.Type()));
        case p.token == "[":
                p.Next();
                return p.Array();
        case p.token == "map":
                p.Next();
                return p.Map();
+       case p.token == "<-":
+               p.Next();
+               dir = RecvDir;
+               if p.token != "chan" {
+                       return MissingStub;
+               }
+               fallthrough;
+       case p.token == "chan":
+               p.Next();
+               return p.Chan(dir);
+       case p.token == "struct":
+               p.Next();
+               if p.token != "{" {
+                       return MissingStub
+               }
+               p.Next();
+               return p.Struct();
+       case p.token == "interface":
+               p.Next();
+               if p.token != "{" {
+                       return MissingStub
+               }
+               p.Next();
+               return p.Interface();
+       case p.token == "(":
+               p.Next();
+               return p.Func();
        case isdigit(p.token[0]):
                p.Next();
-               print("reflect.Simple: number encountered\n");  // TODO: remove
                return MissingStub;
        case special(p.token[0]):
-               // TODO: get chans right
                p.Next();
-               print("reflect.Simple: special character encountered\n");       // TODO: remove
                return MissingStub;
        }
        // must be an identifier. is it basic? if so, we have a stub
@@ -543,7 +632,6 @@ func (p *Parser) Simple() *StubType {
                }
        }
        if ndot != 1 {
-               print("reflect.Simple: illegal identifier ", p.token, "\n");    // TODO: remove
                p.Next();
                return MissingStub;
        }
@@ -553,10 +641,6 @@ func (p *Parser) Simple() *StubType {
        return s;
 }
 
-func (p *Parser) Type() *StubType {
-       return p.Simple();
-}
-
 export func ParseTypeString(str string) Type {
        p := new(Parser);
        p.str = str;