1 // Written in the D programming language 2 3 module dparse.parser; 4 5 import dparse.lexer; 6 import dparse.ast; 7 import dparse.rollback_allocator; 8 import dparse.stack_buffer; 9 import std.experimental.allocator.mallocator; 10 import std.experimental.allocator; 11 import std.conv; 12 import std.algorithm; 13 import std.array; 14 import std.string : format; 15 16 // Uncomment this if you want ALL THE OUTPUT 17 // Caution: generates 180 megabytes of logging for std.datetime 18 //version = dparse_verbose; 19 20 /** 21 * Params: 22 * tokens = the tokens parsed by dparse.lexer 23 * fileName = the name of the file being parsed 24 * messageFunction = a function to call on error or warning messages. 25 * The parameters are the file name, line number, column number, 26 * the error or warning message, and a boolean (true means error, false 27 * means warning). 28 * Returns: the parsed module 29 */ 30 Module parseModule(const(Token)[] tokens, string fileName, RollbackAllocator* allocator, 31 void function(string, size_t, size_t, string, bool) messageFunction = null, 32 uint* errorCount = null, uint* warningCount = null) 33 { 34 auto parser = new Parser(); 35 parser.fileName = fileName; 36 parser.tokens = tokens; 37 parser.messageFunction = messageFunction; 38 parser.allocator = allocator; 39 auto mod = parser.parseModule(); 40 if (warningCount !is null) 41 *warningCount = parser.warningCount; 42 if (errorCount !is null) 43 *errorCount = parser.errorCount; 44 return mod; 45 } 46 47 /** 48 * D Parser. 49 * 50 * It is sometimes useful to sub-class Parser to skip over things that are not 51 * interesting. For example, DCD skips over function bodies when caching symbols 52 * from imported files. 53 */ 54 class Parser 55 { 56 /** 57 * Parses an AddExpression. 58 * 59 * $(GRAMMAR $(RULEDEF addExpression): 60 * $(RULE mulExpression) 61 * | $(RULE addExpression) $(LPAREN)$(LITERAL '+') | $(LITERAL'-') | $(LITERAL'~')$(RPAREN) $(RULE mulExpression) 62 * ;) 63 */ 64 ExpressionNode parseAddExpression() 65 { 66 mixin(traceEnterAndExit!(__FUNCTION__)); 67 return parseLeftAssocBinaryExpression!(AddExpression, MulExpression, 68 tok!"+", tok!"-", tok!"~")(); 69 } 70 71 /** 72 * Parses an AliasDeclaration. 73 * 74 * $(GRAMMAR $(RULEDEF aliasDeclaration): 75 * $(LITERAL 'alias') $(RULE aliasInitializer) $(LPAREN)$(LITERAL ',') $(RULE aliasInitializer)$(RPAREN)* $(LITERAL ';') 76 * | $(LITERAL 'alias') $(RULE storageClass)* $(RULE type) $(RULE identifierList) $(LITERAL ';') 77 * ;) 78 */ 79 AliasDeclaration parseAliasDeclaration() 80 { 81 mixin(traceEnterAndExit!(__FUNCTION__)); 82 auto node = allocator.make!AliasDeclaration; 83 mixin(tokenCheck!"alias"); 84 node.comment = comment; 85 comment = null; 86 87 if (startsWith(tok!"identifier", tok!"=") || startsWith(tok!"identifier", tok!"(")) 88 { 89 StackBuffer initializers; 90 do 91 { 92 if (!initializers.put(parseAliasInitializer())) 93 return null; 94 if (currentIs(tok!",")) 95 advance(); 96 else 97 break; 98 } 99 while (moreTokens()); 100 ownArray(node.initializers, initializers); 101 } 102 else 103 { 104 StackBuffer storageClasses; 105 while (moreTokens() && isStorageClass()) 106 if (!storageClasses.put(parseStorageClass())) 107 return null; 108 ownArray(node.storageClasses, storageClasses); 109 mixin (parseNodeQ!(`node.type`, `Type`)); 110 mixin (parseNodeQ!(`node.identifierList`, `IdentifierList`)); 111 } 112 return attachCommentFromSemicolon(node); 113 } 114 115 /** 116 * Parses an AliasInitializer. 117 * 118 * $(GRAMMAR $(RULEDEF aliasInitializer): 119 * $(LITERAL Identifier) $(RULE templateParameters)? $(LITERAL '=') $(RULE storageClass)* $(RULE type) 120 * | $(LITERAL Identifier) $(RULE templateParameters)? $(LITERAL '=') $(RULE functionLiteralExpression) 121 * ;) 122 */ 123 AliasInitializer parseAliasInitializer() 124 { 125 mixin(traceEnterAndExit!(__FUNCTION__)); 126 auto node = allocator.make!AliasInitializer; 127 mixin (tokenCheck!(`node.name`, "identifier")); 128 if (currentIs(tok!"(")) 129 mixin (parseNodeQ!(`node.templateParameters`, `TemplateParameters`)); 130 mixin(tokenCheck!"="); 131 132 bool isFunction() 133 { 134 if (currentIsOneOf(tok!"function", tok!"delegate", tok!"{")) 135 return true; 136 if (startsWith(tok!"identifier", tok!"=>")) 137 return true; 138 if (currentIs(tok!"(")) 139 { 140 const t = peekPastParens(); 141 if (t !is null) 142 { 143 if (t.type == tok!"=>" || t.type == tok!"{" 144 || isMemberFunctionAttribute(t.type)) 145 return true; 146 } 147 } 148 return false; 149 } 150 151 if (isFunction) 152 mixin (parseNodeQ!(`node.functionLiteralExpression`, `FunctionLiteralExpression`)); 153 else 154 { 155 StackBuffer storageClasses; 156 while (moreTokens() && isStorageClass()) 157 if (!storageClasses.put(parseStorageClass())) 158 return null; 159 ownArray(node.storageClasses, storageClasses); 160 mixin (parseNodeQ!(`node.type`, `Type`)); 161 } 162 return node; 163 } 164 165 /** 166 * Parses an AliasThisDeclaration. 167 * 168 * $(GRAMMAR $(RULEDEF aliasThisDeclaration): 169 * $(LITERAL 'alias') $(LITERAL Identifier) $(LITERAL 'this') $(LITERAL ';') 170 * ;) 171 */ 172 AliasThisDeclaration parseAliasThisDeclaration() 173 { 174 mixin(traceEnterAndExit!(__FUNCTION__)); 175 auto node = allocator.make!AliasThisDeclaration; 176 mixin(tokenCheck!"alias"); 177 mixin(tokenCheck!(`node.identifier`, "identifier")); 178 mixin(tokenCheck!"this"); 179 return attachCommentFromSemicolon(node); 180 } 181 182 /** 183 * Parses an AlignAttribute. 184 * 185 * $(GRAMMAR $(RULEDEF alignAttribute): 186 * $(LITERAL 'align') ($(LITERAL '$(LPAREN)') $(LITERAL IntegerLiteral) $(LITERAL '$(RPAREN)'))? 187 * ;) 188 */ 189 AlignAttribute parseAlignAttribute() 190 { 191 mixin(traceEnterAndExit!(__FUNCTION__)); 192 auto node = allocator.make!AlignAttribute; 193 expect(tok!"align"); 194 if (currentIs(tok!"(")) 195 { 196 mixin(tokenCheck!"("); 197 mixin(tokenCheck!(`node.intLiteral`, "intLiteral")); 198 mixin(tokenCheck!")"); 199 } 200 return node; 201 } 202 203 /** 204 * Parses an AndAndExpression. 205 * 206 * $(GRAMMAR $(RULEDEF andAndExpression): 207 * $(RULE orExpression) 208 * | $(RULE andAndExpression) $(LITERAL '&&') $(RULE orExpression) 209 * ;) 210 */ 211 ExpressionNode parseAndAndExpression() 212 { 213 mixin(traceEnterAndExit!(__FUNCTION__)); 214 return parseLeftAssocBinaryExpression!(AndAndExpression, OrExpression, 215 tok!"&&")(); 216 } 217 218 /** 219 * Parses an AndExpression. 220 * 221 * $(GRAMMAR $(RULEDEF andExpression): 222 * $(RULE cmpExpression) 223 * | $(RULE andExpression) $(LITERAL '&') $(RULE cmpExpression) 224 * ;) 225 */ 226 ExpressionNode parseAndExpression() 227 { 228 mixin(traceEnterAndExit!(__FUNCTION__)); 229 return parseLeftAssocBinaryExpression!(AndExpression, CmpExpression, 230 tok!"&")(); 231 } 232 233 /** 234 * Parses an ArgumentList. 235 * 236 * $(GRAMMAR $(RULEDEF argumentList): 237 * $(RULE assignExpression) ($(LITERAL ',') $(RULE assignExpression)?)* 238 * ;) 239 */ 240 ArgumentList parseArgumentList() 241 { 242 mixin(traceEnterAndExit!(__FUNCTION__)); 243 if (!moreTokens) 244 { 245 error("argument list expected instead of EOF"); 246 return null; 247 } 248 size_t startLocation = current().index; 249 auto node = parseCommaSeparatedRule!(ArgumentList, AssignExpression)(true); 250 mixin (nullCheck!`node`); 251 node.startLocation = startLocation; 252 if (moreTokens) node.endLocation = current().index; 253 return node; 254 } 255 256 /** 257 * Parses Arguments. 258 * 259 * $(GRAMMAR $(RULEDEF arguments): 260 * $(LITERAL '$(LPAREN)') $(RULE argumentList)? $(LITERAL '$(RPAREN)') 261 * ;) 262 */ 263 Arguments parseArguments() 264 { 265 mixin(traceEnterAndExit!(__FUNCTION__)); 266 auto node = allocator.make!Arguments; 267 mixin(tokenCheck!"("); 268 if (!currentIs(tok!")")) 269 mixin (parseNodeQ!(`node.argumentList`, `ArgumentList`)); 270 mixin(tokenCheck!")"); 271 return node; 272 } 273 274 /** 275 * Parses an ArrayInitializer. 276 * 277 * $(GRAMMAR $(RULEDEF arrayInitializer): 278 * $(LITERAL '[') $(LITERAL ']') 279 * | $(LITERAL '[') $(RULE arrayMemberInitialization) ($(LITERAL ',') $(RULE arrayMemberInitialization)?)* $(LITERAL ']') 280 * ;) 281 */ 282 ArrayInitializer parseArrayInitializer() 283 { 284 mixin(traceEnterAndExit!(__FUNCTION__)); 285 auto node = allocator.make!ArrayInitializer; 286 const open = expect(tok!"["); 287 mixin (nullCheck!`open`); 288 node.startLocation = open.index; 289 StackBuffer arrayMemberInitializations; 290 while (moreTokens()) 291 { 292 if (currentIs(tok!"]")) 293 break; 294 if (!arrayMemberInitializations.put(parseArrayMemberInitialization())) 295 return null; 296 if (currentIs(tok!",")) 297 advance(); 298 else 299 break; 300 } 301 ownArray(node.arrayMemberInitializations, arrayMemberInitializations); 302 const close = expect(tok!"]"); 303 mixin (nullCheck!`close`); 304 node.endLocation = close.index; 305 return node; 306 } 307 308 /** 309 * Parses an ArrayLiteral. 310 * 311 * $(GRAMMAR $(RULEDEF arrayLiteral): 312 * $(LITERAL '[') $(RULE argumentList)? $(LITERAL ']') 313 * ;) 314 */ 315 ArrayLiteral parseArrayLiteral() 316 { 317 mixin(traceEnterAndExit!(__FUNCTION__)); 318 auto node = allocator.make!ArrayLiteral; 319 mixin(tokenCheck!"["); 320 if (!currentIs(tok!"]")) 321 mixin (parseNodeQ!(`node.argumentList`, `ArgumentList`)); 322 mixin(tokenCheck!"]"); 323 return node; 324 } 325 326 /** 327 * Parses an ArrayMemberInitialization. 328 * 329 * $(GRAMMAR $(RULEDEF arrayMemberInitialization): 330 * ($(RULE assignExpression) $(LITERAL ':'))? $(RULE nonVoidInitializer) 331 * ;) 332 */ 333 ArrayMemberInitialization parseArrayMemberInitialization() 334 { 335 mixin(traceEnterAndExit!(__FUNCTION__)); 336 auto node = allocator.make!ArrayMemberInitialization; 337 switch (current.type) 338 { 339 case tok!"[": 340 immutable b = setBookmark(); 341 skipBrackets(); 342 if (currentIs(tok!":")) 343 { 344 mixin (parseNodeQ!(`node.assignExpression`, `AssignExpression`)); 345 advance(); // : 346 mixin (parseNodeQ!(`node.nonVoidInitializer`, `NonVoidInitializer`)); 347 break; 348 } 349 else 350 { 351 goToBookmark(b); 352 goto case; 353 } 354 case tok!"{": 355 mixin (parseNodeQ!(`node.nonVoidInitializer`, `NonVoidInitializer`)); 356 break; 357 default: 358 auto assignExpression = parseAssignExpression(); 359 mixin (nullCheck!`assignExpression`); 360 if (currentIs(tok!":")) 361 { 362 node.assignExpression = assignExpression; 363 advance(); 364 mixin(parseNodeQ!(`node.nonVoidInitializer`, `NonVoidInitializer`)); 365 } 366 else 367 { 368 node.nonVoidInitializer = allocator.make!NonVoidInitializer; 369 node.nonVoidInitializer.assignExpression = assignExpression; 370 } 371 } 372 return node; 373 } 374 375 /** 376 * Parses an AsmAddExp 377 * 378 * $(GRAMMAR $(RULEDEF asmAddExp): 379 * $(RULE asmMulExp) 380 * | $(RULE asmAddExp) ($(LITERAL '+') | $(LITERAL '-')) $(RULE asmMulExp) 381 * ;) 382 */ 383 ExpressionNode parseAsmAddExp() 384 { 385 mixin (traceEnterAndExit!(__FUNCTION__)); 386 return parseLeftAssocBinaryExpression!(AsmAddExp, AsmMulExp, 387 tok!"+", tok!"-")(); 388 } 389 390 /** 391 * Parses an AsmAndExp 392 * 393 * $(GRAMMAR $(RULEDEF asmAndExp): 394 * $(RULE asmEqualExp) 395 * | $(RULE asmAndExp) $(LITERAL '&') $(RULE asmEqualExp) 396 * ;) 397 */ 398 ExpressionNode parseAsmAndExp() 399 { 400 mixin (traceEnterAndExit!(__FUNCTION__)); 401 return parseLeftAssocBinaryExpression!(AsmAndExp, AsmEqualExp, tok!"&"); 402 } 403 404 /** 405 * Parses an AsmBrExp 406 * 407 * $(GRAMMAR $(RULEDEF asmBrExp): 408 * $(RULE asmUnaExp) 409 * | $(RULE asmBrExp)? $(LITERAL '[') $(RULE asmExp) $(LITERAL ']') 410 * ;) 411 */ 412 AsmBrExp parseAsmBrExp() 413 { 414 mixin(traceEnterAndExit!(__FUNCTION__)); 415 AsmBrExp node = allocator.make!AsmBrExp(); 416 size_t line = current.line; 417 size_t column = current.column; 418 if (currentIs(tok!"[")) 419 { 420 advance(); // [ 421 mixin (parseNodeQ!(`node.asmExp`, `AsmExp`)); 422 mixin(tokenCheck!"]"); 423 if (currentIs(tok!"[")) 424 goto brLoop; 425 } 426 else 427 { 428 mixin(parseNodeQ!(`node.asmUnaExp`, `AsmUnaExp`)); 429 brLoop: while (currentIs(tok!"[")) 430 { 431 AsmBrExp br = allocator.make!AsmBrExp(); // huehuehuehue 432 br.asmBrExp = node; 433 br.line = current().line; 434 br.column = current().column; 435 node = br; 436 node.line = line; 437 node.column = column; 438 advance(); // [ 439 mixin(parseNodeQ!(`node.asmExp`, `AsmExp`)); 440 mixin(tokenCheck!"]"); 441 } 442 } 443 return node; 444 } 445 446 /** 447 * Parses an AsmEqualExp 448 * 449 * $(GRAMMAR $(RULEDEF asmEqualExp): 450 * $(RULE asmRelExp) 451 * | $(RULE asmEqualExp) ('==' | '!=') $(RULE asmRelExp) 452 * ;) 453 */ 454 ExpressionNode parseAsmEqualExp() 455 { 456 mixin(traceEnterAndExit!(__FUNCTION__)); 457 return parseLeftAssocBinaryExpression!(AsmEqualExp, AsmRelExp, tok!"==", tok!"!=")(); 458 } 459 460 /** 461 * Parses an AsmExp 462 * 463 * $(GRAMMAR $(RULEDEF asmExp): 464 * $(RULE asmLogOrExp) ($(LITERAL '?') $(RULE asmExp) $(LITERAL ':') $(RULE asmExp))? 465 * ;) 466 */ 467 ExpressionNode parseAsmExp() 468 { 469 mixin(traceEnterAndExit!(__FUNCTION__)); 470 AsmExp node = allocator.make!AsmExp; 471 mixin(parseNodeQ!(`node.left`, `AsmLogOrExp`)); 472 if (currentIs(tok!"?")) 473 { 474 advance(); 475 mixin(parseNodeQ!(`node.middle`, `AsmExp`)); 476 mixin(tokenCheck!":"); 477 mixin(parseNodeQ!(`node.right`, `AsmExp`)); 478 } 479 return node; 480 } 481 482 /** 483 * Parses an AsmInstruction 484 * 485 * $(GRAMMAR $(RULEDEF asmInstruction): 486 * $(LITERAL Identifier) 487 * | $(LITERAL 'align') $(LITERAL IntegerLiteral) 488 * | $(LITERAL 'align') $(LITERAL Identifier) 489 * | $(LITERAL Identifier) $(LITERAL ':') $(RULE asmInstruction) 490 * | $(LITERAL Identifier) $(RULE operands) 491 * | $(LITERAL 'in') $(RULE operands) 492 * | $(LITERAL 'out') $(RULE operands) 493 * | $(LITERAL 'int') $(RULE operands) 494 * ;) 495 */ 496 AsmInstruction parseAsmInstruction() 497 { 498 mixin (traceEnterAndExit!(__FUNCTION__)); 499 AsmInstruction node = allocator.make!AsmInstruction; 500 if (currentIs(tok!"align")) 501 { 502 advance(); // align 503 node.hasAlign = true; 504 if (currentIsOneOf(tok!"intLiteral", tok!"identifier")) 505 node.identifierOrIntegerOrOpcode = advance(); 506 else 507 error("Identifier or integer literal expected."); 508 } 509 else if (currentIsOneOf(tok!"identifier", tok!"in", tok!"out", tok!"int")) 510 { 511 node.identifierOrIntegerOrOpcode = advance(); 512 if (node.identifierOrIntegerOrOpcode == tok!"identifier" && currentIs(tok!":")) 513 { 514 advance(); // : 515 mixin(parseNodeQ!(`node.asmInstruction`, `AsmInstruction`)); 516 } 517 else if (!currentIs(tok!";")) 518 mixin(parseNodeQ!(`node.operands`, `Operands`)); 519 } 520 return node; 521 } 522 523 /** 524 * Parses an AsmLogAndExp 525 * 526 * $(GRAMMAR $(RULEDEF asmLogAndExp): 527 * $(RULE asmOrExp) 528 * $(RULE asmLogAndExp) $(LITERAL '&&') $(RULE asmOrExp) 529 * ;) 530 */ 531 ExpressionNode parseAsmLogAndExp() 532 { 533 mixin (traceEnterAndExit!(__FUNCTION__)); 534 return parseLeftAssocBinaryExpression!(AsmLogAndExp, AsmOrExp, tok!"&&"); 535 } 536 537 /** 538 * Parses an AsmLogOrExp 539 * 540 * $(GRAMMAR $(RULEDEF asmLogOrExp): 541 * $(RULE asmLogAndExp) 542 * | $(RULE asmLogOrExp) '||' $(RULE asmLogAndExp) 543 * ;) 544 */ 545 ExpressionNode parseAsmLogOrExp() 546 { 547 mixin(traceEnterAndExit!(__FUNCTION__)); 548 return parseLeftAssocBinaryExpression!(AsmLogOrExp, AsmLogAndExp, tok!"||")(); 549 } 550 551 /** 552 * Parses an AsmMulExp 553 * 554 * $(GRAMMAR $(RULEDEF asmMulExp): 555 * $(RULE asmBrExp) 556 * | $(RULE asmMulExp) ($(LITERAL '*') | $(LITERAL '/') | $(LITERAL '%')) $(RULE asmBrExp) 557 * ;) 558 */ 559 ExpressionNode parseAsmMulExp() 560 { 561 mixin(traceEnterAndExit!(__FUNCTION__)); 562 return parseLeftAssocBinaryExpression!(AsmMulExp, AsmBrExp, tok!"*", tok!"/", tok!"%")(); 563 } 564 565 /** 566 * Parses an AsmOrExp 567 * 568 * $(GRAMMAR $(RULEDEF asmOrExp): 569 * $(RULE asmXorExp) 570 * | $(RULE asmOrExp) $(LITERAL '|') $(RULE asmXorExp) 571 * ;) 572 */ 573 ExpressionNode parseAsmOrExp() 574 { 575 mixin (traceEnterAndExit!(__FUNCTION__)); 576 return parseLeftAssocBinaryExpression!(AsmOrExp, AsmXorExp, tok!"|")(); 577 } 578 579 /** 580 * Parses an AsmPrimaryExp 581 * 582 * $(GRAMMAR $(RULEDEF asmPrimaryExp): 583 * $(LITERAL IntegerLiteral) 584 * | $(LITERAL FloatLiteral) 585 * | $(LITERAL StringLiteral) 586 * | $(RULE register) 587 * | $(RULE identifierChain) 588 * | $(LITERAL '$') 589 * ;) 590 */ 591 AsmPrimaryExp parseAsmPrimaryExp() 592 { 593 import std.range : assumeSorted; 594 mixin (traceEnterAndExit!(__FUNCTION__)); 595 AsmPrimaryExp node = allocator.make!AsmPrimaryExp(); 596 switch (current().type) 597 { 598 case tok!"doubleLiteral": 599 case tok!"floatLiteral": 600 case tok!"intLiteral": 601 case tok!"longLiteral": 602 case tok!"stringLiteral": 603 case tok!"$": 604 node.token = advance(); 605 break; 606 case tok!"identifier": 607 if (assumeSorted(REGISTER_NAMES).equalRange(current().text).length > 0) 608 { 609 trace("Found register"); 610 mixin (nullCheck!`(node.register = parseRegister())`); 611 } 612 else 613 mixin(parseNodeQ!(`node.identifierChain`, `IdentifierChain`)); 614 break; 615 default: 616 error("Float literal, integer literal, $, or identifier expected."); 617 return null; 618 } 619 return node; 620 } 621 622 /** 623 * Parses an AsmRelExp 624 * 625 * $(GRAMMAR $(RULEDEF asmRelExp): 626 * $(RULE asmShiftExp) 627 * | $(RULE asmRelExp) (($(LITERAL '<') | $(LITERAL '<=') | $(LITERAL '>') | $(LITERAL '>=')) $(RULE asmShiftExp))? 628 * ;) 629 */ 630 ExpressionNode parseAsmRelExp() 631 { 632 mixin (traceEnterAndExit!(__FUNCTION__)); 633 return parseLeftAssocBinaryExpression!(AsmRelExp, AsmShiftExp, tok!"<", 634 tok!"<=", tok!">", tok!">=")(); 635 } 636 637 /** 638 * Parses an AsmShiftExp 639 * 640 * $(GRAMMAR $(RULEDEF asmShiftExp): 641 * $(RULE asmAddExp) 642 * $(RULE asmShiftExp) ($(LITERAL '<<') | $(LITERAL '>>') | $(LITERAL '>>>')) $(RULE asmAddExp) 643 * ;) 644 */ 645 ExpressionNode parseAsmShiftExp() 646 { 647 mixin (traceEnterAndExit!(__FUNCTION__)); 648 return parseLeftAssocBinaryExpression!(AsmShiftExp, AsmAddExp, tok!"<<", 649 tok!">>", tok!">>>"); 650 } 651 652 /** 653 * Parses an AsmStatement 654 * 655 * $(GRAMMAR $(RULEDEF asmStatement): 656 * $(LITERAL 'asm') $(RULE functionAttributes)? $(LITERAL '{') $(RULE asmInstruction)+ $(LITERAL '}') 657 * ;) 658 */ 659 AsmStatement parseAsmStatement() 660 { 661 mixin (traceEnterAndExit!(__FUNCTION__)); 662 AsmStatement node = allocator.make!AsmStatement; 663 advance(); // asm 664 StackBuffer functionAttributes; 665 while (isAttribute()) 666 { 667 if (!functionAttributes.put(parseFunctionAttribute())) 668 { 669 error("Function attribute or '{' expected"); 670 return null; 671 } 672 } 673 ownArray(node.functionAttributes, functionAttributes); 674 advance(); // { 675 StackBuffer instructions; 676 while (moreTokens() && !currentIs(tok!"}")) 677 { 678 auto c = allocator.setCheckpoint(); 679 if (!instructions.put(parseAsmInstruction())) 680 allocator.rollback(c); 681 else 682 expect(tok!";"); 683 } 684 ownArray(node.asmInstructions, instructions); 685 expect(tok!"}"); 686 return node; 687 } 688 689 /** 690 * Parses an AsmTypePrefix 691 * 692 * Note that in the following grammar definition the first identifier must 693 * be "near", "far", "word", "dword", or "qword". The second identifier must 694 * be "ptr". 695 * 696 * $(GRAMMAR $(RULEDEF asmTypePrefix): 697 * $(LITERAL Identifier) $(LITERAL Identifier)? 698 * | $(LITERAL 'byte') $(LITERAL Identifier)? 699 * | $(LITERAL 'short') $(LITERAL Identifier)? 700 * | $(LITERAL 'int') $(LITERAL Identifier)? 701 * | $(LITERAL 'float') $(LITERAL Identifier)? 702 * | $(LITERAL 'double') $(LITERAL Identifier)? 703 * | $(LITERAL 'real') $(LITERAL Identifier)? 704 * ;) 705 */ 706 AsmTypePrefix parseAsmTypePrefix() 707 { 708 mixin (traceEnterAndExit!(__FUNCTION__)); 709 switch (current().type) 710 { 711 case tok!"identifier": 712 case tok!"byte": 713 case tok!"short": 714 case tok!"int": 715 case tok!"float": 716 case tok!"double": 717 case tok!"real": 718 AsmTypePrefix node = allocator.make!AsmTypePrefix(); 719 node.left = advance(); 720 if (node.left.type == tok!"identifier") switch (node.left.text) 721 { 722 case "near": 723 case "far": 724 case "word": 725 case "dword": 726 case "qword": 727 break; 728 default: 729 error("ASM type node expected"); 730 return null; 731 } 732 if (currentIs(tok!"identifier") && current().text == "ptr") 733 node.right = advance(); 734 return node; 735 default: 736 error("Expected an identifier, 'byte', 'short', 'int', 'float', 'double', or 'real'"); 737 return null; 738 } 739 } 740 741 /** 742 * Parses an AsmUnaExp 743 * 744 * $(GRAMMAR $(RULEDEF asmUnaExp): 745 * $(RULE asmTypePrefix) $(RULE asmExp) 746 * | $(LITERAL Identifier) $(RULE asmExp) 747 * | $(LITERAL '+') $(RULE asmUnaExp) 748 * | $(LITERAL '-') $(RULE asmUnaExp) 749 * | $(LITERAL '!') $(RULE asmUnaExp) 750 * | $(LITERAL '~') $(RULE asmUnaExp) 751 * | $(RULE asmPrimaryExp) 752 * ;) 753 */ 754 AsmUnaExp parseAsmUnaExp() 755 { 756 mixin (traceEnterAndExit!(__FUNCTION__)); 757 AsmUnaExp node = allocator.make!AsmUnaExp(); 758 switch (current().type) 759 { 760 case tok!"+": 761 case tok!"-": 762 case tok!"!": 763 case tok!"~": 764 node.prefix = advance(); 765 mixin(parseNodeQ!(`node.asmUnaExp`, `AsmUnaExp`)); 766 break; 767 case tok!"byte": 768 case tok!"short": 769 case tok!"int": 770 case tok!"float": 771 case tok!"double": 772 case tok!"real": 773 typePrefix: 774 mixin(parseNodeQ!(`node.asmTypePrefix`, `AsmTypePrefix`)); 775 mixin(parseNodeQ!(`node.asmExp`, `AsmExp`)); 776 break; 777 case tok!"identifier": 778 switch (current().text) 779 { 780 case "offsetof": 781 case "seg": 782 node.prefix = advance(); 783 mixin(parseNodeQ!(`node.asmExp`, `AsmExp`)); 784 break; 785 case "near": 786 case "far": 787 case "word": 788 case "dword": 789 case "qword": 790 goto typePrefix; 791 default: 792 goto outerDefault; 793 } 794 break; 795 outerDefault: 796 default: 797 mixin(parseNodeQ!(`node.asmPrimaryExp`, `AsmPrimaryExp`)); 798 break; 799 } 800 return node; 801 } 802 803 /** 804 * Parses an AsmXorExp 805 * 806 * $(GRAMMAR $(RULEDEF asmXorExp): 807 * $(RULE asmAndExp) 808 * | $(RULE asmXorExp) $(LITERAL '^') $(RULE asmAndExp) 809 * ;) 810 */ 811 ExpressionNode parseAsmXorExp() 812 { 813 mixin (traceEnterAndExit!(__FUNCTION__)); 814 return parseLeftAssocBinaryExpression!(AsmXorExp, AsmAndExp, tok!"^")(); 815 } 816 817 /** 818 * Parses an AssertExpression 819 * 820 * $(GRAMMAR $(RULEDEF assertExpression): 821 * $(LITERAL 'assert') $(LITERAL '$(LPAREN)') $(RULE assignExpression) ($(LITERAL ',') $(RULE assignExpression))? $(LITERAL ',')? $(LITERAL '$(RPAREN)') 822 * ;) 823 */ 824 AssertExpression parseAssertExpression() 825 { 826 mixin(traceEnterAndExit!(__FUNCTION__)); 827 auto node = allocator.make!AssertExpression; 828 node.line = current.line; 829 node.column = current.column; 830 advance(); // "assert" 831 mixin(tokenCheck!"("); 832 mixin(parseNodeQ!(`node.assertion`, `AssignExpression`)); 833 if (currentIs(tok!",")) 834 { 835 advance(); 836 if (currentIs(tok!")")) 837 { 838 advance(); 839 return node; 840 } 841 mixin(parseNodeQ!(`node.message`, `AssignExpression`)); 842 } 843 if (currentIs(tok!",")) 844 advance(); 845 mixin(tokenCheck!")"); 846 return node; 847 } 848 849 /** 850 * Parses an AssignExpression 851 * 852 * $(GRAMMAR $(RULEDEF assignExpression): 853 * $(RULE ternaryExpression) ($(RULE assignOperator) $(RULE expression))? 854 * ; 855 *$(RULEDEF assignOperator): 856 * $(LITERAL '=') 857 * | $(LITERAL '>>>=') 858 * | $(LITERAL '>>=') 859 * | $(LITERAL '<<=') 860 * | $(LITERAL '+=') 861 * | $(LITERAL '-=') 862 * | $(LITERAL '*=') 863 * | $(LITERAL '%=') 864 * | $(LITERAL '&=') 865 * | $(LITERAL '/=') 866 * | $(LITERAL '|=') 867 * | $(LITERAL '^^=') 868 * | $(LITERAL '^=') 869 * | $(LITERAL '~=') 870 * ;) 871 */ 872 ExpressionNode parseAssignExpression() 873 { 874 mixin(traceEnterAndExit!(__FUNCTION__)); 875 if (!moreTokens) 876 { 877 error("Assign expression expected instead of EOF"); 878 return null; 879 } 880 auto ternary = parseTernaryExpression(); 881 if (ternary is null) 882 return null; 883 if (currentIsOneOf(tok!"=", tok!">>>=", 884 tok!">>=", tok!"<<=", 885 tok!"+=", tok!"-=", tok!"*=", 886 tok!"%=", tok!"&=", tok!"/=", 887 tok!"|=", tok!"^^=", tok!"^=", 888 tok!"~=")) 889 { 890 auto node = allocator.make!AssignExpression; 891 node.line = current().line; 892 node.column = current().column; 893 node.ternaryExpression = ternary; 894 node.operator = advance().type; 895 mixin(parseNodeQ!(`node.expression`, `Expression`)); 896 return node; 897 } 898 return ternary; 899 } 900 901 /** 902 * Parses an AssocArrayLiteral 903 * 904 * $(GRAMMAR $(RULEDEF assocArrayLiteral): 905 * $(LITERAL '[') $(RULE keyValuePairs) $(LITERAL ']') 906 * ;) 907 */ 908 AssocArrayLiteral parseAssocArrayLiteral() 909 { 910 mixin(traceEnterAndExit!(__FUNCTION__)); 911 mixin (simpleParse!(AssocArrayLiteral, tok!"[", 912 "keyValuePairs|parseKeyValuePairs", tok!"]")); 913 } 914 915 /** 916 * Parses an AtAttribute 917 * 918 * $(GRAMMAR $(RULEDEF atAttribute): 919 * $(LITERAL '@') $(LITERAL Identifier) 920 * | $(LITERAL '@') $(LITERAL Identifier) $(LITERAL '$(LPAREN)') $(RULE argumentList)? $(LITERAL '$(RPAREN)') 921 * | $(LITERAL '@') $(LITERAL '$(LPAREN)') $(RULE argumentList) $(LITERAL '$(RPAREN)') 922 * | $(LITERAL '@') $(RULE TemplateInstance) 923 * ;) 924 */ 925 AtAttribute parseAtAttribute() 926 { 927 mixin(traceEnterAndExit!(__FUNCTION__)); 928 auto node = allocator.make!AtAttribute; 929 const start = expect(tok!"@"); 930 mixin (nullCheck!`start`); 931 if (!moreTokens) 932 { 933 error(`"(", or identifier expected`); 934 return null; 935 } 936 node.startLocation = start.index; 937 switch (current.type) 938 { 939 case tok!"identifier": 940 if (peekIs(tok!"!")) 941 mixin(parseNodeQ!(`node.templateInstance`, `TemplateInstance`)); 942 else 943 node.identifier = advance(); 944 if (currentIs(tok!"(")) 945 { 946 advance(); // ( 947 if (!currentIs(tok!")")) 948 mixin(parseNodeQ!(`node.argumentList`, `ArgumentList`)); 949 expect(tok!")"); 950 } 951 break; 952 case tok!"(": 953 advance(); 954 mixin(parseNodeQ!(`node.argumentList`, `ArgumentList`)); 955 expect(tok!")"); 956 break; 957 default: 958 error(`"(", or identifier expected`); 959 return null; 960 } 961 if (moreTokens) node.endLocation = current().index; 962 return node; 963 } 964 965 /** 966 * Parses an Attribute 967 * 968 * $(GRAMMAR $(RULEDEF attribute): 969 * | $(RULE pragmaExpression) 970 * | $(RULE alignAttribute) 971 * | $(RULE deprecated) 972 * | $(RULE atAttribute) 973 * | $(RULE linkageAttribute) 974 * | $(LITERAL 'export') 975 * | $(LITERAL 'package') ($(LITERAL "(") $(RULE identifierChain) $(LITERAL ")"))? 976 * | $(LITERAL 'private') 977 * | $(LITERAL 'protected') 978 * | $(LITERAL 'public') 979 * | $(LITERAL 'static') 980 * | $(LITERAL 'extern') 981 * | $(LITERAL 'abstract') 982 * | $(LITERAL 'final') 983 * | $(LITERAL 'override') 984 * | $(LITERAL 'synchronized') 985 * | $(LITERAL 'auto') 986 * | $(LITERAL 'scope') 987 * | $(LITERAL 'const') 988 * | $(LITERAL 'immutable') 989 * | $(LITERAL 'inout') 990 * | $(LITERAL 'shared') 991 * | $(LITERAL '__gshared') 992 * | $(LITERAL 'nothrow') 993 * | $(LITERAL 'pure') 994 * | $(LITERAL 'ref') 995 * ;) 996 */ 997 Attribute parseAttribute() 998 { 999 mixin(traceEnterAndExit!(__FUNCTION__)); 1000 auto node = allocator.make!Attribute; 1001 switch (current.type) 1002 { 1003 case tok!"pragma": 1004 mixin(parseNodeQ!(`node.pragmaExpression`, `PragmaExpression`)); 1005 break; 1006 case tok!"deprecated": 1007 mixin(parseNodeQ!(`node.deprecated_`, `Deprecated`)); 1008 break; 1009 case tok!"align": 1010 mixin(parseNodeQ!(`node.alignAttribute`, `AlignAttribute`)); 1011 break; 1012 case tok!"@": 1013 mixin(parseNodeQ!(`node.atAttribute`, `AtAttribute`)); 1014 break; 1015 case tok!"package": 1016 node.attribute = advance(); 1017 if (currentIs(tok!"(")) 1018 { 1019 expect(tok!"("); 1020 mixin(parseNodeQ!(`node.identifierChain`, `IdentifierChain`)); 1021 expect(tok!")"); 1022 } 1023 break; 1024 case tok!"extern": 1025 if (peekIs(tok!"(")) 1026 { 1027 mixin(parseNodeQ!(`node.linkageAttribute`, `LinkageAttribute`)); 1028 break; 1029 } 1030 else 1031 goto case; 1032 case tok!"private": 1033 case tok!"protected": 1034 case tok!"public": 1035 case tok!"export": 1036 case tok!"static": 1037 case tok!"abstract": 1038 case tok!"final": 1039 case tok!"override": 1040 case tok!"synchronized": 1041 case tok!"auto": 1042 case tok!"scope": 1043 case tok!"const": 1044 case tok!"immutable": 1045 case tok!"inout": 1046 case tok!"shared": 1047 case tok!"__gshared": 1048 case tok!"nothrow": 1049 case tok!"pure": 1050 case tok!"ref": 1051 node.attribute = advance(); 1052 break; 1053 default: 1054 return null; 1055 } 1056 return node; 1057 } 1058 1059 /** 1060 * Parses an AttributeDeclaration 1061 * 1062 * $(GRAMMAR $(RULEDEF attributeDeclaration): 1063 * $(RULE attribute) $(LITERAL ':') 1064 * ;) 1065 */ 1066 AttributeDeclaration parseAttributeDeclaration(Attribute attribute = null) 1067 { 1068 auto node = allocator.make!AttributeDeclaration; 1069 node.line = current.line; 1070 node.attribute = attribute is null ? parseAttribute() : attribute; 1071 expect(tok!":"); 1072 return node; 1073 } 1074 1075 /** 1076 * Parses an AutoDeclaration 1077 * 1078 * $(GRAMMAR $(RULEDEF autoDeclaration): 1079 * $(RULE storageClass)+ $(LITERAL Identifier) $(LITERAL '=') $(RULE initializer) ($(LITERAL ',') $(LITERAL Identifier) $(LITERAL '=') $(RULE initializer))* $(LITERAL ';') 1080 * ;) 1081 */ 1082 AutoDeclaration parseAutoDeclaration() 1083 { 1084 mixin(traceEnterAndExit!(__FUNCTION__)); 1085 auto node = allocator.make!AutoDeclaration; 1086 node.comment = comment; 1087 comment = null; 1088 StackBuffer storageClasses; 1089 while (isStorageClass()) 1090 if (!storageClasses.put(parseStorageClass())) 1091 return null; 1092 ownArray(node.storageClasses, storageClasses); 1093 StackBuffer identifiers; 1094 StackBuffer initializers; 1095 do 1096 { 1097 auto i = expect(tok!"identifier"); 1098 if (i is null) 1099 return null; 1100 identifiers.put(*i); 1101 mixin(tokenCheck!"="); 1102 if (!initializers.put(parseInitializer())) 1103 return null; 1104 if (currentIs(tok!",")) 1105 advance(); 1106 else 1107 break; 1108 } while (moreTokens()); 1109 ownArray(node.identifiers, identifiers); 1110 ownArray(node.initializers, initializers); 1111 return attachCommentFromSemicolon(node); 1112 } 1113 1114 /** 1115 * Parses a BlockStatement 1116 * 1117 * $(GRAMMAR $(RULEDEF blockStatement): 1118 * $(LITERAL '{') $(RULE declarationsAndStatements)? $(LITERAL '}') 1119 * ;) 1120 */ 1121 BlockStatement parseBlockStatement() 1122 { 1123 mixin(traceEnterAndExit!(__FUNCTION__)); 1124 auto node = allocator.make!BlockStatement; 1125 const openBrace = expect(tok!"{"); 1126 mixin (nullCheck!`openBrace`); 1127 node.startLocation = openBrace.index; 1128 if (!currentIs(tok!"}")) 1129 { 1130 mixin(parseNodeQ!(`node.declarationsAndStatements`, `DeclarationsAndStatements`)); 1131 } 1132 const closeBrace = expect(tok!"}"); 1133 if (closeBrace !is null) 1134 node.endLocation = closeBrace.index; 1135 else 1136 { 1137 trace("Could not find end of block statement."); 1138 node.endLocation = size_t.max; 1139 } 1140 1141 return node; 1142 } 1143 1144 /** 1145 * Parses a BodyStatement 1146 * 1147 * $(GRAMMAR $(RULEDEF bodyStatement): 1148 * $(LITERAL 'body') $(RULE blockStatement) 1149 * ;) 1150 */ 1151 BodyStatement parseBodyStatement() 1152 { 1153 mixin(traceEnterAndExit!(__FUNCTION__)); 1154 mixin (simpleParse!(BodyStatement, tok!"body", 1155 "blockStatement|parseBlockStatement")); 1156 } 1157 1158 /** 1159 * Parses a BreakStatement 1160 * 1161 * $(GRAMMAR $(RULEDEF breakStatement): 1162 * $(LITERAL 'break') $(LITERAL Identifier)? $(LITERAL ';') 1163 * ;) 1164 */ 1165 BreakStatement parseBreakStatement() 1166 { 1167 mixin(traceEnterAndExit!(__FUNCTION__)); 1168 expect(tok!"break"); 1169 auto node = allocator.make!BreakStatement; 1170 switch (current.type) 1171 { 1172 case tok!"identifier": 1173 node.label = advance(); 1174 mixin(tokenCheck!";"); 1175 break; 1176 case tok!";": 1177 advance(); 1178 break; 1179 default: 1180 error("Identifier or semicolon expected following \"break\""); 1181 return null; 1182 } 1183 return node; 1184 } 1185 1186 /** 1187 * Parses a BaseClass 1188 * 1189 * $(GRAMMAR $(RULEDEF baseClass): 1190 * $(RULE type2) 1191 * ;) 1192 */ 1193 BaseClass parseBaseClass() 1194 { 1195 mixin(traceEnterAndExit!(__FUNCTION__)); 1196 auto node = allocator.make!BaseClass; 1197 if (current.type.isProtection()) 1198 { 1199 warn("Use of base class protection is deprecated."); 1200 advance(); 1201 } 1202 if ((node.type2 = parseType2()) is null) 1203 { 1204 return null; 1205 } 1206 return node; 1207 } 1208 1209 /** 1210 * Parses a BaseClassList 1211 * 1212 * $(GRAMMAR $(RULEDEF baseClassList): 1213 * $(RULE baseClass) ($(LITERAL ',') $(RULE baseClass))* 1214 * ;) 1215 */ 1216 BaseClassList parseBaseClassList() 1217 { 1218 mixin(traceEnterAndExit!(__FUNCTION__)); 1219 return parseCommaSeparatedRule!(BaseClassList, BaseClass)(); 1220 } 1221 1222 /** 1223 * Parses an BuiltinType 1224 * 1225 * $(GRAMMAR $(RULEDEF builtinType): 1226 * $(LITERAL 'bool') 1227 * | $(LITERAL 'byte') 1228 * | $(LITERAL 'ubyte') 1229 * | $(LITERAL 'short') 1230 * | $(LITERAL 'ushort') 1231 * | $(LITERAL 'int') 1232 * | $(LITERAL 'uint') 1233 * | $(LITERAL 'long') 1234 * | $(LITERAL 'ulong') 1235 * | $(LITERAL 'char') 1236 * | $(LITERAL 'wchar') 1237 * | $(LITERAL 'dchar') 1238 * | $(LITERAL 'float') 1239 * | $(LITERAL 'double') 1240 * | $(LITERAL 'real') 1241 * | $(LITERAL 'ifloat') 1242 * | $(LITERAL 'idouble') 1243 * | $(LITERAL 'ireal') 1244 * | $(LITERAL 'cfloat') 1245 * | $(LITERAL 'cdouble') 1246 * | $(LITERAL 'creal') 1247 * | $(LITERAL 'void') 1248 * ;) 1249 */ 1250 IdType parseBuiltinType() 1251 { 1252 mixin(traceEnterAndExit!(__FUNCTION__)); 1253 return advance().type; 1254 } 1255 1256 /** 1257 * Parses a CaseRangeStatement 1258 * 1259 * $(GRAMMAR $(RULEDEF caseRangeStatement): 1260 * $(LITERAL 'case') $(RULE assignExpression) $(LITERAL ':') $(LITERAL '...') $(LITERAL 'case') $(RULE assignExpression) $(LITERAL ':') $(RULE declarationsAndStatements) 1261 * ;) 1262 */ 1263 CaseRangeStatement parseCaseRangeStatement(ExpressionNode low) 1264 { 1265 mixin(traceEnterAndExit!(__FUNCTION__)); 1266 auto node = allocator.make!CaseRangeStatement; 1267 assert (low !is null); 1268 node.low = low; 1269 mixin(tokenCheck!":"); 1270 mixin(tokenCheck!".."); 1271 expect(tok!"case"); 1272 mixin(parseNodeQ!(`node.high`, `AssignExpression`)); 1273 const colon = expect(tok!":"); 1274 if (colon is null) 1275 return null; 1276 node.colonLocation = colon.index; 1277 mixin(parseNodeQ!(`node.declarationsAndStatements`, `DeclarationsAndStatements`)); 1278 return node; 1279 } 1280 1281 /** 1282 * Parses an CaseStatement 1283 * 1284 * $(GRAMMAR $(RULEDEF caseStatement): 1285 * $(LITERAL 'case') $(RULE argumentList) $(LITERAL ':') $(RULE declarationsAndStatements) 1286 * ;) 1287 */ 1288 CaseStatement parseCaseStatement(ArgumentList argumentList = null) 1289 { 1290 mixin(traceEnterAndExit!(__FUNCTION__)); 1291 auto node = allocator.make!CaseStatement; 1292 node.argumentList = argumentList; 1293 const colon = expect(tok!":"); 1294 if (colon is null) 1295 return null; 1296 node.colonLocation = colon.index; 1297 mixin (nullCheck!`node.declarationsAndStatements = parseDeclarationsAndStatements(false)`); 1298 return node; 1299 } 1300 1301 /** 1302 * Parses a CastExpression 1303 * 1304 * $(GRAMMAR $(RULEDEF castExpression): 1305 * $(LITERAL 'cast') $(LITERAL '$(LPAREN)') ($(RULE type) | $(RULE castQualifier))? $(LITERAL '$(RPAREN)') $(RULE unaryExpression) 1306 * ;) 1307 */ 1308 CastExpression parseCastExpression() 1309 { 1310 mixin(traceEnterAndExit!(__FUNCTION__)); 1311 auto node = allocator.make!CastExpression; 1312 expect(tok!"cast"); 1313 mixin(tokenCheck!"("); 1314 if (!currentIs(tok!")")) 1315 { 1316 if (isCastQualifier()) 1317 mixin(parseNodeQ!(`node.castQualifier`, `CastQualifier`)); 1318 else 1319 mixin(parseNodeQ!(`node.type`, `Type`)); 1320 } 1321 mixin(tokenCheck!")"); 1322 mixin(parseNodeQ!(`node.unaryExpression`, `UnaryExpression`)); 1323 return node; 1324 } 1325 1326 /** 1327 * Parses a CastQualifier 1328 * 1329 * $(GRAMMAR $(RULEDEF castQualifier): 1330 * $(LITERAL 'const') 1331 * | $(LITERAL 'const') $(LITERAL 'shared') 1332 * | $(LITERAL 'immutable') 1333 * | $(LITERAL 'inout') 1334 * | $(LITERAL 'inout') $(LITERAL 'shared') 1335 * | $(LITERAL 'shared') 1336 * | $(LITERAL 'shared') $(LITERAL 'const') 1337 * | $(LITERAL 'shared') $(LITERAL 'inout') 1338 * ;) 1339 */ 1340 CastQualifier parseCastQualifier() 1341 { 1342 mixin(traceEnterAndExit!(__FUNCTION__)); 1343 auto node = allocator.make!CastQualifier; 1344 switch (current.type) 1345 { 1346 case tok!"inout": 1347 case tok!"const": 1348 node.first = advance(); 1349 if (currentIs(tok!"shared")) 1350 node.second = advance(); 1351 break; 1352 case tok!"shared": 1353 node.first = advance(); 1354 if (currentIsOneOf(tok!"const", tok!"inout")) 1355 node.second = advance(); 1356 break; 1357 case tok!"immutable": 1358 node.first = advance(); 1359 break; 1360 default: 1361 error("const, immutable, inout, or shared expected"); 1362 return null; 1363 } 1364 return node; 1365 } 1366 1367 /** 1368 * Parses a Catch 1369 * 1370 * $(GRAMMAR $(RULEDEF catch): 1371 * $(LITERAL 'catch') $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL Identifier)? $(LITERAL '$(RPAREN)') $(RULE declarationOrStatement) 1372 * ;) 1373 */ 1374 Catch parseCatch() 1375 { 1376 mixin(traceEnterAndExit!(__FUNCTION__)); 1377 auto node = allocator.make!Catch; 1378 expect(tok!"catch"); 1379 mixin(tokenCheck!"("); 1380 mixin(parseNodeQ!(`node.type`, `Type`)); 1381 if (currentIs(tok!"identifier")) 1382 node.identifier = advance(); 1383 mixin(tokenCheck!")"); 1384 mixin(parseNodeQ!(`node.declarationOrStatement`, `DeclarationOrStatement`)); 1385 return node; 1386 } 1387 1388 /** 1389 * Parses a Catches 1390 * 1391 * $(GRAMMAR $(RULEDEF catches): 1392 * $(RULE catch)+ 1393 * | $(RULE catch)* $(RULE lastCatch) 1394 * ;) 1395 */ 1396 Catches parseCatches() 1397 { 1398 mixin(traceEnterAndExit!(__FUNCTION__)); 1399 auto node = allocator.make!Catches; 1400 StackBuffer catches; 1401 while (moreTokens()) 1402 { 1403 if (!currentIs(tok!"catch")) 1404 break; 1405 if (peekIs(tok!"(")) 1406 { 1407 if (!catches.put(parseCatch())) 1408 return null; 1409 } 1410 else 1411 { 1412 mixin(parseNodeQ!(`node.lastCatch`, `LastCatch`)); 1413 break; 1414 } 1415 } 1416 ownArray(node.catches, catches); 1417 return node; 1418 } 1419 1420 /** 1421 * Parses a ClassDeclaration 1422 * 1423 * $(GRAMMAR $(RULEDEF classDeclaration): 1424 * $(LITERAL 'class') $(LITERAL Identifier) $(LITERAL ';') 1425 * | $(LITERAL 'class') $(LITERAL Identifier) ($(LITERAL ':') $(RULE baseClassList))? $(RULE structBody) 1426 * | $(LITERAL 'class') $(LITERAL Identifier) $(RULE templateParameters) $(RULE constraint)? ($(RULE structBody) | $(LITERAL ';')) 1427 * | $(LITERAL 'class') $(LITERAL Identifier) $(RULE templateParameters) $(RULE constraint)? ($(LITERAL ':') $(RULE baseClassList))? $(RULE structBody) 1428 * | $(LITERAL 'class') $(LITERAL Identifier) $(RULE templateParameters) ($(LITERAL ':') $(RULE baseClassList))? $(RULE constraint)? $(RULE structBody) 1429 * ;) 1430 */ 1431 ClassDeclaration parseClassDeclaration() 1432 { 1433 mixin(traceEnterAndExit!(__FUNCTION__)); 1434 auto node = allocator.make!ClassDeclaration; 1435 expect(tok!"class"); 1436 return parseInterfaceOrClass(node); 1437 } 1438 1439 /** 1440 * Parses a CmpExpression 1441 * 1442 * $(GRAMMAR $(RULEDEF cmpExpression): 1443 * $(RULE shiftExpression) 1444 * | $(RULE equalExpression) 1445 * | $(RULE identityExpression) 1446 * | $(RULE relExpression) 1447 * | $(RULE inExpression) 1448 * ;) 1449 */ 1450 ExpressionNode parseCmpExpression() 1451 { 1452 mixin(traceEnterAndExit!(__FUNCTION__)); 1453 auto shift = parseShiftExpression(); 1454 if (shift is null) 1455 return null; 1456 if (!moreTokens()) 1457 return shift; 1458 switch (current.type) 1459 { 1460 case tok!"is": 1461 auto node = allocator.make!CmpExpression; 1462 mixin (nullCheck!`node.identityExpression = parseIdentityExpression(shift)`); 1463 return node; 1464 case tok!"in": 1465 auto node = allocator.make!CmpExpression; 1466 mixin (nullCheck!`node.inExpression = parseInExpression(shift)`); 1467 return node; 1468 case tok!"!": 1469 auto node = allocator.make!CmpExpression; 1470 if (peekIs(tok!"is")) 1471 mixin (nullCheck!`node.identityExpression = parseIdentityExpression(shift)`); 1472 else if (peekIs(tok!"in")) 1473 mixin (nullCheck!`node.inExpression = parseInExpression(shift)`); 1474 return node; 1475 case tok!"<": 1476 case tok!"<=": 1477 case tok!">": 1478 case tok!">=": 1479 case tok!"!<>=": 1480 case tok!"!<>": 1481 case tok!"<>": 1482 case tok!"<>=": 1483 case tok!"!>": 1484 case tok!"!>=": 1485 case tok!"!<": 1486 case tok!"!<=": 1487 auto node = allocator.make!CmpExpression; 1488 mixin (nullCheck!`node.relExpression = parseRelExpression(shift)`); 1489 return node; 1490 case tok!"==": 1491 case tok!"!=": 1492 auto node = allocator.make!CmpExpression; 1493 mixin (nullCheck!`node.equalExpression = parseEqualExpression(shift)`); 1494 return node; 1495 default: 1496 return shift; 1497 } 1498 } 1499 1500 /** 1501 * Parses a CompileCondition 1502 * 1503 * $(GRAMMAR $(RULEDEF compileCondition): 1504 * $(RULE versionCondition) 1505 * | $(RULE debugCondition) 1506 * | $(RULE staticIfCondition) 1507 * ;) 1508 */ 1509 CompileCondition parseCompileCondition() 1510 { 1511 mixin(traceEnterAndExit!(__FUNCTION__)); 1512 auto node = allocator.make!CompileCondition; 1513 switch (current.type) 1514 { 1515 case tok!"version": 1516 mixin(parseNodeQ!(`node.versionCondition`, `VersionCondition`)); 1517 break; 1518 case tok!"debug": 1519 mixin(parseNodeQ!(`node.debugCondition`, `DebugCondition`)); 1520 break; 1521 case tok!"static": 1522 mixin(parseNodeQ!(`node.staticIfCondition`, `StaticIfCondition`)); 1523 break; 1524 default: 1525 error(`"version", "debug", or "static" expected`); 1526 return null; 1527 } 1528 return node; 1529 } 1530 1531 /** 1532 * Parses a ConditionalDeclaration 1533 * 1534 * $(GRAMMAR $(RULEDEF conditionalDeclaration): 1535 * $(RULE compileCondition) $(RULE declaration) 1536 * | $(RULE compileCondition) $(LITERAL '{') $(RULE declaration)* $(LITERAL '}') 1537 * | $(RULE compileCondition) $(LITERAL ':') $(RULE declaration)+ 1538 * | $(RULE compileCondition) $(RULE declaration) $(LITERAL 'else') $(LITERAL ':') $(RULE declaration)* 1539 * | $(RULE compileCondition) $(RULE declaration) $(LITERAL 'else') $(RULE declaration) 1540 * | $(RULE compileCondition) $(RULE declaration) $(LITERAL 'else') $(LITERAL '{') $(RULE declaration)* $(LITERAL '}') 1541 * | $(RULE compileCondition) $(LITERAL '{') $(RULE declaration)* $(LITERAL '}') $(LITERAL 'else') $(RULE declaration) 1542 * | $(RULE compileCondition) $(LITERAL '{') $(RULE declaration)* $(LITERAL '}') $(LITERAL 'else') $(LITERAL '{') $(RULE declaration)* $(LITERAL '}') 1543 * | $(RULE compileCondition) $(LITERAL '{') $(RULE declaration)* $(LITERAL '}') $(LITERAL 'else') $(LITERAL ':') $(RULE declaration)* 1544 * | $(RULE compileCondition) $(LITERAL ':') $(RULE declaration)+ $(LITERAL 'else') $(RULE declaration) 1545 * | $(RULE compileCondition) $(LITERAL ':') $(RULE declaration)+ $(LITERAL 'else') $(LITERAL '{') $(RULE declaration)* $(LITERAL '}') 1546 * | $(RULE compileCondition) $(LITERAL ':') $(RULE declaration)+ $(LITERAL 'else') $(LITERAL ':') $(RULE declaration)* 1547 * ;) 1548 */ 1549 ConditionalDeclaration parseConditionalDeclaration(bool strict) 1550 { 1551 mixin(traceEnterAndExit!(__FUNCTION__)); 1552 auto node = allocator.make!ConditionalDeclaration; 1553 mixin(parseNodeQ!(`node.compileCondition`, `CompileCondition`)); 1554 1555 StackBuffer trueDeclarations; 1556 if (currentIs(tok!":") || currentIs(tok!"{")) 1557 { 1558 immutable bool brace = advance() == tok!"{"; 1559 while (moreTokens() && !currentIs(tok!"}") && !currentIs(tok!"else")) 1560 { 1561 immutable b = setBookmark(); 1562 immutable c = allocator.setCheckpoint(); 1563 if (trueDeclarations.put(parseDeclaration(strict, true))) 1564 abandonBookmark(b); 1565 else 1566 { 1567 goToBookmark(b); 1568 allocator.rollback(c); 1569 return null; 1570 } 1571 } 1572 if (brace) 1573 mixin(tokenCheck!"}"); 1574 } 1575 else if (!trueDeclarations.put(parseDeclaration(strict, true))) 1576 return null; 1577 1578 ownArray(node.trueDeclarations, trueDeclarations); 1579 1580 if (currentIs(tok!"else")) 1581 { 1582 node.hasElse = true; 1583 advance(); 1584 } 1585 else 1586 return node; 1587 1588 StackBuffer falseDeclarations; 1589 if (currentIs(tok!":") || currentIs(tok!"{")) 1590 { 1591 immutable bool brace = currentIs(tok!"{"); 1592 advance(); 1593 while (moreTokens() && !currentIs(tok!"}")) 1594 if (!falseDeclarations.put(parseDeclaration(strict, true))) 1595 return null; 1596 if (brace) 1597 mixin(tokenCheck!"}"); 1598 } 1599 else 1600 { 1601 if (!falseDeclarations.put(parseDeclaration(strict, true))) 1602 return null; 1603 } 1604 ownArray(node.falseDeclarations, falseDeclarations); 1605 return node; 1606 } 1607 1608 /** 1609 * Parses a ConditionalStatement 1610 * 1611 * $(GRAMMAR $(RULEDEF conditionalStatement): 1612 * $(RULE compileCondition) $(RULE declarationOrStatement) ($(LITERAL 'else') $(RULE declarationOrStatement))? 1613 * ;) 1614 */ 1615 ConditionalStatement parseConditionalStatement() 1616 { 1617 mixin(traceEnterAndExit!(__FUNCTION__)); 1618 auto node = allocator.make!ConditionalStatement; 1619 mixin(parseNodeQ!(`node.compileCondition`, `CompileCondition`)); 1620 mixin(parseNodeQ!(`node.trueStatement`, `DeclarationOrStatement`)); 1621 if (currentIs(tok!"else")) 1622 { 1623 advance(); 1624 mixin(parseNodeQ!(`node.falseStatement`, `DeclarationOrStatement`)); 1625 } 1626 return node; 1627 } 1628 1629 /** 1630 * Parses a Constraint 1631 * 1632 * $(GRAMMAR $(RULEDEF constraint): 1633 * $(LITERAL 'if') $(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)') 1634 * ;) 1635 */ 1636 Constraint parseConstraint() 1637 { 1638 mixin(traceEnterAndExit!(__FUNCTION__)); 1639 auto node = allocator.make!Constraint; 1640 auto ifToken = expect(tok!"if"); 1641 mixin (nullCheck!`ifToken`); 1642 node.location = ifToken.index; 1643 mixin(tokenCheck!"("); 1644 mixin(parseNodeQ!(`node.expression`, `Expression`)); 1645 mixin(tokenCheck!")"); 1646 return node; 1647 } 1648 1649 /** 1650 * Parses a Constructor 1651 * 1652 * $(GRAMMAR $(RULEDEF constructor): 1653 * $(LITERAL 'this') $(RULE templateParameters)? $(RULE parameters) $(RULE memberFunctionAttribute)* $(RULE constraint)? ($(RULE functionBody) | $(LITERAL ';')) 1654 * ;) 1655 */ 1656 Constructor parseConstructor() 1657 { 1658 mixin(traceEnterAndExit!(__FUNCTION__)); 1659 Constructor node = allocator.make!Constructor; 1660 node.comment = comment; 1661 comment = null; 1662 const t = expect(tok!"this"); 1663 mixin (nullCheck!`t`); 1664 node.location = t.index; 1665 node.line = t.line; 1666 node.column = t.column; 1667 const p = peekPastParens(); 1668 bool isTemplate = false; 1669 if (p !is null && p.type == tok!"(") 1670 { 1671 isTemplate = true; 1672 mixin(parseNodeQ!(`node.templateParameters`, `TemplateParameters`)); 1673 } 1674 mixin(parseNodeQ!(`node.parameters`, `Parameters`)); 1675 1676 StackBuffer memberFunctionAttributes; 1677 while (moreTokens() && currentIsMemberFunctionAttribute()) 1678 if (!memberFunctionAttributes.put(parseMemberFunctionAttribute())) 1679 return null; 1680 ownArray(node.memberFunctionAttributes, memberFunctionAttributes); 1681 1682 if (isTemplate && currentIs(tok!"if")) 1683 mixin(parseNodeQ!(`node.constraint`, `Constraint`)); 1684 if (currentIs(tok!";")) 1685 advance(); 1686 else 1687 mixin(parseNodeQ!(`node.functionBody`, `FunctionBody`)); 1688 return node; 1689 } 1690 1691 /** 1692 * Parses an ContinueStatement 1693 * 1694 * $(GRAMMAR $(RULEDEF continueStatement): 1695 * $(LITERAL 'continue') $(LITERAL Identifier)? $(LITERAL ';') 1696 * ;) 1697 */ 1698 ContinueStatement parseContinueStatement() 1699 { 1700 mixin(traceEnterAndExit!(__FUNCTION__)); 1701 auto node = allocator.make!ContinueStatement; 1702 mixin(tokenCheck!"continue"); 1703 switch (current.type) 1704 { 1705 case tok!"identifier": 1706 node.label = advance(); 1707 mixin(tokenCheck!";"); 1708 break; 1709 case tok!";": 1710 advance(); 1711 break; 1712 default: 1713 error(`Identifier or semicolon expected following "continue"`); 1714 return null; 1715 } 1716 return node; 1717 } 1718 1719 /** 1720 * Parses a DebugCondition 1721 * 1722 * $(GRAMMAR $(RULEDEF debugCondition): 1723 * $(LITERAL 'debug') ($(LITERAL '$(LPAREN)') ($(LITERAL IntegerLiteral) | $(LITERAL Identifier)) $(LITERAL '$(RPAREN)'))? 1724 * ;) 1725 */ 1726 DebugCondition parseDebugCondition() 1727 { 1728 mixin(traceEnterAndExit!(__FUNCTION__)); 1729 auto node = allocator.make!DebugCondition; 1730 1731 const d = expect(tok!"debug"); 1732 mixin (nullCheck!`d`); 1733 node.debugIndex = d.index; 1734 1735 if (currentIs(tok!"(")) 1736 { 1737 advance(); 1738 if (currentIsOneOf(tok!"intLiteral", tok!"identifier")) 1739 node.identifierOrInteger = advance(); 1740 else 1741 { 1742 error(`Integer literal or identifier expected`); 1743 return null; 1744 } 1745 mixin(tokenCheck!")"); 1746 } 1747 return node; 1748 } 1749 1750 /** 1751 * Parses a DebugSpecification 1752 * 1753 * $(GRAMMAR $(RULEDEF debugSpecification): 1754 * $(LITERAL 'debug') $(LITERAL '=') ($(LITERAL Identifier) | $(LITERAL IntegerLiteral)) $(LITERAL ';') 1755 * ;) 1756 */ 1757 DebugSpecification parseDebugSpecification() 1758 { 1759 mixin(traceEnterAndExit!(__FUNCTION__)); 1760 auto node = allocator.make!DebugSpecification; 1761 mixin(tokenCheck!"debug"); 1762 mixin(tokenCheck!"="); 1763 if (currentIsOneOf(tok!"identifier", tok!"intLiteral")) 1764 node.identifierOrInteger = advance(); 1765 else 1766 { 1767 error("Integer literal or identifier expected"); 1768 return null; 1769 } 1770 mixin(tokenCheck!";"); 1771 return node; 1772 } 1773 1774 /** 1775 * Parses a Declaration 1776 * 1777 * Params: strict = if true, do not return partial AST nodes on errors. 1778 * 1779 * $(GRAMMAR $(RULEDEF declaration): 1780 * $(RULE attribute)* $(RULE declaration2) 1781 * | $(RULE attribute)+ $(LITERAL '{') $(RULE declaration)* $(LITERAL '}') 1782 * ; 1783 * $(RULEDEF declaration2): 1784 * $(RULE aliasDeclaration) 1785 * | $(RULE aliasThisDeclaration) 1786 * | $(RULE anonymousEnumDeclaration) 1787 * | $(RULE attributeDeclaration) 1788 * | $(RULE classDeclaration) 1789 * | $(RULE conditionalDeclaration) 1790 * | $(RULE constructor) 1791 * | $(RULE debugSpecification) 1792 * | $(RULE destructor) 1793 * | $(RULE enumDeclaration) 1794 * | $(RULE eponymousTemplateDeclaration) 1795 * | $(RULE functionDeclaration) 1796 * | $(RULE importDeclaration) 1797 * | $(RULE interfaceDeclaration) 1798 * | $(RULE invariant) 1799 * | $(RULE mixinDeclaration) 1800 * | $(RULE mixinTemplateDeclaration) 1801 * | $(RULE pragmaDeclaration) 1802 * | $(RULE sharedStaticConstructor) 1803 * | $(RULE sharedStaticDestructor) 1804 * | $(RULE staticAssertDeclaration) 1805 * | $(RULE staticConstructor) 1806 * | $(RULE staticDestructor) 1807 * | $(RULE structDeclaration) 1808 * | $(RULE templateDeclaration) 1809 * | $(RULE unionDeclaration) 1810 * | $(RULE unittest) 1811 * | $(RULE variableDeclaration) 1812 * | $(RULE versionSpecification) 1813 * ;) 1814 */ 1815 Declaration parseDeclaration(bool strict = false, bool mustBeDeclaration = false) 1816 { 1817 mixin(traceEnterAndExit!(__FUNCTION__)); 1818 auto node = allocator.make!Declaration; 1819 if (!moreTokens) 1820 { 1821 error("declaration expected instead of EOF"); 1822 return null; 1823 } 1824 if (current.comment !is null) 1825 comment = current.comment; 1826 size_t autoStorageClassStart = size_t.max; 1827 DecType isAuto; 1828 StackBuffer attributes; 1829 do 1830 { 1831 isAuto = isAutoDeclaration(autoStorageClassStart); 1832 if (isAuto != DecType.other && index == autoStorageClassStart) 1833 break; 1834 if (!isAttribute()) 1835 break; 1836 immutable c = allocator.setCheckpoint(); 1837 auto attr = parseAttribute(); 1838 if (attr is null) 1839 { 1840 allocator.rollback(c); 1841 break; 1842 } 1843 if (currentIs(tok!":")) 1844 { 1845 node.attributeDeclaration = parseAttributeDeclaration(attr); 1846 mixin(nullCheck!`node.attributeDeclaration`); 1847 ownArray(node.attributes, attributes); 1848 return node; 1849 } 1850 else 1851 attributes.put(attr); 1852 } while (moreTokens()); 1853 ownArray(node.attributes, attributes); 1854 1855 if (!moreTokens) 1856 { 1857 error("declaration expected instead of EOF"); 1858 return null; 1859 } 1860 1861 if (isAuto == DecType.autoVar) 1862 { 1863 mixin(nullCheck!`node.variableDeclaration = parseVariableDeclaration(null, true)`); 1864 return node; 1865 } 1866 else if (isAuto == DecType.autoFun) 1867 { 1868 mixin(nullCheck!`node.functionDeclaration = parseFunctionDeclaration(null, true)`); 1869 return node; 1870 } 1871 1872 switch (current.type) 1873 { 1874 case tok!"asm": 1875 case tok!"break": 1876 case tok!"case": 1877 case tok!"continue": 1878 case tok!"default": 1879 case tok!"do": 1880 case tok!"for": 1881 case tok!"foreach": 1882 case tok!"foreach_reverse": 1883 case tok!"goto": 1884 case tok!"if": 1885 case tok!"return": 1886 case tok!"switch": 1887 case tok!"throw": 1888 case tok!"try": 1889 case tok!"while": 1890 case tok!"assert": 1891 goto default; 1892 case tok!";": 1893 // http://d.puremagic.com/issues/show_bug.cgi?id=4559 1894 warn("Empty declaration"); 1895 advance(); 1896 break; 1897 case tok!"{": 1898 if (node.attributes.empty) 1899 { 1900 error("declaration expected instead of '{'"); 1901 return null; 1902 } 1903 advance(); 1904 StackBuffer declarations; 1905 while (moreTokens() && !currentIs(tok!"}")) 1906 { 1907 auto c = allocator.setCheckpoint(); 1908 if (!declarations.put(parseDeclaration(strict))) 1909 { 1910 allocator.rollback(c); 1911 return null; 1912 } 1913 } 1914 ownArray(node.declarations, declarations); 1915 mixin(tokenCheck!"}"); 1916 break; 1917 case tok!"alias": 1918 if (startsWith(tok!"alias", tok!"identifier", tok!"this")) 1919 mixin(parseNodeQ!(`node.aliasThisDeclaration`, `AliasThisDeclaration`)); 1920 else 1921 mixin(parseNodeQ!(`node.aliasDeclaration`, `AliasDeclaration`)); 1922 break; 1923 case tok!"class": 1924 mixin(parseNodeQ!(`node.classDeclaration`, `ClassDeclaration`)); 1925 break; 1926 case tok!"this": 1927 if (!mustBeDeclaration && peekIs(tok!"(")) 1928 { 1929 // Do not parse as a declaration if we could parse as a function call. 1930 ++index; 1931 const past = peekPastParens(); 1932 --index; 1933 if (past !is null && past.type == tok!";") 1934 return null; 1935 } 1936 if (startsWith(tok!"this", tok!"(", tok!"this", tok!")")) 1937 mixin(parseNodeQ!(`node.postblit`, `Postblit`)); 1938 else 1939 mixin(parseNodeQ!(`node.constructor`, `Constructor`)); 1940 break; 1941 case tok!"~": 1942 mixin(parseNodeQ!(`node.destructor`, `Destructor`)); 1943 break; 1944 case tok!"enum": 1945 immutable b = setBookmark(); 1946 advance(); // enum 1947 if (currentIsOneOf(tok!":", tok!"{")) 1948 { 1949 goToBookmark(b); 1950 mixin(parseNodeQ!(`node.anonymousEnumDeclaration`, `AnonymousEnumDeclaration`)); 1951 } 1952 else if (currentIs(tok!"identifier")) 1953 { 1954 advance(); 1955 if (currentIs(tok!"(")) 1956 { 1957 skipParens(); // () 1958 if (currentIs(tok!"(")) 1959 skipParens(); 1960 if (!currentIs(tok!"=")) 1961 { 1962 goToBookmark(b); 1963 node.functionDeclaration = parseFunctionDeclaration(null, true, node.attributes); 1964 mixin (nullCheck!`node.functionDeclaration`); 1965 } 1966 else 1967 { 1968 goToBookmark(b); 1969 mixin(parseNodeQ!(`node.eponymousTemplateDeclaration`, `EponymousTemplateDeclaration`)); 1970 } 1971 } 1972 else if (currentIsOneOf(tok!":", tok!"{", tok!";")) 1973 { 1974 goToBookmark(b); 1975 mixin(parseNodeQ!(`node.enumDeclaration`, `EnumDeclaration`)); 1976 } 1977 else 1978 { 1979 immutable bool eq = currentIs(tok!"="); 1980 goToBookmark(b); 1981 mixin (nullCheck!`node.variableDeclaration = parseVariableDeclaration(null, eq)`); 1982 } 1983 } 1984 else 1985 { 1986 immutable bool s = isStorageClass(); 1987 goToBookmark(b); 1988 mixin (nullCheck!`node.variableDeclaration = parseVariableDeclaration(null, s)`); 1989 } 1990 break; 1991 case tok!"import": 1992 mixin(parseNodeQ!(`node.importDeclaration`, `ImportDeclaration`)); 1993 break; 1994 case tok!"interface": 1995 mixin(parseNodeQ!(`node.interfaceDeclaration`, `InterfaceDeclaration`)); 1996 break; 1997 case tok!"mixin": 1998 if (peekIs(tok!"template")) 1999 mixin(parseNodeQ!(`node.mixinTemplateDeclaration`, `MixinTemplateDeclaration`)); 2000 else 2001 { 2002 immutable b = setBookmark(); 2003 advance(); 2004 if (currentIs(tok!"(")) 2005 { 2006 const t = peekPastParens(); 2007 if (t !is null && t.type == tok!";") 2008 { 2009 goToBookmark(b); 2010 mixin(parseNodeQ!(`node.mixinDeclaration`, `MixinDeclaration`)); 2011 } 2012 else 2013 { 2014 goToBookmark(b); 2015 error("Declaration expected"); 2016 return null; 2017 } 2018 } 2019 else 2020 { 2021 goToBookmark(b); 2022 mixin(parseNodeQ!(`node.mixinDeclaration`, `MixinDeclaration`)); 2023 } 2024 } 2025 break; 2026 case tok!"pragma": 2027 mixin(parseNodeQ!(`node.pragmaDeclaration`, `PragmaDeclaration`)); 2028 break; 2029 case tok!"shared": 2030 if (startsWith(tok!"shared", tok!"static", tok!"this")) 2031 mixin(parseNodeQ!(`node.sharedStaticConstructor`, `SharedStaticConstructor`)); 2032 else if (startsWith(tok!"shared", tok!"static", tok!"~")) 2033 mixin(parseNodeQ!(`node.sharedStaticDestructor`, `SharedStaticDestructor`)); 2034 else 2035 goto type; 2036 break; 2037 case tok!"static": 2038 if (peekIs(tok!"this")) 2039 mixin(parseNodeQ!(`node.staticConstructor`, `StaticConstructor`)); 2040 else if (peekIs(tok!"~")) 2041 mixin(parseNodeQ!(`node.staticDestructor`, `StaticDestructor`)); 2042 else if (peekIs(tok!"if")) 2043 mixin (nullCheck!`node.conditionalDeclaration = parseConditionalDeclaration(strict)`); 2044 else if (peekIs(tok!"assert")) 2045 mixin(parseNodeQ!(`node.staticAssertDeclaration`, `StaticAssertDeclaration`)); 2046 else 2047 goto type; 2048 break; 2049 case tok!"struct": 2050 mixin(parseNodeQ!(`node.structDeclaration`, `StructDeclaration`)); 2051 break; 2052 case tok!"template": 2053 mixin(parseNodeQ!(`node.templateDeclaration`, `TemplateDeclaration`)); 2054 break; 2055 case tok!"union": 2056 mixin(parseNodeQ!(`node.unionDeclaration`, `UnionDeclaration`)); 2057 break; 2058 case tok!"invariant": 2059 mixin(parseNodeQ!(`node.invariant_`, `Invariant`)); 2060 break; 2061 case tok!"unittest": 2062 mixin(parseNodeQ!(`node.unittest_`, `Unittest`)); 2063 break; 2064 case tok!"identifier": 2065 case tok!".": 2066 case tok!"const": 2067 case tok!"immutable": 2068 case tok!"inout": 2069 case tok!"scope": 2070 case tok!"typeof": 2071 case tok!"__vector": 2072 foreach (B; BasicTypes) { case B: } 2073 type: 2074 Type t = parseType(); 2075 if (t is null || !currentIs(tok!"identifier")) 2076 return null; 2077 if (peekIs(tok!"(")) 2078 mixin (nullCheck!`node.functionDeclaration = parseFunctionDeclaration(t, false)`); 2079 else 2080 mixin (nullCheck!`node.variableDeclaration = parseVariableDeclaration(t, false)`); 2081 break; 2082 case tok!"version": 2083 if (peekIs(tok!"(")) 2084 mixin (nullCheck!`node.conditionalDeclaration = parseConditionalDeclaration(strict)`); 2085 else if (peekIs(tok!"=")) 2086 mixin(parseNodeQ!(`node.versionSpecification`, `VersionSpecification`)); 2087 else 2088 { 2089 error(`"=" or "(" expected following "version"`); 2090 return null; 2091 } 2092 break; 2093 case tok!"debug": 2094 if (peekIs(tok!"=")) 2095 mixin(parseNodeQ!(`node.debugSpecification`, `DebugSpecification`)); 2096 else 2097 mixin (nullCheck!`node.conditionalDeclaration = parseConditionalDeclaration(strict)`); 2098 break; 2099 default: 2100 error("Declaration expected"); 2101 return null; 2102 } 2103 return node; 2104 } 2105 2106 /** 2107 * Parses DeclarationsAndStatements 2108 * 2109 * $(GRAMMAR $(RULEDEF declarationsAndStatements): 2110 * $(RULE declarationOrStatement)+ 2111 * ;) 2112 */ 2113 DeclarationsAndStatements parseDeclarationsAndStatements(bool includeCases = true) 2114 { 2115 mixin(traceEnterAndExit!(__FUNCTION__)); 2116 auto node = allocator.make!DeclarationsAndStatements; 2117 StackBuffer declarationsAndStatements; 2118 while (!currentIsOneOf(tok!"}", tok!"else") && moreTokens() && suppressedErrorCount <= MAX_ERRORS) 2119 { 2120 if (currentIs(tok!"case") && !includeCases) 2121 break; 2122 if (currentIs(tok!"while")) 2123 { 2124 immutable b = setBookmark(); 2125 scope (exit) goToBookmark(b); 2126 advance(); 2127 if (currentIs(tok!"(")) 2128 { 2129 const p = peekPastParens(); 2130 if (p !is null && *p == tok!";") 2131 break; 2132 } 2133 } 2134 immutable c = allocator.setCheckpoint(); 2135 if (!declarationsAndStatements.put(parseDeclarationOrStatement())) 2136 { 2137 allocator.rollback(c); 2138 if (suppressMessages > 0) 2139 return null; 2140 } 2141 } 2142 ownArray(node.declarationsAndStatements, declarationsAndStatements); 2143 return node; 2144 } 2145 2146 /** 2147 * Parses a DeclarationOrStatement 2148 * 2149 * $(GRAMMAR $(RULEDEF declarationOrStatement): 2150 * $(RULE declaration) 2151 * | $(RULE statement) 2152 * ;) 2153 */ 2154 DeclarationOrStatement parseDeclarationOrStatement() 2155 { 2156 mixin(traceEnterAndExit!(__FUNCTION__)); 2157 auto node = allocator.make!DeclarationOrStatement; 2158 // "Any ambiguities in the grammar between Statements and 2159 // Declarations are resolved by the declarations taking precedence." 2160 immutable b = setBookmark(); 2161 immutable c = allocator.setCheckpoint(); 2162 auto d = parseDeclaration(true, false); 2163 if (d is null) 2164 { 2165 allocator.rollback(c); 2166 goToBookmark(b); 2167 mixin(parseNodeQ!(`node.statement`, `Statement`)); 2168 } 2169 else 2170 { 2171 // TODO: Make this more efficient. Right now we parse the declaration 2172 // twice, once with errors and warnings ignored, and once with them 2173 // printed. Maybe store messages to then be abandoned or written later? 2174 allocator.rollback(c); 2175 goToBookmark(b); 2176 node.declaration = parseDeclaration(true, true); 2177 } 2178 return node; 2179 } 2180 2181 /** 2182 * Parses a Declarator 2183 * 2184 * $(GRAMMAR $(RULEDEF declarator): 2185 * $(LITERAL Identifier) 2186 * | $(LITERAL Identifier) $(LITERAL '=') $(RULE initializer) 2187 * | $(LITERAL Identifier) $(RULE templateParameters) $(LITERAL '=') $(RULE initializer) 2188 * ;) 2189 */ 2190 Declarator parseDeclarator() 2191 { 2192 mixin(traceEnterAndExit!(__FUNCTION__)); 2193 auto node = allocator.make!Declarator; 2194 const id = expect(tok!"identifier"); 2195 mixin (nullCheck!`id`); 2196 node.name = *id; 2197 if (currentIs(tok!"[")) // dmd doesn't accept pointer after identifier 2198 { 2199 warn("C-style array declaration."); 2200 StackBuffer typeSuffixes; 2201 while (moreTokens() && currentIs(tok!"[")) 2202 if (!typeSuffixes.put(parseTypeSuffix())) 2203 return null; 2204 ownArray(node.cstyle, typeSuffixes); 2205 } 2206 if (currentIs(tok!"(")) 2207 { 2208 mixin (nullCheck!`(node.templateParameters = parseTemplateParameters())`); 2209 mixin(tokenCheck!"="); 2210 mixin (nullCheck!`(node.initializer = parseInitializer())`); 2211 } 2212 else if (currentIs(tok!"=")) 2213 { 2214 advance(); 2215 mixin(parseNodeQ!(`node.initializer`, `Initializer`)); 2216 } 2217 return node; 2218 } 2219 2220 /** 2221 * Parses a DefaultStatement 2222 * 2223 * $(GRAMMAR $(RULEDEF defaultStatement): 2224 * $(LITERAL 'default') $(LITERAL ':') $(RULE declarationsAndStatements) 2225 * ;) 2226 */ 2227 DefaultStatement parseDefaultStatement() 2228 { 2229 mixin(traceEnterAndExit!(__FUNCTION__)); 2230 auto node = allocator.make!DefaultStatement; 2231 mixin(tokenCheck!"default"); 2232 const colon = expect(tok!":"); 2233 if (colon is null) 2234 return null; 2235 node.colonLocation = colon.index; 2236 mixin(parseNodeQ!(`node.declarationsAndStatements`, `DeclarationsAndStatements`)); 2237 return node; 2238 } 2239 2240 /** 2241 * Parses a DeleteExpression 2242 * 2243 * $(GRAMMAR $(RULEDEF deleteExpression): 2244 * $(LITERAL 'delete') $(RULE unaryExpression) 2245 * ;) 2246 */ 2247 DeleteExpression parseDeleteExpression() 2248 { 2249 mixin(traceEnterAndExit!(__FUNCTION__)); 2250 auto node = allocator.make!DeleteExpression; 2251 node.line = current.line; 2252 node.column = current.column; 2253 mixin(tokenCheck!"delete"); 2254 mixin(parseNodeQ!(`node.unaryExpression`, `UnaryExpression`)); 2255 return node; 2256 } 2257 2258 /** 2259 * Parses a Deprecated attribute 2260 * 2261 * $(GRAMMAR $(RULEDEF deprecated): 2262 * $(LITERAL 'deprecated') ($(LITERAL '$(LPAREN)') $(LITERAL StringLiteral)+ $(LITERAL '$(RPAREN)'))? 2263 * ;) 2264 */ 2265 Deprecated parseDeprecated() 2266 { 2267 mixin(traceEnterAndExit!(__FUNCTION__)); 2268 auto node = allocator.make!Deprecated; 2269 mixin(tokenCheck!"deprecated"); 2270 if (currentIs(tok!"(")) 2271 { 2272 advance(); 2273 mixin (parseNodeQ!(`node.assignExpression`, `AssignExpression`)); 2274 mixin (tokenCheck!")"); 2275 } 2276 return node; 2277 } 2278 2279 /** 2280 * Parses a Destructor 2281 * 2282 * $(GRAMMAR $(RULEDEF destructor): 2283 * $(LITERAL '~') $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)') $(RULE memberFunctionAttribute)* ($(RULE functionBody) | $(LITERAL ';')) 2284 * ;) 2285 */ 2286 Destructor parseDestructor() 2287 { 2288 mixin(traceEnterAndExit!(__FUNCTION__)); 2289 auto node = allocator.make!Destructor; 2290 node.comment = comment; 2291 comment = null; 2292 mixin(tokenCheck!"~"); 2293 if (!moreTokens) 2294 { 2295 error("'this' expected"); 2296 return null; 2297 } 2298 node.index = current.index; 2299 node.line = current.line; 2300 node.column = current.column; 2301 mixin(tokenCheck!"this"); 2302 mixin(tokenCheck!"("); 2303 mixin(tokenCheck!")"); 2304 if (currentIs(tok!";")) 2305 advance(); 2306 else 2307 { 2308 StackBuffer memberFunctionAttributes; 2309 while (moreTokens() && currentIsMemberFunctionAttribute()) 2310 if (!memberFunctionAttributes.put(parseMemberFunctionAttribute())) 2311 return null; 2312 ownArray(node.memberFunctionAttributes, memberFunctionAttributes); 2313 mixin(parseNodeQ!(`node.functionBody`, `FunctionBody`)); 2314 } 2315 return node; 2316 } 2317 2318 /** 2319 * Parses a DoStatement 2320 * 2321 * $(GRAMMAR $(RULEDEF doStatement): 2322 * $(LITERAL 'do') $(RULE statementNoCaseNoDefault) $(LITERAL 'while') $(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)') $(LITERAL ';') 2323 * ;) 2324 */ 2325 DoStatement parseDoStatement() 2326 { 2327 mixin(traceEnterAndExit!(__FUNCTION__)); 2328 auto node = allocator.make!DoStatement; 2329 mixin(tokenCheck!"do"); 2330 mixin(parseNodeQ!(`node.statementNoCaseNoDefault`, `StatementNoCaseNoDefault`)); 2331 mixin(tokenCheck!"while"); 2332 mixin(tokenCheck!"("); 2333 mixin(parseNodeQ!(`node.expression`, `Expression`)); 2334 mixin(tokenCheck!")"); 2335 mixin(tokenCheck!";"); 2336 return node; 2337 } 2338 2339 /** 2340 * Parses an EnumBody 2341 * 2342 * $(GRAMMAR $(RULEDEF enumBody): 2343 * $(LITERAL '{') $(RULE enumMember) ($(LITERAL ',') $(RULE enumMember)?)* $(LITERAL '}') 2344 * ;) 2345 */ 2346 EnumBody parseEnumBody() 2347 { 2348 mixin(traceEnterAndExit!(__FUNCTION__)); 2349 EnumBody node = allocator.make!EnumBody; 2350 const open = expect(tok!"{"); 2351 mixin (nullCheck!`open`); 2352 node.startLocation = open.index; 2353 StackBuffer enumMembers; 2354 EnumMember last; 2355 while (moreTokens()) 2356 { 2357 if (currentIs(tok!",")) 2358 { 2359 if (last !is null && last.comment is null) 2360 last.comment = current.trailingComment; 2361 advance(); 2362 continue; 2363 } 2364 else if (currentIs(tok!"}")) 2365 { 2366 if (last !is null && last.comment is null) 2367 last.comment = tokens[index - 1].trailingComment; 2368 break; 2369 } 2370 else 2371 { 2372 auto c = allocator.setCheckpoint(); 2373 auto e = parseEnumMember(); 2374 if (!enumMembers.put(e)) 2375 allocator.rollback(c); 2376 else 2377 last = e; 2378 } 2379 } 2380 ownArray(node.enumMembers, enumMembers); 2381 const close = expect (tok!"}"); 2382 if (close !is null) 2383 node.endLocation = close.index; 2384 return node; 2385 } 2386 2387 /** 2388 * $(GRAMMAR $(RULEDEF anonymousEnumMember): 2389 * $(RULE type) $(LITERAL identifier) $(LITERAL '=') $(RULE assignExpression) 2390 * | $(LITERAL identifier) $(LITERAL '=') $(RULE assignExpression) 2391 * | $(LITERAL identifier) 2392 * ;) 2393 */ 2394 AnonymousEnumMember parseAnonymousEnumMember(bool typeAllowed) 2395 { 2396 mixin(traceEnterAndExit!(__FUNCTION__)); 2397 auto node = allocator.make!AnonymousEnumMember; 2398 2399 if (currentIs(tok!"identifier") && peekIsOneOf(tok!",", tok!"=", tok!"}")) 2400 { 2401 node.comment = current.comment; 2402 mixin (tokenCheck!(`node.name`, `identifier`)); 2403 if (currentIs(tok!"=")) 2404 { 2405 advance(); // = 2406 goto assign; 2407 } 2408 } 2409 else if (typeAllowed) 2410 { 2411 node.comment = current.comment; 2412 mixin(parseNodeQ!(`node.type`, `Type`)); 2413 mixin (tokenCheck!(`node.name`, `identifier`)); 2414 mixin(tokenCheck!"="); 2415 assign: 2416 mixin(parseNodeQ!(`node.assignExpression`, `AssignExpression`)); 2417 } 2418 else 2419 { 2420 error("Cannot specify anonymous enum member type if anonymous enum has a base type."); 2421 return null; 2422 } 2423 return node; 2424 } 2425 2426 /** 2427 * $(GRAMMAR $(RULEDEF anonymousEnumDeclaration): 2428 * $(LITERAL 'enum') ($(LITERAL ':') $(RULE type))? $(LITERAL '{') $(RULE anonymousEnumMember)+ $(LITERAL '}') 2429 * ;) 2430 */ 2431 AnonymousEnumDeclaration parseAnonymousEnumDeclaration() 2432 { 2433 mixin(traceEnterAndExit!(__FUNCTION__)); 2434 auto node = allocator.make!AnonymousEnumDeclaration; 2435 mixin(tokenCheck!"enum"); 2436 immutable bool hasBaseType = currentIs(tok!":"); 2437 if (hasBaseType) 2438 { 2439 advance(); 2440 mixin(parseNodeQ!(`node.baseType`, `Type`)); 2441 } 2442 mixin(tokenCheck!"{"); 2443 StackBuffer members; 2444 AnonymousEnumMember last; 2445 while (moreTokens()) 2446 { 2447 if (currentIs(tok!",")) 2448 { 2449 if (last !is null && last.comment is null) 2450 last.comment = current.trailingComment; 2451 advance(); 2452 continue; 2453 } 2454 else if (currentIs(tok!"}")) 2455 { 2456 if (last !is null && last.comment is null) 2457 last.comment = tokens[index - 1].trailingComment; 2458 break; 2459 } 2460 else 2461 { 2462 immutable c = allocator.setCheckpoint(); 2463 auto e = parseAnonymousEnumMember(!hasBaseType); 2464 if (!members.put(e)) 2465 allocator.rollback(c); 2466 else 2467 last = e; 2468 } 2469 } 2470 ownArray(node.members, members); 2471 mixin(tokenCheck!"}"); 2472 return node; 2473 } 2474 2475 /** 2476 * Parses an EnumDeclaration 2477 * 2478 * $(GRAMMAR $(RULEDEF enumDeclaration): 2479 * $(LITERAL 'enum') $(LITERAL Identifier) ($(LITERAL ':') $(RULE type))? $(LITERAL ';') 2480 * | $(LITERAL 'enum') $(LITERAL Identifier) ($(LITERAL ':') $(RULE type))? $(RULE enumBody) 2481 * ;) 2482 */ 2483 EnumDeclaration parseEnumDeclaration() 2484 { 2485 mixin(traceEnterAndExit!(__FUNCTION__)); 2486 auto node = allocator.make!EnumDeclaration; 2487 mixin(tokenCheck!"enum"); 2488 mixin (tokenCheck!(`node.name`, `identifier`)); 2489 node.comment = comment; 2490 comment = null; 2491 if (currentIs(tok!";")) 2492 { 2493 advance(); 2494 return node; 2495 } 2496 if (currentIs(tok!":")) 2497 { 2498 advance(); // skip ':' 2499 mixin(parseNodeQ!(`node.type`, `Type`)); 2500 } 2501 mixin(parseNodeQ!(`node.enumBody`, `EnumBody`)); 2502 return node; 2503 } 2504 2505 /** 2506 * Parses an EnumMember 2507 * 2508 * $(GRAMMAR $(RULEDEF enumMember): 2509 * $(LITERAL Identifier) 2510 * | $(LITERAL Identifier) $(LITERAL '=') $(RULE assignExpression) 2511 * ;) 2512 */ 2513 EnumMember parseEnumMember() 2514 { 2515 mixin(traceEnterAndExit!(__FUNCTION__)); 2516 auto node = allocator.make!EnumMember; 2517 node.comment = current.comment; 2518 mixin (tokenCheck!(`node.name`, `identifier`)); 2519 if (currentIs(tok!"=")) 2520 { 2521 advance(); 2522 mixin(parseNodeQ!(`node.assignExpression`, `AssignExpression`)); 2523 } 2524 return node; 2525 } 2526 2527 /** 2528 * Parses an EponymousTemplateDeclaration 2529 * 2530 * $(GRAMMAR $(RULEDEF eponymousTemplateDeclaration): 2531 * $(LITERAL 'enum') $(LITERAL Identifier) $(RULE templateParameters) $(LITERAL '=') $(RULE assignExpression) $(LITERAL ';') 2532 * ;) 2533 */ 2534 EponymousTemplateDeclaration parseEponymousTemplateDeclaration() 2535 { 2536 mixin(traceEnterAndExit!(__FUNCTION__)); 2537 auto node = allocator.make!EponymousTemplateDeclaration; 2538 advance(); // enum 2539 const ident = expect(tok!"identifier"); 2540 mixin (nullCheck!`ident`); 2541 node.name = *ident; 2542 mixin(parseNodeQ!(`node.templateParameters`, `TemplateParameters`)); 2543 expect(tok!"="); 2544 node.assignExpression = parseAssignExpression(); 2545 if (node.assignExpression is null) 2546 mixin(parseNodeQ!(`node.type`, `Type`)); 2547 expect(tok!";"); 2548 return node; 2549 } 2550 2551 /** 2552 * Parses an EqualExpression 2553 * 2554 * $(GRAMMAR $(RULEDEF equalExpression): 2555 * $(RULE shiftExpression) ($(LITERAL '==') | $(LITERAL '!=')) $(RULE shiftExpression) 2556 * ;) 2557 */ 2558 EqualExpression parseEqualExpression(ExpressionNode shift = null) 2559 { 2560 mixin(traceEnterAndExit!(__FUNCTION__)); 2561 auto node = allocator.make!EqualExpression; 2562 node.left = shift is null ? parseShiftExpression() : shift; 2563 mixin (nullCheck!`node.left`); 2564 if (currentIsOneOf(tok!"==", tok!"!=")) 2565 node.operator = advance().type; 2566 mixin(parseNodeQ!(`node.right`, `ShiftExpression`)); 2567 return node; 2568 } 2569 2570 /** 2571 * Parses an Expression 2572 * 2573 * $(GRAMMAR $(RULEDEF expression): 2574 * $(RULE assignExpression) ($(LITERAL ',') $(RULE assignExpression))* 2575 * ;) 2576 */ 2577 Expression parseExpression() 2578 { 2579 mixin(traceEnterAndExit!(__FUNCTION__)); 2580 if (suppressedErrorCount > MAX_ERRORS) 2581 return null; 2582 if (!moreTokens()) 2583 { 2584 error("Expected expression instead of EOF"); 2585 return null; 2586 } 2587 return parseCommaSeparatedRule!(Expression, AssignExpression, true)(); 2588 } 2589 2590 /** 2591 * Parses an ExpressionStatement 2592 * 2593 * $(GRAMMAR $(RULEDEF expressionStatement): 2594 * $(RULE expression) $(LITERAL ';') 2595 * ;) 2596 */ 2597 ExpressionStatement parseExpressionStatement(Expression expression = null) 2598 { 2599 mixin(traceEnterAndExit!(__FUNCTION__)); 2600 auto node = allocator.make!ExpressionStatement; 2601 node.expression = expression is null ? parseExpression() : expression; 2602 if (node.expression is null || expect(tok!";") is null) 2603 return null; 2604 return node; 2605 } 2606 2607 /** 2608 * Parses a FinalSwitchStatement 2609 * 2610 * $(GRAMMAR $(RULEDEF finalSwitchStatement): 2611 * $(LITERAL 'final') $(RULE switchStatement) 2612 * ;) 2613 */ 2614 FinalSwitchStatement parseFinalSwitchStatement() 2615 { 2616 mixin(traceEnterAndExit!(__FUNCTION__)); 2617 mixin (simpleParse!(FinalSwitchStatement, tok!"final", "switchStatement|parseSwitchStatement")); 2618 } 2619 2620 /** 2621 * Parses a Finally 2622 * 2623 * $(GRAMMAR $(RULEDEF finally): 2624 * $(LITERAL 'finally') $(RULE declarationOrStatement) 2625 * ;) 2626 */ 2627 Finally parseFinally() 2628 { 2629 mixin(traceEnterAndExit!(__FUNCTION__)); 2630 auto node = allocator.make!Finally; 2631 mixin(tokenCheck!"finally"); 2632 mixin(parseNodeQ!(`node.declarationOrStatement`, `DeclarationOrStatement`)); 2633 return node; 2634 } 2635 2636 /** 2637 * Parses a ForStatement 2638 * 2639 * $(GRAMMAR $(RULEDEF forStatement): 2640 * $(LITERAL 'for') $(LITERAL '$(LPAREN)') ($(RULE declaration) | $(RULE statementNoCaseNoDefault)) $(RULE expression)? $(LITERAL ';') $(RULE expression)? $(LITERAL '$(RPAREN)') $(RULE declarationOrStatement) 2641 * ;) 2642 */ 2643 ForStatement parseForStatement() 2644 { 2645 mixin(traceEnterAndExit!(__FUNCTION__)); 2646 auto node = allocator.make!ForStatement; 2647 mixin(tokenCheck!"for"); 2648 if (!moreTokens) node.startIndex = current().index; 2649 mixin(tokenCheck!"("); 2650 2651 if (currentIs(tok!";")) 2652 advance(); 2653 else 2654 mixin(parseNodeQ!(`node.initialization`, `DeclarationOrStatement`)); 2655 2656 if (currentIs(tok!";")) 2657 advance(); 2658 else 2659 { 2660 mixin(parseNodeQ!(`node.test`, `Expression`)); 2661 expect(tok!";"); 2662 } 2663 2664 if (!currentIs(tok!")")) 2665 mixin(parseNodeQ!(`node.increment`, `Expression`)); 2666 2667 mixin(tokenCheck!")"); 2668 2669 // Intentionally return an incomplete parse tree so that DCD will work 2670 // more correctly. 2671 if (currentIs(tok!"}")) 2672 { 2673 error("Statement expected", false); 2674 return node; 2675 } 2676 2677 mixin(parseNodeQ!(`node.declarationOrStatement`, `DeclarationOrStatement`)); 2678 return node; 2679 } 2680 2681 /** 2682 * Parses a ForeachStatement 2683 * 2684 * $(GRAMMAR $(RULEDEF foreachStatement): 2685 * ($(LITERAL 'foreach') | $(LITERAL 'foreach_reverse')) $(LITERAL '$(LPAREN)') $(RULE foreachTypeList) $(LITERAL ';') $(RULE expression) $(LITERAL '$(RPAREN)') $(RULE declarationOrStatement) 2686 * | ($(LITERAL 'foreach') | $(LITERAL 'foreach_reverse')) $(LITERAL '$(LPAREN)') $(RULE foreachType) $(LITERAL ';') $(RULE expression) $(LITERAL '..') $(RULE expression) $(LITERAL '$(RPAREN)') $(RULE declarationOrStatement) 2687 * ;) 2688 */ 2689 ForeachStatement parseForeachStatement() 2690 { 2691 mixin(traceEnterAndExit!(__FUNCTION__)); 2692 ForeachStatement node = allocator.make!ForeachStatement; 2693 if (currentIsOneOf(tok!"foreach", tok!"foreach_reverse")) 2694 node.type = advance().type; 2695 else 2696 { 2697 error(`"foreach" or "foreach_reverse" expected`); 2698 return null; 2699 } 2700 node.startIndex = current().index; 2701 mixin(tokenCheck!"("); 2702 ForeachTypeList feType = parseForeachTypeList(); 2703 mixin (nullCheck!`feType`); 2704 immutable bool canBeRange = feType.items.length == 1; 2705 2706 mixin(tokenCheck!";"); 2707 mixin(parseNodeQ!(`node.low`, `Expression`)); 2708 mixin (nullCheck!`node.low`); 2709 if (currentIs(tok!"..")) 2710 { 2711 if (!canBeRange) 2712 { 2713 error(`Cannot have more than one foreach variable for a foreach range statement`); 2714 return null; 2715 } 2716 advance(); 2717 mixin(parseNodeQ!(`node.high`, `Expression`)); 2718 node.foreachType = feType.items[0]; 2719 mixin (nullCheck!`node.high`); 2720 } 2721 else 2722 { 2723 node.foreachTypeList = feType; 2724 } 2725 mixin(tokenCheck!")"); 2726 if (currentIs(tok!"}")) 2727 { 2728 error("Statement expected", false); 2729 return node; // this line makes DCD better 2730 } 2731 mixin(parseNodeQ!(`node.declarationOrStatement`, `DeclarationOrStatement`)); 2732 return node; 2733 } 2734 2735 /** 2736 * Parses a ForeachType 2737 * 2738 * $(GRAMMAR $(RULEDEF foreachType): 2739 * $(LITERAL 'ref')? $(RULE typeConstructors)? $(RULE type)? $(LITERAL Identifier) 2740 * | $(RULE typeConstructors)? $(LITERAL 'ref')? $(RULE type)? $(LITERAL Identifier) 2741 * ;) 2742 */ 2743 ForeachType parseForeachType() 2744 { 2745 mixin(traceEnterAndExit!(__FUNCTION__)); 2746 auto node = allocator.make!ForeachType; 2747 if (currentIs(tok!"ref")) 2748 { 2749 node.isRef = true; 2750 advance(); 2751 } 2752 if (currentIsOneOf(tok!"const", tok!"immutable", 2753 tok!"inout", tok!"shared") && !peekIs(tok!"(")) 2754 { 2755 trace("\033[01;36mType constructor"); 2756 mixin(parseNodeQ!(`node.typeConstructors`, `TypeConstructors`)); 2757 } 2758 if (currentIs(tok!"ref")) 2759 { 2760 node.isRef = true; 2761 advance(); 2762 } 2763 if (currentIs(tok!"identifier") && peekIsOneOf(tok!",", tok!";")) 2764 { 2765 node.identifier = advance(); 2766 return node; 2767 } 2768 mixin(parseNodeQ!(`node.type`, `Type`)); 2769 const ident = expect(tok!"identifier"); 2770 mixin(nullCheck!`ident`); 2771 node.identifier = *ident; 2772 return node; 2773 } 2774 2775 /** 2776 * Parses a ForeachTypeList 2777 * 2778 * $(GRAMMAR $(RULEDEF foreachTypeList): 2779 * $(RULE foreachType) ($(LITERAL ',') $(RULE foreachType))* 2780 * ;) 2781 */ 2782 ForeachTypeList parseForeachTypeList() 2783 { 2784 mixin(traceEnterAndExit!(__FUNCTION__)); 2785 return parseCommaSeparatedRule!(ForeachTypeList, ForeachType)(); 2786 } 2787 2788 /** 2789 * Parses a FunctionAttribute 2790 * 2791 * $(GRAMMAR $(RULEDEF functionAttribute): 2792 * $(RULE atAttribute) 2793 * | $(LITERAL 'pure') 2794 * | $(LITERAL 'nothrow') 2795 * ;) 2796 */ 2797 FunctionAttribute parseFunctionAttribute(bool validate = true) 2798 { 2799 auto node = allocator.make!FunctionAttribute; 2800 switch (current.type) 2801 { 2802 case tok!"@": 2803 mixin(parseNodeQ!(`node.atAttribute`, `AtAttribute`)); 2804 break; 2805 case tok!"pure": 2806 case tok!"nothrow": 2807 node.token = advance(); 2808 break; 2809 default: 2810 if (validate) 2811 error(`@attribute, "pure", or "nothrow" expected`); 2812 return null; 2813 } 2814 return node; 2815 } 2816 2817 /** 2818 * Parses a FunctionBody 2819 * 2820 * $(GRAMMAR $(RULEDEF functionBody): 2821 * $(RULE blockStatement) 2822 * | ($(RULE inStatement) | $(RULE outStatement) | $(RULE outStatement) $(RULE inStatement) | $(RULE inStatement) $(RULE outStatement))? $(RULE bodyStatement)? 2823 * ;) 2824 */ 2825 FunctionBody parseFunctionBody() 2826 { 2827 mixin(traceEnterAndExit!(__FUNCTION__)); 2828 auto node = allocator.make!FunctionBody; 2829 if (currentIs(tok!";")) 2830 { 2831 advance(); 2832 return node; 2833 } 2834 else if (currentIs(tok!"{")) 2835 mixin(parseNodeQ!(`node.blockStatement`, `BlockStatement`)); 2836 else if (currentIsOneOf(tok!"in", tok!"out", tok!"body")) 2837 { 2838 if (currentIs(tok!"in")) 2839 { 2840 mixin(parseNodeQ!(`node.inStatement`, `InStatement`)); 2841 if (currentIs(tok!"out")) 2842 mixin(parseNodeQ!(`node.outStatement`, `OutStatement`)); 2843 } 2844 else if (currentIs(tok!"out")) 2845 { 2846 mixin(parseNodeQ!(`node.outStatement`, `OutStatement`)); 2847 if (currentIs(tok!"in")) 2848 mixin(parseNodeQ!(`node.inStatement`, `InStatement`)); 2849 } 2850 // Allow function bodies without body statements because this is 2851 // valid inside of interfaces. 2852 if (currentIs(tok!"body")) 2853 mixin(parseNodeQ!(`node.bodyStatement`, `BodyStatement`)); 2854 } 2855 else 2856 { 2857 error("'in', 'out', 'body', or block statement expected"); 2858 return null; 2859 } 2860 return node; 2861 } 2862 2863 /** 2864 * Parses a FunctionCallExpression 2865 * 2866 * $(GRAMMAR $(RULEDEF functionCallExpression): 2867 * $(RULE symbol) $(RULE arguments) 2868 * $(RULE unaryExpression) $(RULE arguments) 2869 * | $(RULE type) $(RULE arguments) 2870 * ;) 2871 */ 2872 FunctionCallExpression parseFunctionCallExpression(UnaryExpression unary = null) 2873 { 2874 mixin(traceEnterAndExit!(__FUNCTION__)); 2875 auto node = allocator.make!FunctionCallExpression; 2876 switch (current.type) 2877 { 2878 case tok!"const": 2879 case tok!"immutable": 2880 case tok!"inout": 2881 case tok!"shared": 2882 case tok!"scope": 2883 case tok!"pure": 2884 case tok!"nothrow": 2885 mixin(parseNodeQ!(`node.type`, `Type`)); 2886 mixin(parseNodeQ!(`node.arguments`, `Arguments`)); 2887 break; 2888 default: 2889 if (unary !is null) 2890 node.unaryExpression = unary; 2891 else 2892 mixin(parseNodeQ!(`node.unaryExpression`, `UnaryExpression`)); 2893 if (currentIs(tok!"!")) 2894 mixin(parseNodeQ!(`node.templateArguments`, `TemplateArguments`)); 2895 if (unary !is null) 2896 mixin(parseNodeQ!(`node.arguments`, `Arguments`)); 2897 } 2898 return node; 2899 } 2900 2901 /** 2902 * Parses a FunctionDeclaration 2903 * 2904 * $(GRAMMAR $(RULEDEF functionDeclaration): 2905 * ($(RULE storageClass)+ | $(RULE _type)) $(LITERAL Identifier) $(RULE parameters) $(RULE memberFunctionAttribute)* ($(RULE functionBody) | $(LITERAL ';')) 2906 * | ($(RULE storageClass)+ | $(RULE _type)) $(LITERAL Identifier) $(RULE templateParameters) $(RULE parameters) $(RULE memberFunctionAttribute)* $(RULE constraint)? ($(RULE functionBody) | $(LITERAL ';')) 2907 * ;) 2908 */ 2909 FunctionDeclaration parseFunctionDeclaration(Type type = null, bool isAuto = false, 2910 Attribute[] attributes = null) 2911 { 2912 mixin(traceEnterAndExit!(__FUNCTION__)); 2913 auto node = allocator.make!FunctionDeclaration; 2914 node.comment = comment; 2915 comment = null; 2916 StackBuffer memberFunctionAttributes; 2917 node.attributes = attributes; 2918 2919 if (isAuto) 2920 { 2921 StackBuffer storageClasses; 2922 while (isStorageClass()) 2923 if (!storageClasses.put(parseStorageClass())) 2924 return null; 2925 ownArray(node.storageClasses, storageClasses); 2926 2927 foreach (a; node.attributes) 2928 { 2929 if (a.attribute == tok!"auto") 2930 node.hasAuto = true; 2931 else if (a.attribute == tok!"ref") 2932 node.hasRef = true; 2933 else 2934 continue; 2935 } 2936 } 2937 else 2938 { 2939 while (moreTokens() && currentIsMemberFunctionAttribute()) 2940 if (!memberFunctionAttributes.put(parseMemberFunctionAttribute())) 2941 return null; 2942 if (type is null) 2943 mixin(parseNodeQ!(`node.returnType`, `Type`)); 2944 else 2945 node.returnType = type; 2946 } 2947 2948 mixin(tokenCheck!(`node.name`, "identifier")); 2949 if (!currentIs(tok!"(")) 2950 { 2951 error("'(' expected"); 2952 return null; 2953 } 2954 const p = peekPastParens(); 2955 immutable bool isTemplate = p !is null && p.type == tok!"("; 2956 2957 if (isTemplate) 2958 mixin(parseNodeQ!(`node.templateParameters`, `TemplateParameters`)); 2959 2960 mixin(parseNodeQ!(`node.parameters`, `Parameters`)); 2961 2962 while (moreTokens() && currentIsMemberFunctionAttribute()) 2963 if (!memberFunctionAttributes.put(parseMemberFunctionAttribute())) 2964 return null; 2965 2966 if (isTemplate && currentIs(tok!"if")) 2967 mixin(parseNodeQ!(`node.constraint`, `Constraint`)); 2968 2969 if (currentIs(tok!";")) 2970 advance(); 2971 else 2972 mixin(parseNodeQ!(`node.functionBody`, `FunctionBody`)); 2973 ownArray(node.memberFunctionAttributes, memberFunctionAttributes); 2974 return node; 2975 } 2976 2977 /** 2978 * Parses a FunctionLiteralExpression 2979 * 2980 * $(GRAMMAR $(RULEDEF functionLiteralExpression): 2981 * | $(LITERAL 'delegate') $(RULE type)? ($(RULE parameters) $(RULE functionAttribute)*)? $(RULE functionBody) 2982 * | $(LITERAL 'function') $(RULE type)? ($(RULE parameters) $(RULE functionAttribute)*)? $(RULE functionBody) 2983 * | $(RULE parameters) $(RULE functionAttribute)* $(RULE functionBody) 2984 * | $(RULE functionBody) 2985 * | $(LITERAL Identifier) $(LITERAL '=>') $(RULE assignExpression) 2986 * | $(LITERAL 'function') $(RULE type)? $(RULE parameters) $(RULE functionAttribute)* $(LITERAL '=>') $(RULE assignExpression) 2987 * | $(LITERAL 'delegate') $(RULE type)? $(RULE parameters) $(RULE functionAttribute)* $(LITERAL '=>') $(RULE assignExpression) 2988 * | $(RULE parameters) $(RULE functionAttribute)* $(LITERAL '=>') $(RULE assignExpression) 2989 * ;) 2990 */ 2991 FunctionLiteralExpression parseFunctionLiteralExpression() 2992 { 2993 mixin(traceEnterAndExit!(__FUNCTION__)); 2994 auto node = allocator.make!FunctionLiteralExpression; 2995 if (currentIsOneOf(tok!"function", tok!"delegate")) 2996 { 2997 node.functionOrDelegate = advance().type; 2998 if (!currentIsOneOf(tok!"(", tok!"in", tok!"body", 2999 tok!"out", tok!"{", tok!"=>")) 3000 mixin(parseNodeQ!(`node.returnType`, `Type`)); 3001 } 3002 if (startsWith(tok!"identifier", tok!"=>")) 3003 { 3004 node.identifier = advance(); 3005 advance(); // => 3006 mixin(parseNodeQ!(`node.assignExpression`, `AssignExpression`)); 3007 return node; 3008 } 3009 else if (currentIs(tok!"(")) 3010 { 3011 mixin(parseNodeQ!(`node.parameters`, `Parameters`)); 3012 StackBuffer memberFunctionAttributes; 3013 while (currentIsMemberFunctionAttribute()) 3014 { 3015 auto c = allocator.setCheckpoint(); 3016 if (!memberFunctionAttributes.put(parseMemberFunctionAttribute())) 3017 { 3018 allocator.rollback(c); 3019 break; 3020 } 3021 } 3022 ownArray(node.memberFunctionAttributes, memberFunctionAttributes); 3023 } 3024 if (currentIs(tok!"=>")) 3025 { 3026 advance(); 3027 mixin(parseNodeQ!(`node.assignExpression`, `AssignExpression`)); 3028 } 3029 else 3030 mixin(parseNodeQ!(`node.functionBody`, `FunctionBody`)); 3031 return node; 3032 } 3033 3034 /** 3035 * Parses a GotoStatement 3036 * 3037 * $(GRAMMAR $(RULEDEF gotoStatement): 3038 * $(LITERAL 'goto') ($(LITERAL Identifier) | $(LITERAL 'default') | $(LITERAL 'case') $(RULE expression)?) $(LITERAL ';') 3039 * ;) 3040 */ 3041 GotoStatement parseGotoStatement() 3042 { 3043 mixin(traceEnterAndExit!(__FUNCTION__)); 3044 auto node = allocator.make!GotoStatement; 3045 mixin(tokenCheck!"goto"); 3046 switch (current.type) 3047 { 3048 case tok!"identifier": 3049 case tok!"default": 3050 node.label = advance(); 3051 break; 3052 case tok!"case": 3053 node.label = advance(); 3054 if (!currentIs(tok!";")) 3055 mixin(parseNodeQ!(`node.expression`, `Expression`)); 3056 break; 3057 default: 3058 error(`Identifier, "default", or "case" expected`); 3059 return null; 3060 } 3061 mixin(tokenCheck!";"); 3062 return node; 3063 } 3064 3065 /** 3066 * Parses an IdentifierChain 3067 * 3068 * $(GRAMMAR $(RULEDEF identifierChain): 3069 * $(LITERAL Identifier) ($(LITERAL '.') $(LITERAL Identifier))* 3070 * ;) 3071 */ 3072 IdentifierChain parseIdentifierChain() 3073 { 3074 auto node = allocator.make!IdentifierChain; 3075 StackBuffer identifiers; 3076 while (moreTokens()) 3077 { 3078 const ident = expect(tok!"identifier"); 3079 mixin(nullCheck!`ident`); 3080 identifiers.put(*ident); 3081 if (currentIs(tok!".")) 3082 { 3083 advance(); 3084 continue; 3085 } 3086 else 3087 break; 3088 } 3089 ownArray(node.identifiers, identifiers); 3090 return node; 3091 } 3092 3093 /** 3094 * Parses an IdentifierList 3095 * 3096 * $(GRAMMAR $(RULEDEF identifierList): 3097 * $(LITERAL Identifier) ($(LITERAL ',') $(LITERAL Identifier))* 3098 * ;) 3099 */ 3100 IdentifierList parseIdentifierList() 3101 { 3102 auto node = allocator.make!IdentifierList; 3103 StackBuffer identifiers; 3104 while (moreTokens()) 3105 { 3106 const ident = expect(tok!"identifier"); 3107 mixin(nullCheck!`ident`); 3108 identifiers.put(*ident); 3109 if (currentIs(tok!",")) 3110 { 3111 advance(); 3112 continue; 3113 } 3114 else 3115 break; 3116 } 3117 ownArray(node.identifiers, identifiers); 3118 return node; 3119 } 3120 3121 /** 3122 * Parses an IdentifierOrTemplateChain 3123 * 3124 * $(GRAMMAR $(RULEDEF identifierOrTemplateChain): 3125 * $(RULE identifierOrTemplateInstance) ($(LITERAL '.') $(RULE identifierOrTemplateInstance))* 3126 * ;) 3127 */ 3128 IdentifierOrTemplateChain parseIdentifierOrTemplateChain() 3129 { 3130 auto node = allocator.make!IdentifierOrTemplateChain; 3131 StackBuffer identifiersOrTemplateInstances; 3132 while (moreTokens()) 3133 { 3134 auto c = allocator.setCheckpoint(); 3135 if (!identifiersOrTemplateInstances.put(parseIdentifierOrTemplateInstance())) 3136 { 3137 allocator.rollback(c); 3138 break; 3139 } 3140 if (!currentIs(tok!".")) 3141 break; 3142 else 3143 advance(); 3144 } 3145 ownArray(node.identifiersOrTemplateInstances, identifiersOrTemplateInstances); 3146 return node; 3147 } 3148 3149 /** 3150 * Parses an IdentifierOrTemplateInstance 3151 * 3152 * $(GRAMMAR $(RULEDEF identifierOrTemplateInstance): 3153 * $(LITERAL Identifier) 3154 * | $(RULE templateInstance) 3155 * ;) 3156 */ 3157 IdentifierOrTemplateInstance parseIdentifierOrTemplateInstance() 3158 { 3159 mixin(traceEnterAndExit!(__FUNCTION__)); 3160 auto node = allocator.make!IdentifierOrTemplateInstance; 3161 if (peekIs(tok!"!") && !startsWith(tok!"identifier", 3162 tok!"!", tok!"is") 3163 && !startsWith(tok!"identifier", tok!"!", tok!"in")) 3164 { 3165 mixin(parseNodeQ!(`node.templateInstance`, `TemplateInstance`)); 3166 } 3167 else 3168 { 3169 const ident = expect(tok!"identifier"); 3170 mixin(nullCheck!`ident`); 3171 node.identifier = *ident; 3172 } 3173 return node; 3174 } 3175 3176 /** 3177 * Parses an IdentityExpression 3178 * 3179 * $(GRAMMAR $(RULEDEF identityExpression): 3180 * $(RULE shiftExpression) ($(LITERAL 'is') | ($(LITERAL '!') $(LITERAL 'is'))) $(RULE shiftExpression) 3181 * ;) 3182 */ 3183 ExpressionNode parseIdentityExpression(ExpressionNode shift = null) 3184 { 3185 mixin(traceEnterAndExit!(__FUNCTION__)); 3186 auto node = allocator.make!IdentityExpression; 3187 mixin(nullCheck!`node.left = shift is null ? parseShiftExpression() : shift`); 3188 if (currentIs(tok!"!")) 3189 { 3190 advance(); 3191 node.negated = true; 3192 } 3193 mixin(tokenCheck!"is"); 3194 mixin(parseNodeQ!(`node.right`, `ShiftExpression`)); 3195 return node; 3196 } 3197 3198 /** 3199 * Parses an IfStatement 3200 * 3201 * $(GRAMMAR $(RULEDEF ifStatement): 3202 * $(LITERAL 'if') $(LITERAL '$(LPAREN)') $(RULE ifCondition) $(LITERAL '$(RPAREN)') $(RULE declarationOrStatement) ($(LITERAL 'else') $(RULE declarationOrStatement))? 3203 *$(RULEDEF ifCondition): 3204 * $(LITERAL 'auto') $(LITERAL Identifier) $(LITERAL '=') $(RULE expression) 3205 * | $(RULE type) $(LITERAL Identifier) $(LITERAL '=') $(RULE expression) 3206 * | $(RULE expression) 3207 * ;) 3208 */ 3209 IfStatement parseIfStatement() 3210 { 3211 mixin(traceEnterAndExit!(__FUNCTION__)); 3212 auto node = allocator.make!IfStatement; 3213 node.line = current().line; 3214 node.column = current().column; 3215 mixin(tokenCheck!"if"); 3216 node.startIndex = current().index; 3217 mixin(tokenCheck!"("); 3218 3219 if (currentIs(tok!"auto")) 3220 { 3221 advance(); 3222 const i = expect(tok!"identifier"); 3223 if (i !is null) 3224 node.identifier = *i; 3225 expect(tok!"="); 3226 mixin(parseNodeQ!(`node.expression`, `Expression`)); 3227 } 3228 else 3229 { 3230 immutable b = setBookmark(); 3231 immutable c = allocator.setCheckpoint(); 3232 auto type = parseType(); 3233 if (type is null || !currentIs(tok!"identifier") 3234 || !peekIs(tok!"=")) 3235 { 3236 allocator.rollback(c); 3237 goToBookmark(b); 3238 mixin(parseNodeQ!(`node.expression`, `Expression`)); 3239 } 3240 else 3241 { 3242 abandonBookmark(b); 3243 node.type = type; 3244 mixin(tokenCheck!(`node.identifier`, "identifier")); 3245 mixin(tokenCheck!"="); 3246 mixin(parseNodeQ!(`node.expression`, `Expression`)); 3247 } 3248 } 3249 3250 mixin(tokenCheck!")"); 3251 if (currentIs(tok!"}")) 3252 { 3253 error("Statement expected", false); 3254 return node; // this line makes DCD better 3255 } 3256 mixin(parseNodeQ!(`node.thenStatement`, `DeclarationOrStatement`)); 3257 if (currentIs(tok!"else")) 3258 { 3259 advance(); 3260 mixin(parseNodeQ!(`node.elseStatement`, `DeclarationOrStatement`)); 3261 } 3262 return node; 3263 } 3264 3265 /** 3266 * Parses an ImportBind 3267 * 3268 * $(GRAMMAR $(RULEDEF importBind): 3269 * $(LITERAL Identifier) ($(LITERAL '=') $(LITERAL Identifier))? 3270 * ;) 3271 */ 3272 ImportBind parseImportBind() 3273 { 3274 auto node = allocator.make!ImportBind; 3275 const ident = expect(tok!"identifier"); 3276 mixin(nullCheck!`ident`); 3277 node.left = *ident; 3278 if (currentIs(tok!"=")) 3279 { 3280 advance(); 3281 const id = expect(tok!"identifier"); 3282 mixin(nullCheck!`id`); 3283 node.right = *id; 3284 } 3285 return node; 3286 } 3287 3288 /** 3289 * Parses ImportBindings 3290 * 3291 * $(GRAMMAR $(RULEDEF importBindings): 3292 * $(RULE singleImport) $(LITERAL ':') $(RULE importBind) ($(LITERAL ',') $(RULE importBind))* 3293 * ;) 3294 */ 3295 ImportBindings parseImportBindings(SingleImport singleImport) 3296 { 3297 auto node = allocator.make!ImportBindings; 3298 mixin(nullCheck!`node.singleImport = singleImport is null ? parseSingleImport() : singleImport`); 3299 mixin(tokenCheck!":"); 3300 StackBuffer importBinds; 3301 while (moreTokens()) 3302 { 3303 immutable c = allocator.setCheckpoint(); 3304 if (importBinds.put(parseImportBind())) 3305 { 3306 if (currentIs(tok!",")) 3307 advance(); 3308 else 3309 break; 3310 } 3311 else 3312 { 3313 allocator.rollback(c); 3314 break; 3315 } 3316 } 3317 ownArray(node.importBinds, importBinds); 3318 return node; 3319 } 3320 3321 /** 3322 * Parses an ImportDeclaration 3323 * 3324 * $(GRAMMAR $(RULEDEF importDeclaration): 3325 * $(LITERAL 'import') $(RULE singleImport) ($(LITERAL ',') $(RULE singleImport))* ($(LITERAL ',') $(RULE importBindings))? $(LITERAL ';') 3326 * | $(LITERAL 'import') $(RULE importBindings) $(LITERAL ';') 3327 * ;) 3328 */ 3329 ImportDeclaration parseImportDeclaration() 3330 { 3331 auto node = allocator.make!ImportDeclaration; 3332 mixin(tokenCheck!"import"); 3333 SingleImport si = parseSingleImport(); 3334 if (si is null) 3335 return null; 3336 if (currentIs(tok!":")) 3337 node.importBindings = parseImportBindings(si); 3338 else 3339 { 3340 StackBuffer singleImports; 3341 singleImports.put(si); 3342 if (currentIs(tok!",")) 3343 { 3344 advance(); 3345 while (moreTokens()) 3346 { 3347 auto single = parseSingleImport(); 3348 mixin(nullCheck!`single`); 3349 if (currentIs(tok!":")) 3350 { 3351 node.importBindings = parseImportBindings(single); 3352 break; 3353 } 3354 else 3355 { 3356 singleImports.put(single); 3357 if (currentIs(tok!",")) 3358 advance(); 3359 else 3360 break; 3361 } 3362 } 3363 } 3364 ownArray(node.singleImports, singleImports); 3365 } 3366 mixin(tokenCheck!";"); 3367 return node; 3368 } 3369 3370 /** 3371 * Parses an ImportExpression 3372 * 3373 * $(GRAMMAR $(RULEDEF importExpression): 3374 * $(LITERAL 'import') $(LITERAL '$(LPAREN)') $(RULE assignExpression) $(LITERAL '$(RPAREN)') 3375 * ;) 3376 */ 3377 ImportExpression parseImportExpression() 3378 { 3379 mixin(traceEnterAndExit!(__FUNCTION__)); 3380 mixin(simpleParse!(ImportExpression, tok!"import", tok!"(", 3381 "assignExpression|parseAssignExpression", tok!")")); 3382 } 3383 3384 /** 3385 * Parses an Index 3386 * 3387 * $(GRAMMAR $(RULEDEF index): 3388 * $(RULE assignExpression) ($(LITERAL '..') $(RULE assignExpression))? 3389 * ; 3390 * ) 3391 */ 3392 Index parseIndex() 3393 { 3394 mixin(traceEnterAndExit!(__FUNCTION__)); 3395 auto node = allocator.make!Index(); 3396 mixin(parseNodeQ!(`node.low`, `AssignExpression`)); 3397 if (currentIs(tok!"..")) 3398 { 3399 advance(); 3400 mixin(parseNodeQ!(`node.high`, `AssignExpression`)); 3401 } 3402 return node; 3403 } 3404 3405 /** 3406 * Parses an IndexExpression 3407 * 3408 * $(GRAMMAR $(RULEDEF indexExpression): 3409 * $(RULE unaryExpression) $(LITERAL '[') $(LITERAL ']') 3410 * | $(RULE unaryExpression) $(LITERAL '[') $(RULE index) ($(LITERAL ',') $(RULE index))* $(LITERAL ']') 3411 * ; 3412 * ) 3413 */ 3414 IndexExpression parseIndexExpression(UnaryExpression unaryExpression = null) 3415 { 3416 mixin(traceEnterAndExit!(__FUNCTION__)); 3417 auto node = allocator.make!IndexExpression; 3418 mixin(nullCheck!`node.unaryExpression = unaryExpression is null ? parseUnaryExpression() : unaryExpression`); 3419 mixin(tokenCheck!"["); 3420 StackBuffer indexes; 3421 while (true) 3422 { 3423 if (!moreTokens()) 3424 { 3425 error("Expected unary expression instead of EOF"); 3426 return null; 3427 } 3428 if (currentIs(tok!"]")) 3429 break; 3430 if (!(indexes.put(parseIndex()))) 3431 return null; 3432 if (currentIs(tok!",")) 3433 advance(); 3434 else 3435 break; 3436 } 3437 ownArray(node.indexes, indexes); 3438 advance(); // ] 3439 return node; 3440 } 3441 3442 /** 3443 * Parses an InExpression 3444 * 3445 * $(GRAMMAR $(RULEDEF inExpression): 3446 * $(RULE shiftExpression) ($(LITERAL 'in') | ($(LITERAL '!') $(LITERAL 'in'))) $(RULE shiftExpression) 3447 * ;) 3448 */ 3449 ExpressionNode parseInExpression(ExpressionNode shift = null) 3450 { 3451 auto node = allocator.make!InExpression; 3452 mixin(nullCheck!`node.left = shift is null ? parseShiftExpression() : shift`); 3453 if (currentIs(tok!"!")) 3454 { 3455 node.negated = true; 3456 advance(); 3457 } 3458 mixin(tokenCheck!"in"); 3459 mixin(parseNodeQ!(`node.right`, `ShiftExpression`)); 3460 return node; 3461 } 3462 3463 /** 3464 * Parses an InStatement 3465 * 3466 * $(GRAMMAR $(RULEDEF inStatement): 3467 * $(LITERAL 'in') $(RULE blockStatement) 3468 * ;) 3469 */ 3470 InStatement parseInStatement() 3471 { 3472 auto node = allocator.make!InStatement; 3473 const i = expect(tok!"in"); 3474 mixin(nullCheck!`i`); 3475 node.inTokenLocation = i.index; 3476 mixin(parseNodeQ!(`node.blockStatement`, `BlockStatement`)); 3477 return node; 3478 } 3479 3480 /** 3481 * Parses an Initializer 3482 * 3483 * $(GRAMMAR $(RULEDEF initializer): 3484 * $(LITERAL 'void') 3485 * | $(RULE nonVoidInitializer) 3486 * ;) 3487 */ 3488 Initializer parseInitializer() 3489 { 3490 auto node = allocator.make!Initializer; 3491 if (currentIs(tok!"void") && peekIsOneOf(tok!",", tok!";")) 3492 advance(); 3493 else 3494 mixin(parseNodeQ!(`node.nonVoidInitializer`, `NonVoidInitializer`)); 3495 return node; 3496 } 3497 3498 /** 3499 * Parses an InterfaceDeclaration 3500 * 3501 * $(GRAMMAR $(RULEDEF interfaceDeclaration): 3502 * $(LITERAL 'interface') $(LITERAL Identifier) $(LITERAL ';') 3503 * | $(LITERAL 'interface') $(LITERAL Identifier) ($(LITERAL ':') $(RULE baseClassList))? $(RULE structBody) 3504 * | $(LITERAL 'interface') $(LITERAL Identifier) $(RULE templateParameters) $(RULE constraint)? ($(LITERAL ':') $(RULE baseClassList))? $(RULE structBody) 3505 * | $(LITERAL 'interface') $(LITERAL Identifier) $(RULE templateParameters) ($(LITERAL ':') $(RULE baseClassList))? $(RULE constraint)? $(RULE structBody) 3506 * ;) 3507 */ 3508 InterfaceDeclaration parseInterfaceDeclaration() 3509 { 3510 auto node = allocator.make!InterfaceDeclaration; 3511 expect(tok!"interface"); 3512 return parseInterfaceOrClass(node); 3513 } 3514 3515 /** 3516 * Parses an Invariant 3517 * 3518 * $(GRAMMAR $(RULEDEF invariant): 3519 * $(LITERAL 'invariant') ($(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)'))? $(RULE blockStatement) 3520 * ;) 3521 */ 3522 Invariant parseInvariant() 3523 { 3524 auto node = allocator.make!Invariant; 3525 node.index = current.index; 3526 node.line = current.line; 3527 mixin(tokenCheck!"invariant"); 3528 if (currentIs(tok!"(")) 3529 { 3530 advance(); 3531 mixin(tokenCheck!")"); 3532 } 3533 mixin(parseNodeQ!(`node.blockStatement`, `BlockStatement`)); 3534 return node; 3535 } 3536 3537 /** 3538 * Parses an IsExpression 3539 * 3540 * $(GRAMMAR $(RULEDEF isExpression): 3541 * $(LITERAL'is') $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL identifier)? $(LITERAL '$(RPAREN)') 3542 * $(LITERAL'is') $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL identifier)? $(LITERAL ':') $(RULE typeSpecialization) $(LITERAL '$(RPAREN)') 3543 * $(LITERAL'is') $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL identifier)? $(LITERAL '=') $(RULE typeSpecialization) $(LITERAL '$(RPAREN)') 3544 * $(LITERAL'is') $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL identifier)? $(LITERAL ':') $(RULE typeSpecialization) $(LITERAL ',') $(RULE templateParameterList) $(LITERAL '$(RPAREN)') 3545 * $(LITERAL'is') $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL identifier)? $(LITERAL '=') $(RULE typeSpecialization) $(LITERAL ',') $(RULE templateParameterList) $(LITERAL '$(RPAREN)') 3546 * ;) 3547 */ 3548 IsExpression parseIsExpression() 3549 { 3550 mixin(traceEnterAndExit!(__FUNCTION__)); 3551 auto node = allocator.make!IsExpression; 3552 mixin(tokenCheck!"is"); 3553 mixin(tokenCheck!"("); 3554 mixin(parseNodeQ!(`node.type`, `Type`)); 3555 if (currentIs(tok!"identifier")) 3556 node.identifier = advance(); 3557 if (currentIsOneOf(tok!"==", tok!":")) 3558 { 3559 node.equalsOrColon = advance().type; 3560 mixin(parseNodeQ!(`node.typeSpecialization`, `TypeSpecialization`)); 3561 if (currentIs(tok!",")) 3562 { 3563 advance(); 3564 mixin(parseNodeQ!(`node.templateParameterList`, `TemplateParameterList`)); 3565 } 3566 } 3567 mixin(tokenCheck!")"); 3568 return node; 3569 } 3570 3571 /** 3572 * Parses a KeyValuePair 3573 * 3574 * $(GRAMMAR $(RULEDEF keyValuePair): 3575 * $(RULE assignExpression) $(LITERAL ':') $(RULE assignExpression) 3576 * ;) 3577 */ 3578 KeyValuePair parseKeyValuePair() 3579 { 3580 mixin(traceEnterAndExit!(__FUNCTION__)); 3581 auto node = allocator.make!KeyValuePair; 3582 mixin(parseNodeQ!(`node.key`, `AssignExpression`)); 3583 mixin(tokenCheck!":"); 3584 mixin(parseNodeQ!(`node.value`, `AssignExpression`)); 3585 return node; 3586 } 3587 3588 /** 3589 * Parses KeyValuePairs 3590 * 3591 * $(GRAMMAR $(RULEDEF keyValuePairs): 3592 * $(RULE keyValuePair) ($(LITERAL ',') $(RULE keyValuePair))* $(LITERAL ',')? 3593 * ;) 3594 */ 3595 KeyValuePairs parseKeyValuePairs() 3596 { 3597 mixin(traceEnterAndExit!(__FUNCTION__)); 3598 auto node = allocator.make!KeyValuePairs; 3599 StackBuffer keyValuePairs; 3600 while (moreTokens()) 3601 { 3602 if (!keyValuePairs.put(parseKeyValuePair())) 3603 return null; 3604 if (currentIs(tok!",")) 3605 { 3606 advance(); 3607 if (currentIs(tok!"]")) 3608 break; 3609 } 3610 else 3611 break; 3612 } 3613 ownArray(node.keyValuePairs, keyValuePairs); 3614 return node; 3615 } 3616 3617 /** 3618 * Parses a LabeledStatement 3619 * 3620 * $(GRAMMAR $(RULEDEF labeledStatement): 3621 * $(LITERAL Identifier) $(LITERAL ':') $(RULE declarationOrStatement)? 3622 * ;) 3623 */ 3624 LabeledStatement parseLabeledStatement() 3625 { 3626 mixin(traceEnterAndExit!(__FUNCTION__)); 3627 auto node = allocator.make!LabeledStatement; 3628 const ident = expect(tok!"identifier"); 3629 mixin (nullCheck!`ident`); 3630 node.identifier = *ident; 3631 expect(tok!":"); 3632 if (!currentIs(tok!"}")) 3633 mixin(parseNodeQ!(`node.declarationOrStatement`, `DeclarationOrStatement`)); 3634 return node; 3635 } 3636 3637 /** 3638 * Parses a LastCatch 3639 * 3640 * $(GRAMMAR $(RULEDEF lastCatch): 3641 * $(LITERAL 'catch') $(RULE statementNoCaseNoDefault) 3642 * ;) 3643 */ 3644 LastCatch parseLastCatch() 3645 { 3646 mixin(traceEnterAndExit!(__FUNCTION__)); 3647 auto node = allocator.make!LastCatch; 3648 const t = expect(tok!"catch"); 3649 mixin (nullCheck!`t`); 3650 node.line = t.line; 3651 node.column = t.column; 3652 mixin(parseNodeQ!(`node.statementNoCaseNoDefault`, `StatementNoCaseNoDefault`)); 3653 return node; 3654 } 3655 3656 /** 3657 * Parses a LinkageAttribute 3658 * 3659 * $(GRAMMAR $(RULEDEF linkageAttribute): 3660 * $(LITERAL 'extern') $(LITERAL '$(LPAREN)') $(LITERAL Identifier) ($(LITERAL '++') ($(LITERAL ',') $(RULE identifierChain))?)? $(LITERAL '$(RPAREN)') 3661 * ;) 3662 */ 3663 LinkageAttribute parseLinkageAttribute() 3664 { 3665 mixin(traceEnterAndExit!(__FUNCTION__)); 3666 auto node = allocator.make!LinkageAttribute; 3667 expect(tok!"extern"); 3668 expect(tok!"("); 3669 const ident = expect(tok!"identifier"); 3670 mixin (nullCheck!`ident`); 3671 node.identifier = *ident; 3672 if (currentIs(tok!"++")) 3673 { 3674 advance(); 3675 node.hasPlusPlus = true; 3676 if (currentIs(tok!",")) 3677 { 3678 advance(); 3679 mixin(parseNodeQ!(`node.identifierChain`, `IdentifierChain`)); 3680 } 3681 } 3682 expect(tok!")"); 3683 return node; 3684 } 3685 3686 /** 3687 * Parses a MemberFunctionAttribute 3688 * 3689 * $(GRAMMAR $(RULEDEF memberFunctionAttribute): 3690 * $(RULE functionAttribute) 3691 * | $(LITERAL 'immutable') 3692 * | $(LITERAL 'inout') 3693 * | $(LITERAL 'shared') 3694 * | $(LITERAL 'const') 3695 * | $(LITERAL 'return') 3696 * ;) 3697 */ 3698 MemberFunctionAttribute parseMemberFunctionAttribute() 3699 { 3700 mixin(traceEnterAndExit!(__FUNCTION__)); 3701 auto node = allocator.make!MemberFunctionAttribute; 3702 switch (current.type) 3703 { 3704 case tok!"@": 3705 mixin(parseNodeQ!(`node.atAttribute`, `AtAttribute`)); 3706 break; 3707 case tok!"immutable": 3708 case tok!"inout": 3709 case tok!"shared": 3710 case tok!"const": 3711 case tok!"pure": 3712 case tok!"nothrow": 3713 case tok!"return": 3714 node.tokenType = advance().type; 3715 break; 3716 default: 3717 error(`Member funtion attribute expected`); 3718 } 3719 return node; 3720 } 3721 3722 /** 3723 * Parses a MixinDeclaration 3724 * 3725 * $(GRAMMAR $(RULEDEF mixinDeclaration): 3726 * $(RULE mixinExpression) $(LITERAL ';') 3727 * | $(RULE templateMixinExpression) $(LITERAL ';') 3728 * ;) 3729 */ 3730 MixinDeclaration parseMixinDeclaration() 3731 { 3732 mixin(traceEnterAndExit!(__FUNCTION__)); 3733 auto node = allocator.make!MixinDeclaration; 3734 if (peekIsOneOf(tok!"identifier", tok!"typeof", tok!".")) 3735 mixin(parseNodeQ!(`node.templateMixinExpression`, `TemplateMixinExpression`)); 3736 else if (peekIs(tok!"(")) 3737 mixin(parseNodeQ!(`node.mixinExpression`, `MixinExpression`)); 3738 else 3739 { 3740 error(`"(" or identifier expected`); 3741 return null; 3742 } 3743 expect(tok!";"); 3744 return node; 3745 } 3746 3747 /** 3748 * Parses a MixinExpression 3749 * 3750 * $(GRAMMAR $(RULEDEF mixinExpression): 3751 * $(LITERAL 'mixin') $(LITERAL '$(LPAREN)') $(RULE assignExpression) $(LITERAL '$(RPAREN)') 3752 * ;) 3753 */ 3754 MixinExpression parseMixinExpression() 3755 { 3756 mixin(traceEnterAndExit!(__FUNCTION__)); 3757 auto node = allocator.make!MixinExpression; 3758 expect(tok!"mixin"); 3759 expect(tok!"("); 3760 mixin(parseNodeQ!(`node.assignExpression`, `AssignExpression`)); 3761 expect(tok!")"); 3762 return node; 3763 } 3764 3765 /** 3766 * Parses a MixinTemplateDeclaration 3767 * 3768 * $(GRAMMAR $(RULEDEF mixinTemplateDeclaration): 3769 * $(LITERAL 'mixin') $(RULE templateDeclaration) 3770 * ;) 3771 */ 3772 MixinTemplateDeclaration parseMixinTemplateDeclaration() 3773 { 3774 mixin(traceEnterAndExit!(__FUNCTION__)); 3775 auto node = allocator.make!MixinTemplateDeclaration; 3776 mixin(tokenCheck!"mixin"); 3777 mixin(parseNodeQ!(`node.templateDeclaration`, `TemplateDeclaration`)); 3778 return node; 3779 } 3780 3781 /** 3782 * Parses a MixinTemplateName 3783 * 3784 * $(GRAMMAR $(RULEDEF mixinTemplateName): 3785 * $(RULE symbol) 3786 * | $(RULE typeofExpression) $(LITERAL '.') $(RULE identifierOrTemplateChain) 3787 * ;) 3788 */ 3789 MixinTemplateName parseMixinTemplateName() 3790 { 3791 mixin(traceEnterAndExit!(__FUNCTION__)); 3792 auto node = allocator.make!MixinTemplateName; 3793 if (currentIs(tok!"typeof")) 3794 { 3795 mixin(parseNodeQ!(`node.typeofExpression`, `TypeofExpression`)); 3796 expect(tok!"."); 3797 mixin(parseNodeQ!(`node.identifierOrTemplateChain`, `IdentifierOrTemplateChain`)); 3798 } 3799 else 3800 mixin(parseNodeQ!(`node.symbol`, `Symbol`)); 3801 return node; 3802 } 3803 3804 /** 3805 * Parses a Module 3806 * 3807 * $(GRAMMAR $(RULEDEF module): 3808 * $(RULE moduleDeclaration)? $(RULE declaration)* 3809 * ;) 3810 */ 3811 Module parseModule() 3812 { 3813 mixin(traceEnterAndExit!(__FUNCTION__)); 3814 Module m = allocator.make!Module; 3815 if (currentIs(tok!"scriptLine")) 3816 m.scriptLine = advance(); 3817 bool isDeprecatedModule; 3818 if (currentIs(tok!"deprecated")) 3819 { 3820 immutable b = setBookmark(); 3821 advance(); 3822 if (currentIs(tok!"(")) 3823 skipParens(); 3824 isDeprecatedModule = currentIs(tok!"module"); 3825 goToBookmark(b); 3826 } 3827 if (currentIs(tok!"module") || isDeprecatedModule) 3828 mixin(parseNodeQ!(`m.moduleDeclaration`, `ModuleDeclaration`)); 3829 StackBuffer declarations; 3830 while (moreTokens()) 3831 { 3832 immutable c = allocator.setCheckpoint(); 3833 if (!declarations.put(parseDeclaration(true, true))) 3834 allocator.rollback(c); 3835 } 3836 ownArray(m.declarations, declarations); 3837 return m; 3838 } 3839 3840 /** 3841 * Parses a ModuleDeclaration 3842 * 3843 * $(GRAMMAR $(RULEDEF moduleDeclaration): 3844 * $(RULE deprecated)? $(LITERAL 'module') $(RULE identifierChain) $(LITERAL ';') 3845 * ;) 3846 */ 3847 ModuleDeclaration parseModuleDeclaration() 3848 { 3849 auto node = allocator.make!ModuleDeclaration; 3850 if (currentIs(tok!"deprecated")) 3851 mixin(parseNodeQ!(`node.deprecated_`, `Deprecated`)); 3852 const start = expect(tok!"module"); 3853 mixin(nullCheck!`start`); 3854 mixin(parseNodeQ!(`node.moduleName`, `IdentifierChain`)); 3855 node.comment = start.comment; 3856 if (node.comment is null) 3857 node.comment = start.trailingComment; 3858 comment = null; 3859 const end = expect(tok!";"); 3860 node.startLocation = start.index; 3861 if (end !is null) 3862 node.endLocation = end.index; 3863 return node; 3864 } 3865 3866 /** 3867 * Parses a MulExpression. 3868 * 3869 * $(GRAMMAR $(RULEDEF mulExpression): 3870 * $(RULE powExpression) 3871 * | $(RULE mulExpression) ($(LITERAL '*') | $(LITERAL '/') | $(LITERAL '%')) $(RULE powExpression) 3872 * ;) 3873 */ 3874 ExpressionNode parseMulExpression() 3875 { 3876 mixin(traceEnterAndExit!(__FUNCTION__)); 3877 return parseLeftAssocBinaryExpression!(MulExpression, PowExpression, 3878 tok!"*", tok!"/", tok!"%")(); 3879 } 3880 3881 /** 3882 * Parses a NewAnonClassExpression 3883 * 3884 * $(GRAMMAR $(RULEDEF newAnonClassExpression): 3885 * $(LITERAL 'new') $(RULE arguments)? $(LITERAL 'class') $(RULE arguments)? $(RULE baseClassList)? $(RULE structBody) 3886 * ;) 3887 */ 3888 NewAnonClassExpression parseNewAnonClassExpression() 3889 { 3890 mixin(traceEnterAndExit!(__FUNCTION__)); 3891 auto node = allocator.make!NewAnonClassExpression; 3892 expect(tok!"new"); 3893 if (currentIs(tok!"(")) 3894 mixin(parseNodeQ!(`node.allocatorArguments`, `Arguments`)); 3895 expect(tok!"class"); 3896 if (currentIs(tok!"(")) 3897 mixin(parseNodeQ!(`node.constructorArguments`, `Arguments`)); 3898 if (!currentIs(tok!"{")) 3899 mixin(parseNodeQ!(`node.baseClassList`, `BaseClassList`)); 3900 mixin(parseNodeQ!(`node.structBody`, `StructBody`)); 3901 return node; 3902 } 3903 3904 /** 3905 * Parses a NewExpression 3906 * 3907 * $(GRAMMAR $(RULEDEF newExpression): 3908 * $(LITERAL 'new') $(RULE type) (($(LITERAL '[') $(RULE assignExpression) $(LITERAL ']')) | $(RULE arguments))? 3909 * | $(RULE newAnonClassExpression) 3910 * ;) 3911 */ 3912 NewExpression parseNewExpression() 3913 { 3914 // Parse ambiguity. 3915 // auto a = new int[10]; 3916 // ^^^^^^^ 3917 // auto a = new int[10]; 3918 // ^^^**** 3919 mixin(traceEnterAndExit!(__FUNCTION__)); 3920 auto node = allocator.make!NewExpression; 3921 if (peekIsOneOf(tok!"class", tok!"(")) 3922 mixin(parseNodeQ!(`node.newAnonClassExpression`, `NewAnonClassExpression`)); 3923 else 3924 { 3925 expect(tok!"new"); 3926 mixin(parseNodeQ!(`node.type`, `Type`)); 3927 if (currentIs(tok!"[")) 3928 { 3929 advance(); 3930 mixin(parseNodeQ!(`node.assignExpression`, `AssignExpression`)); 3931 expect(tok!"]"); 3932 } 3933 else if (currentIs(tok!"(")) 3934 mixin(parseNodeQ!(`node.arguments`, `Arguments`)); 3935 } 3936 return node; 3937 } 3938 3939 /** 3940 * Parses a NonVoidInitializer 3941 * 3942 * $(GRAMMAR $(RULEDEF nonVoidInitializer): 3943 * $(RULE assignExpression) 3944 * | $(RULE arrayInitializer) 3945 * | $(RULE structInitializer) 3946 * ;) 3947 */ 3948 NonVoidInitializer parseNonVoidInitializer() 3949 { 3950 mixin(traceEnterAndExit!(__FUNCTION__)); 3951 auto node = allocator.make!NonVoidInitializer; 3952 if (currentIs(tok!"{")) 3953 { 3954 const b = peekPastBraces(); 3955 if (b !is null && (b.type == tok!"(")) 3956 mixin(parseNodeQ!(`node.assignExpression`, `AssignExpression`)); 3957 else 3958 { 3959 assert (currentIs(tok!"{")); 3960 auto m = setBookmark(); 3961 auto initializer = parseStructInitializer(); 3962 if (initializer !is null) 3963 { 3964 node.structInitializer = initializer; 3965 abandonBookmark(m); 3966 } 3967 else 3968 { 3969 goToBookmark(m); 3970 mixin(parseNodeQ!(`node.assignExpression`, `AssignExpression`)); 3971 } 3972 } 3973 } 3974 else if (currentIs(tok!"[")) 3975 { 3976 const b = peekPastBrackets(); 3977 if (b !is null && (b.type == tok!"," 3978 || b.type == tok!")" 3979 || b.type == tok!"]" 3980 || b.type == tok!"}" 3981 || b.type == tok!";")) 3982 { 3983 mixin(parseNodeQ!(`node.arrayInitializer`, `ArrayInitializer`)); 3984 } 3985 else 3986 mixin(parseNodeQ!(`node.assignExpression`, `AssignExpression`)); 3987 } 3988 else 3989 mixin(parseNodeQ!(`node.assignExpression`, `AssignExpression`)); 3990 if (node.assignExpression is null && node.arrayInitializer is null 3991 && node.structInitializer is null) 3992 return null; 3993 return node; 3994 } 3995 3996 /** 3997 * Parses Operands 3998 * 3999 * $(GRAMMAR $(RULEDEF operands): 4000 * $(RULE asmExp) 4001 * | $(RULE asmExp) $(LITERAL ',') $(RULE operands) 4002 * ;) 4003 */ 4004 Operands parseOperands() 4005 { 4006 mixin(traceEnterAndExit!(__FUNCTION__)); 4007 Operands node = allocator.make!Operands; 4008 StackBuffer expressions; 4009 while (true) 4010 { 4011 if (!expressions.put(parseAsmExp())) 4012 return null; 4013 if (currentIs(tok!",")) 4014 advance(); 4015 else 4016 break; 4017 } 4018 ownArray(node.operands, expressions); 4019 return node; 4020 } 4021 4022 /** 4023 * Parses an OrExpression 4024 * 4025 * $(GRAMMAR $(RULEDEF orExpression): 4026 * $(RULE xorExpression) 4027 * | $(RULE orExpression) $(LITERAL '|') $(RULE xorExpression) 4028 * ;) 4029 */ 4030 ExpressionNode parseOrExpression() 4031 { 4032 mixin(traceEnterAndExit!(__FUNCTION__)); 4033 return parseLeftAssocBinaryExpression!(OrExpression, XorExpression, 4034 tok!"|")(); 4035 } 4036 4037 /** 4038 * Parses an OrOrExpression 4039 * 4040 * $(GRAMMAR $(RULEDEF orOrExpression): 4041 * $(RULE andAndExpression) 4042 * | $(RULE orOrExpression) $(LITERAL '||') $(RULE andAndExpression) 4043 * ;) 4044 */ 4045 ExpressionNode parseOrOrExpression() 4046 { 4047 mixin(traceEnterAndExit!(__FUNCTION__)); 4048 return parseLeftAssocBinaryExpression!(OrOrExpression, AndAndExpression, 4049 tok!"||")(); 4050 } 4051 4052 /** 4053 * Parses an OutStatement 4054 * 4055 * $(GRAMMAR $(RULEDEF outStatement): 4056 * $(LITERAL 'out') ($(LITERAL '$(LPAREN)') $(LITERAL Identifier) $(LITERAL '$(RPAREN)'))? $(RULE blockStatement) 4057 * ;) 4058 */ 4059 OutStatement parseOutStatement() 4060 { 4061 auto node = allocator.make!OutStatement; 4062 const o = expect(tok!"out"); 4063 mixin(nullCheck!`o`); 4064 node.outTokenLocation = o.index; 4065 if (currentIs(tok!"(")) 4066 { 4067 advance(); 4068 const ident = expect(tok!"identifier"); 4069 mixin (nullCheck!`ident`); 4070 node.parameter = *ident; 4071 expect(tok!")"); 4072 } 4073 mixin(parseNodeQ!(`node.blockStatement`, `BlockStatement`)); 4074 return node; 4075 } 4076 4077 /** 4078 * Parses a Parameter 4079 * 4080 * $(GRAMMAR $(RULEDEF parameter): 4081 * $(RULE parameterAttribute)* $(RULE type) 4082 * $(RULE parameterAttribute)* $(RULE type) $(LITERAL Identifier)? $(LITERAL '...') 4083 * $(RULE parameterAttribute)* $(RULE type) $(LITERAL Identifier)? ($(LITERAL '=') $(RULE assignExpression))? 4084 * ;) 4085 */ 4086 Parameter parseParameter() 4087 { 4088 mixin(traceEnterAndExit!(__FUNCTION__)); 4089 auto node = allocator.make!Parameter; 4090 StackBuffer parameterAttributes; 4091 while (moreTokens()) 4092 { 4093 IdType type = parseParameterAttribute(false); 4094 if (type == tok!"") 4095 break; 4096 else 4097 parameterAttributes.put(type); 4098 } 4099 ownArray(node.parameterAttributes, parameterAttributes); 4100 mixin(parseNodeQ!(`node.type`, `Type`)); 4101 if (currentIs(tok!"identifier")) 4102 { 4103 node.name = advance(); 4104 if (currentIs(tok!"...")) 4105 { 4106 advance(); 4107 node.vararg = true; 4108 } 4109 else if (currentIs(tok!"=")) 4110 { 4111 advance(); 4112 mixin(parseNodeQ!(`node.default_`, `AssignExpression`)); 4113 } 4114 else if (currentIs(tok!"[")) 4115 { 4116 StackBuffer typeSuffixes; 4117 while(moreTokens() && currentIs(tok!"[")) 4118 if (!typeSuffixes.put(parseTypeSuffix())) 4119 return null; 4120 ownArray(node.cstyle, typeSuffixes); 4121 } 4122 } 4123 else if (currentIs(tok!"...")) 4124 { 4125 node.vararg = true; 4126 advance(); 4127 } 4128 else if (currentIs(tok!"=")) 4129 { 4130 advance(); 4131 mixin(parseNodeQ!(`node.default_`, `AssignExpression`)); 4132 } 4133 return node; 4134 } 4135 4136 /** 4137 * Parses a ParameterAttribute 4138 * 4139 * $(GRAMMAR $(RULEDEF parameterAttribute): 4140 * $(RULE typeConstructor) 4141 * | $(LITERAL 'final') 4142 * | $(LITERAL 'in') 4143 * | $(LITERAL 'lazy') 4144 * | $(LITERAL 'out') 4145 * | $(LITERAL 'ref') 4146 * | $(LITERAL 'scope') 4147 * | $(LITERAL 'auto') 4148 * | $(LITERAL 'return') 4149 * ;) 4150 */ 4151 IdType parseParameterAttribute(bool validate = false) 4152 { 4153 mixin(traceEnterAndExit!(__FUNCTION__)); 4154 switch (current.type) 4155 { 4156 case tok!"immutable": 4157 case tok!"shared": 4158 case tok!"const": 4159 case tok!"inout": 4160 if (peekIs(tok!"(")) 4161 return tok!""; 4162 else 4163 goto case; 4164 case tok!"final": 4165 case tok!"in": 4166 case tok!"lazy": 4167 case tok!"out": 4168 case tok!"ref": 4169 case tok!"scope": 4170 case tok!"auto": 4171 case tok!"return": 4172 return advance().type; 4173 default: 4174 if (validate) 4175 error("Parameter attribute expected"); 4176 return tok!""; 4177 } 4178 } 4179 4180 /** 4181 * Parses Parameters 4182 * 4183 * $(GRAMMAR $(RULEDEF parameters): 4184 * $(LITERAL '$(LPAREN)') $(RULE parameter) ($(LITERAL ',') $(RULE parameter))* ($(LITERAL ',') $(LITERAL '...'))? $(LITERAL '$(RPAREN)') 4185 * | $(LITERAL '$(LPAREN)') $(LITERAL '...') $(LITERAL '$(RPAREN)') 4186 * | $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)') 4187 * ;) 4188 */ 4189 Parameters parseParameters() 4190 { 4191 mixin(traceEnterAndExit!(__FUNCTION__)); 4192 auto node = allocator.make!Parameters; 4193 mixin(tokenCheck!"("); 4194 4195 if (currentIs(tok!")")) 4196 { 4197 advance(); // ) 4198 return node; 4199 } 4200 if (currentIs(tok!"...")) 4201 { 4202 advance(); 4203 node.hasVarargs = true; 4204 mixin(tokenCheck!")"); 4205 return node; 4206 } 4207 StackBuffer parameters; 4208 while (moreTokens()) 4209 { 4210 if (currentIs(tok!"...")) 4211 { 4212 advance(); 4213 node.hasVarargs = true; 4214 break; 4215 } 4216 if (currentIs(tok!")")) 4217 break; 4218 if (!parameters.put(parseParameter())) 4219 return null; 4220 if (currentIs(tok!",")) 4221 advance(); 4222 else 4223 break; 4224 } 4225 ownArray(node.parameters, parameters); 4226 mixin(tokenCheck!")"); 4227 return node; 4228 } 4229 4230 /** 4231 * Parses a Postblit 4232 * 4233 * $(GRAMMAR $(RULEDEF postblit): 4234 * $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL 'this') $(LITERAL '$(RPAREN)') $(RULE memberFunctionAttribute)* ($(RULE functionBody) | $(LITERAL ';')) 4235 * ;) 4236 */ 4237 Postblit parsePostblit() 4238 { 4239 mixin(traceEnterAndExit!(__FUNCTION__)); 4240 auto node = allocator.make!Postblit; 4241 expect(tok!"this"); 4242 expect(tok!"("); 4243 expect(tok!"this"); 4244 expect(tok!")"); 4245 StackBuffer memberFunctionAttributes; 4246 while (currentIsMemberFunctionAttribute()) 4247 if (!memberFunctionAttributes.put(parseMemberFunctionAttribute())) 4248 return null; 4249 ownArray(node.memberFunctionAttributes, memberFunctionAttributes); 4250 if (currentIs(tok!";")) 4251 advance(); 4252 else 4253 mixin(parseNodeQ!(`node.functionBody`, `FunctionBody`)); 4254 return node; 4255 } 4256 4257 /** 4258 * Parses a PowExpression 4259 * 4260 * $(GRAMMAR $(RULEDEF powExpression): 4261 * $(RULE unaryExpression) 4262 * | $(RULE powExpression) $(LITERAL '^^') $(RULE unaryExpression) 4263 * ;) 4264 */ 4265 ExpressionNode parsePowExpression() 4266 { 4267 mixin (traceEnterAndExit!(__FUNCTION__)); 4268 return parseLeftAssocBinaryExpression!(PowExpression, UnaryExpression, 4269 tok!"^^")(); 4270 } 4271 4272 /** 4273 * Parses a PragmaDeclaration 4274 * 4275 * $(GRAMMAR $(RULEDEF pragmaDeclaration): 4276 * $(RULE pragmaExpression) $(LITERAL ';') 4277 * ;) 4278 */ 4279 PragmaDeclaration parsePragmaDeclaration() 4280 { 4281 mixin(traceEnterAndExit!(__FUNCTION__)); 4282 mixin(simpleParse!(PragmaDeclaration, "pragmaExpression|parsePragmaExpression", tok!";")); 4283 } 4284 4285 /** 4286 * Parses a PragmaExpression 4287 * 4288 * $(GRAMMAR $(RULEDEF pragmaExpression): 4289 * $(RULE 'pragma') $(LITERAL '$(LPAREN)') $(LITERAL Identifier) ($(LITERAL ',') $(RULE argumentList))? $(LITERAL '$(RPAREN)') 4290 * ;) 4291 */ 4292 PragmaExpression parsePragmaExpression() 4293 { 4294 mixin (traceEnterAndExit!(__FUNCTION__)); 4295 auto node = allocator.make!PragmaExpression; 4296 expect(tok!"pragma"); 4297 expect(tok!"("); 4298 const ident = expect(tok!"identifier"); 4299 mixin(nullCheck!`ident`); 4300 node.identifier = *ident; 4301 if (currentIs(tok!",")) 4302 { 4303 advance(); 4304 mixin(parseNodeQ!(`node.argumentList`, `ArgumentList`)); 4305 } 4306 expect(tok!")"); 4307 return node; 4308 } 4309 4310 /** 4311 * Parses a PrimaryExpression 4312 * 4313 * $(GRAMMAR $(RULEDEF primaryExpression): 4314 * $(RULE identifierOrTemplateInstance) 4315 * | $(LITERAL '.') $(RULE identifierOrTemplateInstance) 4316 * | $(RULE typeConstructor) $(LITERAL '$(LPAREN)') $(RULE basicType) $(LITERAL '$(RPAREN)') $(LITERAL '.') $(LITERAL Identifier) 4317 * | $(RULE basicType) $(LITERAL '.') $(LITERAL Identifier) 4318 * | $(RULE basicType) $(RULE arguments) 4319 * | $(RULE typeofExpression) 4320 * | $(RULE typeidExpression) 4321 * | $(RULE vector) 4322 * | $(RULE arrayLiteral) 4323 * | $(RULE assocArrayLiteral) 4324 * | $(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)') 4325 * | $(RULE isExpression) 4326 * | $(RULE functionLiteralExpression) 4327 * | $(RULE traitsExpression) 4328 * | $(RULE mixinExpression) 4329 * | $(RULE importExpression) 4330 * | $(LITERAL '$') 4331 * | $(LITERAL 'this') 4332 * | $(LITERAL 'super') 4333 * | $(LITERAL '_null') 4334 * | $(LITERAL '_true') 4335 * | $(LITERAL '_false') 4336 * | $(LITERAL '___DATE__') 4337 * | $(LITERAL '___TIME__') 4338 * | $(LITERAL '___TIMESTAMP__') 4339 * | $(LITERAL '___VENDOR__') 4340 * | $(LITERAL '___VERSION__') 4341 * | $(LITERAL '___FILE__') 4342 * | $(LITERAL '___LINE__') 4343 * | $(LITERAL '___MODULE__') 4344 * | $(LITERAL '___FUNCTION__') 4345 * | $(LITERAL '___PRETTY_FUNCTION__') 4346 * | $(LITERAL IntegerLiteral) 4347 * | $(LITERAL FloatLiteral) 4348 * | $(LITERAL StringLiteral)+ 4349 * | $(LITERAL CharacterLiteral) 4350 * ;) 4351 */ 4352 PrimaryExpression parsePrimaryExpression() 4353 { 4354 mixin(traceEnterAndExit!(__FUNCTION__)); 4355 auto node = allocator.make!PrimaryExpression; 4356 if (!moreTokens()) 4357 { 4358 error("Expected primary statement instead of EOF"); 4359 return null; 4360 } 4361 switch (current.type) 4362 { 4363 case tok!".": 4364 node.dot = advance(); 4365 goto case; 4366 case tok!"identifier": 4367 if (peekIs(tok!"=>")) 4368 mixin(parseNodeQ!(`node.functionLiteralExpression`, `FunctionLiteralExpression`)); 4369 else 4370 mixin(parseNodeQ!(`node.identifierOrTemplateInstance`, `IdentifierOrTemplateInstance`)); 4371 break; 4372 case tok!"immutable": 4373 case tok!"const": 4374 case tok!"inout": 4375 case tok!"shared": 4376 advance(); 4377 expect(tok!"("); 4378 mixin(parseNodeQ!(`node.type`, `Type`)); 4379 expect(tok!")"); 4380 expect(tok!"."); 4381 const ident = expect(tok!"identifier"); 4382 if (ident !is null) 4383 node.primary = *ident; 4384 break; 4385 foreach (B; BasicTypes) { case B: } 4386 node.basicType = advance(); 4387 if (currentIs(tok!".")) 4388 { 4389 advance(); 4390 const t = expect(tok!"identifier"); 4391 if (t !is null) 4392 node.primary = *t; 4393 } 4394 else if (currentIs(tok!"(")) 4395 mixin(parseNodeQ!(`node.arguments`, `Arguments`)); 4396 break; 4397 case tok!"function": 4398 case tok!"delegate": 4399 case tok!"{": 4400 case tok!"in": 4401 case tok!"out": 4402 case tok!"body": 4403 mixin(parseNodeQ!(`node.functionLiteralExpression`, `FunctionLiteralExpression`)); 4404 break; 4405 case tok!"typeof": 4406 mixin(parseNodeQ!(`node.typeofExpression`, `TypeofExpression`)); 4407 break; 4408 case tok!"typeid": 4409 mixin(parseNodeQ!(`node.typeidExpression`, `TypeidExpression`)); 4410 break; 4411 case tok!"__vector": 4412 mixin(parseNodeQ!(`node.vector`, `Vector`)); 4413 break; 4414 case tok!"[": 4415 if (isAssociativeArrayLiteral()) 4416 mixin(parseNodeQ!(`node.assocArrayLiteral`, `AssocArrayLiteral`)); 4417 else 4418 mixin(parseNodeQ!(`node.arrayLiteral`, `ArrayLiteral`)); 4419 break; 4420 case tok!"(": 4421 immutable b = setBookmark(); 4422 skipParens(); 4423 while (isAttribute()) 4424 parseAttribute(); 4425 if (currentIsOneOf(tok!"=>", tok!"{")) 4426 { 4427 goToBookmark(b); 4428 mixin(parseNodeQ!(`node.functionLiteralExpression`, `FunctionLiteralExpression`)); 4429 } 4430 else 4431 { 4432 goToBookmark(b); 4433 advance(); 4434 mixin(parseNodeQ!(`node.expression`, `Expression`)); 4435 mixin(tokenCheck!")"); 4436 } 4437 break; 4438 case tok!"is": 4439 mixin(parseNodeQ!(`node.isExpression`, `IsExpression`)); 4440 break; 4441 case tok!"__traits": 4442 mixin(parseNodeQ!(`node.traitsExpression`, `TraitsExpression`)); 4443 break; 4444 case tok!"mixin": 4445 mixin(parseNodeQ!(`node.mixinExpression`, `MixinExpression`)); 4446 break; 4447 case tok!"import": 4448 mixin(parseNodeQ!(`node.importExpression`, `ImportExpression`)); 4449 break; 4450 case tok!"this": 4451 case tok!"super": 4452 foreach (L; Literals) { case L: } 4453 if (currentIsOneOf(tok!"stringLiteral", tok!"wstringLiteral", tok!"dstringLiteral")) 4454 { 4455 node.primary = advance(); 4456 bool alreadyWarned = false; 4457 while (currentIsOneOf(tok!"stringLiteral", tok!"wstringLiteral", 4458 tok!"dstringLiteral")) 4459 { 4460 if (!alreadyWarned) 4461 { 4462 warn("Implicit concatenation of string literals"); 4463 alreadyWarned = true; 4464 } 4465 node.primary.text ~= advance().text; 4466 } 4467 } 4468 else 4469 node.primary = advance(); 4470 break; 4471 default: 4472 error("Primary expression expected"); 4473 return null; 4474 } 4475 return node; 4476 } 4477 4478 /** 4479 * Parses a Register 4480 * 4481 * $(GRAMMAR $(RULEDEF register): 4482 * $(LITERAL Identifier) 4483 * | $(LITERAL Identifier) $(LITERAL '$(LPAREN)') $(LITERAL IntegerLiteral) $(LITERAL '$(RPAREN)') 4484 * ;) 4485 */ 4486 Register parseRegister() 4487 { 4488 mixin(traceEnterAndExit!(__FUNCTION__)); 4489 auto node = allocator.make!Register; 4490 const ident = expect(tok!"identifier"); 4491 mixin(nullCheck!`ident`); 4492 node.identifier = *ident; 4493 if (currentIs(tok!"(")) 4494 { 4495 advance(); 4496 const intLit = expect(tok!"intLiteral"); 4497 mixin(nullCheck!`intLit`); 4498 node.intLiteral = *intLit; 4499 expect(tok!")"); 4500 } 4501 return node; 4502 } 4503 4504 /** 4505 * Parses a RelExpression 4506 * 4507 * $(GRAMMAR $(RULEDEF relExpression): 4508 * $(RULE shiftExpression) 4509 * | $(RULE relExpression) $(RULE relOperator) $(RULE shiftExpression) 4510 * ; 4511 *$(RULEDEF relOperator): 4512 * $(LITERAL '<') 4513 * | $(LITERAL '<=') 4514 * | $(LITERAL '>') 4515 * | $(LITERAL '>=') 4516 * | $(LITERAL '!<>=') 4517 * | $(LITERAL '!<>') 4518 * | $(LITERAL '<>') 4519 * | $(LITERAL '<>=') 4520 * | $(LITERAL '!>') 4521 * | $(LITERAL '!>=') 4522 * | $(LITERAL '!<') 4523 * | $(LITERAL '!<=') 4524 * ;) 4525 */ 4526 ExpressionNode parseRelExpression(ExpressionNode shift) 4527 { 4528 mixin (traceEnterAndExit!(__FUNCTION__)); 4529 return parseLeftAssocBinaryExpression!(RelExpression, ShiftExpression, 4530 tok!"<", tok!"<=", tok!">", tok!">=", tok!"!<>=", tok!"!<>", 4531 tok!"<>", tok!"<>=", tok!"!>", tok!"!>=", tok!"!>=", tok!"!<", 4532 tok!"!<=")(shift); 4533 } 4534 4535 /** 4536 * Parses a ReturnStatement 4537 * 4538 * $(GRAMMAR $(RULEDEF returnStatement): 4539 * $(LITERAL 'return') $(RULE expression)? $(LITERAL ';') 4540 * ;) 4541 */ 4542 ReturnStatement parseReturnStatement() 4543 { 4544 mixin(traceEnterAndExit!(__FUNCTION__)); 4545 auto node = allocator.make!ReturnStatement; 4546 const start = expect(tok!"return"); 4547 mixin(nullCheck!`start`); 4548 node.startLocation = start.index; 4549 if (!currentIs(tok!";")) 4550 mixin(parseNodeQ!(`node.expression`, `Expression`)); 4551 const semicolon = expect(tok!";"); 4552 mixin(nullCheck!`semicolon`); 4553 node.endLocation = semicolon.index; 4554 return node; 4555 } 4556 4557 /** 4558 * Parses a ScopeGuardStatement 4559 * 4560 * $(GRAMMAR $(RULEDEF scopeGuardStatement): 4561 * $(LITERAL 'scope') $(LITERAL '$(LPAREN)') $(LITERAL Identifier) $(LITERAL '$(RPAREN)') $(RULE statementNoCaseNoDefault) 4562 * ;) 4563 */ 4564 ScopeGuardStatement parseScopeGuardStatement() 4565 { 4566 mixin(traceEnterAndExit!(__FUNCTION__)); 4567 auto node = allocator.make!ScopeGuardStatement; 4568 expect(tok!"scope"); 4569 expect(tok!"("); 4570 const ident = expect(tok!"identifier"); 4571 mixin(nullCheck!`ident`); 4572 node.identifier = *ident; 4573 expect(tok!")"); 4574 mixin(parseNodeQ!(`node.statementNoCaseNoDefault`, `StatementNoCaseNoDefault`)); 4575 return node; 4576 } 4577 4578 /** 4579 * Parses a SharedStaticConstructor 4580 * 4581 * $(GRAMMAR $(RULEDEF sharedStaticConstructor): 4582 * $(LITERAL 'shared') $(LITERAL 'static') $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)') $(RULE MemberFunctionAttribute)* ($(RULE functionBody) | $(LITERAL ";")) 4583 * ;) 4584 */ 4585 SharedStaticConstructor parseSharedStaticConstructor() 4586 { 4587 mixin(traceEnterAndExit!(__FUNCTION__)); 4588 auto node = allocator.make!SharedStaticConstructor; 4589 mixin(tokenCheck!"shared"); 4590 mixin(tokenCheck!"static"); 4591 return parseStaticCtorDtorCommon(node); 4592 } 4593 4594 /** 4595 * Parses a SharedStaticDestructor 4596 * 4597 * $(GRAMMAR $(RULEDEF sharedStaticDestructor): 4598 * $(LITERAL 'shared') $(LITERAL 'static') $(LITERAL '~') $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)') $(RULE MemberFunctionAttribute)* ($(RULE functionBody) | $(LITERAL ";")) 4599 * ;) 4600 */ 4601 SharedStaticDestructor parseSharedStaticDestructor() 4602 { 4603 mixin(traceEnterAndExit!(__FUNCTION__)); 4604 auto node = allocator.make!SharedStaticDestructor; 4605 mixin(tokenCheck!"shared"); 4606 mixin(tokenCheck!"static"); 4607 mixin(tokenCheck!"~"); 4608 return parseStaticCtorDtorCommon(node); 4609 } 4610 4611 /** 4612 * Parses a ShiftExpression 4613 * 4614 * $(GRAMMAR $(RULEDEF shiftExpression): 4615 * $(RULE addExpression) 4616 * | $(RULE shiftExpression) ($(LITERAL '<<') | $(LITERAL '>>') | $(LITERAL '>>>')) $(RULE addExpression) 4617 * ;) 4618 */ 4619 ExpressionNode parseShiftExpression() 4620 { 4621 mixin(traceEnterAndExit!(__FUNCTION__)); 4622 return parseLeftAssocBinaryExpression!(ShiftExpression, AddExpression, 4623 tok!"<<", tok!">>", tok!">>>")(); 4624 } 4625 4626 /** 4627 * Parses a SingleImport 4628 * 4629 * $(GRAMMAR $(RULEDEF singleImport): 4630 * ($(LITERAL Identifier) $(LITERAL '='))? $(RULE identifierChain) 4631 * ;) 4632 */ 4633 SingleImport parseSingleImport() 4634 { 4635 mixin(traceEnterAndExit!(__FUNCTION__)); 4636 auto node = allocator.make!SingleImport; 4637 if (startsWith(tok!"identifier", tok!"=")) 4638 { 4639 node.rename = advance(); // identifier 4640 advance(); // = 4641 } 4642 mixin(parseNodeQ!(`node.identifierChain`, `IdentifierChain`)); 4643 if (node.identifierChain is null) 4644 return null; 4645 return node; 4646 } 4647 4648 /** 4649 * Parses a Statement 4650 * 4651 * $(GRAMMAR $(RULEDEF statement): 4652 * $(RULE statementNoCaseNoDefault) 4653 * | $(RULE caseStatement) 4654 * | $(RULE caseRangeStatement) 4655 * | $(RULE defaultStatement) 4656 * ;) 4657 */ 4658 Statement parseStatement() 4659 { 4660 mixin(traceEnterAndExit!(__FUNCTION__)); 4661 auto node = allocator.make!Statement; 4662 if (!moreTokens()) 4663 { 4664 error("Expected statement instead of EOF"); 4665 return null; 4666 } 4667 switch (current.type) 4668 { 4669 case tok!"case": 4670 advance(); 4671 auto argumentList = parseArgumentList(); 4672 if (argumentList is null) 4673 return null; 4674 if (argumentList.items.length == 1 && startsWith(tok!":", tok!"..")) 4675 node.caseRangeStatement = parseCaseRangeStatement(argumentList.items[0]); 4676 else 4677 node.caseStatement = parseCaseStatement(argumentList); 4678 break; 4679 case tok!"default": 4680 mixin(parseNodeQ!(`node.defaultStatement`, `DefaultStatement`)); 4681 break; 4682 default: 4683 mixin(parseNodeQ!(`node.statementNoCaseNoDefault`, `StatementNoCaseNoDefault`)); 4684 break; 4685 } 4686 return node; 4687 } 4688 4689 /** 4690 * Parses a StatementNoCaseNoDefault 4691 * 4692 * $(GRAMMAR $(RULEDEF statementNoCaseNoDefault): 4693 * $(RULE labeledStatement) 4694 * | $(RULE blockStatement) 4695 * | $(RULE ifStatement) 4696 * | $(RULE whileStatement) 4697 * | $(RULE doStatement) 4698 * | $(RULE forStatement) 4699 * | $(RULE foreachStatement) 4700 * | $(RULE switchStatement) 4701 * | $(RULE finalSwitchStatement) 4702 * | $(RULE continueStatement) 4703 * | $(RULE breakStatement) 4704 * | $(RULE returnStatement) 4705 * | $(RULE gotoStatement) 4706 * | $(RULE withStatement) 4707 * | $(RULE synchronizedStatement) 4708 * | $(RULE tryStatement) 4709 * | $(RULE throwStatement) 4710 * | $(RULE scopeGuardStatement) 4711 * | $(RULE asmStatement) 4712 * | $(RULE conditionalStatement) 4713 * | $(RULE staticAssertStatement) 4714 * | $(RULE versionSpecification) 4715 * | $(RULE debugSpecification) 4716 * | $(RULE expressionStatement) 4717 * ;) 4718 */ 4719 StatementNoCaseNoDefault parseStatementNoCaseNoDefault() 4720 { 4721 mixin(traceEnterAndExit!(__FUNCTION__)); 4722 auto node = allocator.make!StatementNoCaseNoDefault; 4723 node.startLocation = current().index; 4724 switch (current.type) 4725 { 4726 case tok!"{": 4727 mixin(parseNodeQ!(`node.blockStatement`, `BlockStatement`)); 4728 break; 4729 case tok!"if": 4730 mixin(parseNodeQ!(`node.ifStatement`, `IfStatement`)); 4731 break; 4732 case tok!"while": 4733 mixin(parseNodeQ!(`node.whileStatement`, `WhileStatement`)); 4734 break; 4735 case tok!"do": 4736 mixin(parseNodeQ!(`node.doStatement`, `DoStatement`)); 4737 break; 4738 case tok!"for": 4739 mixin(parseNodeQ!(`node.forStatement`, `ForStatement`)); 4740 break; 4741 case tok!"foreach": 4742 case tok!"foreach_reverse": 4743 mixin(parseNodeQ!(`node.foreachStatement`, `ForeachStatement`)); 4744 break; 4745 case tok!"switch": 4746 mixin(parseNodeQ!(`node.switchStatement`, `SwitchStatement`)); 4747 break; 4748 case tok!"continue": 4749 mixin(parseNodeQ!(`node.continueStatement`, `ContinueStatement`)); 4750 break; 4751 case tok!"break": 4752 mixin(parseNodeQ!(`node.breakStatement`, `BreakStatement`)); 4753 break; 4754 case tok!"return": 4755 mixin(parseNodeQ!(`node.returnStatement`, `ReturnStatement`)); 4756 break; 4757 case tok!"goto": 4758 mixin(parseNodeQ!(`node.gotoStatement`, `GotoStatement`)); 4759 break; 4760 case tok!"with": 4761 mixin(parseNodeQ!(`node.withStatement`, `WithStatement`)); 4762 break; 4763 case tok!"synchronized": 4764 mixin(parseNodeQ!(`node.synchronizedStatement`, `SynchronizedStatement`)); 4765 break; 4766 case tok!"try": 4767 mixin(parseNodeQ!(`node.tryStatement`, `TryStatement`)); 4768 break; 4769 case tok!"throw": 4770 mixin(parseNodeQ!(`node.throwStatement`, `ThrowStatement`)); 4771 break; 4772 case tok!"scope": 4773 mixin(parseNodeQ!(`node.scopeGuardStatement`, `ScopeGuardStatement`)); 4774 break; 4775 case tok!"asm": 4776 mixin(parseNodeQ!(`node.asmStatement`, `AsmStatement`)); 4777 break; 4778 case tok!"final": 4779 if (peekIs(tok!"switch")) 4780 { 4781 mixin(parseNodeQ!(`node.finalSwitchStatement`, `FinalSwitchStatement`)); 4782 break; 4783 } 4784 else 4785 { 4786 error(`"switch" expected`); 4787 return null; 4788 } 4789 case tok!"debug": 4790 if (peekIs(tok!"=")) 4791 mixin(parseNodeQ!(`node.debugSpecification`, `DebugSpecification`)); 4792 else 4793 mixin(parseNodeQ!(`node.conditionalStatement`, `ConditionalStatement`)); 4794 break; 4795 case tok!"version": 4796 if (peekIs(tok!"=")) 4797 mixin(parseNodeQ!(`node.versionSpecification`, `VersionSpecification`)); 4798 else 4799 mixin(parseNodeQ!(`node.conditionalStatement`, `ConditionalStatement`)); 4800 break; 4801 case tok!"static": 4802 if (peekIs(tok!"if")) 4803 mixin(parseNodeQ!(`node.conditionalStatement`, `ConditionalStatement`)); 4804 else if (peekIs(tok!"assert")) 4805 mixin(parseNodeQ!(`node.staticAssertStatement`, `StaticAssertStatement`)); 4806 else 4807 { 4808 error("'if' or 'assert' expected."); 4809 return null; 4810 } 4811 break; 4812 case tok!"identifier": 4813 if (peekIs(tok!":")) 4814 { 4815 mixin(parseNodeQ!(`node.labeledStatement`, `LabeledStatement`)); 4816 break; 4817 } 4818 goto default; 4819 case tok!"delete": 4820 case tok!"assert": 4821 default: 4822 mixin(parseNodeQ!(`node.expressionStatement`, `ExpressionStatement`)); 4823 break; 4824 } 4825 node.endLocation = tokens[index - 1].index; 4826 return node; 4827 } 4828 4829 /** 4830 * Parses a StaticAssertDeclaration 4831 * 4832 * $(GRAMMAR $(RULEDEF staticAssertDeclaration): 4833 * $(RULE staticAssertStatement) 4834 * ;) 4835 */ 4836 StaticAssertDeclaration parseStaticAssertDeclaration() 4837 { 4838 mixin(traceEnterAndExit!(__FUNCTION__)); 4839 mixin(simpleParse!(StaticAssertDeclaration, 4840 "staticAssertStatement|parseStaticAssertStatement")); 4841 } 4842 4843 4844 /** 4845 * Parses a StaticAssertStatement 4846 * 4847 * $(GRAMMAR $(RULEDEF staticAssertStatement): 4848 * $(LITERAL 'static') $(RULE assertExpression) $(LITERAL ';') 4849 * ;) 4850 */ 4851 StaticAssertStatement parseStaticAssertStatement() 4852 { 4853 mixin(traceEnterAndExit!(__FUNCTION__)); 4854 mixin(simpleParse!(StaticAssertStatement, 4855 tok!"static", "assertExpression|parseAssertExpression", tok!";")); 4856 } 4857 4858 /** 4859 * Parses a StaticConstructor 4860 * 4861 * $(GRAMMAR $(RULEDEF staticConstructor): 4862 * $(LITERAL 'static') $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)') $(RULE memberFunctionAttribute)* ($(RULE functionBody) | $(LITERAL ";")) 4863 * ;) 4864 */ 4865 StaticConstructor parseStaticConstructor() 4866 { 4867 mixin(traceEnterAndExit!(__FUNCTION__)); 4868 auto node = allocator.make!StaticConstructor; 4869 mixin(tokenCheck!"static"); 4870 return parseStaticCtorDtorCommon(node); 4871 } 4872 4873 /** 4874 * Parses a StaticDestructor 4875 * 4876 * $(GRAMMAR $(RULEDEF staticDestructor): 4877 * $(LITERAL 'static') $(LITERAL '~') $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)') $(RULE memberFunctionAttribute)* ($(RULE functionBody) | $(LITERAL ";")) 4878 * ;) 4879 */ 4880 StaticDestructor parseStaticDestructor() 4881 { 4882 mixin(traceEnterAndExit!(__FUNCTION__)); 4883 auto node = allocator.make!StaticDestructor; 4884 mixin(tokenCheck!"static"); 4885 mixin(tokenCheck!"~"); 4886 return parseStaticCtorDtorCommon(node); 4887 } 4888 4889 /** 4890 * Parses an StaticIfCondition 4891 * 4892 * $(GRAMMAR $(RULEDEF staticIfCondition): 4893 * $(LITERAL 'static') $(LITERAL 'if') $(LITERAL '$(LPAREN)') $(RULE assignExpression) $(LITERAL '$(RPAREN)') 4894 * ;) 4895 */ 4896 StaticIfCondition parseStaticIfCondition() 4897 { 4898 mixin(traceEnterAndExit!(__FUNCTION__)); 4899 mixin(simpleParse!(StaticIfCondition, tok!"static", tok!"if", tok!"(", 4900 "assignExpression|parseAssignExpression", tok!")")); 4901 } 4902 4903 /** 4904 * Parses a StorageClass 4905 * 4906 * $(GRAMMAR $(RULEDEF storageClass): 4907 * $(RULE alignAttribute) 4908 * | $(RULE linkageAttribute) 4909 * | $(RULE atAttribute) 4910 * | $(RULE typeConstructor) 4911 * | $(RULE deprecated) 4912 * | $(LITERAL 'abstract') 4913 * | $(LITERAL 'auto') 4914 * | $(LITERAL 'enum') 4915 * | $(LITERAL 'extern') 4916 * | $(LITERAL 'final') 4917 * | $(LITERAL 'nothrow') 4918 * | $(LITERAL 'override') 4919 * | $(LITERAL 'pure') 4920 * | $(LITERAL 'ref') 4921 * | $(LITERAL '___gshared') 4922 * | $(LITERAL 'scope') 4923 * | $(LITERAL 'static') 4924 * | $(LITERAL 'synchronized') 4925 * ;) 4926 */ 4927 StorageClass parseStorageClass() 4928 { 4929 auto node = allocator.make!StorageClass; 4930 switch (current.type) 4931 { 4932 case tok!"@": 4933 mixin(parseNodeQ!(`node.atAttribute`, `AtAttribute`)); 4934 break; 4935 case tok!"deprecated": 4936 mixin(parseNodeQ!(`node.deprecated_`, `Deprecated`)); 4937 break; 4938 case tok!"align": 4939 mixin(parseNodeQ!(`node.alignAttribute`, `AlignAttribute`)); 4940 break; 4941 case tok!"extern": 4942 if (peekIs(tok!"(")) 4943 { 4944 mixin(parseNodeQ!(`node.linkageAttribute`, `LinkageAttribute`)); 4945 break; 4946 } 4947 else goto case; 4948 case tok!"const": 4949 case tok!"immutable": 4950 case tok!"inout": 4951 case tok!"shared": 4952 case tok!"abstract": 4953 case tok!"auto": 4954 case tok!"enum": 4955 case tok!"final": 4956 case tok!"nothrow": 4957 case tok!"override": 4958 case tok!"pure": 4959 case tok!"ref": 4960 case tok!"__gshared": 4961 case tok!"scope": 4962 case tok!"static": 4963 case tok!"synchronized": 4964 node.token = advance(); 4965 break; 4966 default: 4967 error(`Storage class expected`); 4968 return null; 4969 } 4970 return node; 4971 } 4972 4973 /** 4974 * Parses a StructBody 4975 * 4976 * $(GRAMMAR $(RULEDEF structBody): 4977 * $(LITERAL '{') $(RULE declaration)* $(LITERAL '}') 4978 * ;) 4979 */ 4980 StructBody parseStructBody() 4981 { 4982 mixin(traceEnterAndExit!(__FUNCTION__)); 4983 auto node = allocator.make!StructBody; 4984 const start = expect(tok!"{"); 4985 if (start !is null) node.startLocation = start.index; 4986 StackBuffer declarations; 4987 while (!currentIs(tok!"}") && moreTokens()) 4988 { 4989 immutable c = allocator.setCheckpoint(); 4990 if (!declarations.put(parseDeclaration(true, true))) 4991 allocator.rollback(c); 4992 } 4993 ownArray(node.declarations, declarations); 4994 const end = expect(tok!"}"); 4995 if (end !is null) node.endLocation = end.index; 4996 return node; 4997 } 4998 4999 /** 5000 * Parses a StructDeclaration 5001 * 5002 * $(GRAMMAR $(RULEDEF structDeclaration): 5003 * $(LITERAL 'struct') $(LITERAL Identifier)? ($(RULE templateParameters) $(RULE constraint)? $(RULE structBody) | ($(RULE structBody) | $(LITERAL ';'))) 5004 * ;) 5005 */ 5006 StructDeclaration parseStructDeclaration() 5007 { 5008 mixin(traceEnterAndExit!(__FUNCTION__)); 5009 auto node = allocator.make!StructDeclaration; 5010 const t = expect(tok!"struct"); 5011 if (currentIs(tok!"identifier")) 5012 node.name = advance(); 5013 else 5014 { 5015 node.name.line = t.line; 5016 node.name.column = t.column; 5017 } 5018 node.comment = comment; 5019 comment = null; 5020 5021 if (currentIs(tok!"(")) 5022 { 5023 mixin(parseNodeQ!(`node.templateParameters`, `TemplateParameters`)); 5024 if (currentIs(tok!"if")) 5025 mixin(parseNodeQ!(`node.constraint`, `Constraint`)); 5026 mixin(parseNodeQ!(`node.structBody`, `StructBody`)); 5027 } 5028 else if (currentIs(tok!"{")) 5029 { 5030 mixin(parseNodeQ!(`node.structBody`, `StructBody`)); 5031 } 5032 else if (currentIs(tok!";")) 5033 advance(); 5034 else 5035 { 5036 error("Template Parameters, Struct Body, or Semicolon expected"); 5037 return null; 5038 } 5039 return node; 5040 } 5041 5042 /** 5043 * Parses an StructInitializer 5044 * 5045 * $(GRAMMAR $(RULEDEF structInitializer): 5046 * $(LITERAL '{') $(RULE structMemberInitializers)? $(LITERAL '}') 5047 * ;) 5048 */ 5049 StructInitializer parseStructInitializer() 5050 { 5051 mixin(traceEnterAndExit!(__FUNCTION__)); 5052 auto node = allocator.make!StructInitializer; 5053 const a = expect(tok!"{"); 5054 node.startLocation = a.index; 5055 if (currentIs(tok!"}")) 5056 { 5057 node.endLocation = current.index; 5058 advance(); 5059 } 5060 else 5061 { 5062 mixin(parseNodeQ!(`node.structMemberInitializers`, `StructMemberInitializers`)); 5063 const e = expect(tok!"}"); 5064 mixin (nullCheck!`e`); 5065 node.endLocation = e.index; 5066 } 5067 return node; 5068 } 5069 5070 /** 5071 * Parses a StructMemberInitializer 5072 * 5073 * $(GRAMMAR $(RULEDEF structMemberInitializer): 5074 * ($(LITERAL Identifier) $(LITERAL ':'))? $(RULE nonVoidInitializer) 5075 * ;) 5076 */ 5077 StructMemberInitializer parseStructMemberInitializer() 5078 { 5079 mixin(traceEnterAndExit!(__FUNCTION__)); 5080 auto node = allocator.make!StructMemberInitializer; 5081 if (startsWith(tok!"identifier", tok!":")) 5082 { 5083 node.identifier = tokens[index++]; 5084 index++; 5085 } 5086 mixin(parseNodeQ!(`node.nonVoidInitializer`, `NonVoidInitializer`)); 5087 return node; 5088 } 5089 5090 /** 5091 * Parses StructMemberInitializers 5092 * 5093 * $(GRAMMAR $(RULEDEF structMemberInitializers): 5094 * $(RULE structMemberInitializer) ($(LITERAL ',') $(RULE structMemberInitializer)?)* 5095 * ;) 5096 */ 5097 StructMemberInitializers parseStructMemberInitializers() 5098 { 5099 mixin(traceEnterAndExit!(__FUNCTION__)); 5100 auto node = allocator.make!StructMemberInitializers; 5101 StackBuffer structMemberInitializers; 5102 do 5103 { 5104 auto c = allocator.setCheckpoint(); 5105 if (!structMemberInitializers.put(parseStructMemberInitializer())) 5106 allocator.rollback(c); 5107 if (currentIs(tok!",")) 5108 advance(); 5109 else 5110 break; 5111 } while (moreTokens() && !currentIs(tok!"}")); 5112 ownArray(node.structMemberInitializers, structMemberInitializers); 5113 return node; 5114 } 5115 5116 /** 5117 * Parses a SwitchStatement 5118 * 5119 * $(GRAMMAR $(RULEDEF switchStatement): 5120 * $(LITERAL 'switch') $(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)') $(RULE statement) 5121 * ;) 5122 */ 5123 SwitchStatement parseSwitchStatement() 5124 { 5125 mixin(traceEnterAndExit!(__FUNCTION__)); 5126 auto node = allocator.make!SwitchStatement; 5127 expect(tok!"switch"); 5128 expect(tok!"("); 5129 mixin(parseNodeQ!(`node.expression`, `Expression`)); 5130 expect(tok!")"); 5131 mixin(parseNodeQ!(`node.statement`, `Statement`)); 5132 return node; 5133 } 5134 5135 /** 5136 * Parses a Symbol 5137 * 5138 * $(GRAMMAR $(RULEDEF symbol): 5139 * $(LITERAL '.')? $(RULE identifierOrTemplateChain) 5140 * ;) 5141 */ 5142 Symbol parseSymbol() 5143 { 5144 mixin(traceEnterAndExit!(__FUNCTION__)); 5145 auto node = allocator.make!Symbol; 5146 if (currentIs(tok!".")) 5147 { 5148 node.dot = true; 5149 advance(); 5150 } 5151 mixin(parseNodeQ!(`node.identifierOrTemplateChain`, `IdentifierOrTemplateChain`)); 5152 return node; 5153 } 5154 5155 /** 5156 * Parses a SynchronizedStatement 5157 * 5158 * $(GRAMMAR $(RULEDEF synchronizedStatement): 5159 * $(LITERAL 'synchronized') ($(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)'))? $(RULE statementNoCaseNoDefault) 5160 * ;) 5161 */ 5162 SynchronizedStatement parseSynchronizedStatement() 5163 { 5164 mixin(traceEnterAndExit!(__FUNCTION__)); 5165 auto node = allocator.make!SynchronizedStatement; 5166 expect(tok!"synchronized"); 5167 if (currentIs(tok!"(")) 5168 { 5169 expect(tok!"("); 5170 mixin(parseNodeQ!(`node.expression`, `Expression`)); 5171 expect(tok!")"); 5172 } 5173 mixin(parseNodeQ!(`node.statementNoCaseNoDefault`, `StatementNoCaseNoDefault`)); 5174 return node; 5175 } 5176 5177 /** 5178 * Parses a TemplateAliasParameter 5179 * 5180 * $(GRAMMAR $(RULEDEF templateAliasParameter): 5181 * $(LITERAL 'alias') $(RULE type)? $(LITERAL Identifier) ($(LITERAL ':') ($(RULE type) | $(RULE assignExpression)))? ($(LITERAL '=') ($(RULE type) | $(RULE assignExpression)))? 5182 * ;) 5183 */ 5184 TemplateAliasParameter parseTemplateAliasParameter() 5185 { 5186 mixin(traceEnterAndExit!(__FUNCTION__)); 5187 auto node = allocator.make!TemplateAliasParameter; 5188 expect(tok!"alias"); 5189 if (currentIs(tok!"identifier") && !peekIs(tok!".")) 5190 { 5191 if (peekIsOneOf(tok!",", tok!")", tok!"=", tok!":")) 5192 node.identifier = advance(); 5193 else 5194 goto type; 5195 } 5196 else 5197 { 5198 type: 5199 mixin(parseNodeQ!(`node.type`, `Type`)); 5200 const ident = expect(tok!"identifier"); 5201 mixin(nullCheck!`ident`); 5202 node.identifier = *ident; 5203 } 5204 5205 if (currentIs(tok!":")) 5206 { 5207 advance(); 5208 if (isType()) 5209 mixin(parseNodeQ!(`node.colonType`, `Type`)); 5210 else 5211 mixin(parseNodeQ!(`node.colonExpression`, `AssignExpression`)); 5212 } 5213 if (currentIs(tok!"=")) 5214 { 5215 advance(); 5216 if (isType()) 5217 mixin(parseNodeQ!(`node.assignType`, `Type`)); 5218 else 5219 mixin(parseNodeQ!(`node.assignExpression`, `AssignExpression`)); 5220 } 5221 return node; 5222 } 5223 5224 /** 5225 * Parses a TemplateArgument 5226 * 5227 * $(GRAMMAR $(RULEDEF templateArgument): 5228 * $(RULE type) 5229 * | $(RULE assignExpression) 5230 * ;) 5231 */ 5232 TemplateArgument parseTemplateArgument() 5233 { 5234 mixin(traceEnterAndExit!(__FUNCTION__)); 5235 if (suppressedErrorCount > MAX_ERRORS) return null; 5236 auto node = allocator.make!TemplateArgument; 5237 immutable b = setBookmark(); 5238 auto t = parseType(); 5239 if (t !is null && currentIsOneOf(tok!",", tok!")")) 5240 { 5241 abandonBookmark(b); 5242 node.type = t; 5243 } 5244 else 5245 { 5246 goToBookmark(b); 5247 mixin(parseNodeQ!(`node.assignExpression`, `AssignExpression`)); 5248 } 5249 return node; 5250 } 5251 5252 /** 5253 * Parses a TemplateArgumentList 5254 * 5255 * $(GRAMMAR $(RULEDEF templateArgumentList): 5256 * $(RULE templateArgument) ($(LITERAL ',') $(RULE templateArgument)?)* 5257 * ;) 5258 */ 5259 TemplateArgumentList parseTemplateArgumentList() 5260 { 5261 mixin(traceEnterAndExit!(__FUNCTION__)); 5262 return parseCommaSeparatedRule!(TemplateArgumentList, TemplateArgument)(true); 5263 } 5264 5265 /** 5266 * Parses TemplateArguments 5267 * 5268 * $(GRAMMAR $(RULEDEF templateArguments): 5269 * $(LITERAL '!') ($(LITERAL '$(LPAREN)') $(RULE templateArgumentList)? $(LITERAL '$(RPAREN)')) | $(RULE templateSingleArgument) 5270 * ;) 5271 */ 5272 TemplateArguments parseTemplateArguments() 5273 { 5274 mixin(traceEnterAndExit!(__FUNCTION__)); 5275 if (suppressedErrorCount > MAX_ERRORS) return null; 5276 auto node = allocator.make!TemplateArguments; 5277 expect(tok!"!"); 5278 if (currentIs(tok!"(")) 5279 { 5280 advance(); 5281 if (!currentIs(tok!")")) 5282 mixin(parseNodeQ!(`node.templateArgumentList`, `TemplateArgumentList`)); 5283 mixin(tokenCheck!")"); 5284 } 5285 else 5286 mixin(parseNodeQ!(`node.templateSingleArgument`, `TemplateSingleArgument`)); 5287 return node; 5288 } 5289 5290 /** 5291 * Parses a TemplateDeclaration 5292 * 5293 * $(GRAMMAR $(RULEDEF templateDeclaration): 5294 * $(LITERAL 'template') $(LITERAL Identifier) $(RULE templateParameters) $(RULE constraint)? $(LITERAL '{') $(RULE declaration)* $(LITERAL '}') 5295 * ;) 5296 */ 5297 TemplateDeclaration parseTemplateDeclaration() 5298 { 5299 mixin(traceEnterAndExit!(__FUNCTION__)); 5300 auto node = allocator.make!TemplateDeclaration; 5301 node.comment = comment; 5302 comment = null; 5303 expect(tok!"template"); 5304 const ident = expect(tok!"identifier"); 5305 mixin(nullCheck!`ident`); 5306 node.name = *ident; 5307 mixin(parseNodeQ!(`node.templateParameters`, `TemplateParameters`)); 5308 if (currentIs(tok!"if")) 5309 mixin(parseNodeQ!(`node.constraint`, `Constraint`)); 5310 const start = expect(tok!"{"); 5311 mixin(nullCheck!`start`); 5312 node.startLocation = start.index; 5313 StackBuffer declarations; 5314 while (moreTokens() && !currentIs(tok!"}")) 5315 { 5316 immutable c = allocator.setCheckpoint(); 5317 if (!declarations.put(parseDeclaration(true, true))) 5318 allocator.rollback(c); 5319 } 5320 ownArray(node.declarations, declarations); 5321 const end = expect(tok!"}"); 5322 if (end !is null) node.endLocation = end.index; 5323 return node; 5324 } 5325 5326 /** 5327 * Parses a TemplateInstance 5328 * 5329 * $(GRAMMAR $(RULEDEF templateInstance): 5330 * $(LITERAL Identifier) $(RULE templateArguments) 5331 * ;) 5332 */ 5333 TemplateInstance parseTemplateInstance() 5334 { 5335 mixin(traceEnterAndExit!(__FUNCTION__)); 5336 if (suppressedErrorCount > MAX_ERRORS) return null; 5337 auto node = allocator.make!TemplateInstance; 5338 const ident = expect(tok!"identifier"); 5339 mixin(nullCheck!`ident`); 5340 node.identifier = *ident; 5341 mixin(parseNodeQ!(`node.templateArguments`, `TemplateArguments`)); 5342 if (node.templateArguments is null) 5343 return null; 5344 return node; 5345 } 5346 5347 /** 5348 * Parses a TemplateMixinExpression 5349 * 5350 * $(GRAMMAR $(RULEDEF templateMixinExpression): 5351 * $(LITERAL 'mixin') $(RULE mixinTemplateName) $(RULE templateArguments)? $(LITERAL Identifier)? 5352 * ;) 5353 */ 5354 TemplateMixinExpression parseTemplateMixinExpression() 5355 { 5356 mixin(traceEnterAndExit!(__FUNCTION__)); 5357 auto node = allocator.make!TemplateMixinExpression; 5358 mixin(tokenCheck!"mixin"); 5359 mixin(parseNodeQ!(`node.mixinTemplateName`, `MixinTemplateName`)); 5360 if (currentIs(tok!"!")) 5361 mixin(parseNodeQ!(`node.templateArguments`, `TemplateArguments`)); 5362 if (currentIs(tok!"identifier")) 5363 node.identifier = advance(); 5364 return node; 5365 } 5366 5367 /** 5368 * Parses a TemplateParameter 5369 * 5370 * $(GRAMMAR $(RULEDEF templateParameter): 5371 * $(RULE templateTypeParameter) 5372 * | $(RULE templateValueParameter) 5373 * | $(RULE templateAliasParameter) 5374 * | $(RULE templateTupleParameter) 5375 * | $(RULE templateThisParameter) 5376 * ;) 5377 */ 5378 TemplateParameter parseTemplateParameter() 5379 { 5380 mixin(traceEnterAndExit!(__FUNCTION__)); 5381 auto node = allocator.make!TemplateParameter; 5382 switch (current.type) 5383 { 5384 case tok!"alias": 5385 mixin(parseNodeQ!(`node.templateAliasParameter`, `TemplateAliasParameter`)); 5386 break; 5387 case tok!"identifier": 5388 if (peekIs(tok!"...")) 5389 mixin(parseNodeQ!(`node.templateTupleParameter`, `TemplateTupleParameter`)); 5390 else if (peekIsOneOf(tok!":", tok!"=", tok!",", tok!")")) 5391 mixin(parseNodeQ!(`node.templateTypeParameter`, `TemplateTypeParameter`)); 5392 else 5393 mixin(parseNodeQ!(`node.templateValueParameter`, `TemplateValueParameter`)); 5394 break; 5395 case tok!"this": 5396 mixin(parseNodeQ!(`node.templateThisParameter`, `TemplateThisParameter`)); 5397 break; 5398 default: 5399 mixin(parseNodeQ!(`node.templateValueParameter`, `TemplateValueParameter`)); 5400 break; 5401 } 5402 return node; 5403 } 5404 5405 /** 5406 * Parses a TemplateParameterList 5407 * 5408 * $(GRAMMAR $(RULEDEF templateParameterList): 5409 * $(RULE templateParameter) ($(LITERAL ',') $(RULE templateParameter)?)* $(LITERAL ',')? 5410 * ;) 5411 */ 5412 TemplateParameterList parseTemplateParameterList() 5413 { 5414 mixin(traceEnterAndExit!(__FUNCTION__)); 5415 return parseCommaSeparatedRule!(TemplateParameterList, TemplateParameter)(true); 5416 } 5417 5418 /** 5419 * Parses TemplateParameters 5420 * 5421 * $(GRAMMAR $(RULEDEF templateParameters): 5422 * $(LITERAL '$(LPAREN)') $(RULE templateParameterList)? $(LITERAL '$(RPAREN)') 5423 * ;) 5424 */ 5425 TemplateParameters parseTemplateParameters() 5426 { 5427 mixin(traceEnterAndExit!(__FUNCTION__)); 5428 auto node = allocator.make!TemplateParameters; 5429 mixin(tokenCheck!"("); 5430 if (!currentIs(tok!")")) 5431 mixin(parseNodeQ!(`node.templateParameterList`, `TemplateParameterList`)); 5432 mixin(tokenCheck!")"); 5433 return node; 5434 } 5435 5436 /** 5437 * Parses a TemplateSingleArgument 5438 * 5439 * $(GRAMMAR $(RULEDEF templateSingleArgument): 5440 * $(RULE builtinType) 5441 * | $(LITERAL Identifier) 5442 * | $(LITERAL CharacterLiteral) 5443 * | $(LITERAL StringLiteral) 5444 * | $(LITERAL IntegerLiteral) 5445 * | $(LITERAL FloatLiteral) 5446 * | $(LITERAL '_true') 5447 * | $(LITERAL '_false') 5448 * | $(LITERAL '_null') 5449 * | $(LITERAL 'this') 5450 * | $(LITERAL '___DATE__') 5451 * | $(LITERAL '___TIME__') 5452 * | $(LITERAL '___TIMESTAMP__') 5453 * | $(LITERAL '___VENDOR__') 5454 * | $(LITERAL '___VERSION__') 5455 * | $(LITERAL '___FILE__') 5456 * | $(LITERAL '___LINE__') 5457 * | $(LITERAL '___MODULE__') 5458 * | $(LITERAL '___FUNCTION__') 5459 * | $(LITERAL '___PRETTY_FUNCTION__') 5460 * ;) 5461 */ 5462 TemplateSingleArgument parseTemplateSingleArgument() 5463 { 5464 mixin(traceEnterAndExit!(__FUNCTION__)); 5465 auto node = allocator.make!TemplateSingleArgument; 5466 if (!moreTokens) 5467 { 5468 error("template argument expected instead of EOF"); 5469 return null; 5470 } 5471 switch (current.type) 5472 { 5473 case tok!"this": 5474 case tok!"identifier": 5475 foreach (B; Literals) { case B: } 5476 foreach (C; BasicTypes) { case C: } 5477 node.token = advance(); 5478 break; 5479 default: 5480 error(`Invalid template argument. (Try enclosing in parenthesis?)`); 5481 return null; 5482 } 5483 return node; 5484 } 5485 5486 /** 5487 * Parses a TemplateThisParameter 5488 * 5489 * $(GRAMMAR $(RULEDEF templateThisParameter): 5490 * $(LITERAL 'this') $(RULE templateTypeParameter) 5491 * ;) 5492 */ 5493 TemplateThisParameter parseTemplateThisParameter() 5494 { 5495 mixin(traceEnterAndExit!(__FUNCTION__)); 5496 auto node = allocator.make!TemplateThisParameter; 5497 expect(tok!"this"); 5498 mixin(parseNodeQ!(`node.templateTypeParameter`, `TemplateTypeParameter`)); 5499 return node; 5500 } 5501 5502 /** 5503 * Parses an TemplateTupleParameter 5504 * 5505 * $(GRAMMAR $(RULEDEF templateTupleParameter): 5506 * $(LITERAL Identifier) $(LITERAL '...') 5507 * ;) 5508 */ 5509 TemplateTupleParameter parseTemplateTupleParameter() 5510 { 5511 mixin(traceEnterAndExit!(__FUNCTION__)); 5512 auto node = allocator.make!TemplateTupleParameter; 5513 const i = expect(tok!"identifier"); 5514 if (i is null) 5515 return null; 5516 node.identifier = *i; 5517 mixin(tokenCheck!"..."); 5518 return node; 5519 } 5520 5521 /** 5522 * Parses a TemplateTypeParameter 5523 * 5524 * $(GRAMMAR $(RULEDEF templateTypeParameter): 5525 * $(LITERAL Identifier) ($(LITERAL ':') $(RULE type))? ($(LITERAL '=') $(RULE type))? 5526 * ;) 5527 */ 5528 TemplateTypeParameter parseTemplateTypeParameter() 5529 { 5530 mixin(traceEnterAndExit!(__FUNCTION__)); 5531 auto node = allocator.make!TemplateTypeParameter; 5532 const ident = expect(tok!"identifier"); 5533 mixin(nullCheck!`ident`); 5534 node.identifier = *ident; 5535 if (currentIs(tok!":")) 5536 { 5537 advance(); 5538 mixin(parseNodeQ!(`node.colonType`, `Type`)); 5539 } 5540 if (currentIs(tok!"=")) 5541 { 5542 advance(); 5543 mixin(parseNodeQ!(`node.assignType`, `Type`)); 5544 } 5545 return node; 5546 } 5547 5548 /** 5549 * Parses a TemplateValueParameter 5550 * 5551 * $(GRAMMAR $(RULEDEF templateValueParameter): 5552 * $(RULE type) $(LITERAL Identifier) ($(LITERAL ':') $(RULE assignExpression))? $(RULE templateValueParameterDefault)? 5553 * ;) 5554 */ 5555 TemplateValueParameter parseTemplateValueParameter() 5556 { 5557 mixin(traceEnterAndExit!(__FUNCTION__)); 5558 auto node = allocator.make!TemplateValueParameter; 5559 mixin(parseNodeQ!(`node.type`, `Type`)); 5560 mixin(tokenCheck!(`node.identifier`, "identifier")); 5561 if (currentIs(tok!":")) 5562 { 5563 advance(); 5564 mixin(parseNodeQ!(`node.assignExpression`, `AssignExpression`)); 5565 } 5566 if (currentIs(tok!"=")) 5567 mixin(parseNodeQ!(`node.templateValueParameterDefault`, `TemplateValueParameterDefault`)); 5568 return node; 5569 } 5570 5571 /** 5572 * Parses a TemplateValueParameterDefault 5573 * 5574 * $(GRAMMAR $(RULEDEF templateValueParameterDefault): 5575 * $(LITERAL '=') ($(LITERAL '___FILE__') | $(LITERAL '___MODULE__') | $(LITERAL '___LINE__') | $(LITERAL '___FUNCTION__') | $(LITERAL '___PRETTY_FUNCTION__') | $(RULE assignExpression)) 5576 * ;) 5577 */ 5578 TemplateValueParameterDefault parseTemplateValueParameterDefault() 5579 { 5580 mixin(traceEnterAndExit!(__FUNCTION__)); 5581 auto node = allocator.make!TemplateValueParameterDefault; 5582 expect(tok!"="); 5583 switch (current.type) 5584 { 5585 case tok!"__FILE__": 5586 case tok!"__MODULE__": 5587 case tok!"__LINE__": 5588 case tok!"__FUNCTION__": 5589 case tok!"__PRETTY_FUNCTION__": 5590 node.token = advance(); 5591 break; 5592 default: 5593 mixin(parseNodeQ!(`node.assignExpression`, `AssignExpression`)); 5594 break; 5595 } 5596 return node; 5597 } 5598 5599 /** 5600 * Parses a TernaryExpression 5601 * 5602 * $(GRAMMAR $(RULEDEF ternaryExpression): 5603 * $(RULE orOrExpression) ($(LITERAL '?') $(RULE expression) $(LITERAL ':') $(RULE ternaryExpression))? 5604 * ;) 5605 */ 5606 ExpressionNode parseTernaryExpression() 5607 { 5608 mixin(traceEnterAndExit!(__FUNCTION__)); 5609 5610 auto orOrExpression = parseOrOrExpression(); 5611 if (orOrExpression is null) 5612 return null; 5613 if (currentIs(tok!"?")) 5614 { 5615 TernaryExpression node = allocator.make!TernaryExpression; 5616 node.orOrExpression = orOrExpression; 5617 advance(); 5618 mixin(parseNodeQ!(`node.expression`, `Expression`)); 5619 auto colon = expect(tok!":"); 5620 mixin(nullCheck!`colon`); 5621 node.colon = *colon; 5622 mixin(parseNodeQ!(`node.ternaryExpression`, `TernaryExpression`)); 5623 return node; 5624 } 5625 return orOrExpression; 5626 } 5627 5628 /** 5629 * Parses a ThrowStatement 5630 * 5631 * $(GRAMMAR $(RULEDEF throwStatement): 5632 * $(LITERAL 'throw') $(RULE expression) $(LITERAL ';') 5633 * ;) 5634 */ 5635 ThrowStatement parseThrowStatement() 5636 { 5637 mixin(traceEnterAndExit!(__FUNCTION__)); 5638 auto node = allocator.make!ThrowStatement; 5639 expect(tok!"throw"); 5640 mixin(parseNodeQ!(`node.expression`, `Expression`)); 5641 expect(tok!";"); 5642 return node; 5643 } 5644 5645 /** 5646 * Parses an TraitsExpression 5647 * 5648 * $(GRAMMAR $(RULEDEF traitsExpression): 5649 * $(LITERAL '___traits') $(LITERAL '$(LPAREN)') $(LITERAL Identifier) $(LITERAL ',') $(RULE TemplateArgumentList) $(LITERAL '$(RPAREN)') 5650 * ;) 5651 */ 5652 TraitsExpression parseTraitsExpression() 5653 { 5654 mixin(traceEnterAndExit!(__FUNCTION__)); 5655 auto node = allocator.make!TraitsExpression; 5656 mixin(tokenCheck!"__traits"); 5657 mixin(tokenCheck!"("); 5658 const ident = expect(tok!"identifier"); 5659 mixin(nullCheck!`ident`); 5660 node.identifier = *ident; 5661 if (currentIs(tok!",")) 5662 { 5663 advance(); 5664 mixin (nullCheck!`(node.templateArgumentList = parseTemplateArgumentList())`); 5665 } 5666 mixin(tokenCheck!")"); 5667 return node; 5668 } 5669 5670 /** 5671 * Parses a TryStatement 5672 * 5673 * $(GRAMMAR $(RULEDEF tryStatement): 5674 * $(LITERAL 'try') $(RULE declarationOrStatement) ($(RULE catches) | $(RULE catches) $(RULE finally) | $(RULE finally)) 5675 * ;) 5676 */ 5677 TryStatement parseTryStatement() 5678 { 5679 mixin(traceEnterAndExit!(__FUNCTION__)); 5680 auto node = allocator.make!TryStatement; 5681 expect(tok!"try"); 5682 mixin(parseNodeQ!(`node.declarationOrStatement`, `DeclarationOrStatement`)); 5683 if (currentIs(tok!"catch")) 5684 mixin(parseNodeQ!(`node.catches`, `Catches`)); 5685 if (currentIs(tok!"finally")) 5686 mixin(parseNodeQ!(`node.finally_`, `Finally`)); 5687 return node; 5688 } 5689 5690 /** 5691 * Parses a Type 5692 * 5693 * $(GRAMMAR $(RULEDEF type): 5694 * $(RULE typeConstructors)? $(RULE type2) $(RULE typeSuffix)* 5695 * ;) 5696 */ 5697 Type parseType() 5698 { 5699 mixin(traceEnterAndExit!(__FUNCTION__)); 5700 auto node = allocator.make!Type; 5701 if (!moreTokens) 5702 { 5703 error("type expected"); 5704 return null; 5705 } 5706 switch (current.type) 5707 { 5708 case tok!"const": 5709 case tok!"immutable": 5710 case tok!"inout": 5711 case tok!"shared": 5712 if (!peekIs(tok!"(")) 5713 mixin(parseNodeQ!(`node.typeConstructors`, `TypeConstructors`)); 5714 break; 5715 default: 5716 break; 5717 } 5718 mixin(parseNodeQ!(`node.type2`, `Type2`)); 5719 StackBuffer typeSuffixes; 5720 loop: while (moreTokens()) switch (current.type) 5721 { 5722 case tok!"[": 5723 // Allow this to fail because of the madness that is the 5724 // newExpression rule. Something starting with '[' may be arguments 5725 // to the newExpression instead of part of the type 5726 auto newBookmark = setBookmark(); 5727 auto c = allocator.setCheckpoint(); 5728 if (typeSuffixes.put(parseTypeSuffix())) 5729 abandonBookmark(newBookmark); 5730 else 5731 { 5732 allocator.rollback(c); 5733 goToBookmark(newBookmark); 5734 break loop; 5735 } 5736 break; 5737 case tok!"*": 5738 case tok!"delegate": 5739 case tok!"function": 5740 if (!typeSuffixes.put(parseTypeSuffix())) 5741 return null; 5742 break; 5743 default: 5744 break loop; 5745 } 5746 ownArray(node.typeSuffixes, typeSuffixes); 5747 return node; 5748 } 5749 5750 /** 5751 * Parses a Type2 5752 * 5753 * $(GRAMMAR $(RULEDEF type2): 5754 * $(RULE builtinType) 5755 * | $(RULE symbol) 5756 * | $(LITERAL 'super') $(LITERAL '.') $(RULE identifierOrTemplateChain) 5757 * | $(LITERAL 'this') $(LITERAL '.') $(RULE identifierOrTemplateChain) 5758 * | $(RULE typeofExpression) ($(LITERAL '.') $(RULE identifierOrTemplateChain))? 5759 * | $(RULE typeConstructor) $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL '$(RPAREN)') 5760 * | $(RULE vector) 5761 * ;) 5762 */ 5763 Type2 parseType2() 5764 { 5765 mixin(traceEnterAndExit!(__FUNCTION__)); 5766 auto node = allocator.make!Type2; 5767 if (!moreTokens) 5768 { 5769 error("type2 expected instead of EOF"); 5770 return null; 5771 } 5772 switch (current.type) 5773 { 5774 case tok!"identifier": 5775 case tok!".": 5776 mixin(parseNodeQ!(`node.symbol`, `Symbol`)); 5777 break; 5778 foreach (B; BasicTypes) { case B: } 5779 node.builtinType = parseBuiltinType(); 5780 break; 5781 case tok!"super": 5782 case tok!"this": 5783 node.superOrThis = advance().type; 5784 mixin(tokenCheck!"."); 5785 mixin(parseNodeQ!(`node.identifierOrTemplateChain`, `IdentifierOrTemplateChain`)); 5786 break; 5787 case tok!"typeof": 5788 if ((node.typeofExpression = parseTypeofExpression()) is null) 5789 return null; 5790 if (currentIs(tok!".")) 5791 { 5792 advance(); 5793 mixin(parseNodeQ!(`node.identifierOrTemplateChain`, `IdentifierOrTemplateChain`)); 5794 } 5795 break; 5796 case tok!"const": 5797 case tok!"immutable": 5798 case tok!"inout": 5799 case tok!"shared": 5800 node.typeConstructor = advance().type; 5801 mixin(tokenCheck!"("); 5802 mixin (nullCheck!`(node.type = parseType())`); 5803 mixin(tokenCheck!")"); 5804 break; 5805 case tok!"__vector": 5806 if ((node.vector = parseVector()) is null) 5807 return null; 5808 break; 5809 default: 5810 error("Basic type, type constructor, symbol, or typeof expected"); 5811 return null; 5812 } 5813 return node; 5814 } 5815 5816 /** 5817 * Parses a TypeConstructor 5818 * 5819 * $(GRAMMAR $(RULEDEF typeConstructor): 5820 * $(LITERAL 'const') 5821 * | $(LITERAL 'immutable') 5822 * | $(LITERAL 'inout') 5823 * | $(LITERAL 'shared') 5824 * ;) 5825 */ 5826 IdType parseTypeConstructor(bool validate = true) 5827 { 5828 mixin(traceEnterAndExit!(__FUNCTION__)); 5829 switch (current.type) 5830 { 5831 case tok!"const": 5832 case tok!"immutable": 5833 case tok!"inout": 5834 case tok!"shared": 5835 if (!peekIs(tok!"(")) 5836 return advance().type; 5837 goto default; 5838 default: 5839 if (validate) 5840 error(`"const", "immutable", "inout", or "shared" expected`); 5841 return tok!""; 5842 } 5843 } 5844 5845 /** 5846 * Parses TypeConstructors 5847 * 5848 * $(GRAMMAR $(RULEDEF typeConstructors): 5849 * $(RULE typeConstructor)+ 5850 * ;) 5851 */ 5852 IdType[] parseTypeConstructors() 5853 { 5854 mixin(traceEnterAndExit!(__FUNCTION__)); 5855 IdType[] r; 5856 while (moreTokens()) 5857 { 5858 IdType type = parseTypeConstructor(false); 5859 if (type == tok!"") 5860 break; 5861 else 5862 r ~= type; 5863 } 5864 return r; 5865 } 5866 5867 /** 5868 * Parses a TypeSpecialization 5869 * 5870 * $(GRAMMAR $(RULEDEF typeSpecialization): 5871 * $(RULE type) 5872 * | $(LITERAL 'struct') 5873 * | $(LITERAL 'union') 5874 * | $(LITERAL 'class') 5875 * | $(LITERAL 'interface') 5876 * | $(LITERAL 'enum') 5877 * | $(LITERAL 'function') 5878 * | $(LITERAL 'delegate') 5879 * | $(LITERAL 'super') 5880 * | $(LITERAL 'const') 5881 * | $(LITERAL 'immutable') 5882 * | $(LITERAL 'inout') 5883 * | $(LITERAL 'shared') 5884 * | $(LITERAL 'return') 5885 * | $(LITERAL 'typedef') 5886 * | $(LITERAL '___parameters') 5887 * ;) 5888 */ 5889 TypeSpecialization parseTypeSpecialization() 5890 { 5891 mixin(traceEnterAndExit!(__FUNCTION__)); 5892 auto node = allocator.make!TypeSpecialization; 5893 switch (current.type) 5894 { 5895 case tok!"struct": 5896 case tok!"union": 5897 case tok!"class": 5898 case tok!"interface": 5899 case tok!"enum": 5900 case tok!"function": 5901 case tok!"delegate": 5902 case tok!"super": 5903 case tok!"return": 5904 case tok!"typedef": 5905 case tok!"__parameters": 5906 case tok!"const": 5907 case tok!"immutable": 5908 case tok!"inout": 5909 case tok!"shared": 5910 if (peekIsOneOf(tok!")", tok!",")) 5911 { 5912 node.token = advance(); 5913 break; 5914 } 5915 goto default; 5916 default: 5917 mixin(parseNodeQ!(`node.type`, `Type`)); 5918 break; 5919 } 5920 return node; 5921 } 5922 5923 /** 5924 * Parses a TypeSuffix 5925 * 5926 * $(GRAMMAR $(RULEDEF typeSuffix): 5927 * $(LITERAL '*') 5928 * | $(LITERAL '[') $(RULE type)? $(LITERAL ']') 5929 * | $(LITERAL '[') $(RULE assignExpression) $(LITERAL ']') 5930 * | $(LITERAL '[') $(RULE assignExpression) $(LITERAL '..') $(RULE assignExpression) $(LITERAL ']') 5931 * | ($(LITERAL 'delegate') | $(LITERAL 'function')) $(RULE parameters) $(RULE memberFunctionAttribute)* 5932 * ;) 5933 */ 5934 TypeSuffix parseTypeSuffix() 5935 { 5936 mixin(traceEnterAndExit!(__FUNCTION__)); 5937 auto node = allocator.make!TypeSuffix; 5938 switch (current.type) 5939 { 5940 case tok!"*": 5941 node.star = advance(); 5942 return node; 5943 case tok!"[": 5944 node.array = true; 5945 advance(); 5946 if (currentIs(tok!"]")) 5947 { 5948 advance(); 5949 return node; 5950 } 5951 auto bookmark = setBookmark(); 5952 auto type = parseType(); 5953 if (type !is null && currentIs(tok!"]")) 5954 { 5955 abandonBookmark(bookmark); 5956 node.type = type; 5957 } 5958 else 5959 { 5960 goToBookmark(bookmark); 5961 mixin(parseNodeQ!(`node.low`, `AssignExpression`)); 5962 mixin (nullCheck!`node.low`); 5963 if (currentIs(tok!"..")) 5964 { 5965 advance(); 5966 mixin(parseNodeQ!(`node.high`, `AssignExpression`)); 5967 mixin (nullCheck!`node.high`); 5968 } 5969 } 5970 mixin(tokenCheck!"]"); 5971 return node; 5972 case tok!"delegate": 5973 case tok!"function": 5974 node.delegateOrFunction = advance(); 5975 mixin(parseNodeQ!(`node.parameters`, `Parameters`)); 5976 StackBuffer memberFunctionAttributes; 5977 while (currentIsMemberFunctionAttribute()) 5978 if (!memberFunctionAttributes.put(parseMemberFunctionAttribute())) 5979 return null; 5980 ownArray(node.memberFunctionAttributes, memberFunctionAttributes); 5981 return node; 5982 default: 5983 error(`"*", "[", "delegate", or "function" expected.`); 5984 return null; 5985 } 5986 } 5987 5988 /** 5989 * Parses a TypeidExpression 5990 * 5991 * $(GRAMMAR $(RULEDEF typeidExpression): 5992 * $(LITERAL 'typeid') $(LITERAL '$(LPAREN)') ($(RULE type) | $(RULE expression)) $(LITERAL '$(RPAREN)') 5993 * ;) 5994 */ 5995 TypeidExpression parseTypeidExpression() 5996 { 5997 mixin(traceEnterAndExit!(__FUNCTION__)); 5998 auto node = allocator.make!TypeidExpression; 5999 expect(tok!"typeid"); 6000 expect(tok!"("); 6001 immutable b = setBookmark(); 6002 auto t = parseType(); 6003 if (t is null || !currentIs(tok!")")) 6004 { 6005 goToBookmark(b); 6006 mixin(parseNodeQ!(`node.expression`, `Expression`)); 6007 mixin (nullCheck!`node.expression`); 6008 } 6009 else 6010 { 6011 abandonBookmark(b); 6012 node.type = t; 6013 } 6014 expect(tok!")"); 6015 return node; 6016 } 6017 6018 /** 6019 * Parses a TypeofExpression 6020 * 6021 * $(GRAMMAR $(RULEDEF typeofExpression): 6022 * $(LITERAL 'typeof') $(LITERAL '$(LPAREN)') ($(RULE expression) | $(LITERAL 'return')) $(LITERAL '$(RPAREN)') 6023 * ;) 6024 */ 6025 TypeofExpression parseTypeofExpression() 6026 { 6027 mixin(traceEnterAndExit!(__FUNCTION__)); 6028 auto node = allocator.make!TypeofExpression; 6029 expect(tok!"typeof"); 6030 expect(tok!"("); 6031 if (currentIs(tok!"return")) 6032 node.return_ = advance(); 6033 else 6034 mixin(parseNodeQ!(`node.expression`, `Expression`)); 6035 expect(tok!")"); 6036 return node; 6037 } 6038 6039 /** 6040 * Parses a UnaryExpression 6041 * 6042 * $(GRAMMAR $(RULEDEF unaryExpression): 6043 * $(RULE primaryExpression) 6044 * | $(LITERAL '&') $(RULE unaryExpression) 6045 * | $(LITERAL '!') $(RULE unaryExpression) 6046 * | $(LITERAL '*') $(RULE unaryExpression) 6047 * | $(LITERAL '+') $(RULE unaryExpression) 6048 * | $(LITERAL '-') $(RULE unaryExpression) 6049 * | $(LITERAL '~') $(RULE unaryExpression) 6050 * | $(LITERAL '++') $(RULE unaryExpression) 6051 * | $(LITERAL '--') $(RULE unaryExpression) 6052 * | $(RULE newExpression) 6053 * | $(RULE deleteExpression) 6054 * | $(RULE castExpression) 6055 * | $(RULE assertExpression) 6056 * | $(RULE functionCallExpression) 6057 * | $(RULE indexExpression) 6058 * | $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL '$(RPAREN)') $(LITERAL '.') $(RULE identifierOrTemplateInstance) 6059 * | $(RULE unaryExpression) $(LITERAL '.') $(RULE newExpression) 6060 * | $(RULE unaryExpression) $(LITERAL '.') $(RULE identifierOrTemplateInstance) 6061 * | $(RULE unaryExpression) $(LITERAL '--') 6062 * | $(RULE unaryExpression) $(LITERAL '++') 6063 * ;) 6064 */ 6065 UnaryExpression parseUnaryExpression() 6066 { 6067 mixin(traceEnterAndExit!(__FUNCTION__)); 6068 if (!moreTokens()) 6069 return null; 6070 auto node = allocator.make!UnaryExpression; 6071 switch (current.type) 6072 { 6073 case tok!"const": 6074 case tok!"immutable": 6075 case tok!"inout": 6076 case tok!"shared": 6077 immutable b = setBookmark(); 6078 if (peekIs(tok!"(")) 6079 { 6080 advance(); 6081 const past = peekPastParens(); 6082 if (past !is null && past.type == tok!".") 6083 { 6084 goToBookmark(b); 6085 goto default; 6086 } 6087 } 6088 goToBookmark(b); 6089 goto case; 6090 case tok!"scope": 6091 case tok!"pure": 6092 case tok!"nothrow": 6093 mixin(parseNodeQ!(`node.functionCallExpression`, `FunctionCallExpression`)); 6094 break; 6095 case tok!"&": 6096 case tok!"!": 6097 case tok!"*": 6098 case tok!"+": 6099 case tok!"-": 6100 case tok!"~": 6101 case tok!"++": 6102 case tok!"--": 6103 node.prefix = advance(); 6104 mixin(parseNodeQ!(`node.unaryExpression`, `UnaryExpression`)); 6105 break; 6106 case tok!"new": 6107 mixin(parseNodeQ!(`node.newExpression`, `NewExpression`)); 6108 break; 6109 case tok!"delete": 6110 mixin(parseNodeQ!(`node.deleteExpression`, `DeleteExpression`)); 6111 break; 6112 case tok!"cast": 6113 mixin(parseNodeQ!(`node.castExpression`, `CastExpression`)); 6114 break; 6115 case tok!"assert": 6116 mixin(parseNodeQ!(`node.assertExpression`, `AssertExpression`)); 6117 break; 6118 case tok!"(": 6119 // handle (type).identifier 6120 immutable b = setBookmark(); 6121 skipParens(); 6122 if (startsWith(tok!".", tok!"identifier")) 6123 { 6124 // go back to the ( 6125 goToBookmark(b); 6126 immutable b2 = setBookmark(); 6127 advance(); 6128 auto t = parseType(); 6129 if (t is null || !currentIs(tok!")")) 6130 { 6131 goToBookmark(b); 6132 goto default; 6133 } 6134 abandonBookmark(b2); 6135 node.type = t; 6136 advance(); // ) 6137 advance(); // . 6138 mixin(parseNodeQ!(`node.identifierOrTemplateInstance`, `IdentifierOrTemplateInstance`)); 6139 break; 6140 } 6141 else 6142 { 6143 // not (type).identifier, so treat as primary expression 6144 goToBookmark(b); 6145 goto default; 6146 } 6147 default: 6148 mixin(parseNodeQ!(`node.primaryExpression`, `PrimaryExpression`)); 6149 break; 6150 } 6151 6152 loop: while (moreTokens()) switch (current.type) 6153 { 6154 case tok!"!": 6155 if (peekIs(tok!"(")) 6156 { 6157 index++; 6158 const p = peekPastParens(); 6159 immutable bool jump = (currentIs(tok!"(") && p !is null && p.type == tok!"(") 6160 || peekIs(tok!"("); 6161 index--; 6162 if (jump) 6163 goto case tok!"("; 6164 else 6165 break loop; 6166 } 6167 else 6168 break loop; 6169 case tok!"(": 6170 auto newUnary = allocator.make!UnaryExpression(); 6171 mixin (nullCheck!`newUnary.functionCallExpression = parseFunctionCallExpression(node)`); 6172 node = newUnary; 6173 break; 6174 case tok!"++": 6175 case tok!"--": 6176 auto n = allocator.make!UnaryExpression(); 6177 n.unaryExpression = node; 6178 n.suffix = advance(); 6179 node = n; 6180 break; 6181 case tok!"[": 6182 auto n = allocator.make!UnaryExpression; 6183 n.indexExpression = parseIndexExpression(node); 6184 node = n; 6185 break; 6186 case tok!".": 6187 advance(); 6188 auto n = allocator.make!UnaryExpression(); 6189 n.unaryExpression = node; 6190 if (currentIs(tok!"new")) 6191 mixin(parseNodeQ!(`node.newExpression`, `NewExpression`)); 6192 else 6193 n.identifierOrTemplateInstance = parseIdentifierOrTemplateInstance(); 6194 node = n; 6195 break; 6196 default: 6197 break loop; 6198 } 6199 return node; 6200 } 6201 6202 /** 6203 * Parses an UnionDeclaration 6204 * 6205 * $(GRAMMAR $(RULEDEF unionDeclaration): 6206 * $(LITERAL 'union') $(LITERAL Identifier) $(RULE templateParameters) $(RULE constraint)? $(RULE structBody) 6207 * | $(LITERAL 'union') $(LITERAL Identifier) ($(RULE structBody) | $(LITERAL ';')) 6208 * | $(LITERAL 'union') $(RULE structBody) 6209 * ;) 6210 */ 6211 UnionDeclaration parseUnionDeclaration() 6212 { 6213 mixin(traceEnterAndExit!(__FUNCTION__)); 6214 auto node = allocator.make!UnionDeclaration; 6215 // grab line number even if it's anonymous 6216 const t = expect(tok!"union"); 6217 if (currentIs(tok!"identifier")) 6218 { 6219 node.name = advance(); 6220 if (currentIs(tok!"(")) 6221 { 6222 mixin(parseNodeQ!(`node.templateParameters`, `TemplateParameters`)); 6223 if (currentIs(tok!"if")) 6224 mixin(parseNodeQ!(`node.constraint`, `Constraint`)); 6225 mixin(parseNodeQ!(`node.structBody`, `StructBody`)); 6226 } 6227 else 6228 goto semiOrStructBody; 6229 } 6230 else 6231 { 6232 node.name.line = t.line; 6233 node.name.column = t.column; 6234 semiOrStructBody: 6235 if (currentIs(tok!";")) 6236 advance(); 6237 else 6238 mixin(parseNodeQ!(`node.structBody`, `StructBody`)); 6239 } 6240 return node; 6241 } 6242 6243 /** 6244 * Parses a Unittest 6245 * 6246 * $(GRAMMAR $(RULEDEF unittest): 6247 * $(LITERAL 'unittest') $(RULE blockStatement) 6248 * ;) 6249 */ 6250 Unittest parseUnittest() 6251 { 6252 mixin(traceEnterAndExit!(__FUNCTION__)); 6253 mixin (simpleParse!(Unittest, tok!"unittest", "blockStatement|parseBlockStatement")); 6254 } 6255 6256 /** 6257 * Parses a VariableDeclaration 6258 * 6259 * $(GRAMMAR $(RULEDEF variableDeclaration): 6260 * $(RULE storageClass)* $(RULE type) $(RULE declarator) ($(LITERAL ',') $(RULE declarator))* $(LITERAL ';') 6261 * | $(RULE storageClass)* $(RULE type) $(LITERAL identifier) $(LITERAL '=') $(RULE functionBody) $(LITERAL ';') 6262 * | $(RULE autoDeclaration) 6263 * ;) 6264 */ 6265 VariableDeclaration parseVariableDeclaration(Type type = null, bool isAuto = false) 6266 { 6267 mixin (traceEnterAndExit!(__FUNCTION__)); 6268 auto node = allocator.make!VariableDeclaration; 6269 6270 if (isAuto) 6271 { 6272 mixin(parseNodeQ!(`node.autoDeclaration`, `AutoDeclaration`)); 6273 node.comment = node.autoDeclaration.comment; 6274 return node; 6275 } 6276 6277 StackBuffer storageClasses; 6278 while (isStorageClass()) 6279 if (!storageClasses.put(parseStorageClass())) 6280 return null; 6281 ownArray(node.storageClasses, storageClasses); 6282 6283 node.type = type is null ? parseType() : type; 6284 node.comment = comment; 6285 comment = null; 6286 6287 // TODO: handle function bodies correctly 6288 6289 StackBuffer declarators; 6290 Declarator last; 6291 while (true) 6292 { 6293 auto declarator = parseDeclarator(); 6294 if (!declarators.put(declarator)) 6295 return null; 6296 else 6297 last = declarator; 6298 if (moreTokens() && currentIs(tok!",")) 6299 { 6300 if (node.comment !is null) 6301 declarator.comment = node.comment ~ "\n" ~ current.trailingComment; 6302 else 6303 declarator.comment = current.trailingComment; 6304 advance(); 6305 } 6306 else 6307 break; 6308 } 6309 ownArray(node.declarators, declarators); 6310 const semicolon = expect(tok!";"); 6311 mixin (nullCheck!`semicolon`); 6312 if (node.comment !is null) 6313 { 6314 if (semicolon.trailingComment is null) 6315 last.comment = node.comment; 6316 else 6317 last.comment = node.comment ~ "\n" ~ semicolon.trailingComment; 6318 } 6319 else 6320 last.comment = semicolon.trailingComment; 6321 return node; 6322 } 6323 6324 /** 6325 * Parses a Vector 6326 * 6327 * $(GRAMMAR $(RULEDEF vector): 6328 * $(LITERAL '___vector') $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL '$(RPAREN)') 6329 * ;) 6330 */ 6331 Vector parseVector() 6332 { 6333 mixin(traceEnterAndExit!(__FUNCTION__)); 6334 mixin (simpleParse!(Vector, tok!"__vector", tok!"(", "type|parseType", tok!")")); 6335 } 6336 6337 /** 6338 * Parses a VersionCondition 6339 * 6340 * $(GRAMMAR $(RULEDEF versionCondition): 6341 * $(LITERAL 'version') $(LITERAL '$(LPAREN)') ($(LITERAL IntegerLiteral) | $(LITERAL Identifier) | $(LITERAL 'unittest') | $(LITERAL 'assert')) $(LITERAL '$(RPAREN)') 6342 * ;) 6343 */ 6344 VersionCondition parseVersionCondition() 6345 { 6346 mixin(traceEnterAndExit!(__FUNCTION__)); 6347 auto node = allocator.make!VersionCondition; 6348 const v = expect(tok!"version"); 6349 mixin(nullCheck!`v`); 6350 node.versionIndex = v.index; 6351 mixin(tokenCheck!"("); 6352 if (currentIsOneOf(tok!"intLiteral", tok!"identifier", tok!"unittest", tok!"assert")) 6353 node.token = advance(); 6354 else 6355 { 6356 error(`Expected an integer literal, an identifier, "assert", or "unittest"`); 6357 return null; 6358 } 6359 expect(tok!")"); 6360 return node; 6361 } 6362 6363 /** 6364 * Parses a VersionSpecification 6365 * 6366 * $(GRAMMAR $(RULEDEF versionSpecification): 6367 * $(LITERAL 'version') $(LITERAL '=') ($(LITERAL Identifier) | $(LITERAL IntegerLiteral)) $(LITERAL ';') 6368 * ;) 6369 */ 6370 VersionSpecification parseVersionSpecification() 6371 { 6372 mixin(traceEnterAndExit!(__FUNCTION__)); 6373 auto node = allocator.make!VersionSpecification; 6374 mixin(tokenCheck!"version"); 6375 mixin(tokenCheck!"="); 6376 if (!currentIsOneOf(tok!"identifier", tok!"intLiteral")) 6377 { 6378 error("Identifier or integer literal expected"); 6379 return null; 6380 } 6381 node.token = advance(); 6382 expect(tok!";"); 6383 return node; 6384 } 6385 6386 /** 6387 * Parses a WhileStatement 6388 * 6389 * $(GRAMMAR $(RULEDEF whileStatement): 6390 * $(LITERAL 'while') $(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)') $(RULE declarationOrStatement) 6391 * ;) 6392 */ 6393 WhileStatement parseWhileStatement() 6394 { 6395 mixin(traceEnterAndExit!(__FUNCTION__)); 6396 auto node = allocator.make!WhileStatement; 6397 mixin(tokenCheck!"while"); 6398 node.startIndex = current().index; 6399 mixin(tokenCheck!"("); 6400 mixin(parseNodeQ!(`node.expression`, `Expression`)); 6401 mixin(tokenCheck!")"); 6402 if (currentIs(tok!"}")) 6403 { 6404 error("Statement expected", false); 6405 return node; // this line makes DCD better 6406 } 6407 mixin(parseNodeQ!(`node.declarationOrStatement`, `DeclarationOrStatement`)); 6408 return node; 6409 } 6410 6411 /** 6412 * Parses a WithStatement 6413 * 6414 * $(GRAMMAR $(RULEDEF withStatement): 6415 * $(LITERAL 'with') $(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)') $(RULE statementNoCaseNoDefault) 6416 * ;) 6417 */ 6418 WithStatement parseWithStatement() 6419 { 6420 mixin(traceEnterAndExit!(__FUNCTION__)); 6421 mixin (simpleParse!(WithStatement, tok!"with", tok!"(", 6422 "expression|parseExpression", tok!")", 6423 "statementNoCaseNoDefault|parseStatementNoCaseNoDefault")); 6424 } 6425 6426 /** 6427 * Parses an XorExpression 6428 * 6429 * $(GRAMMAR $(RULEDEF xorExpression): 6430 * $(RULE andExpression) 6431 * | $(RULE xorExpression) $(LITERAL '^') $(RULE andExpression) 6432 * ;) 6433 */ 6434 ExpressionNode parseXorExpression() 6435 { 6436 mixin(traceEnterAndExit!(__FUNCTION__)); 6437 return parseLeftAssocBinaryExpression!(XorExpression, AndExpression, 6438 tok!"^")(); 6439 } 6440 6441 /** 6442 * Current error count 6443 */ 6444 uint errorCount; 6445 6446 /** 6447 * Current warning count 6448 */ 6449 uint warningCount; 6450 6451 /** 6452 * Name used when reporting warnings and errors 6453 */ 6454 string fileName; 6455 6456 /** 6457 * Tokens to parse 6458 */ 6459 const(Token)[] tokens; 6460 6461 /** 6462 * Allocator used for creating AST nodes 6463 */ 6464 RollbackAllocator* allocator; 6465 6466 /** 6467 * Function that is called when a warning or error is encountered. 6468 * The parameters are the file name, line number, column number, 6469 * and the error or warning message. 6470 */ 6471 void function(string, size_t, size_t, string, bool) messageFunction; 6472 6473 void setTokens(const(Token)[] tokens) 6474 { 6475 this.tokens = tokens; 6476 } 6477 6478 /** 6479 * Returns: true if there are more tokens 6480 */ 6481 bool moreTokens() const nothrow pure @safe @nogc 6482 { 6483 return index < tokens.length; 6484 } 6485 6486 protected: 6487 6488 uint suppressedErrorCount; 6489 6490 enum MAX_ERRORS = 500; 6491 6492 void ownArray(T)(ref T[] arr, ref StackBuffer sb) 6493 { 6494 if (sb.length == 0) 6495 return; 6496 void[] a = allocator.allocate(sb.length); 6497 a[] = sb[]; 6498 arr = cast(T[]) a; 6499 } 6500 6501 bool isCastQualifier() const 6502 { 6503 switch (current.type) 6504 { 6505 case tok!"const": 6506 if (peekIs(tok!")")) return true; 6507 return startsWith(tok!"const", tok!"shared", tok!")"); 6508 case tok!"immutable": 6509 return peekIs(tok!")"); 6510 case tok!"inout": 6511 if (peekIs(tok!")")) return true; 6512 return startsWith(tok!"inout", tok!"shared", tok!")"); 6513 case tok!"shared": 6514 if (peekIs(tok!")")) return true; 6515 if (startsWith(tok!"shared", tok!"const", tok!")")) return true; 6516 return startsWith(tok!"shared", tok!"inout", tok!")"); 6517 default: 6518 return false; 6519 } 6520 } 6521 6522 bool isAssociativeArrayLiteral() 6523 { 6524 mixin(traceEnterAndExit!(__FUNCTION__)); 6525 static bool[typeof(current.index)] cached; 6526 if (auto p = current.index in cached) 6527 return *p; 6528 size_t currentIndex = current.index; 6529 immutable b = setBookmark(); 6530 scope(exit) goToBookmark(b); 6531 advance(); 6532 immutable bool result = !currentIs(tok!"]") && parseExpression() !is null && currentIs(tok!":"); 6533 cached[currentIndex] = result; 6534 return result; 6535 } 6536 6537 bool hasMagicDelimiter(alias L, alias T)() 6538 { 6539 mixin(traceEnterAndExit!(__FUNCTION__)); 6540 immutable i = index; 6541 scope(exit) index = i; 6542 assert (currentIs(L)); 6543 advance(); 6544 while (moreTokens()) switch (current.type) 6545 { 6546 case tok!"{": skipBraces(); break; 6547 case tok!"(": skipParens(); break; 6548 case tok!"[": skipBrackets(); break; 6549 case tok!"]": case tok!"}": return false; 6550 case T: return true; 6551 default: advance(); break; 6552 } 6553 return false; 6554 } 6555 6556 enum DecType 6557 { 6558 autoVar, 6559 autoFun, 6560 other 6561 } 6562 6563 DecType isAutoDeclaration(ref size_t beginIndex) nothrow @nogc @safe 6564 { 6565 immutable b = setBookmark(); 6566 scope(exit) goToBookmark(b); 6567 6568 loop: while (moreTokens()) switch (current().type) 6569 { 6570 case tok!"pragma": 6571 beginIndex = size_t.max; 6572 advance(); 6573 if (currentIs(tok!"(")) 6574 { 6575 skipParens(); 6576 break; 6577 } 6578 else 6579 return DecType.other; 6580 case tok!"package": 6581 case tok!"private": 6582 case tok!"protected": 6583 case tok!"public": 6584 beginIndex = size_t.max; 6585 advance(); 6586 break; 6587 case tok!"@": 6588 beginIndex = min(beginIndex, index); 6589 advance(); 6590 if (currentIs(tok!"(")) 6591 skipParens(); 6592 else if (currentIs(tok!"identifier")) 6593 { 6594 advance(); 6595 if (currentIs(tok!"!")) 6596 { 6597 advance(); 6598 if (currentIs(tok!"(")) 6599 skipParens(); 6600 else 6601 advance(); 6602 } 6603 if (currentIs(tok!"(")) 6604 skipParens(); 6605 } 6606 else 6607 return DecType.other; 6608 break; 6609 case tok!"deprecated": 6610 case tok!"align": 6611 case tok!"extern": 6612 beginIndex = min(beginIndex, index); 6613 advance(); 6614 if (currentIs(tok!"(")) 6615 skipParens(); 6616 break; 6617 case tok!"const": 6618 case tok!"immutable": 6619 case tok!"inout": 6620 case tok!"synchronized": 6621 if (peekIs(tok!"(")) 6622 return DecType.other; 6623 else 6624 { 6625 beginIndex = min(beginIndex, index); 6626 advance(); 6627 break; 6628 } 6629 case tok!"auto": 6630 case tok!"enum": 6631 case tok!"export": 6632 case tok!"final": 6633 case tok!"__gshared": 6634 case tok!"nothrow": 6635 case tok!"override": 6636 case tok!"pure": 6637 case tok!"ref": 6638 case tok!"scope": 6639 case tok!"shared": 6640 case tok!"static": 6641 beginIndex = min(beginIndex, index); 6642 advance(); 6643 break; 6644 default: 6645 break loop; 6646 } 6647 if (index <= b) 6648 return DecType.other; 6649 if (startsWith(tok!"identifier", tok!"=")) 6650 return DecType.autoVar; 6651 if (startsWith(tok!"identifier", tok!"(")) 6652 { 6653 advance(); 6654 auto past = peekPastParens(); 6655 return (past !is null && past.type == tok!"=") ? DecType.other : DecType.autoFun; 6656 } 6657 return DecType.other; 6658 } 6659 6660 bool isDeclaration() 6661 { 6662 mixin(traceEnterAndExit!(__FUNCTION__)); 6663 if (!moreTokens()) return false; 6664 switch (current.type) 6665 { 6666 case tok!"final": 6667 return !peekIs(tok!"switch"); 6668 case tok!"debug": 6669 if (peekIs(tok!":")) 6670 return true; 6671 goto case; 6672 case tok!"version": 6673 if (peekIs(tok!"=")) 6674 return true; 6675 if (peekIs(tok!"(")) 6676 goto default; 6677 return false; 6678 case tok!"synchronized": 6679 if (peekIs(tok!"(")) 6680 return false; 6681 else 6682 goto default; 6683 case tok!"static": 6684 if (peekIs(tok!"if")) 6685 return false; 6686 goto case; 6687 case tok!"scope": 6688 if (peekIs(tok!"(")) 6689 return false; 6690 goto case; 6691 case tok!"@": 6692 case tok!"abstract": 6693 case tok!"alias": 6694 case tok!"align": 6695 case tok!"auto": 6696 case tok!"class": 6697 case tok!"deprecated": 6698 case tok!"enum": 6699 case tok!"export": 6700 case tok!"extern": 6701 case tok!"__gshared": 6702 case tok!"interface": 6703 case tok!"nothrow": 6704 case tok!"override": 6705 case tok!"package": 6706 case tok!"private": 6707 case tok!"protected": 6708 case tok!"public": 6709 case tok!"pure": 6710 case tok!"ref": 6711 case tok!"struct": 6712 case tok!"union": 6713 case tok!"unittest": 6714 return true; 6715 foreach (B; BasicTypes) { case B: } 6716 return !peekIsOneOf(tok!".", tok!"("); 6717 case tok!"asm": 6718 case tok!"break": 6719 case tok!"case": 6720 case tok!"continue": 6721 case tok!"default": 6722 case tok!"do": 6723 case tok!"for": 6724 case tok!"foreach": 6725 case tok!"foreach_reverse": 6726 case tok!"goto": 6727 case tok!"if": 6728 case tok!"return": 6729 case tok!"switch": 6730 case tok!"throw": 6731 case tok!"try": 6732 case tok!"while": 6733 case tok!"{": 6734 case tok!"assert": 6735 return false; 6736 default: 6737 immutable b = setBookmark(); 6738 scope(exit) goToBookmark(b); 6739 auto c = allocator.setCheckpoint(); 6740 scope(exit) allocator.rollback(c); 6741 return parseDeclaration(true, true) !is null; 6742 } 6743 } 6744 6745 /// Only use this in template parameter parsing 6746 bool isType() 6747 { 6748 if (!moreTokens()) return false; 6749 immutable b = setBookmark(); 6750 scope (exit) goToBookmark(b); 6751 auto c = allocator.setCheckpoint(); 6752 scope (exit) allocator.rollback(c); 6753 if (parseType() is null) return false; 6754 return currentIsOneOf(tok!",", tok!")", tok!"="); 6755 } 6756 6757 bool isStorageClass() 6758 { 6759 if (!moreTokens()) return false; 6760 switch (current.type) 6761 { 6762 case tok!"const": 6763 case tok!"immutable": 6764 case tok!"inout": 6765 case tok!"shared": 6766 return !peekIs(tok!"("); 6767 case tok!"@": 6768 case tok!"deprecated": 6769 case tok!"abstract": 6770 case tok!"align": 6771 case tok!"auto": 6772 case tok!"enum": 6773 case tok!"extern": 6774 case tok!"final": 6775 case tok!"nothrow": 6776 case tok!"override": 6777 case tok!"pure": 6778 case tok!"ref": 6779 case tok!"__gshared": 6780 case tok!"scope": 6781 case tok!"static": 6782 case tok!"synchronized": 6783 return true; 6784 default: 6785 return false; 6786 } 6787 } 6788 6789 bool isAttribute() 6790 { 6791 if (!moreTokens()) return false; 6792 switch (current.type) 6793 { 6794 case tok!"const": 6795 case tok!"immutable": 6796 case tok!"inout": 6797 case tok!"scope": 6798 return !peekIs(tok!"("); 6799 case tok!"static": 6800 return !peekIsOneOf(tok!"assert", tok!"this", tok!"if", tok!"~"); 6801 case tok!"shared": 6802 return !(startsWith(tok!"shared", tok!"static", tok!"this") 6803 || startsWith(tok!"shared", tok!"static", tok!"~") 6804 || peekIs(tok!"(")); 6805 case tok!"pragma": 6806 immutable b = setBookmark(); 6807 scope(exit) goToBookmark(b); 6808 advance(); 6809 const past = peekPastParens(); 6810 if (past is null || *past == tok!";") 6811 return false; 6812 return true; 6813 case tok!"deprecated": 6814 case tok!"private": 6815 case tok!"package": 6816 case tok!"protected": 6817 case tok!"public": 6818 case tok!"export": 6819 case tok!"final": 6820 case tok!"synchronized": 6821 case tok!"override": 6822 case tok!"abstract": 6823 case tok!"auto": 6824 case tok!"__gshared": 6825 case tok!"pure": 6826 case tok!"nothrow": 6827 case tok!"@": 6828 case tok!"ref": 6829 case tok!"extern": 6830 case tok!"align": 6831 return true; 6832 default: 6833 return false; 6834 } 6835 } 6836 6837 static bool isMemberFunctionAttribute(IdType t) pure nothrow @nogc @safe 6838 { 6839 switch (t) 6840 { 6841 case tok!"const": 6842 case tok!"immutable": 6843 case tok!"inout": 6844 case tok!"shared": 6845 case tok!"@": 6846 case tok!"pure": 6847 case tok!"nothrow": 6848 case tok!"return": 6849 return true; 6850 default: 6851 return false; 6852 } 6853 } 6854 6855 bool currentIsMemberFunctionAttribute() const 6856 { 6857 return moreTokens && isMemberFunctionAttribute(current.type); 6858 } 6859 6860 ExpressionNode parseLeftAssocBinaryExpression(alias ExpressionType, 6861 alias ExpressionPartType, Operators ...)(ExpressionNode part = null) 6862 { 6863 ExpressionNode node; 6864 mixin ("node = part is null ? parse" ~ ExpressionPartType.stringof ~ "() : part;"); 6865 if (node is null) 6866 return null; 6867 while (currentIsOneOf(Operators)) 6868 { 6869 auto n = allocator.make!ExpressionType; 6870 n.line = current.line; 6871 n.column = current.column; 6872 static if (__traits(hasMember, ExpressionType, "operator")) 6873 n.operator = advance().type; 6874 else 6875 advance(); 6876 n.left = node; 6877 mixin (parseNodeQ!(`n.right`, ExpressionPartType.stringof)); 6878 node = n; 6879 } 6880 return node; 6881 } 6882 6883 ListType parseCommaSeparatedRule(alias ListType, alias ItemType, 6884 bool setLineAndColumn = false)(bool allowTrailingComma = false) 6885 { 6886 auto node = allocator.make!ListType; 6887 static if (setLineAndColumn) 6888 { 6889 node.line = current.line; 6890 node.column = current.column; 6891 } 6892 StackBuffer items; 6893 while (moreTokens()) 6894 { 6895 if (!items.put(mixin("parse" ~ ItemType.stringof ~ "()"))) 6896 return null; 6897 if (currentIs(tok!",")) 6898 { 6899 advance(); 6900 if (allowTrailingComma && currentIsOneOf(tok!")", tok!"}", tok!"]")) 6901 break; 6902 else 6903 continue; 6904 } 6905 else 6906 break; 6907 } 6908 ownArray(node.items, items); 6909 return node; 6910 } 6911 6912 void warn(lazy string message) 6913 { 6914 import std.stdio : stderr; 6915 if (suppressMessages > 0) 6916 return; 6917 ++warningCount; 6918 auto column = index < tokens.length ? tokens[index].column : 0; 6919 auto line = index < tokens.length ? tokens[index].line : 0; 6920 if (messageFunction is null) 6921 stderr.writefln("%s(%d:%d)[warn]: %s", fileName, line, column, message); 6922 else 6923 messageFunction(fileName, line, column, message, false); 6924 } 6925 6926 void error(string message, bool shouldAdvance = true) 6927 { 6928 import std.stdio : stderr; 6929 if (suppressMessages == 0) 6930 { 6931 ++errorCount; 6932 auto column = index < tokens.length ? tokens[index].column : tokens[$ - 1].column; 6933 auto line = index < tokens.length ? tokens[index].line : tokens[$ - 1].line; 6934 if (messageFunction is null) 6935 stderr.writefln("%s(%d:%d)[error]: %s", fileName, line, column, message); 6936 else 6937 messageFunction(fileName, line, column, message, true); 6938 } 6939 else 6940 ++suppressedErrorCount; 6941 while (shouldAdvance && moreTokens()) 6942 { 6943 if (currentIsOneOf(tok!";", tok!"}", 6944 tok!")", tok!"]")) 6945 { 6946 advance(); 6947 break; 6948 } 6949 else 6950 advance(); 6951 } 6952 } 6953 6954 void skip(alias O, alias C)() 6955 { 6956 assert (currentIs(O), current().text); 6957 advance(); 6958 int depth = 1; 6959 while (moreTokens()) 6960 { 6961 switch (tokens[index].type) 6962 { 6963 case C: 6964 advance(); 6965 depth--; 6966 if (depth <= 0) 6967 return; 6968 break; 6969 case O: 6970 depth++; 6971 advance(); 6972 break; 6973 default: 6974 advance(); 6975 break; 6976 } 6977 } 6978 } 6979 6980 void skipBraces() pure nothrow @safe @nogc 6981 { 6982 skip!(tok!"{", tok!"}")(); 6983 } 6984 6985 void skipParens() pure nothrow @safe @nogc 6986 { 6987 skip!(tok!"(", tok!")")(); 6988 } 6989 6990 void skipBrackets() pure nothrow @safe @nogc 6991 { 6992 skip!(tok!"[", tok!"]")(); 6993 } 6994 6995 const(Token)* peek() const pure nothrow @safe @nogc 6996 { 6997 return index + 1 < tokens.length ? &tokens[index + 1] : null; 6998 } 6999 7000 const(Token)* peekPast(alias O, alias C)() const pure nothrow @safe @nogc 7001 { 7002 if (index >= tokens.length) 7003 return null; 7004 int depth = 1; 7005 size_t i = index; 7006 ++i; 7007 while (i < tokens.length) 7008 { 7009 if (tokens[i] == O) 7010 { 7011 ++depth; 7012 ++i; 7013 } 7014 else if (tokens[i] == C) 7015 { 7016 --depth; 7017 ++i; 7018 if (depth <= 0) 7019 break; 7020 } 7021 else 7022 ++i; 7023 } 7024 return i >= tokens.length ? null : depth == 0 ? &tokens[i] : null; 7025 } 7026 7027 const(Token)* peekPastParens() const pure nothrow @safe @nogc 7028 { 7029 return peekPast!(tok!"(", tok!")")(); 7030 } 7031 7032 const(Token)* peekPastBrackets() const pure nothrow @safe @nogc 7033 { 7034 return peekPast!(tok!"[", tok!"]")(); 7035 } 7036 7037 const(Token)* peekPastBraces() const pure nothrow @safe @nogc 7038 { 7039 return peekPast!(tok!"{", tok!"}")(); 7040 } 7041 7042 bool peekIs(IdType t) const pure nothrow @safe @nogc 7043 { 7044 return index + 1 < tokens.length && tokens[index + 1].type == t; 7045 } 7046 7047 bool peekIsOneOf(IdType[] types...) const pure nothrow @safe @nogc 7048 { 7049 if (index + 1 >= tokens.length) return false; 7050 return canFind(types, tokens[index + 1].type); 7051 } 7052 7053 /** 7054 * Returns a token of the specified type if it was the next token, otherwise 7055 * calls the error function and returns null. Advances the lexer by one token. 7056 */ 7057 const(Token)* expect(IdType type) 7058 { 7059 if (index < tokens.length && tokens[index].type == type) 7060 return &tokens[index++]; 7061 else 7062 { 7063 string tokenString = str(type) is null 7064 ? to!string(type) : str(type); 7065 immutable bool shouldNotAdvance = index < tokens.length 7066 && (tokens[index].type == tok!")" 7067 || tokens[index].type == tok!";" 7068 || tokens[index].type == tok!"}"); 7069 auto token = (index < tokens.length 7070 ? (tokens[index].text is null ? str(tokens[index].type) : tokens[index].text) 7071 : "EOF"); 7072 error("Expected " ~ tokenString ~ " instead of " ~ token, 7073 !shouldNotAdvance); 7074 return null; 7075 } 7076 } 7077 7078 /** 7079 * Returns: the _current token 7080 */ 7081 Token current() const pure nothrow @safe @nogc @property 7082 { 7083 return tokens[index]; 7084 } 7085 7086 /** 7087 * Advances to the next token and returns the current token 7088 */ 7089 Token advance() pure nothrow @nogc @safe 7090 { 7091 return tokens[index++]; 7092 } 7093 7094 /** 7095 * Returns: true if the current token has the given type 7096 */ 7097 bool currentIs(IdType type) const pure nothrow @safe @nogc 7098 { 7099 return index < tokens.length && tokens[index] == type; 7100 } 7101 7102 /** 7103 * Returns: true if the current token is one of the given types 7104 */ 7105 bool currentIsOneOf(IdType[] types...) const pure nothrow @safe @nogc 7106 { 7107 if (index >= tokens.length) 7108 return false; 7109 return canFind(types, current.type); 7110 } 7111 7112 bool startsWith(IdType[] types...) const pure nothrow @safe @nogc 7113 { 7114 if (index + types.length >= tokens.length) 7115 return false; 7116 for (size_t i = 0; (i < types.length) && ((index + i) < tokens.length); ++i) 7117 { 7118 if (tokens[index + i].type != types[i]) 7119 return false; 7120 } 7121 return true; 7122 } 7123 7124 alias Bookmark = size_t; 7125 7126 Bookmark setBookmark() pure nothrow @safe @nogc 7127 { 7128 // mixin(traceEnterAndExit!(__FUNCTION__)); 7129 ++suppressMessages; 7130 return index; 7131 } 7132 7133 void abandonBookmark(Bookmark) pure nothrow @safe @nogc 7134 { 7135 --suppressMessages; 7136 if (suppressMessages == 0) 7137 suppressedErrorCount = 0; 7138 } 7139 7140 void goToBookmark(Bookmark bookmark) pure nothrow @safe @nogc 7141 { 7142 --suppressMessages; 7143 if (suppressMessages == 0) 7144 suppressedErrorCount = 0; 7145 index = bookmark; 7146 } 7147 7148 template simpleParse(NodeType, parts ...) 7149 { 7150 static if (__traits(hasMember, NodeType, "comment")) 7151 enum nodeComm = "node.comment = comment;\n" 7152 ~ "comment = null;\n"; 7153 else enum nodeComm = ""; 7154 7155 static if (__traits(hasMember, NodeType, "line")) 7156 enum nodeLine = "node.line = current().line;\n"; 7157 else enum nodeLine = ""; 7158 7159 static if (__traits(hasMember, NodeType, "column")) 7160 enum nodeColumn = "node.column = current().column;\n"; 7161 else enum nodeColumn = ""; 7162 7163 static if (__traits(hasMember, NodeType, "location")) 7164 enum nodeLoc = "node.location = current().index;\n"; 7165 else enum nodeLoc = ""; 7166 7167 enum simpleParse = "auto node = allocator.make!" ~ NodeType.stringof ~ ";\n" 7168 ~ nodeComm ~ nodeLine ~ nodeColumn ~ nodeLoc 7169 ~ simpleParseItems!(parts) 7170 ~ "\nreturn node;\n"; 7171 } 7172 7173 template simpleParseItems(items ...) 7174 { 7175 static if (items.length > 1) 7176 enum simpleParseItems = simpleParseItem!(items[0]) ~ "\n" 7177 ~ simpleParseItems!(items[1 .. $]); 7178 else static if (items.length == 1) 7179 enum simpleParseItems = simpleParseItem!(items[0]); 7180 else 7181 enum simpleParseItems = ""; 7182 } 7183 7184 template simpleParseItem(alias item) 7185 { 7186 static if (is (typeof(item) == string)) 7187 enum simpleParseItem = "if ((node." ~ item[0 .. item.countUntil("|")] 7188 ~ " = " ~ item[item.countUntil("|") + 1 .. $] ~ "()) is null) { return null; }"; 7189 else 7190 enum simpleParseItem = "if (expect(" ~ item.stringof ~ ") is null) { return null; }"; 7191 } 7192 7193 template traceEnterAndExit(string fun) 7194 { 7195 enum traceEnterAndExit = `version (dparse_verbose) { _traceDepth++; trace("` 7196 ~ `\033[01;32m` ~ fun ~ `\033[0m"); }` 7197 ~ `version (dparse_verbose) scope(exit) { trace("` 7198 ~ `\033[01;31m` ~ fun ~ `\033[0m"); _traceDepth--; }`; 7199 } 7200 7201 version (dparse_verbose) 7202 { 7203 import std.stdio : stderr; 7204 void trace(string message) 7205 { 7206 if (suppressMessages > 0) 7207 return; 7208 auto depth = format("%4d ", _traceDepth); 7209 if (index < tokens.length) 7210 stderr.writeln(depth, message, "(", current.line, ":", current.column, ")"); 7211 else 7212 stderr.writeln(depth, message, "(EOF:0)"); 7213 } 7214 } 7215 else 7216 { 7217 void trace(lazy string) {} 7218 } 7219 7220 template parseNode(string NodeName, string VarName) 7221 { 7222 enum parseNode = `{ 7223 auto c = allocator.setCheckpoint(); 7224 ` ~ VarName ~ ` = parse` ~ NodeName ~ `(); 7225 if (` ~ VarName ~ ` is null) 7226 { 7227 allocator.rollback(c); 7228 return null; 7229 } 7230 }`; 7231 } 7232 7233 template parseNodeQ(string VarName, string NodeName) 7234 { 7235 enum parseNodeQ = `{ if ((` ~ VarName ~ ` = parse` ~ NodeName ~ `()) is null) return null; }`; 7236 } 7237 7238 template nullCheck(string exp) 7239 { 7240 enum nullCheck = "{if ((" ~ exp ~ ") is null) { return null; }}"; 7241 } 7242 7243 template tokenCheck(string Tok) 7244 { 7245 enum tokenCheck = `{ if (expect(tok!"` ~ Tok ~ `") is null) { return null; } }`; 7246 } 7247 7248 template tokenCheck(string Exp, string Tok) 7249 { 7250 enum tokenCheck = `{auto t = expect(tok!"` ~ Tok ~ `");` 7251 ~ `if (t is null) { return null;}` 7252 ~ `else {` ~ Exp ~ ` = *t; }}`; 7253 } 7254 7255 T attachCommentFromSemicolon(T)(T node) 7256 { 7257 auto semicolon = expect(tok!";"); 7258 if (semicolon is null) 7259 return null; 7260 if (semicolon.trailingComment !is null) 7261 { 7262 if (node.comment is null) 7263 node.comment = semicolon.trailingComment; 7264 else 7265 { 7266 node.comment ~= "\n"; 7267 node.comment ~= semicolon.trailingComment; 7268 } 7269 } 7270 return node; 7271 } 7272 7273 // This list MUST BE MAINTAINED IN SORTED ORDER. 7274 static immutable string[] REGISTER_NAMES = [ 7275 "AH", "AL", "AX", "BH", "BL", "BP", "BPL", "BX", "CH", "CL", "CR0", "CR2", 7276 "CR3", "CR4", "CS", "CX", "DH", "DI", "DIL", "DL", "DR0", "DR1", "DR2", 7277 "DR3", "DR6", "DR7", "DS", "DX", "EAX", "EBP", "EBX", "ECX", "EDI", "EDX", 7278 "ES", "ESI", "ESP", "FS", "GS", "MM0", "MM1", "MM2", "MM3", "MM4", "MM5", 7279 "MM6", "MM7", "R10", "R10B", "R10D", "R10W", "R11", "R11B", "R11D", "R11W", 7280 "R12", "R12B", "R12D", "R12W", "R13", "R13B", "R13D", "R13W", "R14", "R14B", 7281 "R14D", "R14W", "R15", "R15B", "R15D", "R15W", "R8", "R8B", "R8D", "R8W", 7282 "R9", "R9B", "R9D", "R9W", "RAX", "RBP", "RBX", "RCX", "RDI", "RDX", "RSI", 7283 "RSP", "SI", "SIL", "SP", "SPL", "SS", "ST", "TR3", "TR4", "TR5", "TR6", 7284 "TR7", "XMM0", "XMM1", "XMM10", "XMM11", "XMM12", "XMM13", "XMM14", "XMM15", 7285 "XMM2", "XMM3", "XMM4", "XMM5", "XMM6", "XMM7", "XMM8", "XMM9", "YMM0", 7286 "YMM1", "YMM10", "YMM11", "YMM12", "YMM13", "YMM14", "YMM15", "YMM2", 7287 "YMM3", "YMM4", "YMM5", "YMM6", "YMM7", "YMM8", "YMM9" 7288 ]; 7289 7290 7291 N parseStaticCtorDtorCommon(N)(N node) 7292 { 7293 node.line = current.line; 7294 node.column = current.column; 7295 mixin(tokenCheck!"this"); 7296 mixin(tokenCheck!"("); 7297 mixin(tokenCheck!")"); 7298 StackBuffer attributes; 7299 while (moreTokens() && !currentIsOneOf(tok!"{", tok!"in", tok!"out", tok!"body", tok!";")) 7300 if (!attributes.put(parseMemberFunctionAttribute())) 7301 return null; 7302 ownArray(node.memberFunctionAttributes, attributes); 7303 if (currentIs(tok!";")) 7304 advance(); 7305 else 7306 mixin(parseNodeQ!(`node.functionBody`, `FunctionBody`)); 7307 return node; 7308 } 7309 7310 N parseInterfaceOrClass(N)(N node) 7311 { 7312 auto ident = expect(tok!"identifier"); 7313 mixin (nullCheck!`ident`); 7314 node.name = *ident; 7315 node.comment = comment; 7316 comment = null; 7317 if (currentIs(tok!";")) 7318 goto emptyBody; 7319 if (currentIs(tok!"{")) 7320 goto structBody; 7321 if (currentIs(tok!"(")) 7322 { 7323 mixin(parseNodeQ!(`node.templateParameters`, `TemplateParameters`)); 7324 if (currentIs(tok!";")) 7325 goto emptyBody; 7326 constraint: if (currentIs(tok!"if")) 7327 mixin(parseNodeQ!(`node.constraint`, `Constraint`)); 7328 if (node.baseClassList !is null) 7329 { 7330 if (currentIs(tok!"{")) 7331 goto structBody; 7332 else if (currentIs(tok!";")) 7333 goto emptyBody; 7334 else 7335 { 7336 error("Struct body or ';' expected"); 7337 return null; 7338 } 7339 } 7340 if (currentIs(tok!":")) 7341 goto baseClassList; 7342 if (currentIs(tok!"if")) 7343 goto constraint; 7344 if (currentIs(tok!";")) 7345 goto emptyBody; 7346 } 7347 if (currentIs(tok!":")) 7348 { 7349 baseClassList: 7350 advance(); // : 7351 if ((node.baseClassList = parseBaseClassList()) is null) 7352 return null; 7353 if (currentIs(tok!"if")) 7354 goto constraint; 7355 } 7356 structBody: 7357 mixin(parseNodeQ!(`node.structBody`, `StructBody`)); 7358 return node; 7359 emptyBody: 7360 advance(); 7361 return node; 7362 } 7363 7364 int suppressMessages; 7365 size_t index; 7366 int _traceDepth; 7367 string comment; 7368 }