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