1package interp
2
3import (
4	"log"
5	"reflect"
6	"strconv"
7)
8
9// A sKind represents the kind of symbol.
10type sKind uint
11
12// Symbol kinds for the Go interpreter.
13const (
14	undefSym sKind = iota
15	binSym         // Binary from runtime
16	bltnSym        // Builtin
17	constSym       // Constant
18	funcSym        // Function
19	labelSym       // Label
20	pkgSym         // Package
21	typeSym        // Type
22	varSym         // Variable
23)
24
25var symKinds = [...]string{
26	undefSym: "undefSym",
27	binSym:   "binSym",
28	bltnSym:  "bltnSym",
29	constSym: "constSym",
30	funcSym:  "funcSym",
31	labelSym: "labelSym",
32	pkgSym:   "pkgSym",
33	typeSym:  "typeSym",
34	varSym:   "varSym",
35}
36
37func (k sKind) String() string {
38	if k < sKind(len(symKinds)) {
39		return symKinds[k]
40	}
41	return "SymKind(" + strconv.Itoa(int(k)) + ")"
42}
43
44// A symbol represents an interpreter object such as type, constant, var, func,
45// label, builtin or binary object. Symbols are defined within a scope.
46type symbol struct {
47	kind    sKind
48	typ     *itype        // Type of value
49	node    *node         // Node value if index is negative
50	from    []*node       // list of nodes jumping to node if kind is label, or nil
51	recv    *receiver     // receiver node value, if sym refers to a method
52	index   int           // index of value in frame or -1
53	rval    reflect.Value // default value (used for constants)
54	builtin bltnGenerator // Builtin function or nil
55	global  bool          // true if symbol is defined in global space
56}
57
58// scope type stores symbols in maps, and frame layout as array of types
59// The purposes of scopes are to manage the visibility of each symbol
60// and to store the memory frame layout information (type and index in frame)
61// at each level (global, package, functions)
62//
63// scopes are organized in a stack fashion: a first scope (universe) is created
64// once at global level, and for each block (package, func, for, etc...), a new
65// scope is pushed at entry, and poped at exit.
66//
67// Nested scopes with the same level value use the same frame: it allows to have
68// exactly one frame per function, with a fixed position for each variable (named
69// or not), no matter the inner complexity (number of nested blocks in the function)
70//
71// In symbols, the index value corresponds to the index in scope.types, and at
72// execution to the index in frame, created exactly from the types layout.
73//
74type scope struct {
75	anc         *scope             // ancestor upper scope
76	child       []*scope           // included scopes
77	def         *node              // function definition node this scope belongs to, or nil
78	loop        *node              // loop exit node for break statement
79	loopRestart *node              // loop restart node for continue statement
80	pkgID       string             // unique id of package in which scope is defined
81	pkgName     string             // package name for the package
82	types       []reflect.Type     // frame layout, may be shared by same level scopes
83	level       int                // frame level: number of frame indirections to access var during execution
84	sym         map[string]*symbol // map of symbols defined in this current scope
85	global      bool               // true if scope refers to global space (single frame for universe and package level scopes)
86	iota        int                // iota value in this scope
87}
88
89// push creates a new child scope and chain it to the current one.
90func (s *scope) push(indirect bool) *scope {
91	sc := &scope{anc: s, level: s.level, sym: map[string]*symbol{}}
92	s.child = append(s.child, sc)
93	if indirect {
94		sc.types = []reflect.Type{}
95		sc.level = s.level + 1
96	} else {
97		// Propagate size, types, def and global as scopes at same level share the same frame.
98		sc.types = s.types
99		sc.def = s.def
100		sc.global = s.global
101		sc.level = s.level
102	}
103	// inherit loop state and pkgID from ancestor
104	sc.loop, sc.loopRestart, sc.pkgID = s.loop, s.loopRestart, s.pkgID
105	return sc
106}
107
108func (s *scope) pushBloc() *scope { return s.push(false) }
109func (s *scope) pushFunc() *scope { return s.push(true) }
110
111func (s *scope) pop() *scope {
112	if s.level == s.anc.level {
113		// Propagate size and types, as scopes at same level share the same frame.
114		s.anc.types = s.types
115	}
116	return s.anc
117}
118
119func (s *scope) upperLevel() *scope {
120	level := s.level
121	for s != nil && s.level == level {
122		s = s.anc
123	}
124	return s
125}
126
127// lookup searches for a symbol in the current scope, and upper ones if not found
128// it returns the symbol, the number of indirections level from the current scope
129// and status (false if no result).
130func (s *scope) lookup(ident string) (*symbol, int, bool) {
131	level := s.level
132	for {
133		if sym, ok := s.sym[ident]; ok {
134			if sym.global {
135				return sym, globalFrame, true
136			}
137			return sym, level - s.level, true
138		}
139		if s.anc == nil {
140			break
141		}
142		s = s.anc
143	}
144	return nil, 0, false
145}
146
147// lookdown searches for a symbol in the current scope and included ones, recursively.
148// It returns the first found symbol and true, or nil and false.
149func (s *scope) lookdown(ident string) (*symbol, bool) {
150	if sym, ok := s.sym[ident]; ok {
151		return sym, true
152	}
153	for _, c := range s.child {
154		if sym, ok := c.lookdown(ident); ok {
155			return sym, true
156		}
157	}
158	return nil, false
159}
160
161func (s *scope) rangeChanType(n *node) *itype {
162	if sym, _, found := s.lookup(n.child[1].ident); found {
163		if t := sym.typ; len(n.child) == 3 && t != nil && (t.cat == chanT || t.cat == chanRecvT) {
164			return t
165		}
166	}
167
168	c := n.child[1]
169	if c.typ == nil {
170		return nil
171	}
172	switch {
173	case c.typ.cat == chanT, c.typ.cat == chanRecvT:
174		return c.typ
175	case c.typ.cat == valueT && c.typ.rtype.Kind() == reflect.Chan:
176		dir := chanSendRecv
177		switch c.typ.rtype.ChanDir() {
178		case reflect.RecvDir:
179			dir = chanRecv
180		case reflect.SendDir:
181			dir = chanSend
182		}
183		return chanOf(valueTOf(c.typ.rtype.Elem()), dir)
184	}
185
186	return nil
187}
188
189// fixType returns the input type, or a valid default type for untyped constant.
190func (s *scope) fixType(t *itype) *itype {
191	if !t.untyped || t.cat != valueT {
192		return t
193	}
194	switch typ := t.TypeOf(); typ.Kind() {
195	case reflect.Int64:
196		return s.getType("int")
197	case reflect.Uint64:
198		return s.getType("uint")
199	case reflect.Float64:
200		return s.getType("float64")
201	case reflect.Complex128:
202		return s.getType("complex128")
203	}
204	return t
205}
206
207func (s *scope) getType(ident string) *itype {
208	var t *itype
209	if sym, _, found := s.lookup(ident); found {
210		if sym.kind == typeSym {
211			t = sym.typ
212		}
213	}
214	return t
215}
216
217// add adds a type to the scope types array, and returns its index.
218func (s *scope) add(typ *itype) (index int) {
219	if typ == nil {
220		log.Panic("nil type")
221	}
222	index = len(s.types)
223	t := typ.frameType()
224	if t == nil {
225		log.Panic("nil reflect type")
226	}
227	s.types = append(s.types, t)
228	return
229}
230
231func (interp *Interpreter) initScopePkg(pkgID, pkgName string) *scope {
232	sc := interp.universe
233
234	interp.mutex.Lock()
235	if _, ok := interp.scopes[pkgID]; !ok {
236		interp.scopes[pkgID] = sc.pushBloc()
237	}
238	sc = interp.scopes[pkgID]
239	sc.pkgID = pkgID
240	sc.pkgName = pkgName
241	interp.mutex.Unlock()
242	return sc
243}
244