| // 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 eval |
| |
| import ( |
| "log"; |
| "go/token"; |
| "reflect"; |
| ) |
| |
| /* |
| * Type bridging |
| */ |
| |
| var ( |
| evalTypes = make(map[reflect.Type]Type); |
| nativeTypes = make(map[Type]reflect.Type); |
| ) |
| |
| // TypeFromNative converts a regular Go type into a the corresponding |
| // interpreter Type. |
| func TypeFromNative(t reflect.Type) Type { |
| if et, ok := evalTypes[t]; ok { |
| return et |
| } |
| |
| var nt *NamedType; |
| if t.Name() != "" { |
| name := t.PkgPath() + "ยท" + t.Name(); |
| nt = &NamedType{token.Position{}, name, nil, true, make(map[string]Method)}; |
| evalTypes[t] = nt; |
| } |
| |
| var et Type; |
| switch t := t.(type) { |
| case *reflect.BoolType: |
| et = BoolType |
| case *reflect.Float32Type: |
| et = Float32Type |
| case *reflect.Float64Type: |
| et = Float64Type |
| case *reflect.FloatType: |
| et = FloatType |
| case *reflect.Int16Type: |
| et = Int16Type |
| case *reflect.Int32Type: |
| et = Int32Type |
| case *reflect.Int64Type: |
| et = Int64Type |
| case *reflect.Int8Type: |
| et = Int8Type |
| case *reflect.IntType: |
| et = IntType |
| case *reflect.StringType: |
| et = StringType |
| case *reflect.Uint16Type: |
| et = Uint16Type |
| case *reflect.Uint32Type: |
| et = Uint32Type |
| case *reflect.Uint64Type: |
| et = Uint64Type |
| case *reflect.Uint8Type: |
| et = Uint8Type |
| case *reflect.UintType: |
| et = UintType |
| case *reflect.UintptrType: |
| et = UintptrType |
| |
| case *reflect.ArrayType: |
| et = NewArrayType(int64(t.Len()), TypeFromNative(t.Elem())) |
| case *reflect.ChanType: |
| log.Crashf("%T not implemented", t) |
| case *reflect.FuncType: |
| nin := t.NumIn(); |
| // Variadic functions have DotDotDotType at the end |
| varidic := false; |
| if nin > 0 { |
| if _, ok := t.In(nin - 1).(*reflect.DotDotDotType); ok { |
| varidic = true; |
| nin--; |
| } |
| } |
| in := make([]Type, nin); |
| for i := range in { |
| in[i] = TypeFromNative(t.In(i)) |
| } |
| out := make([]Type, t.NumOut()); |
| for i := range out { |
| out[i] = TypeFromNative(t.Out(i)) |
| } |
| et = NewFuncType(in, varidic, out); |
| case *reflect.InterfaceType: |
| log.Crashf("%T not implemented", t) |
| case *reflect.MapType: |
| log.Crashf("%T not implemented", t) |
| case *reflect.PtrType: |
| et = NewPtrType(TypeFromNative(t.Elem())) |
| case *reflect.SliceType: |
| et = NewSliceType(TypeFromNative(t.Elem())) |
| case *reflect.StructType: |
| n := t.NumField(); |
| fields := make([]StructField, n); |
| for i := 0; i < n; i++ { |
| sf := t.Field(i); |
| // TODO(austin) What to do about private fields? |
| fields[i].Name = sf.Name; |
| fields[i].Type = TypeFromNative(sf.Type); |
| fields[i].Anonymous = sf.Anonymous; |
| } |
| et = NewStructType(fields); |
| case *reflect.UnsafePointerType: |
| log.Crashf("%T not implemented", t) |
| default: |
| log.Crashf("unexpected reflect.Type: %T", t) |
| } |
| |
| if nt != nil { |
| if _, ok := et.(*NamedType); !ok { |
| nt.Complete(et); |
| et = nt; |
| } |
| } |
| |
| nativeTypes[et] = t; |
| evalTypes[t] = et; |
| |
| return et; |
| } |
| |
| // TypeOfNative returns the interpreter Type of a regular Go value. |
| func TypeOfNative(v interface{}) Type { return TypeFromNative(reflect.Typeof(v)) } |
| |
| /* |
| * Function bridging |
| */ |
| |
| type nativeFunc struct { |
| fn func(*Thread, []Value, []Value); |
| in, out int; |
| } |
| |
| func (f *nativeFunc) NewFrame() *Frame { |
| vars := make([]Value, f.in+f.out); |
| return &Frame{nil, vars}; |
| } |
| |
| func (f *nativeFunc) Call(t *Thread) { f.fn(t, t.f.Vars[0:f.in], t.f.Vars[f.in:f.in+f.out]) } |
| |
| // FuncFromNative creates an interpreter function from a native |
| // function that takes its in and out arguments as slices of |
| // interpreter Value's. While somewhat inconvenient, this avoids |
| // value marshalling. |
| func FuncFromNative(fn func(*Thread, []Value, []Value), t *FuncType) FuncValue { |
| return &funcV{&nativeFunc{fn, len(t.In), len(t.Out)}} |
| } |
| |
| // FuncFromNativeTyped is like FuncFromNative, but constructs the |
| // function type from a function pointer using reflection. Typically, |
| // the type will be given as a nil pointer to a function with the |
| // desired signature. |
| func FuncFromNativeTyped(fn func(*Thread, []Value, []Value), t interface{}) (*FuncType, FuncValue) { |
| ft := TypeOfNative(t).(*FuncType); |
| return ft, FuncFromNative(fn, ft); |
| } |