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 * callnret0.go
12 *
13 *  Created on Apr 15, 2017
14 *      Author Massimiliano Ghilardi
15 */
16
17package fast
18
19import (
20	r "reflect"
21	"github.com/cosmos72/gomacro/base/reflect"
22)
23
24:import (
25	"go/ast"
26	"go/token"
27	r "reflect"
28)
29
30:func upcasefirstbyte(str string) string {
31	if len(str) > 0 && str[0] >= 'a' && str[0] <= 'z' {
32		bytes := []byte(str)
33		bytes[0] -= 'a' - 'A'
34		return string(bytes)
35	}
36	return str
37}
38
39:func makekind(typ ast.Node) ast.Node {
40	t := EvalType(typ)
41
42	// go/ast.SelectorExpr requires the foo in r.foo to be an *ast.Ident, cannot unquote there
43	kind := ~"{r . foo}
44	kind.Sel = &ast.Ident{Name: upcasefirstbyte(t.Name())}
45	return kind
46}
47
48:func convertvalue1(typ, val ast.Node) ast.Node {
49	var t r.Type = EvalType(typ)
50	if t == nil {
51		// keep the result wrapped in a reflect.Value
52		return val
53	}
54	// unwrap the result
55	tname := t.Name()
56	// remove final digits from t.Name()
57	// needed to convert Uint64 -> Uint etc. to calls reflect.Value.{tname}
58	for len(tname) != 0 {
59		ch := tname[len(tname)-1]
60		if ch < '0' || ch > '9' {
61			break
62		}
63		tname = tname[0:len(tname)-1]
64	}
65	if tname == "uintptr" {
66		tname = "uint" // use reflect.Value.Uint()
67	}
68	sel := ~"{~,val . foo} // we modify it destructively
69	sel.Sel = &ast.Ident{Name: upcasefirstbyte(tname)}
70
71	switch t.Kind() {
72	case r.Bool, r.Int64, r.Uint64, r.Float64, r.Complex128, r.String:
73		// result of reflect.Value.{tname} is already the correct type
74		val = ~"{~,sel ()}
75	default:
76		// convert int64, uint64... to the correct type
77		val = ~"{~,typ ( ~,sel () )}
78	}
79	return val
80}
81
82func (c *Comp) call0ret0(call *Call, maxdepth int) func(env *Env) {
83	expr := call.Fun
84	funsym := expr.Sym
85	if funsym == nil {
86		exprfun := expr.AsX1()
87		return func(env *Env) {
88			fun := exprfun(env).Interface().(func())
89			fun()
90		}
91	}
92
93	var cachedfunv r.Value
94	var cachedfun func()
95
96	funupn := funsym.Upn
97	funindex := funsym.Desc.Index()
98	switch funupn {
99	case maxdepth - 1:
100		return func(env *Env) {
101			funv := env.FileEnv.Vals[funindex]
102			if cachedfunv != funv {
103				cachedfunv = funv
104				cachedfun = funv.Interface().(func())
105			}
106			cachedfun()
107		}
108	case 0:
109		return func(env *Env) {
110			fun := env.Vals[funindex].Interface().(func())
111			fun()
112		}
113	case 1:
114		return func(env *Env) {
115			fun := env.Outer.Vals[funindex].Interface().(func())
116			fun()
117		}
118	case 2:
119		return func(env *Env) {
120			fun := env.Outer.Outer.Vals[funindex].Interface().(func())
121			fun()
122		}
123	default:
124		return func(env *Env) {
125			env = env.Outer.Outer.Outer.Outer
126			for i := 3; i < funupn; i++ {
127				env = env.Outer
128			}
129			fun := env.Vals[funindex].Interface().(func())
130			fun()
131		}
132	}
133}
134
135:macro mcall1ret0(argtyp ast.Node) ast.Node {
136
137	if EvalType(argtyp) == nil {
138		return ~"{
139			ret = func(env *Env) {
140				funv := exprfun(env)
141				// keep the argument wrapped in a reflect.Value
142				argv := []r.Value{
143					argfun(env),
144				}
145				callxr(funv, argv)
146			}
147		}
148	}
149
150	cachefun := ~"{
151		if cachedfunv != funv {
152			cachedfunv = funv
153			cachedfun = funv.Interface().(func(~,argtyp))
154		}
155	}
156
157	argconv := convertvalue1(argtyp, ~'{r.ValueOf(arg.Value)})
158
159	return ~"{
160		if arg.Const() {
161			argconst := ~,argconv
162			if funsym != nil && funupn == maxdepth - 1 {
163				var cachedfun func(~,argtyp)
164				ret = func(env *Env) {
165					funv := env.FileEnv.Vals[funindex]
166					~,cachefun
167					// Debugf("calling %v with args [%v]", r.TypeOf(cachedfun), argconst)
168					cachedfun(argconst)
169				}
170			} else {
171				ret = func(env *Env) {
172					fun := exprfun(env).Interface().(func(~,argtyp))
173					// Debugf("calling %v with args [%v]", r.TypeOf(fun), argconst)
174					fun(argconst)
175				}
176			}
177		} else {
178			argfun := arg.Fun.(func(env *Env) ~,argtyp)
179			if funsym != nil && funupn == maxdepth - 1 {
180				var cachedfun func(~,argtyp)
181				ret = func(env *Env) {
182					funv := env.FileEnv.Vals[funindex]
183					~,cachefun
184					arg := argfun(env)
185					// Debugf("calling %v with args [%v]", r.TypeOf(cachedfun), arg)
186					cachedfun(arg)
187				}
188			} else {
189				ret = func(env *Env) {
190					fun := exprfun(env).Interface().(func(~,argtyp))
191					arg := argfun(env)
192					// Debugf("calling %v with args [%v]", r.TypeOf(fun), arg)
193					fun(arg)
194				}
195			}
196		}
197	}
198}
199
200
201
202func (c *Comp) call1ret0(call *Call, maxdepth int) func(env *Env) {
203	expr := call.Fun
204	exprfun := expr.AsX1()
205	funsym := expr.Sym
206	funupn, funindex := -1, -1
207	if funsym != nil {
208		funupn = funsym.Upn
209		funindex = funsym.Desc.Index()
210		if funindex == NoIndex {
211			c.Errorf("internal error: call1ret0() invoked for constant function %#v. use call_builtin() instead", expr)
212		}
213	}
214	arg := call.Args[0]
215	argfun := call.MakeArgfunsX1()[0]
216
217	var cachedfunv r.Value
218	var ret func(env *Env)
219
220	t := expr.Type.In(0)
221	k := t.Kind()
222	if reflect.KindToType(k) == t.ReflectType() {
223		switch k {
224		case r.Bool:      {mcall1ret0; bool}
225		case r.Int:       {mcall1ret0; int}
226		case r.Int8:      {mcall1ret0; int8}
227		case r.Int16:     {mcall1ret0; int16}
228		case r.Int32:     {mcall1ret0; int32}
229		case r.Int64:     {mcall1ret0; int64}
230		case r.Uint:      {mcall1ret0; uint}
231		case r.Uint8:     {mcall1ret0; uint8}
232		case r.Uint16:    {mcall1ret0; uint16}
233		case r.Uint32:    {mcall1ret0; uint32}
234		case r.Uint64:    {mcall1ret0; uint64}
235		case r.Uintptr:   {mcall1ret0; uintptr}
236		case r.Float32:   {mcall1ret0; float32}
237		case r.Float64:   {mcall1ret0; float64}
238		case r.Complex64: {mcall1ret0; complex64}
239		case r.Complex128:{mcall1ret0; complex128}
240		case r.String:    {mcall1ret0; string}
241		}
242	}
243	if ret == nil {
244		{mcall1ret0; nil}
245	}
246	return ret
247}
248
249:macro mcall2ret0(arg0typ, arg1typ ast.Node) ast.Node {
250
251	if EvalType(arg0typ) == nil || EvalType(arg1typ) == nil {
252		return ~"{
253			ret = func(env *Env) {
254				funv := exprfun(env)
255				// keep the arguments wrapped in a reflect.Value
256				argv := []r.Value{
257					argfuns[0](env),
258					argfuns[1](env),
259				}
260				callxr(funv, argv)
261			}
262		}
263	}
264
265	cachefun := ~"{
266		if cachedfunv != funv {
267			cachedfunv = funv
268			cachedfun = funv.Interface().(func(~,arg0typ, ~,arg1typ))
269		}
270	}
271
272	return ~"{
273		arg0fun := args[0].WithFun().(func(*Env) ~,arg0typ)
274		arg1fun := args[1].WithFun().(func(*Env) ~,arg0typ)
275
276		if funsym != nil && funupn == maxdepth - 1 {
277			var cachedfun func(~,arg0typ, ~,arg1typ)
278			ret = func(env *Env) {
279				funv := env.FileEnv.Vals[funindex]
280				~,cachefun
281				arg0 := arg0fun(env)
282				arg1 := arg1fun(env)
283				cachedfun(arg0, arg1)
284			}
285		} else {
286			ret = func(env *Env) {
287				fun := exprfun(env).Interface().(func(~,arg0typ, ~,arg1typ))
288				arg0 := arg0fun(env)
289				arg1 := arg1fun(env)
290				fun(arg0, arg1)
291			}
292		}
293	}
294}
295
296
297func (c *Comp) call2ret0(call *Call, maxdepth int) func(env *Env) {
298	expr := call.Fun
299	exprfun := expr.AsX1()
300	funsym := expr.Sym
301	funupn, funindex := -1, -1
302	if funsym != nil {
303		funupn = funsym.Upn
304		funindex = funsym.Desc.Index()
305		if funindex == NoIndex {
306			c.Errorf("internal error: call2ret0() invoked for constant function %#v. use call_builtin() instead", expr)
307		}
308	}
309	args := call.Args
310	argfunsX1 := call.MakeArgfunsX1()
311	argfuns := [2]func(*Env)r.Value {
312		argfunsX1[0],
313		argfunsX1[1],
314	}
315	var cachedfunv r.Value
316	var ret func(env *Env)
317
318	t := expr.Type.In(0)
319	rt := t.ReflectType()
320	k := t.Kind()
321	if reflect.KindToType(k) == rt && expr.Type.In(1).ReflectType() == rt {
322		switch k {
323		case r.Bool:      {mcall2ret0; bool;       bool}
324		case r.Int:       {mcall2ret0; int;        int}
325		case r.Int8:      {mcall2ret0; int8;       int8}
326		case r.Int16:     {mcall2ret0; int16;      int16}
327		case r.Int32:     {mcall2ret0; int32;      int32}
328		case r.Int64:     {mcall2ret0; int64;      int64}
329		case r.Uint:      {mcall2ret0; uint;       uint}
330		case r.Uint8:     {mcall2ret0; uint8;      uint8}
331		case r.Uint16:    {mcall2ret0; uint16;     uint16}
332		case r.Uint32:    {mcall2ret0; uint32;     uint32}
333		case r.Uint64:    {mcall2ret0; uint64;     uint64}
334		case r.Uintptr:   {mcall2ret0; uintptr;    uintptr}
335		case r.Float32:   {mcall2ret0; float32;    float32}
336		case r.Float64:   {mcall2ret0; float64;    float64}
337		case r.Complex64: {mcall2ret0; complex64;  complex64}
338		case r.Complex128:{mcall2ret0; complex128; complex128}
339		case r.String:    {mcall2ret0; string;     string}
340		}
341	}
342	if ret == nil {
343		{mcall2ret0; nil; nil}
344	}
345	return ret
346}
347