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 }