• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2017 The Wuffs Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package ast
16
17import (
18	"fmt"
19	"math/big"
20
21	"github.com/google/wuffs/lib/interval"
22
23	t "github.com/google/wuffs/lang/token"
24)
25
26// Kind is what kind of node it is. For example, a top-level func or a numeric
27// constant. Kind is different from Type; the latter is used for type-checking
28// in the programming language sense.
29type Kind uint32
30
31// XType is the explicit type, directly from the source code.
32//
33// MType is the implicit type, deduced for expressions during type checking.
34//
35// MBounds are the implicit bounds, deduced during bounds checking.
36
37const (
38	KInvalid = Kind(iota)
39
40	KArg
41	KAssert
42	KAssign
43	KConst
44	KExpr
45	KField
46	KFile
47	KFunc
48	KIOBind
49	KIf
50	KIterate
51	KJump
52	KRet
53	KStatus
54	KStruct
55	KTypeExpr
56	KUse
57	KVar
58	KWhile
59)
60
61func (k Kind) String() string {
62	if uint(k) < uint(len(kindStrings)) {
63		return kindStrings[k]
64	}
65	return "KUnknown"
66}
67
68var kindStrings = [...]string{
69	KInvalid: "KInvalid",
70
71	KArg:      "KArg",
72	KAssert:   "KAssert",
73	KAssign:   "KAssign",
74	KConst:    "KConst",
75	KExpr:     "KExpr",
76	KField:    "KField",
77	KFile:     "KFile",
78	KFunc:     "KFunc",
79	KIOBind:   "KIOBind",
80	KIf:       "KIf",
81	KIterate:  "KIterate",
82	KJump:     "KJump",
83	KRet:      "KRet",
84	KStatus:   "KStatus",
85	KStruct:   "KStruct",
86	KTypeExpr: "KTypeExpr",
87	KUse:      "KUse",
88	KVar:      "KVar",
89	KWhile:    "KWhile",
90}
91
92type Flags uint32
93
94const (
95	// The low 8 bits are reserved. Effect values (Effect is a uint8) share the
96	// same values as Flags.
97
98	FlagsPublic           = Flags(0x00000100)
99	FlagsHasBreak         = Flags(0x00000200)
100	FlagsHasContinue      = Flags(0x00000400)
101	FlagsGlobalIdent      = Flags(0x00000800)
102	FlagsClassy           = Flags(0x00001000)
103	FlagsSubExprHasEffect = Flags(0x00002000)
104	FlagsRetsError        = Flags(0x00004000)
105	FlagsPrivateData      = Flags(0x00008000)
106)
107
108func (f Flags) AsEffect() Effect { return Effect(f) }
109
110type Effect uint8
111
112const (
113	EffectPure            = Effect(0)
114	EffectImpure          = Effect(effectBitImpure)
115	EffectImpureCoroutine = Effect(effectBitImpure | effectBitCoroutine)
116
117	effectBitImpure    = 0x01
118	effectBitCoroutine = 0x02
119
120	effectMask = Effect(0xFF)
121)
122
123func (e Effect) AsFlags() Flags { return Flags(e) }
124
125func (e Effect) Pure() bool      { return e == 0 }
126func (e Effect) Impure() bool    { return e&effectBitImpure != 0 }
127func (e Effect) Coroutine() bool { return e&effectBitCoroutine != 0 }
128
129func (e Effect) WeakerThan(o Effect) bool { return e < o }
130
131func (e Effect) String() string {
132	switch e & effectMask {
133	case EffectPure:
134		return ""
135	case EffectImpure:
136		return "!"
137	case EffectImpureCoroutine:
138		return "?"
139	}
140	return "‽INVALID_EFFECT‽"
141}
142
143type Node struct {
144	kind  Kind
145	flags Flags
146
147	constValue *big.Int
148	mBounds    interval.IntRange
149	mType      *TypeExpr
150	jumpTarget Loop
151
152	filename string
153	line     uint32
154
155	// The idX fields' meaning depend on what kind of node it is.
156	//
157	// kind          id0           id1           id2           kind
158	// ------------------------------------------------------------
159	// Arg           .             .             name          Arg
160	// Assert        keyword       .             lit(reason)   Assert
161	// Assign        operator      .             .             Assign
162	// Const         .             pkg           name          Const
163	// Expr          operator      pkg           literal/ident Expr
164	// Field         .             .             name          Field
165	// File          .             .             .             File
166	// Func          funcName      receiverPkg   receiverName  Func
167	// IOBind        .             .             .             IOBind
168	// If            .             .             .             If
169	// Iterate       unroll        label         length        Iterate
170	// Jump          keyword       label         .             Jump
171	// Ret           keyword       .             .             Ret
172	// Status        keyword       pkg           lit(message)  Status
173	// Struct        .             pkg           name          Struct
174	// TypeExpr      decorator     pkg           name          TypeExpr
175	// Use           .             .             lit(path)     Use
176	// Var           operator      .             name          Var
177	// While         .             label         .             While
178	id0 t.ID
179	id1 t.ID
180	id2 t.ID
181
182	lhs *Node // Left Hand Side.
183	mhs *Node // Middle Hand Side.
184	rhs *Node // Right Hand Side.
185
186	list0 []*Node
187	list1 []*Node
188	list2 []*Node
189}
190
191func (n *Node) Kind() Kind                     { return n.kind }
192func (n *Node) MBounds() interval.IntRange     { return n.mBounds }
193func (n *Node) MType() *TypeExpr               { return n.mType }
194func (n *Node) SetMBounds(x interval.IntRange) { n.mBounds = x }
195func (n *Node) SetMType(x *TypeExpr)           { n.mType = x }
196
197func (n *Node) AsArg() *Arg           { return (*Arg)(n) }
198func (n *Node) AsAssert() *Assert     { return (*Assert)(n) }
199func (n *Node) AsAssign() *Assign     { return (*Assign)(n) }
200func (n *Node) AsConst() *Const       { return (*Const)(n) }
201func (n *Node) AsExpr() *Expr         { return (*Expr)(n) }
202func (n *Node) AsField() *Field       { return (*Field)(n) }
203func (n *Node) AsFile() *File         { return (*File)(n) }
204func (n *Node) AsFunc() *Func         { return (*Func)(n) }
205func (n *Node) AsIOBind() *IOBind     { return (*IOBind)(n) }
206func (n *Node) AsIf() *If             { return (*If)(n) }
207func (n *Node) AsIterate() *Iterate   { return (*Iterate)(n) }
208func (n *Node) AsJump() *Jump         { return (*Jump)(n) }
209func (n *Node) AsRaw() *Raw           { return (*Raw)(n) }
210func (n *Node) AsRet() *Ret           { return (*Ret)(n) }
211func (n *Node) AsStatus() *Status     { return (*Status)(n) }
212func (n *Node) AsStruct() *Struct     { return (*Struct)(n) }
213func (n *Node) AsTypeExpr() *TypeExpr { return (*TypeExpr)(n) }
214func (n *Node) AsUse() *Use           { return (*Use)(n) }
215func (n *Node) AsVar() *Var           { return (*Var)(n) }
216func (n *Node) AsWhile() *While       { return (*While)(n) }
217
218func (n *Node) Walk(f func(*Node) error) error {
219	if n != nil {
220		if err := f(n); err != nil {
221			return err
222		}
223		for _, o := range n.AsRaw().SubNodes() {
224			if err := o.Walk(f); err != nil {
225				return err
226			}
227		}
228		for _, l := range n.AsRaw().SubLists() {
229			for _, o := range l {
230				if err := o.Walk(f); err != nil {
231					return err
232				}
233			}
234		}
235	}
236	return nil
237}
238
239type Loop interface {
240	AsNode() *Node
241	HasBreak() bool
242	HasContinue() bool
243	Label() t.ID
244	Asserts() []*Node
245	Body() []*Node
246	SetHasBreak()
247	SetHasContinue()
248}
249
250type Raw Node
251
252func (n *Raw) AsNode() *Node                  { return (*Node)(n) }
253func (n *Raw) Flags() Flags                   { return n.flags }
254func (n *Raw) FilenameLine() (string, uint32) { return n.filename, n.line }
255func (n *Raw) SubNodes() [3]*Node             { return [3]*Node{n.lhs, n.mhs, n.rhs} }
256func (n *Raw) SubLists() [3][]*Node           { return [3][]*Node{n.list0, n.list1, n.list2} }
257
258func (n *Raw) SetFilenameLine(f string, l uint32) { n.filename, n.line = f, l }
259
260func (n *Raw) SetPackage(tm *t.Map, pkg t.ID) error {
261	return n.AsNode().Walk(func(o *Node) error {
262		switch o.Kind() {
263		default:
264			return nil
265
266		case KConst, KFunc, KStatus, KStruct:
267			// No-op.
268
269		case KExpr:
270			if o.id0 != t.IDStatus {
271				return nil
272			}
273
274		case KTypeExpr:
275			if o.id0 != 0 {
276				return nil
277			}
278		}
279
280		if o.id1 == t.IDBase {
281			return nil
282		}
283		if o.id1 != 0 {
284			return fmt.Errorf(`invalid SetPackage(%q) call: old package: got %q, want ""`,
285				pkg.Str(tm), o.id1.Str(tm))
286		}
287		o.id1 = pkg
288		return nil
289	})
290}
291
292// MaxExprDepth is an advisory limit for an Expr's recursion depth.
293const MaxExprDepth = 255
294
295// Expr is an expression, such as "i", "+j" or "k + l[m(n, o)].p":
296//  - ID0:   <0|operator|IDOpenParen|IDOpenBracket|IDColon|IDDot>
297//  - ID1:   <0|pkg> (for statuses)
298//  - ID2:   <0|literal|ident>
299//  - LHS:   <nil|Expr>
300//  - MHS:   <nil|Expr>
301//  - RHS:   <nil|Expr|TypeExpr>
302//  - List0: <Arg|Expr> function call args, assoc. op args or list members.
303//
304// A zero ID0 means an identifier or literal in ID2, like `foo`, `42` or a
305// status literal like `"#foo"` or `pkg."$bar"`. For status literals, ID1 is
306// the package.
307//
308// For unary operators, ID0 is the operator and RHS is the operand.
309//
310// For binary operators, ID0 is the operator and LHS and RHS are the operands.
311//
312// For associative operators, ID0 is the operator and List0 holds the operands.
313//
314// The ID0 operator is in disambiguous form. For example, IDXUnaryPlus,
315// IDXBinaryPlus or IDXAssociativePlus, not a bare IDPlus.
316//
317// For function calls, like "LHS(List0)", ID0 is IDOpenParen.
318//
319// For indexes, like "LHS[RHS]", ID0 is IDOpenBracket.
320//
321// For slices, like "LHS[MHS:RHS]", ID0 is IDColon.
322//
323// For selectors, like "LHS.ID2", ID0 is IDDot.
324//
325// For lists, like "[0, 1, 2]", ID0 is IDComma.
326type Expr Node
327
328func (n *Expr) AsNode() *Node              { return (*Node)(n) }
329func (n *Expr) Effect() Effect             { return Effect(n.flags) }
330func (n *Expr) GlobalIdent() bool          { return n.flags&FlagsGlobalIdent != 0 }
331func (n *Expr) SubExprHasEffect() bool     { return n.flags&FlagsSubExprHasEffect != 0 }
332func (n *Expr) ConstValue() *big.Int       { return n.constValue }
333func (n *Expr) MBounds() interval.IntRange { return n.mBounds }
334func (n *Expr) MType() *TypeExpr           { return n.mType }
335func (n *Expr) Operator() t.ID             { return n.id0 }
336func (n *Expr) StatusQID() t.QID           { return t.QID{n.id1, n.id2} }
337func (n *Expr) Ident() t.ID                { return n.id2 }
338func (n *Expr) LHS() *Node                 { return n.lhs }
339func (n *Expr) MHS() *Node                 { return n.mhs }
340func (n *Expr) RHS() *Node                 { return n.rhs }
341func (n *Expr) Args() []*Node              { return n.list0 }
342
343func (n *Expr) SetConstValue(x *big.Int)       { n.constValue = x }
344func (n *Expr) SetGlobalIdent()                { n.flags |= FlagsGlobalIdent }
345func (n *Expr) SetMBounds(x interval.IntRange) { n.mBounds = x }
346func (n *Expr) SetMType(x *TypeExpr)           { n.mType = x }
347
348func NewExpr(flags Flags, operator t.ID, statusPkg t.ID, ident t.ID, lhs *Node, mhs *Node, rhs *Node, args []*Node) *Expr {
349	subExprEffect := Flags(0)
350	if lhs != nil {
351		subExprEffect |= lhs.flags & Flags(effectMask)
352	}
353	if mhs != nil {
354		subExprEffect |= mhs.flags & Flags(effectMask)
355	}
356	if rhs != nil {
357		subExprEffect |= rhs.flags & Flags(effectMask)
358	}
359	for _, o := range args {
360		subExprEffect |= o.flags & Flags(effectMask)
361	}
362	if subExprEffect != 0 {
363		flags |= subExprEffect | FlagsSubExprHasEffect
364	}
365
366	return &Expr{
367		kind:  KExpr,
368		flags: flags,
369		id0:   operator,
370		id1:   statusPkg,
371		id2:   ident,
372		lhs:   lhs,
373		mhs:   mhs,
374		rhs:   rhs,
375		list0: args,
376	}
377}
378
379// Assert is "assert RHS via ID2(args)", "pre etc", "inv etc" or "post etc":
380//  - ID0:   <IDAssert|IDPre|IDInv|IDPost>
381//  - ID2:   <string literal> reason
382//  - RHS:   <Expr>
383//  - List0: <Arg> reason arguments
384type Assert Node
385
386func (n *Assert) AsNode() *Node    { return (*Node)(n) }
387func (n *Assert) Keyword() t.ID    { return n.id0 }
388func (n *Assert) Reason() t.ID     { return n.id2 }
389func (n *Assert) Condition() *Expr { return n.rhs.AsExpr() }
390func (n *Assert) Args() []*Node    { return n.list0 }
391
392func NewAssert(keyword t.ID, condition *Expr, reason t.ID, args []*Node) *Assert {
393	return &Assert{
394		kind:  KAssert,
395		id0:   keyword,
396		id2:   reason,
397		rhs:   condition.AsNode(),
398		list0: args,
399	}
400}
401
402// Arg is "name:value".
403//  - ID2:   <ident> name
404//  - RHS:   <Expr> value
405type Arg Node
406
407func (n *Arg) AsNode() *Node { return (*Node)(n) }
408func (n *Arg) Name() t.ID    { return n.id2 }
409func (n *Arg) Value() *Expr  { return n.rhs.AsExpr() }
410
411func NewArg(name t.ID, value *Expr) *Arg {
412	return &Arg{
413		kind: KArg,
414		id2:  name,
415		rhs:  value.AsNode(),
416	}
417}
418
419// Assign is "LHS = RHS" or "LHS op= RHS" or "RHS":
420//  - ID0:   operator
421//  - LHS:   <nil|Expr>
422//  - RHS:   <Expr>
423type Assign Node
424
425func (n *Assign) AsNode() *Node  { return (*Node)(n) }
426func (n *Assign) Operator() t.ID { return n.id0 }
427func (n *Assign) LHS() *Expr     { return n.lhs.AsExpr() }
428func (n *Assign) RHS() *Expr     { return n.rhs.AsExpr() }
429
430func NewAssign(operator t.ID, lhs *Expr, rhs *Expr) *Assign {
431	return &Assign{
432		kind: KAssign,
433		id0:  operator,
434		lhs:  lhs.AsNode(),
435		rhs:  rhs.AsNode(),
436	}
437}
438
439// Var is "var ID2 LHS":
440//  - ID2:   name
441//  - LHS:   <TypeExpr>
442type Var Node
443
444func (n *Var) AsNode() *Node    { return (*Node)(n) }
445func (n *Var) Name() t.ID       { return n.id2 }
446func (n *Var) XType() *TypeExpr { return n.lhs.AsTypeExpr() }
447
448func NewVar(name t.ID, xType *TypeExpr) *Var {
449	return &Var{
450		kind: KVar,
451		id2:  name,
452		lhs:  xType.AsNode(),
453	}
454}
455
456// Field is a "name type" struct field:
457//  - FlagsPrivateData is the initializer need not explicitly memset to zero.
458//  - ID2:   name
459//  - LHS:   <TypeExpr>
460type Field Node
461
462func (n *Field) AsNode() *Node     { return (*Node)(n) }
463func (n *Field) PrivateData() bool { return n.flags&FlagsPrivateData != 0 }
464func (n *Field) Name() t.ID        { return n.id2 }
465func (n *Field) XType() *TypeExpr  { return n.lhs.AsTypeExpr() }
466
467func NewField(flags Flags, name t.ID, xType *TypeExpr) *Field {
468	return &Field{
469		kind:  KField,
470		flags: flags,
471		id2:   name,
472		lhs:   xType.AsNode(),
473	}
474}
475
476// IOBind is "io_bind (io:LHS, data:MHS) { List2 }" or "io_limit (io:LHS,
477// limit:MHS) { List2 }":
478//  - ID0:   <IDIOBind|IDIOLimit>
479//  - LHS:   <Expr>
480//  - MHS:   <Expr>
481//  - List2: <Statement> body
482type IOBind Node
483
484func (n *IOBind) AsNode() *Node { return (*Node)(n) }
485func (n *IOBind) Keyword() t.ID { return n.id0 }
486func (n *IOBind) IO() *Expr     { return n.lhs.AsExpr() }
487func (n *IOBind) Arg1() *Expr   { return n.mhs.AsExpr() }
488func (n *IOBind) Body() []*Node { return n.list2 }
489
490func NewIOBind(keyword t.ID, io *Expr, arg1 *Expr, body []*Node) *IOBind {
491	return &IOBind{
492		kind:  KIOBind,
493		id0:   keyword,
494		lhs:   io.AsNode(),
495		mhs:   arg1.AsNode(),
496		list2: body,
497	}
498}
499
500// Iterate is
501// "iterate:ID1 (assigns)(length:ID2, unroll:ID0), List1 { List2 } else RHS":
502//  - FlagsHasBreak    is the iterate has an explicit break
503//  - FlagsHasContinue is the iterate has an explicit continue
504//  - ID0:   unroll
505//  - ID1:   <0|label>
506//  - ID2:   length
507//  - RHS:   <nil|Iterate>
508//  - List0: <Assign> assigns
509//  - List1: <Assert> asserts
510//  - List2: <Statement> body
511type Iterate Node
512
513func (n *Iterate) AsNode() *Node         { return (*Node)(n) }
514func (n *Iterate) HasBreak() bool        { return n.flags&FlagsHasBreak != 0 }
515func (n *Iterate) HasContinue() bool     { return n.flags&FlagsHasContinue != 0 }
516func (n *Iterate) Unroll() t.ID          { return n.id0 }
517func (n *Iterate) Label() t.ID           { return n.id1 }
518func (n *Iterate) Length() t.ID          { return n.id2 }
519func (n *Iterate) ElseIterate() *Iterate { return n.rhs.AsIterate() }
520func (n *Iterate) Assigns() []*Node      { return n.list0 }
521func (n *Iterate) Asserts() []*Node      { return n.list1 }
522func (n *Iterate) Body() []*Node         { return n.list2 }
523
524func (n *Iterate) SetHasBreak()    { n.flags |= FlagsHasBreak }
525func (n *Iterate) SetHasContinue() { n.flags |= FlagsHasContinue }
526
527func NewIterate(label t.ID, assigns []*Node, length t.ID, unroll t.ID, asserts []*Node, body []*Node, elseIterate *Iterate) *Iterate {
528	return &Iterate{
529		kind:  KIterate,
530		id0:   unroll,
531		id1:   label,
532		id2:   length,
533		rhs:   elseIterate.AsNode(),
534		list0: assigns,
535		list1: asserts,
536		list2: body,
537	}
538}
539
540// While is "while:ID1 MHS, List1 { List2 }":
541//  - FlagsHasBreak    is the while has an explicit break
542//  - FlagsHasContinue is the while has an explicit continue
543//  - ID1:   <0|label>
544//  - MHS:   <Expr>
545//  - List1: <Assert> asserts
546//  - List2: <Statement> body
547//
548// TODO: should we be able to unroll while loops too?
549type While Node
550
551func (n *While) AsNode() *Node     { return (*Node)(n) }
552func (n *While) HasBreak() bool    { return n.flags&FlagsHasBreak != 0 }
553func (n *While) HasContinue() bool { return n.flags&FlagsHasContinue != 0 }
554func (n *While) Label() t.ID       { return n.id1 }
555func (n *While) Condition() *Expr  { return n.mhs.AsExpr() }
556func (n *While) Asserts() []*Node  { return n.list1 }
557func (n *While) Body() []*Node     { return n.list2 }
558
559func (n *While) SetHasBreak()    { n.flags |= FlagsHasBreak }
560func (n *While) SetHasContinue() { n.flags |= FlagsHasContinue }
561
562func NewWhile(label t.ID, condition *Expr, asserts []*Node, body []*Node) *While {
563	return &While{
564		kind:  KWhile,
565		id1:   label,
566		mhs:   condition.AsNode(),
567		list1: asserts,
568		list2: body,
569	}
570}
571
572// If is "if MHS { List2 } else RHS" or "if MHS { List2 } else { List1 }":
573//  - MHS:   <Expr>
574//  - RHS:   <nil|If>
575//  - List1: <Statement> if-false body
576//  - List2: <Statement> if-true body
577type If Node
578
579func (n *If) AsNode() *Node        { return (*Node)(n) }
580func (n *If) Condition() *Expr     { return n.mhs.AsExpr() }
581func (n *If) ElseIf() *If          { return n.rhs.AsIf() }
582func (n *If) BodyIfTrue() []*Node  { return n.list2 }
583func (n *If) BodyIfFalse() []*Node { return n.list1 }
584
585func NewIf(condition *Expr, bodyIfTrue []*Node, bodyIfFalse []*Node, elseIf *If) *If {
586	return &If{
587		kind:  KIf,
588		mhs:   condition.AsNode(),
589		rhs:   elseIf.AsNode(),
590		list1: bodyIfFalse,
591		list2: bodyIfTrue,
592	}
593}
594
595// Ret is "return LHS" or "yield LHS":
596//  - FlagsReturnsError LHS is an error status
597//  - ID0:   <IDReturn|IDYield>
598//  - LHS:   <Expr>
599type Ret Node
600
601func (n *Ret) AsNode() *Node   { return (*Node)(n) }
602func (n *Ret) RetsError() bool { return n.flags&FlagsRetsError != 0 }
603func (n *Ret) Keyword() t.ID   { return n.id0 }
604func (n *Ret) Value() *Expr    { return n.lhs.AsExpr() }
605
606func (n *Ret) SetRetsError() { n.flags |= FlagsRetsError }
607
608func NewRet(keyword t.ID, value *Expr) *Ret {
609	return &Ret{
610		kind: KRet,
611		id0:  keyword,
612		lhs:  value.AsNode(),
613	}
614}
615
616// Jump is "break" or "continue", with an optional label, "break:label":
617//  - ID0:   <IDBreak|IDContinue>
618//  - ID1:   <0|label>
619type Jump Node
620
621func (n *Jump) AsNode() *Node    { return (*Node)(n) }
622func (n *Jump) JumpTarget() Loop { return n.jumpTarget }
623func (n *Jump) Keyword() t.ID    { return n.id0 }
624func (n *Jump) Label() t.ID      { return n.id1 }
625
626func (n *Jump) SetJumpTarget(o Loop) { n.jumpTarget = o }
627
628func NewJump(keyword t.ID, label t.ID) *Jump {
629	return &Jump{
630		kind: KJump,
631		id0:  keyword,
632		id1:  label,
633	}
634}
635
636// MaxTypeExprDepth is an advisory limit for a TypeExpr's recursion depth.
637const MaxTypeExprDepth = 63
638
639// TypeExpr is a type expression, such as "base.u32", "base.u32[..8]", "foo",
640// "pkg.bar", "ptr T", "array[8] T", "slice T" or "table T":
641//  - ID0:   <0|IDArray|IDFunc|IDNptr|IDPtr|IDSlice|IDTable>
642//  - ID1:   <0|pkg>
643//  - ID2:   <0|type name>
644//  - LHS:   <nil|Expr>
645//  - MHS:   <nil|Expr>
646//  - RHS:   <nil|TypeExpr>
647//
648// An IDNptr or IDPtr ID0 means "nptr RHS" or "ptr RHS". RHS is the inner type.
649//
650// An IDArray ID0 means "array[LHS] RHS". RHS is the inner type.
651//
652// An IDSlice ID0 means "slice RHS". RHS is the inner type.
653//
654// An IDTable ID0 means "table RHS". RHS is the inner type.
655//
656// An IDFunc ID0 means "func ID2" or "func (LHS).ID2", a function or method
657// type. LHS is the receiver type, which may be nil. If non-nil, it will be a
658// pointee type: "T" instead of "ptr T", "ptr ptr T", etc.
659//
660// TODO: method effects: "foo" vs "foo!" vs "foo?".
661//
662// A zero ID0 means a (possibly package-qualified) type like "pkg.foo" or
663// "foo". ID1 is the "pkg" or zero, ID2 is the "foo".
664//
665// Numeric types can be refined as "foo[LHS..MHS]". LHS and MHS are Expr's,
666// possibly nil. For example, the LHS for "base.u32[..4095]" is nil.
667//
668// TODO: struct types, list types, nptr vs ptr.
669type TypeExpr Node
670
671func (n *TypeExpr) AsNode() *Node       { return (*Node)(n) }
672func (n *TypeExpr) Decorator() t.ID     { return n.id0 }
673func (n *TypeExpr) QID() t.QID          { return t.QID{n.id1, n.id2} }
674func (n *TypeExpr) FuncName() t.ID      { return n.id2 }
675func (n *TypeExpr) ArrayLength() *Expr  { return n.lhs.AsExpr() }
676func (n *TypeExpr) Receiver() *TypeExpr { return n.lhs.AsTypeExpr() }
677func (n *TypeExpr) Bounds() [2]*Expr    { return [2]*Expr{n.lhs.AsExpr(), n.mhs.AsExpr()} }
678func (n *TypeExpr) Min() *Expr          { return n.lhs.AsExpr() }
679func (n *TypeExpr) Max() *Expr          { return n.mhs.AsExpr() }
680func (n *TypeExpr) Inner() *TypeExpr    { return n.rhs.AsTypeExpr() }
681
682func (n *TypeExpr) Innermost() *TypeExpr {
683	for ; n != nil && n.Inner() != nil; n = n.Inner() {
684	}
685	return n
686}
687
688func (n *TypeExpr) Pointee() *TypeExpr {
689	for ; n != nil && (n.id0 == t.IDNptr || n.id0 == t.IDPtr); n = n.Inner() {
690	}
691	return n
692}
693
694func (n *TypeExpr) IsBool() bool {
695	return n.id0 == 0 && n.id1 == t.IDBase && n.id2 == t.IDBool
696}
697
698func (n *TypeExpr) IsIdeal() bool {
699	return n.id0 == 0 && n.id1 == t.IDBase && n.id2 == t.IDQIdeal
700}
701
702func (n *TypeExpr) IsIOType() bool {
703	return n.id0 == 0 && n.id1 == t.IDBase && (n.id2 == t.IDIOReader || n.id2 == t.IDIOWriter)
704}
705
706func (n *TypeExpr) IsNullptr() bool {
707	return n.id0 == 0 && n.id1 == t.IDBase && n.id2 == t.IDQNullptr
708}
709
710func (n *TypeExpr) IsNumType() bool {
711	return n.id0 == 0 && n.id1 == t.IDBase && n.id2.IsNumType()
712}
713
714func (n *TypeExpr) IsNumTypeOrIdeal() bool {
715	return n.id0 == 0 && n.id1 == t.IDBase && n.id2.IsNumTypeOrIdeal()
716}
717
718func (n *TypeExpr) IsRefined() bool {
719	return n.id0 == 0 && n.id1 == t.IDBase && n.id2.IsNumType() && (n.lhs != nil || n.mhs != nil)
720}
721
722func (n *TypeExpr) IsStatus() bool {
723	return n.id0 == 0 && n.id1 == t.IDBase && n.id2 == t.IDStatus
724}
725
726func (n *TypeExpr) IsArrayType() bool {
727	return n.id0 == t.IDArray
728}
729
730func (n *TypeExpr) IsPointerType() bool {
731	return n.id0 == t.IDNptr || n.id0 == t.IDPtr
732}
733
734func (n *TypeExpr) IsSliceType() bool {
735	return n.id0 == t.IDSlice
736}
737
738func (n *TypeExpr) IsTableType() bool {
739	return n.id0 == t.IDTable
740}
741
742func (n *TypeExpr) IsUnsignedInteger() bool {
743	return n.id0 == 0 && n.id1 == t.IDBase &&
744		(n.id2 == t.IDU8 || n.id2 == t.IDU16 || n.id2 == t.IDU32 || n.id2 == t.IDU64)
745}
746
747func (n *TypeExpr) HasPointers() bool {
748	for ; n != nil; n = n.Inner() {
749		switch n.id0 {
750		case 0:
751			if n.id1 == t.IDBase {
752				switch n.id2 {
753				case t.IDIOReader, t.IDIOWriter:
754					return true
755				}
756			}
757		case t.IDNptr, t.IDPtr, t.IDSlice, t.IDTable:
758			return true
759		}
760	}
761	return false
762}
763
764func (n *TypeExpr) Unrefined() *TypeExpr {
765	if !n.IsRefined() {
766		return n
767	}
768	return &TypeExpr{
769		kind: KTypeExpr,
770		id1:  n.id1,
771		id2:  n.id2,
772	}
773}
774
775func NewTypeExpr(decorator t.ID, pkg t.ID, name t.ID, alenRecvMin *Node, max *Expr, inner *TypeExpr) *TypeExpr {
776	return &TypeExpr{
777		kind: KTypeExpr,
778		id0:  decorator,
779		id1:  pkg,
780		id2:  name,
781		lhs:  alenRecvMin,
782		mhs:  max.AsNode(),
783		rhs:  inner.AsNode(),
784	}
785}
786
787// MaxBodyDepth is an advisory limit for a function body's recursion depth.
788const MaxBodyDepth = 255
789
790// Func is "func ID2.ID0(LHS)(RHS) { List2 }":
791//  - FlagsPublic      is "pub" vs "pri"
792//  - ID0:   funcName
793//  - ID1:   <0|receiverPkg> (set by calling SetPackage)
794//  - ID2:   <0|receiverName>
795//  - LHS:   <Struct> in-parameters
796//  - RHS:   <Struct> out-parameters
797//  - List1: <Assert> asserts
798//  - List2: <Statement> body
799//
800// Statement means one of:
801//  - Assert
802//  - Assign
803//  - IOBind
804//  - If
805//  - Iterate
806//  - Jump
807//  - Ret
808//  - Var
809//  - While
810type Func Node
811
812func (n *Func) AsNode() *Node    { return (*Node)(n) }
813func (n *Func) Effect() Effect   { return Effect(n.flags) }
814func (n *Func) Public() bool     { return n.flags&FlagsPublic != 0 }
815func (n *Func) Filename() string { return n.filename }
816func (n *Func) Line() uint32     { return n.line }
817func (n *Func) QQID() t.QQID     { return t.QQID{n.id1, n.id2, n.id0} }
818func (n *Func) Receiver() t.QID  { return t.QID{n.id1, n.id2} }
819func (n *Func) FuncName() t.ID   { return n.id0 }
820func (n *Func) In() *Struct      { return n.lhs.AsStruct() }
821func (n *Func) Out() *TypeExpr   { return n.rhs.AsTypeExpr() }
822func (n *Func) Asserts() []*Node { return n.list1 }
823func (n *Func) Body() []*Node    { return n.list2 }
824
825func NewFunc(flags Flags, filename string, line uint32, receiverName t.ID, funcName t.ID, in *Struct, out *TypeExpr, asserts []*Node, body []*Node) *Func {
826	return &Func{
827		kind:     KFunc,
828		flags:    flags,
829		filename: filename,
830		line:     line,
831		id0:      funcName,
832		id2:      receiverName,
833		lhs:      in.AsNode(),
834		rhs:      out.AsNode(),
835		list1:    asserts,
836		list2:    body,
837	}
838}
839
840// Status is "error (RHS) ID2" or "suspension (RHS) ID2":
841//  - FlagsPublic      is "pub" vs "pri"
842//  - ID1:   <0|pkg> (set by calling SetPackage)
843//  - ID2:   message
844type Status Node
845
846func (n *Status) AsNode() *Node    { return (*Node)(n) }
847func (n *Status) Public() bool     { return n.flags&FlagsPublic != 0 }
848func (n *Status) Filename() string { return n.filename }
849func (n *Status) Line() uint32     { return n.line }
850func (n *Status) QID() t.QID       { return t.QID{n.id1, n.id2} }
851
852func NewStatus(flags Flags, filename string, line uint32, message t.ID) *Status {
853	return &Status{
854		kind:     KStatus,
855		flags:    flags,
856		filename: filename,
857		line:     line,
858		id2:      message,
859	}
860}
861
862// Const is "const ID2 LHS = RHS":
863//  - FlagsPublic      is "pub" vs "pri"
864//  - ID1:   <0|pkg> (set by calling SetPackage)
865//  - ID2:   name
866//  - LHS:   <TypeExpr>
867//  - RHS:   <Expr>
868type Const Node
869
870func (n *Const) AsNode() *Node    { return (*Node)(n) }
871func (n *Const) Public() bool     { return n.flags&FlagsPublic != 0 }
872func (n *Const) Filename() string { return n.filename }
873func (n *Const) Line() uint32     { return n.line }
874func (n *Const) QID() t.QID       { return t.QID{n.id1, n.id2} }
875func (n *Const) XType() *TypeExpr { return n.lhs.AsTypeExpr() }
876func (n *Const) Value() *Expr     { return n.rhs.AsExpr() }
877
878func NewConst(flags Flags, filename string, line uint32, name t.ID, xType *TypeExpr, value *Expr) *Const {
879	return &Const{
880		kind:     KConst,
881		flags:    flags,
882		filename: filename,
883		line:     line,
884		id2:      name,
885		lhs:      xType.AsNode(),
886		rhs:      value.AsNode(),
887	}
888}
889
890// Struct is "struct ID2(List0)" or "struct ID2?(List0)":
891//  - FlagsPublic      is "pub" vs "pri"
892//  - FlagsClassy      is "ID2" vs "ID2?"
893//  - ID1:   <0|pkg> (set by calling SetPackage)
894//  - ID2:   name
895//  - List0: <Field> fields
896//
897// The question mark indicates a classy struct - one that supports methods,
898// especially coroutines.
899type Struct Node
900
901func (n *Struct) AsNode() *Node    { return (*Node)(n) }
902func (n *Struct) Classy() bool     { return n.flags&FlagsClassy != 0 }
903func (n *Struct) Public() bool     { return n.flags&FlagsPublic != 0 }
904func (n *Struct) Filename() string { return n.filename }
905func (n *Struct) Line() uint32     { return n.line }
906func (n *Struct) QID() t.QID       { return t.QID{n.id1, n.id2} }
907func (n *Struct) Fields() []*Node  { return n.list0 }
908
909func NewStruct(flags Flags, filename string, line uint32, name t.ID, fields []*Node) *Struct {
910	return &Struct{
911		kind:     KStruct,
912		flags:    flags,
913		filename: filename,
914		line:     line,
915		id2:      name,
916		list0:    fields,
917	}
918}
919
920// Use is "use ID2":
921//  - ID2:   <string literal> package path
922type Use Node
923
924func (n *Use) AsNode() *Node    { return (*Node)(n) }
925func (n *Use) Filename() string { return n.filename }
926func (n *Use) Line() uint32     { return n.line }
927func (n *Use) Path() t.ID       { return n.id2 }
928
929func NewUse(filename string, line uint32, path t.ID) *Use {
930	return &Use{
931		kind:     KUse,
932		filename: filename,
933		line:     line,
934		id2:      path,
935	}
936}
937
938// File is a file of source code:
939//  - List0: <Const|Func|Status|Struct|Use> top-level declarations
940type File Node
941
942func (n *File) AsNode() *Node          { return (*Node)(n) }
943func (n *File) Filename() string       { return n.filename }
944func (n *File) TopLevelDecls() []*Node { return n.list0 }
945
946func NewFile(filename string, topLevelDecls []*Node) *File {
947	return &File{
948		kind:     KFile,
949		filename: filename,
950		list0:    topLevelDecls,
951	}
952}
953