1
0
mirror of https://github.com/golang/go synced 2024-11-26 00:28:00 -07:00

parsing of type strings. still missing: func, struct, interface, chan

R=rsc
DELTA=366  (337 added, 7 deleted, 22 changed)
OCL=17321
CL=17324
This commit is contained in:
Rob Pike 2008-10-16 16:38:33 -07:00
parent 1163b1db6f
commit 32b84d5a94
3 changed files with 352 additions and 28 deletions

View File

@ -11,6 +11,7 @@ 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");
@ -25,9 +26,30 @@ func main() {
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");
s = reflect.ToString(t); print(s, "\n");
t = reflect.ParseTypeString("**int8");
s = reflect.ToString(t); print(s, "\n");
t = reflect.ParseTypeString("**P.integer");
s = reflect.ToString(t); print(s, "\n");
t = reflect.ParseTypeString("[32]int32");
s = reflect.ToString(t); print(s, "\n");
t = reflect.ParseTypeString("[]int8");
s = reflect.ToString(t); print(s, "\n");
t = reflect.ParseTypeString("map[string]int32");
s = reflect.ToString(t); print(s, "\n");
}

View File

@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Reflection library.
// Formatting of types for debugging.
package reflect
import (
@ -28,6 +31,8 @@ func FieldsToString(t Type) string {
func ToString(typ Type) string {
var str string;
switch(typ.Kind()) {
case MissingKind:
return "missing";
case Int8Kind:
return "int8";
case Int16Kind:

View File

@ -2,22 +2,20 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Reflection library.
// Types and parsing of type strings.
package reflect
export type Type interface
export type Value interface{} // TODO: define this
export func LookupTypeName(name string) Type
export func ExpandType(name string) Type
//export var GlobalTypeStrings = sys.typestrings;
// Cache of types keyed by type name
var types = new(map[string] *Type) // BUG TODO: should be Type not *Type
// Cache of type strings keyed by type name
var strings = new(map[string] string)
export const (
ArrayKind = iota;
MissingKind = iota;
ArrayKind;
ChanKind;
Float32Kind;
Float64Kind;
@ -37,6 +35,8 @@ export const (
Uint8Kind;
)
var MissingString = "missing" // syntactic name for undefined type names
type Type interface {
Kind() int;
}
@ -57,6 +57,7 @@ func NewBasicType(k int) Type {
// Basic types
export var (
Missing = NewBasicType(MissingKind);
Int8 = NewBasicType(Int8Kind);
Int16 = NewBasicType(Int16Kind);
Int32 = NewBasicType(Int32Kind);
@ -71,6 +72,8 @@ export var (
String = NewBasicType(StringKind);
)
// Stub types allow us to defer evaluating type names until needed.
// If the name is empty, the type must be non-nil.
type StubType struct {
name string;
typ Type;
@ -78,11 +81,23 @@ type StubType struct {
func (t *StubType) Get() Type {
if t.typ == nil {
t.typ = LookupTypeName(t.name)
t.typ = ExpandType(t.name)
}
return t.typ
}
func NewStubType(t Type) *StubType {
s := new(StubType);
s.typ = t;
return s;
}
func NewNamedStubType(n string) *StubType {
s := new(StubType);
s.name = n;
return s;
}
export type PtrType interface {
Sub() Type
}
@ -274,8 +289,8 @@ func NewFuncTypeStruct(receiver, in, out *StructTypeStruct) *FuncTypeStruct {
return t;
}
////////////////////////
//helpers for early bootstrap and debugging
export func LookupTypeName(name string) Type { return Int8 }
func Stub(n string, t Type) *StubType {
s := new(StubType);
s.name = n;
@ -283,6 +298,7 @@ func Stub(n string, t Type) *StubType {
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));
@ -290,3 +306,284 @@ 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
var typestrings *map[string] string
// Map of basic types to prebuilt StubTypes
var basicstubs *map[string] *StubType
var MissingStub *StubType;
func init() {
types = new(map[string] *Type);
typestrings = new(map[string] string);
basicstubs = new(map[string] *StubType);
// Basics go into types table
types["missing"] = &Missing;
types["int8"] = &Int8;
types["int16"] = &Int16;
types["int32"] = &Int32;
types["int64"] = &Int64;
types["uint8"] = &Uint8;
types["uint16"] = &Uint16;
types["uint32"] = &Uint32;
types["uint64"] = &Uint64;
types["float32"] = &Float32;
types["float64"] = &Float64;
types["float80"] = &Float80;
types["string"] = &String;
// Basics get prebuilt stubs
MissingStub = NewStubType(Missing);
basicstubs["missing"] = MissingStub;
basicstubs["int8"] = NewStubType(Int8);
basicstubs["int16"] = NewStubType(Int16);
basicstubs["int32"] = NewStubType(Int32);
basicstubs["int64"] = NewStubType(Int64);
basicstubs["uint8"] = NewStubType(Uint8);
basicstubs["uint16"] = NewStubType(Uint16);
basicstubs["uint32"] = NewStubType(Uint32);
basicstubs["uint64"] = NewStubType(Uint64);
basicstubs["float32"] = NewStubType(Float32);
basicstubs["float64"] = NewStubType(Float64);
basicstubs["float80"] = NewStubType(Float80);
basicstubs["string"] = NewStubType(String);
typestrings["P.integer"] = "int32";
return;
typestrings["P.S"] = "struct {t *P.T}";
typestrings["P.T"] = "struct {c *(? *chan P.S, *int)}";
}
/*
Grammar
stubtype = - represent as StubType when possible
type
identifier =
name
'?'
type =
basictypename - int8, string, etc.
typename
arraytype
structtype
interfacetype
chantype
maptype
pointertype
functiontype
typename =
name '.' name
fieldlist =
[ field { ',' field } ]
field =
identifier stubtype
arraytype =
'[' [ number ] ']' stubtype
structtype =
'struct' '{' fieldlist '}'
interfacetype =
'interface' '{' fieldlist '}'
chantype =
'<-' chan stubtype
chan '<-' stubtype
chan stubtype
maptype =
'map' '[' stubtype ']' stubtype
pointertype =
'*' stubtype
functiontype =
'(' fieldlist ')'
*/
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 "?".
for i := 0; i < len(s); i++ {
if c == s[i] {
return true
}
}
return false;
}
type Parser struct {
str string;
index int;
token string;
}
func (p *Parser) Next() {
token := "";
for ; p.index < len(p.str) && p.str[p.index] == ' '; p.index++ {
}
if p.index >= len(p.str) {
p.token = "";
return;
}
start := p.index;
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] == '-' {
p.index++;
p.token = "<-";
return;
}
p.token = "<"; // shouldn't happen but let the parser figure it out
return;
case isdigit(uint8(c)):
for p.index < len(p.str) && isdigit(p.str[p.index]) {
p.index++
}
p.token = p.str[start : p.index];
return;
}
for p.index < len(p.str) && !special(p.str[p.index]) {
p.index++
}
p.token = p.str[start : p.index];
}
func (p *Parser) Type() *StubType
func (p *Parser) Array() *StubType {
size := -1;
if p.token != "]" {
if len(p.token) == 0 || !isdigit(p.token[0]) {
return MissingStub
}
// write our own (trivial and simpleminded) atoi to avoid dependency
size = 0;
for i := 0; i < len(p.token); i++ {
size = size * 10 + int(p.token[i]) - '0'
}
p.Next();
}
if p.token != "]" {
return MissingStub
}
p.Next();
elemtype := p.Type();
return NewStubType(NewArrayTypeStruct(size, elemtype));
}
func (p *Parser) Map() *StubType {
if p.token != "[" {
return MissingStub
}
p.Next();
keytype := p.Type();
if p.token != "]" {
return MissingStub
}
p.Next();
elemtype := p.Type();
return NewStubType(NewMapTypeStruct(keytype, elemtype));
}
func (p *Parser) Simple() *StubType {
switch {
case p.token == "":
return nil;
case p.token == "*":
p.Next();
return NewStubType(NewPtrTypeStruct(p.Simple()));
case p.token == "[":
p.Next();
return p.Array();
case p.token == "map":
p.Next();
return p.Map();
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
if s, ok := basicstubs[p.token]; ok {
p.Next();
return s
}
// not a basic - must be of the form "P.T"
ndot := 0;
for i := 0; i < len(p.token); i++ {
if p.token[i] == '.' {
ndot++
}
}
if ndot != 1 {
print("reflect.Simple: illegal identifier ", p.token, "\n"); // TODO: remove
p.Next();
return MissingStub;
}
s := new(StubType);
s.name = p.token;
p.Next();
return s;
}
func (p *Parser) Type() *StubType {
return p.Simple();
}
export func ParseTypeString(str string) Type {
p := new(Parser);
p.str = str;
p.Next();
return p.Type().Get();
}
// Look up type string associated with name.
func TypeNameToTypeString(name string) string {
s, ok := typestrings[name];
if !ok {
s = MissingString;
typestrings[name] = s;
}
return s
}
// Type is known by name. Find (and create if necessary) its real type.
func ExpandType(name string) Type {
t, ok := types[name];
if ok {
return *t
}
types[name] = &Missing; // prevent recursion; will overwrite
t1 := ParseTypeString(TypeNameToTypeString(name));
p := new(Type);
*p = t1;
types[name] = p;
return t1;
}