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 if (currentIs(tok!"=>"))
2985 	{
2986 		advance();
2987 		parseAssignExpression();
2988 		expect(tok!";");
2989 		auto fb = new FunctionBody();
2990                 fb.hadABody = true;
2991                 return fb;
2992 	}
2993         else
2994         {
2995 	    while(currentIs(tok!"in") || currentIs(tok!"out")) {
2996 		    if (currentIs(tok!"in"))
2997 		    {
2998 			mixin(nullCheck!`node.inStatement = parseInStatement()`);
2999 		    }
3000 		    else if (currentIs(tok!"out"))
3001 		    {
3002 			mixin(nullCheck!`node.outStatement = parseOutStatement()`);
3003 		    }
3004 	    }
3005             // Allow function bodies without body statements because this is
3006             // valid inside of interfaces.
3007             if (currentIs(tok!"identifier")) // was tok!"body"
3008                 mixin(nullCheck!`node.bodyStatement = parseBodyStatement()`);
3009 	    else if(currentIs(tok!"do"))
3010                 mixin(nullCheck!`node.bodyStatement = parseBodyDoStatement()`);
3011 	    else if(currentIs(tok!"{")) {
3012 		hackFunctionBody();
3013 
3014 		auto fb = new FunctionBody();
3015                 fb.hadABody = true;
3016                 return fb;
3017 	    } else if(currentIs(tok!"=>")) {
3018 		advance();
3019 		parseAssignExpression();
3020 		expect(tok!";");
3021 		auto fb = new FunctionBody();
3022                 fb.hadABody = true;
3023                 return fb;
3024 	    }
3025         }
3026 	if(minimize_memory) {
3027 		.destroy(node.blockStatement);
3028 		.destroy(node.bodyStatement);
3029 	}
3030         return node;
3031     }
3032 
3033     /**
3034      * Parses a FunctionCallExpression
3035      *
3036      * $(GRAMMAR $(RULEDEF functionCallExpression):
3037      *      $(RULE symbol) $(RULE arguments)
3038      *      $(RULE unaryExpression) $(RULE arguments)
3039      *     | $(RULE type) $(RULE arguments)
3040      *     ;)
3041      */
3042     FunctionCallExpression parseFunctionCallExpression(UnaryExpression unary = null)
3043     {
3044         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
3045         auto node = allocate!FunctionCallExpression;
3046         switch (current.type)
3047         {
3048         case tok!"const":
3049         case tok!"immutable":
3050         case tok!"inout":
3051         case tok!"shared":
3052         case tok!"scope":
3053         case tok!"pure":
3054         case tok!"nothrow":
3055             mixin(nullCheck!`node.type = parseType()`);
3056             mixin(nullCheck!`node.arguments = parseArguments()`);
3057             break;
3058         default:
3059             if (unary !is null)
3060                 node.unaryExpression = unary;
3061             else
3062                 mixin(nullCheck!`node.unaryExpression = parseUnaryExpression()`);
3063             if (currentIs(tok!"!"))
3064                 mixin(nullCheck!`node.templateArguments = parseTemplateArguments()`);
3065             if (unary !is null)
3066                 mixin(nullCheck!`node.arguments = parseArguments()`);
3067         }
3068         return node;
3069     }
3070 
3071     /**
3072      * Parses a FunctionDeclaration
3073      *
3074      * $(GRAMMAR $(RULEDEF functionDeclaration):
3075      *       ($(RULE storageClass)+ | $(RULE _type)) $(LITERAL Identifier) $(RULE parameters) $(RULE memberFunctionAttribute)* ($(RULE functionBody) | $(LITERAL ';'))
3076      *     | ($(RULE storageClass)+ | $(RULE _type)) $(LITERAL Identifier) $(RULE templateParameters) $(RULE parameters) $(RULE memberFunctionAttribute)* $(RULE constraint)? ($(RULE functionBody) | $(LITERAL ';'))
3077      *     ;)
3078      */
3079     FunctionDeclaration parseFunctionDeclaration(Type type = null, bool isAuto = false,
3080         Attribute[] attributes = null)
3081     {
3082         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
3083         auto node = allocate!FunctionDeclaration;
3084         node.comment = comment;
3085         comment = null;
3086         MemberFunctionAttribute[] memberFunctionAttributes;
3087 
3088         node.attributes = attributes;
3089 
3090         if (isAuto)
3091         {
3092             StorageClass[] storageClasses;
3093             while (isStorageClass())
3094             {
3095                 auto s = parseStorageClass();
3096                 if (s is null)
3097                 {
3098                     deallocate(node);
3099                     return null;
3100                 }
3101                 else
3102                     storageClasses ~= s;
3103             }
3104             node.storageClasses = storageClasses;
3105 
3106 
3107             foreach (a; node.attributes)
3108             {
3109                 if (a.attribute == tok!"auto")
3110                     node.hasAuto = true;
3111                 else if (a.attribute == tok!"ref")
3112                     node.hasRef = true;
3113                 else
3114                     continue;
3115             }
3116         }
3117         else
3118         {
3119             while (moreTokens() && currentIsMemberFunctionAttribute())
3120                 memberFunctionAttributes ~= parseMemberFunctionAttribute();
3121 
3122             node.returnType = type is null ? parseType() : type;
3123         }
3124 
3125         const ident = expect(tok!"identifier");
3126         if (ident is null) { deallocate(node); return null; }
3127 
3128         node.name = *ident;
3129 
3130         if (!currentIs(tok!"("))
3131         {
3132             error(`"(" expected`);
3133             return null;
3134         }
3135 
3136         assert (currentIs(tok!"("));
3137         const p = peekPastParens();
3138         immutable bool isTemplate = p !is null && p.type == tok!"(";
3139 
3140         if (isTemplate)
3141             mixin(nullCheck!`node.templateParameters = parseTemplateParameters()`);
3142 
3143         mixin(nullCheck!`node.parameters = parseParameters()`);
3144         if (node.parameters is null) { deallocate(node); return null; }
3145 
3146 	/+
3147 	if(comment) {
3148 		import std.stdio; writeln("omgomg ", comment);
3149 	}
3150 	+/
3151 
3152         while (moreTokens() && currentIsMemberFunctionAttribute())
3153             memberFunctionAttributes ~= parseMemberFunctionAttribute();
3154 
3155         if (isTemplate && currentIs(tok!"if"))
3156             mixin(nullCheck!`node.constraint = parseConstraint()`);
3157 
3158 
3159         if (currentIs(tok!";"))
3160             advance();
3161         else
3162             mixin(nullCheck!`node.functionBody = parseFunctionBody()`);
3163         node.memberFunctionAttributes = ownArray(memberFunctionAttributes);
3164         return node;
3165     }
3166 
3167     /**
3168      * Parses a FunctionLiteralExpression
3169      *
3170      * $(GRAMMAR $(RULEDEF functionLiteralExpression):
3171      *     (($(LITERAL 'function') | $(LITERAL 'delegate')) $(RULE type)?)? ($(RULE parameters) $(RULE functionAttribute)*)? $(RULE functionBody)
3172      *     ;)
3173      */
3174     FunctionLiteralExpression parseFunctionLiteralExpression()
3175     {
3176         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
3177         auto node = allocate!FunctionLiteralExpression;
3178         if (currentIsOneOf(tok!"function", tok!"delegate"))
3179         {
3180             node.functionOrDelegate = advance().type;
3181             if (!currentIsOneOf(tok!"(", tok!"in", tok!"do", // tok!"body" should be here too but awkard
3182                 tok!"out", tok!"{"))
3183             {
3184                 mixin(nullCheck!`node.type = parseType()`);
3185                 if (node.type is null) { deallocate(node); return null; }
3186             }
3187         }
3188         if (currentIs(tok!"("))
3189         {
3190             mixin(nullCheck!`node.parameters = parseParameters()`);
3191             if (node.parameters is null) { deallocate(node); return null; }
3192             MemberFunctionAttribute[] memberFunctionAttributes;
3193             while (currentIsMemberFunctionAttribute())
3194             {
3195                 auto attr = parseMemberFunctionAttribute();
3196                 if (attr is null)
3197                     break;
3198                 else
3199                     memberFunctionAttributes ~= attr;
3200             }
3201             node.memberFunctionAttributes = ownArray(memberFunctionAttributes);
3202         }
3203         if ((node.functionBody = parseFunctionBody()) is null) { deallocate(node); return null; }
3204         return node;
3205     }
3206 
3207     /**
3208      * Parses a GotoStatement
3209      *
3210      * $(GRAMMAR $(RULEDEF gotoStatement):
3211      *     $(LITERAL 'goto') ($(LITERAL Identifier) | $(LITERAL 'default') | $(LITERAL 'case') $(RULE expression)?) $(LITERAL ';')
3212      *     ;)
3213      */
3214     GotoStatement parseGotoStatement()
3215     {
3216         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
3217         auto node = allocate!GotoStatement;
3218         if (expect(tok!"goto") is null) { deallocate(node); return null; }
3219         switch (current.type)
3220         {
3221         case tok!"identifier":
3222         case tok!"default":
3223             node.label = advance();
3224             break;
3225         case tok!"case":
3226             node.label = advance();
3227             if (!currentIs(tok!";"))
3228                 mixin(nullCheck!`node.expression = parseExpression()`);
3229             break;
3230         default:
3231             error(`Identifier, "default", or "case" expected`);
3232             return null;
3233         }
3234         if (expect(tok!";") is null) { deallocate(node); return null; }
3235         return node;
3236     }
3237 
3238     /**
3239      * Parses an IdentifierChain
3240      *
3241      * $(GRAMMAR $(RULEDEF identifierChain):
3242      *     $(LITERAL Identifier) ($(LITERAL '.') $(LITERAL Identifier))*
3243      *     ;)
3244      */
3245     IdentifierChain parseIdentifierChain()
3246     {
3247         auto node = allocate!IdentifierChain;
3248         Token[] identifiers;
3249         while (moreTokens())
3250         {
3251             const ident = expect(tok!"identifier");
3252             if (ident is null) { deallocate(node); return null; }
3253             identifiers ~= *ident;
3254             if (currentIs(tok!"."))
3255             {
3256                 advance();
3257                 continue;
3258             }
3259             else
3260                 break;
3261         }
3262         node.identifiers = ownArray(identifiers);
3263         return node;
3264     }
3265 
3266     /**
3267      * Parses an IdentifierList
3268      *
3269      * $(GRAMMAR $(RULEDEF identifierList):
3270      *     $(LITERAL Identifier) ($(LITERAL ',') $(LITERAL Identifier))*
3271      *     ;)
3272      */
3273     IdentifierList parseIdentifierList()
3274     {
3275         auto node = allocate!IdentifierList;
3276         Token[] identifiers;
3277         while (moreTokens())
3278         {
3279             const ident = expect(tok!"identifier");
3280             if (ident is null) { deallocate(node); return null; }
3281             identifiers ~= *ident;
3282             if (currentIs(tok!","))
3283             {
3284                 advance();
3285                 continue;
3286             }
3287             else
3288                 break;
3289         }
3290         node.identifiers = ownArray(identifiers);
3291         return node;
3292     }
3293 
3294     /**
3295      * Parses an IdentifierOrTemplateChain
3296      *
3297      * $(GRAMMAR $(RULEDEF identifierOrTemplateChain):
3298      *     $(RULE identifierOrTemplateInstance) ($(LITERAL '.') $(RULE identifierOrTemplateInstance))*
3299      *     ;)
3300      */
3301     IdentifierOrTemplateChain parseIdentifierOrTemplateChain()
3302     {
3303         auto node = allocate!IdentifierOrTemplateChain;
3304         IdentifierOrTemplateInstance[] identifiersOrTemplateInstances;
3305         while (moreTokens())
3306         {
3307             auto t = parseIdentifierOrTemplateInstance();
3308             if (t !is null)
3309                 identifiersOrTemplateInstances ~= t;
3310             else
3311                 break;
3312             if (!currentIs(tok!"."))
3313                 break;
3314             else
3315                 advance();
3316         }
3317         node.identifiersOrTemplateInstances = ownArray(identifiersOrTemplateInstances);
3318         return node;
3319     }
3320 
3321     /**
3322      * Parses an IdentifierOrTemplateInstance
3323      *
3324      * $(GRAMMAR $(RULEDEF identifierOrTemplateInstance):
3325      *       $(LITERAL Identifier)
3326      *     | $(RULE templateInstance)
3327      *     ;)
3328      */
3329     IdentifierOrTemplateInstance parseIdentifierOrTemplateInstance()
3330     {
3331         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
3332         auto node = allocate!IdentifierOrTemplateInstance;
3333         if (peekIs(tok!"!") && !startsWith(tok!"identifier",
3334             tok!"!", tok!"is")
3335             && !startsWith(tok!"identifier", tok!"!", tok!"in"))
3336         {
3337             mixin(nullCheck!`node.templateInstance = parseTemplateInstance()`);
3338         }
3339         else
3340         {
3341             const ident = expect(tok!"identifier");
3342             if (ident is null) { deallocate(node); return null; }
3343             node.identifier = *ident;
3344         }
3345         return node;
3346     }
3347 
3348     /**
3349      * Parses an IdentityExpression
3350      *
3351      * $(GRAMMAR $(RULEDEF identityExpression):
3352      *     $(RULE shiftExpression) ($(LITERAL 'is') | ($(LITERAL '!') $(LITERAL 'is'))) $(RULE shiftExpression)
3353      *     ;)
3354      */
3355     ExpressionNode parseIdentityExpression(ExpressionNode shift = null)
3356     {
3357         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
3358         auto node = allocate!IdentityExpression;
3359         node.left = shift is null ? parseShiftExpression() : shift;
3360         if (currentIs(tok!"!"))
3361         {
3362             advance();
3363             node.negated = true;
3364         }
3365         if (expect(tok!"is") is null) { deallocate(node); return null; }
3366         mixin(nullCheck!`node.right = parseShiftExpression()`);
3367         return node;
3368     }
3369 
3370     /**
3371      * Parses an IfStatement
3372      *
3373      * $(GRAMMAR $(RULEDEF ifStatement):
3374      *     $(LITERAL 'if') $(LITERAL '$(LPAREN)') $(RULE ifCondition) $(LITERAL '$(RPAREN)') $(RULE declarationOrStatement) ($(LITERAL 'else') $(RULE declarationOrStatement))?
3375      *$(RULEDEF ifCondition):
3376      *       $(LITERAL 'auto') $(LITERAL Identifier) $(LITERAL '=') $(RULE expression)
3377      *     | $(RULE type) $(LITERAL Identifier) $(LITERAL '=') $(RULE expression)
3378      *     | $(RULE expression)
3379      *     ;)
3380      */
3381     IfStatement parseIfStatement()
3382     {
3383         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
3384         auto node = allocate!IfStatement;
3385         node.line = current().line;
3386         node.column = current().column;
3387         if (expect(tok!"if") is null) { deallocate(node); return null; }
3388         node.startIndex = current().index;
3389         if (expect(tok!"(") is null) { deallocate(node); return null; }
3390 
3391         if (currentIs(tok!"auto") || currentIs(tok!"const") || currentIs(tok!"immutable") || currentIs(tok!"inout") || currentIs(tok!"shared"))
3392         {
3393         while(currentIs(tok!"auto") || currentIs(tok!"const") || currentIs(tok!"immutable") || currentIs(tok!"inout") || currentIs(tok!"shared"))
3394             advance();
3395 	/*
3396 
3397             auto b = setBookmark();
3398             auto t = parseType();
3399 
3400 	    if(t is null)
3401 	    	goToBookmark(b);
3402 		*/
3403 
3404             const i = expect(tok!"identifier");
3405             if (i !is null)
3406                 node.identifier = *i;
3407             expect(tok!"=");
3408             mixin(nullCheck!`node.expression = parseExpression()`);
3409         }
3410         else
3411         {
3412             auto b = setBookmark();
3413             auto t = parseType();
3414             if (t is null || !currentIs(tok!"identifier")
3415                 || !peekIs(tok!"="))
3416             {
3417                 goToBookmark(b);
3418                 mixin(nullCheck!`node.expression = parseExpression()`);
3419             }
3420             else
3421             {
3422                 goToBookmark(b);
3423                 mixin(nullCheck!`node.type = parseType()`);
3424                 const i = expect(tok!"identifier");
3425                 if (i !is null)
3426                     node.identifier = *i;
3427                 expect(tok!"=");
3428                 mixin(nullCheck!`node.expression = parseExpression()`);
3429             }
3430         }
3431 
3432         if (expect(tok!")") is null) { deallocate(node); return null; }
3433         if (currentIs(tok!"}"))
3434         {
3435             error("Statement expected", false);
3436             return node; // this line makes DCD better
3437         }
3438         mixin(nullCheck!`node.thenStatement = parseDeclarationOrStatement()`);
3439         if (currentIs(tok!"else"))
3440         {
3441             advance();
3442             mixin(nullCheck!`node.elseStatement = parseDeclarationOrStatement()`);
3443         }
3444         return node;
3445     }
3446 
3447     /**
3448      * Parses an ImportBind
3449      *
3450      * $(GRAMMAR $(RULEDEF importBind):
3451      *     $(LITERAL Identifier) ($(LITERAL '=') $(LITERAL Identifier))?
3452      *     ;)
3453      */
3454     ImportBind parseImportBind()
3455     {
3456         auto node = allocate!ImportBind;
3457         const ident = expect(tok!"identifier");
3458         if (ident is null) { deallocate(node); return null; }
3459         node.left = *ident;
3460         if (currentIs(tok!"="))
3461         {
3462             advance();
3463             const id = expect(tok!"identifier");
3464             if (id is null) { deallocate(node); return null; }
3465             node.right = *id;
3466         }
3467         return node;
3468     }
3469 
3470     /**
3471      * Parses ImportBindings
3472      *
3473      * $(GRAMMAR $(RULEDEF importBindings):
3474      *     $(RULE singleImport) $(LITERAL ':') $(RULE importBind) ($(LITERAL ',') $(RULE importBind))*
3475      *     ;)
3476      */
3477     ImportBindings parseImportBindings(SingleImport singleImport)
3478     {
3479         auto node = allocate!ImportBindings;
3480         node.singleImport = singleImport is null ? parseSingleImport() : singleImport;
3481         if (expect(tok!":") is null) { deallocate(node); return null; }
3482         ImportBind[] importBinds;
3483         while (moreTokens())
3484         {
3485             auto b = parseImportBind();
3486             if (b !is null)
3487             {
3488                 importBinds ~= b;
3489                 if (currentIs(tok!","))
3490                     advance();
3491                 else
3492                     break;
3493             }
3494             else
3495                 break;
3496         }
3497         node.importBinds = ownArray(importBinds);
3498         return node;
3499     }
3500 
3501     /**
3502      * Parses an ImportDeclaration
3503      *
3504      * $(GRAMMAR $(RULEDEF importDeclaration):
3505      *       $(LITERAL 'import') $(RULE singleImport) ($(LITERAL ',') $(RULE singleImport))* ($(LITERAL ',') $(RULE importBindings))? $(LITERAL ';')
3506      *     | $(LITERAL 'import') $(RULE importBindings) $(LITERAL ';')
3507      *     ;)
3508      */
3509     ImportDeclaration parseImportDeclaration()
3510     {
3511         auto node = allocate!ImportDeclaration;
3512         if (expect(tok!"import") is null) { deallocate(node); return null; }
3513 
3514         node.comment = comment;
3515         comment = null;
3516 	node.line = current.line;
3517 
3518         SingleImport si = parseSingleImport();
3519         if (currentIs(tok!":"))
3520             node.importBindings = parseImportBindings(si);
3521         else
3522         {
3523             SingleImport[] singleImports;
3524             singleImports ~= si;
3525             if (currentIs(tok!","))
3526             {
3527                 advance();
3528                 while (moreTokens())
3529                 {
3530                     auto single = parseSingleImport();
3531                     if (single is null)
3532                         return null;
3533                     if (currentIs(tok!":"))
3534                     {
3535                         node.importBindings = parseImportBindings(single);
3536                         break;
3537                     }
3538                     else
3539                     {
3540                         singleImports ~= single;
3541                         if (currentIs(tok!","))
3542                             advance();
3543                         else
3544                             break;
3545                     }
3546                 }
3547             }
3548             node.singleImports = ownArray(singleImports);
3549         }
3550         if (expect(tok!";") is null) { deallocate(node); return null; }
3551         return node;
3552     }
3553 
3554     /**
3555      * Parses an ImportExpression
3556      *
3557      * $(GRAMMAR $(RULEDEF importExpression):
3558      *     $(LITERAL 'import') $(LITERAL '$(LPAREN)') $(RULE assignExpression) $(LITERAL '$(RPAREN)')
3559      *     ;)
3560      */
3561     ImportExpression parseImportExpression()
3562     {
3563         auto node = allocate!ImportExpression;
3564         if (expect(tok!"import") is null) { deallocate(node); return null; }
3565         if (expect(tok!"(") is null) { deallocate(node); return null; }
3566         mixin(nullCheck!`node.assignExpression = parseAssignExpression()`);
3567         if (expect(tok!")") is null) { deallocate(node); return null; }
3568         return node;
3569     }
3570 
3571     /**
3572      * Parses an Index
3573      *
3574      * $(GRAMMAR $(RULEDEF index):
3575      *     $(RULE assignExpression) ($(LITERAL '..') $(RULE assignExpression))?
3576      *     ;
3577      * )
3578      */
3579     Index parseIndex()
3580     {
3581         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
3582         auto node = allocate!Index();
3583         mixin(nullCheck!`node.low = parseAssignExpression()`);
3584         if (currentIs(tok!".."))
3585         {
3586             advance();
3587             mixin(nullCheck!`node.high = parseAssignExpression()`);
3588         }
3589         return node;
3590     }
3591 
3592     /**
3593      * Parses an IndexExpression
3594      *
3595      * $(GRAMMAR $(RULEDEF indexExpression):
3596      *       $(RULE unaryExpression) $(LITERAL '[') $(LITERAL ']')
3597      *     | $(RULE unaryExpression) $(LITERAL '[') $(RULE index) ($(LITERAL ',') $(RULE index))* $(LITERAL ']')
3598      *     ;
3599      * )
3600      */
3601     IndexExpression parseIndexExpression(UnaryExpression unaryExpression = null)
3602     {
3603         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
3604         auto node = allocate!IndexExpression;
3605         node.unaryExpression = unaryExpression is null ? parseUnaryExpression() : unaryExpression;
3606         mixin(nullCheck!`node.unaryExpression`);
3607         mixin(nullCheck!`expect(tok!"[")`);
3608         Index[] indexes;
3609         while (true)
3610         {
3611             if (!moreTokens())
3612             {
3613                 error("Expected unary expression instead of EOF");
3614                 deallocate(node);
3615                 return null;
3616             }
3617             if (currentIs(tok!"]"))
3618 				break;
3619             auto index = parseIndex();
3620             mixin(nullCheck!`index`);
3621             indexes ~= index;
3622 			if (currentIs(tok!","))
3623 				advance();
3624 			else
3625 				break;
3626         }
3627         node.indexes = ownArray(indexes);
3628 		advance(); // ]
3629 		return node;
3630     }
3631 
3632     /**
3633      * Parses an InExpression
3634      *
3635      * $(GRAMMAR $(RULEDEF inExpression):
3636      *     $(RULE shiftExpression) ($(LITERAL 'in') | ($(LITERAL '!') $(LITERAL 'in'))) $(RULE shiftExpression)
3637      *     ;)
3638      */
3639     ExpressionNode parseInExpression(ExpressionNode shift = null)
3640     {
3641         auto node = allocate!InExpression;
3642         node.left = shift is null ? parseShiftExpression() : shift;
3643         if (currentIs(tok!"!"))
3644         {
3645             node.negated = true;
3646             advance();
3647         }
3648         if (expect(tok!"in") is null) { deallocate(node); return null; }
3649         mixin(nullCheck!`node.right = parseShiftExpression()`);
3650         return node;
3651     }
3652 
3653     /**
3654      * Parses an InStatement
3655      *
3656      * $(GRAMMAR $(RULEDEF inStatement):
3657      *     $(LITERAL 'in') $(RULE blockStatement)
3658      *     ;)
3659      */
3660     InStatement parseInStatement()
3661     {
3662         auto node = allocate!InStatement;
3663         const i = expect(tok!"in");
3664         mixin(nullCheck!`i`);
3665         node.inTokenLocation = i.index;
3666 	if(currentIs(tok!"(")) {
3667 		advance();
3668 		mixin(nullCheck!`node.expression = parseExpression()`);
3669 		if (node.expression is null)
3670 		    return null;
3671              version(none)
3672 	     if(currentIs(tok!",")) {
3673 		advance();
3674                 parseExpression(); // FIXME: probably should store this but it is the string message
3675 
3676              }
3677 		expect(tok!")");
3678 	} else {
3679 		mixin(nullCheck!`node.blockStatement = parseBlockStatement()`);
3680 		if (node.blockStatement is null)
3681 		    return null;
3682 	}
3683         return node;
3684     }
3685 
3686     /**
3687      * Parses an Initializer
3688      *
3689      * $(GRAMMAR $(RULEDEF initializer):
3690      *       $(LITERAL 'void')
3691      *     | $(RULE nonVoidInitializer)
3692      *     ;)
3693      */
3694     Initializer parseInitializer()
3695     {
3696         auto node = allocate!Initializer;
3697         if (currentIs(tok!"void") && peekIsOneOf(tok!",", tok!";"))
3698             advance();
3699         else
3700             mixin(nullCheck!`node.nonVoidInitializer = parseNonVoidInitializer()`);
3701         return node;
3702     }
3703 
3704     /**
3705      * Parses an InterfaceDeclaration
3706      *
3707      * $(GRAMMAR $(RULEDEF interfaceDeclaration):
3708      *       $(LITERAL 'interface') $(LITERAL Identifier) $(LITERAL ';')
3709      *     | $(LITERAL 'interface') $(LITERAL Identifier) ($(LITERAL ':') $(RULE baseClassList))? $(RULE structBody)
3710      *     | $(LITERAL 'interface') $(LITERAL Identifier) $(RULE templateParameters) $(RULE constraint)? ($(LITERAL ':') $(RULE baseClassList))? $(RULE structBody)
3711      *     | $(LITERAL 'interface') $(LITERAL Identifier) $(RULE templateParameters) ($(LITERAL ':') $(RULE baseClassList))? $(RULE constraint)? $(RULE structBody)
3712      *     ;)
3713      */
3714     InterfaceDeclaration parseInterfaceDeclaration()
3715     {
3716         auto node = allocate!InterfaceDeclaration;
3717         expect(tok!"interface");
3718         mixin(PARSE_INTERFACE_OR_CLASS);
3719     }
3720 
3721     /**
3722      * Parses an Invariant
3723      *
3724      * $(GRAMMAR $(RULEDEF invariant):
3725      *     $(LITERAL 'invariant') ($(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)'))? $(RULE blockStatement)
3726      *     ;)
3727      */
3728     Invariant parseInvariant()
3729     {
3730         auto node = allocate!Invariant;
3731         node.index = current.index;
3732         node.line = current.line;
3733         if (expect(tok!"invariant") is null) { deallocate(node); return null; }
3734         if (currentIs(tok!"("))
3735         {
3736             advance();
3737             if (expect(tok!")") is null) { deallocate(node); return null; }
3738         }
3739         if ((node.blockStatement = parseBlockStatement()) is null) { deallocate(node); return null; }
3740         return node;
3741     }
3742 
3743     /**
3744      * Parses an IsExpression
3745      *
3746      * $(GRAMMAR $(RULEDEF isExpression):
3747      *     $(LITERAL'is') $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL identifier)? $(LITERAL '$(RPAREN)')
3748      *     $(LITERAL'is') $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL identifier)? $(LITERAL ':') $(RULE typeSpecialization) $(LITERAL '$(RPAREN)')
3749      *     $(LITERAL'is') $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL identifier)? $(LITERAL '=') $(RULE typeSpecialization) $(LITERAL '$(RPAREN)')
3750      *     $(LITERAL'is') $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL identifier)? $(LITERAL ':') $(RULE typeSpecialization) $(LITERAL ',') $(RULE templateParameterList) $(LITERAL '$(RPAREN)')
3751      *     $(LITERAL'is') $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL identifier)? $(LITERAL '=') $(RULE typeSpecialization) $(LITERAL ',') $(RULE templateParameterList) $(LITERAL '$(RPAREN)')
3752      *     ;)
3753      */
3754     IsExpression parseIsExpression()
3755     {
3756         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
3757         auto node = allocate!IsExpression;
3758         if (expect(tok!"is") is null) { deallocate(node); return null; }
3759         if (expect(tok!"(") is null) { deallocate(node); return null; }
3760         mixin(nullCheck!`node.type = parseType()`);
3761         if (node.type is null) { deallocate(node); return null; }
3762         if (currentIs(tok!"identifier"))
3763             node.identifier = advance();
3764         if (currentIsOneOf(tok!"==", tok!":"))
3765         {
3766             node.equalsOrColon = advance().type;
3767             mixin(nullCheck!`node.typeSpecialization = parseTypeSpecialization()`);
3768             if (currentIs(tok!","))
3769             {
3770                 advance();
3771                 mixin(nullCheck!`node.templateParameterList = parseTemplateParameterList()`);
3772             }
3773         }
3774         if (expect(tok!")") is null) { deallocate(node); return null; }
3775         return node;
3776     }
3777 
3778     /**
3779      * Parses a KeyValuePair
3780      *
3781      * $(GRAMMAR $(RULEDEF keyValuePair):
3782      *     $(RULE assignExpression) $(LITERAL ':') $(RULE assignExpression)
3783      *     ;)
3784      */
3785     KeyValuePair parseKeyValuePair()
3786     {
3787         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
3788         auto node = allocate!KeyValuePair;
3789         mixin(nullCheck!`node.key = parseAssignExpression()`);
3790         if (expect(tok!":") is null) { deallocate(node); return null; }
3791         mixin(nullCheck!`node.value = parseAssignExpression()`);
3792         return node;
3793     }
3794 
3795     /**
3796      * Parses KeyValuePairs
3797      *
3798      * $(GRAMMAR $(RULEDEF keyValuePairs):
3799      *     $(RULE keyValuePair) ($(LITERAL ',') $(RULE keyValuePair))* $(LITERAL ',')?
3800      *     ;)
3801      */
3802     KeyValuePairs parseKeyValuePairs()
3803     {
3804         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
3805         auto node = allocate!KeyValuePairs;
3806         KeyValuePair[] keyValuePairs;
3807         while (moreTokens())
3808         {
3809             auto kvPair = parseKeyValuePair();
3810             if (kvPair !is null)
3811                 keyValuePairs ~= kvPair;
3812             if (currentIs(tok!","))
3813             {
3814                 advance();
3815                 if (currentIs(tok!"]"))
3816                     break;
3817             }
3818             else
3819                 break;
3820         }
3821         node.keyValuePairs = ownArray(keyValuePairs);
3822         return node;
3823     }
3824 
3825     /**
3826      * Parses a LabeledStatement
3827      *
3828      * $(GRAMMAR $(RULEDEF labeledStatement):
3829      *     $(LITERAL Identifier) $(LITERAL ':') $(RULE declarationOrStatement)?
3830      *     ;)
3831      */
3832     LabeledStatement parseLabeledStatement()
3833     {
3834         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
3835         auto node = allocate!LabeledStatement;
3836         const ident = expect(tok!"identifier");
3837         if (ident is null) { deallocate(node); return null; }
3838         node.identifier = *ident;
3839         expect(tok!":");
3840         if (!currentIs(tok!"}"))
3841             mixin(nullCheck!`node.declarationOrStatement = parseDeclarationOrStatement()`);
3842         return node;
3843     }
3844 
3845     /**
3846      * Parses a LambdaExpression
3847      *
3848      * $(GRAMMAR $(RULEDEF lambdaExpression):
3849      *       $(LITERAL Identifier) $(LITERAL '=>') $(RULE assignExpression)
3850      *     | $(LITERAL 'function') $(RULE type)? $(RULE parameters) $(RULE functionAttribute)* $(LITERAL '=>') $(RULE assignExpression)
3851      *     | $(LITERAL 'delegate') $(RULE type)? $(RULE parameters) $(RULE functionAttribute)* $(LITERAL '=>') $(RULE assignExpression)
3852      *     | $(RULE parameters) $(RULE functionAttribute)* $(LITERAL '=>') $(RULE assignExpression)
3853      *     ;)
3854      */
3855     LambdaExpression parseLambdaExpression()
3856     {
3857         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
3858         auto node = allocate!LambdaExpression;
3859         if (currentIsOneOf(tok!"function", tok!"delegate"))
3860         {
3861             node.functionType = advance().type;
3862             if (!currentIs(tok!"("))
3863                 if ((node.returnType = parseType()) is null) { deallocate(node); return null; }
3864             goto lParen;
3865         }
3866         else if (startsWith(tok!"identifier", tok!"=>"))
3867         {
3868             node.identifier = advance();
3869             goto lambda;
3870         }
3871 
3872         if (currentIs(tok!"("))
3873         {
3874         lParen:
3875             mixin(nullCheck!`node.parameters = parseParameters()`);
3876             FunctionAttribute[] functionAttributes;
3877             while (moreTokens())
3878             {
3879                 auto attribute = parseFunctionAttribute(false);
3880                 if (attribute is null)
3881                     break;
3882                 functionAttributes ~= attribute;
3883             }
3884             node.functionAttributes = ownArray(functionAttributes);
3885         }
3886         else
3887         {
3888             error(`Identifier, type, or argument list expected`);
3889             return null;
3890         }
3891 
3892     lambda:
3893         if (expect(tok!"=>") is null) { deallocate(node); return null; }
3894         if ((node.assignExpression = parseAssignExpression()) is null) { deallocate(node); return null; }
3895         return node;
3896     }
3897 
3898     /**
3899      * Parses a LastCatch
3900      *
3901      * $(GRAMMAR $(RULEDEF lastCatch):
3902      *     $(LITERAL 'catch') $(RULE statementNoCaseNoDefault)
3903      *     ;)
3904      */
3905     LastCatch parseLastCatch()
3906     {
3907         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
3908         auto node = allocate!LastCatch;
3909         const t = expect(tok!"catch");
3910         if (t is null) { deallocate(node); return null; }
3911         node.line = t.line;
3912         node.column = t.column;
3913         if ((node.statementNoCaseNoDefault = parseStatementNoCaseNoDefault()) is null)
3914             return null;
3915         return node;
3916     }
3917 
3918     /**
3919      * Parses a LinkageAttribute
3920      *
3921      * $(GRAMMAR $(RULEDEF linkageAttribute):
3922      *     $(LITERAL 'extern') $(LITERAL '$(LPAREN)') $(LITERAL Identifier) ($(LITERAL '++') ($(LITERAL ',') $(RULE identifierChain))?)? $(LITERAL '$(RPAREN)')
3923      *     ;)
3924      */
3925     LinkageAttribute parseLinkageAttribute()
3926     {
3927         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
3928         auto node = allocate!LinkageAttribute;
3929         expect(tok!"extern");
3930         expect(tok!"(");
3931         const ident = expect(tok!"identifier");
3932         if (ident is null) { deallocate(node); return null; }
3933         node.identifier = *ident;
3934         if (currentIs(tok!"-"))
3935         {
3936             advance(); // skip the -
3937             advance(); // skip the C
3938         } else if (currentIs(tok!"++"))
3939         {
3940             advance();
3941             node.hasPlusPlus = true;
3942             if (currentIs(tok!","))
3943             {
3944                 advance();
3945 		if(currentIs(tok!"struct") || currentIs(tok!"class")) {
3946 			advance(); // FIXME: discarding it!
3947 
3948 		} else if(currentIs(tok!"(")) {
3949 			parseExpression(); // FIXME: discarding it!
3950 		} else
3951                 	mixin(nullCheck!`node.identifierChain = parseIdentifierChain()`);
3952             }
3953         }
3954         expect(tok!")");
3955         return node;
3956     }
3957 
3958     /**
3959      * Parses a MemberFunctionAttribute
3960      *
3961      * $(GRAMMAR $(RULEDEF memberFunctionAttribute):
3962      *       $(RULE functionAttribute)
3963      *     | $(LITERAL 'immutable')
3964      *     | $(LITERAL 'inout')
3965      *     | $(LITERAL 'shared')
3966      *     | $(LITERAL 'const')
3967      *     | $(LITERAL 'return')
3968      *     ;)
3969      */
3970     MemberFunctionAttribute parseMemberFunctionAttribute()
3971     {
3972         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
3973         auto node = allocate!MemberFunctionAttribute;
3974         switch (current.type)
3975         {
3976         case tok!"@":
3977             mixin(nullCheck!`node.atAttribute = parseAtAttribute()`);
3978             break;
3979         case tok!"immutable":
3980         case tok!"inout":
3981         case tok!"shared":
3982         case tok!"const":
3983         case tok!"pure":
3984         case tok!"nothrow":
3985         case tok!"return":
3986         case tok!"scope":
3987             node.tokenType = advance().type;
3988             break;
3989         default:
3990             error(`Member function attribute expected`);
3991         }
3992         return node;
3993     }
3994 
3995     /**
3996      * Parses a MixinDeclaration
3997      *
3998      * $(GRAMMAR $(RULEDEF mixinDeclaration):
3999      *       $(RULE mixinExpression) $(LITERAL ';')
4000      *     | $(RULE templateMixinExpression) $(LITERAL ';')
4001      *     ;)
4002      */
4003     MixinDeclaration parseMixinDeclaration()
4004     {
4005         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4006         auto node = allocate!MixinDeclaration;
4007         if (peekIsOneOf(tok!"identifier", tok!"typeof", tok!"."))
4008             mixin(nullCheck!`node.templateMixinExpression = parseTemplateMixinExpression()`);
4009         else if (peekIs(tok!"(")) {
4010             mixin(nullCheck!`node.mixinExpression = parseMixinExpression()`);
4011 
4012 	    if(auto ae = cast(UnaryExpression) node.mixinExpression.assignExpression) {
4013 	    	auto pe = ae.primaryExpression;
4014 		if(pe) {
4015 			auto txt = pe.primary.text;
4016 			if(txt.length > 5 && txt[0 .. 2] == "q{") {
4017 				txt = txt[2 .. $-1];
4018 
4019 				LexerConfig config;
4020 				StringCache* stringCache = new StringCache(128);
4021 
4022 				config.stringBehavior = StringBehavior.source;
4023 				config.whitespaceBehavior = WhitespaceBehavior.include;
4024 				config.fileName = "mixin";
4025 
4026 				auto tokens = getTokensForParser(cast(ubyte[]) txt, config, stringCache);
4027 
4028 				foreach(ref token; tokens) {
4029 					cast() token.line += pe.primary.line - 1;
4030 				}
4031 				auto m = .parseModule(tokens, "mixin");
4032 				node.trivialDeclarations = m.declarations.dup;
4033 			}
4034 		}
4035 	    }
4036 
4037 	    //node.trivialDeclarations = parseDeclaration
4038         } else
4039         {
4040             error(`"(" or identifier expected`);
4041             return null;
4042         }
4043         expect(tok!";");
4044         return node;
4045     }
4046 
4047     /**
4048      * Parses a MixinExpression
4049      *
4050      * $(GRAMMAR $(RULEDEF mixinExpression):
4051      *     $(LITERAL 'mixin') $(LITERAL '$(LPAREN)') $(RULE assignExpression) $(LITERAL '$(RPAREN)')
4052      *     ;)
4053      */
4054     MixinExpression parseMixinExpression()
4055     {
4056         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4057         auto node = allocate!MixinExpression;
4058         expect(tok!"mixin");
4059         expect(tok!"(");
4060 	moar:
4061 	    // FIXME: it discards the others...
4062             mixin(nullCheck!`node.assignExpression = parseAssignExpression()`);
4063         if (currentIs(tok!",")) {
4064 		advance();
4065 		goto moar;
4066 	}
4067         expect(tok!")");
4068         return node;
4069     }
4070 
4071     /**
4072      * Parses a MixinTemplateDeclaration
4073      *
4074      * $(GRAMMAR $(RULEDEF mixinTemplateDeclaration):
4075      *     $(LITERAL 'mixin') $(RULE templateDeclaration)
4076      *     ;)
4077      */
4078     MixinTemplateDeclaration parseMixinTemplateDeclaration()
4079     {
4080         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4081         auto node = allocate!MixinTemplateDeclaration;
4082         if (expect(tok!"mixin") is null) { deallocate(node); return null; }
4083         mixin(nullCheck!`node.templateDeclaration = parseTemplateDeclaration()`);
4084         if (node.templateDeclaration is null) { deallocate(node); return null; }
4085         return node;
4086     }
4087 
4088     /**
4089      * Parses a MixinTemplateName
4090      *
4091      * $(GRAMMAR $(RULEDEF mixinTemplateName):
4092      *       $(RULE symbol)
4093      *     | $(RULE typeofExpression) $(LITERAL '.') $(RULE identifierOrTemplateChain)
4094      *     ;)
4095      */
4096     MixinTemplateName parseMixinTemplateName()
4097     {
4098         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4099         auto node = allocate!MixinTemplateName;
4100         if (currentIs(tok!"typeof"))
4101         {
4102             mixin(nullCheck!`node.typeofExpression = parseTypeofExpression()`);
4103             expect(tok!".");
4104             mixin(nullCheck!`node.identifierOrTemplateChain = parseIdentifierOrTemplateChain()`);
4105         }
4106         else
4107             mixin(nullCheck!`node.symbol = parseSymbol()`);
4108         return node;
4109     }
4110 
4111     /**
4112      * Parses a Module
4113      *
4114      * $(GRAMMAR $(RULEDEF module):
4115      *     $(RULE moduleDeclaration)? $(RULE declaration)*
4116      *     ;)
4117      */
4118     Module parseModule()
4119     {
4120         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4121         Module m = allocate!Module;
4122         if (currentIs(tok!"scriptLine"))
4123             m.scriptLine = advance();
4124         bool isDeprecatedModule;
4125         if (currentIs(tok!"deprecated"))
4126         {
4127             auto b = setBookmark();
4128             advance();
4129             if (currentIs(tok!"("))
4130                 skipParens();
4131             isDeprecatedModule = currentIs(tok!"module");
4132             goToBookmark(b);
4133         }
4134         if (currentIs(tok!"module") || isDeprecatedModule)
4135             m.moduleDeclaration = parseModuleDeclaration();
4136         Declaration[] declarations;
4137         while (moreTokens())
4138         {
4139             auto declaration = parseDeclaration();
4140             if (declaration !is null)
4141                 declarations ~= declaration;
4142         }
4143         m.declarations = ownArray(declarations);
4144         return m;
4145     }
4146 
4147     /**
4148      * Parses a ModuleDeclaration
4149      *
4150      * $(GRAMMAR $(RULEDEF moduleDeclaration):
4151      *     $(RULE deprecated)? $(LITERAL 'module') $(RULE identifierChain) $(LITERAL ';')
4152      *     ;)
4153      */
4154     ModuleDeclaration parseModuleDeclaration()
4155     {
4156         auto node = allocate!ModuleDeclaration;
4157         if (currentIs(tok!"deprecated"))
4158             mixin(nullCheck!`node.deprecated_ = parseDeprecated()`);
4159         const start = expect(tok!"module");
4160         if (start is null) { deallocate(node); return null; }
4161         mixin(nullCheck!`node.moduleName = parseIdentifierChain()`);
4162         node.comment = start.comment;
4163         if (node.comment is null)
4164             node.comment = start.trailingComment;
4165         comment = null;
4166         const end = expect(tok!";");
4167         node.startLocation = start.index;
4168         if (end !is null)
4169             node.endLocation = end.index;
4170         return node;
4171     }
4172 
4173     /**
4174      * Parses a MulExpression.
4175      *
4176      * $(GRAMMAR $(RULEDEF mulExpression):
4177      *       $(RULE powExpression)
4178      *     | $(RULE mulExpression) ($(LITERAL '*') | $(LITERAL '/') | $(LITERAL '%')) $(RULE powExpression)
4179      *     ;)
4180      */
4181     ExpressionNode parseMulExpression()
4182     {
4183         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4184         return parseLeftAssocBinaryExpression!(MulExpression, PowExpression,
4185             tok!"*", tok!"/", tok!"%")();
4186     }
4187 
4188     /**
4189      * Parses a NewAnonClassExpression
4190      *
4191      * $(GRAMMAR $(RULEDEF newAnonClassExpression):
4192      *     $(LITERAL 'new') $(RULE arguments)? $(LITERAL 'class') $(RULE arguments)? $(RULE baseClassList)? $(RULE structBody)
4193      *     ;)
4194      */
4195     NewAnonClassExpression parseNewAnonClassExpression()
4196     {
4197         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4198         auto node = allocate!NewAnonClassExpression;
4199         expect(tok!"new");
4200         if (currentIs(tok!"("))
4201             mixin(nullCheck!`node.allocatorArguments = parseArguments()`);
4202         expect(tok!"class");
4203         if (currentIs(tok!"("))
4204             mixin(nullCheck!`node.constructorArguments = parseArguments()`);
4205         if (!currentIs(tok!"{"))
4206             mixin(nullCheck!`node.baseClassList = parseBaseClassList()`);
4207         mixin(nullCheck!`node.structBody = parseStructBody()`);
4208         return node;
4209     }
4210 
4211     /**
4212      * Parses a NewExpression
4213      *
4214      * $(GRAMMAR $(RULEDEF newExpression):
4215      *       $(LITERAL 'new') $(RULE type) (($(LITERAL '[') $(RULE assignExpression) $(LITERAL ']')) | $(RULE arguments))?
4216      *     | $(RULE newAnonClassExpression)
4217      *     ;)
4218      */
4219     NewExpression parseNewExpression()
4220     {
4221         // Parse ambiguity.
4222         // auto a = new int[10];
4223         //              ^^^^^^^
4224         // auto a = new int[10];
4225         //              ^^^****
4226         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4227         auto node = allocate!NewExpression;
4228         if (peekIsOneOf(tok!"class", tok!"("))
4229         {
4230             mixin(nullCheck!`node.newAnonClassExpression = parseNewAnonClassExpression()`);
4231             if (node.newAnonClassExpression is null)
4232             {
4233                 deallocate(node);
4234                 return null;
4235             }
4236         }
4237         else
4238         {
4239             expect(tok!"new");
4240             if (!moreTokens()) goto fail;
4241             if ((node.type = parseType()) is null) goto fail;
4242             if (currentIs(tok!"["))
4243             {
4244                 advance();
4245                 mixin(nullCheck!`node.assignExpression = parseAssignExpression()`);
4246                 expect(tok!"]");
4247             }
4248             else if (currentIs(tok!"("))
4249                 mixin(nullCheck!`node.arguments = parseArguments()`);
4250         }
4251         return node;
4252     fail:
4253         deallocate(node);
4254         return null;
4255     }
4256 
4257     /**
4258      * Parses a NonVoidInitializer
4259      *
4260      * $(GRAMMAR $(RULEDEF nonVoidInitializer):
4261      *       $(RULE assignExpression)
4262      *     | $(RULE arrayInitializer)
4263      *     | $(RULE structInitializer)
4264      *     ;)
4265      */
4266     NonVoidInitializer parseNonVoidInitializer()
4267     {
4268         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4269         auto node = allocate!NonVoidInitializer;
4270         if (currentIs(tok!"{"))
4271         {
4272             const b = peekPastBraces();
4273             if (b !is null && (b.type == tok!"("))
4274                 mixin(nullCheck!`node.assignExpression = parseAssignExpression()`);
4275             else
4276             {
4277                 assert (currentIs(tok!"{"));
4278                 auto m = setBookmark();
4279                 auto initializer = parseStructInitializer();
4280                 if (initializer !is null)
4281                 {
4282                     node.structInitializer = initializer;
4283                     abandonBookmark(m);
4284                 }
4285                 else
4286                 {
4287                     goToBookmark(m);
4288                     mixin(nullCheck!`node.assignExpression = parseAssignExpression()`);
4289                 }
4290             }
4291         }
4292         else if (currentIs(tok!"["))
4293         {
4294             const b = peekPastBrackets();
4295             if (b !is null && (b.type == tok!","
4296                 || b.type == tok!")"
4297                 || b.type == tok!"]"
4298                 || b.type == tok!"}"
4299                 || b.type == tok!";"))
4300             {
4301                 mixin(nullCheck!`node.arrayInitializer = parseArrayInitializer()`);
4302             }
4303             else
4304                 mixin(nullCheck!`node.assignExpression = parseAssignExpression()`);
4305         }
4306         else
4307             mixin(nullCheck!`node.assignExpression = parseAssignExpression()`);
4308         if (node.assignExpression is null && node.arrayInitializer is null
4309             && node.structInitializer is null)
4310         {
4311             deallocate(node);
4312             return null;
4313         }
4314         return node;
4315     }
4316 
4317     /**
4318      * Parses Operands
4319      *
4320      * $(GRAMMAR $(RULEDEF operands):
4321      *       $(RULE asmExp)
4322      *     | $(RULE asmExp) $(LITERAL ',') $(RULE operands)
4323      *     ;)
4324      */
4325     Operands parseOperands()
4326     {
4327         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4328         Operands node = allocate!Operands;
4329         ExpressionNode[] expressions;
4330         while (true)
4331         {
4332             ExpressionNode exp = parseAsmExp();
4333             if (exp is null)
4334                 return null;
4335             expressions ~= exp;
4336             if (currentIs(tok!","))
4337                 advance();
4338             else
4339                 break;
4340         }
4341         node.operands = ownArray(expressions);
4342         return node;
4343     }
4344 
4345     /**
4346      * Parses an OrExpression
4347      *
4348      * $(GRAMMAR $(RULEDEF orExpression):
4349      *       $(RULE xorExpression)
4350      *     | $(RULE orExpression) $(LITERAL '|') $(RULE xorExpression)
4351      *     ;)
4352      */
4353     ExpressionNode parseOrExpression()
4354     {
4355         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4356         return parseLeftAssocBinaryExpression!(OrExpression, XorExpression,
4357             tok!"|")();
4358     }
4359 
4360     /**
4361      * Parses an OrOrExpression
4362      *
4363      * $(GRAMMAR $(RULEDEF orOrExpression):
4364      *       $(RULE andAndExpression)
4365      *     | $(RULE orOrExpression) $(LITERAL '||') $(RULE andAndExpression)
4366      *     ;)
4367      */
4368     ExpressionNode parseOrOrExpression()
4369     {
4370         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4371         return parseLeftAssocBinaryExpression!(OrOrExpression, AndAndExpression,
4372             tok!"||")();
4373     }
4374 
4375     /**
4376      * Parses an OutStatement
4377      *
4378      * $(GRAMMAR $(RULEDEF outStatement):
4379      *     $(LITERAL 'out') ($(LITERAL '$(LPAREN)') $(LITERAL Identifier) $(LITERAL '$(RPAREN)'))? $(RULE blockStatement)
4380      *     ;)
4381      */
4382     OutStatement parseOutStatement()
4383     {
4384         auto node = allocate!OutStatement;
4385         const o = expect(tok!"out");
4386         mixin(nullCheck!`o`);
4387         node.outTokenLocation = o.index;
4388 
4389 /*
4390 	if tere's a semicolon in the parens, it is the short syntax.
4391 */
4392 
4393         if (currentIs(tok!"("))
4394         {
4395             advance();
4396 	    if(currentIs(tok!"identifier")) {
4397             	const ident = expect(tok!"identifier");
4398             	node.parameter = *ident;
4399 	}
4400 	    if(currentIs(tok!";")) {
4401 			// short syntax......
4402 			advance();
4403 			node.expression = parseExpression;
4404             		expect(tok!")");
4405 			return node;
4406 	    } else {
4407             		expect(tok!")");
4408 	    }
4409         }
4410         mixin(nullCheck!`node.blockStatement = parseBlockStatement()`);
4411         if (node.blockStatement is null)
4412             return null;
4413         return node;
4414     }
4415 
4416     /**
4417      * Parses a Parameter
4418      *
4419      * $(GRAMMAR $(RULEDEF parameter):
4420      *     $(RULE parameterAttribute)* $(RULE type)
4421      *     $(RULE parameterAttribute)* $(RULE type) $(LITERAL Identifier)? $(LITERAL '...')
4422      *     $(RULE parameterAttribute)* $(RULE type) $(LITERAL Identifier)? ($(LITERAL '=') $(RULE assignExpression))?
4423      *     ;)
4424      */
4425     Parameter parseParameter()
4426     {
4427         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4428         auto node = allocate!Parameter;
4429 
4430         node.comment = current.comment;
4431 
4432         while (moreTokens())
4433 	{
4434 		if(currentIs(tok!"@")) {
4435 			AtAttribute atAttribute;
4436 			mixin(nullCheck!`atAttribute = parseAtAttribute()`);
4437 			if (atAttribute is null) { deallocate(node); break; }
4438 			node.atAttributes ~= atAttribute;
4439 		} else {
4440 			break;
4441 		}
4442 	}
4443 
4444         IdType[] parameterAttributes;
4445         while (moreTokens())
4446         {
4447             IdType type = parseParameterAttribute(false);
4448             if (type == tok!"")
4449                 break;
4450             else
4451                 parameterAttributes ~= type;
4452         }
4453         node.parameterAttributes = ownArray(parameterAttributes);
4454         mixin(nullCheck!`node.type = parseType()`);
4455         if (node.type is null) { deallocate(node); return null; }
4456         if (currentIs(tok!"identifier"))
4457         {
4458             node.name = advance();
4459             if (currentIs(tok!"..."))
4460             {
4461                 advance();
4462                 node.vararg = true;
4463             }
4464             else if (currentIs(tok!"="))
4465             {
4466                 advance();
4467                 mixin(nullCheck!`node.default_ = parseAssignExpression()`);
4468             }
4469             else if (currentIs(tok!"["))
4470             {
4471                 TypeSuffix[] typeSuffixes;
4472                 while(moreTokens() && currentIs(tok!"["))
4473                 {
4474                     auto suffix = parseTypeSuffix();
4475                     if (suffix !is null)
4476                         typeSuffixes ~= suffix;
4477                     else
4478                         return null;
4479                 }
4480                 node.cstyle = ownArray(typeSuffixes);
4481             }
4482         }
4483         else if (currentIs(tok!"..."))
4484         {
4485             node.vararg = true;
4486             advance();
4487         }
4488         else if (currentIs(tok!"="))
4489         {
4490             advance();
4491             mixin(nullCheck!`node.default_ = parseAssignExpression()`);
4492         }
4493         return node;
4494     }
4495 
4496     /**
4497      * Parses a ParameterAttribute
4498      *
4499      * $(GRAMMAR $(RULEDEF parameterAttribute):
4500      *       $(RULE typeConstructor)
4501      *     | $(LITERAL 'final')
4502      *     | $(LITERAL 'in')
4503      *     | $(LITERAL 'lazy')
4504      *     | $(LITERAL 'out')
4505      *     | $(LITERAL 'ref')
4506      *     | $(LITERAL 'scope')
4507      *     | $(LITERAL 'auto')
4508      *     | $(LITERAL 'return')
4509      *     ;)
4510      */
4511     IdType parseParameterAttribute(bool validate = false)
4512     {
4513         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4514         switch (current.type)
4515         {
4516         case tok!"immutable":
4517         case tok!"shared":
4518         case tok!"const":
4519         case tok!"inout":
4520             if (peekIs(tok!"("))
4521                 return tok!"";
4522             else
4523                 goto case;
4524         case tok!"final":
4525         case tok!"in":
4526         case tok!"lazy":
4527         case tok!"out":
4528         case tok!"ref":
4529         case tok!"scope":
4530         case tok!"auto":
4531         case tok!"return":
4532             return advance().type;
4533         default:
4534             if (validate)
4535                 error("Parameter attribute expected");
4536             return tok!"";
4537         }
4538     }
4539 
4540     /**
4541      * Parses Parameters
4542      *
4543      * $(GRAMMAR $(RULEDEF parameters):
4544      *       $(LITERAL '$(LPAREN)') $(RULE parameter) ($(LITERAL ',') $(RULE parameter))* ($(LITERAL ',') $(LITERAL '...'))? $(LITERAL '$(RPAREN)')
4545      *     | $(LITERAL '$(LPAREN)') $(LITERAL '...') $(LITERAL '$(RPAREN)')
4546      *     | $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)')
4547      *     ;)
4548      */
4549     Parameters parseParameters()
4550     {
4551         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4552         auto node = allocate!Parameters;
4553         if (expect(tok!"(") is null) { deallocate(node); return null; }
4554         Parameter[] parameters;
4555         if (currentIs(tok!")"))
4556             goto end;
4557         if (currentIs(tok!"..."))
4558         {
4559             advance();
4560             node.hasVarargs = true;
4561             goto end;
4562         }
4563         while (moreTokens())
4564         {
4565             if (currentIs(tok!"..."))
4566             {
4567                 advance();
4568                 node.hasVarargs = true;
4569                 break;
4570             }
4571             if (currentIs(tok!")"))
4572                 break;
4573             auto param = parseParameter();
4574             if (param is null)
4575                 return null;
4576             parameters ~= param;
4577             if (currentIs(tok!","))
4578                 advance();
4579             else
4580                 break;
4581         }
4582         node.parameters = ownArray(parameters);
4583     end:
4584         if (expect(tok!")") is null)
4585             return null;
4586         return node;
4587     }
4588 
4589     /**
4590      * Parses a Postblit
4591      *
4592      * $(GRAMMAR $(RULEDEF postblit):
4593      *     $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL 'this') $(LITERAL '$(RPAREN)') $(RULE memberFunctionAttribute)* ($(RULE functionBody) | $(LITERAL ';'))
4594      *     ;)
4595      */
4596     Postblit parsePostblit()
4597     {
4598         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4599         auto node = allocate!Postblit;
4600 	node.comment = comment;
4601 	node.line = current.line;
4602 	comment = null;
4603         expect(tok!"this");
4604         expect(tok!"(");
4605         expect(tok!"this");
4606         expect(tok!")");
4607         MemberFunctionAttribute[] memberFunctionAttributes;
4608         while (currentIsMemberFunctionAttribute())
4609             memberFunctionAttributes ~= parseMemberFunctionAttribute();
4610         node.memberFunctionAttributes = ownArray(memberFunctionAttributes);
4611         if (currentIs(tok!";"))
4612             advance();
4613         else
4614             mixin(nullCheck!`node.functionBody = parseFunctionBody()`);
4615         return node;
4616     }
4617 
4618     /**
4619      * Parses a PowExpression
4620      *
4621      * $(GRAMMAR $(RULEDEF powExpression):
4622      *       $(RULE unaryExpression)
4623      *     | $(RULE powExpression) $(LITERAL '^^') $(RULE unaryExpression)
4624      *     ;)
4625      */
4626     ExpressionNode parsePowExpression()
4627     {
4628         mixin(traceEnterAndExit!(__FUNCTION__));
4629         return parseLeftAssocBinaryExpression!(PowExpression, UnaryExpression,
4630             tok!"^^")();
4631     }
4632 
4633     /**
4634      * Parses a PragmaDeclaration
4635      *
4636      * $(GRAMMAR $(RULEDEF pragmaDeclaration):
4637      *     $(RULE pragmaExpression) $(LITERAL ';')
4638      *     ;)
4639      */
4640     PragmaDeclaration parsePragmaDeclaration()
4641     {
4642         mixin(traceEnterAndExit!(__FUNCTION__));
4643         auto node = allocate!PragmaDeclaration;
4644         mixin(nullCheck!`node.pragmaExpression = parsePragmaExpression()`);
4645         expect(tok!";");
4646         return node;
4647     }
4648 
4649     /**
4650      * Parses a PragmaExpression
4651      *
4652      * $(GRAMMAR $(RULEDEF pragmaExpression):
4653      *     $(RULE 'pragma') $(LITERAL '$(LPAREN)') $(LITERAL Identifier) ($(LITERAL ',') $(RULE argumentList))? $(LITERAL '$(RPAREN)')
4654      *     ;)
4655      */
4656     PragmaExpression parsePragmaExpression()
4657     {
4658         mixin(traceEnterAndExit!(__FUNCTION__));
4659         auto node = allocate!PragmaExpression;
4660         expect(tok!"pragma");
4661         expect(tok!"(");
4662         const ident = expect(tok!"identifier");
4663         if (ident is null) { deallocate(node); return null; }
4664         node.identifier = *ident;
4665         if (currentIs(tok!","))
4666         {
4667             advance();
4668             mixin(nullCheck!`node.argumentList = parseArgumentList()`);
4669         }
4670         expect(tok!")");
4671         return node;
4672     }
4673 
4674     /**
4675      * Parses a PrimaryExpression
4676      *
4677      * $(GRAMMAR $(RULEDEF primaryExpression):
4678      *       $(RULE identifierOrTemplateInstance)
4679      *     | $(LITERAL '.') $(RULE identifierOrTemplateInstance)
4680      *     | $(RULE typeConstructor) $(LITERAL '$(LPAREN)') $(RULE basicType) $(LITERAL '$(RPAREN)') $(LITERAL '.') $(LITERAL Identifier)
4681      *     | $(RULE basicType) $(LITERAL '.') $(LITERAL Identifier)
4682      *     | $(RULE basicType) $(RULE arguments)
4683      *     | $(RULE typeofExpression)
4684      *     | $(RULE typeidExpression)
4685      *     | $(RULE vector)
4686      *     | $(RULE arrayLiteral)
4687      *     | $(RULE assocArrayLiteral)
4688      *     | $(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)')
4689      *     | $(RULE isExpression)
4690      *     | $(RULE lambdaExpression)
4691      *     | $(RULE functionLiteralExpression)
4692      *     | $(RULE traitsExpression)
4693      *     | $(RULE mixinExpression)
4694      *     | $(RULE importExpression)
4695      *     | $(LITERAL '$')
4696      *     | $(LITERAL 'this')
4697      *     | $(LITERAL 'super')
4698      *     | $(LITERAL '_null')
4699      *     | $(LITERAL '_true')
4700      *     | $(LITERAL '_false')
4701      *     | $(LITERAL '___DATE__')
4702      *     | $(LITERAL '___TIME__')
4703      *     | $(LITERAL '___TIMESTAMP__')
4704      *     | $(LITERAL '___VENDOR__')
4705      *     | $(LITERAL '___VERSION__')
4706      *     | $(LITERAL '___FILE__')
4707      *     | $(LITERAL '___LINE__')
4708      *     | $(LITERAL '___MODULE__')
4709      *     | $(LITERAL '___FUNCTION__')
4710      *     | $(LITERAL '___PRETTY_FUNCTION__')
4711      *     | $(LITERAL IntegerLiteral)
4712      *     | $(LITERAL FloatLiteral)
4713      *     | $(LITERAL StringLiteral)+
4714      *     | $(LITERAL CharacterLiteral)
4715      *     ;)
4716      */
4717     PrimaryExpression parsePrimaryExpression()
4718     {
4719         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4720         auto node = allocate!PrimaryExpression;
4721         if (!moreTokens())
4722         {
4723             error("Expected primary statement instead of EOF");
4724             return null;
4725         }
4726         switch (current.type)
4727         {
4728         case tok!".":
4729             node.dot = advance();
4730             goto case;
4731         case tok!"identifier":
4732             if (peekIs(tok!"=>"))
4733                 mixin(nullCheck!`node.lambdaExpression = parseLambdaExpression()`);
4734             else
4735                 mixin(nullCheck!`node.identifierOrTemplateInstance = parseIdentifierOrTemplateInstance()`);
4736             break;
4737         case tok!"immutable":
4738         case tok!"const":
4739         case tok!"inout":
4740         case tok!"shared":
4741             advance();
4742             expect(tok!"(");
4743             mixin(nullCheck!`node.type = parseType()`);
4744             expect(tok!")");
4745             expect(tok!".");
4746 	    {
4747             const ident = expect(tok!"identifier");
4748             if (ident !is null)
4749                 node.primary = *ident;
4750 	    }
4751             break;
4752         mixin(BUILTIN_TYPE_CASES);
4753             node.basicType = advance();
4754             if (currentIs(tok!"."))
4755             {
4756                 advance();
4757                 const t = expect(tok!"identifier");
4758                 if (t !is null)
4759                     node.primary = *t;
4760             }
4761             else if (currentIs(tok!"("))
4762                 mixin(nullCheck!`node.arguments = parseArguments()`);
4763             break;
4764         case tok!"function":
4765         case tok!"delegate":
4766             if (peekIs(tok!"("))
4767             {
4768                 auto b = setBookmark();
4769                 advance(); // function | delegate
4770                 skipParens();
4771                 while (isAttribute())
4772                     parseAttribute();
4773                 if (currentIs(tok!"=>"))
4774                 {
4775                     goToBookmark(b);
4776                     mixin(nullCheck!`node.lambdaExpression = parseLambdaExpression()`);
4777                     break;
4778                 }
4779                 else
4780                 {
4781                     goToBookmark(b);
4782                     mixin(nullCheck!`node.functionLiteralExpression = parseFunctionLiteralExpression()`);
4783                     break;
4784                 }
4785             }
4786             else if (peekIs(tok!"{"))
4787             {
4788                 mixin(nullCheck!`node.functionLiteralExpression = parseFunctionLiteralExpression()`);
4789                 break;
4790             }
4791             else
4792             {
4793                 auto b = setBookmark();
4794                 advance(); // function or delegate
4795                 if (parseType() is null)
4796                 {
4797                     goToBookmark(b);
4798                     goto case;
4799                 }
4800                 if (!currentIs(tok!"("))
4801                 {
4802                     goToBookmark(b);
4803                     goto case;
4804                 }
4805                 skipParens();
4806                 while (currentIsMemberFunctionAttribute())
4807                     parseMemberFunctionAttribute();
4808                 if (!currentIs(tok!"=>"))
4809                 {
4810                     goToBookmark(b);
4811                     goto case;
4812                 }
4813                 goToBookmark(b);
4814                 if ((node.lambdaExpression = parseLambdaExpression()) is null) { deallocate(node); return null; }
4815                 return node;
4816             }
4817         case tok!"{":
4818         case tok!"in":
4819         case tok!"out":
4820         // case tok!"body":
4821         case tok!"do":
4822             if ((node.functionLiteralExpression = parseFunctionLiteralExpression()) is null)
4823             {
4824                 deallocate(node);
4825                 return null;
4826             }
4827             break;
4828         case tok!"typeof":
4829             mixin(nullCheck!`node.typeofExpression = parseTypeofExpression()`);
4830             break;
4831         case tok!"typeid":
4832             mixin(nullCheck!`node.typeidExpression = parseTypeidExpression()`);
4833             break;
4834         case tok!"__vector":
4835             mixin(nullCheck!`node.vector = parseVector()`);
4836             break;
4837         case tok!"[":
4838             if (isAssociativeArrayLiteral())
4839                 mixin(nullCheck!`node.assocArrayLiteral = parseAssocArrayLiteral()`);
4840             else
4841                 mixin(nullCheck!`node.arrayLiteral = parseArrayLiteral()`);
4842             break;
4843         case tok!"(":
4844             auto b = setBookmark();
4845             skipParens();
4846             while (isAttribute())
4847                 parseAttribute();
4848             if (currentIs(tok!"=>"))
4849             {
4850                 goToBookmark(b);
4851                 mixin(nullCheck!`node.lambdaExpression = parseLambdaExpression()`);
4852             }
4853             else if (currentIs(tok!"{"))
4854             {
4855                 goToBookmark(b);
4856                 mixin(nullCheck!`node.functionLiteralExpression = parseFunctionLiteralExpression()`);
4857             }
4858             else
4859             {
4860                 goToBookmark(b);
4861                 advance();
4862                 mixin(nullCheck!`node.expression = parseExpression()`);
4863                 mixin(nullCheck!`expect(tok!")")`);
4864             }
4865             break;
4866         case tok!"is":
4867             mixin(nullCheck!`node.isExpression = parseIsExpression()`);
4868             break;
4869         case tok!"__traits":
4870             mixin(nullCheck!`node.traitsExpression = parseTraitsExpression()`);
4871             break;
4872         case tok!"mixin":
4873             mixin(nullCheck!`node.mixinExpression = parseMixinExpression()`);
4874             break;
4875         case tok!"import":
4876             mixin(nullCheck!`node.importExpression = parseImportExpression()`);
4877             break;
4878         case tok!"$":
4879         case tok!"this":
4880         case tok!"super":
4881         case tok!"null":
4882         case tok!"true":
4883         case tok!"false":
4884         mixin(SPECIAL_CASES);
4885         mixin(LITERAL_CASES);
4886             if (currentIsOneOf(tok!"stringLiteral", tok!"wstringLiteral", tok!"dstringLiteral"))
4887             {
4888                 node.primary = advance();
4889                 bool alreadyWarned = false;
4890                 while (currentIsOneOf(tok!"stringLiteral", tok!"wstringLiteral",
4891                     tok!"dstringLiteral"))
4892                 {
4893                     if (!alreadyWarned)
4894                     {
4895                         warn("Implicit concatenation of string literals");
4896                         alreadyWarned = true;
4897                     }
4898                     node.primary.text ~= advance().text;
4899                 }
4900             }
4901             else
4902                 node.primary = advance();
4903             break;
4904         default:
4905             deallocate(node);
4906             error("Primary expression expected");
4907             return null;
4908         }
4909         return node;
4910     }
4911 
4912     /**
4913      * Parses a Register
4914      *
4915      * $(GRAMMAR $(RULEDEF register):
4916      *       $(LITERAL Identifier)
4917      *     | $(LITERAL Identifier) $(LITERAL '$(LPAREN)') $(LITERAL IntegerLiteral) $(LITERAL '$(RPAREN)')
4918      *     ;)
4919      */
4920     Register parseRegister()
4921     {
4922         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4923         auto node = allocate!Register;
4924         const ident = expect(tok!"identifier");
4925         if (ident is null) { deallocate(node); return null; }
4926         node.identifier = *ident;
4927         if (currentIs(tok!"("))
4928         {
4929             advance();
4930             const intLit = expect(tok!"intLiteral");
4931             if (intLit is null) { deallocate(node); return null; }
4932             node.intLiteral = *intLit;
4933             expect(tok!")");
4934         }
4935         return node;
4936     }
4937 
4938     /**
4939      * Parses a RelExpression
4940      *
4941      * $(GRAMMAR $(RULEDEF relExpression):
4942      *       $(RULE shiftExpression)
4943      *     | $(RULE relExpression) $(RULE relOperator) $(RULE shiftExpression)
4944      *     ;
4945      *$(RULEDEF relOperator):
4946      *       $(LITERAL '<')
4947      *     | $(LITERAL '<=')
4948      *     | $(LITERAL '>')
4949      *     | $(LITERAL '>=')
4950      *     | $(LITERAL '!<>=')
4951      *     | $(LITERAL '!<>')
4952      *     | $(LITERAL '<>')
4953      *     | $(LITERAL '<>=')
4954      *     | $(LITERAL '!>')
4955      *     | $(LITERAL '!>=')
4956      *     | $(LITERAL '!<')
4957      *     | $(LITERAL '!<=')
4958      *     ;)
4959      */
4960     ExpressionNode parseRelExpression(ExpressionNode shift)
4961     {
4962         mixin(traceEnterAndExit!(__FUNCTION__));
4963         return parseLeftAssocBinaryExpression!(RelExpression, ShiftExpression,
4964             tok!"<", tok!"<=", tok!">", tok!">=", tok!"!<>=", tok!"!<>",
4965             tok!"<>", tok!"<>=", tok!"!>", tok!"!>=", tok!"!>=", tok!"!<",
4966             tok!"!<=")(shift);
4967     }
4968 
4969     /**
4970      * Parses a ReturnStatement
4971      *
4972      * $(GRAMMAR $(RULEDEF returnStatement):
4973      *     $(LITERAL 'return') $(RULE expression)? $(LITERAL ';')
4974      *     ;)
4975      */
4976     ReturnStatement parseReturnStatement()
4977     {
4978         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
4979         auto node = allocate!ReturnStatement;
4980         const start = expect(tok!"return");
4981         if (start is null) { deallocate(node); return null; }
4982         node.startLocation = start.index;
4983         if (!currentIs(tok!";"))
4984         {
4985             if ((node.expression = parseExpression()) is null)
4986             {
4987                 deallocate(node);
4988                 return null;
4989             }
4990         }
4991         const semicolon = expect(tok!";");
4992         if (semicolon is null) { deallocate(node); return null; }
4993         node.endLocation = semicolon.index;
4994         return node;
4995     }
4996 
4997     /**
4998      * Parses a ScopeGuardStatement
4999      *
5000      * $(GRAMMAR $(RULEDEF scopeGuardStatement):
5001      *     $(LITERAL 'scope') $(LITERAL '$(LPAREN)') $(LITERAL Identifier) $(LITERAL '$(RPAREN)') $(RULE statementNoCaseNoDefault)
5002      *     ;)
5003      */
5004     ScopeGuardStatement parseScopeGuardStatement()
5005     {
5006         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5007         auto node = allocate!ScopeGuardStatement;
5008         expect(tok!"scope");
5009         expect(tok!"(");
5010         const ident = expect(tok!"identifier");
5011         if (ident is null) { deallocate(node); return null; }
5012         node.identifier = *ident;
5013         expect(tok!")");
5014         mixin(nullCheck!`node.statementNoCaseNoDefault = parseStatementNoCaseNoDefault()`);
5015         return node;
5016     }
5017 
5018     /**
5019      * Parses a SharedStaticConstructor
5020      *
5021      * $(GRAMMAR $(RULEDEF sharedStaticConstructor):
5022      *     $(LITERAL 'shared') $(LITERAL 'static') $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)') $(RULE functionBody)
5023      *     ;)
5024      */
5025     SharedStaticConstructor parseSharedStaticConstructor()
5026     {
5027         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5028         mixin(simpleParse!(SharedStaticConstructor, tok!"shared", tok!"static",
5029             tok!"this", tok!"(", tok!")", "functionBody|parseFunctionBody"));
5030     }
5031 
5032     /**
5033      * Parses a SharedStaticDestructor
5034      *
5035      * $(GRAMMAR $(RULEDEF sharedStaticDestructor):
5036      *     $(LITERAL 'shared') $(LITERAL 'static') $(LITERAL '~') $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)') $(RULE functionBody)
5037      *     ;)
5038      */
5039     SharedStaticDestructor parseSharedStaticDestructor()
5040     {
5041         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5042         mixin(simpleParse!(SharedStaticDestructor, tok!"shared", tok!"static",
5043             tok!"~", tok!"this", tok!"(", tok!")",
5044             "functionBody|parseFunctionBody"));
5045     }
5046 
5047     /**
5048      * Parses a ShiftExpression
5049      *
5050      * $(GRAMMAR $(RULEDEF shiftExpression):
5051      *       $(RULE addExpression)
5052      *     | $(RULE shiftExpression) ($(LITERAL '<<') | $(LITERAL '>>') | $(LITERAL '>>>')) $(RULE addExpression)
5053      *     ;)
5054      */
5055     ExpressionNode parseShiftExpression()
5056     {
5057         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5058         return parseLeftAssocBinaryExpression!(ShiftExpression, AddExpression,
5059             tok!"<<", tok!">>", tok!">>>")();
5060     }
5061 
5062     /**
5063      * Parses a SingleImport
5064      *
5065      * $(GRAMMAR $(RULEDEF singleImport):
5066      *     ($(LITERAL Identifier) $(LITERAL '='))? $(RULE identifierChain)
5067      *     ;)
5068      */
5069     SingleImport parseSingleImport()
5070     {
5071         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5072         auto node = allocate!SingleImport;
5073         if (startsWith(tok!"identifier", tok!"="))
5074         {
5075             node.rename = advance();
5076             advance(); // =
5077         }
5078         mixin(nullCheck!`node.identifierChain = parseIdentifierChain()`);
5079         if (node.identifierChain is null)
5080             return null;
5081         return node;
5082     }
5083 
5084     /**
5085      * Parses a Statement
5086      *
5087      * $(GRAMMAR $(RULEDEF statement):
5088      *       $(RULE statementNoCaseNoDefault)
5089      *     | $(RULE caseStatement)
5090      *     | $(RULE caseRangeStatement)
5091      *     | $(RULE defaultStatement)
5092      *     ;)
5093      */
5094     Statement parseStatement()
5095     {
5096         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5097         auto node = allocate!Statement;
5098         if (!moreTokens())
5099         {
5100             error("Expected statement instead of EOF");
5101             return null;
5102         }
5103         switch (current.type)
5104         {
5105         case tok!"case":
5106             advance();
5107             auto argumentList = parseArgumentList();
5108             if (argumentList is null)
5109             {
5110                 deallocate(node);
5111                 return null;
5112             }
5113             if (argumentList.items.length == 1 && startsWith(tok!":", tok!".."))
5114                 node.caseRangeStatement = parseCaseRangeStatement(argumentList.items[0]);
5115             else
5116                 node.caseStatement = parseCaseStatement(argumentList);
5117             break;
5118         case tok!"default":
5119             mixin(nullCheck!`node.defaultStatement = parseDefaultStatement()`);
5120             break;
5121         default:
5122             if ((node.statementNoCaseNoDefault = parseStatementNoCaseNoDefault()) is null)
5123             {
5124                 deallocate(node);
5125                 return null;
5126             }
5127             break;
5128         }
5129         return node;
5130     }
5131 
5132     /**
5133      * Parses a StatementNoCaseNoDefault
5134      *
5135      * $(GRAMMAR $(RULEDEF statementNoCaseNoDefault):
5136      *       $(RULE labeledStatement)
5137      *     | $(RULE blockStatement)
5138      *     | $(RULE ifStatement)
5139      *     | $(RULE whileStatement)
5140      *     | $(RULE doStatement)
5141      *     | $(RULE forStatement)
5142      *     | $(RULE foreachStatement)
5143      *     | $(RULE switchStatement)
5144      *     | $(RULE finalSwitchStatement)
5145      *     | $(RULE continueStatement)
5146      *     | $(RULE breakStatement)
5147      *     | $(RULE returnStatement)
5148      *     | $(RULE gotoStatement)
5149      *     | $(RULE withStatement)
5150      *     | $(RULE synchronizedStatement)
5151      *     | $(RULE tryStatement)
5152      *     | $(RULE throwStatement)
5153      *     | $(RULE scopeGuardStatement)
5154      *     | $(RULE asmStatement)
5155      *     | $(RULE conditionalStatement)
5156      *     | $(RULE staticAssertStatement)
5157      *     | $(RULE versionSpecification)
5158      *     | $(RULE debugSpecification)
5159      *     | $(RULE expressionStatement)
5160      *     ;)
5161      */
5162     StatementNoCaseNoDefault parseStatementNoCaseNoDefault()
5163     {
5164     version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5165         auto node = allocate!StatementNoCaseNoDefault;
5166         node.startLocation = current().index;
5167         switch (current.type)
5168         {
5169         case tok!"{":
5170             mixin(nullCheck!`node.blockStatement = parseBlockStatement()`);
5171             break;
5172         case tok!"if":
5173             mixin(nullCheck!`node.ifStatement = parseIfStatement()`);
5174             break;
5175         case tok!"while":
5176             mixin(nullCheck!`node.whileStatement = parseWhileStatement()`);
5177             break;
5178         case tok!"do":
5179             mixin(nullCheck!`node.doStatement = parseDoStatement()`);
5180             break;
5181         case tok!"for":
5182             mixin(nullCheck!`node.forStatement = parseForStatement()`);
5183             break;
5184         case tok!"foreach":
5185         case tok!"foreach_reverse":
5186             mixin(nullCheck!`node.foreachStatement = parseForeachStatement()`);
5187             break;
5188         case tok!"switch":
5189             mixin(nullCheck!`node.switchStatement = parseSwitchStatement()`);
5190             break;
5191         case tok!"continue":
5192             mixin(nullCheck!`node.continueStatement = parseContinueStatement()`);
5193             break;
5194         case tok!"break":
5195             mixin(nullCheck!`node.breakStatement = parseBreakStatement()`);
5196             break;
5197         case tok!"return":
5198             mixin(nullCheck!`node.returnStatement = parseReturnStatement()`);
5199             break;
5200         case tok!"goto":
5201             mixin(nullCheck!`node.gotoStatement = parseGotoStatement()`);
5202             break;
5203         case tok!"with":
5204             mixin(nullCheck!`node.withStatement = parseWithStatement()`);
5205             break;
5206         case tok!"synchronized":
5207             mixin(nullCheck!`node.synchronizedStatement = parseSynchronizedStatement()`);
5208             break;
5209         case tok!"try":
5210             mixin(nullCheck!`node.tryStatement = parseTryStatement()`);
5211             break;
5212         case tok!"throw":
5213             mixin(nullCheck!`node.throwStatement = parseThrowStatement()`);
5214             break;
5215         case tok!"scope":
5216             mixin(nullCheck!`node.scopeGuardStatement = parseScopeGuardStatement()`);
5217             break;
5218         case tok!"asm":
5219             mixin(nullCheck!`node.asmStatement = parseAsmStatement()`);
5220             break;
5221         case tok!"final":
5222             if (peekIs(tok!"switch"))
5223             {
5224                 mixin(nullCheck!`node.finalSwitchStatement = parseFinalSwitchStatement()`);
5225                 break;
5226             }
5227             else
5228             {
5229                 error(`"switch" expected`);
5230                 return null;
5231             }
5232         case tok!"debug":
5233             if (peekIs(tok!"="))
5234                 mixin(nullCheck!`node.debugSpecification = parseDebugSpecification()`);
5235             else
5236                 mixin(nullCheck!`node.conditionalStatement = parseConditionalStatement()`);
5237             break;
5238         case tok!"version":
5239             if (peekIs(tok!"="))
5240                 mixin(nullCheck!`node.versionSpecification = parseVersionSpecification()`);
5241             else
5242                 mixin(nullCheck!`node.conditionalStatement = parseConditionalStatement()`);
5243             break;
5244         case tok!"static":
5245             if (peekIs(tok!"if"))
5246                 mixin(nullCheck!`node.conditionalStatement = parseConditionalStatement()`);
5247             else if (peekIs(tok!"assert"))
5248                 mixin(nullCheck!`node.staticAssertStatement = parseStaticAssertStatement()`);
5249             else if (peekIs(tok!"foreach"))
5250                 mixin(nullCheck!`node.staticForeachStatement = parseStaticForeachStatement()`);
5251             else
5252             {
5253                 error("'if' or 'assert' expected.");
5254                 return null;
5255             }
5256             break;
5257         case tok!"identifier":
5258             if (peekIs(tok!":"))
5259             {
5260                 mixin(nullCheck!`node.labeledStatement = parseLabeledStatement()`);
5261                 break;
5262             }
5263             goto default;
5264         case tok!"delete":
5265         case tok!"assert":
5266         default:
5267             if ((node.expressionStatement = parseExpressionStatement()) is null)
5268             {
5269                 deallocate(node);
5270                 return null;
5271             }
5272             break;
5273         }
5274         node.endLocation = tokens[index - 1].index;
5275         return node;
5276     }
5277 
5278     /**
5279      * Parses a StaticAssertDeclaration
5280      *
5281      * $(GRAMMAR $(RULEDEF staticAssertDeclaration):
5282      *     $(RULE staticAssertStatement)
5283      *     ;)
5284      */
5285     StaticAssertDeclaration parseStaticAssertDeclaration()
5286     {
5287         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5288         mixin(simpleParse!(StaticAssertDeclaration,
5289             "staticAssertStatement|parseStaticAssertStatement"));
5290     }
5291 
5292 
5293     /**
5294      * Parses a StaticAssertStatement
5295      *
5296      * $(GRAMMAR $(RULEDEF staticAssertStatement):
5297      *     $(LITERAL 'static') $(RULE assertExpression) $(LITERAL ';')
5298      *     ;)
5299      */
5300     StaticAssertStatement parseStaticAssertStatement()
5301     {
5302         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5303         mixin(simpleParse!(StaticAssertStatement,
5304             tok!"static", "assertExpression|parseAssertExpression", tok!";"));
5305     }
5306 
5307 	// FIXME: so this one is kinda important but i am doing it lazily
5308     StaticForeachDeclaration parseStaticForeachDeclaration()
5309     {
5310 
5311 
5312 	auto node = new StaticForeachDeclaration();
5313 
5314 	expect(tok!"static");
5315 	expect(tok!"foreach");
5316 	expect(tok!"(");
5317 	auto n = advance();
5318 	int parensCount = 1;
5319 	while(parensCount > 0) {
5320 		if(n == tok!"(")
5321 			parensCount++;
5322 		else if(n == tok!")")
5323 			parensCount--;
5324 		n = advance();
5325 	}
5326 
5327 	if(n == tok!"{") {
5328 		int bracesCount = 1;
5329 		n = advance();
5330 		while(bracesCount > 0) {
5331 			if(n == tok!"}") {
5332 				bracesCount--;
5333 				if(bracesCount == 0) break;
5334 			} else if(n == tok!"{")
5335 				bracesCount++;
5336 			n = advance();
5337 		}
5338 	} else {
5339 		if(isDeclaration())
5340 			parseDeclaration();
5341 		else
5342 			parseStatement();
5343 	}
5344 
5345 	return node;
5346 
5347 
5348 /+
5349 
5350         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5351 	expect(tok!"static");
5352 	expect(tok!"foreach");
5353 	expect(tok!"(");
5354 	auto n = advance();
5355 	int parensCount = 1;
5356 	while(parensCount > 0) {
5357 		if(n == tok!"(")
5358 			parensCount++;
5359 		else if(n == tok!")")
5360 			parensCount--;
5361 		n = advance();
5362 	}
5363 
5364 	auto node = new StaticForeachDeclaration();
5365 
5366         Declaration[] declarations;
5367         if (currentIs(tok!"{"))
5368         {
5369             advance();
5370             while (moreTokens() && !currentIs(tok!"}"))
5371             {
5372                 auto b = setBookmark();
5373                 auto d = parseDeclaration();
5374                 if (d !is null)
5375                 {
5376                     abandonBookmark(b);
5377                     declarations ~= d;
5378                 }
5379                 else
5380                 {
5381                     goToBookmark(b);
5382                     return null;
5383                 }
5384             }
5385             node.declarations = declarations;
5386             return node;
5387         } else {
5388             node.declarations ~= parseDeclaration();
5389 	}
5390 
5391 	return node;
5392 +/
5393     }
5394 
5395     // FIXME. i don't really care about this right now but just want it
5396     // good enough to avoid errors for now
5397     StaticForeachStatement parseStaticForeachStatement()
5398     {
5399         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5400 
5401 	auto node = new StaticForeachStatement();
5402 
5403 	expect(tok!"static");
5404 	expect(tok!"foreach");
5405 	expect(tok!"(");
5406 	auto n = advance();
5407 	int parensCount = 1;
5408 	while(parensCount > 0) {
5409 		if(n == tok!"(")
5410 			parensCount++;
5411 		else if(n == tok!")")
5412 			parensCount--;
5413 		n = advance();
5414 	}
5415 
5416 	if(n == tok!"{") {
5417 		int bracesCount = 1;
5418 		n = advance();
5419 		while(bracesCount > 0) {
5420 			if(n == tok!"}") {
5421 				bracesCount--;
5422 				if(bracesCount == 0) break;
5423 			} else if(n == tok!"{")
5424 				bracesCount++;
5425 			n = advance();
5426 		}
5427 	} else {
5428 		if(isDeclaration())
5429 			parseDeclaration();
5430 		else
5431 			parseStatement();
5432 	}
5433 
5434 	return node;
5435     }
5436 
5437     /**
5438      * Parses a StaticConstructor
5439      *
5440      * $(GRAMMAR $(RULEDEF staticConstructor):
5441      *     $(LITERAL 'static') $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)') $(RULE functionBody)
5442      *     ;)
5443      */
5444     StaticConstructor parseStaticConstructor()
5445     {
5446         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5447         mixin(simpleParse!(StaticConstructor, tok!"static", tok!"this",
5448             tok!"(", tok!")", "functionBody|parseFunctionBody"));
5449     }
5450 
5451     /**
5452      * Parses a StaticDestructor
5453      *
5454      * $(GRAMMAR $(RULEDEF staticDestructor):
5455      *     $(LITERAL 'static') $(LITERAL '~') $(LITERAL 'this') $(LITERAL '$(LPAREN)') $(LITERAL '$(RPAREN)') $(RULE functionBody)
5456      *     ;)
5457      */
5458     StaticDestructor parseStaticDestructor()
5459     {
5460         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5461         mixin(simpleParse!(StaticDestructor, tok!"static", tok!"~", tok!"this",
5462             tok!"(", tok!")", "functionBody|parseFunctionBody"));
5463     }
5464 
5465     /**
5466      * Parses an StaticIfCondition
5467      *
5468      * $(GRAMMAR $(RULEDEF staticIfCondition):
5469      *     $(LITERAL 'static') $(LITERAL 'if') $(LITERAL '$(LPAREN)') $(RULE assignExpression) $(LITERAL '$(RPAREN)')
5470      *     ;)
5471      */
5472     StaticIfCondition parseStaticIfCondition()
5473     {
5474         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5475         mixin(simpleParse!(StaticIfCondition, tok!"static", tok!"if", tok!"(",
5476             "assignExpression|parseAssignExpression", tok!")"));
5477     }
5478 
5479     /**
5480      * Parses a StorageClass
5481      *
5482      * $(GRAMMAR $(RULEDEF storageClass):
5483      *       $(RULE alignAttribute)
5484      *     | $(RULE linkageAttribute)
5485      *     | $(RULE atAttribute)
5486      *     | $(RULE typeConstructor)
5487      *     | $(RULE deprecated)
5488      *     | $(LITERAL 'abstract')
5489      *     | $(LITERAL 'auto')
5490      *     | $(LITERAL 'enum')
5491      *     | $(LITERAL 'extern')
5492      *     | $(LITERAL 'final')
5493      *     | $(LITERAL 'nothrow')
5494      *     | $(LITERAL 'override')
5495      *     | $(LITERAL 'pure')
5496      *     | $(LITERAL 'ref')
5497      *     | $(LITERAL '___gshared')
5498      *     | $(LITERAL 'scope')
5499      *     | $(LITERAL 'static')
5500      *     | $(LITERAL 'synchronized')
5501      *     ;)
5502      */
5503     StorageClass parseStorageClass()
5504     {
5505         auto node = allocate!StorageClass;
5506         switch (current.type)
5507         {
5508         case tok!"@":
5509             mixin(nullCheck!`node.atAttribute = parseAtAttribute()`);
5510             if (node.atAttribute is null) { deallocate(node); return null; }
5511             break;
5512         case tok!"deprecated":
5513             mixin(nullCheck!`node.deprecated_ = parseDeprecated()`);
5514             break;
5515         case tok!"align":
5516             mixin(nullCheck!`node.alignAttribute = parseAlignAttribute()`);
5517             break;
5518         case tok!"extern":
5519             if (peekIs(tok!"("))
5520             {
5521                 mixin(nullCheck!`node.linkageAttribute = parseLinkageAttribute()`);
5522                 break;
5523             }
5524             else goto case;
5525         case tok!"const":
5526         case tok!"immutable":
5527         case tok!"inout":
5528         case tok!"shared":
5529         case tok!"abstract":
5530         case tok!"auto":
5531         case tok!"enum":
5532         case tok!"final":
5533         case tok!"nothrow":
5534         case tok!"override":
5535         case tok!"pure":
5536         case tok!"ref":
5537         case tok!"__gshared":
5538         case tok!"scope":
5539         case tok!"static":
5540         case tok!"synchronized":
5541             node.token = advance();
5542             break;
5543         default:
5544             error(`Storage class expected`);
5545             return null;
5546         }
5547         return node;
5548     }
5549 
5550     /**
5551      * Parses a StructBody
5552      *
5553      * $(GRAMMAR $(RULEDEF structBody):
5554      *     $(LITERAL '{') $(RULE declaration)* $(LITERAL '}')
5555      *     ;)
5556      */
5557     StructBody parseStructBody()
5558     {
5559         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5560         auto node = allocate!StructBody;
5561         const start = expect(tok!"{");
5562         if (start !is null) node.startLocation = start.index;
5563         Declaration[] declarations;
5564         while (!currentIs(tok!"}") && moreTokens())
5565         {
5566             auto dec = parseDeclaration();
5567             if (dec !is null)
5568                 declarations ~= dec;
5569         }
5570         node.declarations = ownArray(declarations);
5571         const end = expect(tok!"}");
5572         if (end !is null) node.endLocation = end.index;
5573         return node;
5574     }
5575 
5576     /**
5577      * Parses a StructDeclaration
5578      *
5579      * $(GRAMMAR $(RULEDEF structDeclaration):
5580      *     $(LITERAL 'struct') $(LITERAL Identifier)? ($(RULE templateParameters) $(RULE constraint)? $(RULE structBody) | ($(RULE structBody) | $(LITERAL ';')))
5581      *     ;)
5582      */
5583     StructDeclaration parseStructDeclaration()
5584     {
5585         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5586         auto node = allocate!StructDeclaration;
5587         const t = expect(tok!"struct");
5588         if (currentIs(tok!"identifier"))
5589             node.name = advance();
5590         else
5591         {
5592             node.name.line = t.line;
5593             node.name.column = t.column;
5594         }
5595         node.comment = comment;
5596         comment = null;
5597 
5598         if (currentIs(tok!"("))
5599         {
5600             mixin(nullCheck!`node.templateParameters = parseTemplateParameters()`);
5601             if (currentIs(tok!"if"))
5602                 mixin(nullCheck!`node.constraint = parseConstraint()`);
5603             mixin(nullCheck!`node.structBody = parseStructBody()`);
5604         }
5605         else if (currentIs(tok!"{"))
5606         {
5607             mixin(nullCheck!`node.structBody = parseStructBody()`);
5608         }
5609         else if (currentIs(tok!";"))
5610             advance();
5611         else
5612         {
5613             error("Template Parameters, Struct Body, or Semicolon expected");
5614             return null;
5615         }
5616         return node;
5617     }
5618 
5619     /**
5620      * Parses an StructInitializer
5621      *
5622      * $(GRAMMAR $(RULEDEF structInitializer):
5623      *     $(LITERAL '{') $(RULE structMemberInitializers)? $(LITERAL '}')
5624      *     ;)
5625      */
5626     StructInitializer parseStructInitializer()
5627     {
5628         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5629         auto node = allocate!StructInitializer;
5630         const a = expect(tok!"{");
5631         node.startLocation = a.index;
5632         if (currentIs(tok!"}"))
5633         {
5634             node.endLocation = current.index;
5635             advance();
5636         }
5637         else
5638         {
5639             mixin(nullCheck!`node.structMemberInitializers = parseStructMemberInitializers()`);
5640             const e = expect(tok!"}");
5641             mixin(nullCheck!`e`);
5642             node.endLocation = e.index;
5643         }
5644         return node;
5645     }
5646 
5647     /**
5648      * Parses a StructMemberInitializer
5649      *
5650      * $(GRAMMAR $(RULEDEF structMemberInitializer):
5651      *     ($(LITERAL Identifier) $(LITERAL ':'))? $(RULE nonVoidInitializer)
5652      *     ;)
5653      */
5654     StructMemberInitializer parseStructMemberInitializer()
5655     {
5656         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5657         auto node = allocate!StructMemberInitializer;
5658         if (startsWith(tok!"identifier", tok!":"))
5659         {
5660             node.identifier = tokens[index++];
5661             index++;
5662         }
5663         mixin(nullCheck!`node.nonVoidInitializer = parseNonVoidInitializer()`);
5664         return node;
5665     }
5666 
5667     /**
5668      * Parses StructMemberInitializers
5669      *
5670      * $(GRAMMAR $(RULEDEF structMemberInitializers):
5671      *     $(RULE structMemberInitializer) ($(LITERAL ',') $(RULE structMemberInitializer)?)*
5672      *     ;)
5673      */
5674     StructMemberInitializers parseStructMemberInitializers()
5675     {
5676         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5677         auto node = allocate!StructMemberInitializers;
5678         StructMemberInitializer[] structMemberInitializers;
5679         do
5680         {
5681             auto structMemberInitializer = parseStructMemberInitializer();
5682             if (structMemberInitializer is null)
5683             {
5684                 deallocate(node);
5685                 return null;
5686             }
5687             else
5688                 structMemberInitializers ~= structMemberInitializer;
5689 
5690             if (currentIs(tok!","))
5691             {
5692                 advance();
5693                 if (!currentIs(tok!"}"))
5694                     continue;
5695                 else
5696                     break;
5697             }
5698             else
5699                 break;
5700         } while (moreTokens());
5701         node.structMemberInitializers = ownArray(structMemberInitializers);
5702         return node;
5703     }
5704 
5705     /**
5706      * Parses a SwitchStatement
5707      *
5708      * $(GRAMMAR $(RULEDEF switchStatement):
5709      *     $(LITERAL 'switch') $(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)') $(RULE statement)
5710      *     ;)
5711      */
5712     SwitchStatement parseSwitchStatement()
5713     {
5714         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5715         auto node = allocate!SwitchStatement;
5716         expect(tok!"switch");
5717         expect(tok!"(");
5718         mixin(nullCheck!`node.expression = parseExpression()`);
5719         expect(tok!")");
5720         mixin(nullCheck!`node.statement = parseStatement()`);
5721         return node;
5722     }
5723 
5724     /**
5725      * Parses a Symbol
5726      *
5727      * $(GRAMMAR $(RULEDEF symbol):
5728      *     $(LITERAL '.')? $(RULE identifierOrTemplateChain)
5729      *     ;)
5730      */
5731     Symbol parseSymbol()
5732     {
5733         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5734         auto node = allocate!Symbol;
5735         if (currentIs(tok!"."))
5736         {
5737             node.dot = true;
5738             advance();
5739         }
5740         mixin(nullCheck!`node.identifierOrTemplateChain = parseIdentifierOrTemplateChain()`);
5741         return node;
5742     }
5743 
5744     /**
5745      * Parses a SynchronizedStatement
5746      *
5747      * $(GRAMMAR $(RULEDEF synchronizedStatement):
5748      *     $(LITERAL 'synchronized') ($(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)'))? $(RULE statementNoCaseNoDefault)
5749      *     ;)
5750      */
5751     SynchronizedStatement parseSynchronizedStatement()
5752     {
5753         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5754         auto node = allocate!SynchronizedStatement;
5755         expect(tok!"synchronized");
5756         if (currentIs(tok!"("))
5757         {
5758             expect(tok!"(");
5759             mixin(nullCheck!`node.expression = parseExpression()`);
5760             expect(tok!")");
5761         }
5762         mixin(nullCheck!`node.statementNoCaseNoDefault = parseStatementNoCaseNoDefault()`);
5763         return node;
5764     }
5765 
5766     /**
5767      * Parses a TemplateAliasParameter
5768      *
5769      * $(GRAMMAR $(RULEDEF templateAliasParameter):
5770      *     $(LITERAL 'alias') $(RULE type)? $(LITERAL Identifier) ($(LITERAL ':') ($(RULE type) | $(RULE assignExpression)))? ($(LITERAL '=') ($(RULE type) | $(RULE assignExpression)))?
5771      *     ;)
5772      */
5773     TemplateAliasParameter parseTemplateAliasParameter()
5774     {
5775         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5776         auto node = allocate!TemplateAliasParameter;
5777         expect(tok!"alias");
5778         if (currentIs(tok!"identifier") && !peekIs(tok!"."))
5779         {
5780             if (peekIsOneOf(tok!",", tok!")", tok!"=", tok!":"))
5781                 node.identifier = advance();
5782             else
5783                 goto type;
5784         }
5785         else
5786         {
5787     type:
5788             if ((node.type = parseType()) is null) { deallocate(node); return null; }
5789             const ident = expect(tok!"identifier");
5790             if (ident is null) { deallocate(node); return null; }
5791             node.identifier = *ident;
5792         }
5793 
5794         if (currentIs(tok!":"))
5795         {
5796             advance();
5797             if (isType())
5798                 mixin(nullCheck!`node.colonType = parseType()`);
5799             else
5800                 mixin(nullCheck!`node.colonExpression = parseAssignExpression()`);
5801         }
5802         if (currentIs(tok!"="))
5803         {
5804             advance();
5805             if (isType())
5806                 mixin(nullCheck!`node.assignType = parseType()`);
5807             else
5808                 mixin(nullCheck!`node.assignExpression = parseAssignExpression()`);
5809         }
5810         return node;
5811     }
5812 
5813     /**
5814      * Parses a TemplateArgument
5815      *
5816      * $(GRAMMAR $(RULEDEF templateArgument):
5817      *       $(RULE type)
5818      *     | $(RULE assignExpression)
5819      *     ;)
5820      */
5821     TemplateArgument parseTemplateArgument()
5822     {
5823         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5824         if (suppressedErrorCount > MAX_ERRORS) return null;
5825         auto node = allocate!TemplateArgument;
5826         auto b = setBookmark();
5827         auto t = parseType();
5828         if (t !is null && currentIsOneOf(tok!",", tok!")"))
5829         {
5830             abandonBookmark(b);
5831             node.type = t;
5832         }
5833         else
5834         {
5835             goToBookmark(b);
5836             if ((node.assignExpression = parseAssignExpression()) is null) { deallocate(node); return null; }
5837         }
5838         return node;
5839     }
5840 
5841     /**
5842      * Parses a TemplateArgumentList
5843      *
5844      * $(GRAMMAR $(RULEDEF templateArgumentList):
5845      *     $(RULE templateArgument) ($(LITERAL ',') $(RULE templateArgument)?)*
5846      *     ;)
5847      */
5848     TemplateArgumentList parseTemplateArgumentList()
5849     {
5850         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5851         return parseCommaSeparatedRule!(TemplateArgumentList, TemplateArgument)(true);
5852     }
5853 
5854     /**
5855      * Parses TemplateArguments
5856      *
5857      * $(GRAMMAR $(RULEDEF templateArguments):
5858      *     $(LITERAL '!') ($(LITERAL '$(LPAREN)') $(RULE templateArgumentList)? $(LITERAL '$(RPAREN)')) | $(RULE templateSingleArgument)
5859      *     ;)
5860      */
5861     TemplateArguments parseTemplateArguments()
5862     {
5863         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5864         if (suppressedErrorCount > MAX_ERRORS) return null;
5865         auto node = allocate!TemplateArguments;
5866         expect(tok!"!");
5867         if (currentIs(tok!"("))
5868         {
5869             advance();
5870             if (!currentIs(tok!")"))
5871                 mixin(nullCheck!`node.templateArgumentList = parseTemplateArgumentList()`);
5872             if (expect(tok!")") is null) { deallocate(node); return null; }
5873         }
5874         else
5875             mixin(nullCheck!`node.templateSingleArgument = parseTemplateSingleArgument()`);
5876         return node;
5877     }
5878 
5879     /**
5880      * Parses a TemplateDeclaration
5881      *
5882      * $(GRAMMAR $(RULEDEF templateDeclaration):
5883      *       $(LITERAL 'template') $(LITERAL Identifier) $(RULE templateParameters) $(RULE constraint)? $(LITERAL '{') $(RULE declaration)* $(LITERAL '}')
5884      *     ;)
5885      */
5886     TemplateDeclaration parseTemplateDeclaration()
5887     {
5888         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5889         auto node = allocate!TemplateDeclaration;
5890         node.comment = comment;
5891         comment = null;
5892         expect(tok!"template");
5893         const ident = expect(tok!"identifier");
5894         if (ident is null) { deallocate(node); return null; }
5895         node.name = *ident;
5896         mixin(nullCheck!`node.templateParameters = parseTemplateParameters()`);
5897         if (currentIs(tok!"if"))
5898             mixin(nullCheck!`node.constraint = parseConstraint()`);
5899         const start = expect(tok!"{");
5900         if (start is null) { deallocate(node); return null; } else node.startLocation = start.index;
5901         Declaration[] declarations;
5902         while (moreTokens() && !currentIs(tok!"}"))
5903         {
5904             auto decl = parseDeclaration();
5905             if (decl !is null)
5906                 declarations ~= decl;
5907         }
5908         node.declarations = ownArray(declarations);
5909         const end = expect(tok!"}");
5910         if (end !is null) node.endLocation = end.index;
5911         return node;
5912     }
5913 
5914     /**
5915      * Parses a TemplateInstance
5916      *
5917      * $(GRAMMAR $(RULEDEF templateInstance):
5918      *     $(LITERAL Identifier) $(RULE templateArguments)
5919      *     ;)
5920      */
5921     TemplateInstance parseTemplateInstance()
5922     {
5923         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5924         if (suppressedErrorCount > MAX_ERRORS) return null;
5925         auto node = allocate!TemplateInstance;
5926         const ident = expect(tok!"identifier");
5927         if (ident is null) { deallocate(node); return null; }
5928         node.identifier = *ident;
5929         mixin(nullCheck!`node.templateArguments = parseTemplateArguments()`);
5930         if (node.templateArguments is null)
5931             return null;
5932         return node;
5933     }
5934 
5935     /**
5936      * Parses a TemplateMixinExpression
5937      *
5938      * $(GRAMMAR $(RULEDEF templateMixinExpression):
5939      *     $(LITERAL 'mixin') $(RULE mixinTemplateName) $(RULE templateArguments)? $(LITERAL Identifier)?
5940      *     ;)
5941      */
5942     TemplateMixinExpression parseTemplateMixinExpression()
5943     {
5944         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5945         auto node = allocate!TemplateMixinExpression;
5946         node.comment = comment;
5947 	node.line = current.line;
5948         comment = null;
5949         if (expect(tok!"mixin") is null) { deallocate(node); return null; }
5950         mixin(nullCheck!`node.mixinTemplateName = parseMixinTemplateName()`);
5951         if (currentIs(tok!"!"))
5952             mixin(nullCheck!`node.templateArguments = parseTemplateArguments()`);
5953         if (currentIs(tok!"identifier"))
5954             node.identifier = advance();
5955         return node;
5956     }
5957 
5958     /**
5959      * Parses a TemplateParameter
5960      *
5961      * $(GRAMMAR $(RULEDEF templateParameter):
5962      *       $(RULE templateTypeParameter)
5963      *     | $(RULE templateValueParameter)
5964      *     | $(RULE templateAliasParameter)
5965      *     | $(RULE templateTupleParameter)
5966      *     | $(RULE templateThisParameter)
5967      *     ;)
5968      */
5969     TemplateParameter parseTemplateParameter()
5970     {
5971         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
5972         auto node = allocate!TemplateParameter;
5973 
5974         node.comment = current.comment;
5975 
5976         switch (current.type)
5977         {
5978         case tok!"alias":
5979             mixin(nullCheck!`node.templateAliasParameter = parseTemplateAliasParameter()`);
5980             break;
5981         case tok!"identifier":
5982             if (peekIs(tok!"..."))
5983                 mixin(nullCheck!`node.templateTupleParameter = parseTemplateTupleParameter()`);
5984             else if (peekIsOneOf(tok!":", tok!"=", tok!",", tok!")"))
5985                 mixin(nullCheck!`node.templateTypeParameter = parseTemplateTypeParameter()`);
5986             else
5987                 mixin(nullCheck!`node.templateValueParameter = parseTemplateValueParameter()`);
5988             break;
5989         case tok!"this":
5990             mixin(nullCheck!`node.templateThisParameter = parseTemplateThisParameter()`);
5991             break;
5992         default:
5993             mixin(nullCheck!`node.templateValueParameter = parseTemplateValueParameter()`);
5994             break;
5995         }
5996         return node;
5997     }
5998 
5999     /**
6000      * Parses an TemplateParameterList
6001      *
6002      * $(GRAMMAR $(RULEDEF templateParameterList):
6003      *     $(RULE templateParameter) ($(LITERAL ',') $(RULE templateParameter)?)*
6004      *     ;)
6005      */
6006     TemplateParameterList parseTemplateParameterList()
6007     {
6008         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6009         return parseCommaSeparatedRule!(TemplateParameterList, TemplateParameter)(true);
6010     }
6011 
6012     /**
6013      * Parses TemplateParameters
6014      *
6015      * $(GRAMMAR $(RULEDEF templateParameters):
6016      *     $(LITERAL '$(LPAREN)') $(RULE templateParameterList)? $(LITERAL '$(RPAREN)')
6017      *     ;)
6018      */
6019     TemplateParameters parseTemplateParameters()
6020     {
6021         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6022         auto node = allocate!TemplateParameters;
6023         if (expect(tok!"(") is null) { deallocate(node); return null; }
6024         if (!currentIs(tok!")"))
6025             if ((node.templateParameterList = parseTemplateParameterList()) is null) { deallocate(node); return null; }
6026         if (expect(tok!")") is null) { deallocate(node); return null; }
6027         return node;
6028     }
6029 
6030     /**
6031      * Parses a TemplateSingleArgument
6032      *
6033      * $(GRAMMAR $(RULEDEF templateSingleArgument):
6034      *       $(RULE builtinType)
6035      *     | $(LITERAL Identifier)
6036      *     | $(LITERAL CharacterLiteral)
6037      *     | $(LITERAL StringLiteral)
6038      *     | $(LITERAL IntegerLiteral)
6039      *     | $(LITERAL FloatLiteral)
6040      *     | $(LITERAL '_true')
6041      *     | $(LITERAL '_false')
6042      *     | $(LITERAL '_null')
6043      *     | $(LITERAL 'this')
6044      *     | $(LITERAL '___DATE__')
6045      *     | $(LITERAL '___TIME__')
6046      *     | $(LITERAL '___TIMESTAMP__')
6047      *     | $(LITERAL '___VENDOR__')
6048      *     | $(LITERAL '___VERSION__')
6049      *     | $(LITERAL '___FILE__')
6050      *     | $(LITERAL '___LINE__')
6051      *     | $(LITERAL '___MODULE__')
6052      *     | $(LITERAL '___FUNCTION__')
6053      *     | $(LITERAL '___PRETTY_FUNCTION__')
6054      *     ;)
6055      */
6056     TemplateSingleArgument parseTemplateSingleArgument()
6057     {
6058         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6059         auto node = allocate!TemplateSingleArgument;
6060         if (!moreTokens)
6061         {
6062             error("template argument expected instead of EOF");
6063             return null;
6064         }
6065         switch (current.type)
6066         {
6067         case tok!"true":
6068         case tok!"false":
6069         case tok!"null":
6070         case tok!"this":
6071         case tok!"identifier":
6072         mixin(SPECIAL_CASES);
6073         mixin(LITERAL_CASES);
6074         mixin(BUILTIN_TYPE_CASES);
6075             node.token = advance();
6076             break;
6077         default:
6078             error(`Invalid template argument. (Try enclosing in parenthesis?)`);
6079             return null;
6080         }
6081         return node;
6082     }
6083 
6084     /**
6085      * Parses a TemplateThisParameter
6086      *
6087      * $(GRAMMAR $(RULEDEF templateThisParameter):
6088      *     $(LITERAL 'this') $(RULE templateTypeParameter)
6089      *     ;)
6090      */
6091     TemplateThisParameter parseTemplateThisParameter()
6092     {
6093         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6094         auto node = allocate!TemplateThisParameter;
6095         expect(tok!"this");
6096         mixin(nullCheck!`node.templateTypeParameter = parseTemplateTypeParameter()`);
6097         return node;
6098     }
6099 
6100     /**
6101      * Parses an TemplateTupleParameter
6102      *
6103      * $(GRAMMAR $(RULEDEF templateTupleParameter):
6104      *     $(LITERAL Identifier) $(LITERAL '...')
6105      *     ;)
6106      */
6107     TemplateTupleParameter parseTemplateTupleParameter()
6108     {
6109         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6110         auto node = allocate!TemplateTupleParameter;
6111         const i = expect(tok!"identifier");
6112         if (i is null)
6113             return null;
6114         node.identifier = *i;
6115         if (expect(tok!"...") is null) { deallocate(node); return null; }
6116         return node;
6117     }
6118 
6119     /**
6120      * Parses a TemplateTypeParameter
6121      *
6122      * $(GRAMMAR $(RULEDEF templateTypeParameter):
6123      *     $(LITERAL Identifier) ($(LITERAL ':') $(RULE type))? ($(LITERAL '=') $(RULE type))?
6124      *     ;)
6125      */
6126     TemplateTypeParameter parseTemplateTypeParameter()
6127     {
6128         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6129         auto node = allocate!TemplateTypeParameter;
6130         const ident = expect(tok!"identifier");
6131         if (ident is null) { deallocate(node); return null; }
6132         node.identifier = *ident;
6133         if (currentIs(tok!":"))
6134         {
6135             advance();
6136             mixin(nullCheck!`node.colonType = parseType()`);
6137         }
6138         if (currentIs(tok!"="))
6139         {
6140             advance();
6141             mixin(nullCheck!`node.assignType = parseType()`);
6142         }
6143         return node;
6144     }
6145 
6146     /**
6147      * Parses a TemplateValueParameter
6148      *
6149      * $(GRAMMAR $(RULEDEF templateValueParameter):
6150      *     $(RULE type) $(LITERAL Identifier) ($(LITERAL ':') $(RULE assignExpression))? $(RULE templateValueParameterDefault)?
6151      *     ;)
6152      */
6153     TemplateValueParameter parseTemplateValueParameter()
6154     {
6155         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6156         auto node = allocate!TemplateValueParameter;
6157         if ((node.type = parseType()) is null) { deallocate(node); return null; }
6158         const ident = expect(tok!"identifier");
6159         if (ident is null) { deallocate(node); return null; }
6160         node.identifier = *ident;
6161         if (currentIs(tok!":"))
6162         {
6163             advance();
6164             if ((node.assignExpression = parseAssignExpression()) is null) { deallocate(node); return null; }
6165         }
6166         if (currentIs(tok!"="))
6167         {
6168             if ((node.templateValueParameterDefault = parseTemplateValueParameterDefault()) is null)
6169                 return null;
6170         }
6171         return node;
6172     }
6173 
6174     /**
6175      * Parses a TemplateValueParameterDefault
6176      *
6177      * $(GRAMMAR $(RULEDEF templateValueParameterDefault):
6178      *     $(LITERAL '=') ($(LITERAL '___FILE__') | $(LITERAL '___MODULE__') | $(LITERAL '___LINE__') | $(LITERAL '___FUNCTION__') | $(LITERAL '___PRETTY_FUNCTION__') | $(RULE assignExpression))
6179      *     ;)
6180      */
6181     TemplateValueParameterDefault parseTemplateValueParameterDefault()
6182     {
6183         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6184         auto node = allocate!TemplateValueParameterDefault;
6185         expect(tok!"=");
6186         switch (current.type)
6187         {
6188         case tok!"__FILE__":
6189         case tok!"__MODULE__":
6190         case tok!"__LINE__":
6191         case tok!"__FUNCTION__":
6192         case tok!"__PRETTY_FUNCTION__":
6193             node.token = advance();
6194             break;
6195         default:
6196             mixin(nullCheck!`node.assignExpression = parseAssignExpression()`);
6197             break;
6198         }
6199         return node;
6200     }
6201 
6202     /**
6203      * Parses a TernaryExpression
6204      *
6205      * $(GRAMMAR $(RULEDEF ternaryExpression):
6206      *     $(RULE orOrExpression) ($(LITERAL '?') $(RULE expression) $(LITERAL ':') $(RULE ternaryExpression))?
6207      *     ;)
6208      */
6209     ExpressionNode parseTernaryExpression()
6210     {
6211         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6212 
6213         auto orOrExpression = parseOrOrExpression();
6214         if (orOrExpression is null)
6215             return null;
6216         if (currentIs(tok!"?"))
6217         {
6218             TernaryExpression node = allocate!TernaryExpression;
6219             node.orOrExpression = orOrExpression;
6220             advance();
6221             mixin(nullCheck!`node.expression = parseExpression()`);
6222             auto colon = expect(tok!":");
6223             if (colon is null) { deallocate(node); return null; }
6224             node.colon = *colon;
6225             mixin(nullCheck!`node.ternaryExpression = parseTernaryExpression()`);
6226             return node;
6227         }
6228         return orOrExpression;
6229     }
6230 
6231     /**
6232      * Parses a ThrowStatement
6233      *
6234      * $(GRAMMAR $(RULEDEF throwStatement):
6235      *     $(LITERAL 'throw') $(RULE expression) $(LITERAL ';')
6236      *     ;)
6237      */
6238     ThrowStatement parseThrowStatement()
6239     {
6240         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6241         auto node = allocate!ThrowStatement;
6242         expect(tok!"throw");
6243         mixin(nullCheck!`node.expression = parseExpression()`);
6244         expect(tok!";");
6245         return node;
6246     }
6247 
6248     /**
6249      * Parses an TraitsExpression
6250      *
6251      * $(GRAMMAR $(RULEDEF traitsExpression):
6252      *     $(LITERAL '___traits') $(LITERAL '$(LPAREN)') $(LITERAL Identifier) $(LITERAL ',') $(RULE TemplateArgumentList) $(LITERAL '$(RPAREN)')
6253      *     ;)
6254      */
6255     TraitsExpression parseTraitsExpression()
6256     {
6257         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6258         auto node = allocate!TraitsExpression;
6259         if (expect(tok!"__traits") is null) { deallocate(node); return null; }
6260         if (expect(tok!"(") is null) { deallocate(node); return null; }
6261         const ident = expect(tok!"identifier");
6262         if (ident is null) { deallocate(node); return null; }
6263         node.identifier = *ident;
6264         if (currentIs(tok!","))
6265         {
6266             advance();
6267             mixin(nullCheck!`(node.templateArgumentList = parseTemplateArgumentList())`);
6268         }
6269         mixin(nullCheck!`expect(tok!")")`);
6270         return node;
6271     }
6272 
6273     /**
6274      * Parses a TryStatement
6275      *
6276      * $(GRAMMAR $(RULEDEF tryStatement):
6277      *     $(LITERAL 'try') $(RULE declarationOrStatement) ($(RULE catches) | $(RULE catches) $(RULE finally) | $(RULE finally))
6278      *     ;)
6279      */
6280     TryStatement parseTryStatement()
6281     {
6282         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6283         auto node = allocate!TryStatement;
6284         expect(tok!"try");
6285         mixin(nullCheck!`node.declarationOrStatement = parseDeclarationOrStatement()`);
6286         if (currentIs(tok!"catch"))
6287             mixin(nullCheck!`node.catches = parseCatches()`);
6288         if (currentIs(tok!"finally"))
6289             mixin(nullCheck!`node.finally_ = parseFinally()`);
6290         return node;
6291     }
6292 
6293     /**
6294      * Parses a Type
6295      *
6296      * $(GRAMMAR $(RULEDEF type):
6297      *     $(RULE typeConstructors)? $(RULE type2) $(RULE typeSuffix)*
6298      *     ;)
6299      */
6300     Type parseType()
6301     {
6302         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6303         auto node = allocate!Type;
6304         if (!moreTokens)
6305         {
6306             error("type expected");
6307             return null;
6308         }
6309         switch (current.type)
6310         {
6311 	case tok!"__traits":
6312 		advance();
6313 		skipParens();
6314 		break;
6315         case tok!"const":
6316         case tok!"immutable":
6317         case tok!"inout":
6318         case tok!"shared":
6319             if (!peekIs(tok!"("))
6320                 mixin(nullCheck!`node.typeConstructors = parseTypeConstructors()`);
6321             break;
6322         default:
6323             break;
6324         }
6325         mixin(nullCheck!`node.type2 = parseType2()`);
6326         if (node.type2 is null)
6327             return null;
6328         TypeSuffix[] typeSuffixes;
6329         loop: while (moreTokens()) switch (current.type)
6330         {
6331         case tok!"[":
6332             // Allow this to fail because of the madness that is the
6333             // newExpression rule. Something starting with '[' may be arguments
6334             // to the newExpression instead of part of the type
6335             auto newBookmark = setBookmark();
6336             auto suffix = parseTypeSuffix();
6337             if (suffix !is null)
6338             {
6339                 abandonBookmark(newBookmark);
6340                 typeSuffixes ~= suffix;
6341             }
6342             else
6343             {
6344                 goToBookmark(newBookmark);
6345                 break loop;
6346             }
6347             break;
6348         case tok!"*":
6349         case tok!"delegate":
6350         case tok!"function":
6351             auto suffix = parseTypeSuffix();
6352             if (suffix !is null)
6353                 typeSuffixes ~= suffix;
6354             else
6355                 return null;
6356             break;
6357         default:
6358             break loop;
6359         }
6360         node.typeSuffixes = ownArray(typeSuffixes);
6361         return node;
6362     }
6363 
6364     /**
6365      * Parses a Type2
6366      *
6367      * $(GRAMMAR $(RULEDEF type2):
6368      *       $(RULE builtinType)
6369      *     | $(RULE symbol)
6370      *     | $(RULE typeofExpression) ($(LITERAL '.') $(RULE identifierOrTemplateChain))?
6371      *     | $(RULE typeConstructor) $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL '$(RPAREN)')
6372      *     | $(RULE vector)
6373      *     ;)
6374      */
6375     Type2 parseType2()
6376     {
6377         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6378         auto node = allocate!Type2;
6379         if (!moreTokens)
6380         {
6381             error("type2 expected instead of EOF");
6382             return null;
6383         }
6384         switch (current.type)
6385         {
6386         case tok!"identifier":
6387         case tok!".":
6388             if ((node.symbol = parseSymbol()) is null)
6389                 return null;
6390             break;
6391         mixin(BUILTIN_TYPE_CASES);
6392             if ((node.builtinType = parseBuiltinType()) == tok!"")
6393                 return null;
6394             break;
6395         case tok!"typeof":
6396             if ((node.typeofExpression = parseTypeofExpression()) is null)
6397                 return null;
6398             if (currentIs(tok!"."))
6399             {
6400                 advance();
6401                 mixin(nullCheck!`node.identifierOrTemplateChain = parseIdentifierOrTemplateChain()`);
6402                 if (node.identifierOrTemplateChain is null)
6403                     return null;
6404             }
6405             break;
6406         case tok!"const":
6407         case tok!"immutable":
6408         case tok!"inout":
6409         case tok!"shared":
6410             node.typeConstructor = advance().type;
6411             mixin(nullCheck!`expect(tok!"(")`);
6412             mixin(nullCheck!`(node.type = parseType())`);
6413             mixin(nullCheck!`expect(tok!")")`);
6414             break;
6415         case tok!"__vector":
6416             if ((node.vector = parseVector()) is null)
6417                 return null;
6418             break;
6419         default:
6420             error("Basic type, type constructor, symbol, or typeof expected");
6421             return null;
6422         }
6423         return node;
6424     }
6425 
6426     /**
6427      * Parses a TypeConstructor
6428      *
6429      * $(GRAMMAR $(RULEDEF typeConstructor):
6430      *       $(LITERAL 'const')
6431      *     | $(LITERAL 'immutable')
6432      *     | $(LITERAL 'inout')
6433      *     | $(LITERAL 'shared')
6434      *     ;)
6435      */
6436     IdType parseTypeConstructor(bool validate = true)
6437     {
6438         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6439         switch (current.type)
6440         {
6441         case tok!"const":
6442         case tok!"immutable":
6443         case tok!"inout":
6444         case tok!"shared":
6445             if (!peekIs(tok!"("))
6446                 return advance().type;
6447             goto default;
6448         default:
6449             if (validate)
6450                 error(`"const", "immutable", "inout", or "shared" expected`);
6451             return tok!"";
6452         }
6453     }
6454 
6455     /**
6456      * Parses TypeConstructors
6457      *
6458      * $(GRAMMAR $(RULEDEF typeConstructors):
6459      *     $(RULE typeConstructor)+
6460      *     ;)
6461      */
6462     IdType[] parseTypeConstructors()
6463     {
6464         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6465         IdType[] r;
6466         while (moreTokens())
6467         {
6468             IdType type = parseTypeConstructor(false);
6469             if (type == tok!"")
6470                 break;
6471             else
6472                 r ~= type;
6473         }
6474         return r;
6475     }
6476 
6477     /**
6478      * Parses a TypeSpecialization
6479      *
6480      * $(GRAMMAR $(RULEDEF typeSpecialization):
6481      *       $(RULE type)
6482      *     | $(LITERAL 'struct')
6483      *     | $(LITERAL 'union')
6484      *     | $(LITERAL 'class')
6485      *     | $(LITERAL 'interface')
6486      *     | $(LITERAL 'enum')
6487      *     | $(LITERAL 'function')
6488      *     | $(LITERAL 'delegate')
6489      *     | $(LITERAL 'super')
6490      *     | $(LITERAL 'const')
6491      *     | $(LITERAL 'immutable')
6492      *     | $(LITERAL 'inout')
6493      *     | $(LITERAL 'shared')
6494      *     | $(LITERAL 'return')
6495      *     | $(LITERAL 'typedef')
6496      *     | $(LITERAL '___parameters')
6497      *     ;)
6498      */
6499     TypeSpecialization parseTypeSpecialization()
6500     {
6501         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6502         auto node = allocate!TypeSpecialization;
6503         switch (current.type)
6504         {
6505         case tok!"struct":
6506         case tok!"union":
6507         case tok!"class":
6508         case tok!"interface":
6509         case tok!"enum":
6510         case tok!"function":
6511         case tok!"delegate":
6512         case tok!"super":
6513         case tok!"return":
6514         case tok!"typedef":
6515         case tok!"__parameters":
6516         case tok!"__vector":
6517         case tok!"const":
6518         case tok!"immutable":
6519         case tok!"inout":
6520         case tok!"shared":
6521             if (peekIsOneOf(tok!")", tok!","))
6522             {
6523                 node.token = advance();
6524                 break;
6525             }
6526             goto default;
6527         default:
6528             mixin(nullCheck!`node.type = parseType()`);
6529             break;
6530         }
6531         return node;
6532     }
6533 
6534     /**
6535      * Parses a TypeSuffix
6536      *
6537      * $(GRAMMAR $(RULEDEF typeSuffix):
6538      *       $(LITERAL '*')
6539      *     | $(LITERAL '[') $(RULE type)? $(LITERAL ']')
6540      *     | $(LITERAL '[') $(RULE assignExpression) $(LITERAL ']')
6541      *     | $(LITERAL '[') $(RULE assignExpression) $(LITERAL '..')  $(RULE assignExpression) $(LITERAL ']')
6542      *     | ($(LITERAL 'delegate') | $(LITERAL 'function')) $(RULE parameters) $(RULE memberFunctionAttribute)*
6543      *     ;)
6544      */
6545     TypeSuffix parseTypeSuffix()
6546     {
6547         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6548         auto node = allocate!TypeSuffix;
6549         switch (current.type)
6550         {
6551         case tok!"*":
6552             node.star = advance();
6553             return node;
6554         case tok!"[":
6555             node.array = true;
6556             advance();
6557             if (currentIs(tok!"]"))
6558             {
6559                 advance();
6560                 return node;
6561             }
6562             auto bookmark = setBookmark();
6563             auto type = parseType();
6564             if (type !is null && currentIs(tok!"]"))
6565             {
6566                 abandonBookmark(bookmark);
6567                 node.type = type;
6568             }
6569             else
6570             {
6571                 goToBookmark(bookmark);
6572                 mixin(nullCheck!`node.low = parseAssignExpression()`);
6573                 mixin(nullCheck!`node.low`);
6574                 if (currentIs(tok!".."))
6575                 {
6576                     advance();
6577                     mixin(nullCheck!`node.high = parseAssignExpression()`);
6578                     mixin(nullCheck!`node.high`);
6579                 }
6580             }
6581             mixin(nullCheck!`expect(tok!"]")`);
6582             return node;
6583         case tok!"delegate":
6584         case tok!"function":
6585             node.delegateOrFunction = advance();
6586             mixin(nullCheck!`node.parameters = parseParameters()`);
6587             MemberFunctionAttribute[] memberFunctionAttributes;
6588             while (currentIsMemberFunctionAttribute())
6589                 memberFunctionAttributes ~= parseMemberFunctionAttribute();
6590             node.memberFunctionAttributes = ownArray(memberFunctionAttributes);
6591             return node;
6592         default:
6593             error(`"*", "[", "delegate", or "function" expected.`);
6594             return null;
6595         }
6596     }
6597 
6598     /**
6599      * Parses a TypeidExpression
6600      *
6601      * $(GRAMMAR $(RULEDEF typeidExpression):
6602      *     $(LITERAL 'typeid') $(LITERAL '$(LPAREN)') ($(RULE type) | $(RULE expression)) $(LITERAL '$(RPAREN)')
6603      *     ;)
6604      */
6605     TypeidExpression parseTypeidExpression()
6606     {
6607         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6608         auto node = allocate!TypeidExpression;
6609         expect(tok!"typeid");
6610         expect(tok!"(");
6611         auto b = setBookmark();
6612         auto t = parseType();
6613         if (t is null || !currentIs(tok!")"))
6614         {
6615             goToBookmark(b);
6616             mixin(nullCheck!`node.expression = parseExpression()`);
6617             mixin(nullCheck!`node.expression`);
6618         }
6619         else
6620         {
6621             abandonBookmark(b);
6622             node.type = t;
6623         }
6624         expect(tok!")");
6625         return node;
6626     }
6627 
6628     /**
6629      * Parses a TypeofExpression
6630      *
6631      * $(GRAMMAR $(RULEDEF typeofExpression):
6632      *     $(LITERAL 'typeof') $(LITERAL '$(LPAREN)') ($(RULE expression) | $(LITERAL 'return')) $(LITERAL '$(RPAREN)')
6633      *     ;)
6634      */
6635     TypeofExpression parseTypeofExpression()
6636     {
6637         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6638         auto node = allocate!TypeofExpression;
6639         expect(tok!"typeof");
6640         expect(tok!"(");
6641         if (currentIs(tok!"return"))
6642             node.return_ = advance();
6643         else
6644             mixin(nullCheck!`node.expression = parseExpression()`);
6645         expect(tok!")");
6646         return node;
6647     }
6648 
6649     /**
6650      * Parses a UnaryExpression
6651      *
6652      * $(GRAMMAR $(RULEDEF unaryExpression):
6653      *       $(RULE primaryExpression)
6654      *     | $(LITERAL '&') $(RULE unaryExpression)
6655      *     | $(LITERAL '!') $(RULE unaryExpression)
6656      *     | $(LITERAL '*') $(RULE unaryExpression)
6657      *     | $(LITERAL '+') $(RULE unaryExpression)
6658      *     | $(LITERAL '-') $(RULE unaryExpression)
6659      *     | $(LITERAL '~') $(RULE unaryExpression)
6660      *     | $(LITERAL '++') $(RULE unaryExpression)
6661      *     | $(LITERAL '--') $(RULE unaryExpression)
6662      *     | $(RULE newExpression)
6663      *     | $(RULE deleteExpression)
6664      *     | $(RULE castExpression)
6665      *     | $(RULE assertExpression)
6666      *     | $(RULE functionCallExpression)
6667      *     | $(RULE indexExpression)
6668      *     | $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL '$(RPAREN)') $(LITERAL '.') $(RULE identifierOrTemplateInstance)
6669      *     | $(RULE unaryExpression) $(LITERAL '.') $(RULE identifierOrTemplateInstance)
6670      *     | $(RULE unaryExpression) $(LITERAL '--')
6671      *     | $(RULE unaryExpression) $(LITERAL '++')
6672      *     ;)
6673      */
6674     UnaryExpression parseUnaryExpression()
6675     {
6676         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6677         if (!moreTokens())
6678             return null;
6679         auto node = allocate!UnaryExpression;
6680         switch (current.type)
6681         {
6682         case tok!"const":
6683         case tok!"immutable":
6684         case tok!"inout":
6685         case tok!"shared":
6686             auto b = setBookmark();
6687             if (peekIs(tok!"("))
6688             {
6689                 advance();
6690                 const past = peekPastParens();
6691                 if (past !is null && past.type == tok!".")
6692                 {
6693                     goToBookmark(b);
6694                     goto default;
6695                 }
6696             }
6697             goToBookmark(b);
6698             goto case;
6699         case tok!"scope":
6700         case tok!"pure":
6701         case tok!"nothrow":
6702             mixin(nullCheck!`node.functionCallExpression = parseFunctionCallExpression()`);
6703             break;
6704         case tok!"&":
6705         case tok!"!":
6706         case tok!"*":
6707         case tok!"+":
6708         case tok!"-":
6709         case tok!"~":
6710         case tok!"++":
6711         case tok!"--":
6712             node.prefix = advance();
6713             mixin(nullCheck!`node.unaryExpression = parseUnaryExpression()`);
6714             break;
6715         case tok!"new":
6716             mixin(nullCheck!`node.newExpression = parseNewExpression()`);
6717             break;
6718         case tok!"delete":
6719             mixin(nullCheck!`node.deleteExpression = parseDeleteExpression()`);
6720             break;
6721         case tok!"cast":
6722             mixin(nullCheck!`node.castExpression = parseCastExpression()`);
6723             break;
6724         case tok!"assert":
6725             mixin(nullCheck!`node.assertExpression = parseAssertExpression()`);
6726             break;
6727         case tok!"(":
6728             // handle (type).identifier
6729             auto b = setBookmark();
6730             skipParens();
6731             if (startsWith(tok!".", tok!"identifier"))
6732             {
6733                 // go back to the (
6734                 goToBookmark(b);
6735                 b = setBookmark();
6736                 advance();
6737                 auto t = parseType();
6738                 if (t is null || !currentIs(tok!")"))
6739                 {
6740                     goToBookmark(b);
6741                     goto default;
6742                 }
6743                 abandonBookmark(b);
6744                 node.type = t;
6745                 advance(); // )
6746                 advance(); // .
6747                 mixin(nullCheck!`node.identifierOrTemplateInstance = parseIdentifierOrTemplateInstance()`);
6748                 break;
6749             }
6750             else
6751             {
6752                 // not (type).identifier, so treat as primary expression
6753                 goToBookmark(b);
6754                 goto default;
6755             }
6756         default:
6757             mixin(nullCheck!`node.primaryExpression = parsePrimaryExpression()`);
6758             break;
6759         }
6760 
6761         loop: while (moreTokens()) switch (current.type)
6762         {
6763         case tok!"!":
6764             if (peekIs(tok!"("))
6765             {
6766                 index++;
6767                 const p = peekPastParens();
6768                 immutable bool jump =  (currentIs(tok!"(") && p !is null && p.type == tok!"(")
6769                     || peekIs(tok!"(");
6770                 index--;
6771                 if (jump)
6772                     goto case tok!"(";
6773                 else
6774                     break loop;
6775             }
6776             else
6777                 break loop;
6778         case tok!"(":
6779             auto newUnary = allocate!UnaryExpression();
6780             mixin(nullCheck!`newUnary.functionCallExpression = parseFunctionCallExpression(node)`);
6781             node = newUnary;
6782             break;
6783         case tok!"++":
6784         case tok!"--":
6785             auto n = allocate!UnaryExpression();
6786             n.unaryExpression = node;
6787             n.suffix = advance();
6788             node = n;
6789             break;
6790         case tok!"[":
6791             auto n = allocate!UnaryExpression;
6792 			n.indexExpression = parseIndexExpression(node);
6793             node = n;
6794             break;
6795         case tok!".":
6796             advance();
6797             auto n = allocate!UnaryExpression();
6798             n.unaryExpression = node;
6799             n.identifierOrTemplateInstance = parseIdentifierOrTemplateInstance();
6800             node = n;
6801             break;
6802         default:
6803             break loop;
6804         }
6805         return node;
6806     }
6807 
6808     /**
6809      * Parses an UnionDeclaration
6810      *
6811      * $(GRAMMAR $(RULEDEF unionDeclaration):
6812      *       $(LITERAL 'union') $(LITERAL Identifier) $(RULE templateParameters) $(RULE constraint)? $(RULE structBody)
6813      *     | $(LITERAL 'union') $(LITERAL Identifier) ($(RULE structBody) | $(LITERAL ';'))
6814      *     | $(LITERAL 'union') $(RULE structBody)
6815      *     ;)
6816      */
6817     UnionDeclaration parseUnionDeclaration()
6818     {
6819         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6820         auto node = allocate!UnionDeclaration;
6821         // grab line number even if it's anonymous
6822         const t = expect(tok!"union");
6823 	node.comment = comment;
6824         if (currentIs(tok!"identifier"))
6825         {
6826             node.name = advance();
6827             if (currentIs(tok!"("))
6828             {
6829                 mixin(nullCheck!`node.templateParameters = parseTemplateParameters()`);
6830                 if (currentIs(tok!"if"))
6831                     mixin(nullCheck!`node.constraint = parseConstraint()`);
6832                 mixin(nullCheck!`node.structBody = parseStructBody()`);
6833             }
6834             else
6835                 goto semiOrStructBody;
6836         }
6837         else
6838         {
6839             node.name.line = t.line;
6840             node.name.column = t.column;
6841     semiOrStructBody:
6842             if (currentIs(tok!";"))
6843                 advance();
6844             else
6845                 mixin(nullCheck!`node.structBody = parseStructBody()`);
6846         }
6847         return node;
6848     }
6849 
6850     /**
6851      * Parses a Unittest
6852      *
6853      * $(GRAMMAR $(RULEDEF unittest):
6854      *     $(LITERAL 'unittest') $(RULE blockStatement)
6855      *     ;)
6856      */
6857     Unittest parseUnittest()
6858     {
6859         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6860         mixin(simpleParse!(Unittest, tok!"unittest", "blockStatement|parseBlockStatement"));
6861     }
6862 
6863     /**
6864      * Parses a VariableDeclaration
6865      *
6866      * $(GRAMMAR $(RULEDEF variableDeclaration):
6867      *       $(RULE storageClass)* $(RULE type) $(RULE declarator) ($(LITERAL ',') $(RULE declarator))* $(LITERAL ';')
6868      *     | $(RULE storageClass)* $(RULE type) $(LITERAL identifier) $(LITERAL '=') $(RULE functionBody) $(LITERAL ';')
6869      *     | $(RULE autoDeclaration)
6870      *     ;)
6871      */
6872     VariableDeclaration parseVariableDeclaration(Type type = null, bool isAuto = false,
6873         Attribute[] attributes = null, bool isEnum = false)
6874     {
6875         mixin(traceEnterAndExit!(__FUNCTION__));
6876         auto node = allocate!VariableDeclaration;
6877         node.attributes = attributes;
6878 	node.isEnum = isEnum;
6879         if (isAuto)
6880         {
6881             mixin(nullCheck!`node.autoDeclaration = parseAutoDeclaration()`);
6882             node.comment = node.autoDeclaration.comment;
6883             return node;
6884         }
6885 
6886         StorageClass[] storageClasses;
6887         while (isStorageClass())
6888         {
6889             auto s = parseStorageClass();
6890             if (s !is null)
6891                 storageClasses ~= s;
6892             else
6893             {
6894                 deallocate(node);
6895                 return null;
6896             }
6897         }
6898         node.storageClasses = ownArray(storageClasses);
6899 
6900         node.type = type is null ? parseType() : type;
6901         node.comment = comment;
6902         comment = null;
6903 
6904         // TODO: handle function bodies correctly
6905 
6906         Declarator[] declarators;
6907         while (true)
6908         {
6909             auto declarator = parseDeclarator();
6910             mixin(nullCheck!`declarator`);
6911             declarators ~= declarator;
6912             if (moreTokens() && currentIs(tok!","))
6913             {
6914                 declarator.comment = current.trailingComment;
6915                 advance();
6916             }
6917             else
6918                 break;
6919         }
6920         node.declarators = ownArray(declarators);
6921         const semicolon = expect(tok!";");
6922         mixin(nullCheck!`semicolon`);
6923         declarators[$ - 1].comment = semicolon.trailingComment;
6924         return node;
6925     }
6926 
6927     /**
6928      * Parses a Vector
6929      *
6930      * $(GRAMMAR $(RULEDEF vector):
6931      *     $(LITERAL '___vector') $(LITERAL '$(LPAREN)') $(RULE type) $(LITERAL '$(RPAREN)')
6932      *     ;)
6933      */
6934     Vector parseVector()
6935     {
6936         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6937         mixin(simpleParse!(Vector, tok!"__vector", tok!"(", "type|parseType", tok!")"));
6938     }
6939 
6940     /**
6941      * Parses a VersionCondition
6942      *
6943      * $(GRAMMAR $(RULEDEF versionCondition):
6944      *     $(LITERAL 'version') $(LITERAL '$(LPAREN)') ($(LITERAL IntegerLiteral) | $(LITERAL Identifier) | $(LITERAL 'unittest') | $(LITERAL 'assert')) $(LITERAL '$(RPAREN)')
6945      *     ;)
6946      */
6947     VersionCondition parseVersionCondition()
6948     {
6949         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6950         auto node = allocate!VersionCondition;
6951         const v = expect(tok!"version");
6952 
6953         mixin(nullCheck!`v`);
6954         node.versionIndex = v.index;
6955         mixin(nullCheck!`expect(tok!"(")`);
6956         if (currentIsOneOf(tok!"intLiteral", tok!"identifier",
6957             tok!"unittest", tok!"assert"))
6958         {
6959             node.token = advance();
6960         }
6961         else
6962         {
6963             error(`Expected an integer literal, an identifier, "assert", or "unittest"`);
6964             return null;
6965         }
6966         expect(tok!")");
6967         return node;
6968     }
6969 
6970     /**
6971      * Parses a VersionSpecification
6972      *
6973      * $(GRAMMAR $(RULEDEF versionSpecification):
6974      *     $(LITERAL 'version') $(LITERAL '=') ($(LITERAL Identifier) | $(LITERAL IntegerLiteral)) $(LITERAL ';')
6975      *     ;)
6976      */
6977     VersionSpecification parseVersionSpecification()
6978     {
6979         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
6980         auto node = allocate!VersionSpecification;
6981         mixin(expectSequence!(tok!"version", tok!"="));
6982         if (!currentIsOneOf(tok!"identifier", tok!"intLiteral"))
6983         {
6984             error("Identifier or integer literal expected");
6985             return null;
6986         }
6987         node.token = advance();
6988         expect(tok!";");
6989         return node;
6990     }
6991 
6992     /**
6993      * Parses a WhileStatement
6994      *
6995      * $(GRAMMAR $(RULEDEF whileStatement):
6996      *     $(LITERAL 'while') $(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)') $(RULE declarationOrStatement)
6997      *     ;)
6998      */
6999     WhileStatement parseWhileStatement()
7000     {
7001         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
7002         auto node = allocate!WhileStatement;
7003         expect(tok!"while");
7004         node.startIndex = current().index;
7005         expect(tok!"(");
7006         mixin(nullCheck!`node.expression = parseExpression()`);
7007         expect(tok!")");
7008         if (currentIs(tok!"}"))
7009         {
7010             error("Statement expected", false);
7011             return node; // this line makes DCD better
7012         }
7013         mixin(nullCheck!`node.declarationOrStatement = parseDeclarationOrStatement()`);
7014         return node;
7015     }
7016 
7017     /**
7018      * Parses a WithStatement
7019      *
7020      * $(GRAMMAR $(RULEDEF withStatement):
7021      *     $(LITERAL 'with') $(LITERAL '$(LPAREN)') $(RULE expression) $(LITERAL '$(RPAREN)') $(RULE statementNoCaseNoDefault)
7022      *     ;)
7023      */
7024     WithStatement parseWithStatement()
7025     {
7026         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
7027         mixin(simpleParse!(WithStatement, tok!"with", tok!"(",
7028             "expression|parseExpression", tok!")",
7029             "statementNoCaseNoDefault|parseStatementNoCaseNoDefault"));
7030     }
7031 
7032     /**
7033      * Parses an XorExpression
7034      *
7035      * $(GRAMMAR $(RULEDEF xorExpression):
7036      *       $(RULE andExpression)
7037      *     | $(RULE xorExpression) $(LITERAL '^') $(RULE andExpression)
7038      *     ;)
7039      */
7040     ExpressionNode parseXorExpression()
7041     {
7042         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
7043         return parseLeftAssocBinaryExpression!(XorExpression, AndExpression,
7044             tok!"^")();
7045     }
7046 
7047     /**
7048      * Current error count
7049      */
7050     uint errorCount;
7051 
7052     /**
7053      * Current warning count
7054      */
7055     uint warningCount;
7056 
7057     /**
7058      * Name used when reporting warnings and errors
7059      */
7060     string fileName;
7061 
7062     /**
7063      * Allocator used for creating AST nodes
7064      */
7065     IAllocator allocator;
7066 
7067     /**
7068      * Function that is called when a warning or error is encountered.
7069      * The parameters are the file name, line number, column number,
7070      * and the error or warning message.
7071      */
7072     void function(string, size_t, size_t, string, bool) messageFunction;
7073 
7074     void setTokens(const(Token)[] tokens)
7075     {
7076         this.tokens = tokens;
7077     }
7078 
7079     /**
7080      * Returns: true if there are more tokens
7081      */
7082     bool moreTokens() const nothrow pure @safe
7083     {
7084         return index < tokens.length;
7085     }
7086 
7087 protected:
7088 
7089     uint suppressedErrorCount;
7090 
7091     enum MAX_ERRORS = 500;
7092 
7093     T[] ownArray(T)(T[] from)
7094     {
7095         if (allocator is null)
7096             return from;
7097         T[] to = cast(T[]) allocator.allocate(T.sizeof * from.length);
7098         assert (to.length == from.length, format("from.length = %d, to.length = %d", from.length, to.length));
7099         to[] = from[];
7100         return to;
7101     }
7102 
7103     T allocate(T, Args...)(auto ref Args args)
7104     {
7105         if (allocator is null)
7106             return new T(args);
7107         enum numBytes = __traits(classInstanceSize, T);
7108         void[] mem = allocator.allocate(numBytes);
7109         assert (mem.length == numBytes, format("%d", mem.length));
7110         T t = emplace!T(mem, args);
7111         assert (cast(void*) t == mem.ptr, "%x, %x".format(cast(void*) t, mem.ptr));
7112         return t;
7113     }
7114 
7115     void deallocate(T)(T t)
7116     {
7117         if (allocator !is null)
7118             allocator.deallocate((cast (void*) t)[0 .. __traits(classInstanceSize, T)]);
7119     }
7120 
7121     bool isCastQualifier() const
7122     {
7123         switch (current.type)
7124         {
7125         case tok!"const":
7126             if (peekIs(tok!")")) return true;
7127             return startsWith(tok!"const", tok!"shared", tok!")");
7128         case tok!"immutable":
7129             return peekIs(tok!")");
7130         case tok!"inout":
7131             if (peekIs(tok!")")) return true;
7132             return startsWith(tok!"inout", tok!"shared", tok!")");
7133         case tok!"shared":
7134             if (peekIs(tok!")")) return true;
7135             if (startsWith(tok!"shared", tok!"const", tok!")")) return true;
7136             return startsWith(tok!"shared", tok!"inout", tok!")");
7137         default:
7138             return false;
7139         }
7140     }
7141 
7142     bool isAssociativeArrayLiteral()
7143     {
7144         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
7145         static bool[typeof(current.index)] cached;
7146         if (auto p = current.index in cached)
7147             return *p;
7148         size_t currentIndex = current.index;
7149         auto b = setBookmark();
7150         scope(exit) goToBookmark(b);
7151         advance();
7152         bool result = !currentIs(tok!"]") && parseExpression() !is null && currentIs(tok!":");
7153         cached[currentIndex] = result;
7154         return result;
7155     }
7156 
7157     bool hasMagicDelimiter(alias L, alias T)()
7158     {
7159         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
7160         immutable i = index;
7161         scope(exit) index = i;
7162         assert (currentIs(L));
7163         advance();
7164         while (moreTokens()) switch (current.type)
7165         {
7166         case tok!"{": skipBraces(); break;
7167         case tok!"(": skipParens(); break;
7168         case tok!"[": skipBrackets(); break;
7169         case tok!"]": case tok!"}": return false;
7170         case T: return true;
7171         default: advance(); break;
7172         }
7173         return false;
7174     }
7175 
7176     bool isDeclaration()
7177     {
7178         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
7179         if (!moreTokens()) return false;
7180         switch (current.type)
7181         {
7182         case tok!"final":
7183             return !peekIs(tok!"switch");
7184         case tok!"debug":
7185             if (peekIs(tok!":"))
7186                 return true;
7187             goto case;
7188         case tok!"version":
7189             if (peekIs(tok!"="))
7190                 return true;
7191             if (peekIs(tok!"("))
7192             {
7193                 auto b = setBookmark();
7194                 scope (exit) goToBookmark(b);
7195                 auto dec = parseDeclaration(true);
7196                 if (dec is null)
7197                     return false;
7198                 else
7199                 {
7200                     deallocate(dec);
7201                     return true;
7202                 }
7203             }
7204             return false;
7205         case tok!"synchronized":
7206             if (peekIs(tok!"("))
7207                 return false;
7208             else
7209                 goto default;
7210         case tok!"static":
7211             if (peekIs(tok!"if"))
7212                 return false;
7213             goto case;
7214         case tok!"scope":
7215             if (peekIs(tok!"("))
7216                 return false;
7217             goto case;
7218         case tok!"const":
7219         case tok!"immutable":
7220         case tok!"inout":
7221         case tok!"shared":
7222             goto default;
7223         case tok!"@":
7224         case tok!"abstract":
7225         case tok!"alias":
7226         case tok!"align":
7227         case tok!"auto":
7228         case tok!"class":
7229         case tok!"deprecated":
7230         case tok!"enum":
7231         case tok!"export":
7232         case tok!"extern":
7233         case tok!"__gshared":
7234         case tok!"interface":
7235         case tok!"nothrow":
7236         case tok!"override":
7237         case tok!"package":
7238         case tok!"private":
7239         case tok!"protected":
7240         case tok!"public":
7241         case tok!"pure":
7242         case tok!"ref":
7243         case tok!"struct":
7244         case tok!"union":
7245         case tok!"unittest":
7246             return true;
7247         mixin(BUILTIN_TYPE_CASES);
7248             return !peekIsOneOf(tok!".", tok!"(");
7249         case tok!"asm":
7250         case tok!"break":
7251         case tok!"case":
7252         case tok!"continue":
7253         case tok!"default":
7254         case tok!"do":
7255         case tok!"for":
7256         case tok!"foreach":
7257         case tok!"foreach_reverse":
7258         case tok!"goto":
7259         case tok!"if":
7260         case tok!"return":
7261         case tok!"switch":
7262         case tok!"throw":
7263         case tok!"try":
7264         case tok!"while":
7265         case tok!"{":
7266         case tok!"assert":
7267             return false;
7268         default:
7269             auto b = setBookmark();
7270             auto p = parseDeclaration();
7271             if (p is null)
7272             {
7273                 goToBookmark(b);
7274                 return false;
7275             }
7276             else
7277             {
7278                 deallocate(p);
7279                 goToBookmark(b);
7280                 return true;
7281             }
7282         }
7283     }
7284 
7285     /// Only use this in template parameter parsing
7286     bool isType()
7287     {
7288         if (!moreTokens()) return false;
7289         auto b = setBookmark();
7290         scope (exit) goToBookmark(b);
7291         auto t = parseType();
7292         if (t is null) return false; else deallocate(t);
7293         if (currentIsOneOf(tok!",", tok!")", tok!"=")) return true;
7294         return false;
7295     }
7296 
7297     bool isStorageClass()
7298     {
7299         if (!moreTokens()) return false;
7300         switch (current.type)
7301         {
7302         case tok!"const":
7303         case tok!"immutable":
7304         case tok!"inout":
7305         case tok!"shared":
7306             return !peekIs(tok!"(");
7307         case tok!"@":
7308         case tok!"deprecated":
7309         case tok!"abstract":
7310         case tok!"align":
7311         case tok!"auto":
7312         case tok!"enum":
7313         case tok!"extern":
7314         case tok!"final":
7315         case tok!"nothrow":
7316         case tok!"override":
7317         case tok!"pure":
7318         case tok!"ref":
7319         case tok!"__gshared":
7320         case tok!"scope":
7321         case tok!"static":
7322         case tok!"synchronized":
7323             return true;
7324         default:
7325             return false;
7326         }
7327     }
7328 
7329     bool isAttribute()
7330     {
7331         if (!moreTokens()) return false;
7332         switch (current.type)
7333         {
7334         case tok!"const":
7335         case tok!"immutable":
7336         case tok!"inout":
7337         case tok!"scope":
7338             return !peekIs(tok!"(");
7339         case tok!"static":
7340             return !peekIsOneOf(tok!"assert", tok!"this", tok!"if", tok!"~");
7341         case tok!"shared":
7342             return !(startsWith(tok!"shared", tok!"static", tok!"this")
7343                 || startsWith(tok!"shared", tok!"static", tok!"~")
7344                 || peekIs(tok!"("));
7345         case tok!"pragma":
7346             auto b = setBookmark();
7347             scope(exit) goToBookmark(b);
7348             advance();
7349             const past = peekPastParens();
7350             if (past is null || *past == tok!";")
7351                 return false;
7352             return true;
7353         case tok!"deprecated":
7354         case tok!"private":
7355         case tok!"package":
7356         case tok!"protected":
7357         case tok!"public":
7358         case tok!"export":
7359         case tok!"final":
7360         case tok!"synchronized":
7361         case tok!"override":
7362         case tok!"abstract":
7363         case tok!"auto":
7364         case tok!"__gshared":
7365         case tok!"pure":
7366         case tok!"nothrow":
7367         case tok!"@":
7368         case tok!"ref":
7369         case tok!"extern":
7370         case tok!"align":
7371             return true;
7372         default:
7373             return false;
7374         }
7375     }
7376 
7377     bool currentIsMemberFunctionAttribute() const
7378     {
7379         if (!moreTokens) return false;
7380         switch (current.type)
7381         {
7382         case tok!"const":
7383         case tok!"immutable":
7384         case tok!"inout":
7385         case tok!"shared":
7386         case tok!"@":
7387         case tok!"pure":
7388         case tok!"nothrow":
7389         case tok!"return":
7390         case tok!"scope":
7391             return true;
7392         default:
7393             return false;
7394         }
7395     }
7396 
7397     ExpressionNode parseLeftAssocBinaryExpression(alias ExpressionType,
7398         alias ExpressionPartType, Operators ...)(ExpressionNode part = null)
7399     {
7400         ExpressionNode node;
7401         mixin("node = part is null ? parse" ~ ExpressionPartType.stringof ~ "() : part;");
7402         if (node is null)
7403         {
7404             deallocate(node);
7405             return null;
7406         }
7407         while (currentIsOneOf(Operators))
7408         {
7409             auto n = allocate!ExpressionType;
7410             n.line = current.line;
7411             n.column = current.column;
7412             static if (__traits(hasMember, ExpressionType, "operator"))
7413                 n.operator = advance().type;
7414             else
7415                 advance();
7416             n.left = node;
7417             mixin("n.right = parse" ~ ExpressionPartType.stringof ~ "();");
7418             node = n;
7419         }
7420         return node;
7421     }
7422 
7423     ListType parseCommaSeparatedRule(alias ListType, alias ItemType, bool setLineAndColumn = false)
7424         (bool allowTrailingComma = false)
7425     {
7426         auto node = allocate!ListType;
7427         static if (setLineAndColumn)
7428         {
7429             node.line = current.line;
7430             node.column = current.column;
7431         }
7432         static if (is(ItemType : ExpressionNode))
7433             ExpressionNode[] items;
7434         else
7435             ItemType[] items;
7436         while (moreTokens())
7437         {
7438             mixin("auto i = parse" ~ ItemType.stringof ~ "();");
7439             if (i !is null)
7440                 items ~= i;
7441             else
7442             {
7443                 deallocate(node);
7444                 return null;
7445             }
7446             if (currentIs(tok!","))
7447             {
7448                 advance();
7449                 if (allowTrailingComma && currentIsOneOf(tok!")",
7450                     tok!"}", tok!"]"))
7451                 {
7452                     break;
7453                 }
7454                 else
7455                     continue;
7456             }
7457             else
7458                 break;
7459         }
7460         node.items = ownArray(items);
7461         return node;
7462     }
7463 
7464     void warn(lazy string message)
7465     {
7466         import std.stdio : stderr;
7467         if (suppressMessages > 0)
7468             return;
7469         ++warningCount;
7470         auto column = index < tokens.length ? tokens[index].column : 0;
7471         auto line = index < tokens.length ? tokens[index].line : 0;
7472         if (messageFunction is null)
7473             stderr.writefln("%s(%d:%d)[warn]: %s", fileName, line, column, message);
7474         else
7475             messageFunction(fileName, line, column, message, false);
7476     }
7477 
7478     void error(string message, bool shouldAdvance = true)
7479     {
7480         import std.stdio : stderr;
7481         if (suppressMessages == 0)
7482         {
7483             ++errorCount;
7484             auto column = index < tokens.length ? tokens[index].column : tokens[$ - 1].column;
7485             auto line = index < tokens.length ? tokens[index].line : tokens[$ - 1].line;
7486             if (messageFunction is null)
7487                 stderr.writefln("%s(%d:%d)[error]: %s", fileName, line, column, message);
7488             else
7489                 messageFunction(fileName, line, column, message, true);
7490         }
7491         else
7492             ++suppressedErrorCount;
7493         while (shouldAdvance && moreTokens())
7494         {
7495             if (currentIsOneOf(tok!";", tok!"}",
7496                 tok!")", tok!"]"))
7497             {
7498                 advance();
7499                 break;
7500             }
7501             else
7502                 advance();
7503         }
7504     }
7505 
7506     void skip(alias O, alias C)()
7507     {
7508         assert (currentIs(O), current().text);
7509         advance();
7510         int depth = 1;
7511         while (moreTokens())
7512         {
7513             switch (tokens[index].type)
7514             {
7515                 case C:
7516                     advance();
7517                     depth--;
7518                     if (depth <= 0)
7519                         return;
7520                     break;
7521                 case O:
7522                     depth++;
7523                     advance();
7524                     break;
7525                 default:
7526                     advance();
7527                     break;
7528             }
7529         }
7530     }
7531 
7532     void skipBraces()
7533     {
7534         skip!(tok!"{", tok!"}")();
7535     }
7536 
7537     void skipParens()
7538     {
7539         version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
7540         skip!(tok!"(", tok!")")();
7541     }
7542 
7543     void skipBrackets()
7544     {
7545         skip!(tok!"[", tok!"]")();
7546     }
7547 
7548     const(Token)* peek() const
7549     {
7550         return index + 1 < tokens.length ? &tokens[index + 1] : null;
7551     }
7552 
7553     const(Token)* peekPast(alias O, alias C)() const nothrow
7554     {
7555         if (index >= tokens.length)
7556             return null;
7557         int depth = 1;
7558         size_t i = index;
7559         ++i;
7560         while (i < tokens.length)
7561         {
7562             if (tokens[i] == O)
7563             {
7564                 ++depth;
7565                 ++i;
7566             }
7567             else if (tokens[i] == C)
7568             {
7569                 --depth;
7570                 ++i;
7571                 if (depth <= 0)
7572                     break;
7573             }
7574             else
7575                 ++i;
7576         }
7577         return i >= tokens.length ? null : depth == 0 ? &tokens[i] : null;
7578     }
7579 
7580     const(Token)* peekPastParens() const nothrow
7581     {
7582         return peekPast!(tok!"(", tok!")")();
7583     }
7584 
7585     const(Token)* peekPastBrackets() const nothrow
7586     {
7587         return peekPast!(tok!"[", tok!"]")();
7588     }
7589 
7590     const(Token)* peekPastBraces() const nothrow
7591     {
7592         return peekPast!(tok!"{", tok!"}")();
7593     }
7594 
7595     bool peekIs(IdType t) const nothrow
7596     {
7597         return index + 1 < tokens.length && tokens[index + 1].type == t;
7598     }
7599 
7600     bool peekIsOneOf(IdType[] types...) const nothrow
7601     {
7602         if (index + 1 >= tokens.length) return false;
7603         return canFind(types, tokens[index + 1].type);
7604     }
7605 
7606     /**
7607      * Returns a token of the specified type if it was the next token, otherwise
7608      * calls the error function and returns null. Advances the lexer by one token.
7609      */
7610     const(Token)* expect(IdType type)
7611     {
7612         if (index < tokens.length && tokens[index].type == type)
7613             return &tokens[index++];
7614         else
7615         {
7616             string tokenString = str(type) is null
7617                 ? to!string(type) : str(type);
7618             immutable bool shouldNotAdvance = index < tokens.length
7619                 && (tokens[index].type == tok!")"
7620                 || tokens[index].type == tok!";"
7621                 || tokens[index].type == tok!"}");
7622             auto token = (index < tokens.length
7623                 ? (tokens[index].text is null ? str(tokens[index].type) : tokens[index].text)
7624                 : "EOF");
7625             error("Expected " ~  tokenString ~ " instead of " ~ token,
7626                 !shouldNotAdvance);
7627             return null;
7628         }
7629     }
7630 
7631     /**
7632      * Returns: the _current token
7633      */
7634     Token current() const pure nothrow @nogc @property
7635     {
7636         return tokens[index];
7637     }
7638 
7639     /**
7640      * Advances to the next token and returns the current token
7641      */
7642     Token advance() pure nothrow @nogc
7643     {
7644 	debug if(index + 1 > tokens.length) {
7645 		import std.stdio;
7646 		foreach(token; tokens) {
7647 			    string tokenString = str(token.type) is null
7648 				? to!string(token.type) : str(token.type);
7649 			write(tokenString == "identifier" ? token.text : tokenString, " ");
7650 		}
7651 		writeln();
7652 
7653 		return Token(tok!"}");
7654 	}
7655         return tokens[index++];
7656     }
7657 
7658     /**
7659      * Returns: true if the current token has the given type
7660      */
7661     bool currentIs(IdType type) const pure nothrow @nogc
7662     {
7663         return index < tokens.length && tokens[index] == type;
7664     }
7665 
7666     /**
7667      * Returns: true if the current token is one of the given types
7668      */
7669     bool currentIsOneOf(IdType[] types...) const pure nothrow @nogc
7670     {
7671         if (index >= tokens.length)
7672             return false;
7673         return canFind(types, current.type);
7674     }
7675 
7676     bool startsWith(IdType[] types...) const pure nothrow @nogc
7677     {
7678         if (index + types.length >= tokens.length)
7679             return false;
7680         for (size_t i = 0; (i < types.length) && ((index + i) < tokens.length); ++i)
7681         {
7682             if (tokens[index + i].type != types[i])
7683                 return false;
7684         }
7685         return true;
7686     }
7687 
7688     alias Bookmark = size_t;
7689 
7690     Bookmark setBookmark()
7691     {
7692 //        version(std_parser_verbose) mixin(traceEnterAndExit!(__FUNCTION__));
7693         ++suppressMessages;
7694         return index;
7695     }
7696 
7697     void abandonBookmark(Bookmark) nothrow
7698     {
7699         --suppressMessages;
7700         if (suppressMessages == 0)
7701             suppressedErrorCount = 0;
7702     }
7703 
7704     void goToBookmark(Bookmark bookmark) nothrow
7705     {
7706         --suppressMessages;
7707         if (suppressMessages == 0)
7708             suppressedErrorCount = 0;
7709         index = bookmark;
7710     }
7711 
7712     template simpleParse(NodeType, parts ...)
7713     {
7714         static if (__traits(hasMember, NodeType, "comment"))
7715             enum nodeComm = "node.comment = comment;\n"
7716                         ~ "comment = null;\n";
7717         else enum nodeComm = "";
7718 
7719         static if (__traits(hasMember, NodeType, "line"))
7720             enum nodeLine = "node.line = current().line;\n";
7721         else enum nodeLine = "";
7722 
7723         static if (__traits(hasMember, NodeType, "column"))
7724             enum nodeColumn = "node.column = current().column;\n";
7725         else enum nodeColumn = "";
7726 
7727         static if (__traits(hasMember, NodeType, "location"))
7728             enum nodeLoc = "node.location = current().index;\n";
7729         else enum nodeLoc = "";
7730 
7731         enum simpleParse = "auto node = allocate!" ~ NodeType.stringof ~ ";\n"
7732                         ~ nodeComm ~ nodeLine ~ nodeColumn ~ nodeLoc
7733                         ~ simpleParseItems!(parts)
7734                         ~ "\nreturn node;\n";
7735     }
7736 
7737     template simpleParseItems(items ...)
7738     {
7739         static if (items.length > 1)
7740             enum simpleParseItems = simpleParseItem!(items[0]) ~ "\n"
7741                 ~ simpleParseItems!(items[1 .. $]);
7742         else static if (items.length == 1)
7743             enum simpleParseItems = simpleParseItem!(items[0]);
7744         else
7745             enum simpleParseItems = "";
7746     }
7747 
7748     template simpleParseItem(alias item)
7749     {
7750         static if (is (typeof(item) == string))
7751             enum simpleParseItem = "if ((node." ~ item[0 .. item.countUntil("|")]
7752                 ~ " = " ~ item[item.countUntil("|") + 1 .. $] ~ "()) is null) { deallocate(node); return null; }";
7753         else
7754             enum simpleParseItem = "if (expect(" ~ item.stringof ~ ") is null) { deallocate(node); return null; }";
7755     }
7756 
7757     template expectSequence(sequence ...)
7758     {
7759         static if (sequence.length == 1)
7760             enum expectSequence = "if (expect(" ~ sequence[0].stringof ~ ") is null) { deallocate(node); return null; }";
7761         else
7762             enum expectSequence = "if (expect(" ~ sequence[0].stringof ~ ") is null) { deallocate(node); return null; }\n"
7763                 ~ expectSequence!(sequence[1..$]);
7764     }
7765 
7766     template traceEnterAndExit(string fun)
7767     {
7768         enum traceEnterAndExit = `version (std_parser_verbose) { _traceDepth++; trace("`
7769             ~ `\033[01;32m` ~ fun ~ `\033[0m"); }`
7770             ~ `version (std_parser_verbose) scope(exit) { trace("`
7771             ~ `\033[01;31m` ~ fun ~ `\033[0m"); _traceDepth--; }`;
7772     }
7773 
7774     version (std_parser_verbose)
7775     {
7776         import std.stdio : stderr;
7777         void trace(string message)
7778         {
7779             if (suppressMessages > 0)
7780                 return;
7781             auto depth = format("%4d ", _traceDepth);
7782             if (index < tokens.length)
7783                 stderr.writeln(depth, message, "(", current.line, ":", current.column, ")");
7784             else
7785                 stderr.writeln(depth, message, "(EOF:0)");
7786         }
7787     }
7788     else
7789     {
7790         void trace(lazy string) {}
7791     }
7792 
7793     template nullCheck(string exp)
7794     {
7795         enum nullCheck = "{if ((" ~ exp ~ ") is null) { deallocate(node); return null; }}";
7796     }
7797 
7798     template tokenCheck(string exp, string tok)
7799     {
7800         enum tokenCheck = `{auto t = expect(tok!"` ~ tok ~ `");`
7801             ~ `if (t is null) { deallocate(node); return null;}`
7802             ~ `else {` ~ exp ~ ` = *t; }}`;
7803     }
7804 
7805     // This list MUST BE MAINTAINED IN SORTED ORDER.
7806     static immutable string[] REGISTER_NAMES = [
7807         "AH", "AL", "AX", "BH", "BL", "BP", "BPL", "BX", "CH", "CL", "CR0", "CR2",
7808         "CR3", "CR4", "CS", "CX", "DH", "DI", "DIL", "DL", "DR0", "DR1", "DR2",
7809         "DR3", "DR6", "DR7", "DS", "DX", "EAX", "EBP", "EBX", "ECX", "EDI", "EDX",
7810         "ES", "ESI", "ESP", "FS", "GS", "MM0", "MM1", "MM2", "MM3", "MM4", "MM5",
7811         "MM6", "MM7", "R10", "R10B", "R10D", "R10W", "R11", "R11B", "R11D", "R11W",
7812         "R12", "R12B", "R12D", "R12W", "R13", "R13B", "R13D", "R13W", "R14", "R14B",
7813         "R14D", "R14W", "R15", "R15B", "R15D", "R15W", "R8", "R8B", "R8D", "R8W",
7814         "R9", "R9B", "R9D", "R9W", "RAX", "RBP", "RBX", "RCX", "RDI", "RDX", "RSI",
7815         "RSP", "SI", "SIL", "SP", "SPL", "SS", "ST", "TR3", "TR4", "TR5", "TR6",
7816         "TR7", "XMM0", "XMM1", "XMM10", "XMM11", "XMM12", "XMM13", "XMM14", "XMM15",
7817         "XMM2", "XMM3", "XMM4", "XMM5", "XMM6", "XMM7", "XMM8", "XMM9", "YMM0",
7818         "YMM1", "YMM10", "YMM11", "YMM12", "YMM13", "YMM14", "YMM15", "YMM2",
7819         "YMM3", "YMM4", "YMM5", "YMM6", "YMM7", "YMM8", "YMM9"
7820     ];
7821 
7822     enum string BUILTIN_TYPE_CASES = q{
7823         case tok!"int":
7824         case tok!"uint":
7825         case tok!"double":
7826         case tok!"idouble":
7827         case tok!"float":
7828         case tok!"ifloat":
7829         case tok!"short":
7830         case tok!"ushort":
7831         case tok!"long":
7832         case tok!"ulong":
7833         case tok!"char":
7834         case tok!"wchar":
7835         case tok!"dchar":
7836         case tok!"bool":
7837         case tok!"void":
7838         case tok!"cent":
7839         case tok!"ucent":
7840         case tok!"real":
7841         case tok!"ireal":
7842         case tok!"byte":
7843         case tok!"ubyte":
7844         case tok!"cdouble":
7845         case tok!"cfloat":
7846         case tok!"creal":
7847     };
7848 
7849     enum string LITERAL_CASES = q{
7850         case tok!"doubleLiteral":
7851         case tok!"floatLiteral":
7852         case tok!"idoubleLiteral":
7853         case tok!"ifloatLiteral":
7854         case tok!"intLiteral":
7855         case tok!"longLiteral":
7856         case tok!"realLiteral":
7857         case tok!"irealLiteral":
7858         case tok!"uintLiteral":
7859         case tok!"ulongLiteral":
7860         case tok!"stringLiteral":
7861         case tok!"wstringLiteral":
7862         case tok!"dstringLiteral":
7863         case tok!"characterLiteral":
7864     };
7865 
7866     enum string SPECIAL_CASES = q{
7867         case tok!"__DATE__":
7868         case tok!"__EOF__":
7869         case tok!"__FILE__":
7870         case tok!"__FUNCTION__":
7871         case tok!"__LINE__":
7872         case tok!"__MODULE__":
7873         case tok!"__PRETTY_FUNCTION__":
7874         case tok!"__TIME__":
7875         case tok!"__TIMESTAMP__":
7876         case tok!"__VENDOR__":
7877         case tok!"__VERSION__":
7878     };
7879 
7880     enum string PARSE_INTERFACE_OR_CLASS = q{
7881         auto ident = expect(tok!"identifier");
7882         mixin(nullCheck!`ident`);
7883         node.name = *ident;
7884         node.comment = comment;
7885         comment = null;
7886         if (currentIs(tok!";"))
7887             goto emptyBody;
7888         if (currentIs(tok!"{"))
7889             goto structBody;
7890         templateStuff: if (currentIs(tok!"("))
7891         {
7892             mixin(nullCheck!`node.templateParameters = parseTemplateParameters()`);
7893             if (currentIs(tok!";"))
7894                 goto emptyBody;
7895             constraint: if (currentIs(tok!"if"))
7896                 mixin(nullCheck!`node.constraint = parseConstraint()`);
7897             if (node.baseClassList !is null)
7898             {
7899                 if (currentIs(tok!"{"))
7900                     goto structBody;
7901                 else if (currentIs(tok!";"))
7902                     goto emptyBody;
7903                 else
7904                 {
7905                     error("Struct body or ';' expected");
7906                     return null;
7907                 }
7908             }
7909             if (currentIs(tok!":"))
7910                 goto baseClassList;
7911             if (currentIs(tok!"if"))
7912                 goto constraint;
7913             if (currentIs(tok!";"))
7914                 goto emptyBody;
7915         }
7916         if (currentIs(tok!":"))
7917         {
7918     baseClassList:
7919             advance(); // :
7920             if ((node.baseClassList = parseBaseClassList()) is null)
7921                 return null;
7922             if (currentIs(tok!"if"))
7923                 goto constraint;
7924         }
7925     structBody:
7926         mixin(nullCheck!`node.structBody = parseStructBody()`);
7927         return node;
7928     emptyBody:
7929         advance();
7930         return node;
7931     };
7932 
7933     const(Token)[] tokens;
7934     int suppressMessages;
7935     size_t index;
7936     int _traceDepth;
7937     string comment;
7938 }
7939