summaryrefslogtreecommitdiff
path: root/src/cmd/internal/gc/syntax.go
blob: ac7c28578b3cc053bff3eca66ecf5948538f2c03 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// “Abstract” syntax representation.

package gc

// A Node is a single node in the syntax tree.
// Actually the syntax tree is a syntax DAG, because there is only one
// node with Op=ONAME for a given instance of a variable x.
// The same is true for Op=OTYPE and Op=OLITERAL.
type Node struct {
	// Tree structure.
	// Generic recursive walks should follow these fields.
	Left  *Node
	Right *Node
	Ntest *Node
	Nincr *Node
	Ninit *NodeList
	Nbody *NodeList
	Nelse *NodeList
	List  *NodeList
	Rlist *NodeList

	Op             uint8
	Nointerface    bool
	Ullman         uint8 // sethi/ullman number
	Addable        uint8 // type of addressability - 0 is not addressable
	Etype          uint8 // op for OASOP, etype for OTYPE, exclam for export
	Bounded        bool  // bounds check unnecessary
	Class          uint8 // PPARAM, PAUTO, PEXTERN, etc
	Method         uint8 // OCALLMETH name
	Embedded       uint8 // ODCLFIELD embedded type
	Colas          uint8 // OAS resulting from :=
	Diag           uint8 // already printed error about this
	Noescape       bool  // func arguments do not escape
	Nosplit        bool  // func should not execute on separate stack
	Nowritebarrier bool  // emit compiler error instead of write barrier
	Walkdef        uint8
	Typecheck      uint8
	Local          bool
	Dodata         uint8
	Initorder      uint8
	Used           bool
	Isddd          bool // is the argument variadic
	Readonly       bool
	Implicit       bool
	Addrtaken      bool  // address taken, even if not moved to heap
	Assigned       bool  // is the variable ever assigned to
	Captured       bool  // is the variable captured by a closure
	Byval          bool  // is the variable captured by value or by reference
	Dupok          bool  // duplicate definitions ok (for func)
	Wrapper        bool  // is method wrapper (for func)
	Reslice        bool  // this is a reslice x = x[0:y] or x = append(x, ...)
	Likely         int8  // likeliness of if statement
	Hasbreak       bool  // has break statement
	Needzero       bool  // if it contains pointers, needs to be zeroed on function entry
	Needctxt       bool  // function uses context register (has closure variables)
	Esc            uint8 // EscXXX
	Funcdepth      int32

	// most nodes
	Type *Type
	Orig *Node // original form, for printing, and tracking copies of ONAMEs

	// func
	Nname     *Node
	Shortname *Node
	Enter     *NodeList
	Exit      *NodeList
	Cvars     *NodeList // closure params
	Dcl       *NodeList // autodcl for this func/closure
	Inl       *NodeList // copy of the body for use in inlining
	Inldcl    *NodeList // copy of dcl for use in inlining
	Closgen   int
	Outerfunc *Node

	// OLITERAL/OREGISTER
	Val Val

	// ONAME
	Ntype     *Node
	Defn      *Node // ONAME: initializing assignment; OLABEL: labeled statement
	Pack      *Node // real package for import . names
	Curfn     *Node // function for local variables
	Paramfld  *Type // TFIELD for this PPARAM; also for ODOT, curfn
	Decldepth int   // declaration loop depth, increased for every loop or label

	// ONAME func param with PHEAP
	Heapaddr   *Node // temp holding heap address of param
	Outerexpr  *Node // expression copied into closure for variable
	Stackparam *Node // OPARAM node referring to stack copy of param
	Alloc      *Node // allocation call

	// ONAME closure param with PPARAMREF
	Outer   *Node // outer PPARAMREF in nested closure
	Closure *Node // ONAME/PHEAP <-> ONAME/PPARAMREF
	Top     int   // top context (Ecall, Eproc, etc)

	// ONAME substitute while inlining
	Inlvar *Node

	// OPACK
	Pkg *Pkg

	// OARRAYLIT, OMAPLIT, OSTRUCTLIT.
	Initplan *InitPlan

	// Escape analysis.
	Escflowsrc   *NodeList // flow(this, src)
	Escretval    *NodeList // on OCALLxxx, list of dummy return values
	Escloopdepth int       // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes

	Sym       *Sym  // various
	InlCost   int32 // unique name for OTYPE/ONAME
	Vargen    int32
	Lineno    int32
	Endlineno int32
	Xoffset   int64
	Stkdelta  int64 // offset added by stack frame compaction phase.
	Ostk      int32
	Iota      int32
	Walkgen   uint32
	Esclevel  int32
	Opt       interface{} // for optimization passes
}

