1 module format.parser;
2 
3 /**
4  * While we already have a parser in libd, we cannot use it here.
5  * This is because libd's parser is meant to validate that the source
6  * is well a formed D program. However, we want to be able to format
7  * even incomplete programs as part of the developper's process.
8  *
9  * This parser, on the other hand, is meant to recognize common patterns
10  * in the language, without ensuring that they are indeed correct.
11  */
12 struct Parser {
13 private:
14 	import source.dlexer;
15 	TokenRange trange;
16 
17 	import format.chunk;
18 	Builder builder;
19 
20 	bool needDoubleIndent = false;
21 	bool doubleIndentBlock = false;
22 	bool canBeDeclaration = false;
23 	bool expectParameters = false;
24 
25 	enum Mode {
26 		Declaration,
27 		Statement,
28 		Parameter,
29 	}
30 
31 	Mode mode;
32 
33 	auto changeMode(Mode m) {
34 		static struct Guard {
35 			~this() {
36 				parser.mode = oldMode;
37 			}
38 
39 		private:
40 			Parser* parser;
41 			Mode oldMode;
42 		}
43 
44 		Mode oldMode = mode;
45 		mode = m;
46 
47 		return Guard(&this, oldMode);
48 	}
49 
50 	/**
51 	 * When we can't parse we skip and forward chunks "as this"
52 	 */
53 	Location skipped;
54 
55 	/**
56 	 * Comments to be emitted before the next token.
57 	 *  - inFlightComments: Comments which are on their own.
58 	 *  - nextComments: Comment attached to what comes next.
59 	 */
60 	Location[] inFlightComments;
61 	Location[] nextComments;
62 
63 	/**
64 	 * Passthrough for portion of code not to be formatted.
65 	 *
66 	 * When formatting is disabled, we keep parsing anyways. This ensures
67 	 * the state of affairs, such as identation levels, are kept track off.
68 	 * However, nothign is sent to the builder as parsing progresses, and
69 	 * everything is sent as one signle chunk at the end of it.
70 	 */
71 	Position sdfmtOffStart;
72 
73 	bool skipFormatting() const {
74 		return sdfmtOffStart != Position();
75 	}
76 
77 public:
78 	import source.context;
79 	this(Position base, Context context) {
80 		this.trange =
81 			lex(base, context).withStringDecoding(false).withComments();
82 	}
83 
84 	Chunk[] parse() in {
85 		assert(match(TokenType.Begin));
86 	} do {
87 		// Emit the shebang if there is one.
88 		write(token.location, token.toString(context));
89 		trange.popFront();
90 		newline();
91 
92 		parseComments();
93 
94 		parseModule();
95 
96 		assert(match(TokenType.End));
97 
98 		emitSkippedTokens();
99 		flushComments();
100 
101 		return builder.build();
102 	}
103 
104 private:
105 	/**
106 	 * Chunk builder facilities
107 	 */
108 	void write(Location loc, string s) {
109 		if (skipFormatting()) {
110 			return;
111 		}
112 
113 		if (newLineCount(loc) == 0) {
114 			builder.write(s);
115 			return;
116 		}
117 
118 		// We have a multi line chunk.
119 		import std.array;
120 		foreach (i, l; s.split('\n')) {
121 			if (i > 0) {
122 				builder.split(true, true);
123 				builder.newline(1);
124 			}
125 
126 			builder.write(l);
127 		}
128 	}
129 
130 	void space() {
131 		if (skipFormatting()) {
132 			return;
133 		}
134 
135 		builder.space();
136 	}
137 
138 	void newline() {
139 		newline(newLineCount());
140 	}
141 
142 	void newline(int nl) {
143 		if (skipFormatting()) {
144 			return;
145 		}
146 
147 		builder.newline(nl);
148 	}
149 
150 	void clearSeparator() {
151 		if (skipFormatting()) {
152 			return;
153 		}
154 
155 		builder.clearSeparator();
156 	}
157 
158 	void split(bool glued = false, bool continuation = false) {
159 		emitRawContent();
160 		builder.split(glued || skipFormatting(), continuation);
161 	}
162 
163 	auto indent(uint level = 1) {
164 		return builder.indent(level);
165 	}
166 
167 	auto unindent(uint level = 1) {
168 		return builder.unindent(level);
169 	}
170 
171 	import format.span;
172 	auto span(S = Span, T...)(T args) {
173 		emitSkippedTokens();
174 		emitInFlightComments();
175 
176 		return builder.span!S(args);
177 	}
178 
179 	auto spliceSpan(S = Span, T...)(T args) {
180 		emitSkippedTokens();
181 		emitInFlightComments();
182 
183 		return builder.spliceSpan!S(args);
184 	}
185 
186 	auto block() {
187 		emitRawContent();
188 		return builder.block();
189 	}
190 
191 	/**
192 	 * Miscellaneous and conveniences.
193 	 */
194 	@property
195 	auto context() {
196 		return trange.context;
197 	}
198 
199 	/**
200 	 * Whitespace management.
201 	 */
202 	import source.location;
203 	uint getLineNumber(Position p) {
204 		return p.getFullPosition(context).getLineNumber();
205 	}
206 
207 	int newLineCount(Position start, Position stop) {
208 		return getLineNumber(stop) - getLineNumber(start);
209 	}
210 
211 	int newLineCount(Location location) {
212 		return newLineCount(location.start, location.stop);
213 	}
214 
215 	int newLineCount(ref TokenRange r) {
216 		return newLineCount(r.previous, r.front.location.start);
217 	}
218 
219 	int newLineCount() {
220 		return newLineCount(trange);
221 	}
222 
223 	uint getSourceOffset(Position p) {
224 		return p.getFullPosition(context).getSourceOffset();
225 	}
226 
227 	int whiteSpaceLength(Position start, Position stop) {
228 		return getSourceOffset(stop) - getSourceOffset(start);
229 	}
230 
231 	int whiteSpaceLength() {
232 		return whiteSpaceLength(trange.previous, token.location.start);
233 	}
234 
235 	void emitSourceBasedWhiteSpace(Position previous, Location current) {
236 		if (auto nl = newLineCount(previous, current.start)) {
237 			newline(nl);
238 			return;
239 		}
240 
241 		if (whiteSpaceLength(previous, current.start) > 0) {
242 			space();
243 		}
244 	}
245 
246 	void emitSourceBasedWhiteSpace() {
247 		emitSourceBasedWhiteSpace(trange.previous, token.location);
248 	}
249 
250 	/**
251 	 * Token processing.
252 	 */
253 	@property
254 	Token token() const {
255 		return trange.front;
256 	}
257 
258 	bool match(TokenType t) {
259 		return token.type == t;
260 	}
261 
262 	auto runOnType(TokenType T, alias fun)() {
263 		if (match(T)) {
264 			return fun();
265 		}
266 	}
267 
268 	void nextToken() {
269 		emitSkippedTokens();
270 		flushComments();
271 
272 		if (match(TokenType.End)) {
273 			// We reached the end of our input.
274 			return;
275 		}
276 
277 		// Process current token.
278 		write(token.location, token.toString(context));
279 
280 		trange.popFront();
281 		parseComments();
282 	}
283 
284 	/**
285 	 * We skip over portions of the code we can't parse.
286 	 */
287 	void skipToken() {
288 		flushComments();
289 
290 		if (skipped.length == 0) {
291 			emitSourceBasedWhiteSpace();
292 			space();
293 			split();
294 
295 			skipped = Location(trange.previous, token.location.stop);
296 		} else {
297 			skipped.spanTo(token.location);
298 		}
299 
300 		if (match(TokenType.End)) {
301 			// We skipped until the end.
302 			return;
303 		}
304 
305 		trange.popFront();
306 
307 		// Skip over comments that look related too.
308 		while (match(TokenType.Comment) && newLineCount() == 0) {
309 			skipped.spanTo(token.location);
310 			trange.popFront();
311 		}
312 
313 		parseComments();
314 	}
315 
316 	void emitSkippedTokens() {
317 		if (skipped.length == 0) {
318 			return;
319 		}
320 
321 		import std.string;
322 		auto str = skipped.getFullLocation(context).getSlice().strip();
323 		write(skipped, str);
324 		skipped = Location.init;
325 
326 		emitSourceBasedWhiteSpace();
327 		split();
328 	}
329 
330 	/**
331 	 * Unformateed code management.
332 	 */
333 	void emitRawContent() {
334 		auto upTo = inFlightComments.length > 0
335 			? inFlightComments[0]
336 			: nextComments.length > 0 ? nextComments[0] : token.location;
337 
338 		emitRawContent(upTo.start);
339 	}
340 
341 	void emitRawContent(Position upTo) {
342 		if (!skipFormatting()) {
343 			return;
344 		}
345 
346 		builder.write(
347 			Location(sdfmtOffStart, upTo).getFullLocation(context).getSlice());
348 		sdfmtOffStart = upTo;
349 	}
350 
351 	/**
352 	 * Comments management
353 	 */
354 	void emitComment(Location loc, Position previous) {
355 		emitSourceBasedWhiteSpace(previous, loc);
356 
357 		import std.string;
358 		auto comment = loc.getFullLocation(context).getSlice().strip();
359 		if (skipFormatting() && comment == "// sdfmt on") {
360 			emitRawContent(loc.start);
361 			sdfmtOffStart = Position();
362 		}
363 
364 		write(loc, comment);
365 
366 		if (comment == "// sdfmt off") {
367 			sdfmtOffStart = loc.stop;
368 			assert(skipFormatting(), "We should start skipping.");
369 		}
370 
371 		// Make sure we have a line split after // style comments.
372 		if (!skipFormatting() && comment.startsWith("//")) {
373 			newline(1);
374 			split();
375 		}
376 	}
377 
378 	void emitComments(ref Location[] commentBlock, Location nextTokenLoc) {
379 		if (commentBlock.length == 0) {
380 			return;
381 		}
382 
383 		scope(success) {
384 			commentBlock = [];
385 		}
386 
387 		Position previous = commentBlock[0].start;
388 
389 		foreach (loc; commentBlock) {
390 			scope(success) {
391 				previous = loc.stop;
392 			}
393 
394 			emitComment(loc, previous);
395 		}
396 
397 		emitSourceBasedWhiteSpace(previous, nextTokenLoc);
398 	}
399 
400 	void emitInFlightComments() {
401 		auto nextTokenLoc =
402 			nextComments.length > 0 ? nextComments[0] : token.location;
403 
404 		emitComments(inFlightComments, nextTokenLoc);
405 	}
406 
407 	void flushComments() {
408 		emitInFlightComments();
409 		emitComments(nextComments, token.location);
410 	}
411 
412 	void parseComments() in {
413 		assert(inFlightComments == []);
414 		assert(nextComments == []);
415 	} do {
416 		if (!match(TokenType.Comment)) {
417 			return;
418 		}
419 
420 		emitSkippedTokens();
421 
422 		/**
423 		 * We distrube comments in 3 groups:
424 		 *   1 - The comments attached to the previous structural element.
425 		 *   2 - The comments in flight between two structural elements.
426 		 *   3 - The comments attached to the next structural element.
427 		 * We want to emit group 1 right away, but wait for later when
428 		 * emitting groups 2 and 3.
429 		 */
430 		while (match(TokenType.Comment) && newLineCount() == 0) {
431 			emitComment(token.location, trange.previous);
432 			trange.popFront();
433 		}
434 
435 		emitSourceBasedWhiteSpace();
436 
437 		Location[] commentBlock = [];
438 		while (match(TokenType.Comment)) {
439 			commentBlock ~= token.location;
440 			trange.popFront();
441 
442 			if (newLineCount() < 2) {
443 				continue;
444 			}
445 
446 			inFlightComments ~= commentBlock;
447 			commentBlock = [];
448 		}
449 
450 		nextComments = commentBlock;
451 	}
452 
453 	/**
454 	 * Parsing
455 	 */
456 	void parseModule() {
457 		auto guard = changeMode(Mode.Declaration);
458 
459 		while (!match(TokenType.End)) {
460 			parseStructuralElement();
461 		}
462 	}
463 
464 	void parseStructuralElement() {
465 		emitInFlightComments();
466 
467 		canBeDeclaration = true;
468 
469 	Entry:
470 		switch (token.type) with (TokenType) {
471 			case End:
472 				return;
473 
474 			case Module:
475 				parseModuleDeclaration();
476 				break;
477 
478 			/**
479 			 * Misc
480 			 */
481 			case DotDotDot:
482 				nextToken();
483 				return;
484 
485 			/**
486 			 * Statements
487 			 */
488 			case OpenBrace:
489 				parseBlock(mode);
490 
491 				// Blocks do not end with a semicolon.
492 				return;
493 
494 			case Identifier:
495 				auto lookahead = trange.getLookahead();
496 				lookahead.popFront();
497 				auto t = lookahead.front.type;
498 
499 				if (mode == Mode.Parameter
500 					    && (t == Colon || t == Equal || t == DotDotDot)) {
501 					parseTemplateParameter();
502 					break;
503 				}
504 
505 				if (t != Colon) {
506 					// This is an expression or a declaration.
507 					goto default;
508 				}
509 
510 				lookahead.popFront();
511 				if (newLineCount(lookahead) == 0) {
512 					nextToken();
513 					nextToken();
514 					space();
515 					goto Entry;
516 				}
517 
518 				{
519 					auto guard = unindent();
520 					newline(2);
521 					nextToken();
522 				}
523 
524 				parseColonBlock();
525 				break;
526 
527 			case If:
528 				parseIf();
529 				break;
530 
531 			case Version, Debug:
532 				parseVersion();
533 				break;
534 
535 			case Else:
536 				parseElse();
537 				break;
538 
539 			case While:
540 				parseWhile();
541 				break;
542 
543 			case Do:
544 				parseDoWhile();
545 				break;
546 
547 			case For:
548 				parseFor();
549 				break;
550 
551 			case Foreach, ForeachReverse:
552 				withCaseLevelIndent!parseForeach();
553 				break;
554 
555 			case Return:
556 				// If this is a parameter, then return is a storage class.
557 				if (mode == Mode.Parameter) {
558 					goto default;
559 				}
560 
561 				goto ReturnLike;
562 
563 			case Throw:
564 				goto ReturnLike;
565 
566 			ReturnLike:
567 				parseReturn();
568 				break;
569 
570 			case Break, Continue:
571 				nextToken();
572 
573 				if (match(Identifier)) {
574 					space();
575 					nextToken();
576 				}
577 
578 				break;
579 
580 			case With:
581 				parseWith();
582 				break;
583 
584 			case Switch:
585 				parseSwitch();
586 				break;
587 
588 			case Case:
589 				{
590 					auto guard = unindent();
591 					newline();
592 
593 					while (true) {
594 						nextToken();
595 						space();
596 
597 						parseList!parseExpression(TokenType.Colon);
598 
599 						if (!match(DotDot)) {
600 							break;
601 						}
602 
603 						space();
604 						nextToken();
605 						space();
606 					}
607 				}
608 
609 				parseColonBlock();
610 				break;
611 
612 			case Default:
613 				{
614 					auto guard = unindent();
615 					newline();
616 					nextToken();
617 				}
618 
619 				parseColonBlock();
620 				break;
621 
622 			case Goto:
623 				nextToken();
624 				if (match(Identifier) || match(Default)) {
625 					space();
626 					nextToken();
627 				} else if (match(Case)) {
628 					space();
629 					nextToken();
630 
631 					if (!match(Semicolon)) {
632 						space();
633 						parseExpression();
634 					}
635 				}
636 
637 				break;
638 
639 			case Try:
640 				parseTry();
641 				break;
642 
643 			case Catch:
644 				parseCatch();
645 				break;
646 
647 			case Finally:
648 				parseFinally();
649 				break;
650 
651 			case Scope:
652 				parseScope();
653 				break;
654 
655 			case Assert:
656 				parseExpression();
657 				break;
658 
659 			/**
660 			 * Compile time constructs.
661 			 */
662 			case Static:
663 				withCaseLevelIndent!parseStatic();
664 				break;
665 
666 			case Mixin:
667 				parseMixin();
668 				break;
669 
670 			/**
671 			 * Declaration
672 			 */
673 			case This:
674 				// This template parameters.
675 				auto lookahead = trange.getLookahead();
676 				lookahead.popFront();
677 
678 				auto t = lookahead.front.type;
679 				if (t == TokenType.Identifier) {
680 					nextToken();
681 					space();
682 					parseTypedDeclaration();
683 					break;
684 				}
685 
686 				if (t != TokenType.OpenParen || mode != Mode.Declaration) {
687 					// This is an expression.
688 					goto default;
689 				}
690 
691 				parseConstructor();
692 				break;
693 
694 			case Tilde:
695 				// Check for destructors.
696 				auto lookahead = trange.getLookahead();
697 				lookahead.popFront();
698 
699 				if (lookahead.front.type != TokenType.This) {
700 					// This is an expression.
701 					goto default;
702 				}
703 
704 				lookahead.popFront();
705 
706 				auto t = lookahead.front.type;
707 				if (t != TokenType.OpenParen || mode != Mode.Declaration) {
708 					// This is an expression.
709 					goto default;
710 				}
711 
712 				parseDestructor();
713 				break;
714 
715 			case Template:
716 				parseTemplate();
717 				break;
718 
719 			case Import:
720 				auto lookahead = trange.getLookahead();
721 				lookahead.popFront();
722 
723 				if (lookahead.front.type == TokenType.OpenParen) {
724 					// This is an import expression.
725 					goto default;
726 				}
727 
728 				parseImport();
729 				break;
730 
731 			case Unittest:
732 				nextToken();
733 				space();
734 
735 				if (match(Identifier)) {
736 					nextToken();
737 					space();
738 				}
739 
740 				parseBlock(Mode.Statement);
741 
742 				// Blocks do not end with a semicolon.
743 				return;
744 
745 			case Invariant:
746 				nextToken();
747 				parseArgumentList();
748 
749 				if (!match(OpenBrace)) {
750 					break;
751 				}
752 
753 				space();
754 				parseBlock(Mode.Statement);
755 
756 				// Blocks do not end with a semicolon.
757 				return;
758 
759 			case Struct, Union, Class, Interface:
760 				parseAggregate();
761 				break;
762 
763 			default:
764 				if (parseStorageClassDeclaration()) {
765 					break;
766 				}
767 
768 				if (!parseIdentifier()) {
769 					// We made no progress, start skipping.
770 					skipToken();
771 					return;
772 				}
773 
774 				if (match(Identifier)) {
775 					// We have a declaration.
776 					parseTypedDeclaration();
777 					break;
778 				}
779 
780 				// We just have some kind of expression.
781 				parseAssignExpressionSuffix();
782 				break;
783 		}
784 
785 		if (mode != Mode.Parameter) {
786 			if (match(TokenType.Semicolon)) {
787 				nextToken();
788 				newline();
789 			} else {
790 				emitSourceBasedWhiteSpace();
791 			}
792 		}
793 	}
794 
795 	/**
796 	 * Structural elements.
797 	 */
798 	void parseModuleDeclaration() in {
799 		assert(match(TokenType.Module));
800 	} do {
801 		nextToken();
802 		space();
803 		parseIdentifier();
804 	}
805 
806 	/**
807 	 * Identifiers
808 	 */
809 	enum IdentifierKind {
810 		None,
811 		Symbol,
812 		Type,
813 		Expression,
814 	}
815 
816 	bool parseIdentifier(IdentifierKind expected = IdentifierKind.Symbol) {
817 		flushComments();
818 		auto guard = span();
819 
820 		parseIdentifierPrefix();
821 
822 		auto kind = parseBaseIdentifier(expected);
823 		if (kind == IdentifierKind.None) {
824 			return false;
825 		}
826 
827 		kind = parseIdentifierSuffix(kind);
828 
829 		if (expected <= IdentifierKind.Symbol) {
830 			return true;
831 		}
832 
833 		// We expect something specific.
834 		while (kind == IdentifierKind.Symbol) {
835 			kind = parseIdentifierSuffix(expected);
836 		}
837 
838 		return true;
839 	}
840 
841 	void parseIdentifierPrefix() {
842 		while (true) {
843 			switch (token.type) with (TokenType) {
844 				// Prefixes.
845 				case Dot:
846 				case Ampersand:
847 				case PlusPlus:
848 				case MinusMinus:
849 				case Star:
850 				case Plus:
851 				case Minus:
852 				case Bang:
853 				case Tilde:
854 					nextToken();
855 					break;
856 
857 				case Cast:
858 					nextToken();
859 					if (match(OpenParen)) {
860 						nextToken();
861 						parseType();
862 						clearSeparator();
863 					}
864 
865 					runOnType!(CloseParen, nextToken)();
866 					space();
867 					split();
868 					break;
869 
870 				default:
871 					return;
872 			}
873 		}
874 	}
875 
876 	IdentifierKind parseBaseIdentifier(IdentifierKind kind) {
877 		switch (token.type) with (TokenType) {
878 			case Identifier:
879 				nextToken();
880 
881 				import source.parserutil;
882 				auto lookahead = trange.getLookahead();
883 				auto t = getStorageClassTokenType(lookahead);
884 
885 				if (t != EqualMore) {
886 					return kind;
887 				}
888 
889 				// Lambda expression
890 				parseStorageClasses(true);
891 				space();
892 				nextToken();
893 				space();
894 				split();
895 				parseExpression();
896 				return IdentifierKind.Expression;
897 
898 			// Litterals
899 			case This:
900 			case Super:
901 			case True:
902 			case False:
903 			case Null:
904 			case IntegerLiteral:
905 			case FloatLiteral:
906 			case StringLiteral:
907 			case CharacterLiteral:
908 			case __File__:
909 			case __Line__:
910 			case Dollar:
911 				nextToken();
912 				return IdentifierKind.Expression;
913 
914 			case __Traits:
915 				nextToken();
916 				parseArgumentList();
917 				return IdentifierKind.Symbol;
918 
919 			case Assert, Import:
920 				nextToken();
921 				parseArgumentList();
922 				return IdentifierKind.Expression;
923 
924 			case Throw:
925 				parseReturn();
926 				return IdentifierKind.Expression;
927 
928 			case New:
929 				nextToken();
930 				space();
931 
932 				if (!match(Class)) {
933 					parseType();
934 					parseArgumentList();
935 					return IdentifierKind.Expression;
936 				}
937 
938 				// Ok new class.
939 				nextToken();
940 				parseArgumentList();
941 				space();
942 				parseIdentifier();
943 				space();
944 				parseInlineBlock(Mode.Declaration);
945 
946 				return IdentifierKind.Expression;
947 
948 			case Is:
949 				parseIsExpression();
950 				return IdentifierKind.Expression;
951 
952 			case OpenParen: {
953 				import source.parserutil;
954 				auto lookahead = trange.getLookahead();
955 				lookahead.popMatchingDelimiter!OpenParen();
956 
957 				auto t = getStorageClassTokenType(lookahead);
958 				if (t != OpenBrace && t != EqualMore && t != At && t != Nothrow
959 					    && t != Pure && t != Ref && t != Synchronized) {
960 					// Not a lambda.
961 					goto ParenIdentifier;
962 				}
963 
964 				// We have a lambda.
965 				goto LambdaWithParameters;
966 			}
967 
968 			ParenIdentifier:
969 				auto guard = span();
970 				nextToken();
971 
972 				// FIXME: Customize the list parsed based on kind.
973 				parseExpression();
974 
975 				runOnType!(CloseParen, nextToken)();
976 				return kind;
977 
978 			case OpenBrace: {
979 				// Try to detect if it is a struct literal or a parameterless lambda.
980 				import source.parserutil;
981 				auto lookahead = trange.getLookahead();
982 
983 				lookahead.popFront();
984 				if (lookahead.front.type != Identifier) {
985 					goto Lambda;
986 				}
987 
988 				lookahead.popFront();
989 				if (lookahead.front.type != Colon) {
990 					goto Lambda;
991 				}
992 
993 				// We may still have a lambda starting with a labeled statement,
994 				// so we go on the hunt for a semicolon.
995 				lookahead.popFront();
996 				while (true) {
997 					switch (lookahead.front.type) {
998 						case CloseBrace:
999 							goto StructLiteral;
1000 
1001 						case Semicolon:
1002 							goto Lambda;
1003 
1004 						case End:
1005 							// This is malformed, assume literal.
1006 							goto StructLiteral;
1007 
1008 						case OpenParen:
1009 							lookahead.popMatchingDelimiter!OpenParen();
1010 							break;
1011 
1012 						case OpenBrace:
1013 							lookahead.popMatchingDelimiter!OpenBrace();
1014 							break;
1015 
1016 						case OpenBracket:
1017 							lookahead.popMatchingDelimiter!OpenBracket();
1018 							break;
1019 
1020 						default:
1021 							lookahead.popFront();
1022 					}
1023 				}
1024 			}
1025 
1026 			StructLiteral:
1027 				parseStructLiteral();
1028 				return IdentifierKind.Expression;
1029 
1030 			case Function, Delegate:
1031 				nextToken();
1032 				if (!match(OpenParen) && !match(OpenBrace)) {
1033 					// We have an explicit type.
1034 					expectParameters = true;
1035 					scope(success) expectParameters = false;
1036 
1037 					space();
1038 					parseType();
1039 				}
1040 
1041 				goto LambdaWithParameters;
1042 
1043 			LambdaWithParameters:
1044 				parseParameterList();
1045 				space();
1046 				parseStorageClasses(true);
1047 				goto Lambda;
1048 
1049 			Lambda:
1050 				if (parseInlineBlock(Mode.Statement)) {
1051 					return IdentifierKind.Expression;
1052 				}
1053 
1054 				if (match(EqualMore)) {
1055 					nextToken();
1056 					space();
1057 					split();
1058 					parseExpression();
1059 				}
1060 
1061 				return IdentifierKind.Expression;
1062 
1063 			case OpenBracket:
1064 				parseArrayLiteral();
1065 				return IdentifierKind.Expression;
1066 
1067 			case Typeid:
1068 				nextToken();
1069 				parseArgumentList();
1070 				return IdentifierKind.Expression;
1071 
1072 			case Mixin:
1073 				parseMixin();
1074 
1075 				// Assume it is an expression. Technically, it could be a declaration,
1076 				// but it does change anything from a formatting perspective.
1077 				return IdentifierKind.Expression;
1078 
1079 			// Types
1080 			case Typeof:
1081 				nextToken();
1082 				if (!match(OpenParen)) {
1083 					return IdentifierKind.Type;
1084 				}
1085 
1086 				auto lookahead = trange.getLookahead();
1087 				lookahead.popFront();
1088 
1089 				if (lookahead.front.type == Return) {
1090 					nextToken();
1091 					nextToken();
1092 					nextToken();
1093 				} else {
1094 					parseArgumentList();
1095 				}
1096 
1097 				return IdentifierKind.Type;
1098 
1099 			case Bool:
1100 			case Byte, Ubyte:
1101 			case Short, Ushort:
1102 			case Int, Uint:
1103 			case Long, Ulong:
1104 			case Cent, Ucent:
1105 			case Char, Wchar, Dchar:
1106 			case Float, Double, Real:
1107 			case Void:
1108 				nextToken();
1109 				return IdentifierKind.Type;
1110 
1111 			// Type qualifiers
1112 			case Const, Immutable, Inout, Shared:
1113 				nextToken();
1114 				if (!match(OpenParen)) {
1115 					space();
1116 					return parseBaseIdentifier(kind);
1117 				}
1118 
1119 				nextToken();
1120 				parseType();
1121 				runOnType!(CloseParen, nextToken)();
1122 				return IdentifierKind.Type;
1123 
1124 			default:
1125 				return IdentifierKind.None;
1126 		}
1127 	}
1128 
1129 	IdentifierKind parseIdentifierSuffix(IdentifierKind kind) {
1130 		const tryDeclaration = canBeDeclaration;
1131 		const skipParentheses = expectParameters;
1132 		canBeDeclaration = false;
1133 		expectParameters = false;
1134 
1135 		kind =
1136 			parseNonDotIdentifierSuffix(kind, tryDeclaration, skipParentheses);
1137 		if (!match(TokenType.Dot)) {
1138 			return kind;
1139 		}
1140 
1141 		auto guard = spliceSpan!ExpandingListSpan();
1142 		while (match(TokenType.Dot)) {
1143 			split();
1144 			guard.registerFix(function(ExpandingListSpan s, size_t i) {
1145 				s.registerElement(i);
1146 			});
1147 
1148 			nextToken();
1149 
1150 			if (!match(TokenType.Identifier)) {
1151 				return IdentifierKind.None;
1152 			}
1153 
1154 			kind = IdentifierKind.Symbol;
1155 			nextToken();
1156 
1157 			kind = parseNonDotIdentifierSuffix(kind, tryDeclaration,
1158 			                                   skipParentheses);
1159 		}
1160 
1161 		return kind;
1162 	}
1163 
1164 	IdentifierKind parseNonDotIdentifierSuffix(
1165 		IdentifierKind kind,
1166 		bool tryDeclaration,
1167 		bool skipParentheses,
1168 	) {
1169 		while (true) {
1170 			switch (token.type) with (TokenType) {
1171 				case Star:
1172 					final switch (kind) with (IdentifierKind) {
1173 						case Type:
1174 							// This is a pointer.
1175 							nextToken();
1176 							continue;
1177 
1178 						case Expression:
1179 							// This is a multiplication.
1180 							return IdentifierKind.Expression;
1181 
1182 						case Symbol:
1183 							// This could be either. Use lookahead.
1184 							break;
1185 
1186 						case None:
1187 							assert(0);
1188 					}
1189 
1190 					auto lookahead = trange.getLookahead();
1191 					lookahead.popFront();
1192 
1193 					IdentifierStarLookahead: while (true) {
1194 						switch (lookahead.front.type) {
1195 							case Identifier:
1196 								// Lean toward Indentifier* Identifier being a delcaration.
1197 								if (tryDeclaration) {
1198 									goto IdentifierStarType;
1199 								}
1200 
1201 								goto IdentifierStarExpression;
1202 
1203 							case Comma, CloseParen, CloseBracket:
1204 								// This indicates some kind of termination, so assume a type.
1205 								goto IdentifierStarType;
1206 
1207 							case Star, Function, Delegate:
1208 								goto IdentifierStarType;
1209 
1210 							IdentifierStarType:
1211 								kind = IdentifierKind.Type;
1212 								nextToken();
1213 								break IdentifierStarLookahead;
1214 
1215 							case This:
1216 							case Super:
1217 							case True:
1218 							case False:
1219 							case Null:
1220 							case IntegerLiteral:
1221 							case FloatLiteral:
1222 							case StringLiteral:
1223 							case CharacterLiteral:
1224 							case __File__:
1225 							case __Line__:
1226 							case Dollar:
1227 								goto IdentifierStarExpression;
1228 
1229 							IdentifierStarExpression:
1230 								return IdentifierKind.Expression;
1231 
1232 							case OpenBracket:
1233 								import source.parserutil;
1234 								lookahead.popMatchingDelimiter!OpenBracket();
1235 								continue;
1236 
1237 							default:
1238 								// No idea what this is, move on.
1239 								return IdentifierKind.Symbol;
1240 						}
1241 					}
1242 
1243 					break;
1244 
1245 				case Function, Delegate:
1246 					kind = IdentifierKind.Type;
1247 					space();
1248 					nextToken();
1249 					parseParameterList();
1250 					space();
1251 					if (!parseStorageClasses(true)) {
1252 						// Not sure how this will fare in the presence of comments,
1253 						// but this will have to do for now.
1254 						clearSeparator();
1255 					}
1256 
1257 					break;
1258 
1259 				case Bang:
1260 					if (isBangIsOrIn()) {
1261 						// This is a binary expression.
1262 						return IdentifierKind.Expression;
1263 					}
1264 
1265 					// Template instance.
1266 					kind = IdentifierKind.Symbol;
1267 					nextToken();
1268 					if (!parseAliasList()) {
1269 						parseBaseIdentifier(IdentifierKind.Symbol);
1270 					}
1271 
1272 					break;
1273 
1274 				case PlusPlus, MinusMinus:
1275 					kind = IdentifierKind.Expression;
1276 					nextToken();
1277 					break;
1278 
1279 				case OpenParen:
1280 					if (skipParentheses) {
1281 						return kind;
1282 					}
1283 
1284 					// FIXME: customize based on kind.
1285 					kind = IdentifierKind.Expression;
1286 					parseArgumentList();
1287 					break;
1288 
1289 				case OpenBracket:
1290 					// FIXME: customize based on kind.
1291 					// Technically, this is not an array literal,
1292 					// but this should do for now.
1293 					parseArrayLiteral();
1294 					break;
1295 
1296 				default:
1297 					return kind;
1298 			}
1299 		}
1300 
1301 		assert(0, "DMD is not smart enough to figure out this is unreachable.");
1302 	}
1303 
1304 	bool parseMixin() {
1305 		if (!match(TokenType.Mixin)) {
1306 			return false;
1307 		}
1308 
1309 		nextToken();
1310 
1311 		switch (token.type) with (TokenType) {
1312 			case Template:
1313 				space();
1314 				parseTemplate();
1315 				break;
1316 
1317 			case OpenParen:
1318 				parseArgumentList();
1319 				break;
1320 
1321 			default:
1322 				space();
1323 				parseIdentifier();
1324 
1325 				if (match(Identifier)) {
1326 					space();
1327 					nextToken();
1328 				}
1329 
1330 				break;
1331 		}
1332 
1333 		return true;
1334 	}
1335 
1336 	/**
1337 	 * Statements
1338 	 */
1339 	bool parseEmptyBlock() {
1340 		if (!match(TokenType.CloseBrace) && !match(TokenType.End)) {
1341 			return false;
1342 		}
1343 
1344 		{
1345 			// Flush comments so that they have the proper indentation.
1346 			auto guard = indent();
1347 			flushComments();
1348 		}
1349 
1350 		nextToken();
1351 		return true;
1352 	}
1353 
1354 	bool parseInlineBlock(Mode m) {
1355 		auto oldNeedDoubleIndent = needDoubleIndent;
1356 		scope(exit) {
1357 			needDoubleIndent = oldNeedDoubleIndent;
1358 		}
1359 
1360 		needDoubleIndent = false;
1361 		if (parseBlock(m)) {
1362 			clearSeparator();
1363 			return true;
1364 		}
1365 
1366 		return false;
1367 	}
1368 
1369 	bool parseBlock(alias fun = parseBlockContent, T...)(T args) {
1370 		if (!match(TokenType.OpenBrace)) {
1371 			return false;
1372 		}
1373 
1374 		nextToken();
1375 		if (parseEmptyBlock()) {
1376 			newline(mode == Mode.Declaration ? 2 : 1);
1377 			return true;
1378 		}
1379 
1380 		{
1381 			// We have an actual block.
1382 			clearSeparator();
1383 			newline(1);
1384 
1385 			auto blockGuard = block();
1386 			fun(args);
1387 		}
1388 
1389 		if (match(TokenType.CloseBrace)) {
1390 			nextToken();
1391 			newline(2);
1392 		}
1393 
1394 		return true;
1395 	}
1396 
1397 	void parseBlockContent(Mode m) {
1398 		auto indentGuard = indent(1 + needDoubleIndent);
1399 		auto modeGuard = changeMode(m);
1400 
1401 		auto oldNeedDoubleIndent = needDoubleIndent;
1402 		auto oldDoubleIndentBlock = doubleIndentBlock;
1403 		scope(exit) {
1404 			needDoubleIndent = oldNeedDoubleIndent;
1405 			doubleIndentBlock = oldDoubleIndentBlock;
1406 		}
1407 
1408 		doubleIndentBlock = needDoubleIndent;
1409 		needDoubleIndent = false;
1410 
1411 		split();
1412 
1413 		while (!match(TokenType.CloseBrace) && !match(TokenType.End)) {
1414 			parseStructuralElement();
1415 		}
1416 
1417 		// Flush comments so that they have the proper indentation.
1418 		flushComments();
1419 	}
1420 
1421 	static isBasicBlockEntry(ref TokenRange r) {
1422 		auto t = r.front.type;
1423 		if (t == TokenType.Case || t == TokenType.Default) {
1424 			return true;
1425 		}
1426 
1427 		if (t != TokenType.Identifier) {
1428 			return false;
1429 		}
1430 
1431 		// Check for labeled statements.
1432 		r.popFront();
1433 		return r.front.type == TokenType.Colon;
1434 	}
1435 
1436 	static isBasicBlockTerminator(TokenType t) {
1437 		return t == TokenType.CloseBrace || t == TokenType.Return
1438 			|| t == TokenType.Break || t == TokenType.Continue
1439 			|| t == TokenType.Goto || t == TokenType.Throw;
1440 	}
1441 
1442 	static isBasicBlockBoundary(ref TokenRange r) {
1443 		return isBasicBlockTerminator(r.front.type) || isBasicBlockEntry(r);
1444 	}
1445 
1446 	void parseColonBlock() {
1447 		runOnType!(TokenType.Colon, nextToken)();
1448 
1449 		if (match(TokenType.CloseBrace)) {
1450 			// Empty colon block.
1451 			return;
1452 		}
1453 
1454 		if (!match(TokenType.OpenBrace)) {
1455 			newline();
1456 			parseStructuralElement();
1457 			return;
1458 		}
1459 
1460 		import source.parserutil;
1461 		auto lookahead = trange.getLookahead();
1462 		lookahead.popMatchingDelimiter!(TokenType.OpenBrace)();
1463 		if (!isBasicBlockBoundary(lookahead)) {
1464 			newline(1);
1465 			return;
1466 		}
1467 
1468 		auto guard = unindent();
1469 		space();
1470 		parseBlock(mode);
1471 	}
1472 
1473 	bool parseControlFlowBlock(bool forceNewLine = true) {
1474 		if (parseBlock(mode)) {
1475 			return true;
1476 		}
1477 
1478 		auto guard = span();
1479 
1480 		// Carry indentation just like blocks.
1481 		auto indentGuard = indent(needDoubleIndent);
1482 
1483 		auto oldNeedDoubleIndent = needDoubleIndent;
1484 		auto oldDoubleIndentBlock = doubleIndentBlock;
1485 		scope(exit) {
1486 			needDoubleIndent = oldNeedDoubleIndent;
1487 			doubleIndentBlock = oldDoubleIndentBlock;
1488 		}
1489 
1490 		doubleIndentBlock = needDoubleIndent;
1491 		needDoubleIndent = false;
1492 
1493 		if (forceNewLine) {
1494 			newline(1);
1495 		} else {
1496 			space();
1497 		}
1498 
1499 		split();
1500 		parseStructuralElement();
1501 		return false;
1502 	}
1503 
1504 	void emitPostControlFlowWhitespace(bool isBlock) {
1505 		flushComments();
1506 		clearSeparator();
1507 		if (isBlock) {
1508 			space();
1509 		} else {
1510 			newline(1);
1511 		}
1512 	}
1513 
1514 	void parseElsableBlock() {
1515 		if (match(TokenType.Colon)) {
1516 			parseColonBlock();
1517 			return;
1518 		}
1519 
1520 		space();
1521 
1522 		bool isBlock = parseControlFlowBlock();
1523 		if (!match(TokenType.Else)) {
1524 			return;
1525 		}
1526 
1527 		emitPostControlFlowWhitespace(isBlock);
1528 		parseElse();
1529 	}
1530 
1531 	void parseCondition(bool glued = false) {
1532 		if (!match(TokenType.OpenParen)) {
1533 			return;
1534 		}
1535 
1536 		nextToken();
1537 
1538 		auto guard = span!AlignedSpan();
1539 		split(glued);
1540 
1541 		guard.registerFix(function(AlignedSpan s, size_t i) {
1542 			s.alignOn(i);
1543 		});
1544 
1545 		auto modeGuard = changeMode(Mode.Parameter);
1546 
1547 		parseStructuralElement();
1548 		runOnType!(TokenType.CloseParen, nextToken)();
1549 	}
1550 
1551 	void parseIf() in {
1552 		assert(match(TokenType.If));
1553 	} do {
1554 		nextToken();
1555 		space();
1556 
1557 		parseCondition();
1558 		parseElsableBlock();
1559 	}
1560 
1561 	void parseVersion() in {
1562 		assert(match(TokenType.Version) || match(TokenType.Debug));
1563 	} do {
1564 		nextToken();
1565 
1566 		if (match(TokenType.OpenParen)) {
1567 			space();
1568 			nextToken();
1569 
1570 			if (match(TokenType.Identifier) || match(TokenType.Unittest)) {
1571 				nextToken();
1572 			}
1573 
1574 			runOnType!(TokenType.CloseParen, nextToken)();
1575 		}
1576 
1577 		parseElsableBlock();
1578 	}
1579 
1580 	void parseElse() in {
1581 		assert(match(TokenType.Else));
1582 	} do {
1583 		space();
1584 		nextToken();
1585 		space();
1586 
1587 		switch (token.type) with (TokenType) {
1588 			case If:
1589 				parseIf();
1590 				break;
1591 
1592 			case Version, Debug:
1593 				parseVersion();
1594 				break;
1595 
1596 			case While:
1597 				parseWhile();
1598 				break;
1599 
1600 			case Do:
1601 				parseDoWhile();
1602 				break;
1603 
1604 			case For:
1605 				parseFor();
1606 				break;
1607 
1608 			case Foreach, ForeachReverse:
1609 				parseForeach();
1610 				break;
1611 
1612 			case Static:
1613 				auto lookahead = trange.getLookahead();
1614 				lookahead.popFront();
1615 
1616 				auto t = lookahead.front.type;
1617 				if (t == If || t == Foreach || t == ForeachReverse) {
1618 					parseStatic();
1619 					break;
1620 				}
1621 
1622 				goto default;
1623 
1624 			default:
1625 				parseControlFlowBlock();
1626 				break;
1627 		}
1628 	}
1629 
1630 	void parseWhile() in {
1631 		assert(match(TokenType.While));
1632 	} do {
1633 		nextToken();
1634 		space();
1635 
1636 		parseCondition();
1637 
1638 		space();
1639 		parseControlFlowBlock();
1640 	}
1641 
1642 	void parseDoWhile() in {
1643 		assert(match(TokenType.Do));
1644 	} do {
1645 		nextToken();
1646 		space();
1647 		bool isBlock = parseControlFlowBlock();
1648 
1649 		if (!match(TokenType.While)) {
1650 			return;
1651 		}
1652 
1653 		emitPostControlFlowWhitespace(isBlock);
1654 		nextToken();
1655 
1656 		space();
1657 		parseCondition();
1658 
1659 		runOnType!(TokenType.Semicolon, nextToken)();
1660 		newline(2);
1661 	}
1662 
1663 	void parseFor() in {
1664 		assert(match(TokenType.For));
1665 	} do {
1666 		nextToken();
1667 		space();
1668 
1669 		if (match(TokenType.OpenParen)) {
1670 			nextToken();
1671 			parseForArguments();
1672 			runOnType!(TokenType.CloseParen, nextToken)();
1673 		}
1674 
1675 		space();
1676 		parseControlFlowBlock();
1677 	}
1678 
1679 	void parseForArguments() {
1680 		auto guard = span!CompactListSpan();
1681 
1682 		if (match(TokenType.Semicolon)) {
1683 			nextToken();
1684 		} else {
1685 			split();
1686 			guard.registerFix(function(CompactListSpan s, size_t i) {
1687 				s.registerElement(i);
1688 			});
1689 
1690 			parseStructuralElement();
1691 			clearSeparator();
1692 		}
1693 
1694 		if (match(TokenType.Semicolon)) {
1695 			nextToken();
1696 		} else {
1697 			space();
1698 			split();
1699 			guard.registerFix(function(CompactListSpan s, size_t i) {
1700 				s.registerElement(i);
1701 			});
1702 
1703 			parseCommaExpression();
1704 			runOnType!(TokenType.Semicolon, nextToken)();
1705 		}
1706 
1707 		if (match(TokenType.CloseParen)) {
1708 			nextToken();
1709 		} else {
1710 			space();
1711 			split();
1712 			guard.registerFix(function(CompactListSpan s, size_t i) {
1713 				s.registerElement(i);
1714 			});
1715 
1716 			parseCommaExpression();
1717 		}
1718 	}
1719 
1720 	void parseForeach() in {
1721 		assert(match(TokenType.Foreach) || match(TokenType.ForeachReverse));
1722 	} do {
1723 		nextToken();
1724 		space();
1725 
1726 		if (match(TokenType.OpenParen)) {
1727 			nextToken();
1728 			auto modeGuard = changeMode(Mode.Parameter);
1729 			auto listGuard = span!CompactListSpan();
1730 
1731 			split();
1732 			listGuard.registerFix(function(CompactListSpan s, size_t i) {
1733 				s.registerElement(i);
1734 			});
1735 
1736 			parseList!parseStructuralElement(TokenType.Semicolon);
1737 
1738 			split();
1739 			listGuard.registerFix(function(CompactListSpan s, size_t i) {
1740 				s.registerElement(i);
1741 			});
1742 
1743 			space();
1744 			parseList!parseArrayElement(TokenType.CloseParen);
1745 		}
1746 
1747 		space();
1748 		parseControlFlowBlock();
1749 	}
1750 
1751 	void parseReturn() in {
1752 		assert(match(TokenType.Return) || match(TokenType.Throw));
1753 	} do {
1754 		nextToken();
1755 		if (token.type == TokenType.Semicolon) {
1756 			nextToken();
1757 			return;
1758 		}
1759 
1760 		auto guard = span();
1761 
1762 		space();
1763 		split();
1764 
1765 		parseExpression();
1766 	}
1767 
1768 	void parseWith() in {
1769 		assert(match(TokenType.With));
1770 	} do {
1771 		nextToken();
1772 		space();
1773 
1774 		parseCondition();
1775 		space();
1776 
1777 		parseStructuralElement();
1778 	}
1779 
1780 	void parseSwitch() in {
1781 		assert(match(TokenType.Switch));
1782 	} do {
1783 		nextToken();
1784 		space();
1785 
1786 		parseCondition();
1787 		space();
1788 		split();
1789 
1790 		// Request the next nested block to be double indented.
1791 		auto oldNeedDoubleIndent = needDoubleIndent;
1792 		scope(exit) {
1793 			needDoubleIndent = oldNeedDoubleIndent;
1794 		}
1795 
1796 		needDoubleIndent = true;
1797 		parseStructuralElement();
1798 	}
1799 
1800 	auto withCaseLevelIndent(alias fun)() {
1801 		// There is nothing special to do in this case, just move on.
1802 		if (!isCaseLevelStatement()) {
1803 			return fun();
1804 		}
1805 
1806 		// Request the next nested block to be double indented.
1807 		auto oldNeedDoubleIndent = needDoubleIndent;
1808 		scope(exit) {
1809 			needDoubleIndent = oldNeedDoubleIndent;
1810 		}
1811 
1812 		needDoubleIndent = true;
1813 
1814 		auto guard = unindent();
1815 		split();
1816 
1817 		return fun();
1818 	}
1819 
1820 	bool isCaseLevelStatement() {
1821 		if (!doubleIndentBlock) {
1822 			// No case level statement if we are not in
1823 			// switch style block.
1824 			return false;
1825 		}
1826 
1827 		static void skip(ref TokenRange r) {
1828 			while (true) {
1829 				switch (r.front.type) with (TokenType) {
1830 					case CloseBrace, End:
1831 						return;
1832 
1833 					case Semicolon:
1834 						r.popFront();
1835 						return;
1836 
1837 					case OpenBrace:
1838 						import source.parserutil;
1839 						r.popMatchingDelimiter!OpenBrace();
1840 						return;
1841 
1842 					case OpenParen:
1843 						// Make sure we don't stop on `for (;;)`
1844 						// so skip over parentheses.
1845 						import source.parserutil;
1846 						r.popMatchingDelimiter!OpenParen();
1847 						continue;
1848 
1849 					default:
1850 						r.popFront();
1851 						continue;
1852 				}
1853 			}
1854 		}
1855 
1856 		static bool isCaseBlock()(ref TokenRange r) {
1857 			if (r.front.type != TokenType.OpenBrace) {
1858 				return containsCase(r);
1859 			}
1860 
1861 			r.popFront();
1862 			while (r.front.type != TokenType.End) {
1863 				if (containsCase(r)) {
1864 					return true;
1865 				}
1866 
1867 				if (r.front.type == TokenType.CloseBrace) {
1868 					r.popFront();
1869 					break;
1870 				}
1871 			}
1872 
1873 			return false;
1874 		}
1875 
1876 		static bool containsCase(ref TokenRange r, bool doSkip = true) {
1877 			// Pop labels.
1878 			while (r.front.type == TokenType.Identifier) {
1879 				r.popFront();
1880 				if (r.front.type != TokenType.Colon) {
1881 					goto Skip;
1882 				}
1883 
1884 				r.popFront();
1885 			}
1886 
1887 			switch (r.front.type) with (TokenType) {
1888 				case Case, Default:
1889 					return true;
1890 
1891 				case Static:
1892 					r.popFront();
1893 
1894 					auto t = r.front.type;
1895 					if (t == If || t == Foreach || t == ForeachReverse) {
1896 						goto CheckBlock;
1897 					}
1898 
1899 					break;
1900 
1901 				case Foreach, ForeachReverse:
1902 					goto CheckBlock;
1903 
1904 				CheckBlock:
1905 					// As far as we are concenred here, foreach and
1906 					// static if have the same syntax.
1907 					r.popFront();
1908 					if (r.front.type == OpenParen) {
1909 						import source.parserutil;
1910 						r.popMatchingDelimiter!OpenParen();
1911 					}
1912 
1913 					return isCaseBlock(r);
1914 
1915 				default:
1916 					break;
1917 			}
1918 
1919 		Skip:
1920 			if (doSkip) {
1921 				skip(r);
1922 			}
1923 
1924 			return false;
1925 		}
1926 
1927 		auto lookahead = trange.getLookahead();
1928 		return containsCase(lookahead, false);
1929 	}
1930 
1931 	void parseTry() in {
1932 		assert(match(TokenType.Try));
1933 	} do {
1934 		nextToken();
1935 		space();
1936 		bool isBlock = parseControlFlowBlock();
1937 
1938 		while (true) {
1939 			while (match(TokenType.Catch)) {
1940 				emitPostControlFlowWhitespace(isBlock);
1941 				isBlock = parseCatch();
1942 			}
1943 
1944 			if (!match(TokenType.Finally)) {
1945 				break;
1946 			}
1947 
1948 			emitPostControlFlowWhitespace(isBlock);
1949 			isBlock = parseFinally();
1950 		}
1951 	}
1952 
1953 	bool parseCatch() in {
1954 		assert(match(TokenType.Catch));
1955 	} do {
1956 		nextToken();
1957 		space();
1958 		parseParameterList();
1959 		space();
1960 		return parseControlFlowBlock();
1961 	}
1962 
1963 	bool parseFinally() in {
1964 		assert(match(TokenType.Finally));
1965 	} do {
1966 		nextToken();
1967 		space();
1968 		return parseControlFlowBlock();
1969 	}
1970 
1971 	void parseScope() in {
1972 		assert(match(TokenType.Scope));
1973 	} do {
1974 		auto lookahead = trange.getLookahead();
1975 		lookahead.popFront();
1976 
1977 		if (lookahead.front.type != TokenType.OpenParen) {
1978 			parseStorageClassDeclaration();
1979 			return;
1980 		}
1981 
1982 		nextToken();
1983 		parseArgumentList();
1984 
1985 		space();
1986 		parseControlFlowBlock(false);
1987 	}
1988 
1989 	/**
1990 	 * Types
1991 	 */
1992 	bool parseType() {
1993 		return parseIdentifier(IdentifierKind.Type);
1994 	}
1995 
1996 	/**
1997 	 * Expressions
1998 	 */
1999 	void parseExpression() {
2000 		canBeDeclaration = false;
2001 		parseBaseExpression();
2002 		parseAssignExpressionSuffix();
2003 	}
2004 
2005 	bool parseBaseExpression() {
2006 		return parseIdentifier(IdentifierKind.Expression);
2007 	}
2008 
2009 	void parseCommaExpression() {
2010 		parseBaseExpression();
2011 		parseCommaExpressionSuffix();
2012 	}
2013 
2014 	void parseCommaExpressionSuffix() {
2015 		parseAssignExpressionSuffix();
2016 
2017 		if (!match(TokenType.Comma)) {
2018 			return;
2019 		}
2020 
2021 		auto guard = spliceSpan();
2022 		do {
2023 			nextToken();
2024 			split();
2025 			space();
2026 
2027 			parseExpression();
2028 		} while (match(TokenType.Comma));
2029 	}
2030 
2031 	void parseAssignExpressionSuffix() {
2032 		parseConditionalExpressionSuffix();
2033 
2034 		static bool isAssignExpression(TokenType t) {
2035 			return t == TokenType.Equal || t == TokenType.PlusEqual
2036 				|| t == TokenType.MinusEqual || t == TokenType.StarEqual
2037 				|| t == TokenType.SlashEqual || t == TokenType.PercentEqual
2038 				|| t == TokenType.AmpersandEqual || t == TokenType.PipeEqual
2039 				|| t == TokenType.CaretEqual || t == TokenType.TildeEqual
2040 				|| t == TokenType.LessLessEqual || t == TokenType.MoreMoreEqual
2041 				|| t == TokenType.MoreMoreMoreEqual
2042 				|| t == TokenType.CaretCaretEqual;
2043 		}
2044 
2045 		if (!isAssignExpression(token.type)) {
2046 			return;
2047 		}
2048 
2049 		auto guard = spliceSpan();
2050 		do {
2051 			space();
2052 			nextToken();
2053 			split();
2054 			space();
2055 
2056 			parseBaseExpression();
2057 			parseConditionalExpressionSuffix();
2058 		} while (isAssignExpression(token.type));
2059 	}
2060 
2061 	void parseConditionalExpressionSuffix() {
2062 		parseBinaryExpressionSuffix();
2063 
2064 		if (!match(TokenType.QuestionMark)) {
2065 			return;
2066 		}
2067 
2068 		auto guard = spliceSpan!ConditionalSpan();
2069 
2070 		space();
2071 		split();
2072 
2073 		guard.registerFix(function(ConditionalSpan s, size_t i) {
2074 			s.setQuestionMarkIndex(i);
2075 		});
2076 
2077 		nextToken();
2078 		space();
2079 
2080 		parseExpression();
2081 
2082 		space();
2083 		split();
2084 
2085 		runOnType!(TokenType.Comma, nextToken)();
2086 		guard.registerFix(function(ConditionalSpan s, size_t i) {
2087 			s.setColonIndex(i);
2088 		});
2089 
2090 		nextToken();
2091 		space();
2092 
2093 		parseBaseExpression();
2094 		parseConditionalExpressionSuffix();
2095 	}
2096 
2097 	bool isBangIsOrIn() in {
2098 		assert(match(TokenType.Bang));
2099 	} do {
2100 		auto lookahead = trange.getLookahead();
2101 		lookahead.popFront();
2102 		auto t = lookahead.front.type;
2103 		return t == TokenType.Is || t == TokenType.In;
2104 	}
2105 
2106 	uint getPrecedence() {
2107 		switch (token.type) with (TokenType) {
2108 			case PipePipe:
2109 				return 1;
2110 
2111 			case AmpersandAmpersand:
2112 				return 2;
2113 
2114 			case Pipe:
2115 				return 3;
2116 
2117 			case Caret:
2118 				return 4;
2119 
2120 			case Ampersand:
2121 				return 5;
2122 
2123 			case Is:
2124 			case In:
2125 				return 6;
2126 
2127 			case Bang:
2128 				return isBangIsOrIn() ? 6 : 0;
2129 
2130 			case EqualEqual:
2131 			case BangEqual:
2132 				return 6;
2133 
2134 			case More:
2135 			case MoreEqual:
2136 			case Less:
2137 			case LessEqual:
2138 				return 6;
2139 
2140 			case LessLess:
2141 			case MoreMore:
2142 			case MoreMoreMore:
2143 				return 7;
2144 
2145 			case BangLessMoreEqual:
2146 			case BangLessMore:
2147 			case LessMore:
2148 			case LessMoreEqual:
2149 			case BangMore:
2150 			case BangMoreEqual:
2151 			case BangLess:
2152 			case BangLessEqual:
2153 				return 7;
2154 
2155 			case Plus:
2156 			case Minus:
2157 				return 8;
2158 
2159 			case Slash:
2160 			case Star:
2161 			case Percent:
2162 				return 9;
2163 
2164 			case Tilde:
2165 				return 10;
2166 
2167 			default:
2168 				return 0;
2169 		}
2170 	}
2171 
2172 	void parseBinaryExpressionSuffix(uint minPrecedence = 0) {
2173 		auto currentPrecedence = getPrecedence();
2174 
2175 		while (currentPrecedence > minPrecedence) {
2176 			auto previousPrecedence = currentPrecedence;
2177 			auto guard = spliceSpan();
2178 
2179 			while (previousPrecedence == currentPrecedence) {
2180 				scope(success) {
2181 					currentPrecedence = getPrecedence();
2182 					if (currentPrecedence > previousPrecedence) {
2183 						parseBinaryExpressionSuffix(previousPrecedence);
2184 						currentPrecedence = getPrecedence();
2185 					}
2186 
2187 					assert(currentPrecedence <= previousPrecedence);
2188 				}
2189 
2190 				space();
2191 				split();
2192 				if (match(TokenType.Bang)) {
2193 					nextToken();
2194 				}
2195 
2196 				nextToken();
2197 				space();
2198 
2199 				parseBaseExpression();
2200 			}
2201 		}
2202 	}
2203 
2204 	bool parseArgumentList() {
2205 		if (!match(TokenType.OpenParen)) {
2206 			return false;
2207 		}
2208 
2209 		nextToken();
2210 		parseList!parseExpression(TokenType.CloseParen);
2211 		return true;
2212 	}
2213 
2214 	void parseArrayLiteral() {
2215 		if (!match(TokenType.OpenBracket)) {
2216 			return;
2217 		}
2218 
2219 		nextToken();
2220 		parseList!parseArrayElement(TokenType.CloseBracket);
2221 	}
2222 
2223 	void parseArrayElement() {
2224 		parseExpression();
2225 
2226 		switch (token.type) with (TokenType) {
2227 			case Colon: {
2228 				auto guard = spliceSpan();
2229 				space();
2230 				nextToken();
2231 				space();
2232 				split();
2233 				parseExpression();
2234 				break;
2235 			}
2236 
2237 			case DotDot: {
2238 				auto guard = spliceSpan();
2239 				space();
2240 				split();
2241 				nextToken();
2242 				space();
2243 				parseExpression();
2244 				break;
2245 			}
2246 
2247 			default:
2248 				break;
2249 		}
2250 	}
2251 
2252 	void parseIsExpression() in {
2253 		assert(match(TokenType.Is));
2254 	} do {
2255 		auto modeGuard = changeMode(Mode.Parameter);
2256 		nextToken();
2257 		runOnType!(TokenType.OpenParen, nextToken)();
2258 		parseList!parseIsElement(TokenType.CloseParen);
2259 	}
2260 
2261 	void parseIsElement(size_t i) {
2262 		if (i == 0) {
2263 			parseIsSpecialization();
2264 		} else {
2265 			parseStructuralElement();
2266 		}
2267 	}
2268 
2269 	void parseIsSpecialization() {
2270 		parseType();
2271 		if (match(TokenType.Identifier)) {
2272 			space();
2273 			nextToken();
2274 		}
2275 
2276 		static bool isTypeSpecialization(TokenType t) {
2277 			return t == TokenType.Struct || t == TokenType.Union
2278 				|| t == TokenType.Class || t == TokenType.Interface
2279 				|| t == TokenType.Enum || t == TokenType.__Vector
2280 				|| t == TokenType.Function || t == TokenType.Delegate
2281 				|| t == TokenType.Super || t == TokenType.Return
2282 				|| t == TokenType.__Parameters || t == TokenType.Module
2283 				|| t == TokenType.Package;
2284 		}
2285 
2286 		while (match(TokenType.EqualEqual) || match(TokenType.Colon)) {
2287 			auto specGuard = span();
2288 
2289 			space();
2290 			split();
2291 			nextToken();
2292 			space();
2293 
2294 			if (isTypeSpecialization(token.type)) {
2295 				nextToken();
2296 			} else {
2297 				parseType();
2298 			}
2299 
2300 			clearSeparator();
2301 		}
2302 	}
2303 
2304 	void parseStructLiteral() {
2305 		parseBlock!parseStructLiteralContent();
2306 		clearSeparator();
2307 	}
2308 
2309 	void parseStructLiteralContent() {
2310 		auto indentGuard = indent();
2311 
2312 		split();
2313 
2314 		while (!match(TokenType.CloseBrace) && !match(TokenType.End)) {
2315 			parseMapEntry();
2316 			runOnType!(TokenType.Comma, nextToken)();
2317 			newline(1);
2318 		}
2319 
2320 		// Flush comments so that they have the proper indentation.
2321 		flushComments();
2322 	}
2323 
2324 	void parseMapEntry() {
2325 		auto guard = span();
2326 		runOnType!(TokenType.Identifier, nextToken)();
2327 		runOnType!(TokenType.Colon, nextToken)();
2328 
2329 		split();
2330 		space();
2331 		parseExpression();
2332 	}
2333 
2334 	/**
2335 	 * Declarations
2336 	 */
2337 	void parseParameterPacks() {
2338 		auto guard = changeMode(Mode.Parameter);
2339 
2340 		while (match(TokenType.OpenParen)) {
2341 			nextToken();
2342 			parseList!(parseStructuralElement,
2343 			           ExpandingListSpan)(TokenType.CloseParen);
2344 		}
2345 	}
2346 
2347 	void parseTypedDeclaration() in {
2348 		assert(match(TokenType.Identifier));
2349 	} do {
2350 		bool isParameter = mode == Mode.Parameter;
2351 		while (true) {
2352 			auto guard = span!PrefixSpan();
2353 			split();
2354 			space();
2355 			runOnType!(TokenType.Identifier, nextToken)();
2356 
2357 			parseParameterPacks();
2358 
2359 			// Variable, template parameters, whatever.
2360 			if (match(TokenType.Equal) || match(TokenType.Colon)) {
2361 				auto valueGuard = spliceSpan();
2362 
2363 				space();
2364 				nextToken();
2365 				space();
2366 				split();
2367 
2368 				parseExpression();
2369 			}
2370 
2371 			if (isParameter) {
2372 				if (match(TokenType.DotDotDot)) {
2373 					nextToken();
2374 				}
2375 
2376 				break;
2377 			}
2378 
2379 			if (!match(TokenType.Comma)) {
2380 				break;
2381 			}
2382 
2383 			nextToken();
2384 		}
2385 
2386 		parseFunctionBody();
2387 	}
2388 
2389 	void parseConstructor() in {
2390 		assert(match(TokenType.This));
2391 	} do {
2392 		nextToken();
2393 		parseParameterPacks();
2394 		parseFunctionBody();
2395 	}
2396 
2397 	void parseDestructor() in {
2398 		assert(match(TokenType.Tilde));
2399 	} do {
2400 		nextToken();
2401 		parseConstructor();
2402 	}
2403 
2404 	void parseFunctionBody() {
2405 		if (parseFunctionPostfix()) {
2406 			space();
2407 			parseBlock(Mode.Statement);
2408 		}
2409 	}
2410 
2411 	bool parseFunctionPostfix() {
2412 		auto guard = span!IndentSpan(2);
2413 
2414 		while (true) {
2415 			clearSeparator();
2416 			space();
2417 
2418 			switch (token.type) with (TokenType) {
2419 				case OpenBrace:
2420 					// Function declaration.
2421 					return true;
2422 
2423 				case Body, Do:
2424 					split();
2425 					nextToken();
2426 					return true;
2427 
2428 				case In:
2429 					auto lookahead = trange.getLookahead();
2430 					lookahead.popFront();
2431 
2432 					if (lookahead.front.type == OpenBrace) {
2433 						nextToken();
2434 						goto ContractBlock;
2435 					}
2436 
2437 					split();
2438 					nextToken();
2439 					parseArgumentList();
2440 					break;
2441 
2442 				case Out:
2443 					auto lookahead = trange.getLookahead();
2444 					lookahead.popFront();
2445 
2446 					if (lookahead.front.type == OpenBrace) {
2447 						nextToken();
2448 						goto ContractBlock;
2449 					}
2450 
2451 					split();
2452 					nextToken();
2453 
2454 					runOnType!(OpenParen, nextToken)();
2455 					runOnType!(Identifier, nextToken)();
2456 
2457 					if (match(CloseParen)) {
2458 						nextToken();
2459 						goto ContractBlock;
2460 					}
2461 
2462 					auto outGuard = span();
2463 					runOnType!(Semicolon, nextToken)();
2464 
2465 					space();
2466 					split();
2467 
2468 					parseList!(parseExpression)(CloseParen);
2469 					break;
2470 
2471 				ContractBlock:
2472 					space();
2473 					parseBlock(Mode.Statement);
2474 					break;
2475 
2476 				case If:
2477 					parseConstraint();
2478 					break;
2479 
2480 				default:
2481 					if (!parseStorageClasses(true)) {
2482 						clearSeparator();
2483 						return false;
2484 					}
2485 
2486 					break;
2487 			}
2488 		}
2489 
2490 		assert(0);
2491 	}
2492 
2493 	void parseConstraint() {
2494 		if (!match(TokenType.If)) {
2495 			return;
2496 		}
2497 
2498 		split();
2499 		nextToken();
2500 		space();
2501 		parseCondition(true);
2502 	}
2503 
2504 	void parseTemplate() in {
2505 		assert(match(TokenType.Template));
2506 	} do {
2507 		nextToken();
2508 		space();
2509 		runOnType!(TokenType.Identifier, nextToken)();
2510 		parseParameterList();
2511 		space();
2512 
2513 		if (match(TokenType.If)) {
2514 			auto guard = span!IndentSpan(2);
2515 			parseConstraint();
2516 			space();
2517 		}
2518 
2519 		parseBlock(Mode.Declaration);
2520 	}
2521 
2522 	void parseTemplateParameter() in {
2523 		assert(token.type == TokenType.Identifier);
2524 	} do {
2525 		nextToken();
2526 
2527 		if (match(TokenType.DotDotDot)) {
2528 			nextToken();
2529 		}
2530 
2531 		while (match(TokenType.Colon) || match(TokenType.Equal)) {
2532 			space();
2533 			nextToken();
2534 			space();
2535 			parseType();
2536 		}
2537 	}
2538 
2539 	bool parseParameterList() {
2540 		if (!match(TokenType.OpenParen)) {
2541 			return false;
2542 		}
2543 
2544 		auto guard = changeMode(Mode.Parameter);
2545 		nextToken();
2546 
2547 		parseList!(parseStructuralElement,
2548 		           ExpandingListSpan)(TokenType.CloseParen);
2549 		return true;
2550 	}
2551 
2552 	void parseImport() in {
2553 		assert(match(TokenType.Import));
2554 	} do {
2555 		nextToken();
2556 
2557 		auto guard = span!PrefixSpan();
2558 
2559 		while (true) {
2560 			space();
2561 			split();
2562 			parseIdentifier();
2563 
2564 			if (!match(TokenType.Comma)) {
2565 				break;
2566 			}
2567 
2568 			nextToken();
2569 		}
2570 
2571 		parseColonList!parseImportBind();
2572 	}
2573 
2574 	void parseImportBind() {
2575 		parseIdentifier();
2576 
2577 		if (!match(TokenType.Equal)) {
2578 			return;
2579 		}
2580 
2581 		auto guard = spliceSpan();
2582 		space();
2583 		nextToken();
2584 		space();
2585 		split();
2586 
2587 		parseIdentifier();
2588 	}
2589 
2590 	bool parseAttribute() {
2591 		if (!match(TokenType.At)) {
2592 			return false;
2593 		}
2594 
2595 		nextToken();
2596 		if (parseAliasList()) {
2597 			return true;
2598 		}
2599 
2600 		if (!match(TokenType.Identifier)) {
2601 			parseIdentifier();
2602 			return true;
2603 		}
2604 
2605 		nextToken();
2606 		parseIdentifierSuffix(IdentifierKind.Symbol);
2607 		return true;
2608 	}
2609 
2610 	bool parseAttributes() {
2611 		if (!parseAttribute()) {
2612 			return false;
2613 		}
2614 
2615 		while (match(TokenType.At)) {
2616 			space();
2617 			split();
2618 			parseAttribute();
2619 		}
2620 
2621 		space();
2622 		return true;
2623 	}
2624 
2625 	static popDeclarator(ref TokenRange lookahead) {
2626 		lookahead.popFront();
2627 
2628 		if (lookahead.front.type == TokenType.Identifier) {
2629 			lookahead.popFront();
2630 		}
2631 
2632 		if (lookahead.front.type == TokenType.OpenParen) {
2633 			import source.parserutil;
2634 			lookahead.popMatchingDelimiter!(TokenType.OpenParen)();
2635 		}
2636 
2637 		return lookahead.front.type;
2638 	}
2639 
2640 	TokenType getStorageClassTokenType() {
2641 		auto lookahead = trange.getLookahead();
2642 		return getStorageClassTokenType(lookahead);
2643 	}
2644 
2645 	static getStorageClassTokenType(ref TokenRange lookahead) {
2646 		while (true) {
2647 			auto t = lookahead.front.type;
2648 			switch (t) with (TokenType) {
2649 				case Const, Immutable, Inout, Shared, Scope:
2650 					lookahead.popFront();
2651 					if (lookahead.front.type == OpenParen) {
2652 						// This is a type.
2653 						return t;
2654 					}
2655 
2656 					break;
2657 
2658 				case Abstract, Auto, Export, Final, In, Lazy, Nothrow, Out,
2659 				     Override, Private, Protected, Pure, Ref, Return, __Gshared:
2660 					lookahead.popFront();
2661 					break;
2662 
2663 				case Align, Deprecated, Extern, Package, Pragma, Synchronized:
2664 					lookahead.popFront();
2665 					if (lookahead.front.type == OpenParen) {
2666 						import source.parserutil;
2667 						lookahead.popMatchingDelimiter!OpenParen();
2668 					}
2669 
2670 					break;
2671 
2672 				case At:
2673 					// FIXME: A declarator is not apropriate here.
2674 					popDeclarator(lookahead);
2675 					break;
2676 
2677 				case Public:
2678 					auto l2 = lookahead.getLookahead();
2679 					l2.popFront();
2680 
2681 					if (l2.front.type == Import) {
2682 						// This is a public import.
2683 						return t;
2684 					}
2685 
2686 					lookahead.popFront();
2687 					break;
2688 
2689 				case Static:
2690 					auto l2 = lookahead.getLookahead();
2691 					l2.popFront();
2692 
2693 					auto t2 = l2.front.type;
2694 					if (t2 == Assert || t2 == Import || t2 == If
2695 						    || t2 == Foreach || t2 == ForeachReverse) {
2696 						// This is a static something.
2697 						return t;
2698 					}
2699 
2700 					lookahead.popFront();
2701 					break;
2702 
2703 				case Enum:
2704 					auto l2 = lookahead.getLookahead();
2705 					popDeclarator(l2);
2706 
2707 					auto t2 = l2.front.type;
2708 					if (t2 == Colon || t2 == OpenBrace) {
2709 						// This is an enum declaration.
2710 						return t;
2711 					}
2712 
2713 					lookahead.popFront();
2714 					break;
2715 
2716 				case Alias:
2717 					auto l2 = lookahead.getLookahead();
2718 					popDeclarator(l2);
2719 
2720 					auto t2 = l2.front.type;
2721 					if (t2 == This || t2 == Identifier) {
2722 						// This is an alias declaration.
2723 						return t;
2724 					}
2725 
2726 					lookahead.popFront();
2727 					break;
2728 
2729 				default:
2730 					return t;
2731 			}
2732 		}
2733 	}
2734 
2735 	bool parseStorageClasses(bool isPostfix = false) {
2736 		bool foundStorageClass = false;
2737 		while (true) {
2738 			scope(success) {
2739 				// This will be true after the first loop iterration.
2740 				foundStorageClass = true;
2741 			}
2742 
2743 			switch (token.type) with (TokenType) {
2744 				case Const, Immutable, Inout, Shared, Scope:
2745 					auto lookahead = trange.getLookahead();
2746 					lookahead.popFront();
2747 					if (lookahead.front.type == OpenParen) {
2748 						// This is a type.
2749 						goto default;
2750 					}
2751 
2752 					nextToken();
2753 					break;
2754 
2755 				case In, Out:
2756 					// Make sure we deambiguate with contracts.
2757 					if (isPostfix) {
2758 						goto default;
2759 					}
2760 
2761 					nextToken();
2762 					break;
2763 
2764 				case Abstract, Auto, Export, Final, Lazy, Nothrow, Override,
2765 				     Private, Protected, Pure, Ref, Return, __Gshared:
2766 					nextToken();
2767 					break;
2768 
2769 				case Align, Deprecated, Extern, Package, Synchronized:
2770 					nextToken();
2771 					parseArgumentList();
2772 					break;
2773 
2774 				case Pragma:
2775 					nextToken();
2776 					parseArgumentList();
2777 					if (!isPostfix && !match(Colon)) {
2778 						newline(1);
2779 					}
2780 
2781 					break;
2782 
2783 				case At:
2784 					parseAttributes();
2785 					if (!isPostfix && !foundStorageClass && !match(Colon)) {
2786 						newline(1);
2787 					}
2788 
2789 					break;
2790 
2791 				case Public:
2792 					auto lookahead = trange.getLookahead();
2793 					lookahead.popFront();
2794 
2795 					if (lookahead.front.type == Import) {
2796 						// This is a public import.
2797 						goto default;
2798 					}
2799 
2800 					nextToken();
2801 					break;
2802 
2803 				case Static:
2804 					auto lookahead = trange.getLookahead();
2805 					lookahead.popFront();
2806 
2807 					auto t = lookahead.front.type;
2808 					if (t == Assert || t == Import || t == If || t == Foreach
2809 						    || t == ForeachReverse) {
2810 						// This is a static something.
2811 						goto default;
2812 					}
2813 
2814 					nextToken();
2815 					break;
2816 
2817 				case Enum:
2818 					auto lookahead = trange.getLookahead();
2819 					popDeclarator(lookahead);
2820 
2821 					auto t = lookahead.front.type;
2822 					if (t == Colon || t == OpenBrace) {
2823 						// This is an enum declaration.
2824 						goto default;
2825 					}
2826 
2827 					nextToken();
2828 					break;
2829 
2830 				case Alias:
2831 					auto lookahead = trange.getLookahead();
2832 					popDeclarator(lookahead);
2833 
2834 					auto t = lookahead.front.type;
2835 					if (t == This || t == Identifier) {
2836 						// This is an alias declaration.
2837 						goto default;
2838 					}
2839 
2840 					nextToken();
2841 					break;
2842 
2843 				default:
2844 					return foundStorageClass;
2845 			}
2846 
2847 			if (match(TokenType.Colon) || match(TokenType.Semicolon)) {
2848 				clearSeparator();
2849 			} else {
2850 				if (!isPostfix && !match(TokenType.Identifier)) {
2851 					split();
2852 				}
2853 
2854 				space();
2855 			}
2856 		}
2857 
2858 		return foundStorageClass;
2859 	}
2860 
2861 	bool parseStorageClassDeclaration() {
2862 		auto guard = span!StorageClassSpan();
2863 
2864 		bool isColonBlock = getStorageClassTokenType() == TokenType.Colon;
2865 		bool foundStorageClass = false;
2866 
2867 		{
2868 			auto indentGuard = unindent(isColonBlock);
2869 			foundStorageClass = parseStorageClasses();
2870 		}
2871 
2872 		// Before bailing, try storage class looking declarations.
2873 		switch (token.type) with (TokenType) {
2874 			case Public:
2875 				return parsePublic();
2876 
2877 			case Enum:
2878 				return parseEnum();
2879 
2880 			case Alias:
2881 				return parseAlias();
2882 
2883 			default:
2884 				break;
2885 		}
2886 
2887 		if (!foundStorageClass) {
2888 			return false;
2889 		}
2890 
2891 		switch (token.type) with (TokenType) {
2892 			case Colon:
2893 				clearSeparator();
2894 				parseColonBlock();
2895 				break;
2896 
2897 			case Semicolon:
2898 				clearSeparator();
2899 				nextToken();
2900 				break;
2901 
2902 			case OpenBrace:
2903 				parseBlock(mode);
2904 				break;
2905 
2906 			case Identifier:
2907 				auto lookahead = trange.getLookahead();
2908 				lookahead.popFront();
2909 
2910 				auto t = lookahead.front.type;
2911 				if (t == Equal || t == OpenParen) {
2912 					split();
2913 					parseTypedDeclaration();
2914 					break;
2915 				}
2916 
2917 				goto default;
2918 
2919 			default:
2920 				split();
2921 				parseStructuralElement();
2922 				break;
2923 		}
2924 
2925 		return true;
2926 	}
2927 
2928 	bool parsePublic() {
2929 		if (!match(TokenType.Public)) {
2930 			return false;
2931 		}
2932 
2933 		auto lookahead = trange.getLookahead();
2934 		lookahead.popFront();
2935 
2936 		if (lookahead.front.type == TokenType.Import) {
2937 			nextToken();
2938 			space();
2939 			parseImport();
2940 		} else {
2941 			parseStorageClassDeclaration();
2942 		}
2943 
2944 		return true;
2945 	}
2946 
2947 	bool parseStatic() {
2948 		if (!match(TokenType.Static)) {
2949 			return false;
2950 		}
2951 
2952 		auto lookahead = trange.getLookahead();
2953 		lookahead.popFront();
2954 
2955 		auto t = lookahead.front.type;
2956 		switch (t) with (TokenType) {
2957 			case If:
2958 				nextToken();
2959 				space();
2960 				parseIf();
2961 				break;
2962 
2963 			case Foreach, ForeachReverse:
2964 				nextToken();
2965 				space();
2966 				parseForeach();
2967 				break;
2968 
2969 			case Assert:
2970 				nextToken();
2971 				space();
2972 				parseExpression();
2973 				break;
2974 
2975 			case Import:
2976 				nextToken();
2977 				space();
2978 				parseImport();
2979 				break;
2980 
2981 			default:
2982 				parseStorageClassDeclaration();
2983 				break;
2984 		}
2985 
2986 		return true;
2987 	}
2988 
2989 	bool parseEnum() {
2990 		if (!match(TokenType.Enum)) {
2991 			return false;
2992 		}
2993 
2994 		nextToken();
2995 		if (match(TokenType.Identifier)) {
2996 			space();
2997 			nextToken();
2998 		}
2999 
3000 		if (match(TokenType.Colon)) {
3001 			space();
3002 			nextToken();
3003 			space();
3004 			parseType();
3005 		}
3006 
3007 		if (match(TokenType.OpenBrace)) {
3008 			space();
3009 			nextToken();
3010 			parseList!parseEnumEntry(TokenType.CloseBrace, true);
3011 		}
3012 
3013 		return true;
3014 	}
3015 
3016 	void parseEnumEntry() {
3017 		if (parseAttributes()) {
3018 			newline(1);
3019 		}
3020 
3021 		parseExpression();
3022 	}
3023 
3024 	bool parseAlias() {
3025 		if (!match(TokenType.Alias)) {
3026 			return false;
3027 		}
3028 
3029 		nextToken();
3030 		space();
3031 
3032 		parseIdentifier();
3033 
3034 		if (match(TokenType.Identifier) || match(TokenType.This)) {
3035 			space();
3036 			nextToken();
3037 		}
3038 
3039 		return true;
3040 	}
3041 
3042 	void parseAliasEntry() {
3043 		// FIXME: This is wrong because identifier * identifier shouldn't be
3044 		// parsed as a declaration here, but provide the right entry point for the
3045 		// rest of the code.
3046 		parseType();
3047 		parseAssignExpressionSuffix();
3048 	}
3049 
3050 	bool parseAliasList() {
3051 		if (!match(TokenType.OpenParen)) {
3052 			return false;
3053 		}
3054 
3055 		nextToken();
3056 		parseList!parseAliasEntry(TokenType.CloseParen);
3057 		return true;
3058 	}
3059 
3060 	void parseAggregate() in {
3061 		assert(match(TokenType.Struct) || match(TokenType.Union)
3062 			|| match(TokenType.Class) || match(TokenType.Interface));
3063 	} do {
3064 		nextToken();
3065 		space();
3066 
3067 		runOnType!(TokenType.Identifier, nextToken)();
3068 
3069 		parseParameterList();
3070 
3071 		while (true) {
3072 			space();
3073 
3074 			switch (token.type) with (TokenType) {
3075 				case Colon:
3076 					parseColonList!parseIdentifier();
3077 					break;
3078 
3079 				case If: {
3080 					auto guard = span!IndentSpan(2);
3081 					parseConstraint();
3082 					break;
3083 				}
3084 
3085 				default:
3086 					parseBlock(Mode.Declaration);
3087 					return;
3088 			}
3089 		}
3090 	}
3091 
3092 	/**
3093 	 * Parsing utilities
3094 	 */
3095 	void parseListAdapter(alias fun)(size_t i) {
3096 		fun();
3097 	}
3098 
3099 	void parseList(alias fun, S = CompactListSpan)(TokenType closingTokenType,
3100 	                                               bool addNewLines = false) {
3101 		if (match(closingTokenType)) {
3102 			auto guard = builder.virtualSpan();
3103 			nextToken();
3104 			return;
3105 		}
3106 
3107 		static if (is(typeof(fun(0)))) {
3108 			alias afun = fun;
3109 		} else {
3110 			alias afun = parseListAdapter!fun;
3111 		}
3112 
3113 		auto guard = span!S();
3114 
3115 		size_t i = 0;
3116 		while (!match(closingTokenType)) {
3117 			if (addNewLines) {
3118 				newline(1);
3119 			}
3120 
3121 			split();
3122 			guard.registerFix(function(S s, size_t i) {
3123 				s.registerElement(i);
3124 			});
3125 
3126 			afun(i++);
3127 
3128 			if (!match(TokenType.Comma)) {
3129 				break;
3130 			}
3131 
3132 			nextToken();
3133 			space();
3134 		}
3135 
3136 		if (match(closingTokenType)) {
3137 			if (addNewLines) {
3138 				newline(1);
3139 			}
3140 
3141 			split();
3142 			guard.registerFix(function(S s, size_t i) {
3143 				s.registerTrailingSplit(i);
3144 			});
3145 
3146 			nextToken();
3147 		}
3148 
3149 		if (addNewLines) {
3150 			newline(2);
3151 		}
3152 	}
3153 
3154 	bool parseColonList(alias fun)() {
3155 		if (!match(TokenType.Colon)) {
3156 			return false;
3157 		}
3158 
3159 		auto colonGuard = spliceSpan();
3160 		space();
3161 		split();
3162 		nextToken();
3163 
3164 		auto listGuard = span!CompactListSpan();
3165 		bool first = true;
3166 		while (true) {
3167 			space();
3168 			split(first);
3169 			first = false;
3170 
3171 			listGuard.registerFix(function(CompactListSpan s, size_t i) {
3172 				s.registerElement(i);
3173 			});
3174 
3175 			fun();
3176 
3177 			if (!match(TokenType.Comma)) {
3178 				break;
3179 			}
3180 
3181 			nextToken();
3182 		}
3183 
3184 		return true;
3185 	}
3186 }