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