// Node ops.
const (
	OXXX = iota

	// names
	ONAME    // var, const or func name
	ONONAME  // unnamed arg or return value: f(int, string) (int, error) { etc }
	OTYPE    // type name
	OPACK    // import
	OLITERAL // literal

	// expressions
	OADD             // x + y
	OSUB             // x - y
	OOR              // x | y
	OXOR             // x ^ y
	OADDSTR          // s + "foo"
	OADDR            // &x
	OANDAND          // b0 && b1
	OAPPEND          // append
	OARRAYBYTESTR    // string(bytes)
	OARRAYBYTESTRTMP // string(bytes) ephemeral
	OARRAYRUNESTR    // string(runes)
	OSTRARRAYBYTE    // []byte(s)
	OSTRARRAYBYTETMP // []byte(s) ephemeral
	OSTRARRAYRUNE    // []rune(s)
	OAS              // x = y or x := y
	OAS2             // x, y, z = xx, yy, zz
	OAS2FUNC         // x, y = f()
	OAS2RECV         // x, ok = <-c
	OAS2MAPR         // x, ok = m["foo"]
	OAS2DOTTYPE      // x, ok = I.(int)
	OASOP            // x += y
	OCALL            // function call, method call or type conversion, possibly preceded by defer or go.
	OCALLFUNC        // f()
	OCALLMETH        // t.Method()
	OCALLINTER       // err.Error()
	OCALLPART        // t.Method (without ())
	OCAP             // cap
	OCLOSE           // close
	OCLOSURE         // f = func() { etc }
	OCMPIFACE        // err1 == err2
	OCMPSTR          // s1 == s2
	OCOMPLIT         // composite literal, typechecking may convert to a more specific OXXXLIT.
	OMAPLIT          // M{"foo":3, "bar":4}
	OSTRUCTLIT       // T{x:3, y:4}
	OARRAYLIT        // [2]int{3, 4}
	OPTRLIT          // &T{x:3, y:4}
	OCONV            // var i int; var u uint; i = int(u)
	OCONVIFACE       // I(t)
	OCONVNOP         // type Int int; var i int; var j Int; i = int(j)
	OCOPY            // copy
	ODCL             // var x int
	ODCLFUNC         // func f() or func (r) f()
	ODCLFIELD        // struct field, interface field, or func/method argument/return value.
	ODCLCONST        // const pi = 3.14
	ODCLTYPE         // type Int int
	ODELETE          // delete
	ODOT             // t.x
	ODOTPTR          // p.x that is implicitly (*p).x
	ODOTMETH         // t.Method
	ODOTINTER        // err.Error
	OXDOT            // t.x, typechecking may convert to a more specific ODOTXXX.
	ODOTTYPE         // e = err.(MyErr)
	ODOTTYPE2        // e, ok = err.(MyErr)
	OEQ              // x == y
	ONE              // x != y
	OLT              // x < y
	OLE              // x <= y
	OGE              // x >= y
	OGT              // x > y
	OIND             // *p
	OINDEX           // a[i]
	OINDEXMAP        // m[s]
	OKEY             // The x:3 in t{x:3, y:4}, the 1:2 in a[1:2], the 2:20 in [3]int{2:20}, etc.
	OPARAM           // The on-stack copy of a parameter or return value that escapes.
	OLEN             // len
	OMAKE            // make, typechecking may convert to a more specific OMAKEXXX.
	OMAKECHAN        // make(chan int)
	OMAKEMAP         // make(map[string]int)
	OMAKESLICE       // make([]int, 0)
	OMUL             // *
	ODIV             // x / y
	OMOD             // x % y
	OLSH             // x << u
	ORSH             // x >> u
	OAND             // x & y
	OANDNOT          // x &^ y
	ONEW             // new
	ONOT             // !b
	OCOM             // ^x
	OPLUS            // +x
	OMINUS           // -y
	OOROR            // b1 || b2
	OPANIC           // panic
	OPRINT           // print
	OPRINTN          // println
	OPAREN           // (x)
	OSEND            // c <- x
	OSLICE           // v[1:2], typechecking may convert to a more specific OSLICEXXX.
	OSLICEARR        // a[1:2]
	OSLICESTR        // s[1:2]
	OSLICE3          // v[1:2:3], typechecking may convert to OSLICE3ARR.
	OSLICE3ARR       // a[1:2:3]
	ORECOVER         // recover
	ORECV            // <-c
	ORUNESTR         // string(i)
	OSELRECV         // case x = <-c:
	OSELRECV2        // case x, ok = <-c:
	OIOTA            // iota
	OREAL            // real
	OIMAG            // imag
	OCOMPLEX         // complex

	// statements
	OBLOCK    // block of code
	OBREAK    // break
	OCASE     // case, after being verified by swt.c's casebody.
	OXCASE    // case, before verification.
	OCONTINUE // continue
	ODEFER    // defer
	OEMPTY    // no-op
	OFALL     // fallthrough, after being verified by swt.c's casebody.
	OXFALL    // fallthrough, before verification.
	OFOR      // for
	OGOTO     // goto
	OIF       // if
	OLABEL    // label:
	OPROC     // go
	ORANGE    // range
	ORETURN   // return
	OSELECT   // select
	OSWITCH   // switch x
	OTYPESW   // switch err.(type)

	// types
	OTCHAN   // chan int
	OTMAP    // map[string]int
	OTSTRUCT // struct{}
	OTINTER  // interface{}
	OTFUNC   // func()
	OTARRAY  // []int, [8]int, [N]int or [...]int

	// misc
	ODDD        // func f(args ...int) or f(l...) or var a = [...]int{0, 1, 2}.
	ODDDARG     // func f(args ...int), introduced by escape analysis.
	OINLCALL    // intermediary representation of an inlined call.
	OEFACE      // itable and data words of an empty-interface value.
	OITAB       // itable word of an interface value.
	OSPTR       // base pointer of a slice or string.
	OCLOSUREVAR // variable reference at beginning of closure function
	OCFUNC      // reference to c function pointer (not go func value)
	OCHECKNIL   // emit code to ensure pointer/interface not nil
	OVARKILL    // variable is dead

	// thearch-specific registers
	OREGISTER // a register, such as AX.
	OINDREG   // offset plus indirect of a register, such as 8(SP).

	// 386/amd64-specific opcodes
	OCMP    // compare: ACMP.
	ODEC    // decrement: ADEC.
	OINC    // increment: AINC.
	OEXTEND // extend: ACWD/ACDQ/ACQO.
	OHMUL   // high mul: AMUL/AIMUL for unsigned/signed (OMUL uses AIMUL for both).
	OLROT   // left rotate: AROL.
	ORROTC  // right rotate-carry: ARCR.
	ORETJMP // return to other function

	OEND
)

