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 * func_ret1.go
12 *
13 *  Created on Apr 16, 2017
14 *      Author Massimiliano Ghilardi
15 */
16
17package fast
18
19import (
20	r "reflect"
21	"unsafe"
22
23	. "github.com/cosmos72/gomacro/base"
24	xr "github.com/cosmos72/gomacro/xreflect"
25)
26
27:import (
28	r "reflect"
29	"go/ast"
30)
31
32
33:func upcasefirstbyte(str string) string {
34	if len(str) > 0 && str[0] >= 'a' && str[0] <= 'z' {
35		bytes := []byte(str)
36		bytes[0] -= 'a' - 'A'
37		return string(bytes)
38	}
39	return str
40}
41
42:func makeprefixtypeident(prefix string, t r.Type) *ast.Ident {
43	name := prefix + upcasefirstbyte(t.Name())
44	return &ast.Ident{Name: name}
45}
46
47// convert a well-known reflect.Type into one of the constants TypeOf*
48:func maketypeident(t r.Type) *ast.Ident {
49	return makeprefixtypeident("TypeOf", t)
50}
51
52:macro mcallfunc1retx1(typ ast.Node) ast.Node {
53	var t r.Type = EvalType(typ)
54	ident := makeprefixtypeident("func1ret1", t)
55	return ~"{
56		ret = ~,ident (m, indexes, kret0, debugC)
57	}
58}
59
60:macro mcallfuncx1retx1(dummy ast.Node) ast.Node {
61	return ~"{
62		switch karg0 {
63		case r.Bool:      {mcallfunc1retx1; bool}
64		case r.Int:       {mcallfunc1retx1; int}
65		case r.Int8:      {mcallfunc1retx1; int8}
66		case r.Int16:     {mcallfunc1retx1; int16}
67		case r.Int32:     {mcallfunc1retx1; int32}
68		case r.Int64:     {mcallfunc1retx1; int64}
69		case r.Uint:      {mcallfunc1retx1; uint}
70		case r.Uint8:     {mcallfunc1retx1; uint8}
71		case r.Uint16:    {mcallfunc1retx1; uint16}
72		case r.Uint32:    {mcallfunc1retx1; uint32}
73		case r.Uint64:    {mcallfunc1retx1; uint64}
74		case r.Uintptr:   {mcallfunc1retx1; uintptr}
75		case r.Float32:   {mcallfunc1retx1; float32}
76		case r.Float64:   {mcallfunc1retx1; float64}
77		case r.Complex64: {mcallfunc1retx1; complex64}
78		case r.Complex128:{mcallfunc1retx1; complex128}
79		case r.String:    {mcallfunc1retx1; string}
80		}
81	}
82}
83
84// ==================================== func1ret1 ========================================
85
86func (c *Comp) func1ret1(t xr.Type, m *funcMaker) func(*Env) r.Value {
87	var debugC *Comp
88	if c.Globals.Options&OptDebugger != 0 {
89		// keep a reference to c only if needed
90		debugC = c
91	}
92	karg0 := t.In(0).Kind()
93	kret0 := t.Out(0).Kind()
94
95	indexes := &[2]int{
96		m.Param[0].Desc.Index(),
97		m.Result[0].Desc.Index(),
98	}
99	var ret func(*Env) r.Value
100
101	// if IsOptimizedKind(karg0) && IsOptimizedKind(kret0)
102	mcallfuncx1retx1; nil
103
104	return ret
105}
106
107// ==================================== func1ret1{Bool,Int,...} ========================================
108
109:func fsetarg(typ, name, index ast.Node) ast.Node {
110	var t r.Type = EvalType(typ)
111	var bind ast.Node
112	typeident := maketypeident(t)
113	switch t.Kind() {
114		case r.String:
115			bind = ~"{
116				place := r.New(~,typeident).Elem()
117				place.SetString(~,name)
118				env.Vals[~,index] = place
119			}
120		case r.Uint64:
121			bind = ~"{env.Ints[~,index] = ~,name}
122		default:
123			bind = ~"{*(*~,typ)(unsafe.Pointer(&env.Ints[~,index])) = ~,name}
124	}
125	return bind
126}
127
128:func fgetresult(typ, index ast.Node) ast.Node {
129	var t r.Type = EvalType(typ)
130	var bind ast.Node
131	if t == nil {
132		bind = ~"{env.Vals[~,index]}
133	} else {
134		typeident := maketypeident(t)
135		switch t.Kind() {
136			case r.String:
137				bind = ~"{env.Vals[~,index].String()}
138			case r.Uint64:
139				bind = ~"{env.Ints[~,index]}
140			default:
141				bind = ~"{*(*~,typ)(unsafe.Pointer(&env.Ints[~,index]))}
142		}
143	}
144	return bind
145}
146
147// ----------------- func(t0) t1 ---------------------
148
149// generate fully optimized function implementation for func(arg0typ) ret0typ
150:macro mfunc1ret1(arg0typ, ret0typ ast.Node) ast.Node {
151	arg0bind := fsetarg(arg0typ, ~'arg0, ~'{indexes[0]})
152	ret0bind := fgetresult(ret0typ, ~'{indexes[1]})
153	return ~"{
154		if funcbody == nil {
155			funv := r.ValueOf(func(~,arg0typ) (ret0 ~,ret0typ) {
156				return
157			})
158			ret = func(env *Env) r.Value {
159				return funv
160			}
161			break
162		}
163		ret = func(env *Env) r.Value {
164			// function is closed over the env used to DECLARE it
165			env.MarkUsedByClosure()
166			return r.ValueOf(func(arg0 ~,arg0typ) (ret0 ~,ret0typ) {
167				env := newEnv4Func(env, nbind, nintbind, debugC)
168
169				// copy arg into allocated binds
170				~,arg0bind
171
172				// execute the body
173				funcbody(env)
174
175				// extract result
176				ret0 = ~,ret0bind
177				env.freeEnv4Func()
178				return
179			})
180		}
181	}
182}
183
184:macro mfunc1retx1(arg0typ ast.Node) ast.Node {
185	return ~"{
186		switch kret0 {
187		case r.Bool:      {mfunc1ret1; ~,arg0typ; bool}
188		case r.Int:       {mfunc1ret1; ~,arg0typ; int}
189		case r.Int8:      {mfunc1ret1; ~,arg0typ; int8}
190		case r.Int16:     {mfunc1ret1; ~,arg0typ; int16}
191		case r.Int32:     {mfunc1ret1; ~,arg0typ; int32}
192		case r.Int64:     {mfunc1ret1; ~,arg0typ; int64}
193		case r.Uint:      {mfunc1ret1; ~,arg0typ; uint}
194		case r.Uint8:     {mfunc1ret1; ~,arg0typ; uint8}
195		case r.Uint16:    {mfunc1ret1; ~,arg0typ; uint16}
196		case r.Uint32:    {mfunc1ret1; ~,arg0typ; uint32}
197		case r.Uint64:    {mfunc1ret1; ~,arg0typ; uint64}
198		case r.Uintptr:   {mfunc1ret1; ~,arg0typ; uintptr}
199		case r.Float32:   {mfunc1ret1; ~,arg0typ; float32}
200		case r.Float64:   {mfunc1ret1; ~,arg0typ; float64}
201		case r.Complex64: {mfunc1ret1; ~,arg0typ; complex64}
202		case r.Complex128:{mfunc1ret1; ~,arg0typ; complex128}
203		case r.String:    {mfunc1ret1; ~,arg0typ; string}
204		}
205	}
206}
207
208:macro mdeclfunc1retx1(arg0typ ast.Node) ast.Node {
209	decl := ~"{
210		~func foo (m *funcMaker, indexes *[2]int, kret0 r.Kind, debugC *Comp) func(*Env) r.Value {
211			// do NOT keep a reference to funcMaker
212			nbind := m.nbind
213			nintbind := m.nintbind
214			funcbody := m.funcbody
215			var ret func(*Env) r.Value
216
217			mfunc1retx1; ~,arg0typ
218
219			return ret
220		}
221	}
222	var t r.Type = EvalType(arg0typ)
223	decl.Name = makeprefixtypeident("func1ret1", t)
224	return decl
225}
226
227mdeclfunc1retx1; bool
228mdeclfunc1retx1; int
229mdeclfunc1retx1; int8
230mdeclfunc1retx1; int16
231mdeclfunc1retx1; int32
232mdeclfunc1retx1; int64
233mdeclfunc1retx1; uint
234mdeclfunc1retx1; uint8
235mdeclfunc1retx1; uint16
236mdeclfunc1retx1; uint32
237mdeclfunc1retx1; uint64
238mdeclfunc1retx1; uintptr
239mdeclfunc1retx1; float32
240mdeclfunc1retx1; float64
241mdeclfunc1retx1; complex64
242mdeclfunc1retx1; complex128
243mdeclfunc1retx1; string
244