
1 // 2 // Copyright (c) 2006, Brian Frank and Andy Frank 3 // Licensed under the Academic Free License version 3.0 4 // 5 // History: 6 // 15 Sep 05 Brian Frank Creation 7 // 6 Jun 06 Brian Frank Ported from Java to Fan 8 // 9 10 ** 11 ** Parser is responsible for parsing a list of tokens into the 12 ** abstract syntax tree. At this point the CompilationUnit, Usings, 13 ** and TypeDefs are already populated by the ScanForUsingAndTypes 14 ** step. 15 ** 16 public class Parser : CompilerSupport 17 { 18 19 ////////////////////////////////////////////////////////////////////////// 20 // Construction 21 ////////////////////////////////////////////////////////////////////////// 22 23 ** 24 ** Construct the parser for the specified compilation unit. 25 ** 26 new make(Compiler compiler, CompilationUnit unit, ClosureExpr[] closures) 27 : super(compiler) 28 { 29 this.unit = unit 30 this.tokens = unit.tokens 31 this.numTokens = unit.tokens.size 32 this.closures = closures 33 this.suppressErr = false 34 if (compiler != null) this.isSys = compiler.isSys 35 reset(0) 36 } 37 38 ////////////////////////////////////////////////////////////////////////// 39 // Access 40 ////////////////////////////////////////////////////////////////////////// 41 42 ** 43 ** Top level parse a compilation unit: 44 ** 45 ** <compilationUnit> := [<usings>] <typeDef>* 46 ** 47 Void parse() 48 { 49 usings 50 while (curt !== Token.eof) typeDef 51 } 52 53 ////////////////////////////////////////////////////////////////////////// 54 // Usings 55 ////////////////////////////////////////////////////////////////////////// 56 57 ** 58 ** Parse <using>* - note that we are just skipping them because 59 ** they are already parsed by ScanForUsingsAndTypes. 60 ** 61 ** <using> := <usingPod> | <usingType> | <usingAs> 62 ** <usingPod> := "using" <id> <eos> 63 ** <usingType> := "using" <id> "::" <id> <eos> 64 ** <usingAs> := "using" <id> "::" <id> "as" <id> <eos> 65 ** 66 private Void usings() 67 { 68 while (curt == Token.usingKeyword) 69 { 70 consume 71 consumeId 72 if (curt === Token.doubleColon) 73 { 74 consume 75 consumeId 76 if (curt === Token.asKeyword) 77 { 78 consume 79 consumeId 80 } 81 } 82 endOfStmt 83 } 84 } 85 86 ////////////////////////////////////////////////////////////////////////// 87 // TypeDef 88 ////////////////////////////////////////////////////////////////////////// 89 90 ** 91 ** TypeDef: 92 ** <typeDef> := <classDef> | <mixinDef> | <enumDef> 93 ** 94 ** <classDef> := <classHeader> <classBody> 95 ** <classHeader> := [<doc>] <facets> <typeFlags> "class" [<inheritance>] 96 ** <classFlags> := [<protection>] ["abstract"] ["final"] 97 ** <classBody> := "{" <slotDefs> "}" 98 ** 99 ** <enumDef> := <enumHeader> <enumBody> 100 ** <enumHeader> := [<doc>] <facets> <protection> "enum" [<inheritance>] 101 ** <enumBody> := "{" <enumDefs> <slotDefs> "}" 102 ** 103 ** <mixinDef> := <enumHeader> <enumBody> 104 ** <mixinHeader> := [<doc>] <facets> <protection> "mixin" [<inheritance>] 105 ** <mixinBody> := "{" <slotDefs> "}" 106 ** 107 ** <protection> := "public" | "protected" | "private" | "internal" 108 ** <inheritance> := ":" <typeList> 109 ** 110 Void typeDef() 111 { 112 // [<doc>] 113 doc := doc() 114 if (curt === Token.eof) return 115 116 // <facets> 117 facets := facets() 118 119 // <flags> 120 flags := flags(false) 121 if (flags & ~ProtectionMask == 0) flags |= FConst.Public 122 123 // local working variables 124 loc := cur 125 isMixin := false 126 isEnum := false 127 128 // mixin, enum, or class 129 if (curt === Token.mixinKeyword) 130 { 131 if (flags & FConst.Abstract != 0) err("The 'abstract' modifier is implied on mixin", loc) 132 if (flags & FConst.Const != 0) err("Cannot use 'const' modifier on mixin", loc) 133 if (flags & FConst.Final != 0) err("Cannot use 'final' modifier on mixin", loc) 134 flags |= FConst.Mixin | FConst.Abstract 135 isMixin = true 136 consume 137 } 138 else if (curt === Token.enumKeyword) 139 { 140 if (flags & FConst.Const != 0) err("The 'const' modifier is implied on enum", loc) 141 if (flags & FConst.Final != 0) err("The 'final' modifier is implied on enum", loc) 142 if (flags & FConst.Abstract != 0) err("Cannot use 'abstract' modifier on enum", loc) 143 flags |= FConst.Enum | FConst.Const | FConst.Final 144 isEnum = true 145 consume 146 } 147 else 148 { 149 consume(Token.classKeyword) 150 } 151 152 // name 153 name := consumeId 154 // lookup TypeDef 155 def := unit.types.find |TypeDef def->Bool| { return def.name == name } 156 if (def == null) throw err("Invalid class definition", cur) 157 158 // populate it's doc, facets, and flags 159 def.doc = doc 160 def.facets = facets 161 def.flags = flags 162 163 // inheritance 164 if (curt === Token.colon) 165 { 166 // first inheritance type can be extends or mixin 167 consume 168 first := typeRef 169 if (!first.isMixin) 170 def.base = first 171 else 172 def.mixins.add(first) 173 174 // additional mixins 175 while (curt === Token.comma) 176 { 177 consume 178 def.mixins.add(typeRef) 179 } 180 } 181 182 // if no inheritance specified then apply default base class 183 if (def.base == null) 184 { 185 def.baseSpecified = false 186 if (isEnum) 187 def.base = ns.enumType 188 else if (def.qname != "sys::Obj") 189 def.base = ns.objType 190 } 191 192 // start class body 193 consume(Token.lbrace) 194 195 // if enum, parse values 196 if (isEnum) enumDefs(def) 197 198 // slots 199 curType = def 200 closureCount = 0 201 while (true) 202 { 203 doc = this.doc 204 if (curt === Token.rbrace) break 205 slot := slotDef(def, doc) 206 207 // do duplicate name error checking here 208 if (def.hasSlotDef(slot.name)) 209 { 210 err("Duplicate slot name '$slot.name'", slot.location) 211 } 212 else 213 { 214 def.addSlot(slot) 215 } 216 } 217 closureCount = null 218 curType = null 219 220 // end of class body 221 consume(Token.rbrace) 222 } 223 224 private Void mixins(TypeDef def) 225 { 226 consume // extends or mixin 227 def.mixins.add(typeRef) 228 while (curt === Token.comma) 229 { 230 consume 231 def.mixins.add(typeRef) 232 } 233 } 234 235 ////////////////////////////////////////////////////////////////////////// 236 // Flags 237 ////////////////////////////////////////////////////////////////////////// 238 239 ** 240 ** Parse any list of flags in any order, we will check invalid 241 ** combinations in the CheckErrors step. 242 ** 243 private Int flags(Bool normalize := true) 244 { 245 loc := cur 246 flags := 0 247 protection := false 248 for (done := false; !done; ) 249 { 250 oldFlags := flags 251 switch (curt) 252 { 253 case Token.abstractKeyword: flags |= FConst.Abstract 254 case Token.constKeyword: flags |= FConst.Const 255 case Token.finalKeyword: flags |= FConst.Final 256 case Token.internalKeyword: flags |= FConst.Internal; protection = true 257 case Token.nativeKeyword: flags |= FConst.Native 258 case Token.newKeyword: flags |= FConst.Ctor 259 case Token.overrideKeyword: flags |= FConst.Override 260 case Token.privateKeyword: flags |= FConst.Private; protection = true 261 case Token.protectedKeyword: flags |= FConst.Protected; protection = true 262 case Token.publicKeyword: flags |= FConst.Public; protection = true 263 case Token.readonlyKeyword: flags |= Readonly // Parser only flag 264 case Token.staticKeyword: flags |= FConst.Static 265 case Token.virtualKeyword: flags |= FConst.Virtual 266 default: done = true 267 } 268 if (done) break 269 if (oldFlags == flags) err("Repeated modifier") 270 oldFlags = flags 271 consume 272 } 273 274 if ((flags & FConst.Abstract !== 0) && (flags & FConst.Virtual !== 0)) 275 err("Abstract implies virtual", loc) 276 if ((flags & FConst.Override !== 0) && (flags & FConst.Virtual !== 0)) 277 err("Override implies virtual", loc) 278 279 if (normalize) 280 { 281 if (!protection) flags |= FConst.Public 282 if (flags & FConst.Abstract !== 0) flags |= FConst.Virtual 283 if (flags & FConst.Override !== 0) 284 { 285 if (flags & FConst.Final !== 0) 286 flags &= ~FConst.Final 287 else 288 flags |= FConst.Virtual 289 } 290 } 291 292 return flags 293 } 294 295 ////////////////////////////////////////////////////////////////////////// 296 // Enum 297 ////////////////////////////////////////////////////////////////////////// 298 299 ** 300 ** Enum definition list: 301 ** <enumDefs> := <enumDef> ("," <enumDef>)* <eos> 302 ** 303 private Void enumDefs(TypeDef def) 304 { 305 ordinal := 0 306 def.enumDefs.add(enumDef(ordinal++)) 307 while (curt === Token.comma) 308 { 309 consume 310 def.enumDefs.add(enumDef(ordinal++)) 311 } 312 endOfStmt 313 } 314 315 ** 316 ** Enum definition: 317 ** <enumDef> := <id> ["(" <args> ")"] 318 ** 319 private EnumDef enumDef(Int ordinal) 320 { 321 doc := doc() 322 323 def := EnumDef.make(cur) 324 def.doc = doc 325 def.ordinal = ordinal 326 def.name = consumeId 327 328 // optional ctor args 329 if (curt === Token.lparen) 330 { 331 consume(Token.lparen) 332 if (curt != Token.rparen) 333 { 334 while (true) 335 { 336 def.ctorArgs.add( expr ) 337 if (curt === Token.rparen) break 338 consume(Token.comma); 339 } 340 } 341 consume(Token.rparen) 342 } 343 344 return def 345 } 346 347 ////////////////////////////////////////////////////////////////////////// 348 // Slots 349 ////////////////////////////////////////////////////////////////////////// 350 351 ** 352 ** Slot definition: 353 ** <slotDef> := <fieldDef> | <methodDef> | <ctorDef> 354 ** 355 private SlotDef slotDef(TypeDef parent, Str[] doc) 356 { 357 // check for static {} class initialization 358 if (curt === Token.staticKeyword && peekt === Token.lbrace) 359 { 360 location := cur 361 consume 362 curMethod = MethodDef.makeStaticInit(location, parent, null) 363 curMethod.code = block(true) 364 return curMethod 365 } 366 367 // all members start with facets, flags 368 loc := cur 369 facets := facets() 370 flags := flags() 371 372 // check if this is a Java style constructor, log error and parse like Fan sytle ctor 373 if (curt === Token.identifier && cur.val == parent.name && peekt == Token.lparen) 374 { 375 err("Invalid constructor syntax - use new keyword") 376 return methodDef(loc, parent, doc, facets, flags|FConst.Ctor, TypeRef.make(loc, ns.voidType), consumeId) 377 } 378 379 // check for inferred typed field 380 // if = used rather than := then fieldDef() will log error 381 if (curt === Token.identifier && (peekt === Token.defAssign || peekt === Token.assign)) 382 { 383 name := consumeId 384 return fieldDef(loc, parent, doc, facets, flags, null, name) 385 } 386 387 // check for constructor 388 if (flags & FConst.Ctor !== 0) 389 { 390 name := consumeId 391 return methodDef(loc, parent, doc, facets, flags, TypeRef.make(loc, ns.voidType), name) 392 } 393 394 // otherwise must be field or method 395 type := typeRef 396 name := consumeId 397 if (curt === Token.lparen) 398 { 399 return methodDef(loc, parent, doc, facets, flags, type, name) 400 } 401 else 402 { 403 return fieldDef(loc, parent, doc, facets, flags, type, name) 404 } 405 } 406 407 ////////////////////////////////////////////////////////////////////////// 408 // FieldDef 409 ////////////////////////////////////////////////////////////////////////// 410 411 ** 412 ** Field definition: 413 ** <fieldDef> := <facets> <fieldFlags> [<type>] <id> [":=" <expr>] 414 ** [ "{" [<fieldGetter>] [<fieldSetter>] "}" ] <eos> 415 ** <fieldFlags> := [<protection>] ["readonly"] ["static"] 416 ** <fieldGetter> := "get" (<eos> | <block>) 417 ** <fieldSetter> := <protection> "set" (<eos> | <block>) 418 ** 419 private FieldDef fieldDef(Location loc, TypeDef parent, Str[] doc, Str:FacetDef facets, Int flags, TypeRef type, Str name) 420 { 421 // define field itself 422 field := FieldDef.make(loc, parent) 423 field.doc = doc 424 field.facets = facets 425 field.flags = flags & ~ParserFlagsMask 426 field.fieldType = type 427 field.name = name 428 429 // const always has storage, otherwise assume no storage 430 // until proved otherwise in ResolveExpr step or we 431 // auto-generate getters/setters 432 if (field.isConst) 433 field.flags |= FConst.Storage 434 435 // field initializer 436 if (curt === Token.defAssign || curt === Token.assign) 437 { 438 if (curt === Token.assign) err("Must use := for field initialization") 439 consume 440 inFieldInit = true 441 field.init = expr 442 inFieldInit = false 443 } 444 445 // disable type inference for now - doing inference for literals is 446 // pretty trivial, but other types is tricky; I'm not sure it is such 447 // a hot idea anyways so it may just stay disabled forever 448 if (type == null) 449 err("Type inference not supported for fields", loc) 450 451 // if not const, define getter/setter methods 452 if (!field.isConst) defGetAndSet(field) 453 454 // explicit getter or setter 455 if (curt === Token.lbrace) 456 { 457 consume(Token.lbrace) 458 getOrSet(field) 459 getOrSet(field) 460 consume(Token.rbrace) 461 } 462 463 // generate synthetic getter or setter code if necessary 464 if (!field.isConst) 465 { 466 if (field.get.code == null) genSyntheticGet(field) 467 if (field.set.code == null) genSyntheticSet(field) 468 } 469 470 // readonly is syntatic sugar for { private set } 471 if (flags & Readonly !== 0) 472 { 473 field.set.flags = (field.set.flags & ProtectionMask) | FConst.Private 474 } 475 476 endOfStmt 477 return field 478 } 479 480 private Void defGetAndSet(FieldDef f) 481 { 482 loc := f.location 483 484 // getter MethodDef 485 get := MethodDef.make(loc, f.parentDef) 486 get.accessorFor = f 487 get.flags = f.flags | FConst.Getter 488 get.name = f.name 489 get.ret = f.fieldType 490 f.get = get 491 492 // setter MethodDef 493 set := MethodDef.make(loc, f.parentDef) 494 set.accessorFor = f 495 set.flags = f.flags | FConst.Setter 496 set.name = f.name 497 set.ret = ns.voidType 498 set.params.add(ParamDef.make(loc, f.fieldType, "val")) 499 f.set = set 500 } 501 502 private Void genSyntheticGet(FieldDef f) 503 { 504 loc := f.location 505 f.get.flags |= FConst.Synthetic 506 if (!f.isAbstract) 507 { 508 f.flags |= FConst.Storage 509 f.get.code = Block.make(loc) 510 f.get.code.add(ReturnStmt.make(loc, f.makeAccessorExpr(loc, false))) 511 } 512 } 513 514 private Void genSyntheticSet(FieldDef f) 515 { 516 loc := f.location 517 f.set.flags |= FConst.Synthetic 518 if (!f.isAbstract) 519 { 520 f.flags |= FConst.Storage 521 lhs := f.makeAccessorExpr(loc, false) 522 rhs := UnknownVarExpr.make(loc, null, "val") 523 f.set.code = Block.make(loc) 524 f.set.code.add(BinaryExpr.makeAssign(lhs, rhs).toStmt) 525 f.set.code.add(ReturnStmt.make(loc)) 526 } 527 } 528 529 private Void getOrSet(FieldDef f) 530 { 531 loc := cur 532 accessorFlags := flags(false) 533 if (curt === Token.identifier) 534 { 535 // get or set 536 idLoc := cur 537 id := consumeId 538 539 if (id == "get") 540 curMethod = f.get 541 else 542 curMethod = f.set 543 544 // { ...block... } 545 Block block := null 546 if (curt === Token.lbrace) 547 block = this.block(id != "get") 548 else 549 endOfStmt 550 551 // const field cannot have getter/setter 552 if (f.isConst) 553 { 554 err("Const field '$f.name' cannot have ${id}ter", idLoc) 555 return 556 } 557 558 // map to get or set on FieldDef 559 if (id == "get") 560 { 561 if (accessorFlags != 0) err("Cannot use modifiers on field getter", loc) 562 f.get.code = block 563 } 564 else if (id.equals("set")) 565 { 566 if (accessorFlags != 0) 567 { 568 if (accessorFlags & ProtectionMask != 0) 569 err("Cannot use modifiers on field setter except to narrow protection", loc) 570 f.set.flags = (f.set.flags & ProtectionMask) | accessorFlags 571 } 572 f.set.code = block 573 } 574 else 575 { 576 err("Expected 'get' or 'set', not '$id'", idLoc) 577 } 578 } 579 } 580 581 ////////////////////////////////////////////////////////////////////////// 582 // MethodDef 583 ////////////////////////////////////////////////////////////////////////// 584 585 ** 586 ** Method definition: 587 ** <methodDef> := <facets> <methodFlags> <type> <id> "(" <params> ")" <methodBody> 588 ** <methodFlags> := [<protection>] ["virtual"] ["override"] ["abstract"] ["static"] 589 ** <params> := [<param> ("," <param>)*] 590 ** <param> := <type> <id> [":=" <expr>] 591 ** <methodBody> := <eos> | ( "{" <stmts> "}" ) 592 ** 593 private MethodDef methodDef(Location loc, TypeDef parent, Str[] doc, Str:FacetDef facets, Int flags, TypeRef ret, Str name) 594 { 595 method := MethodDef.make(loc, parent) 596 method.doc = doc 597 method.facets = facets 598 method.flags = flags 599 method.ret = ret 600 method.name = name 601 602 // enter scope 603 curMethod = method 604 605 // parameters 606 consume(Token.lparen) 607 if (curt !== Token.rparen) 608 { 609 while (true) 610 { 611 method.params.add(paramDef) 612 if (curt === Token.rparen) break 613 consume(Token.comma) 614 } 615 } 616 consume(Token.rparen) 617 618 // if no body expected 619 if (flags & FConst.Abstract !== 0 || flags & FConst.Native !== 0 || isSys) 620 { 621 if (curt === Token.lbrace) 622 { 623 err("Abstract and native methods cannot have method body") 624 block(ret.isVoid) // keep parsing 625 } 626 else 627 { 628 endOfStmt 629 } 630 return method 631 } 632 633 // ctor chain 634 if ((flags & FConst.Ctor !== 0) && (curt === Token.colon)) 635 method.ctorChain = ctorChain(method); 636 637 // body 638 if (curt != Token.lbrace) 639 err("Expecting method body") 640 else 641 method.code = block(ret.isVoid) 642 643 // exit scope 644 curMethod = null 645 646 return method 647 } 648 649 private ParamDef paramDef() 650 { 651 param := ParamDef.make(cur) 652 param.paramType = typeRef 653 param.name = consumeId 654 if (curt === Token.defAssign || curt === Token.assign) 655 { 656 if (curt === Token.assign) err("Must use := for parameter default"); 657 consume 658 param.def = expr 659 } 660 return param 661 } 662 663 private CallExpr ctorChain(MethodDef method) 664 { 665 consume(Token.colon) 666 loc := cur 667 668 call := CallExpr.make(loc) 669 call.isCtorChain = true 670 switch (curt) 671 { 672 case Token.superKeyword: consume; call.target = SuperExpr.make(loc) 673 case Token.thisKeyword: consume; call.target = ThisExpr.make(loc) 674 default: throw err("Expecting this or super for constructor chaining", loc); 675 } 676 677 // we can omit name if super 678 if (call.target.id === ExprId.superExpr && curt != Token.dot) 679 { 680 call.name = method.name 681 } 682 else 683 { 684 consume(Token.dot) 685 call.name = consumeId 686 } 687 688 // TODO: omit args if pass thru? 689 callArgs(call) 690 return call 691 } 692 693 ////////////////////////////////////////////////////////////////////////// 694 // Facets 695 ////////////////////////////////////////////////////////////////////////// 696 697 private Str:FacetDef facets() 698 { 699 if (curt !== Token.at) return null 700 701 facets := Str:FacetDef[:] 702 while (curt === Token.at) 703 { 704 consume 705 loc := cur 706 name := consumeId 707 Expr val 708 if (curt === Token.assign) 709 { 710 consume() 711 val = expr 712 } 713 else 714 { 715 val = LiteralExpr.make(loc, ExprId.trueLiteral, ns.boolType, true) 716 } 717 if (facets[name] != null) err("Duplicate facet '$name'", loc) 718 facets[name] = FacetDef.make(loc, name, val) 719 } 720 return facets 721 } 722 723 ////////////////////////////////////////////////////////////////////////// 724 // Block 725 ////////////////////////////////////////////////////////////////////////// 726 727 ** 728 ** Top level for blocks which must be surrounded by braces 729 ** 730 private Block block(Bool inVoid) 731 { 732 this.inVoid = inVoid 733 verify(Token.lbrace) 734 return stmtOrBlock 735 } 736 737 ** 738 ** <block> := <stmt> | ( "{" <stmts> "}" ) 739 ** <stmts> := <stmt>* 740 ** 741 private Block stmtOrBlock() 742 { 743 block := Block.make(cur) 744 745 if (curt !== Token.lbrace) 746 { 747 block.stmts.add( stmt ) 748 } 749 else 750 { 751 consume(Token.lbrace) 752 while (curt != Token.rbrace) 753 block.stmts.add( stmt ) 754 consume(Token.rbrace) 755 } 756 757 return block 758 } 759 760 ////////////////////////////////////////////////////////////////////////// 761 // Statements 762 ////////////////////////////////////////////////////////////////////////// 763 764 ** 765 ** Statement: 766 ** <stmt> := <break> | <continue> | <for> | <if> | <return> | <switch> | 767 ** <throw> | <while> | <try> | <exprStmt> | <localDef> 768 ** 769 private Stmt stmt() 770 { 771 // check for statement keywords 772 switch (curt) 773 { 774 case Token.breakKeyword: return breakStmt 775 case Token.continueKeyword: return continueStmt 776 case Token.forKeyword: return forStmt 777 case Token.ifKeyword: return ifStmt 778 case Token.returnKeyword: return returnStmt 779 case Token.switchKeyword: return switchStmt 780 case Token.throwKeyword: return throwStmt 781 case Token.tryKeyword: return tryStmt 782 case Token.whileKeyword: return whileStmt 783 } 784 785 // at this point we either have an expr or local var declaration 786 return exprOrLocalDefStmt(true) 787 } 788 789 ** 790 ** Expression or local variable declaration: 791 ** <exprStmt> := <expr> <eos> 792 ** <localDef> := [<type>] <id> [":=" <expr>] <eos> 793 ** 794 private Stmt exprOrLocalDefStmt(Bool isEndOfStmt) 795 { 796 // see if this statement begins with a type literal 797 loc := cur 798 mark := pos 799 localType := tryType 800 801 // type followed by identifier must be local variable declaration 802 if (localType != null && curt === Token.identifier) 803 { 804 return localDefStmt(loc, localType, isEndOfStmt) 805 } 806 reset(mark) 807 808 // identifier followed by def assign is inferred typed local var declaration 809 if (curt === Token.identifier && peekt === Token.defAssign) 810 { 811 return localDefStmt(loc, null, isEndOfStmt) 812 } 813 814 // if current is an identifer, save for special error handling 815 Str id := (curt === Token.identifier) ? (Str)cur.val : null 816 817 // otherwise assume it's a stand alone expression statement 818 stmt := ExprStmt.make(expr) 819 if (!isEndOfStmt) return stmt 820 if (endOfStmt(null)) return stmt 821 822 // report error 823 if (id != null && curt === Token.identifier && (peekt === Token.defAssign || peekt === Token.assign)) 824 throw err("Unknown type '$id' for local declaration", loc) 825 else 826 throw err("Expected expression statement", loc) 827 } 828 829 ** 830 ** Parse local variable declaration, the current token must be 831 ** the identifier of the local variable. 832 ** 833 private LocalDefStmt localDefStmt(Location loc, CType localType, Bool isEndOfStmt) 834 { 835 stmt := LocalDefStmt.make(loc) 836 stmt.ctype = localType 837 stmt.name = consumeId 838 839 if (curt === Token.defAssign || curt === Token.assign) 840 { 841 if (curt === Token.assign) err("Must use := for declaration assignments") 842 consume 843 stmt.init = expr 844 } 845 846 if (isEndOfStmt) endOfStmt 847 return stmt 848 } 849 850 ** 851 ** If/else statement: 852 ** <if> := "if" "(" <expr> ")" <block> [ "else" <block> ] 853 ** 854 private IfStmt ifStmt() 855 { 856 stmt := IfStmt.make(cur) 857 consume(Token.ifKeyword) 858 consume(Token.lparen) 859 stmt.condition = expr 860 consume(Token.rparen) 861 stmt.trueBlock = stmtOrBlock 862 if (curt === Token.elseKeyword) 863 { 864 consume(Token.elseKeyword) 865 stmt.falseBlock = stmtOrBlock 866 } 867 return stmt 868 } 869 870 ** 871 ** Return statement: 872 ** <return> := "return" [<expr>] <eos> 873 ** 874 private ReturnStmt returnStmt() 875 { 876 stmt := ReturnStmt.make(cur) 877 consume(Token.returnKeyword) 878 if (inVoid) 879 { 880 endOfStmt("Expected end of statement after return in Void method") 881 } 882 else 883 { 884 stmt.expr = expr 885 endOfStmt 886 } 887 return stmt 888 } 889 890 ** 891 ** Throw statement: 892 ** <throw> := "throw" <expr> <eos> 893 ** 894 private ThrowStmt throwStmt() 895 { 896 stmt := ThrowStmt.make(cur) 897 consume(Token.throwKeyword) 898 stmt.exception = expr 899 endOfStmt 900 return stmt 901 } 902 903 ** 904 ** While statement: 905 ** <while> := "while" "(" <expr> ")" <block> 906 ** 907 private WhileStmt whileStmt() 908 { 909 stmt := WhileStmt.make(cur) 910 consume(Token.whileKeyword) 911 consume(Token.lparen) 912 stmt.condition = expr 913 consume(Token.rparen) 914 stmt.block = stmtOrBlock 915 return stmt 916 } 917 918 ** 919 ** For statement: 920 ** <for> := "for" "(" [<forInit>] ";" <expr> ";" <expr> ")" <block> 921 ** <forInit> := <expr> | <localDef> 922 ** 923 private ForStmt forStmt() 924 { 925 stmt := ForStmt.make(cur) 926 consume(Token.forKeyword) 927 consume(Token.lparen) 928 929 if (curt !== Token.semicolon) stmt.init = exprOrLocalDefStmt(false) 930 consume(Token.semicolon) 931 932 if (curt != Token.semicolon) stmt.condition = expr 933 consume(Token.semicolon) 934 935 if (curt != Token.rparen) stmt.update = expr 936 consume(Token.rparen) 937 938 stmt.block = stmtOrBlock 939 return stmt 940 } 941 942 ** 943 ** Break statement: 944 ** <break> := "break" <eos> 945 ** 946 private BreakStmt breakStmt() 947 { 948 stmt := BreakStmt.make(cur) 949 consume(Token.breakKeyword) 950 endOfStmt 951 return stmt 952 } 953 954 ** 955 ** Continue statement: 956 ** <continue> := "continue" <eos> 957 ** 958 private ContinueStmt continueStmt() 959 { 960 stmt := ContinueStmt.make(cur) 961 consume(Token.continueKeyword) 962 endOfStmt 963 return stmt 964 } 965 966 ** 967 ** Try-catch-finally statement: 968 ** <try> := "try" "{" <stmt>* "}" <catch>* [<finally>] 969 ** <catch> := "catch" [<catchDef>] "{" <stmt>* "}" 970 ** <catchDef> := "(" <type> <id> ")" 971 ** <finally> := "finally" "{" <stmt>* "}" 972 ** 973 private TryStmt tryStmt() 974 { 975 stmt := TryStmt.make(cur) 976 consume(Token.tryKeyword) 977 verify(Token.lbrace) 978 stmt.block = block(inVoid) 979 if (curt !== Token.catchKeyword && curt !== Token.finallyKeyword) 980 throw err("Expecting catch or finally block") 981 while (curt === Token.catchKeyword) 982 { 983 stmt.catches.add(tryCatch) 984 } 985 if (curt === Token.finallyKeyword) 986 { 987 consume 988 verify(Token.lbrace) 989 stmt.finallyBlock = block(inVoid) 990 } 991 return stmt 992 } 993 994 private Catch tryCatch() 995 { 996 c := Catch.make(cur) 997 consume(Token.catchKeyword) 998 999 if (curt === Token.lparen) 1000 { 1001 consume(Token.lparen) 1002 c.errType = typeRef 1003 c.errVariable = consumeId 1004 consume(Token.rparen) 1005 } 1006 1007 c.block = block(inVoid) 1008 1009 // insert implicit local variable declaration 1010 if (c.errVariable != null) 1011 c.block.stmts.insert(0, LocalDefStmt.makeCatchVar(c)) 1012 1013 return c 1014 } 1015 1016 ** 1017 ** Switch statement: 1018 ** <switch> := "switch" "(" <expr> ")" "{" <case>* [<default>] "}" 1019 ** <case> := "case" <expr> ":" <stmts> 1020 ** <default> := "default" ":" <stmts> 1021 ** 1022 private SwitchStmt switchStmt() 1023 { 1024 stmt := SwitchStmt.make(cur) 1025 consume(Token.switchKeyword) 1026 consume(Token.lparen) 1027 stmt.condition = expr 1028 consume(Token.rparen) 1029 consume(Token.lbrace) 1030 while (curt != Token.rbrace) 1031 { 1032 if (curt === Token.caseKeyword) 1033 { 1034 c := Case.make(cur) 1035 while (curt === Token.caseKeyword) 1036 { 1037 consume 1038 c.cases.add(expr) 1039 consume(Token.colon) 1040 } 1041 if (curt !== Token.defaultKeyword) // optimize away case fall-thru to default 1042 { 1043 c.block = switchBlock 1044 stmt.cases.add(c) 1045 } 1046 } 1047 else if (curt === Token.defaultKeyword) 1048 { 1049 if (stmt.defaultBlock != null) err("Duplicate default blocks") 1050 consume 1051 consume(Token.colon) 1052 stmt.defaultBlock = switchBlock 1053 } 1054 else 1055 { 1056 throw err("Expected case or default statement") 1057 } 1058 } 1059 consume(Token.rbrace) 1060 endOfStmt 1061 return stmt 1062 } 1063 1064 private Block switchBlock() 1065 { 1066 Block block := null 1067 while (curt !== Token.caseKeyword && curt != Token.defaultKeyword && curt !== Token.rbrace) 1068 { 1069 if (block == null) block = Block.make(cur) 1070 block.stmts.add(stmt) 1071 } 1072 return block; 1073 } 1074 1075 ////////////////////////////////////////////////////////////////////////// 1076 // Expr 1077 ////////////////////////////////////////////////////////////////////////// 1078 1079 ** 1080 ** Expression: 1081 ** <expr> := <assignExpr> 1082 ** 1083 private Expr expr() 1084 { 1085 return assignExpr 1086 } 1087 1088 ** 1089 ** Assignment expression: 1090 ** <assignExpr> := <condOrExpr> [<assignOp> <assignExpr>] 1091 ** <assignOp> := "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" 1092 ** 1093 private Expr assignExpr(Expr expr := null) 1094 { 1095 // this is tree if built to the right (others to the left) 1096 if (expr == null) expr = ternary 1097 if (curt.isAssign) 1098 { 1099 if (curt === Token.assign) 1100 return BinaryExpr.make(expr, consume.kind, assignExpr) 1101 else 1102 return ShortcutExpr.makeBinary(expr, consume.kind, assignExpr) 1103 } 1104 return expr 1105 } 1106 1107 ** 1108 ** Ternary expression: 1109 ** <ternaryExpr> := <condOrExpr> "?" <condOrExpr> ":" <condOrExpr> 1110 ** 1111 private Expr ternary() 1112 { 1113 expr := condOrExpr 1114 if (curt === Token.question) 1115 { 1116 condition := expr 1117 consume(Token.question); 1118 trueExpr := condOrExpr 1119 consume(Token.colon) 1120 falseExpr := condOrExpr 1121 expr = TernaryExpr.make(condition, trueExpr, falseExpr) 1122 } 1123 return expr 1124 } 1125 1126 ** 1127 ** Conditional or expression: 1128 ** <condOrExpr> := <condAndExpr> ("||" <condAndExpr>)* 1129 ** 1130 private Expr condOrExpr() 1131 { 1132 expr := condAndExpr 1133 if (curt === Token.doublePipe) 1134 { 1135 cond := CondExpr.make(expr, cur.kind) 1136 while (curt === Token.doublePipe) 1137 { 1138 consume 1139 cond.operands.add(condAndExpr) 1140 } 1141 expr = cond 1142 } 1143 return expr 1144 } 1145 1146 ** 1147 ** Conditional and expression: 1148 ** <condAndExpr> := <equalityExpr> ("&&" <equalityExpr>)* 1149 ** 1150 private Expr condAndExpr() 1151 { 1152 expr := equalityExpr 1153 if (curt === Token.doubleAmp) 1154 { 1155 cond := CondExpr.make(expr, cur.kind) 1156 while (curt === Token.doubleAmp) 1157 { 1158 consume 1159 cond.operands.add(equalityExpr) 1160 } 1161 expr = cond 1162 } 1163 return expr 1164 } 1165 1166 ** 1167 ** Equality expression: 1168 ** <equalityExpr> := <relationalExpr> (("==" | "!=" | "===" | "!==") <relationalExpr>)* 1169 ** 1170 private Expr equalityExpr() 1171 { 1172 expr := relationalExpr 1173 while (curt === Token.eq || curt === Token.notEq || 1174 curt === Token.same || curt === Token.notSame) 1175 { 1176 lhs := expr 1177 tok := consume.kind 1178 rhs := relationalExpr 1179 1180 // optimize for null literal 1181 if (lhs.id === ExprId.nullLiteral || rhs.id === ExprId.nullLiteral) 1182 { 1183 id := (tok === Token.eq || tok === Token.same) ? ExprId.cmpNull : ExprId.cmpNotNull 1184 operand := (lhs.id === ExprId.nullLiteral) ? rhs : lhs 1185 expr = UnaryExpr.make(lhs.location, id, tok, operand) 1186 } 1187 else 1188 { 1189 if (tok === Token.same || tok === Token.notSame) 1190 expr = BinaryExpr.make(lhs, tok, rhs) 1191 else 1192 expr = ShortcutExpr.makeBinary(lhs, tok, rhs) 1193 } 1194 } 1195 return expr 1196 } 1197 1198 ** 1199 ** Relational expression: 1200 ** <relationalExpr> := <rangeExpr> (("is" | "as" | "<" | "<=" | ">" | ">=" | "<=>") <rangeExpr>)* 1201 ** 1202 private Expr relationalExpr() 1203 { 1204 expr := rangeExpr 1205 while (curt === Token.isKeyword || curt === Token.asKeyword || 1206 curt === Token.lt || curt === Token.ltEq || 1207 curt === Token.gt || curt === Token.gtEq || 1208 curt === Token.cmp) 1209 { 1210 if (curt === Token.isKeyword) 1211 { 1212 consume 1213 expr = TypeCheckExpr.make(expr.location, ExprId.isExpr, expr, ctype) 1214 } 1215 else if (curt === Token.asKeyword) 1216 { 1217 consume 1218 expr = TypeCheckExpr.make(expr.location, ExprId.asExpr, expr, ctype) 1219 } 1220 else 1221 { 1222 expr = ShortcutExpr.makeBinary(expr, consume.kind, rangeExpr) 1223 } 1224 } 1225 return expr 1226 } 1227 1228 ** 1229 ** Range expression: 1230 ** <rangeExpr> := <bitOrExpr> ((".." | "...") <bitOrExpr>)* 1231 ** 1232 private Expr rangeExpr() 1233 { 1234 expr := bitOrExpr 1235 if (curt === Token.dotDot || curt === Token.dotDotDot) 1236 { 1237 range := RangeLiteralExpr.make(expr.location, ns.rangeType) 1238 range.start = expr 1239 range.exclusive = consume.kind === Token.dotDotDot 1240 range.end = bitOrExpr 1241 return range 1242 } 1243 return expr 1244 } 1245 1246 ** 1247 ** Bitwise or expression: 1248 ** <bitOrExpr> := <bitAndExpr> (("^" | "|") <bitAndExpr>)* 1249 ** 1250 private Expr bitOrExpr() 1251 { 1252 expr := bitAndExpr 1253 while (curt === Token.caret || curt === Token.pipe) 1254 expr = ShortcutExpr.makeBinary(expr, consume.kind, bitAndExpr) 1255 return expr 1256 } 1257 1258 ** 1259 ** Bitwise and expression: 1260 ** <bitAndExpr> := <shiftExpr> (("&" <shiftExpr>)* 1261 ** 1262 private Expr bitAndExpr() 1263 { 1264 expr := shiftExpr 1265 while (curt === Token.amp) 1266 expr = ShortcutExpr.makeBinary(expr, consume.kind, shiftExpr) 1267 return expr 1268 } 1269 1270 ** 1271 ** Bitwise shift expression: 1272 ** <shiftExpr> := <addExpr> (("<<" | ">>") <addExpr>)* 1273 ** 1274 private Expr shiftExpr() 1275 { 1276 expr := additiveExpr 1277 while (curt === Token.lshift || curt === Token.rshift) 1278 expr = ShortcutExpr.makeBinary(expr, consume.kind, additiveExpr) 1279 return expr 1280 } 1281 1282 ** 1283 ** Additive expression: 1284 ** <addExpr> := <multExpr> (("+" | "-") <multExpr>)* 1285 ** 1286 private Expr additiveExpr() 1287 { 1288 expr := multiplicativeExpr 1289 while (curt === Token.plus || curt === Token.minus) 1290 expr = ShortcutExpr.makeBinary(expr, consume.kind, multiplicativeExpr) 1291 return expr 1292 } 1293 1294 ** 1295 ** Multiplicative expression: 1296 ** <multExpr> := <parenExpr> (("*" | "/" | "%") <parenExpr>)* 1297 ** 1298 private Expr multiplicativeExpr() 1299 { 1300 expr := parenExpr 1301 while (curt === Token.star || curt === Token.slash || curt === Token.percent) 1302 expr = ShortcutExpr.makeBinary(expr, consume.kind, parenExpr) 1303 return expr 1304 } 1305 1306 ** 1307 ** Paren grouped expression: 1308 ** <parenExpr> := <unaryExpr> | <castExpr> | <groupedExpr> 1309 ** <castExpr> := "(" <type> ")" <parenExpr> 1310 ** <groupedExpr> := "(" <expr> ")" <termChain>* 1311 ** 1312 private Expr parenExpr() 1313 { 1314 if (curt != Token.lparen) 1315 return unaryExpr 1316 1317 // consume opening paren 1318 loc := cur 1319 consume(Token.lparen) 1320 1321 // In Fan just like C# and Java, a paren could mean 1322 // either a cast or a parenthesized expression 1323 mark := pos 1324 castType := tryType 1325 if (curt === Token.rparen) 1326 { 1327 consume 1328 return TypeCheckExpr.make(loc, ExprId.cast, parenExpr, castType) 1329 } 1330 reset(mark) 1331 1332 // this is just a normal parenthesized expression 1333 expr := expr 1334 consume(Token.rparen) 1335 while (true) 1336 { 1337 chained := termChainExpr(expr) 1338 if (chained == null) break 1339 expr = chained 1340 } 1341 return expr 1342 } 1343 1344 ** 1345 ** Unary expression: 1346 ** <unaryExpr> := <prefixExpr> | <termExpr> | <postfixExpr> 1347 ** <prefixExpr> := ("!" | "+" | "-" | "~" | "++" | "--") <parenExpr> 1348 ** <postfixExpr> := <termExpr> ("++" | "--") 1349 ** 1350 private Expr unaryExpr() 1351 { 1352 loc := cur 1353 tok := cur 1354 tokt := curt 1355 1356 if (tokt === Token.bang) 1357 { 1358 consume 1359 return UnaryExpr.make(loc, tokt.toExprId, tokt, parenExpr) 1360 } 1361 1362 if (tokt === Token.amp) 1363 { 1364 consume 1365 return CurryExpr.make(loc, parenExpr) 1366 } 1367 1368 if (tokt === Token.plus) 1369 { 1370 consume 1371 return parenExpr // optimize +expr to just expr 1372 } 1373 1374 if (tokt === Token.tilde || tokt === Token.minus) 1375 { 1376 consume 1377 return ShortcutExpr.makeUnary(loc, tokt, parenExpr) 1378 } 1379 1380 if (tokt === Token.increment || tokt === Token.decrement) 1381 { 1382 consume 1383 return ShortcutExpr.makeUnary(loc, tokt, parenExpr) 1384 } 1385 1386 expr := termExpr 1387 1388 tokt = curt 1389 if (tokt === Token.increment || tokt == Token.decrement) 1390 { 1391 consume 1392 shortcut := ShortcutExpr.makeUnary(loc, tokt, expr) 1393 shortcut.isPostfixLeave = true 1394 return shortcut 1395 } 1396 1397 return expr 1398 } 1399 1400 ////////////////////////////////////////////////////////////////////////// 1401 // Term Expr 1402 ////////////////////////////////////////////////////////////////////////// 1403 1404 ** 1405 ** A term is a base terminal such as a variable, call, or literal, 1406 ** optionally followed by a chain of accessor expressions - such 1407 ** as "x.y[z](a, b)". 1408 ** 1409 ** <termExpr> := <termBase> <termChain>* [withBlock] 1410 ** 1411 private Expr termExpr(Expr target := null) 1412 { 1413 if (target == null) target = termBaseExpr 1414 while (true) 1415 { 1416 chained := termChainExpr(target) 1417 if (chained == null) break 1418 target = chained 1419 } 1420 if (curt == Token.lbrace) 1421 return withBlock(target) 1422 return target 1423 } 1424 1425 ** 1426 ** Atomic base of a termExpr 1427 ** 1428 ** <termBase> := <literal> | <idExpr> | <closure> 1429 ** <literal> := "null" | "this" | "super" | <bool> | <int> | 1430 ** <float> | <str> | <duration> | <list> | <map> | <uri> 1431 ** 1432 private Expr termBaseExpr() 1433 { 1434 loc := cur 1435 1436 ctype := tryType 1437 if (ctype != null) return typeBaseExpr(loc, ctype) 1438 1439 switch (curt) 1440 { 1441 case Token.at: return idExpr(null, false) 1442 case Token.identifier: return idExpr(null, false) 1443 case Token.intLiteral: return LiteralExpr.make(loc, ExprId.intLiteral, ns.intType, consume.val) 1444 case Token.floatLiteral: return LiteralExpr.make(loc, ExprId.floatLiteral, ns.floatType, consume.val) 1445 case Token.strLiteral: return LiteralExpr.make(loc, ExprId.strLiteral, ns.strType, consume.val) 1446 case Token.durationLiteral: return LiteralExpr.make(loc, ExprId.durationLiteral, ns.durationType, consume.val) 1447 case Token.uriLiteral: return LiteralExpr.make(loc, ExprId.uriLiteral, ns.uriType, consume.val) 1448 case Token.lbracket: return collectionLiteralExpr(loc, null) 1449 case Token.falseKeyword: consume; return LiteralExpr.make(loc, ExprId.falseLiteral, ns.boolType, false) 1450 case Token.nullKeyword: consume; return LiteralExpr.make(loc, ExprId.nullLiteral, ns.objType, null) 1451 case Token.superKeyword: consume; return SuperExpr.make(loc) 1452 case Token.thisKeyword: consume; return ThisExpr.make(loc) 1453 case Token.trueKeyword: consume; return LiteralExpr.make(loc, ExprId.trueLiteral, ns.boolType, true) 1454 } 1455 throw err("Expected expression, not '" + cur + "'") 1456 } 1457 1458 ** 1459 ** Handle a term expression which begins with a type literal. 1460 ** 1461 private Expr typeBaseExpr(Location loc, CType ctype) 1462 { 1463 // type literal 1464 if (curt === Token.dot && peekt === Token.identifier && peek.val == "type") 1465 { 1466 consume 1467 consume 1468 return LiteralExpr.make(loc, ExprId.typeLiteral, ns.typeType, ctype) 1469 } 1470 1471 // dot is named super or static call chain 1472 if (curt == Token.dot) 1473 { 1474 consume 1475 if (curt === Token.superKeyword) 1476 { 1477 consume 1478 return SuperExpr.make(loc, ctype) 1479 } 1480 else 1481 { 1482 return idExpr(StaticTargetExpr.make(loc, ctype), false) 1483 } 1484 } 1485 1486 // list/map literal with explicit type 1487 if (curt === Token.lbracket) 1488 { 1489 return collectionLiteralExpr(loc, ctype) 1490 } 1491 1492 // closure 1493 if (curt == Token.lbrace && ctype is FuncType) 1494 { 1495 return closure(loc, (FuncType)ctype) 1496 } 1497 1498 // simple literal type(arg) 1499 if (curt == Token.lparen) 1500 { 1501 consume 1502 arg := expr 1503 consume(Token.rparen) 1504 return SimpleLiteralExpr.make(loc, ctype, arg) 1505 } 1506 1507 // complex literal type {...} 1508 if (curt == Token.lbrace) 1509 { 1510 base := UnknownVarExpr.make(loc, StaticTargetExpr.make(loc, ctype), "make") 1511 return withBlock(base) 1512 } 1513 1514 throw err("Unexpected type literal", loc) 1515 } 1516 1517 ** 1518 ** A chain expression is a piece of a term expression that may 1519 ** be chained together such as "call.var[x]". If the specified 1520 ** target expression contains a chained access, then return the new 1521 ** expression, otherwise return null. 1522 ** 1523 ** <termChain> := <compiledCall> | <dynamicCall> | <indexExpr> 1524 ** <compiledCall> := "." <idExpr> 1525 ** <dynamicCall> := "->" <idExpr> 1526 ** 1527 private Expr termChainExpr(Expr target) 1528 { 1529 loc := cur 1530 1531 // if ".id" field access or ".id" call 1532 if (curt === Token.dot) 1533 { 1534 consume 1535 return idExpr(target, false) 1536 } 1537 1538 // if "->id" dynamic call 1539 if (curt === Token.arrow) 1540 { 1541 consume 1542 return idExpr(target, true) 1543 } 1544 1545 // if target[...] 1546 if (curt === Token.lbracket) 1547 return indexExpr(target) 1548 1549 // if target(...) 1550 if (curt === Token.lparen) 1551 return callOp(target) 1552 1553 // we treat a with base as a dot slot access 1554 if (target.id === ExprId.withBase) 1555 return idExpr(target, false) 1556 1557 // otherwise the expression should be finished 1558 return null; 1559 } 1560 1561 ** 1562 ** A with block is a series of sub-expressions 1563 ** inside {} appended to the end of an expression. 1564 ** 1565 private Expr withBlock(Expr base) 1566 { 1567 // field initializers look like a with block, but 1568 // we can safely peek to see if the next token is "get", 1569 // "set", or a keyword like "private" 1570 if (inFieldInit) 1571 { 1572 if (peek.kind.keyword) return base 1573 if (peekt == Token.identifier) 1574 { 1575 if (peek.val == "get" || peek.val == "set") return base 1576 } 1577 } 1578 1579 withBlock := WithBlockExpr.make(base) 1580 consume(Token.lbrace) 1581 while (curt !== Token.rbrace) 1582 { 1583 sub := assignExpr(termExpr(WithBaseExpr.make(withBlock))) 1584 withBlock.subs.add(sub) 1585 endOfStmt 1586 } 1587 consume(Token.rbrace) 1588 return withBlock 1589 } 1590 1591 ////////////////////////////////////////////////////////////////////////// 1592 // Term Expr Utils 1593 ////////////////////////////////////////////////////////////////////////// 1594 1595 ** 1596 ** Identifier expression: 1597 ** <idExpr> := <local> | <field> | <call> 1598 ** <local> := <id> 1599 ** <field> := ["@"] <id> 1600 ** 1601 private Expr idExpr(Expr target, Bool dynamicCall) 1602 { 1603 loc := cur 1604 1605 if (curt == Token.at) 1606 { 1607 consume 1608 return UnknownVarExpr.makeStorage(loc, target, consumeId) 1609 } 1610 1611 if (peekt === Token.lparen) 1612 { 1613 call := callExpr(target) 1614 call.isDynamic = dynamicCall 1615 return call 1616 } 1617 1618 name := consumeId 1619 1620 // if we have a closure then this is a call with one arg of a closure 1621 closure := tryClosure 1622 if (closure != null) 1623 { 1624 call := CallExpr.make(loc) 1625 call.target = target 1626 call.name = name 1627 call.args.add(closure) 1628 return call 1629 } 1630 1631 // if dynamic call then we know this is a call not a field 1632 if (dynamicCall) 1633 { 1634 call := CallExpr.make(loc) 1635 call.target = target 1636 call.name = name 1637 call.isDynamic = true 1638 return call 1639 } 1640 1641 return UnknownVarExpr.make(loc, target, name) 1642 } 1643 1644 ** 1645 ** Call expression: 1646 ** <call> := <id> ["(" <args> ")"] [<closure>] 1647 ** 1648 private CallExpr callExpr(Expr target) 1649 { 1650 call := CallExpr.make(cur) 1651 call.target = target 1652 call.name = consumeId 1653 callArgs(call) 1654 return call 1655 } 1656 1657 ** 1658 ** Parse args with known parens: 1659 ** <args> := [<expr> ("," <expr>)*] [<closure>] 1660 ** 1661 private Void callArgs(CallExpr call) 1662 { 1663 consume(Token.lparen) 1664 if (curt != Token.rparen) 1665 { 1666 while (true) 1667 { 1668 call.args.add(expr) 1669 if (curt === Token.rparen) break 1670 consume(Token.comma) 1671 } 1672 } 1673 consume(Token.rparen) 1674 1675 closure := tryClosure 1676 if (closure != null) call.args.add(closure); 1677 } 1678 1679 ** 1680 ** Call operator: 1681 ** <callOp> := "(" <args> ")" [<closure>] 1682 ** 1683 private Expr callOp(Expr target) 1684 { 1685 loc := cur 1686 call := CallExpr.make(loc) 1687 call.target = target 1688 callArgs(call) 1689 call.name = "call${call.args.size}" 1690 return call 1691 } 1692 1693 ** 1694 ** Index expression: 1695 ** <indexExpr> := "[" <expr> "]" 1696 ** 1697 private Expr indexExpr(Expr target) 1698 { 1699 loc := cur 1700 consume(Token.lbracket) 1701 1702 // otherwise this must be a standard single key index 1703 expr := expr 1704 consume(Token.rbracket) 1705 return ShortcutExpr.makeGet(loc, target, expr) 1706 } 1707 1708 ////////////////////////////////////////////////////////////////////////// 1709 // Collection "Literals" 1710 ////////////////////////////////////////////////////////////////////////// 1711 1712 ** 1713 ** Collection literal: 1714 ** <list> := [<type>] "[" <listItems> "]" 1715 ** <listItems> := "," | (<expr> ("," <expr>)*) 1716 ** <map> := [<mapType>] "[" <mapItems> "]" 1717 ** <mapItems> := ":" | (<mapPair> ("," <mapPair>)*) 1718 ** <mapPair> := <expr> ":" <expr> 1719 ** 1720 private Expr collectionLiteralExpr(Location loc, CType explicitType) 1721 { 1722 // empty list [,] 1723 if (peekt === Token.comma) 1724 return listLiteralExpr(loc, explicitType, null) 1725 1726 // empty map [:] 1727 if (peekt === Token.colon) 1728 return mapLiteralExpr(loc, explicitType, null) 1729 1730 // opening bracket 1731 consume(Token.lbracket) 1732 1733 // [] is error 1734 if (curt === Token.rbracket) 1735 { 1736 err("Invalid list literal; use '[,]' for empty Obj[] list", loc) 1737 consume 1738 return ListLiteralExpr.make(loc) 1739 } 1740 1741 // read first expression 1742 first := expr 1743 1744 // at this point we can determine if it is a list or a map 1745 if (curt === Token.colon) 1746 return mapLiteralExpr(loc, explicitType, first) 1747 else 1748 return listLiteralExpr(loc, explicitType, first) 1749 } 1750 1751 ** 1752 ** Parse List literal; if first is null then 1753 ** cur must be on lbracket 1754 ** else 1755 ** cur must be on comma after first item 1756 ** 1757 private ListLiteralExpr listLiteralExpr(Location loc, CType explicitType, Expr first) 1758 { 1759 // explicitType is type of List: Str[,] 1760 if (explicitType != null) 1761 explicitType = explicitType.toListOf 1762 1763 list := ListLiteralExpr.make(loc, (ListType)explicitType) 1764 1765 // if first is null, must be on lbracket 1766 if (first == null) 1767 { 1768 consume(Token.lbracket) 1769 1770 // if [,] empty list 1771 if (curt === Token.comma) 1772 { 1773 consume 1774 consume(Token.rbracket) 1775 return list 1776 } 1777 1778 first = expr 1779 } 1780 1781 list.vals.add(first) 1782 while (curt === Token.comma) 1783 { 1784 consume 1785 if (curt === Token.rbracket) break // allow extra trailing comma 1786 list.vals.add(expr) 1787 } 1788 consume(Token.rbracket) 1789 return list 1790 } 1791 1792 ** 1793 ** Parse Map literal; if first is null: 1794 ** cur must be on lbracket 1795 ** else 1796 ** cur must be on colon of first key/value pair 1797 ** 1798 private MapLiteralExpr mapLiteralExpr(Location loc, CType explicitType, Expr first) 1799 { 1800 // explicitType is *the* map type: Str:Str[,] 1801 if (explicitType != null && !(explicitType is MapType)) 1802 { 1803 err("Invalid map type '$explicitType' for map literal", loc) 1804 explicitType = null 1805 } 1806 1807 map := MapLiteralExpr.make(loc, (MapType)explicitType) 1808 1809 // if first is null, must be on lbracket 1810 if (first == null) 1811 { 1812 consume(Token.lbracket) 1813 1814 // if [,] empty list 1815 if (curt === Token.colon) 1816 { 1817 consume 1818 consume(Token.rbracket) 1819 return map 1820 } 1821 1822 first = expr 1823 } 1824 1825 map.keys.add(first) 1826 consume(Token.colon) 1827 map.vals.add(expr) 1828 while (curt === Token.comma) 1829 { 1830 consume 1831 if (curt === Token.rbracket) break // allow extra trailing comma 1832 map.keys.add(expr) 1833 consume(Token.colon) 1834 map.vals.add(expr) 1835 } 1836 consume(Token.rbracket) 1837 return map 1838 } 1839 1840 ////////////////////////////////////////////////////////////////////////// 1841 // Closure 1842 ////////////////////////////////////////////////////////////////////////// 1843 1844 ** 1845 ** Attempt to parse a closure expression or return null if we 1846 ** aren't positioned at the start of a closure expression. 1847 ** 1848 private ClosureExpr tryClosure() 1849 { 1850 loc := cur 1851 1852 // if no pipe, then no closure 1853 if (curt !== Token.pipe) return null 1854 1855 // otherwise this can only be a FuncType declaration, 1856 // so give it a whirl, and bail if that fails 1857 mark := pos 1858 funcType := (FuncType)tryType 1859 if (funcType == null) return null 1860 1861 // if we don't see opening brace for body - no go 1862 if (curt !== Token.lbrace) { reset(mark); return null } 1863 1864 return closure(loc, funcType) 1865 } 1866 1867 ** 1868 ** Parse body of closure expression and return ClosureExpr. 1869 ** 1870 private ClosureExpr closure(Location loc, FuncType funcType) 1871 { 1872 if (curMethod == null) 1873 throw err("Unexpected closure outside of a method") 1874 1875 // closure anonymous class name: class$method$count 1876 name := "${curType.name}\$${curMethod.name}\$${closureCount++}" 1877 1878 // create closure 1879 closure := ClosureExpr.make(loc, curType, curMethod, curClosure, funcType, name) 1880 1881 // save all closures in global list and list per type 1882 closures.add(closure) 1883 curType.closures.add(closure) 1884 1885 // parse block; temporarily change our inVoid flag and curClosure 1886 oldInVoid := inVoid 1887 oldClosure := curClosure 1888 curClosure = closure 1889 closure.code = block(funcType.ret.isVoid) 1890 curClosure = oldClosure 1891 inVoid = oldInVoid 1892 1893 return closure 1894 } 1895 1896 ////////////////////////////////////////////////////////////////////////// 1897 // Types 1898 ////////////////////////////////////////////////////////////////////////// 1899 1900 ** 1901 ** Parse a type production into a CType and wrap it as AST TypeRef. 1902 ** 1903 private TypeRef typeRef() 1904 { 1905 Location loc := cur 1906 return TypeRef.make(loc, ctype) 1907 } 1908 1909 ** 1910 ** If the current stream of tokens can be parsed as a 1911 ** valid type production return it. Otherwise leave 1912 ** the parser positioned on the current token. 1913 ** 1914 private CType tryType() 1915 { 1916 // types can only begin with identifier, | or [ 1917 if (curt !== Token.identifier && curt !== Token.pipe && curt !== Token.lbracket) 1918 return null 1919 1920 suppressErr = true 1921 mark := pos 1922 CType type := null 1923 try 1924 { 1925 type = ctype 1926 } 1927 catch (SuppressedErr e) 1928 { 1929 } 1930 suppressErr = false 1931 if (type == null) reset(mark) 1932 return type 1933 } 1934 1935 ** 1936 ** Type signature: 1937 ** <type> := <simpleType> | <listType> | <mapType> | <funcType> 1938 ** <listType> := <type> "[]" 1939 ** <mapType> := ["["] <type> ":" <type> ["]"] 1940 ** 1941 private CType ctype() 1942 { 1943 CType t := null 1944 1945 // Types can begin with: 1946 // - id 1947 // - [k:v] 1948 // - |a, b -> r| 1949 if (curt === Token.identifier) 1950 { 1951 t = simpleType 1952 } 1953 else if (curt === Token.lbracket) 1954 { 1955 loc := consume(Token.lbracket) 1956 t = ctype 1957 consume(Token.rbracket) 1958 if (!(t is MapType)) err("Invalid map type", loc) 1959 } 1960 else if (curt === Token.pipe) 1961 { 1962 t = funcType 1963 } 1964 else 1965 { 1966 throw err("Expecting type name") 1967 } 1968 1969 // trailing [] for lists 1970 while (curt === Token.lbracket && peekt === Token.rbracket) 1971 { 1972 consume(Token.lbracket) 1973 consume(Token.rbracket) 1974 t = t.toListOf 1975 } 1976 1977 // check for ":" for map type 1978 if (curt === Token.colon) 1979 { 1980 consume(Token.colon) 1981 key := t 1982 val := ctype 1983 t = MapType.make(key, val) 1984 } 1985 1986 return t 1987 } 1988 1989 ** 1990 ** Simple type signature: 1991 ** <simpleType> := <id> ["::" <id>] 1992 ** 1993 private CType simpleType() 1994 { 1995 loc := cur 1996 id := consumeId 1997 1998 // fully qualified 1999 if (curt === Token.doubleColon) 2000 { 2001 consume 2002 return ResolveImports.resolveQualified(this, id, consumeId, loc) 2003 } 2004 2005 // unqualified name, lookup in imported types 2006 types := unit.importedTypes[id] 2007 if (types == null) 2008 { 2009 // handle sys generic parameters 2010 if (isSys && id.size == 1) 2011 return ns.genericParameter(id) 2012 2013 // not found in imports 2014 err("Unknown type '$id'", loc) 2015 return ns.voidType 2016 } 2017 2018 // if more then one it is ambiguous 2019 if (types.size > 1) err("Ambiguous type: " + types.join(", ")) 2020 2021 // got it 2022 return types.first 2023 } 2024 2025 ** 2026 ** Method type signature: 2027 ** <funcType> := "|" <formals> ["->" <type> "|" 2028 ** <formals> := [<formal> ("," <formal>)*] 2029 ** <formal> := <type> <id> 2030 ** 2031 private CType funcType() 2032 { 2033 params := CType[,] 2034 names := Str[,] 2035 ret := ns.voidType 2036 2037 // opening pipe 2038 consume(Token.pipe) 2039 2040 // |,| is the empty method type 2041 if (curt === Token.comma) 2042 { 2043 consume 2044 consume(Token.pipe) 2045 return FuncType.make(params, names, ret) 2046 } 2047 2048 // params, must be one if no -> 2049 if (curt !== Token.arrow) 2050 { 2051 params.add(ctype) 2052 names.add(consumeId) 2053 } 2054 while (curt === Token.comma) 2055 { 2056 consume 2057 params.add(ctype) 2058 names.add(consumeId) 2059 } 2060 2061 // optional arrow 2062 if (curt === Token.arrow) 2063 { 2064 consume 2065 ret = ctype 2066 } 2067 2068 // closing pipe 2069 consume(Token.pipe) 2070 return FuncType.make(params, names, ret) 2071 } 2072 2073 ////////////////////////////////////////////////////////////////////////// 2074 // Misc 2075 ////////////////////////////////////////////////////////////////////////// 2076 2077 ** 2078 ** Parse fandoc or retur null 2079 ** 2080 private Str[] doc() 2081 { 2082 Str[] doc := null 2083 while (curt === Token.docComment) 2084 doc = (Str[])consume(Token.docComment).val 2085 return doc 2086 } 2087 2088 ////////////////////////////////////////////////////////////////////////// 2089 // Errors 2090 ////////////////////////////////////////////////////////////////////////// 2091 2092 override CompilerErr err(Str msg, Location loc := null) 2093 { 2094 if (suppressErr) throw SuppressedErr.make 2095 if (loc == null) loc = cur 2096 return super.err(msg, loc) 2097 } 2098 2099 ////////////////////////////////////////////////////////////////////////// 2100 // Tokens 2101 ////////////////////////////////////////////////////////////////////////// 2102 2103 ** 2104 ** Verify current is an identifier, consume it, and return it. 2105 ** 2106 private Str consumeId() 2107 { 2108 if (curt !== Token.identifier) 2109 throw err("Expected identifier, not '$cur'"); 2110 return (Str)consume.val; 2111 } 2112 2113 ** 2114 ** Check that the current token matches the specified 2115 ** type, but do not consume it. 2116 ** 2117 private Void verify(Token kind) 2118 { 2119 if (curt !== kind) 2120 throw err("Expected '$kind.symbol', not '$cur'"); 2121 } 2122 2123 ** 2124 ** Consume the current token and return consumed token. 2125 ** If kind is non-null then verify first 2126 ** 2127 private TokenVal consume(Token kind := null) 2128 { 2129 // verify if not null 2130 if (kind != null) verify(kind) 2131 2132 // save the current we are about to consume for return 2133 result := cur 2134 2135 // get the next token from the buffer, if pos is past numTokens, 2136 // then always use the last token which will be eof 2137 TokenVal next; 2138 pos++; 2139 if (pos+1 < numTokens) 2140 next = tokens[pos+1] // next peek is cur+1 2141 else 2142 next = tokens[numTokens-1] 2143 2144 this.cur = peek 2145 this.peek = next 2146 this.curt = cur.kind 2147 this.peekt = peek.kind 2148 2149 return result 2150 } 2151 2152 ** 2153 ** Statements can be terminated with a semicolon, end of line 2154 ** or } end of block. Return true on success. On failure 2155 ** return false if errMsg is null or log/throw an exception. 2156 ** 2157 private Bool endOfStmt(Str errMsg := "Expected end of statement: semicolon, newline, or end of block; not '$cur'") 2158 { 2159 if (cur.newline) return true 2160 if (curt === Token.semicolon) { consume; return true } 2161 if (curt === Token.rbrace) return true 2162 if (errMsg == null) return false 2163 throw err(errMsg) 2164 } 2165 2166 ** 2167 ** Reset the current position to the specified tokens index. 2168 ** 2169 private Void reset(Int pos) 2170 { 2171 this.pos = pos 2172 this.cur = tokens[pos] 2173 if (pos+1 < numTokens) 2174 this.peek = tokens[pos+1] 2175 else 2176 this.peek = tokens[pos] 2177 this.curt = cur.kind 2178 this.peekt = peek.kind 2179 } 2180 2181 ////////////////////////////////////////////////////////////////////////// 2182 // Parser Flags 2183 ////////////////////////////////////////////////////////////////////////// 2184 2185 // These are flags used only by the parser we merge with FConst 2186 // flags by starting from most significant bit and working down 2187 const static Int Readonly := 0x80000000 2188 const static Int ParserFlagsMask := Readonly 2189 2190 // Bitwise and this mask to clear all protection scope flags 2191 const static Int ProtectionMask := ~(FConst.Public|FConst.Protected|FConst.Private|FConst.Internal) 2192 2193 ////////////////////////////////////////////////////////////////////////// 2194 // Fields 2195 ////////////////////////////////////////////////////////////////////////// 2196 2197 private CompilationUnit unit // compilation unit to generate 2198 private TokenVal[] tokens // tokens all read in 2199 private Int numTokens // number of tokens 2200 private Int pos; // offset Into tokens for cur 2201 private TokenVal cur // current token 2202 private Token curt // current token type 2203 private TokenVal peek // next token 2204 private Token peekt // next token type 2205 private Bool suppressErr // throw SuppressedErr instead of CompilerErr 2206 private Bool isSys := false // are we parsing the sys pod itself 2207 private Bool inVoid // are we currently in a void method 2208 private Bool inFieldInit := false // are we currently in a field initializer 2209 private TypeDef curType // current TypeDef scope 2210 private MethodDef curMethod // current MethodDef scope 2211 private ClosureExpr curClosure // current ClosureExpr if inside closure 2212 private Int closureCount // number of closures parsed inside curMethod 2213 private ClosureExpr[] closures // list of all closures parsed 2214 2215 } 2216 2217 ////////////////////////////////////////////////////////////////////////// 2218 // SuppressedErr 2219 ////////////////////////////////////////////////////////////////////////// 2220 2221 const class SuppressedErr : Err 2222 { 2223 new make() : super(null, null) {} 2224 }