Commit 3bc6fd63 authored by Rob Pike's avatar Rob Pike

document reflect.

R=rsc
DELTA=201  (90 added, 0 deleted, 111 changed)
OCL=25904
CL=25966
parent 5bd5242b
......@@ -43,7 +43,7 @@ func assert(s, t string) {
func typedump(s, t string) {
typ := reflect.ParseTypeString("", s);
assert(reflect.TypeToString(typ, true), t);
assert(reflect.typeToString(typ, true), t);
}
func valuedump(s, t string) {
......@@ -84,7 +84,7 @@ func valuedump(s, t string) {
case reflect.BoolKind:
v.(reflect.BoolValue).Set(true);
}
assert(reflect.ValueToString(v), t);
assert(reflect.valueToString(v), t);
}
type T struct { a int; b float64; c string; d *int }
......@@ -156,43 +156,43 @@ func TestAll(tt *testing.T) { // TODO(r): wrap up better
{ var tmp = 123;
value := reflect.NewValue(tmp);
assert(reflect.ValueToString(value), "123");
assert(reflect.valueToString(value), "123");
}
{ var tmp = 123.4;
value := reflect.NewValue(tmp);
assert(reflect.ValueToString(value), "123.4");
assert(reflect.valueToString(value), "123.4");
}
{ var tmp = "abc";
value := reflect.NewValue(tmp);
assert(reflect.ValueToString(value), "abc");
assert(reflect.valueToString(value), "abc");
}
{
var i int = 7;
var tmp = &T{123, 456.75, "hello", &i};
value := reflect.NewValue(tmp);
assert(reflect.ValueToString(value.(reflect.PtrValue).Sub()), "reflect.T{123, 456.75, hello, *int(@)}");
assert(reflect.valueToString(value.(reflect.PtrValue).Sub()), "reflect.T{123, 456.75, hello, *int(@)}");
}
{
type C chan *T; // TODO: should not be necessary
var tmp = new(C);
value := reflect.NewValue(tmp);
assert(reflect.ValueToString(value), "*reflect.C·all_test(@)");
assert(reflect.valueToString(value), "*reflect.C·all_test(@)");
}
// {
// type A [10]int;
// var tmp A = A{1,2,3,4,5,6,7,8,9,10};
// value := reflect.NewValue(&tmp);
// assert(reflect.ValueToString(value.(reflect.PtrValue).Sub()), "reflect.A·all_test{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}");
// assert(reflect.valueToString(value.(reflect.PtrValue).Sub()), "reflect.A·all_test{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}");
// value.(reflect.PtrValue).Sub().(reflect.ArrayValue).Elem(4).(reflect.IntValue).Set(123);
// assert(reflect.ValueToString(value.(reflect.PtrValue).Sub()), "reflect.A·all_test{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}");
// assert(reflect.valueToString(value.(reflect.PtrValue).Sub()), "reflect.A·all_test{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}");
// }
{
type AA []int;
var tmp = AA{1,2,3,4,5,6,7,8,9,10};
value := reflect.NewValue(&tmp); // TODO: NewValue(tmp) too
assert(reflect.ValueToString(value.(reflect.PtrValue).Sub()), "reflect.AA·all_test{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}");
assert(reflect.valueToString(value.(reflect.PtrValue).Sub()), "reflect.AA·all_test{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}");
value.(reflect.PtrValue).Sub().(reflect.ArrayValue).Elem(4).(reflect.IntValue).Set(123);
assert(reflect.ValueToString(value.(reflect.PtrValue).Sub()), "reflect.AA·all_test{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}");
assert(reflect.valueToString(value.(reflect.PtrValue).Sub()), "reflect.AA·all_test{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}");
}
{
......
......@@ -3,7 +3,9 @@
// license that can be found in the LICENSE file.
// Reflection library.
// Formatting of types and values for debugging.
// Formatting of reflection types and values for debugging.
// Not defined as methods so they do not need to be linked into most binaries;
// the functions are not used by the library itself, only in tests.
package reflect
......@@ -12,8 +14,8 @@ import (
"strconv";
)
func TypeToString(typ Type, expand bool) string
func ValueToString(val Value) string
func typeToString(typ Type, expand bool) string
func valueToString(val Value) string
func doubleQuote(s string) string {
out := "\"";
......@@ -50,7 +52,7 @@ func typeFieldsToString(t hasFields, sep string) string {
if str1 != "" {
str1 += " "
}
str1 += TypeToString(typ, false);
str1 += typeToString(typ, false);
if tag != "" {
str1 += " " + doubleQuote(tag);
}
......@@ -62,7 +64,11 @@ func typeFieldsToString(t hasFields, sep string) string {
return str;
}
func TypeToString(typ Type, expand bool) string {
// typeToString returns a textual representation of typ. The expand
// flag specifies whether to expand the contents of type names; if false,
// the name itself is used as the representation.
// Meant for debugging only; typ.String() serves for most purposes.
func typeToString(typ Type, expand bool) string {
var str string;
if name := typ.Name(); !expand && name != "" {
return name
......@@ -78,7 +84,7 @@ func TypeToString(typ Type, expand bool) string {
return typ.Name();
case PtrKind:
p := typ.(PtrType);
return "*" + TypeToString(p.Sub(), false);
return "*" + typeToString(p.Sub(), false);
case ArrayKind:
a := typ.(ArrayType);
if a.IsSlice() {
......@@ -86,11 +92,11 @@ func TypeToString(typ Type, expand bool) string {
} else {
str = "[" + strconv.Itoa64(int64(a.Len())) + "]"
}
return str + TypeToString(a.Elem(), false);
return str + typeToString(a.Elem(), false);
case MapKind:
m := typ.(MapType);
str = "map[" + TypeToString(m.Key(), false) + "]";
return str + TypeToString(m.Elem(), false);
str = "map[" + typeToString(m.Key(), false) + "]";
return str + typeToString(m.Elem(), false);
case ChanKind:
c := typ.(ChanType);
switch c.Dir() {
......@@ -101,9 +107,9 @@ func TypeToString(typ Type, expand bool) string {
case BothDir:
str = "chan";
default:
panicln("reflect.TypeToString: unknown chan direction");
panicln("reflect.typeToString: unknown chan direction");
}
return str + TypeToString(c.Elem(), false);
return str + typeToString(c.Elem(), false);
case StructKind:
return "struct{" + typeFieldsToString(typ.(StructType), ";") + "}";
case InterfaceKind:
......@@ -116,9 +122,9 @@ func TypeToString(typ Type, expand bool) string {
}
return str;
default:
panicln("reflect.TypeToString: can't print type ", typ.Kind());
panicln("reflect.typeToString: can't print type ", typ.Kind());
}
return "reflect.TypeToString: can't happen";
return "reflect.typeToString: can't happen";
}
// TODO: want an unsigned one too
......@@ -126,7 +132,9 @@ func integer(v int64) string {
return strconv.Itoa64(v);
}
func ValueToString(val Value) string {
// valueToString returns a textual representation of the reflection value val.
// For debugging only.
func valueToString(val Value) string {
var str string;
typ := val.Type();
switch(val.Kind()) {
......@@ -174,41 +182,41 @@ func ValueToString(val Value) string {
}
case PtrKind:
v := val.(PtrValue);
return TypeToString(typ, false) + "(" + integer(int64(uintptr(v.Get()))) + ")";
return typeToString(typ, false) + "(" + integer(int64(uintptr(v.Get()))) + ")";
case ArrayKind:
t := typ.(ArrayType);
v := val.(ArrayValue);
str += TypeToString(t, false);
str += typeToString(t, false);
str += "{";
for i := 0; i < v.Len(); i++ {
if i > 0 {
str += ", "
}
str += ValueToString(v.Elem(i));
str += valueToString(v.Elem(i));
}
str += "}";
return str;
case MapKind:
t := typ.(MapType);
v := val.(MapValue);
str = TypeToString(t, false);
str = typeToString(t, false);
str += "{";
str += "<can't iterate on maps>";
str += "}";
return str;
case ChanKind:
str = TypeToString(typ, false);
str = typeToString(typ, false);
return str;
case StructKind:
t := typ.(StructType);
v := val.(StructValue);
str += TypeToString(t, false);
str += typeToString(t, false);
str += "{";
for i := 0; i < v.Len(); i++ {
if i > 0 {
str += ", "
}
str += ValueToString(v.Field(i));
str += valueToString(v.Field(i));
}
str += "}";
return str;
......@@ -217,7 +225,7 @@ func ValueToString(val Value) string {
case FuncKind:
return "can't print funcs yet";
default:
panicln("reflect.ValueToString: can't print type ", val.Kind());
panicln("reflect.valueToString: can't print type ", val.Kind());
}
return "reflect.ValueToString: can't happen";
return "reflect.valueToString: can't happen";
}
......@@ -5,6 +5,10 @@
// Reflection library.
// Types and parsing of type strings.
// This package implements data ``reflection''. A program can use it to analyze types
// and values it does not know at compile time, such as the values passed in a call
// to a function with a ... parameter. This is achieved by extracting the dynamic
// contents of an interface value.
package reflect
import (
......@@ -19,6 +23,7 @@ func ExpandType(name string) Type
func typestrings() string // implemented in C; declared here
// These constants identify what kind of thing a Type represents: an int, struct, etc.
const (
MissingKind = iota;
ArrayKind;
......@@ -57,10 +62,18 @@ const (
var missingString = "$missing$" // syntactic name for undefined type names
var dotDotDotString = "..."
// Type is the generic interface to reflection types. Once its Kind is known,
// such as BoolKind, the Type can be narrowed to the appropriate, more
// specific interface, such as BoolType. Such narrowed types still implement
// the Type interface.
type Type interface {
// The kind of thing described: ArrayKind, BoolKind, etc.
Kind() int;
// The name declared for the type ("int", "BoolArray", etc.).
Name() string;
// For a named type, same as Name(); otherwise a representation of the type such as "[]int".
String() string;
// The number of bytes needed to store a value; analogous to unsafe.Sizeof().
Size() int;
}
......@@ -104,7 +117,10 @@ func newBasicType(name string, kind int, size int) Type {
return &basicType{ commonType{kind, name, name, size} }
}
// Prebuilt basic types
// Prebuilt basic Type objects representing the predeclared basic types.
// Most are self-evident except:
// Missing represents types whose representation cannot be discovered; usually an error.
// DotDotDot represents the pseudo-type of a ... parameter.
var (
Missing = newBasicType(missingString, MissingKind, 1);
empty interface{};
......@@ -149,9 +165,10 @@ func (t *stubType) Get() Type {
// -- Pointer
// PtrType represents a pointer.
type PtrType interface {
Type;
Sub() Type
Sub() Type // The type of the pointed-to item; for "*int", it will be "int".
}
type ptrTypeStruct struct {
......@@ -169,11 +186,12 @@ func (t *ptrTypeStruct) Sub() Type {
// -- Array
// ArrayType represents an array or slice type.
type ArrayType interface {
Type;
IsSlice() bool;
Len() int;
Elem() Type;
IsSlice() bool; // True for slices, false for arrays.
Len() int; // 0 for slices, the length for array types.
Elem() Type; // The type of the elements.
}
type arrayTypeStruct struct {
......@@ -184,7 +202,7 @@ type arrayTypeStruct struct {
}
func newArrayTypeStruct(name, typestring string, open bool, len int, elem *stubType) *arrayTypeStruct {
return &arrayTypeStruct{ commonType{ArrayKind, typestring, name, 0}, elem, open, len}
return &arrayTypeStruct{ commonType{ArrayKind, typestring, name, 0 }, elem, open, len}
}
func (t *arrayTypeStruct) Size() int {
......@@ -199,7 +217,9 @@ func (t *arrayTypeStruct) IsSlice() bool {
}
func (t *arrayTypeStruct) Len() int {
// what about open array? TODO
if t.isslice {
return 0
}
return t.len
}
......@@ -209,10 +229,11 @@ func (t *arrayTypeStruct) Elem() Type {
// -- Map
// MapType represents a map type.
type MapType interface {
Type;
Key() Type;
Elem() Type;
Key() Type; // The type of the keys.
Elem() Type; // The type of the elements/values.
}
type mapTypeStruct struct {
......@@ -235,13 +256,15 @@ func (t *mapTypeStruct) Elem() Type {
// -- Chan
// ChanType represents a chan type.
type ChanType interface {
Type;
Dir() int;
Elem() Type;
Dir() int; // The direction of the channel.
Elem() Type; // The type of the elements.
}
const ( // channel direction
// Channel direction.
const (
SendDir = 1 << iota;
RecvDir;
BothDir = SendDir | RecvDir;
......@@ -267,9 +290,13 @@ func (t *chanTypeStruct) Elem() Type {
// -- Struct
// StructType represents a struct type.
type StructType interface {
Type;
Field(int) (name string, typ Type, tag string, offset int);
// Field returns, for field i, its name, Type, tag information, and byte offset.
// The indices are in declaration order starting at 0.
Field(i int) (name string, typ Type, tag string, offset int);
// Len is the number of fields.
Len() int;
}
......@@ -328,8 +355,12 @@ func (t *structTypeStruct) Len() int {
// -- Interface
// InterfaceType represents an interface type.
// It behaves much like a StructType, treating the methods as fields.
type InterfaceType interface {
Type;
// Field returns, for method i, its name, Type, the empty string, and 0.
// The indices are in declaration order starting at 0. TODO: is this true?
Field(int) (name string, typ Type, tag string, offset int);
Len() int;
}
......@@ -355,10 +386,11 @@ var nilInterface = newInterfaceTypeStruct("nil", "", make([]structField, 0));
// -- Func
// FuncType represents a function type.
type FuncType interface {
Type;
In() StructType;
Out() StructType;
In() StructType; // The parameters in the form of a StructType.
Out() StructType; // The results in the form of a StructType.
}
type funcTypeStruct struct {
......@@ -466,6 +498,9 @@ func init() {
}
/*
Parsing of type strings. These strings are how the run-time recovers type
information dynamically.
Grammar
stubtype = - represent as StubType when possible
......@@ -850,6 +885,9 @@ func (p *typeParser) Type(name string) *stubType {
return s;
}
// ParseTypeString takes a type name and type string (such as "[]int") and
// returns the Type structure representing a type name specifying the corresponding
// type. An empty typestring represents (the type of) a nil interface value.
func ParseTypeString(name, typestring string) Type {
if typestring == "" {
// If the typestring is empty, it represents (the type of) a nil interface value
......@@ -909,7 +947,8 @@ func typeNameToTypeString(name string) string {
return s
}
// Type is known by name. Find (and create if necessary) its real type.
// ExpandType takes the name of a type and returns its Type structure,
// unpacking the associated type string if necessary.
func ExpandType(name string) Type {
lock();
t, ok := types[name];
......
This diff is collapsed.
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