--- /dev/null
+// Copyright 2013 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 interp
+
+// Emulated "reflect" package.
+//
+// We completely replace the built-in "reflect" package.
+// The only thing clients can depend upon are that reflect.Type is an
+// interface and reflect.Value is an (opaque) struct.
+
+import (
+ "fmt"
+ "go/token"
+ "go/types"
+ "reflect"
+ "unsafe"
+
+ "golang.org/x/tools/go/ssa"
+)
+
+type opaqueType struct {
+ types.Type
+ name string
+}
+
+func (t *opaqueType) String() string { return t.name }
+
+// A bogus "reflect" type-checker package. Shared across interpreters.
+var reflectTypesPackage = types.NewPackage("reflect", "reflect")
+
+// rtype is the concrete type the interpreter uses to implement the
+// reflect.Type interface.
+//
+// type rtype <opaque>
+var rtypeType = makeNamedType("rtype", &opaqueType{nil, "rtype"})
+
+// error is an (interpreted) named type whose underlying type is string.
+// The interpreter uses it for all implementations of the built-in error
+// interface that it creates.
+// We put it in the "reflect" package for expedience.
+//
+// type error string
+var errorType = makeNamedType("error", &opaqueType{nil, "error"})
+
+func makeNamedType(name string, underlying types.Type) *types.Named {
+ obj := types.NewTypeName(token.NoPos, reflectTypesPackage, name, nil)
+ return types.NewNamed(obj, underlying, nil)
+}
+
+func makeReflectValue(t types.Type, v value) value {
+ return structure{rtype{t}, v}
+}
+
+// Given a reflect.Value, returns its rtype.
+func rV2T(v value) rtype {
+ return v.(structure)[0].(rtype)
+}
+
+// Given a reflect.Value, returns the underlying interpreter value.
+func rV2V(v value) value {
+ return v.(structure)[1]
+}
+
+// makeReflectType boxes up an rtype in a reflect.Type interface.
+func makeReflectType(rt rtype) value {
+ return iface{rtypeType, rt}
+}
+
+func ext۰reflect۰rtype۰Bits(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) int
+ rt := args[0].(rtype).t
+ basic, ok := rt.Underlying().(*types.Basic)
+ if !ok {
+ panic(fmt.Sprintf("reflect.Type.Bits(%T): non-basic type", rt))
+ }
+ return int(fr.i.sizes.Sizeof(basic)) * 8
+}
+
+func ext۰reflect۰rtype۰Elem(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) reflect.Type
+ return makeReflectType(rtype{args[0].(rtype).t.Underlying().(interface {
+ Elem() types.Type
+ }).Elem()})
+}
+
+func ext۰reflect۰rtype۰Field(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype, i int) reflect.StructField
+ st := args[0].(rtype).t.Underlying().(*types.Struct)
+ i := args[1].(int)
+ f := st.Field(i)
+ return structure{
+ f.Name(),
+ f.Pkg().Path(),
+ makeReflectType(rtype{f.Type()}),
+ st.Tag(i),
+ 0, // TODO(adonovan): offset
+ []value{}, // TODO(adonovan): indices
+ f.Anonymous(),
+ }
+}
+
+func ext۰reflect۰rtype۰In(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype, i int) int
+ i := args[1].(int)
+ return makeReflectType(rtype{args[0].(rtype).t.(*types.Signature).Params().At(i).Type()})
+}
+
+func ext۰reflect۰rtype۰Kind(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) uint
+ return uint(reflectKind(args[0].(rtype).t))
+}
+
+func ext۰reflect۰rtype۰NumField(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) int
+ return args[0].(rtype).t.Underlying().(*types.Struct).NumFields()
+}
+
+func ext۰reflect۰rtype۰NumIn(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) int
+ return args[0].(rtype).t.(*types.Signature).Params().Len()
+}
+
+func ext۰reflect۰rtype۰NumMethod(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) int
+ return fr.i.prog.MethodSets.MethodSet(args[0].(rtype).t).Len()
+}
+
+func ext۰reflect۰rtype۰NumOut(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) int
+ return args[0].(rtype).t.(*types.Signature).Results().Len()
+}
+
+func ext۰reflect۰rtype۰Out(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype, i int) int
+ i := args[1].(int)
+ return makeReflectType(rtype{args[0].(rtype).t.(*types.Signature).Results().At(i).Type()})
+}
+
+func ext۰reflect۰rtype۰Size(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) uintptr
+ return uintptr(fr.i.sizes.Sizeof(args[0].(rtype).t))
+}
+
+func ext۰reflect۰rtype۰String(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) string
+ return args[0].(rtype).t.String()
+}
+
+func ext۰reflect۰New(fr *frame, args []value) value {
+ // Signature: func (t reflect.Type) reflect.Value
+ t := args[0].(iface).v.(rtype).t
+ alloc := zero(t)
+ return makeReflectValue(types.NewPointer(t), &alloc)
+}
+
+func ext۰reflect۰SliceOf(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) Type
+ return makeReflectType(rtype{types.NewSlice(args[0].(iface).v.(rtype).t)})
+}
+
+func ext۰reflect۰TypeOf(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) Type
+ return makeReflectType(rtype{args[0].(iface).t})
+}
+
+func ext۰reflect۰ValueOf(fr *frame, args []value) value {
+ // Signature: func (interface{}) reflect.Value
+ itf := args[0].(iface)
+ return makeReflectValue(itf.t, itf.v)
+}
+
+func ext۰reflect۰Zero(fr *frame, args []value) value {
+ // Signature: func (t reflect.Type) reflect.Value
+ t := args[0].(iface).v.(rtype).t
+ return makeReflectValue(t, zero(t))
+}
+
+func reflectKind(t types.Type) reflect.Kind {
+ switch t := t.(type) {
+ case *types.Named:
+ return reflectKind(t.Underlying())
+ case *types.Basic:
+ switch t.Kind() {
+ case types.Bool:
+ return reflect.Bool
+ case types.Int:
+ return reflect.Int
+ case types.Int8:
+ return reflect.Int8
+ case types.Int16:
+ return reflect.Int16
+ case types.Int32:
+ return reflect.Int32
+ case types.Int64:
+ return reflect.Int64
+ case types.Uint:
+ return reflect.Uint
+ case types.Uint8:
+ return reflect.Uint8
+ case types.Uint16:
+ return reflect.Uint16
+ case types.Uint32:
+ return reflect.Uint32
+ case types.Uint64:
+ return reflect.Uint64
+ case types.Uintptr:
+ return reflect.Uintptr
+ case types.Float32:
+ return reflect.Float32
+ case types.Float64:
+ return reflect.Float64
+ case types.Complex64:
+ return reflect.Complex64
+ case types.Complex128:
+ return reflect.Complex128
+ case types.String:
+ return reflect.String
+ case types.UnsafePointer:
+ return reflect.UnsafePointer
+ }
+ case *types.Array:
+ return reflect.Array
+ case *types.Chan:
+ return reflect.Chan
+ case *types.Signature:
+ return reflect.Func
+ case *types.Interface:
+ return reflect.Interface
+ case *types.Map:
+ return reflect.Map
+ case *types.Pointer:
+ return reflect.Ptr
+ case *types.Slice:
+ return reflect.Slice
+ case *types.Struct:
+ return reflect.Struct
+ }
+ panic(fmt.Sprint("unexpected type: ", t))
+}
+
+func ext۰reflect۰Value۰Kind(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) uint
+ return uint(reflectKind(rV2T(args[0]).t))
+}
+
+func ext۰reflect۰Value۰String(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) string
+ return toString(rV2V(args[0]))
+}
+
+func ext۰reflect۰Value۰Type(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) reflect.Type
+ return makeReflectType(rV2T(args[0]))
+}
+
+func ext۰reflect۰Value۰Uint(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) uint64
+ switch v := rV2V(args[0]).(type) {
+ case uint:
+ return uint64(v)
+ case uint8:
+ return uint64(v)
+ case uint16:
+ return uint64(v)
+ case uint32:
+ return uint64(v)
+ case uint64:
+ return uint64(v)
+ case uintptr:
+ return uint64(v)
+ }
+ panic("reflect.Value.Uint")
+}
+
+func ext۰reflect۰Value۰Len(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) int
+ switch v := rV2V(args[0]).(type) {
+ case string:
+ return len(v)
+ case array:
+ return len(v)
+ case chan value:
+ return cap(v)
+ case []value:
+ return len(v)
+ case *hashmap:
+ return v.len()
+ case map[value]value:
+ return len(v)
+ default:
+ panic(fmt.Sprintf("reflect.(Value).Len(%v)", v))
+ }
+}
+
+func ext۰reflect۰Value۰MapIndex(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) Value
+ tValue := rV2T(args[0]).t.Underlying().(*types.Map).Key()
+ k := rV2V(args[1])
+ switch m := rV2V(args[0]).(type) {
+ case map[value]value:
+ if v, ok := m[k]; ok {
+ return makeReflectValue(tValue, v)
+ }
+
+ case *hashmap:
+ if v := m.lookup(k.(hashable)); v != nil {
+ return makeReflectValue(tValue, v)
+ }
+
+ default:
+ panic(fmt.Sprintf("(reflect.Value).MapIndex(%T, %T)", m, k))
+ }
+ return makeReflectValue(nil, nil)
+}
+
+func ext۰reflect۰Value۰MapKeys(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) []Value
+ var keys []value
+ tKey := rV2T(args[0]).t.Underlying().(*types.Map).Key()
+ switch v := rV2V(args[0]).(type) {
+ case map[value]value:
+ for k := range v {
+ keys = append(keys, makeReflectValue(tKey, k))
+ }
+
+ case *hashmap:
+ for _, e := range v.entries() {
+ for ; e != nil; e = e.next {
+ keys = append(keys, makeReflectValue(tKey, e.key))
+ }
+ }
+
+ default:
+ panic(fmt.Sprintf("(reflect.Value).MapKeys(%T)", v))
+ }
+ return keys
+}
+
+func ext۰reflect۰Value۰NumField(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) int
+ return len(rV2V(args[0]).(structure))
+}
+
+func ext۰reflect۰Value۰NumMethod(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) int
+ return fr.i.prog.MethodSets.MethodSet(rV2T(args[0]).t).Len()
+}
+
+func ext۰reflect۰Value۰Pointer(fr *frame, args []value) value {
+ // Signature: func (v reflect.Value) uintptr
+ switch v := rV2V(args[0]).(type) {
+ case *value:
+ return uintptr(unsafe.Pointer(v))
+ case chan value:
+ return reflect.ValueOf(v).Pointer()
+ case []value:
+ return reflect.ValueOf(v).Pointer()
+ case *hashmap:
+ return reflect.ValueOf(v.entries()).Pointer()
+ case map[value]value:
+ return reflect.ValueOf(v).Pointer()
+ case *ssa.Function:
+ return uintptr(unsafe.Pointer(v))
+ case *closure:
+ return uintptr(unsafe.Pointer(v))
+ default:
+ panic(fmt.Sprintf("reflect.(Value).Pointer(%T)", v))
+ }
+}
+
+func ext۰reflect۰Value۰Index(fr *frame, args []value) value {
+ // Signature: func (v reflect.Value, i int) Value
+ i := args[1].(int)
+ t := rV2T(args[0]).t.Underlying()
+ switch v := rV2V(args[0]).(type) {
+ case array:
+ return makeReflectValue(t.(*types.Array).Elem(), v[i])
+ case []value:
+ return makeReflectValue(t.(*types.Slice).Elem(), v[i])
+ default:
+ panic(fmt.Sprintf("reflect.(Value).Index(%T)", v))
+ }
+}
+
+func ext۰reflect۰Value۰Bool(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) bool
+ return rV2V(args[0]).(bool)
+}
+
+func ext۰reflect۰Value۰CanAddr(fr *frame, args []value) value {
+ // Signature: func (v reflect.Value) bool
+ // Always false for our representation.
+ return false
+}
+
+func ext۰reflect۰Value۰CanInterface(fr *frame, args []value) value {
+ // Signature: func (v reflect.Value) bool
+ // Always true for our representation.
+ return true
+}
+
+func ext۰reflect۰Value۰Elem(fr *frame, args []value) value {
+ // Signature: func (v reflect.Value) reflect.Value
+ switch x := rV2V(args[0]).(type) {
+ case iface:
+ return makeReflectValue(x.t, x.v)
+ case *value:
+ return makeReflectValue(rV2T(args[0]).t.Underlying().(*types.Pointer).Elem(), *x)
+ default:
+ panic(fmt.Sprintf("reflect.(Value).Elem(%T)", x))
+ }
+}
+
+func ext۰reflect۰Value۰Field(fr *frame, args []value) value {
+ // Signature: func (v reflect.Value, i int) reflect.Value
+ v := args[0]
+ i := args[1].(int)
+ return makeReflectValue(rV2T(v).t.Underlying().(*types.Struct).Field(i).Type(), rV2V(v).(structure)[i])
+}
+
+func ext۰reflect۰Value۰Float(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) float64
+ switch v := rV2V(args[0]).(type) {
+ case float32:
+ return float64(v)
+ case float64:
+ return float64(v)
+ }
+ panic("reflect.Value.Float")
+}
+
+func ext۰reflect۰Value۰Interface(fr *frame, args []value) value {
+ // Signature: func (v reflect.Value) interface{}
+ return ext۰reflect۰valueInterface(fr, args)
+}
+
+func ext۰reflect۰Value۰Int(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) int64
+ switch x := rV2V(args[0]).(type) {
+ case int:
+ return int64(x)
+ case int8:
+ return int64(x)
+ case int16:
+ return int64(x)
+ case int32:
+ return int64(x)
+ case int64:
+ return x
+ default:
+ panic(fmt.Sprintf("reflect.(Value).Int(%T)", x))
+ }
+}
+
+func ext۰reflect۰Value۰IsNil(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) bool
+ switch x := rV2V(args[0]).(type) {
+ case *value:
+ return x == nil
+ case chan value:
+ return x == nil
+ case map[value]value:
+ return x == nil
+ case *hashmap:
+ return x == nil
+ case iface:
+ return x.t == nil
+ case []value:
+ return x == nil
+ case *ssa.Function:
+ return x == nil
+ case *ssa.Builtin:
+ return x == nil
+ case *closure:
+ return x == nil
+ default:
+ panic(fmt.Sprintf("reflect.(Value).IsNil(%T)", x))
+ }
+}
+
+func ext۰reflect۰Value۰IsValid(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) bool
+ return rV2V(args[0]) != nil
+}
+
+func ext۰reflect۰Value۰Set(fr *frame, args []value) value {
+ // TODO(adonovan): implement.
+ return nil
+}
+
+func ext۰reflect۰valueInterface(fr *frame, args []value) value {
+ // Signature: func (v reflect.Value, safe bool) interface{}
+ v := args[0].(structure)
+ return iface{rV2T(v).t, rV2V(v)}
+}
+
+func ext۰reflect۰error۰Error(fr *frame, args []value) value {
+ return args[0]
+}
+
+// newMethod creates a new method of the specified name, package and receiver type.
+func newMethod(pkg *ssa.Package, recvType types.Type, name string) *ssa.Function {
+ // TODO(adonovan): fix: hack: currently the only part of Signature
+ // that is needed is the "pointerness" of Recv.Type, and for
+ // now, we'll set it to always be false since we're only
+ // concerned with rtype. Encapsulate this better.
+ sig := types.NewSignature(types.NewVar(token.NoPos, nil, "recv", recvType), nil, nil, false)
+ fn := pkg.Prog.NewFunction(name, sig, "fake reflect method")
+ fn.Pkg = pkg
+ return fn
+}
+
+func initReflect(i *interpreter) {
+ i.reflectPackage = &ssa.Package{
+ Prog: i.prog,
+ Pkg: reflectTypesPackage,
+ Members: make(map[string]ssa.Member),
+ }
+
+ // Clobber the type-checker's notion of reflect.Value's
+ // underlying type so that it more closely matches the fake one
+ // (at least in the number of fields---we lie about the type of
+ // the rtype field).
+ //
+ // We must ensure that calls to (ssa.Value).Type() return the
+ // fake type so that correct "shape" is used when allocating
+ // variables, making zero values, loading, and storing.
+ //
+ // TODO(adonovan): obviously this is a hack. We need a cleaner
+ // way to fake the reflect package (almost---DeepEqual is fine).
+ // One approach would be not to even load its source code, but
+ // provide fake source files. This would guarantee that no bad
+ // information leaks into other packages.
+ if r := i.prog.ImportedPackage("reflect"); r != nil {
+ rV := r.Pkg.Scope().Lookup("Value").Type().(*types.Named)
+
+ // delete bodies of the old methods
+ mset := i.prog.MethodSets.MethodSet(rV)
+ for j := 0; j < mset.Len(); j++ {
+ i.prog.MethodValue(mset.At(j)).Blocks = nil
+ }
+
+ tEface := types.NewInterface(nil, nil).Complete()
+ rV.SetUnderlying(types.NewStruct([]*types.Var{
+ types.NewField(token.NoPos, r.Pkg, "t", tEface, false), // a lie
+ types.NewField(token.NoPos, r.Pkg, "v", tEface, false),
+ }, nil))
+ }
+
+ i.rtypeMethods = methodSet{
+ "Bits": newMethod(i.reflectPackage, rtypeType, "Bits"),
+ "Elem": newMethod(i.reflectPackage, rtypeType, "Elem"),
+ "Field": newMethod(i.reflectPackage, rtypeType, "Field"),
+ "In": newMethod(i.reflectPackage, rtypeType, "In"),
+ "Kind": newMethod(i.reflectPackage, rtypeType, "Kind"),
+ "NumField": newMethod(i.reflectPackage, rtypeType, "NumField"),
+ "NumIn": newMethod(i.reflectPackage, rtypeType, "NumIn"),
+ "NumMethod": newMethod(i.reflectPackage, rtypeType, "NumMethod"),
+ "NumOut": newMethod(i.reflectPackage, rtypeType, "NumOut"),
+ "Out": newMethod(i.reflectPackage, rtypeType, "Out"),
+ "Size": newMethod(i.reflectPackage, rtypeType, "Size"),
+ "String": newMethod(i.reflectPackage, rtypeType, "String"),
+ }
+ i.errorMethods = methodSet{
+ "Error": newMethod(i.reflectPackage, errorType, "Error"),
+ }
+}