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 * declaration.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	"github.com/cosmos72/gomacro/base/reflect"
25
26	"github.com/cosmos72/gomacro/base/strings"
27
28	"github.com/cosmos72/gomacro/base"
29	xr "github.com/cosmos72/gomacro/xreflect"
30)
31
32// Decl compiles a constant, variable, function or type declaration - or an import
33func (c *Comp) Decl(node ast.Decl) {
34	if node != nil {
35		c.Pos = node.Pos()
36	}
37	switch node := node.(type) {
38	case *ast.GenDecl:
39		c.GenDecl(node)
40	case *ast.FuncDecl:
41		c.DeclFunc(node)
42	default:
43		c.Errorf("unsupported declaration, expecting <*ast.GenDecl> or <*ast.FuncDecl>, found: %v <%v>", node, r.TypeOf(node))
44	}
45}
46
47// GenDecl compiles a constant, variable or type declaration - or an import
48func (c *Comp) GenDecl(node *ast.GenDecl) {
49	switch node.Tok {
50	case token.IMPORT:
51		for _, decl := range node.Specs {
52			c.Import(decl)
53		}
54	case token.CONST:
55		var defaultType ast.Expr
56		var defaultExprs []ast.Expr
57		// https://go-review.googlesource.com/c/go/+/71750
58		// states "each block has its own version of iota"
59		// which is also implied, although somewhat subtly,
60		// by the latest definition of iota in Go language specs.
61		//
62		// So declare iota in the top scope, but restore the original bind after the const declarations,
63		// because an in-progress outer const declaration may have a current value for it.
64		top := c.TopComp()
65		defer top.endIota(top.beginIota())
66		for i, decl := range node.Specs {
67			top.setIota(i)
68			c.DeclConsts(decl, defaultType, defaultExprs)
69			if valueSpec, ok := decl.(*ast.ValueSpec); ok && valueSpec.Values != nil {
70				defaultType = valueSpec.Type
71				defaultExprs = valueSpec.Values
72			}
73		}
74	case token.TYPE:
75		for _, decl := range node.Specs {
76			c.DeclType(decl)
77		}
78	case token.VAR:
79		for _, decl := range node.Specs {
80			c.DeclVars(decl)
81		}
82	case token.PACKAGE:
83		/*
84			modified parser converts 'package foo' to:
85
86			ast.GenDecl{
87				Tok: token.PACKAGE,
88				Specs: []ast.Spec{
89					&ast.ValueSpec{
90						Values: []ast.Expr{
91							&ast.BasicLit{
92								Kind:  token.String,
93								Value: "path/to/package",
94							},
95						},
96					},
97				},
98			}
99		*/
100		if len(node.Specs) == 1 {
101			if decl, ok := node.Specs[0].(*ast.ValueSpec); ok {
102				if len(decl.Values) == 1 {
103					if lit, ok := decl.Values[0].(*ast.BasicLit); ok {
104						if lit.Kind == token.STRING && (lit.Value == c.Name || strings.MaybeUnescapeString(lit.Value) == c.Path) {
105							break
106						}
107					}
108					// c.changePackage(name)
109					c.Debugf("cannot switch package from fast.Comp.Compile(), use Interp.ChangePackage() instead: %v // %T", node, node)
110				}
111			}
112		}
113		c.Errorf("unsupported package syntax, expecting a single package name, found: %v // %T", node, node)
114	default:
115		c.Errorf("unsupported declaration kind, expecting token.IMPORT, token.PACKAGE, token.CONST, token.TYPE or token.VAR, found %v: %v // %T",
116			node.Tok, node, node)
117	}
118}
119
120// DeclConsts compiles a set of constant declarations
121func (c *Comp) DeclConsts(node ast.Spec, defaultType ast.Expr, defaultExprs []ast.Expr) {
122	c.Pos = node.Pos()
123	switch node := node.(type) {
124	case *ast.ValueSpec:
125		if node.Type != nil || node.Values != nil {
126			defaultType = node.Type
127			defaultExprs = node.Values
128		}
129		names, t, inits := c.prepareDeclConstsOrVars(toStrings(node.Names), defaultType, defaultExprs)
130		c.DeclConsts0(names, t, inits)
131	default:
132		c.Errorf("unsupported constant declaration: expecting <*ast.ValueSpec>, found: %v <%v>", node, r.TypeOf(node))
133	}
134}
135
136// DeclVars compiles a set of variable declarations i.e. "var x1, x2... [type] = expr1, expr2..."
137func (c *Comp) DeclVars(node ast.Spec) {
138	c.Pos = node.Pos()
139	switch node := node.(type) {
140	case *ast.ValueSpec:
141		names, t, inits := c.prepareDeclConstsOrVars(toStrings(node.Names), node.Type, node.Values)
142		c.DeclVars0(names, t, inits, toPos(node.Names))
143	default:
144		c.Errorf("unsupported variable declaration: expecting <*ast.ValueSpec>, found: %v <%v>", node, r.TypeOf(node))
145	}
146}
147
148// DeclVarsShort compiles a set of variable short declarations i.e. "x1, x2... := expr1, expr2..."
149func (c *Comp) DeclVarsShort(lhs []ast.Expr, rhs []ast.Expr) {
150	n := len(lhs)
151	if n == 0 {
152		return
153	}
154	names := make([]string, n)
155	pos := make([]token.Pos, n)
156	for i := range lhs {
157		if ident, ok := lhs[i].(*ast.Ident); ok {
158			names[i] = ident.Name
159			pos[i] = ident.NamePos
160		} else {
161			c.Errorf("non-name %v on left side of :=", lhs[i])
162		}
163	}
164	_, t, inits := c.prepareDeclConstsOrVars(names, nil, rhs)
165	c.DeclVars0(names, t, inits, pos)
166}
167
168func toStrings(idents []*ast.Ident) []string {
169	n := len(idents)
170	names := make([]string, n)
171	for i, ident := range idents {
172		names[i] = ident.Name
173	}
174	return names
175}
176
177func toPos(idents []*ast.Ident) []token.Pos {
178	n := len(idents)
179	pos := make([]token.Pos, n)
180	for i, ident := range idents {
181		pos[i] = ident.NamePos
182	}
183	return pos
184}
185
186func (c *Comp) prepareDeclConstsOrVars(names []string, typ ast.Expr, exprs []ast.Expr) (names_out []string, t xr.Type, inits []*Expr) {
187	n := len(names)
188	if typ != nil {
189		t = c.Type(typ)
190	}
191	if exprs != nil {
192		inits = c.ExprsMultipleValues(exprs, n)
193	}
194	return names, t, inits
195}
196
197func (c *Comp) DeclConsts0(names []string, t xr.Type, inits []*Expr) {
198	n := len(names)
199	if inits == nil {
200		c.Errorf("constants without initialization: %v", names)
201	} else if len(inits) != n {
202		c.Errorf("cannot declare %d constants with %d initializers: %v", n, len(inits), names)
203	}
204	for i, name := range names {
205		init := inits[i]
206		if !init.Const() {
207			c.Errorf("const initializer for %q is not a constant", name)
208		}
209		c.DeclConst0(name, t, init.Value)
210	}
211}
212
213// DeclVars0 compiles a set of variable declarations
214func (c *Comp) DeclVars0(names []string, t xr.Type, inits []*Expr, pos []token.Pos) {
215	n := len(names)
216	ni := len(inits)
217	if ni == 0 || ni == n {
218		npos := len(pos)
219		for i, name := range names {
220			var init *Expr
221			if i < ni {
222				init = inits[i]
223			}
224			if i < npos {
225				c.Pos = pos[i]
226			}
227			c.DeclVar0(name, t, init)
228		}
229	} else if ni == 1 && n > 1 {
230		c.DeclMultiVar0(names, t, inits[0], pos)
231	} else {
232		c.Errorf("cannot declare %d variables from %d expressions: %v", n, ni, names)
233	}
234}
235
236// DeclConst0 compiles a constant declaration
237func (c *Comp) DeclConst0(name string, t xr.Type, value I) {
238	if !isLiteral(value) {
239		c.Errorf("const initializer for %q is not a constant: %v <%T>", name, value, value)
240		return
241	}
242	lit := c.litValue(value)
243	if t == nil {
244		t = lit.Type
245	} else {
246		value = lit.ConstTo(t)
247	}
248	bind := c.NewBind(name, ConstBind, t)
249	bind.Value = value // c.Binds[] is a map[string]*Bind => changes to *Bind propagate to the map
250}
251
252// NewFuncBind reserves space for a subsequent function declaration
253func (c *Comp) NewFuncBind(name string, t xr.Type) *Bind {
254	bind := c.NewBind(name, FuncBind, t)
255	if bind.Desc.Class() != FuncBind {
256		c.Errorf("internal error! Comp.NewBind(name=%q, class=FuncBind, type=%v) returned class=%v, expecting FuncBind",
257			name, t, bind.Desc.Class())
258	}
259	return bind
260}
261
262// NewBind reserves space for a subsequent constant, function or variable declaration
263func (c *Comp) NewBind(name string, class BindClass, t xr.Type) *Bind {
264	if class == IntBind || class == VarBind {
265		// respect c.IntBindMax: if != 0, it's the maximum number of IntBind variables we can declare
266		// reason: see comment in IntBindMax definition. Shortly, Ent.Ints[] address was taken
267		// thus we cannot reallocate it => we must stop at its capacity, stored in c.IntBindMax
268		// by Interp.PrepareEnv()
269		if (c.IntBindMax == 0 || c.IntBindNum < c.IntBindMax) &&
270			reflect.IsCategory(t.Kind(), r.Bool, r.Int, r.Uint, r.Float64, r.Complex128) {
271			// optimize booleans, integers, floats and complexes by storing them in Env.Ints []uint64
272			// note: complex128 occupies two uint64 slots!
273			class = IntBind
274		} else {
275			class = VarBind
276		}
277	}
278	return c.CompBinds.NewBind(&c.Output, name, class, t)
279}
280
281// NewBind reserves space for a subsequent constant, function or variable declaration
282func (c *CompBinds) NewBind(o *base.Output, name string, class BindClass, t xr.Type) *Bind {
283	// do NOT replace VarBind -> IntBind here: done by Comp.NewBind() above,
284	// and we are also invoked by Import.loadBinds() which needs to store
285	// booleans, integers, floats and complex64 into reflect.Value
286	// because such compiled global variables already exist at their own address
287	var index = NoIndex
288	if name == "_" {
289		// never store bindings for "_" in c.Binds
290		desc := class.MakeDescriptor(index)
291		return &Bind{Lit: Lit{Type: t}, Desc: desc, Name: name}
292	}
293	if c.Binds == nil {
294		c.Binds = make(map[string]*Bind)
295	}
296	if len(name) == 0 {
297		// unnamed function result, or unnamed switch/range/... expression
298	} else if bind := c.Binds[name]; bind != nil {
299		o.Warnf("redefined identifier: %v", name)
300		oldclass := bind.Desc.Class()
301		if (oldclass == IntBind) == (class == IntBind) {
302			// both are IntBind, or neither is.
303			if bind.Type.Kind() == r.Complex128 || t.Kind() != r.Complex128 {
304				// the new bind occupies fewer slots than the old one,
305				// or occupies the same number of slots
306				// => we can reuse the bind index
307				index = bind.Desc.Index()
308			}
309		}
310	}
311	// allocate a slot either in Binds or in IntBinds
312	switch class {
313	case ConstBind, TemplateFuncBind:
314		index = NoIndex
315	default: // case FuncBind, VarBind:
316		if index == NoIndex {
317			index = c.BindNum
318			c.BindNum++
319		}
320	case IntBind:
321		if index == NoIndex {
322			index = c.IntBindNum
323			c.IntBindNum++
324			if t.Kind() == r.Complex128 {
325				// complex128 occupies two slots
326				c.IntBindNum++
327			}
328		}
329	}
330	desc := class.MakeDescriptor(index)
331	bind := &Bind{Lit: Lit{Type: t}, Desc: desc, Name: name}
332	if len(name) != 0 {
333		// skip unnamed function results, and unnamed switch/range/... expression
334		c.Binds[name] = bind
335	}
336	return bind
337}
338
339func (c *Comp) declUnnamedBind(init *Expr, o *Comp, upn int) *Symbol {
340	t := init.Type
341	bind := o.NewBind("", VarBind, t)
342	// c.Debugf("declUnnamedBind: allocated bind %v, upn = %d", bind, upn)
343	switch bind.Desc.Class() {
344	case IntBind:
345		// no difference between declaration and assignment for this class
346		va := bind.AsVar(upn, PlaceSettable)
347		c.SetVar(va, token.ASSIGN, init)
348	case VarBind:
349		// cannot use c.DeclVar0 because the variable is declared in o
350		// cannot use o.DeclVar0 because the initializer must be evaluated in c
351		// so initialize the binding manually
352		index := bind.Desc.Index()
353		f := init.AsX1()
354		conv := c.Converter(init.Type, t)
355		switch upn {
356		case 0:
357			c.append(func(env *Env) (Stmt, *Env) {
358				v := f(env)
359				if conv != nil {
360					v = conv(v)
361				}
362				// no need to create a settable reflect.Value
363				env.Vals[index] = v
364				env.IP++
365				return env.Code[env.IP], env
366			})
367		case 1:
368			c.append(func(env *Env) (Stmt, *Env) {
369				v := f(env)
370				if conv != nil {
371					v = conv(v)
372				}
373				// no need to create a settable reflect.Value
374				env.Outer.Vals[index] = v
375				env.IP++
376				return env.Code[env.IP], env
377			})
378		default:
379			c.append(func(env *Env) (Stmt, *Env) {
380				o := env
381				for i := 0; i < upn; i++ {
382					o = o.Outer
383				}
384				v := f(env)
385				if conv != nil {
386					v = conv(v)
387				}
388				// no need to create a settable reflect.Value
389				o.Vals[index] = v
390				env.IP++
391				return env.Code[env.IP], env
392			})
393		}
394	default:
395		c.Errorf("internal error! Comp.NewBind(name=%q, class=VarBind, type=%v) returned class=%v, expecting VarBind or IntBind",
396			"", t, bind.Desc.Class())
397		return nil
398	}
399	return bind.AsSymbol(upn)
400}
401
402// DeclVar0 compiles a variable declaration. For caller's convenience, returns allocated Bind
403func (c *Comp) DeclVar0(name string, t xr.Type, init *Expr) *Bind {
404	if t == nil {
405		if init == nil {
406			c.Errorf("no value and no type, cannot declare : %v", name)
407		}
408		t = init.DefaultType()
409		if t == nil {
410			c.Errorf("cannot declare variable as untyped nil: %v", name)
411		}
412		n := init.NumOut()
413		if n == 0 {
414			c.Errorf("initializer returns no values, cannot declare variable: %v", name)
415		} else if n > 1 {
416			c.Warnf("initializer returns %d values, using only the first one to declare variable: %v", n, name)
417		}
418	}
419	bind := c.NewBind(name, VarBind, t)
420	desc := bind.Desc
421	switch desc.Class() {
422	default:
423		c.Errorf("internal error! Comp.NewBind(name=%q, class=VarBind, type=%v) returned class=%v, expecting VarBind or IntBind",
424			name, t, desc.Class())
425		return bind
426	case IntBind:
427		// no difference between declaration and assignment for these classes
428		if init == nil {
429			// no initializer... use the zero-value of t
430			init = c.exprValue(t, xr.Zero(t).Interface())
431		}
432		va := bind.AsVar(0, PlaceSettable)
433		c.SetVar(va, token.ASSIGN, init)
434	case VarBind:
435		index := desc.Index()
436		if index == NoIndex && init != nil {
437			// assigning a constant or expression to _
438			// only keep the expression side effects
439			c.append(init.AsStmt(c))
440			return bind
441		}
442		// declaring a variable in Env.Binds[], we must create a settable and addressable reflect.Value
443		if init == nil {
444			// no initializer... use the zero-value of t
445			rtype := t.ReflectType()
446			c.append(func(env *Env) (Stmt, *Env) {
447				// base.Debugf("declaring %v", bind)
448				env.Vals[index] = r.New(rtype).Elem()
449				env.IP++
450				return env.Code[env.IP], env
451			})
452			return bind
453		}
454		if init.Const() {
455			init.ConstTo(t) // convert untyped constants, check typed constants
456		}
457		fun := init.AsX1() // AsX1() panics if init.NumOut() == 0, warns if init.NumOut() > 1
458		tfun := init.Out(0)
459		if tfun == nil || (!tfun.IdenticalTo(t) && !tfun.AssignableTo(t)) {
460			c.Errorf("cannot assign <%v> to <%v> in variable declaration: %v <%v>%s", tfun, t, name, t, interfaceMissingMethod(tfun, t))
461			return bind
462		}
463		var ret func(env *Env) (Stmt, *Env)
464		conv := c.Converter(init.Type, t)
465		rtype := t.ReflectType()
466		// optimization: no need to wrap multiple-valued function into a single-value function
467		if f, ok := init.Fun.(func(*Env) (r.Value, []r.Value)); ok {
468			if conv != nil {
469				ret = func(env *Env) (Stmt, *Env) {
470					ret, _ := f(env)
471					place := r.New(rtype).Elem()
472					place.Set(conv(ret))
473					env.Vals[index] = place
474					env.IP++
475					return env.Code[env.IP], env
476				}
477			} else {
478				ret = func(env *Env) (Stmt, *Env) {
479					ret, _ := f(env)
480					place := r.New(rtype).Elem()
481					place.Set(ret)
482					env.Vals[index] = place
483					env.IP++
484					return env.Code[env.IP], env
485				}
486			}
487		} else {
488			if conv != nil {
489				ret = func(env *Env) (Stmt, *Env) {
490					ret := fun(env)
491					place := r.New(rtype).Elem()
492					place.Set(conv(ret))
493					env.Vals[index] = place
494					env.IP++
495					return env.Code[env.IP], env
496				}
497			} else {
498				ret = func(env *Env) (Stmt, *Env) {
499					ret := fun(env)
500					place := r.New(rtype).Elem()
501					place.Set(ret)
502					env.Vals[index] = place
503					env.IP++
504					return env.Code[env.IP], env
505				}
506			}
507		}
508		c.append(ret)
509	}
510	return bind
511}
512
513// DeclBindRuntimeValue compiles a variable, function or constant declaration with a reflect.Value passed at runtime
514func (c *Comp) DeclBindRuntimeValue(bind *Bind) func(*Env, r.Value) {
515	desc := bind.Desc
516	index := desc.Index()
517	if index == NoIndex {
518		return nil
519	}
520	t := bind.Type
521	rtype := t.ReflectType()
522	switch desc.Class() {
523	default:
524		c.Errorf("cannot declare a %s with a value passed at runtime: %v <%v>", desc.Class(), bind.Name, t)
525		return nil
526	case FuncBind:
527		// declaring a function in Env.Binds[], the reflect.Value must not be addressable or settable
528		return func(env *Env, v r.Value) {
529			env.Vals[index] = convert(v, rtype)
530		}
531	case VarBind:
532		// declaring a variable in Env.Binds[], we must create a settable and addressable reflect.Value
533		return func(env *Env, v r.Value) {
534			place := r.New(rtype).Elem()
535			if v.Type() != rtype {
536				v = convert(v, rtype)
537			}
538			place.Set(v)
539			env.Vals[index] = place
540		}
541	case IntBind:
542		// no difference between declaration and assignment for IntBind
543		return c.varSetValue(bind.AsVar(0, PlaceSettable))
544	}
545}
546
547// DeclMultiVar0 compiles multiple variable declarations from a single multi-valued expression
548func (c *Comp) DeclMultiVar0(names []string, t xr.Type, init *Expr, pos []token.Pos) {
549	if t == nil {
550		if init == nil {
551			c.Errorf("no value and no type, cannot declare variables: %v", names)
552		}
553	}
554	n := len(names)
555	npos := len(pos)
556	if n == 1 {
557		if npos != 0 {
558			c.Pos = pos[0]
559		}
560		c.DeclVar0(names[0], t, init)
561		return
562	}
563	ni := init.NumOut()
564	if ni < n {
565		c.Errorf("cannot declare %d variables from expression returning %d values: %v", n, ni, names)
566	} else if ni > n {
567		c.Warnf("declaring %d variables from expression returning %d values: %v", n, ni, names)
568	}
569	decls := make([]func(*Env, r.Value), n)
570	for i, name := range names {
571		ti := init.Out(i)
572		if t != nil && !t.IdenticalTo(ti) {
573			if ti != nil && !ti.AssignableTo(t) {
574				c.Errorf("cannot assign <%v> to <%v> in variable declaration: %v", ti, t, names)
575				return
576			} else {
577				ti = t // declared variable has type t, not the i-th type returned by multi-valued expression
578			}
579		}
580		bind := c.NewBind(name, VarBind, ti)
581		decls[i] = c.DeclBindRuntimeValue(bind)
582	}
583	fun := init.AsXV(COptDefaults)
584	if npos != 0 {
585		c.Pos = pos[0]
586	}
587	c.append(func(env *Env) (Stmt, *Env) {
588		// call the multi-valued function. we know ni > 1, so just use the []r.Value
589		_, rets := fun(env)
590
591		// declare and assign the variables one by one. we know n <= ni
592		for i, decl := range decls {
593			if decl != nil {
594				decl(env, rets[i])
595			}
596		}
597		env.IP++
598		return env.Code[env.IP], env
599	})
600}
601
602// DeclFunc0 compiles a function declaration. For caller's convenience, returns allocated Bind
603func (c *Comp) DeclFunc0(name string, fun I) *Bind {
604	funv := r.ValueOf(fun)
605	t := c.TypeOf(fun)
606	if t.Kind() != r.Func {
607		c.Errorf("DeclFunc0(%s): expecting a function, received %v <%v>", name, fun, t)
608	}
609	bind := c.NewFuncBind(name, t)
610	index := bind.Desc.Index()
611	ret := func(env *Env) (Stmt, *Env) {
612		env.Vals[index] = funv
613		env.IP++
614		return env.Code[env.IP], env
615	}
616	c.append(ret)
617	return bind
618}
619
620// DeclEnvFunc0 compiles a function declaration that accesses interpreter's Env. For caller's convenience, returns allocated Bind
621func (c *Comp) DeclEnvFunc0(name string, envfun Function) *Bind {
622	t := c.TypeOfFunction()
623	bind := c.NewBind(name, ConstBind, t) // not a regular function... its type is not accurate
624	bind.Value = envfun                   // c.Binds[] is a map[string]*Bind => changes to *Bind propagate to the map
625	return bind
626}
627
628// DeclBuiltin0 compiles a builtin function declaration. For caller's convenience, returns allocated Bind
629func (c *Comp) DeclBuiltin0(name string, builtin Builtin) *Bind {
630	t := c.TypeOfBuiltin()
631	bind := c.NewBind(name, ConstBind, t) // not a regular function... its type is not accurate
632	bind.Value = builtin                  // c.Binds[] is a map[string]*Bind => changes to *Bind propagate to the map
633	return bind
634}
635
636// replacement of reflect.TypeOf() that uses xreflect.TypeOf()
637func (c *Comp) TypeOf(val interface{}) xr.Type {
638	v := c.Universe
639	v.TryResolve = c.tryResolveForXtype
640
641	return v.TypeOf(val)
642}
643
644func (c *Comp) tryResolveForXtype(name, pkgpath string) xr.Type {
645	if c.FileComp().Path != pkgpath {
646		return nil
647	}
648	var t xr.Type
649	for c != nil && t == nil {
650		t = c.Types[name]
651		c = c.Outer
652	}
653	return t
654}
655