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 * expr.go
12 *
13 *  Created on Apr 01, 2017
14 *      Author Massimiliano Ghilardi
15 */
16
17package fast
18
19import (
20	"go/ast"
21	"go/token"
22	r "reflect"
23
24	xr "github.com/cosmos72/gomacro/xreflect"
25)
26
27// ExprsMultipleValues either a single expression returning multiple values,
28// or multiple expressions each returning a value.
29func (c *Comp) ExprsMultipleValues(nodes []ast.Expr, expectedValuesN int) (inits []*Expr) {
30	n := len(nodes)
31	if n != expectedValuesN {
32		if n != 1 {
33			c.Errorf("value count mismatch: cannot assign %d values to %d places: %v",
34				n, expectedValuesN, nodes)
35			return nil
36		}
37		e := c.expr(nodes[0], nil)
38		if actualN := e.NumOut(); actualN != expectedValuesN {
39			var plural string
40			if actualN != 1 {
41				plural = "s"
42			}
43			c.Errorf("expression returns %d value%s, expecting %d: %v", actualN, plural, expectedValuesN, nodes[0])
44		}
45		inits = []*Expr{e}
46	} else {
47		inits = c.exprs(nodes)
48	}
49	return inits
50}
51
52// Exprs compiles multiple expressions
53func (c *Comp) Exprs(nodes []ast.Expr) []*Expr {
54	es := c.exprs(nodes)
55	for _, e := range es {
56		c.Jit.Fun(e)
57	}
58	return es
59}
60
61// same as Exprs, but does not replace e[i].Fun with jit-compiled code
62func (c *Comp) exprs(nodes []ast.Expr) []*Expr {
63	var es []*Expr
64	if n := len(nodes); n != 0 {
65		es = make([]*Expr, n)
66		for i := range nodes {
67			es[i] = c.expr1(nodes[i], nil)
68		}
69	}
70	return es
71}
72
73// Expr1 compiles an expression that returns a single value
74// t is optional and used for type inference on composite literals,
75// see https://golang.org/ref/spec#Composite_literals
76func (c *Comp) Expr1(in ast.Expr, t xr.Type) *Expr {
77	return c.expr1(in, t)
78}
79
80// same as Expr1, but does not replace e.Fun with jit-compiled code
81func (c *Comp) expr1(in ast.Expr, t xr.Type) *Expr {
82	for {
83		if in != nil {
84			c.Pos = in.Pos()
85		}
86		// env.Debugf("Expr1() %v", node)
87		switch node := in.(type) {
88		case *ast.ParenExpr:
89			in = node.X
90			continue
91		case *ast.IndexExpr:
92			return c.IndexExpr1(node)
93		case *ast.TypeAssertExpr:
94			return c.TypeAssert1(node)
95		case *ast.UnaryExpr:
96			if node.Op == token.ARROW {
97				xe := c.Expr1(node.X, nil)
98				return c.Recv1(node, xe)
99			} else {
100				return c.UnaryExpr(node)
101			}
102		}
103		break
104	}
105	e := c.expr(in, t)
106	nout := e.NumOut()
107	switch nout {
108	case 0:
109		c.Errorf("expression returns no values, expecting one: %v", in)
110		return nil
111	case 1:
112		return e
113	default:
114		return e.exprXVAsI()
115	}
116}
117
118// Expr compiles an expression.
119// t is optional and used for type inference on composite literals,
120// see https://golang.org/ref/spec#Composite_literals
121func (c *Comp) Expr(in ast.Expr, t xr.Type) *Expr {
122	e := c.expr(in, t)
123	return c.Jit.Fun(e)
124}
125
126// same as Expr, but does not replace e.Fun with jit-compiled code
127func (c *Comp) expr(in ast.Expr, t xr.Type) *Expr {
128	for {
129		if in != nil {
130			c.Pos = in.Pos()
131		}
132		// env.Debugf("Expr() %v", node)
133		switch node := in.(type) {
134		case *ast.BasicLit:
135			return c.BasicLit(node)
136		case *ast.BinaryExpr:
137			return c.BinaryExpr(node)
138		case *ast.CallExpr:
139			return c.CallExpr(node)
140		case *ast.CompositeLit:
141			// propagate inferred type
142			return c.CompositeLit(node, t)
143		case *ast.FuncLit:
144			return c.FuncLit(node)
145		case *ast.Ident:
146			return c.Ident(node.Name)
147		case *ast.IndexExpr:
148			return c.IndexExpr(node)
149		case *ast.ParenExpr:
150			in = node.X
151			continue
152		case *ast.UnaryExpr:
153			return c.UnaryExpr(node)
154		case *ast.SelectorExpr:
155			return c.SelectorExpr(node)
156		case *ast.SliceExpr:
157			return c.SliceExpr(node)
158		case *ast.StarExpr:
159			return c.StarExpr(node)
160		case *ast.TypeAssertExpr:
161			return c.TypeAssert2(node)
162		default:
163		}
164		c.Errorf("unimplemented Compile() for: %v <%v>", in, r.TypeOf(in))
165		return nil
166	}
167}
168
169// Expr1OrType compiles an single-valued expression or a type.
170// performs simultaneous lookup for type names, constants, variables and functions
171func (c *Comp) Expr1OrType(expr ast.Expr) (e *Expr, t xr.Type) {
172	node := expr
173	for {
174		switch n := node.(type) {
175		case *ast.StarExpr:
176			node = n.X
177			continue
178		case *ast.ParenExpr:
179			node = n.X
180			continue
181		case *ast.Ident:
182			name := n.Name
183			for o := c; o != nil; o = o.Outer {
184				bind, okb := o.Binds[name]
185				var okt bool
186				if GENERICS_V1 && okb {
187					_, okt = bind.Value.(*TemplateType) // template types are stored in Comp.Bind[]
188					okb = !okt
189				}
190				if okb {
191					return c.Expr1(expr, nil), nil
192				} else if _, ok := o.Types[name]; ok || okt {
193					return nil, c.Type(expr)
194				}
195			}
196		case *ast.IndexExpr:
197			if GENERICS_V1 {
198				if lit, ok := n.Index.(*ast.CompositeLit); ok && lit.Type == nil {
199					// foo#[a, b...] can be a template function or a template type
200					node = n.X
201					continue
202				}
203			}
204		}
205		break
206	}
207	panicking := true
208	defer func() {
209		if panicking {
210			recover()
211			t = c.Type(expr)
212		}
213	}()
214	e = c.Expr1(expr, nil)
215	panicking = false
216	return
217}
218
219// IndexExpr compiles a read operation on obj[idx]
220// or a template function name#[T1, T2...]
221func (c *Comp) IndexExpr(node *ast.IndexExpr) *Expr {
222	if GENERICS_V1 {
223		if e := c.TemplateFunc(node); e != nil {
224			return e
225		}
226	}
227	return c.indexExpr(node, true)
228}
229
230// IndexExpr1 compiles a single-valued read operation on obj[idx]
231// or a template function name#[T1, T2...]
232func (c *Comp) IndexExpr1(node *ast.IndexExpr) *Expr {
233	if GENERICS_V1 {
234		if e := c.TemplateFunc(node); e != nil {
235			return e
236		}
237	}
238	return c.indexExpr(node, false)
239}
240