/*
 * Every node has a walkgen field.
 * If you want to do a traversal of a node graph that
 * might contain duplicates and want to avoid
 * visiting the same nodes twice, increment walkgen
 * before starting.  Then before processing a node, do
 *
 *	if(n->walkgen == walkgen)
 *		return;
 *	n->walkgen = walkgen;
 *
 * Such a walk cannot call another such walk recursively,
 * because of the use of the global walkgen.
 */
var walkgen uint32

// A NodeList is a linked list of nodes.
// TODO(rsc): Some uses of NodeList should be made into slices.
// The remaining ones probably just need a simple linked list,
// not one with concatenation support.
type NodeList struct {
	N    *Node
	Next *NodeList
	End  *NodeList
}

// concat returns the concatenation of the lists a and b.
// The storage taken by both is reused for the result.
func concat(a *NodeList, b *NodeList) *NodeList {
	if a == nil {
		return b
	}
	if b == nil {
		return a
	}

	a.End.Next = b
	a.End = b.End
	b.End = nil
	return a
}

// list1 returns a one-element list containing n.
func list1(n *Node) *NodeList {
	if n == nil {
		return nil
	}
	if n.Op == OBLOCK && n.Ninit == nil {
		// Flatten list and steal storage.
		// Poison pointer to catch errant uses.
		l := n.List

		n.List = nil
		return l
	}

	l := new(NodeList)
	l.N = n
	l.End = l
	return l
}

// list returns the result of appending n to l.
func list(l *NodeList, n *Node) *NodeList {
	return concat(l, list1(n))
}

// listsort sorts *l in place according to the 3-way comparison function f.
// The algorithm is mergesort, so it is guaranteed to be O(n log n).
func listsort(l **NodeList, f func(*Node, *Node) int) {
	if *l == nil || (*l).Next == nil {
		return
	}

	l1 := *l
	l2 := *l
	for {
		l2 = l2.Next
		if l2 == nil {
			break
		}
		l2 = l2.Next
		if l2 == nil {
			break
		}
		l1 = l1.Next
	}

	l2 = l1.Next
	l1.Next = nil
	l2.End = (*l).End
	(*l).End = l1

	l1 = *l
	listsort(&l1, f)
	listsort(&l2, f)

	if f(l1.N, l2.N) < 0 {
		*l = l1
	} else {
		*l = l2
		l2 = l1
		l1 = *l
	}

	// now l1 == *l; and l1 < l2

	var le *NodeList
	for (l1 != nil) && (l2 != nil) {
		for (l1.Next != nil) && f(l1.Next.N, l2.N) < 0 {
			l1 = l1.Next
		}

		// l1 is last one from l1 that is < l2
		le = l1.Next // le is the rest of l1, first one that is >= l2
		if le != nil {
			le.End = (*l).End
		}

		(*l).End = l1       // cut *l at l1
		*l = concat(*l, l2) // glue l2 to *l's tail

		l1 = l2 // l1 is the first element of *l that is < the new l2
		l2 = le // ... because l2 now is the old tail of l1
	}

	*l = concat(*l, l2) // any remainder
}

// count returns the length of the list l.
func count(l *NodeList) int {
	n := int64(0)
	for ; l != nil; l = l.Next {
		n++
	}
	if int64(int(n)) != n { // Overflow.
		Yyerror("too many elements in list")
	}
	return int(n)
}