summaryrefslogtreecommitdiff
path: root/src/pkg/exp/eval/bridge.go
blob: f31d9ab9bd6e0bcf124dda6e6edbd807ec75639f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// 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.NoPos, name, nil, true, make(map[string]Method)}
		evalTypes[t] = nt
	}

	var et Type
	switch t.Kind() {
	case reflect.Bool:
		et = BoolType

	case reflect.Float32:
		et = Float32Type
	case reflect.Float64:
		et = Float64Type

	case reflect.Int16:
		et = Int16Type
	case reflect.Int32:
		et = Int32Type
	case reflect.Int64:
		et = Int64Type
	case reflect.Int8:
		et = Int8Type
	case reflect.Int:
		et = IntType

	case reflect.Uint16:
		et = Uint16Type
	case reflect.Uint32:
		et = Uint32Type
	case reflect.Uint64:
		et = Uint64Type
	case reflect.Uint8:
		et = Uint8Type
	case reflect.Uint:
		et = UintType
	case reflect.Uintptr:
		et = UintptrType

	case reflect.String:
		et = StringType
	case reflect.Array:
		et = NewArrayType(int64(t.Len()), TypeFromNative(t.Elem()))
	case reflect.Chan:
		log.Panicf("%T not implemented", t)
	case reflect.Func:
		nin := t.NumIn()
		// Variadic functions have DotDotDotType at the end
		variadic := t.IsVariadic()
		if variadic {
			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, variadic, out)
	case reflect.Interface:
		log.Panicf("%T not implemented", t)
	case reflect.Map:
		log.Panicf("%T not implemented", t)
	case reflect.Ptr:
		et = NewPtrType(TypeFromNative(t.Elem()))
	case reflect.Slice:
		et = NewSliceType(TypeFromNative(t.Elem()))
	case reflect.Struct:
		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.UnsafePointer:
		log.Panicf("%T not implemented", t)
	default:
		log.Panicf("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)
}