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