diff options
author | Rob Pike <r@golang.org> | 2008-10-22 17:12:07 -0700 |
---|---|---|
committer | Rob Pike <r@golang.org> | 2008-10-22 17:12:07 -0700 |
commit | 56d93449c174ccb49a87193c17dfd5630261fc0c (patch) | |
tree | 14959b40e9b74299b5a069a9639591eff3000d50 /src | |
parent | 7b904af284aab3b669e41a9df0a7a2b8240710a6 (diff) | |
download | golang-56d93449c174ccb49a87193c17dfd5630261fc0c.tar.gz |
move reflection code into final place.
this is just a branch.
next cl will update and add to build
R=rsc
DELTA=4528 (2264 added, 2264 deleted, 0 changed)
OCL=17670
CL=17672
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/reflect/Makefile | 56 | ||||
-rw-r--r-- | src/lib/reflect/cast_amd64.s | 133 | ||||
-rwxr-xr-x | src/lib/reflect/gencast.sh | 36 | ||||
-rw-r--r-- | src/lib/reflect/main.go | 155 | ||||
-rw-r--r-- | src/lib/reflect/tostring.go | 199 | ||||
-rw-r--r-- | src/lib/reflect/type.go | 870 | ||||
-rw-r--r-- | src/lib/reflect/typestring.c | 12 | ||||
-rw-r--r-- | src/lib/reflect/value.go | 822 |
8 files changed, 2283 insertions, 0 deletions
diff --git a/src/lib/reflect/Makefile b/src/lib/reflect/Makefile new file mode 100644 index 000000000..b0927a3b8 --- /dev/null +++ b/src/lib/reflect/Makefile @@ -0,0 +1,56 @@ +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m reflect tostring.go type.go value.go cast_amd64.s\ +# typestring.c +O=6 +GC=$(O)g +CC=$(O)c -w +AS=$(O)a +AR=$(O)ar + +PKG=$(GOROOT)/pkg/reflect.a + +install: $(PKG) + +nuke: clean + rm -f $(PKG) + +clean: + rm -f *.$O *.a + +%.$O: %.go + $(GC) $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + + +O1=\ + type.$O\ + cast_amd64.$O\ + typestring.$O\ + +O2=\ + value.$O\ + +O3=\ + tostring.$O\ + +$(PKG): a1 a2 a3 +a1: $(O1) + $(AR) grc $(PKG) $(O1) +a2: $(O2) + $(AR) grc $(PKG) $(O2) +a3: $(O3) + $(AR) grc $(PKG) $(O3) + +$(O1): nuke +$(O2): a1 +$(O3): a2 + diff --git a/src/lib/reflect/cast_amd64.s b/src/lib/reflect/cast_amd64.s new file mode 100644 index 000000000..1de31dd04 --- /dev/null +++ b/src/lib/reflect/cast_amd64.s @@ -0,0 +1,133 @@ +// Conversion operators - really just casts +// *** Created by gencast.sh - Do Not Edit *** + +TEXT reflect·AddrToPtrAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrAddrToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrInt8(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrInt8ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrInt16(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrInt16ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrInt32(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrInt32ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrInt64(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrInt64ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrUint8(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrUint8ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrUint16(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrUint16ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrUint32(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrUint32ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrUint64(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrUint64ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrFloat32(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrFloat32ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrFloat64(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrFloat64ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrFloat80(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrFloat80ToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·AddrToPtrString(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + +TEXT reflect·PtrStringToAddr(SB),7,$-8 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET + diff --git a/src/lib/reflect/gencast.sh b/src/lib/reflect/gencast.sh new file mode 100755 index 000000000..e3871a531 --- /dev/null +++ b/src/lib/reflect/gencast.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +awk ' +BEGIN { + print("// Conversion operators - really just casts") + print("// *** Created by gencast.sh - Do Not Edit ***\n")} +{ + print("TEXT reflect·AddrToPtr" $0 "(SB),7,$-8") + print("\tMOVQ 8(SP), AX") + print("\tMOVQ AX, 16(SP)") + print("\tRET") + print("") + print("TEXT reflect·Ptr" $0 "ToAddr(SB),7,$-8") + print("\tMOVQ 8(SP), AX") + print("\tMOVQ AX, 16(SP)") + print("\tRET") + print("") +} +' > cast_$GOARCH.s << '!' +Addr +Int8 +Int16 +Int32 +Int64 +Uint8 +Uint16 +Uint32 +Uint64 +Float32 +Float64 +Float80 +String +! diff --git a/src/lib/reflect/main.go b/src/lib/reflect/main.go new file mode 100644 index 000000000..c00f2b975 --- /dev/null +++ b/src/lib/reflect/main.go @@ -0,0 +1,155 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "reflect" +) + +func typedump(s string) { + t := reflect.ParseTypeString("", s); + print(reflect.TypeToString(t, true),"; size = ", t.Size(), "\n"); +} + +func valuedump(s string) { + t := reflect.ParseTypeString("", s); + v := reflect.NewInitValue(t); + switch v.Kind() { + case reflect.Int8Kind: + v.(reflect.Int8Value).Put(8); + case reflect.Int16Kind: + v.(reflect.Int16Value).Put(16); + case reflect.Int32Kind: + v.(reflect.Int32Value).Put(32); + case reflect.Int64Kind: + v.(reflect.Int64Value).Put(64); + case reflect.Uint8Kind: + v.(reflect.Uint8Value).Put(8); + case reflect.Uint16Kind: + v.(reflect.Uint16Value).Put(16); + case reflect.Uint32Kind: + v.(reflect.Uint32Value).Put(32); + case reflect.Uint64Kind: + v.(reflect.Uint64Value).Put(64); + case reflect.Float32Kind: + v.(reflect.Float32Value).Put(32.0); + case reflect.Float64Kind: + v.(reflect.Float64Value).Put(64.0); + case reflect.StringKind: + v.(reflect.StringValue).Put("stringy cheese"); + } + print(s, " value = ", reflect.ValueToString(v), "\n"); +} + +export type empty interface {} + +export type T struct { a int; b float64; c string; d *int } + +func main() { + var s string; + var t reflect.Type; + +if false{ + typedump("int8"); + typedump("int16"); + typedump("int32"); + typedump("int64"); + typedump("uint8"); + typedump("uint16"); + typedump("uint32"); + typedump("uint64"); + typedump("float32"); + typedump("float64"); + typedump("float80"); + typedump("int8"); + typedump("**int8"); + typedump("**P.integer"); + typedump("[32]int32"); + typedump("[]int8"); + typedump("*map[string]int32"); + typedump("*chan<-string"); + typedump("struct {c *chan *int32; d float32}"); + typedump("*(a int8, b int32)"); + typedump("struct {c *(? *chan *P.integer, ? *int8)}"); + typedump("struct {a int8; b int32}"); + typedump("struct {a int8; b int8; b int32}"); + typedump("struct {a int8; b int8; c int8; b int32}"); + typedump("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}"); + + valuedump("int8"); + valuedump("int16"); + valuedump("int32"); + valuedump("int64"); + valuedump("uint8"); + valuedump("uint16"); + valuedump("uint32"); + valuedump("uint64"); + valuedump("float32"); + valuedump("float64"); + valuedump("string"); + valuedump("*int8"); + valuedump("**int8"); + valuedump("[32]int32"); + valuedump("**P.integer"); + valuedump("[32]int32"); + valuedump("[]int8"); + valuedump("*map[string]int32"); + valuedump("*chan<-string"); + valuedump("struct {c *chan *int32; d float32}"); + valuedump("*(a int8, b int32)"); + valuedump("struct {c *(? *chan *P.integer, ? *int8)}"); + valuedump("struct {a int8; b int32}"); + valuedump("struct {a int8; b int8; b int32}"); + valuedump("struct {a int8; b int8; c int8; b int32}"); + valuedump("struct {a int8; b int8; c int8; d int8; b int32}"); + valuedump("struct {a int8; b int8; c int8; d int8; e int8; b int32}"); +} +{ var tmp = 123; + value := reflect.NewValue(tmp); + println(reflect.ValueToString(value)); +} +{ var tmp = 123.4; + value := reflect.NewValue(tmp); + println(reflect.ValueToString(value)); +} +{ var tmp = "abc"; + value := reflect.NewValue(tmp); + println(reflect.ValueToString(value)); +} +{ + var i int = 7; + var tmp = &T{123, 456.0, "hello", &i}; + value := reflect.NewValue(tmp); + println(reflect.ValueToString(value.(reflect.PtrValue).Sub())); +} +{ + type C chan *T; // TODO: should not be necessary + var tmp = new(C); + value := reflect.NewValue(tmp); + println(reflect.ValueToString(value)); +} +{ + type A [10]int; + var tmp A = A{1,2,3,4,5,6,7,8,9,10}; + value := reflect.NewValue(&tmp); + println(reflect.TypeToString(value.Type().(reflect.PtrType).Sub(), true)); + println(reflect.TypeToString(value.(reflect.PtrValue).Sub().Type(), true)); + println(reflect.ValueToString(value.(reflect.PtrValue).Sub())); + value.(reflect.PtrValue).Sub().(reflect.ArrayValue).Elem(4).(reflect.Int32Value).Put(123); + println(reflect.ValueToString(value.(reflect.PtrValue).Sub())); +} +{ + type AA []int; + tmp1 := [10]int{1,2,3,4,5,6,7,8,9,10}; + var tmp *AA = &tmp1; + value := reflect.NewValue(tmp); + println(reflect.TypeToString(value.Type().(reflect.PtrType).Sub(), true)); + println(reflect.TypeToString(value.(reflect.PtrValue).Sub().Type(), true)); + println(reflect.ValueToString(value.(reflect.PtrValue).Sub())); + value.(reflect.PtrValue).Sub().(reflect.ArrayValue).Elem(4).(reflect.Int32Value).Put(123); + println(reflect.ValueToString(value.(reflect.PtrValue).Sub())); +} +} diff --git a/src/lib/reflect/tostring.go b/src/lib/reflect/tostring.go new file mode 100644 index 000000000..ca3ada9fd --- /dev/null +++ b/src/lib/reflect/tostring.go @@ -0,0 +1,199 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// 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 and values for debugging. + +package reflect + +import ( + "reflect"; + "strings"; +) + +export func TypeToString(typ Type, expand bool) string +export func ValueToString(val Value) string + +type HasFields interface { + Field(i int) (name string, typ Type, 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 += " " + TypeToString(typ, false); + if i < t.Len() - 1 { + str1 += sep + " "; + } + str += str1; + } + return str; +} + +func TypeToString(typ Type, expand bool) string { + var str string; + if name := typ.Name(); !expand && name != "" { + return name + } + switch(typ.Kind()) { + case MissingKind: + return "$missing$"; + case Int8Kind: + return "int8"; + case Int16Kind: + return "int16"; + case Int32Kind: + return "int32"; + case Int64Kind: + return "int64"; + case Uint8Kind: + return "uint8"; + case Uint16Kind: + return "uint16"; + case Uint32Kind: + return "uint32"; + case Uint64Kind: + return "uint64"; + case Float32Kind: + return "float32"; + case Float64Kind: + return "float64"; + case Float80Kind: + return "float80"; + case StringKind: + return "string"; + case PtrKind: + p := typ.(PtrType); + return "*" + TypeToString(p.Sub(), false); + case ArrayKind: + a := typ.(ArrayType); + if a.Open() { + str = "[]" + } else { + str = "[" + strings.ltoa(int64(a.Len())) + "]" + } + return str + TypeToString(a.Elem(), false); + case MapKind: + m := typ.(MapType); + str = "map[" + TypeToString(m.Key(), false) + "]"; + return str + TypeToString(m.Elem(), false); + case ChanKind: + c := typ.(ChanType); + switch c.Dir() { + case RecvDir: + str = "<-chan"; + case SendDir: + str = "chan<-"; + case BothDir: + str = "chan"; + default: + panicln("reflect.TypeToString: unknown chan direction"); + } + return str + TypeToString(c.Elem(), false); + case StructKind: + return "struct{" + TypeFieldsToString(typ, ";") + "}"; + case InterfaceKind: + return "interface{" + TypeFieldsToString(typ, ";") + "}"; + case FuncKind: + f := typ.(FuncType); + str = "(" + TypeFieldsToString(f.In(), ",") + ")"; + if f.Out() != nil { + str += "(" + TypeFieldsToString(f.Out(), ",") + ")"; + } + return str; + default: + panicln("reflect.TypeToString: can't print type ", typ.Kind()); + } + return "reflect.TypeToString: can't happen"; +} + +// TODO: want an unsigned one too +func integer(v int64) string { + return strings.ltoa(v); +} + +func floatingpoint(v float64) string { + return strings.dtoa(v); +} + +func ValueToString(val Value) string { + var str string; + typ := val.Type(); + switch(val.Kind()) { + case MissingKind: + return "missing"; + case Int8Kind: + return integer(int64(val.(Int8Value).Get())); + case Int16Kind: + return integer(int64(val.(Int16Value).Get())); + case Int32Kind: + return integer(int64(val.(Int32Value).Get())); + case Int64Kind: + return integer(int64(val.(Int64Value).Get())); + case Uint8Kind: + return integer(int64(val.(Uint8Value).Get())); + case Uint16Kind: + return integer(int64(val.(Uint16Value).Get())); + case Uint32Kind: + return integer(int64(val.(Uint32Value).Get())); + case Uint64Kind: + return integer(int64(val.(Uint64Value).Get())); + case Float32Kind: + return floatingpoint(float64(val.(Float32Value).Get())); + case Float64Kind: + return floatingpoint(float64(val.(Float64Value).Get())); + case Float80Kind: + return "float80"; + case StringKind: + return val.(StringValue).Get(); + case PtrKind: + v := val.(PtrValue); + return TypeToString(typ, false) + "(" + integer(int64(v.Indirect())) + ")"; + case ArrayKind: + t := typ.(ArrayType); + v := val.(ArrayValue); + str += TypeToString(t, false); + str += "{"; + for i := uint64(0); i < v.Len(); i++ { + if i > 0 { + str += ", " + } + str += ValueToString(v.Elem(i)); + } + str += "}"; + return str; + case MapKind: + t := typ.(MapType); + v := val.(ArrayValue); + str = TypeToString(t, false); + str += "{"; + str += "<can't iterate on maps>"; + str += "}"; + return str; + case ChanKind: + return "can't print chans yet"; + case StructKind: + t := typ.(StructType); + v := val.(StructValue); + str += TypeToString(t, false); + str += "{"; + for i := 0; i < v.Len(); i++ { + if i > 0 { + str += ", " + } + str += ValueToString(v.Field(i)); + } + str += "}"; + return str; + case InterfaceKind: + return "can't print interfaces yet"; + case FuncKind: + return "can't print funcs yet"; + default: + panicln("reflect.ValueToString: can't print type ", val.Kind()); + } + return "reflect.ValueToString: can't happen"; +} diff --git a/src/lib/reflect/type.go b/src/lib/reflect/type.go new file mode 100644 index 000000000..c69a3394e --- /dev/null +++ b/src/lib/reflect/type.go @@ -0,0 +1,870 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// 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 func ExpandType(name string) Type + +export func typestrings() string // implemented in C; declared here + +export const ( + MissingKind = iota; + ArrayKind; + ChanKind; + Float32Kind; + Float64Kind; + Float80Kind; + FuncKind; + Int16Kind; + Int32Kind; + Int64Kind; + Int8Kind; + InterfaceKind; + MapKind; + PtrKind; + StringKind; + StructKind; + Uint16Kind; + Uint32Kind; + Uint64Kind; + Uint8Kind; +) + +var ptrsize uint64 +var interfacesize uint64 + +var MissingString = "$missing$" // syntactic name for undefined type names + +export type Type interface { + Kind() int; + Name() string; + Size() uint64; +} + +// -- Basic + +type BasicType struct{ + kind int; + name string; + size uint64; +} + +func (t *BasicType) Name() string { + return t.name +} + +func (t *BasicType) Kind() int { + return t.kind +} + +func (t *BasicType) Size() uint64 { + return t.size +} + +func NewBasicType(n string, k int, size uint64) Type { + t := new(BasicType); + t.name = n; + t.kind = k; + t.size = size; + return t; +} + +// Prebuilt basic types +export var ( + Missing = NewBasicType(MissingString, MissingKind, 1); + Int8 = NewBasicType("int8", Int8Kind, 1); + Int16 = NewBasicType("int16", Int16Kind, 2); + Int32 = NewBasicType("int32", Int32Kind, 4); + Int64 = NewBasicType("int64", Int64Kind, 8); + Uint8 = NewBasicType("uint8", Uint8Kind, 1); + Uint16 = NewBasicType("uint16", Uint16Kind, 2); + Uint32 = NewBasicType("uint32", Uint32Kind, 4); + Uint64 = NewBasicType("uint64", Uint64Kind, 8); + Float32 = NewBasicType("float32", Float32Kind, 4); + Float64 = NewBasicType("float64", Float64Kind, 8); + Float80 = NewBasicType("float80", Float80Kind, 10); // TODO: strange size? + String = NewBasicType("string", StringKind, 8); // implemented as a pointer +) + +// 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; +} + +func (t *StubType) Get() Type { + if t.typ == nil { + t.typ = ExpandType(t.name) + } + return t.typ +} + +func NewStubType(name string, t Type) *StubType { + s := new(StubType); + s.name = name; + s.typ = t; + return s; +} + +// -- Pointer + +export type PtrType interface { + Sub() Type +} + +type PtrTypeStruct struct { + name string; + sub *StubType; +} + +func (t *PtrTypeStruct) Kind() int { + return PtrKind +} + +func (t *PtrTypeStruct) Name() string { + return t.name +} + +func (t *PtrTypeStruct) Size() uint64 { + return ptrsize +} + +func (t *PtrTypeStruct) Sub() Type { + return t.sub.Get() +} + +func NewPtrTypeStruct(name string, sub *StubType) *PtrTypeStruct { + t := new(PtrTypeStruct); + t.name = name; + t.sub = sub; + return t; +} + +// -- Array + +export type ArrayType interface { + Open() bool; + Len() uint64; + Elem() Type; +} + +type ArrayTypeStruct struct { + name string; + elem *StubType; + open bool; // otherwise fixed size + len uint64; +} + +func (t *ArrayTypeStruct) Kind() int { + return ArrayKind +} + +func (t *ArrayTypeStruct) Name() string { + return t.name +} + +func (t *ArrayTypeStruct) Size() uint64 { + if t.open { + return ptrsize // open arrays are pointers to structures + } + return t.len * t.elem.Get().Size(); +} + +func (t *ArrayTypeStruct) Open() bool { + return t.open +} + +func (t *ArrayTypeStruct) Len() uint64 { + // what about open array? TODO + return t.len +} + +func (t *ArrayTypeStruct) Elem() Type { + return t.elem.Get() +} + +func NewArrayTypeStruct(name string, open bool, len uint64, elem *StubType) *ArrayTypeStruct { + t := new(ArrayTypeStruct); + t.name = name; + t.open = open; + t.len = len; + t.elem = elem; + return t; +} + +// -- Map + +export type MapType interface { + Key() Type; + Elem() Type; +} + +type MapTypeStruct struct { + name string; + key *StubType; + elem *StubType; +} + +func (t *MapTypeStruct) Kind() int { + return MapKind +} + +func (t *MapTypeStruct) Name() string { + return t.name +} + +func (t *MapTypeStruct) Size() uint64 { + panic("reflect.type: map.Size(): cannot happen"); + return 0 +} + +func (t *MapTypeStruct) Key() Type { + return t.key.Get() +} + +func (t *MapTypeStruct) Elem() Type { + return t.elem.Get() +} + +func NewMapTypeStruct(name string, key, elem *StubType) *MapTypeStruct { + t := new(MapTypeStruct); + t.name = name; + t.key = key; + t.elem = elem; + return t; +} + +// -- Chan + +export type ChanType interface { + Dir() int; + Elem() Type; +} + +export const ( // channel direction + SendDir = 1 << iota; + RecvDir; + BothDir = SendDir | RecvDir; +) + +type ChanTypeStruct struct { + name string; + elem *StubType; + dir int; +} + +func (t *ChanTypeStruct) Kind() int { + return ChanKind +} + +func (t *ChanTypeStruct) Name() string { + return t.name +} + +func (t *ChanTypeStruct) Size() uint64 { + panic("reflect.type: chan.Size(): cannot happen"); + return 0 +} + +func (t *ChanTypeStruct) Dir() int { + // -1 is open array? TODO + return t.dir +} + +func (t *ChanTypeStruct) Elem() Type { + return t.elem.Get() +} + +func NewChanTypeStruct(name string, dir int, elem *StubType) *ChanTypeStruct { + t := new(ChanTypeStruct); + t.name = name; + t.dir = dir; + t.elem = elem; + return t; +} + +// -- Struct + +export type StructType interface { + Field(int) (name string, typ Type, offset uint64); + Len() int; +} + +type Field struct { + name string; + typ *StubType; + size uint64; + offset uint64; +} + +type StructTypeStruct struct { + name string; + field *[]Field; +} + +func (t *StructTypeStruct) Kind() int { + return StructKind +} + +func (t *StructTypeStruct) Name() string { + return t.name +} + +// TODO: not portable; depends on 6g +func (t *StructTypeStruct) Size() uint64 { + size := uint64(0); + for i := 0; i < len(t.field); i++ { + elemsize := t.field[i].typ.Get().Size(); + // pad until at (elemsize mod 8) boundary + align := elemsize - 1; + if align > 7 { // BUG: we know structs are 8-aligned + align = 7 + } + if align > 0 { + size = (size + align) & ^align; + } + t.field[i].offset = size; + size += elemsize; + } + size = (size + 7) & ((1<<64 - 1) & ^7); + return size; +} + +func (t *StructTypeStruct) Field(i int) (name string, typ Type, 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 +} + +func (t *StructTypeStruct) Len() int { + return len(t.field) +} + +func NewStructTypeStruct(name string, field *[]Field) *StructTypeStruct { + t := new(StructTypeStruct); + t.name = name; + t.field = field; + return t; +} + +// -- Interface + +export type InterfaceType interface { + Field(int) (name string, typ Type, offset uint64); + Len() int; +} + +type InterfaceTypeStruct struct { + name string; + field *[]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) Len() int { + return len(t.field) +} + +func NewInterfaceTypeStruct(name string, field *[]Field) *InterfaceTypeStruct { + t := new(InterfaceTypeStruct); + t.name = name; + t.field = field; + return t; +} + +func (t *InterfaceTypeStruct) Kind() int { + return InterfaceKind +} + +func (t *InterfaceTypeStruct) Name() string { + return t.name +} + +func (t *InterfaceTypeStruct) Size() uint64 { + return interfacesize +} + +// -- Func + +export type FuncType interface { + In() StructType; + Out() StructType; +} + +type FuncTypeStruct struct { + name string; + in *StructTypeStruct; + out *StructTypeStruct; +} + +func (t *FuncTypeStruct) Kind() int { + return FuncKind +} + +func (t *FuncTypeStruct) Name() string { + return t.name +} + +func (t *FuncTypeStruct) Size() uint64 { + panic("reflect.type: func.Size(): cannot happen"); + return 0 +} + +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(name string, in, out *StructTypeStruct) *FuncTypeStruct { + t := new(FuncTypeStruct); + t.name = name; + t.in = in; + t.out = out; + return t; +} + +// 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 typestring *map[string] string +var initialized bool = false + +// Map of basic types to prebuilt StubTypes +var basicstub *map[string] *StubType + +var MissingStub *StubType; + +// The database stored in the maps is global; use locking to guarantee safety. +var lockchan *chan bool // Channel with buffer of 1, used as a mutex + +func Lock() { + lockchan <- true // block if buffer is full +} + +func Unlock() { + <-lockchan // release waiters +} + +func init() { + ptrsize = 8; // TODO: compute this + interfacesize = 2*ptrsize; // TODO: compute this + + lockchan = new(chan bool, 1); // unlocked at creation - buffer is empty + Lock(); // not necessary because of init ordering but be safe. + + types = new(map[string] *Type); + typestring = new(map[string] string); + basicstub = new(map[string] *StubType); + + // Basics go into types table + types[MissingString] = &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(MissingString, Missing); + basicstub[MissingString] = MissingStub; + basicstub["int8"] = NewStubType("int8", Int8); + basicstub["int16"] = NewStubType("int16", Int16); + basicstub["int32"] = NewStubType("int32", Int32); + basicstub["int64"] = NewStubType("int64", Int64); + basicstub["uint8"] = NewStubType("uint8", Uint8); + basicstub["uint16"] = NewStubType("uint16", Uint16); + basicstub["uint32"] = NewStubType("uint32", Uint32); + basicstub["uint64"] = NewStubType("uint64", Uint64); + basicstub["float32"] = NewStubType("float32", Float32); + basicstub["float64"] = NewStubType("float64", Float64); + basicstub["float80"] = NewStubType("float80", Float80); + basicstub["string"] = NewStubType("string", String); + + Unlock(); +} + +/* + 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 ')' + +*/ + +// 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 "?". + for i := 0; i < len(s); i++ { + if c == s[i] { + return true + } + } + return false; +} + +// Simple parser for type strings +type Parser struct { + 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++ { + } + 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 == '<': + if p.index < len(p.str) && p.str[p.index] == '-' { + p.index++; + p.token = "<-"; + return; + } + 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]) { + p.index++ + } + p.token = p.str[start : p.index]; + return; + } + for p.index < len(p.str) && p.str[p.index] != ' ' && !special(p.str[p.index]) { + p.index++ + } + p.token = p.str[start : p.index]; +} + +func (p *Parser) Type(name string) *StubType + +func (p *Parser) Array(name string) *StubType { + size := uint64(0); + open := true; + 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 + uint64(p.token[i]) - '0' + } + p.Next(); + open = false; + } + if p.token != "]" { + return MissingStub + } + p.Next(); + elemtype := p.Type(""); + return NewStubType(name, NewArrayTypeStruct(name, open, size, elemtype)); +} + +func (p *Parser) Map(name string) *StubType { + if p.token != "[" { + return MissingStub + } + p.Next(); + keytype := p.Type(""); + if p.token != "]" { + return MissingStub + } + p.Next(); + elemtype := p.Type(""); + return NewStubType(name, NewMapTypeStruct(name, keytype, elemtype)); +} + +func (p *Parser) Chan(name string, dir int) *StubType { + if p.token == "<-" { + if dir != BothDir { + return MissingStub + } + p.Next(); + dir = SendDir; + } + elemtype := p.Type(""); + return NewStubType(name, NewChanTypeStruct(name, 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(name string) *StubType { + f := p.Fields(";"); + if p.token != "}" { + return MissingStub; + } + p.Next(); + return NewStubType(name, NewStructTypeStruct(name, f)); +} + +func (p *Parser) Interface(name string) *StubType { + f := p.Fields(";"); + if p.token != "}" { + return MissingStub; + } + p.Next(); + return NewStubType(name, NewInterfaceTypeStruct(name, f)); +} + +func (p *Parser) Func(name string) *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(name, NewFuncTypeStruct(name, 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(name, NewFuncTypeStruct(name, f1, f2)); +} + +func (p *Parser) Type(name string) *StubType { + dir := BothDir; + switch { + case p.token == "": + return nil; + case p.token == "*": + p.Next(); + return NewStubType(name, NewPtrTypeStruct(name, p.Type(""))); + case p.token == "[": + p.Next(); + return p.Array(name); + case p.token == "map": + p.Next(); + return p.Map(name); + case p.token == "<-": + p.Next(); + dir = RecvDir; + if p.token != "chan" { + return MissingStub; + } + fallthrough; + case p.token == "chan": + p.Next(); + return p.Chan(name, dir); + case p.token == "struct": + p.Next(); + if p.token != "{" { + return MissingStub + } + p.Next(); + return p.Struct(name); + case p.token == "interface": + p.Next(); + if p.token != "{" { + return MissingStub + } + p.Next(); + return p.Interface(name); + case p.token == "(": + p.Next(); + return p.Func(name); + case isdigit(p.token[0]): + p.Next(); + return MissingStub; + case special(p.token[0]): + p.Next(); + return MissingStub; + } + // must be an identifier. is it basic? if so, we have a stub + if s, ok := basicstub[p.token]; ok { + p.Next(); + if name != "" { + // Need to make a copy because we are renaming a basic type + b := s.Get(); + s = NewStubType(name, NewBasicType(name, b.Kind(), b.Size())); + } + 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 { + p.Next(); + return MissingStub; + } + s := NewStubType(p.token, nil); + p.Next(); + return s; +} + +export func ParseTypeString(name, typestring string) Type { + p := new(Parser); + p.str = typestring; + p.Next(); + return p.Type(name).Get(); +} + +// Create typestring map from reflect.typestrings() data. Lock is held. +func InitializeTypeStrings() { + if initialized { + return + } + initialized = true; + s := typestrings(); + slen := len(s); + for i := 0; i < slen; { + // "reflect.PtrType interface { Sub () (? reflect.Type) }\n" + // find the identifier + idstart := i; + for ; i < slen && s[i] != ' '; i++ { + } + if i == slen { + print("reflect.InitializeTypeStrings: bad identifier\n"); + return; + } + idend := i; + i++; + // find the end of the line, terminating the type + typestart := i; + for ; i < slen && s[i] != '\n'; i++ { + } + if i == slen { + print("reflect.InitializeTypeStrings: bad type string\n"); + return; + } + typeend := i; + i++; //skip newline + typestring[s[idstart:idend]] = s[typestart:typeend]; + } +} + +// Look up type string associated with name. Lock is held. +func TypeNameToTypeString(name string) string { + s, ok := typestring[name]; + if !ok { + InitializeTypeStrings(); + s, ok = typestring[name]; + if !ok { + s = MissingString; + typestring[name] = s; + } + } + return s +} + +// Type is known by name. Find (and create if necessary) its real type. +func ExpandType(name string) Type { + Lock(); + t, ok := types[name]; + if ok { + Unlock(); + return *t + } + types[name] = &Missing; // prevent recursion; will overwrite + t1 := ParseTypeString(name, TypeNameToTypeString(name)); + p := new(Type); + *p = t1; + types[name] = p; + Unlock(); + return t1; +} diff --git a/src/lib/reflect/typestring.c b/src/lib/reflect/typestring.c new file mode 100644 index 000000000..a5e6398ad --- /dev/null +++ b/src/lib/reflect/typestring.c @@ -0,0 +1,12 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +extern char gotypestrings[]; // really a go String, but we don't have the definition here + +void FLUSH(void *v) { } + +void reflect·typestrings(void *s) { + s = gotypestrings; + FLUSH(&s); +} diff --git a/src/lib/reflect/value.go b/src/lib/reflect/value.go new file mode 100644 index 000000000..a180b8140 --- /dev/null +++ b/src/lib/reflect/value.go @@ -0,0 +1,822 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Reflection library. +// Handling values. + +package reflect + +import ( + "reflect"; +) + + +type Addr uint64 // TODO: where are ptrint/intptr etc? + +export type Value interface { + Kind() int; + Type() Type; +} + +func NewValueAddr(typ Type, addr Addr) Value + +type Creator *(typ Type, addr Addr) Value + +// Conversion functions, implemented in assembler +func AddrToPtrAddr(Addr) *Addr +func AddrToPtrInt8(Addr) *int8 +func AddrToPtrInt16(Addr) *int16 +func AddrToPtrInt32(Addr) *int32 +func AddrToPtrInt64(Addr) *int64 +func AddrToPtrUint8(Addr) *uint8 +func PtrUint8ToAddr(*uint8) Addr +func AddrToPtrUint16(Addr) *uint16 +func AddrToPtrUint32(Addr) *uint32 +func AddrToPtrUint64(Addr) *uint64 +func PtrUint64ToAddr(*uint64) Addr +func AddrToPtrFloat32(Addr) *float32 +func AddrToPtrFloat64(Addr) *float64 +func AddrToPtrFloat80(Addr) *float80 +func AddrToPtrString(Addr) *string + +// -- Int8 + +export type Int8Value interface { + Kind() int; + Get() int8; + Put(int8); + Type() Type; +} + +type Int8ValueStruct struct { + addr Addr +} + +func (v *Int8ValueStruct) Kind() int { + return Int8Kind +} + +func (v *Int8ValueStruct) Type() Type { + return Int8 +} + +func (v *Int8ValueStruct) Get() int8 { + return *AddrToPtrInt8(v.addr) +} + +func (v *Int8ValueStruct) Put(i int8) { + *AddrToPtrInt8(v.addr) = i +} + +func Int8Creator(typ Type, addr Addr) Value { + v := new(Int8ValueStruct); + v.addr = addr; + return v; +} + +// -- Int16 + +export type Int16Value interface { + Kind() int; + Get() int16; + Put(int16); + Type() Type; +} + +type Int16ValueStruct struct { + addr Addr +} + +func (v *Int16ValueStruct) Kind() int { + return Int16Kind +} + +func (v *Int16ValueStruct) Type() Type { + return Int16 +} + +func (v *Int16ValueStruct) Get() int16 { + return *AddrToPtrInt16(v.addr) +} + +func (v *Int16ValueStruct) Put(i int16) { + *AddrToPtrInt16(v.addr) = i +} + +func Int16Creator(typ Type, addr Addr) Value { + v := new(Int16ValueStruct); + v.addr = addr; + return v; +} + +// -- Int32 + +export type Int32Value interface { + Kind() int; + Get() int32; + Put(int32); + Type() Type; +} + +type Int32ValueStruct struct { + addr Addr +} + +func (v *Int32ValueStruct) Type() Type { + return Int32 +} + +func (v *Int32ValueStruct) Kind() int { + return Int32Kind +} + +func (v *Int32ValueStruct) Get() int32 { + return *AddrToPtrInt32(v.addr) +} + +func (v *Int32ValueStruct) Put(i int32) { + *AddrToPtrInt32(v.addr) = i +} + +func Int32Creator(typ Type, addr Addr) Value { + v := new(Int32ValueStruct); + v.addr = addr; + return v; +} + +// -- Int64 + +export type Int64Value interface { + Kind() int; + Get() int64; + Put(int64); + Type() Type; +} + +type Int64ValueStruct struct { + addr Addr +} + +func (v *Int64ValueStruct) Kind() int { + return Int64Kind +} + +func (v *Int64ValueStruct) Type() Type { + return Int64 +} + +func (v *Int64ValueStruct) Get() int64 { + return *AddrToPtrInt64(v.addr) +} + +func (v *Int64ValueStruct) Put(i int64) { + *AddrToPtrInt64(v.addr) = i +} + +func Int64Creator(typ Type, addr Addr) Value { + v := new(Int64ValueStruct); + v.addr = addr; + return v; +} + +// -- Uint8 + +export type Uint8Value interface { + Kind() int; + Get() uint8; + Put(uint8); + Type() Type; +} + +type Uint8ValueStruct struct { + addr Addr +} + +func (v *Uint8ValueStruct) Kind() int { + return Uint8Kind +} + +func (v *Uint8ValueStruct) Type() Type { + return Uint8 +} + +func (v *Uint8ValueStruct) Get() uint8 { + return *AddrToPtrUint8(v.addr) +} + +func (v *Uint8ValueStruct) Put(i uint8) { + *AddrToPtrUint8(v.addr) = i +} + +func Uint8Creator(typ Type, addr Addr) Value { + v := new(Uint8ValueStruct); + v.addr = addr; + return v; +} + +// -- Uint16 + +export type Uint16Value interface { + Kind() int; + Get() uint16; + Put(uint16); + Type() Type; +} + +type Uint16ValueStruct struct { + addr Addr +} + +func (v *Uint16ValueStruct) Kind() int { + return Uint16Kind +} + +func (v *Uint16ValueStruct) Type() Type { + return Uint16 +} + +func (v *Uint16ValueStruct) Get() uint16 { + return *AddrToPtrUint16(v.addr) +} + +func (v *Uint16ValueStruct) Put(i uint16) { + *AddrToPtrUint16(v.addr) = i +} + +func Uint16Creator(typ Type, addr Addr) Value { + v := new(Uint16ValueStruct); + v.addr = addr; + return v; +} + +// -- Uint32 + +export type Uint32Value interface { + Kind() int; + Get() uint32; + Put(uint32); + Type() Type; +} + +type Uint32ValueStruct struct { + addr Addr +} + +func (v *Uint32ValueStruct) Kind() int { + return Uint32Kind +} + +func (v *Uint32ValueStruct) Type() Type { + return Uint32 +} + +func (v *Uint32ValueStruct) Get() uint32 { + return *AddrToPtrUint32(v.addr) +} + +func (v *Uint32ValueStruct) Put(i uint32) { + *AddrToPtrUint32(v.addr) = i +} + +func Uint32Creator(typ Type, addr Addr) Value { + v := new(Uint32ValueStruct); + v.addr = addr; + return v; +} + +// -- Uint64 + +export type Uint64Value interface { + Kind() int; + Get() uint64; + Put(uint64); + Type() Type; +} + +type Uint64ValueStruct struct { + addr Addr +} + +func (v *Uint64ValueStruct) Kind() int { + return Uint64Kind +} + +func (v *Uint64ValueStruct) Type() Type { + return Uint64 +} + +func (v *Uint64ValueStruct) Get() uint64 { + return *AddrToPtrUint64(v.addr) +} + +func (v *Uint64ValueStruct) Put(i uint64) { + *AddrToPtrUint64(v.addr) = i +} + +func Uint64Creator(typ Type, addr Addr) Value { + v := new(Uint64ValueStruct); + v.addr = addr; + return v; +} + +// -- Float32 + +export type Float32Value interface { + Kind() int; + Get() float32; + Put(float32); + Type() Type; +} + +type Float32ValueStruct struct { + addr Addr +} + +func (v *Float32ValueStruct) Kind() int { + return Float32Kind +} + +func (v *Float32ValueStruct) Type() Type { + return Float32 +} + +func (v *Float32ValueStruct) Get() float32 { + return *AddrToPtrFloat32(v.addr) +} + +func (v *Float32ValueStruct) Put(f float32) { + *AddrToPtrFloat32(v.addr) = f +} + +func Float32Creator(typ Type, addr Addr) Value { + v := new(Float32ValueStruct); + v.addr = addr; + return v; +} + +// -- Float64 + +export type Float64Value interface { + Kind() int; + Get() float64; + Put(float64); + Type() Type; +} + +type Float64ValueStruct struct { + addr Addr +} + +func (v *Float64ValueStruct) Kind() int { + return Float64Kind +} + +func (v *Float64ValueStruct) Type() Type { + return Float64 +} + +func (v *Float64ValueStruct) Get() float64 { + return *AddrToPtrFloat64(v.addr) +} + +func (v *Float64ValueStruct) Put(f float64) { + *AddrToPtrFloat64(v.addr) = f +} + +func Float64Creator(typ Type, addr Addr) Value { + v := new(Float64ValueStruct); + v.addr = addr; + return v; +} + +// -- Float80 + +export type Float80Value interface { + Kind() int; + Get() float80; + Put(float80); + Type() Type; +} + +type Float80ValueStruct struct { + addr Addr +} + +func (v *Float80ValueStruct) Kind() int { + return Float80Kind +} + +func (v *Float80ValueStruct) Type() Type { + return Float80 +} + +/* +BUG: can't gen code for float80s +func (v *Float80ValueStruct) Get() float80 { + return *AddrToPtrFloat80(v.addr) + return 0; +} + +func (v *Float80ValueStruct) Put(f float80) { + *AddrToPtrFloat80(v.addr) = f +} +*/ + +func Float80Creator(typ Type, addr Addr) Value { + v := new(Float80ValueStruct); + v.addr = addr; + return v; +} + +// -- String + +export type StringValue interface { + Kind() int; + Get() string; + Put(string); + Type() Type; +} + +type StringValueStruct struct { + addr Addr +} + +func (v *StringValueStruct) Kind() int { + return StringKind +} + +func (v *StringValueStruct) Type() Type { + return String +} + +func (v *StringValueStruct) Get() string { + return *AddrToPtrString(v.addr) +} + +func (v *StringValueStruct) Put(s string) { + *AddrToPtrString(v.addr) = s +} + +func StringCreator(typ Type, addr Addr) Value { + v := new(StringValueStruct); + v.addr = addr; + return v; +} + +// -- Pointer + +export type PtrValue interface { + Kind() int; + Sub() Value; + Type() Type; + Indirect() Addr; +} + +type PtrValueStruct struct { + addr Addr; + typ Type; +} + +func (v *PtrValueStruct) Kind() int { + return PtrKind +} + +func (v *PtrValueStruct) Type() Type { + return v.typ +} + +func (v *PtrValueStruct) Indirect() Addr { + return *AddrToPtrAddr(v.addr) +} + +func (v *PtrValueStruct) Sub() Value { + return NewValueAddr(v.typ.(PtrType).Sub(), v.Indirect()); +} + +func PtrCreator(typ Type, addr Addr) Value { + return &PtrValueStruct{addr, typ}; +} + +// -- Array TODO: finish and test + +export type ArrayValue interface { + Kind() int; + Type() Type; + Open() bool; + Len() uint64; + Elem(i uint64) Value; +} + +type OpenArrayValueStruct struct { + addr Addr; + typ Type; + elemtype Type; + elemsize uint64; +} +/* + Run-time representation of open arrays looks like this: + struct Array { + byte* array; // actual data + uint32 nel; // number of elements + }; +*/ + +func (v *OpenArrayValueStruct) Kind() int { + return ArrayKind +} + +func (v *OpenArrayValueStruct) Type() Type { + return v.typ +} + +func (v *OpenArrayValueStruct) Open() bool { + return true +} + +func (v *OpenArrayValueStruct) Len() uint64 { + return uint64(*AddrToPtrInt32(v.addr+8)); +} + +func (v *OpenArrayValueStruct) Elem(i uint64) Value { + base := *AddrToPtrAddr(v.addr); + return NewValueAddr(v.elemtype, base + i * v.elemsize); +} + +type FixedArrayValueStruct struct { + addr Addr; + typ Type; + elemtype Type; + elemsize uint64; + len uint64; +} + +func (v *FixedArrayValueStruct) Kind() int { + return ArrayKind +} + +func (v *FixedArrayValueStruct) Type() Type { + return v.typ +} + +func (v *FixedArrayValueStruct) Open() bool { + return false +} + +func (v *FixedArrayValueStruct) Len() uint64 { + return v.len +} + +func (v *FixedArrayValueStruct) Elem(i uint64) Value { + return NewValueAddr(v.elemtype, v.addr + i * v.elemsize); + return nil +} + +func ArrayCreator(typ Type, addr Addr) Value { + arraytype := typ.(ArrayType); + if arraytype.Open() { + v := new(OpenArrayValueStruct); + v.addr = addr; + v.typ = typ; + v.elemtype = arraytype.Elem(); + v.elemsize = v.elemtype.Size(); + return v; + } + v := new(FixedArrayValueStruct); + v.addr = addr; + v.typ = typ; + v.elemtype = arraytype.Elem(); + v.elemsize = v.elemtype.Size(); + v.len = arraytype.Len(); + return v; +} + +// -- Map TODO: finish and test + +export type MapValue interface { + Kind() int; + Type() Type; + Len() int; + Elem(key Value) Value; +} + +type MapValueStruct struct { + addr Addr; + typ Type; + len int; +} + +func (v *MapValueStruct) Kind() int { + return MapKind +} + +func (v *MapValueStruct) Type() Type { + return v.typ +} + +func (v *MapValueStruct) Len() int { + return v.len // TODO: probably want this to be dynamic +} + +func (v *MapValueStruct) Elem(key Value) Value { + panic("map value element"); + return nil +} + +func MapCreator(typ Type, addr Addr) Value { + arraytype := typ.(MapType); + v := new(MapValueStruct); + v.addr = addr; + v.typ = typ; + return v; +} + +// -- Chan + +export type ChanValue interface { + Kind() int; + Type() Type; +} + +type ChanValueStruct struct { + addr Addr; + typ Type; + len int; +} + +func (v *ChanValueStruct) Kind() int { + return ChanKind +} + +func (v *ChanValueStruct) Type() Type { + return v.typ +} + +func ChanCreator(typ Type, addr Addr) Value { + v := new(ChanValueStruct); + v.addr = addr; + v.typ = typ; + return v; +} + +// -- Struct + +export type StructValue interface { + Kind() int; + Type() Type; + Len() int; + Field(i int) Value; +} + +type StructValueStruct struct { + addr Addr; + typ Type; + field *[]Value; +} + +func (v *StructValueStruct) Kind() int { + return StructKind +} + +func (v *StructValueStruct) Type() Type { + return v.typ +} + +func (v *StructValueStruct) Len() int { + return len(v.field) +} + +func (v *StructValueStruct) Field(i int) Value { + return v.field[i] +} + +func StructCreator(typ Type, addr Addr) Value { + t := typ.(StructType); + v := new(StructValueStruct); + v.addr = addr; + nfield := t.Len(); + v.field = new([]Value, nfield); + for i := 0; i < nfield; i++ { + name, ftype, offset := t.Field(i); + v.field[i] = NewValueAddr(ftype, addr + offset); + } + v.typ = typ; + return v; +} + +// -- Interface + +export type InterfaceValue interface { + Kind() int; + Type() Type; +} + +type InterfaceValueInterface struct { + addr Addr; + typ Type; +} + +func (v *InterfaceValueInterface) Kind() int { + return InterfaceKind +} + +func (v *InterfaceValueInterface) Type() Type { + return v.typ +} + +func InterfaceCreator(typ Type, addr Addr) Value { + v := new(InterfaceValueInterface); + v.addr = addr; + v.typ = typ; + return v; +} + +// -- Func + +export type FuncValue interface { + Kind() int; + Type() Type; +} + +type FuncValueFunc struct { + addr Addr; + typ Type; +} + +func (v *FuncValueFunc) Kind() int { + return FuncKind +} + +func (v *FuncValueFunc) Type() Type { + return v.typ +} + +func FuncCreator(typ Type, addr Addr) Value { + v := new(FuncValueFunc); + v.addr = addr; + v.typ = typ; + return v; +} + +var creator *map[int] Creator + +func init() { + creator = new(map[int] Creator); + creator[Int8Kind] = &Int8Creator; + creator[Int16Kind] = &Int16Creator; + creator[Int32Kind] = &Int32Creator; + creator[Int64Kind] = &Int64Creator; + creator[Uint8Kind] = &Uint8Creator; + creator[Uint16Kind] = &Uint16Creator; + creator[Uint32Kind] = &Uint32Creator; + creator[Uint64Kind] = &Uint64Creator; + creator[Float32Kind] = &Float32Creator; + creator[Float64Kind] = &Float64Creator; + creator[Float80Kind] = &Float80Creator; + creator[StringKind] = &StringCreator; + creator[PtrKind] = &PtrCreator; + creator[ArrayKind] = &ArrayCreator; + creator[MapKind] = &MapCreator; + creator[ChanKind] = &ChanCreator; + creator[StructKind] = &StructCreator; + creator[InterfaceKind] = &InterfaceCreator; + creator[FuncKind] = &FuncCreator; +} + +func NewValueAddr(typ Type, addr Addr) Value { + c, ok := creator[typ.Kind()]; + if !ok { + panicln("no creator for type" , typ.Kind()); + } + return c(typ, addr); +} + +export func NewInitValue(typ Type) Value { + // Some values cannot be made this way. + switch typ.Kind() { + case FuncKind, ChanKind, MapKind: // must be pointers, at least for now (TODO?) + return nil; + case ArrayKind: + if typ.(ArrayType).Open() { + return nil + } + } + size := typ.Size(); + if size == 0 { + size = 1; + } + data := new([]uint8, size); + return NewValueAddr(typ, PtrUint8ToAddr(&data[0])); +} + +export type Empty interface {} + +export func NewValue(e Empty) Value { + value, typestring := sys.reflect(e); + typ := ParseTypeString("", typestring); + // Content of interface is a value; need a permanent copy to take its address + // so we can modify the contents. Values contain pointers to 'values'. + ap := new(uint64); + *ap = value; + return NewValueAddr(typ, PtrUint64ToAddr(ap)); +} |