summaryrefslogtreecommitdiff
path: root/vm/type.go
blob: 58b6c4610a0be15ac2021326dfe79b52d4342112 (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
package vm

import "reflect"

// Runtime type and value representations (based on reflect).

// Type is the representation of a runtime type.
type Type struct {
	PkgPath string
	Name    string
	Rtype   reflect.Type
}

func (t *Type) String() string {
	if t.Name != "" {
		if t.PkgPath != "" {
			return t.PkgPath + "." + t.Name
		}
		return t.Name
	}
	return t.Rtype.String()
}

// Elem returns a type's element type.
func (t *Type) Elem() *Type {
	return &Type{Rtype: t.Rtype.Elem()}
}

// Out returns the type's i'th output parameter.
func (t *Type) Out(i int) *Type {
	return &Type{Rtype: t.Rtype.Out(i)}
}

// Value is the representation of a runtime value.
type Value struct {
	*Type
	reflect.Value
}

// NewValue returns an addressable zero value for the specified type.
func NewValue(typ *Type, arg ...int) Value {
	switch typ.Rtype.Kind() {
	case reflect.Slice:
		if len(arg) == 1 {
			v := reflect.New(typ.Rtype).Elem()
			v.Set(reflect.MakeSlice(typ.Rtype, arg[0], arg[0]))
			return Value{Type: typ, Value: v}
		}
	case reflect.Map:
		if len(arg) == 1 {
			v := reflect.New(typ.Rtype).Elem()
			v.Set(reflect.MakeMapWithSize(typ.Rtype, arg[0]))
			return Value{Type: typ, Value: v}
		}
	case reflect.Func:
		typ = TypeOf(0) // Function value is its index in the code segment.
	}
	return Value{Type: typ, Value: reflect.New(typ.Rtype).Elem()}
}

// TypeOf returns the runtime type of v.
func TypeOf(v any) *Type {
	t := reflect.TypeOf(v)
	return &Type{Name: t.Name(), Rtype: t}
}

// ValueOf returns the runtime value of v.
func ValueOf(v any) Value {
	return Value{Value: reflect.ValueOf(v)}
}

// PointerTo returns the pointer type with element t.
func PointerTo(t *Type) *Type {
	return &Type{Rtype: reflect.PointerTo(t.Rtype)}
}

// ArrayOf returns the array type with the given length and element type.
func ArrayOf(length int, t *Type) *Type {
	return &Type{Rtype: reflect.ArrayOf(length, t.Rtype)}
}

// SliceOf returns the slice type with the given element type.
func SliceOf(t *Type) *Type {
	return &Type{Rtype: reflect.SliceOf(t.Rtype)}
}

// MapOf returns the map type with the given key and element types.
func MapOf(k, e *Type) *Type {
	return &Type{Rtype: reflect.MapOf(k.Rtype, e.Rtype)}
}

// FuncOf returns the function type with the given argument and result types.
func FuncOf(arg, ret []*Type, variadic bool) *Type {
	a := make([]reflect.Type, len(arg))
	for i, e := range arg {
		a[i] = e.Rtype
	}
	r := make([]reflect.Type, len(ret))
	for i, e := range ret {
		r[i] = e.Rtype
	}
	return &Type{Rtype: reflect.FuncOf(a, r, variadic)}
}

// StructOf returns the struct type with the given field types.
func StructOf(fields []*Type) *Type {
	rf := make([]reflect.StructField, len(fields))
	for i, f := range fields {
		rf[i].Name = f.Name
		rf[i].PkgPath = f.PkgPath
		rf[i].Type = f.Rtype
	}
	return &Type{Rtype: reflect.StructOf(rf)}
}

// FieldIndex returns the index of struct field name.
func (t *Type) FieldIndex(name string) []int {
	for _, f := range reflect.VisibleFields(t.Rtype) {
		if f.Name == name {
			return f.Index
		}
	}
	return nil
}

// FieldType returns the type of struct field name.
func (t *Type) FieldType(name string) *Type {
	for _, f := range reflect.VisibleFields(t.Rtype) {
		if f.Name == name {
			return &Type{Name: f.Name, PkgPath: f.PkgPath, Rtype: f.Type}
		}
	}
	return nil
}

// IsPtr returns true if type t is of pointer kind.
func (t *Type) IsPtr() bool { return t.Rtype.Kind() == reflect.Pointer }