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