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