1/*
2 * gomacro - A Go interpreter with Lisp-like macros
3 *
4 * Copyright (C) 2017-2019 Massimiliano Ghilardi
5 *
6 *     This Source Code Form is subject to the terms of the Mozilla Public
7 *     License, v. 2.0. If a copy of the MPL was not distributed with this
8 *     file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 *
11 * util.go
12 *
13 *  Created on May 07, 2017
14 *      Author Massimiliano Ghilardi
15 */
16
17package xreflect
18
19import (
20	"fmt"
21	"go/token"
22	"go/types"
23	"reflect"
24)
25
26func concat(a, b []int) []int {
27	na := len(a)
28	c := make([]int, na+len(b))
29	copy(c, a)
30	copy(c[na:], b)
31	return c
32}
33
34type Error struct {
35	Type   Type
36	format string
37	args   []interface{}
38}
39
40func (e *Error) Error() string {
41	return fmt.Sprintf(e.format, e.args...)
42}
43
44func errorf(t Type, format string, args ...interface{}) {
45	panic(&Error{t, format, args})
46}
47
48func xerrorf(t *xtype, format string, args ...interface{}) {
49	panic(&Error{wrap(t), format, args})
50}
51
52func dirToGdir(dir reflect.ChanDir) types.ChanDir {
53	var gdir types.ChanDir
54	switch dir {
55	case reflect.RecvDir:
56		gdir = types.RecvOnly
57	case reflect.SendDir:
58		gdir = types.SendOnly
59	case reflect.BothDir:
60		gdir = types.SendRecv
61	}
62	return gdir
63}
64
65func gtypeToKind(t *xtype, gtype types.Type) reflect.Kind {
66	gtype = gtype.Underlying()
67	var kind reflect.Kind
68	switch gtype := gtype.(type) {
69	case *types.Array:
70		kind = reflect.Array
71	case *types.Basic:
72		kind = ToReflectKind(gtype.Kind())
73	case *types.Chan:
74		kind = reflect.Chan
75	case *types.Signature:
76		kind = reflect.Func
77	case *types.Interface:
78		kind = reflect.Interface
79	case *types.Map:
80		kind = reflect.Map
81	case *types.Pointer:
82		kind = reflect.Ptr
83	case *types.Slice:
84		kind = reflect.Slice
85	case *types.Struct:
86		kind = reflect.Struct
87	// case *types.Named: // impossible, handled above
88	default:
89		xerrorf(t, "unsupported types.Type: %v", gtype)
90	}
91	// debugf("gtypeToKind(%T) -> %v", gtype, kind)
92	return kind
93}
94
95func IsGoUntypedKind(gkind types.BasicKind) bool {
96	switch gkind {
97	case types.UntypedBool, types.UntypedInt, types.UntypedRune,
98		types.UntypedFloat, types.UntypedComplex, types.UntypedString, types.UntypedNil:
99		return true
100	default:
101		return false
102	}
103}
104
105func ToReflectKind(gkind types.BasicKind) reflect.Kind {
106	var kind reflect.Kind
107	switch gkind {
108	case types.Bool, types.UntypedBool:
109		kind = reflect.Bool
110	case types.Int, types.UntypedInt:
111		kind = reflect.Int
112	case types.Int8:
113		kind = reflect.Int8
114	case types.Int16:
115		kind = reflect.Int16
116	case types.Int32, types.UntypedRune:
117		kind = reflect.Int32
118	case types.Int64:
119		kind = reflect.Int64
120	case types.Uint:
121		kind = reflect.Uint
122	case types.Uint8:
123		kind = reflect.Uint8
124	case types.Uint16:
125		kind = reflect.Uint16
126	case types.Uint32:
127		kind = reflect.Uint32
128	case types.Uint64:
129		kind = reflect.Uint64
130	case types.Uintptr:
131		kind = reflect.Uintptr
132	case types.Float32:
133		kind = reflect.Float32
134	case types.Float64, types.UntypedFloat:
135		kind = reflect.Float64
136	case types.Complex64:
137		kind = reflect.Complex64
138	case types.Complex128, types.UntypedComplex:
139		kind = reflect.Complex128
140	case types.String, types.UntypedString:
141		kind = reflect.String
142	case types.UnsafePointer:
143		kind = reflect.UnsafePointer
144	case types.UntypedNil:
145		kind = reflect.Invalid
146	default:
147		errorf(nil, "unsupported types.BasicKind: %v", gkind)
148	}
149	return kind
150}
151
152func ToBasicKind(kind reflect.Kind, untyped bool) types.BasicKind {
153	var gkind types.BasicKind
154	switch kind {
155	case reflect.Bool:
156		if untyped {
157			gkind = types.UntypedBool
158		} else {
159			gkind = types.Bool
160		}
161	case reflect.Int:
162		if untyped {
163			gkind = types.Int
164		} else {
165			gkind = types.UntypedInt
166		}
167	case reflect.Int8:
168		gkind = types.Int8
169	case reflect.Int16:
170		gkind = types.Int16
171	case reflect.Int32:
172		if untyped {
173			gkind = types.UntypedRune
174		} else {
175			gkind = types.Int32
176		}
177	case reflect.Int64:
178		gkind = types.Int64
179	case reflect.Uint:
180		gkind = types.Uint
181	case reflect.Uint8:
182		gkind = types.Uint8
183	case reflect.Uint16:
184		gkind = types.Uint16
185	case reflect.Uint32:
186		gkind = types.Uint32
187	case reflect.Uint64:
188		gkind = types.Uint64
189	case reflect.Uintptr:
190		gkind = types.Uintptr
191	case reflect.Float32:
192		gkind = types.Float32
193	case reflect.Float64:
194		if untyped {
195			gkind = types.UntypedFloat
196		} else {
197			gkind = types.Float64
198		}
199	case reflect.Complex64:
200		gkind = types.Complex64
201	case reflect.Complex128:
202		if untyped {
203			gkind = types.UntypedComplex
204		} else {
205			gkind = types.Complex128
206		}
207	case reflect.String:
208		if untyped {
209			gkind = types.UntypedString
210		} else {
211			gkind = types.String
212		}
213	case reflect.UnsafePointer:
214		gkind = types.UnsafePointer
215	case reflect.Invalid:
216		gkind = types.UntypedNil
217	default:
218		errorf(nil, "unsupported refletc.Kind: %v", kind)
219	}
220	return gkind
221}
222
223func path(gpkg *types.Package) string {
224	if gpkg == nil {
225		return ""
226	}
227	return gpkg.Path()
228}
229
230func toReflectTypes(ts []Type) []reflect.Type {
231	rts := make([]reflect.Type, len(ts))
232	for i, t := range ts {
233		rts[i] = t.ReflectType()
234	}
235	return rts
236}
237
238func toGoParam(t Type) *types.Var {
239	return types.NewParam(token.NoPos, nil, "", t.GoType())
240}
241
242func toGoParams(ts []Type) []*types.Var {
243	vars := make([]*types.Var, len(ts))
244	for i, t := range ts {
245		vars[i] = toGoParam(t)
246	}
247	return vars
248}
249
250func toGoTuple(ts []Type) *types.Tuple {
251	vars := toGoParams(ts)
252	return types.NewTuple(vars...)
253}
254