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 * channel.go
12 *
13 *  Created on May 01, 2017
14 *      Author Massimiliano Ghilardi
15 */
16
17package fast
18
19:import (
20	"go/ast"
21	r "reflect"
22)
23
24import (
25	"go/ast"
26	r "reflect"
27
28	. "github.com/cosmos72/gomacro/base"
29	"github.com/cosmos72/gomacro/base/reflect"
30	xr "github.com/cosmos72/gomacro/xreflect"
31)
32
33
34:func upcasefirstbyte(str string) string {
35	if len(str) > 0 && str[0] >= 'a' && str[0] <= 'z' {
36		bytes := []byte(str)
37		bytes[0] -= 'a' - 'A'
38		return string(bytes)
39	}
40	return str
41}
42
43:func makekind(typ ast.Node) ast.Node {
44	t := EvalType(typ)
45	if t == nil {
46		return nil
47	}
48	// go/ast.SelectorExpr requires the foo in r.foo to be an *ast.Ident, cannot unquote there
49	kind := ~"{r . foo}
50	kind.Sel = &ast.Ident{Name: upcasefirstbyte(t.Name())}
51	return kind
52}
53
54:func maketypevar(typ ast.Node) ast.Node {
55	t := EvalType(typ)
56	sel := &ast.SelectorExpr{
57		X: &ast.Ident{Name: "c"},
58		Sel: &ast.Ident{Name: "TypeOf" + upcasefirstbyte(t.Name())},
59	}
60	return ~"{~,sel ()}
61}
62
63
64:func convertvalue(typ, val ast.Node) (ast.Node, ast.Node) {
65	var t r.Type = EvalType(typ)
66	if t == nil {
67		// keep the result wrapped in a reflect.Value
68		typ = ~'{r.Value}
69	} else {
70		// unwrap the result
71		tname := t.Name()
72		// remove final digits from t.Name()
73		// needed to convert Uint64 -> Uint etc. to calls reflect.Value.{tname}
74		for len(tname) != 0 {
75			ch := tname[len(tname)-1]
76			if ch < '0' || ch > '9' {
77				break
78			}
79			tname = tname[0:len(tname)-1]
80		}
81		if tname == "uintptr" {
82			tname = "uint" // use reflect.Value.Uint()
83		}
84		sel := ~"{~,val . foo} // we modify it destructively
85		sel.Sel = &ast.Ident{Name: upcasefirstbyte(tname)}
86
87		switch t.Kind() {
88		case r.Bool, r.Int64, r.Uint64, r.Float64, r.Complex128, r.String:
89			// result of reflect.Value.{tname} is already the correct type
90			val = ~"{~,sel ()}
91		default:
92			// convert int64, uint64... to the correct type
93			val = ~"{~,typ ( ~,sel () )}
94		}
95	}
96	return typ, val
97}
98
99// Recv compiles <-channel (returns two values: the received value and an 'ok' flag)
100func (c *Comp) Recv(node *ast.UnaryExpr, xe *Expr) *Expr {
101	t := xe.Type
102	if t.Kind() != r.Chan {
103		return c.badUnaryExpr("expecting channel, found", node, xe)
104	}
105	if t.ChanDir()&r.RecvDir == 0 {
106		return c.badUnaryExpr("cannot receive from send-only channel", node, xe)
107	}
108	var fun func(env *Env) (r.Value, []r.Value)
109	switch x := xe.Fun.(type) {
110	case func(env *Env) (r.Value, []r.Value):
111		channelfun := x
112		fun = func(env *Env) (r.Value, []r.Value) {
113			channel, _ := channelfun(env)
114			retv, ok := channel.Recv()
115			var okv r.Value
116			if ok {
117				okv = True
118			} else {
119				okv = False
120			}
121			return retv, []r.Value{retv, okv}
122		}
123	default:
124		channelfun := xe.AsX1()
125		fun = func(env *Env) (r.Value, []r.Value) {
126			retv, ok := channelfun(env).Recv()
127			var okv r.Value
128			if ok {
129				okv = True
130			} else {
131				okv = False
132			}
133			return retv, []r.Value{retv, okv}
134		}
135	}
136	types := []xr.Type{t.Elem(), c.TypeOfBool()}
137	return exprXV(types, fun)
138}
139
140:macro recv1_xv(typ ast.Node) ast.Node {
141	if EvalType(typ) == nil {
142		return ~"{
143			default:
144			fun = func(env *Env) r.Value {
145				channel, _ := channelfun(env)
146				retv, _ := channel.Recv()
147				return retv
148			}
149		}
150	}
151	kind := makekind(typ)
152	typ2, ret := convertvalue(typ, ~'retv)
153	return ~"{
154		case ~,kind:
155		fun = func(env *Env) ~,typ2 {
156			channel, _ := channelfun(env)
157			retv, _ := channel.Recv()
158			return ~,ret
159		}
160	}
161}
162
163:macro recv1(typ ast.Node) ast.Node {
164	if EvalType(typ) == nil {
165		return ~"{
166			default:
167			fun = func(env *Env) r.Value {
168				retv, _ := channelfun(env).Recv()
169				return retv
170			}
171		}
172	}
173	kind := makekind(typ)
174	typ2, ret := convertvalue(typ, ~'retv)
175	return ~"{
176		case ~,kind:
177		if telem.ReflectType() != reflect.KindToType(~,kind) {
178			fun = func(env *Env) ~,typ {
179				retv, _ := channelfun(env).Recv()
180				return ~,ret
181			}
182		} else if recvonly {
183			fun = func(env *Env) ~,typ {
184				channel := channelfun(env).Interface().(<-chan ~,typ)
185				return <-channel
186			}
187		} else {
188			fun = func(env *Env) ~,typ {
189				channel := channelfun(env).Interface().(chan ~,typ)
190				return <-channel
191			}
192		}
193	}
194}
195
196// Recv1 compiles <-channel (returns a single value: the received value)
197// mandatory optimization: fast_interpreter ASSUMES that expressions
198// returning bool, int, uint, float, complex, string do NOT wrap them in reflect.Value
199func (c *Comp) Recv1(node *ast.UnaryExpr, xe *Expr) *Expr {
200	t := xe.Type
201	if t.Kind() != r.Chan {
202		return c.badUnaryExpr("expecting channel, found", node, xe)
203	}
204	if t.ChanDir()&r.RecvDir == 0 {
205		return c.badUnaryExpr("cannot receive from send-only channel", node, xe)
206	}
207	telem := t.Elem()
208	var fun I
209	switch x := xe.Fun.(type) {
210	case func(env *Env) (r.Value, []r.Value):
211		channelfun := x
212		switch telem.Kind() {
213			{recv1_xv; bool}
214			{recv1_xv; int}
215			{recv1_xv; int8}
216			{recv1_xv; int16}
217			{recv1_xv; int32}
218			{recv1_xv; int64}
219			{recv1_xv; uint}
220			{recv1_xv; uint8}
221			{recv1_xv; uint16}
222			{recv1_xv; uint32}
223			{recv1_xv; uint64}
224			{recv1_xv; uintptr}
225			{recv1_xv; float32}
226			{recv1_xv; float64}
227			{recv1_xv; complex64}
228			{recv1_xv; complex128}
229			{recv1_xv; string}
230			{recv1_xv; nil}
231		}
232	default:
233		recvonly := t.ChanDir() == r.RecvDir
234		channelfun := xe.AsX1()
235		switch telem.Kind() {
236			{recv1; bool}
237			{recv1; int}
238			{recv1; int8}
239			{recv1; int16}
240			{recv1; int32}
241			{recv1; int64}
242			{recv1; uint}
243			{recv1; uint8}
244			{recv1; uint16}
245			{recv1; uint32}
246			{recv1; uint64}
247			{recv1; uintptr}
248			{recv1; float32}
249			{recv1; float64}
250			{recv1; complex64}
251			{recv1; complex128}
252			{recv1; string}
253			{recv1; nil}
254		}
255	}
256	return exprFun(telem, fun)
257}
258
259:macro send_c(typ ast.Node) ast.Node {
260	kind := makekind(typ)
261	typ2, conv := convertvalue(typ, ~'v)
262	return ~"{
263		case ~,kind:
264		value := ~,conv
265		if sendonly {
266			stmt = func(env *Env) (Stmt, *Env) {
267				channel := channelfun(env).Interface().(chan<- ~,typ)
268				channel <- value
269				env.IP++
270				return env.Code[env.IP], env
271			}
272		} else {
273			stmt = func(env *Env) (Stmt, *Env) {
274				channel := channelfun(env).Interface().(chan ~,typ)
275				channel <- value
276				env.IP++
277				return env.Code[env.IP], env
278			}
279		}
280	}
281}
282
283:macro send_e(typ ast.Node) ast.Node {
284	kind := makekind(typ)
285	return ~"{
286		case ~,kind:
287		if exprfun, ok := expr.Fun.(func (*Env) ~,typ); !ok {
288			break
289		} else if sendonly {
290			stmt = func(env *Env) (Stmt, *Env) {
291				channel := channelfun(env).Interface().(chan<- ~,typ)
292				channel <- exprfun(env)
293				env.IP++
294				return env.Code[env.IP], env
295			}
296		} else {
297			stmt = func(env *Env) (Stmt, *Env) {
298				channel := channelfun(env).Interface().(chan ~,typ)
299				channel <- exprfun(env)
300				env.IP++
301				return env.Code[env.IP], env
302			}
303		}
304	}
305}
306
307func (c *Comp) Send(node *ast.SendStmt) {
308	channel := c.Expr1(node.Chan, nil)
309	t := channel.Type
310	if t.Kind() != r.Chan {
311		c.Errorf("cannot send to non-channel type %v: %v", t, node)
312		return
313	}
314	if t.ChanDir()&r.SendDir == 0 {
315		c.Errorf("cannot send to receive-only channel type %v: %v", t, node)
316		return
317	}
318	telem := t.Elem()
319	rtelem := telem.ReflectType()
320	kelem := rtelem.Kind()
321	expr := c.Expr1(node.Value, nil)
322	if expr.Const() {
323		expr.ConstTo(telem)
324	} else if expr.Type == nil || !expr.Type.AssignableTo(telem) {
325		c.Errorf("cannot use %v <%v> as type %v in send", node.Value, expr.Type, telem)
326		return
327	} else {
328		expr.To(c, telem)
329	}
330	channelfun := channel.AsX1()
331	sendonly := t.ChanDir() == r.SendDir
332	var stmt Stmt
333	if expr.Const() {
334		v := r.ValueOf(expr.Value)
335		if reflect.KindToType(kelem) == rtelem {
336			switch kelem {
337			{send_c; bool}
338			{send_c; int}
339			{send_c; int8}
340			{send_c; int16}
341			{send_c; int32}
342			{send_c; int64}
343			{send_c; uint}
344			{send_c; uint8}
345			{send_c; uint16}
346			{send_c; uint32}
347			{send_c; uint64}
348			{send_c; uintptr}
349			{send_c; float32}
350			{send_c; float64}
351			{send_c; complex64}
352			{send_c; complex128}
353			{send_c; string}
354			}
355		}
356		if stmt == nil {
357			stmt = func(env *Env) (Stmt, *Env) {
358				channel := channelfun(env)
359				channel.Send(v)
360				env.IP++
361				return env.Code[env.IP], env
362			}
363		}
364	} else {
365		if reflect.KindToType(kelem) == rtelem {
366			switch kelem {
367			{send_e; bool}
368			{send_e; int}
369			{send_e; int8}
370			{send_e; int16}
371			{send_e; int32}
372			{send_e; int64}
373			{send_e; uint}
374			{send_e; uint8}
375			{send_e; uint16}
376			{send_e; uint32}
377			{send_e; uint64}
378			{send_e; uintptr}
379			{send_e; float32}
380			{send_e; float64}
381			{send_e; complex64}
382			{send_e; complex128}
383			{send_e; string}
384			}
385		}
386		if stmt == nil {
387			exprfun := expr.AsX1()
388			stmt = func(env *Env) (Stmt, *Env) {
389				channel := channelfun(env)
390				value := exprfun(env)
391				channel.Send(value)
392				env.IP++
393				return env.Code[env.IP], env
394			}
395		}
396	}
397	c.append(stmt)
398}
399