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 * init.go
12 *
13 *  Created on May 19, 2017
14 *      Author Massimiliano Ghilardi
15 */
16
17package xreflect
18
19import (
20	"reflect"
21	"unsafe"
22
23	"go/types"
24)
25
26var rbasictypes = []reflect.Type{
27	reflect.Bool:          reflect.TypeOf(bool(false)),
28	reflect.Int:           reflect.TypeOf(int(0)),
29	reflect.Int8:          reflect.TypeOf(int8(0)),
30	reflect.Int16:         reflect.TypeOf(int16(0)),
31	reflect.Int32:         reflect.TypeOf(int32(0)),
32	reflect.Int64:         reflect.TypeOf(int64(0)),
33	reflect.Uint:          reflect.TypeOf(uint(0)),
34	reflect.Uint8:         reflect.TypeOf(uint8(0)),
35	reflect.Uint16:        reflect.TypeOf(uint16(0)),
36	reflect.Uint32:        reflect.TypeOf(uint32(0)),
37	reflect.Uint64:        reflect.TypeOf(uint64(0)),
38	reflect.Uintptr:       reflect.TypeOf(uintptr(0)),
39	reflect.Float32:       reflect.TypeOf(float32(0)),
40	reflect.Float64:       reflect.TypeOf(float64(0)),
41	reflect.Complex64:     reflect.TypeOf(complex64(0)),
42	reflect.Complex128:    reflect.TypeOf(complex128(0)),
43	reflect.String:        reflect.TypeOf(string("")),
44	reflect.UnsafePointer: reflect.TypeOf(unsafe.Pointer(nil)),
45}
46
47var ReflectBasicTypes = rbasictypes
48
49func (v *Universe) makeBasicTypes() []Type {
50	m := make([]Type, len(rbasictypes))
51	for gkind := types.Bool; gkind <= types.UnsafePointer; gkind++ {
52		kind := ToReflectKind(gkind)
53		gtype := types.Typ[gkind]
54		rtype := rbasictypes[kind]
55		if gtype == nil || rtype == nil {
56			continue
57		}
58		t := wrap(&xtype{kind: kind, gtype: gtype, rtype: rtype, universe: v})
59		v.add(t)
60		m[kind] = t
61	}
62	return m
63}
64
65func (v *Universe) makeError() Type {
66	t := wrap(&xtype{
67		kind:     reflect.Interface,
68		gtype:    types.Universe.Lookup("error").Type(),
69		rtype:    reflect.TypeOf((*error)(nil)).Elem(),
70		universe: v,
71	})
72	v.add(t)
73	return t
74}
75
76func (v *Universe) makeInterface() Type {
77	t := wrap(&xtype{
78		kind:     reflect.Interface,
79		gtype:    types.NewInterface(nil, nil).Complete(),
80		rtype:    rTypeOfInterface,
81		universe: v,
82	})
83	v.add(t)
84	return t
85}
86
87func (v *Universe) makeForward() Type {
88	t := wrap(&xtype{
89		kind:     reflect.Invalid,
90		gtype:    types.NewInterface(nil, nil).Complete(),
91		rtype:    rTypeOfForward,
92		universe: v,
93	})
94	v.add(t)
95	return t
96}
97
98func NewUniverse() *Universe {
99	v := &Universe{}
100	v.BasicTypes = v.makeBasicTypes()
101	v.TypeOfForward = v.makeForward()
102	v.TypeOfInterface = v.makeInterface()
103	v.TypeOfError = v.makeError()
104	// critical! trying to rebuild "error" type creates a non-indentical copy... lots of conversions would fail
105	v.cache(v.TypeOfError.ReflectType(), v.TypeOfError)
106	v.cache(v.TypeOfInterface.ReflectType(), v.TypeOfInterface)
107	return v
108}
109
110const MaxDepth = int(^uint(0) >> 1)
111
112var (
113	rTypeOfInterface       = reflect.TypeOf((*interface{})(nil)).Elem()
114	rTypeOfInterfaceHeader = reflect.TypeOf(InterfaceHeader{})
115	rTypeOfForward         = reflect.TypeOf((*Forward)(nil)).Elem()
116)
117
118// Bits returns the size of the type in bits.
119// It panics if the type's Kind is not one of the
120// sized or unsized Int, Uint, Float, or Complex kinds.
121func (t *xtype) Bits() int {
122	return t.rtype.Bits()
123}
124
125// Align returns the alignment in bytes of a value of
126// this type when allocated in memory.
127func (t *xtype) Align() int {
128	return t.rtype.Align()
129}
130
131// FieldAlign returns the alignment in bytes of a value of
132// this type when used as a field in a struct.
133func (t *xtype) FieldAlign() int {
134	return t.rtype.FieldAlign()
135}
136