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