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