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