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