1 /**
2 Copyright: Copyright (c) 2017-2019 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 /// Grammar
7 /// Lexer
8 /// Recursive descent parser
9 /// For expressions pratt parser is used
10 ///   Copyright (c) 2017, Jean-Marc Bourguet
11 ///   https://github.com/bourguet/operator_precedence_parsing/blob/86c11baa737673da521c9cb488fdc3b25d73f0b6/pratt_tdop_parser.py
12 module vox.fe.passes.parser;
13 
14 import std.format : formattedWrite;
15 import std.string : format;
16 import std.range : repeat;
17 import std.stdio;
18 import std.conv : to;
19 
20 import vox.all;
21 
22 
23 // Grammar
24 /**
25 	<module> = <declaration>* EOF
26 	<declaration> = <alias_decl> / <func_decl> / <var_decl> / <struct_decl> / <enum_decl>
27 
28 	<alias_decl> = "alias" <id> "=" <expr> ";"
29 	<func_decl> = <type> <identifier> ("[" <template_args> "]")? "(" <param_list> ")" (<block_statement> / ';')
30 	<param_list> = <parameter> "," <parameter_list> / <parameter>?
31 	<parameter> = <type> <identifier>?
32 
33 	<var_decl> = <type> <identifier> ("=" <expression>)? ";"
34 	<struct_decl> = "struct" <identifier> ("[" <template_args> "]")? "{" <declaration>* "}"
35 	<enum_decl> = <enum_decl_single> / <enum_decl_multi>
36 	<enum_decl_multi> = "enum" [<identifier>] [":" <type>] "{" (<identifier> ["=" <expr>] ",") * "}"
37 	<enum_decl_single> = "enum" <identifier> [ "=" <expr> ] ";"
38 
39 	<statement> = "if" <paren_expression> <statement> ("else" <statement>)?
40 				  "while" <paren_expression> <statement> /
41 				  "do" <statement> "while" <paren_expression> ";" /
42 				  "return" <expression>? ";" /
43 				  "continue" ";" /
44 				  "break" ";" /
45 				  <block_statement> /
46 				  <expression> ("=" <expression>)? ";" /
47 				  <declaration_statement>
48 
49 	<declaration_statement> = <declaration>
50 	<block_statement> = "{" <statement>* "}"
51 
52 	<expression> = <test>
53 	<test> = <sum> | <sum> ("=="|"!="|"<"|">"|"<="|">=") <sum>
54 	<sum> = <term> / <sum> ("+"|"-") <term>
55 	<term> = <identifier> "(" <expression_list> ")" / <identifier> "[" <expression> "]" / <identifier> / <int_literal> / <string_literal> / <paren_expression>
56 	<paren_expression> = "(" <expression> ")"
57 
58 	<expression_list> = (<expression> ",")*
59 	<identifier> = [_a-zA-Z] [_a-zA-Z0-9]*
60 
61 	<type> = (<type_basic> / <type_struct>) <type_specializer>*
62 	<type_specializer> = "*" / "[" <expression> "]" / "[" "]" / "function" "(" <param_list> ")"
63 	<type_basic> = ("i8" | "i16" | "i32" | "i64" |
64 		"u8" | "u16" | "u32" | "u64" | "void" | "f32" | "f64")
65 
66 	<type_struct> = <identifier>
67 
68 	<int_literal> = <literal_dec_int> / <literal_hex_int> / <literal_bin_int>
69 	<literal_dec_int> = 0|[1-9][0-9_]*
70 	<literal_hex_int> = ("0x"|"0X")[0-9A-Fa-f_]+
71 	<literal_bin_int> = ("0b"|"0B")[01_]+
72 */
73 
74 void pass_parser(ref CompilationContext ctx, CompilePassPerModule[] subPasses) {
75 	Parser parser = Parser(&ctx);
76 
77 	foreach (ref SourceFileInfo file; ctx.files.data)
78 	{
79 		parser.parseModule(file.mod, file.firstTokenIndex);
80 
81 		if (ctx.printAstFresh) {
82 			writefln("// AST fresh `%s`", file.name);
83 			print_ast(ctx.getAstNodeIndex(file.mod), &ctx, 2);
84 		}
85 	}
86 }
87 
88 // Attribute stack has the following structure at runtime
89 //
90 // - uneffective attributes (0 or more)
91 // - broadcasted attributes (0 or more)
92 // - immediate attributes   (0 or more) top of the stack
93 //
94 // when a new attribute is parsed it is added to the top of the attribute stack
95 //
96 struct BroadcastedAttribState
97 {
98 	// Number of attributes on the top of `attributeStack`, but below immediate attributes,
99 	// that will be applied to the next declaration
100 	// after application they will remain on the stack
101 	ushort numBroadcastedAttributes;
102 
103 	// one bit per attribute in BuiltinFlagAttrib set
104 	// will be added to the next declaration
105 	// and will remain until the end of the scope
106 	ushort broadcastedFlagAttributes;
107 }
108 
109 struct ImmediateAttribState
110 {
111 	// Number of attributes on the top of `attributeStack`, that
112 	// will be added to the next declaration
113 	// and will be dropped from the stack
114 	ushort numImmediateAttributes;
115 
116 	// one bit per attribute in BuiltinFlagAttrib set
117 	// will be added to the next declaration
118 	// and will be zeroed
119 	ushort immediateFlagAttributes;
120 }
121 
122 struct AttribState
123 {
124 	BroadcastedAttribState broadcasted;
125 	ImmediateAttribState immediate;
126 
127 	ushort numEffectiveAttributes() { return cast(ushort)(broadcasted.numBroadcastedAttributes + immediate.numImmediateAttributes); }
128 	ushort effectiveFlagAttributes() { return broadcasted.broadcastedFlagAttributes | immediate.immediateFlagAttributes; }
129 
130 	bool isStaticDecl() {
131 		return cast(bool)(effectiveFlagAttributes & BuiltinFlagAttrib.isStatic);
132 	}
133 }
134 
135 struct ScopeTempData
136 {
137 	BroadcastedAttribState prevBroadcasted;
138 	bool isNonScope;
139 }
140 
141 //version = print_parse;
142 struct Parser
143 {
144 	CompilationContext* context;
145 	ModuleDeclNode* currentModule;
146 	/// For member functions
147 	/// module, struct or function
148 	AstIndex declarationOwner;
149 	ScopeIndex currentScopeIndex;
150 
151 	// Current token
152 	Token tok;
153 
154 	// Saved to ScopeTempData on scope push/pop
155 	AttribState attribState;
156 	// Attributes affecting next declaration
157 	AstNodes attributeStack;
158 
159 	// Allocates AttributeInfo in AST arena, so it will be before next AST node allocated.
160 	// returns 0 or AstFlags.hasAttributes flag. Must be added to node flags.
161 	ushort createAttributeInfo() {
162 		ushort declFlags;
163 		//writefln("%s %s", attribState.immediateFlagAttributes, attribState.broadcastedFlagAttributes);
164 		if (attribState.isStaticDecl) {
165 			declFlags |= AstFlags.isGlobal;
166 		} else {
167 			switch (declarationOwner.astType(context)) {
168 				case AstType.decl_struct:
169 					declFlags |= AstFlags.isMember;
170 					break;
171 				case AstType.decl_module:
172 					declFlags |= AstFlags.isGlobal;
173 					break;
174 				default: break;
175 			}
176 		}
177 
178 		attribState.immediate.immediateFlagAttributes = 0;
179 
180 		if (attribState.numEffectiveAttributes == 0) return declFlags;
181 
182 		declFlags |= AstFlags.hasAttributes;
183 
184 		AstNodes attributes;
185 		attributes.voidPut(context.arrayArena, attribState.numEffectiveAttributes);
186 		uint attribFlags;
187 
188 		auto offset = attributeStack.length - attribState.numEffectiveAttributes;
189 		foreach(i; 0..attribState.numEffectiveAttributes) {
190 			AstIndex attrib = attributeStack[offset + i];
191 			attributes[i] = attrib;
192 			attribFlags |= calcAttribFlags(attrib, context);
193 		}
194 
195 		attributeStack.unput(attribState.immediate.numImmediateAttributes);
196 		attribState.immediate.numImmediateAttributes = 0;
197 
198 		context.appendAst!AttributeInfo(attributes, attribFlags);
199 		return declFlags;
200 	}
201 
202 	SourceLocation loc() {
203 		return context.tokenLocationBuffer[tok.index];
204 	}
205 
206 	int nesting;
207 	auto indent(uint var) { return ' '.repeat(var*2); }
208 	struct PrintScope { Parser* p; ~this(){--p.nesting;}}
209 	PrintScope scop(Args...)(string name, Args args) { write(indent(nesting)); writefln(name, args); ++nesting; return PrintScope(&this); }
210 
211 	void nextToken()
212 	{
213 		do {
214 			++tok.index;
215 			tok.type = context.tokenBuffer[tok.index];
216 		}
217 		while (tok.type == TokenType.COMMENT);
218 	}
219 
220 	void skipPast(TokenType tokType)
221 	{
222 		while (tok.type != TokenType.EOI)
223 		{
224 			++tok.index;
225 			tok.type = context.tokenBuffer[tok.index];
226 			if (tok.type == tokType) {
227 				nextToken;
228 				break;
229 			}
230 		}
231 	}
232 
233 	bool hasMoreTokens() {
234 		return tok.type != TokenType.EOI;
235 	}
236 
237 	AstIndex make(T, Args...)(TokenIndex start, Args args) {
238 		return context.appendAst!T(start, args);
239 	}
240 	// Will attach attributes if present
241 	AstIndex makeDecl(T, Args...)(TokenIndex start, Args args) {
242 		auto flags = createAttributeInfo;
243 		AstIndex declIndex = context.appendAst!T(start, args);
244 		if (flags) {
245 			AstNode* declNode = context.getAstNode(declIndex);
246 			declNode.flags |= flags;
247 		}
248 		return declIndex;
249 	}
250 	AstIndex makeExpr(T, Args...)(TokenIndex start, Args args) {
251 		return context.appendAst!T(start, AstIndex.init, args);
252 	}
253 
254 	void expect(TokenType type, string after = null) {
255 		if (tok.type != type) {
256 			const(char)[] tokenString = context.getTokenString(tok.index);
257 			if (after)
258 				context.unrecoverable_error(tok.index, "Expected `%s` after %s, while got `%s` token '%s'",
259 					type, after, tok.type, tokenString);
260 			else
261 				context.unrecoverable_error(tok.index, "Expected `%s` token, while got `%s` token '%s'",
262 					type, tok.type, tokenString);
263 		}
264 	}
265 
266 	void expectAndConsume(TokenType type, string after = null) {
267 		expect(type, after);
268 		nextToken;
269 	}
270 
271 	Identifier makeIdentifier(TokenIndex index)
272 	{
273 		const(char)[] str = context.getTokenString(index);
274 		return context.idMap.getOrReg(context, str);
275 	}
276 
277 	Identifier expectIdentifier(string after = null)
278 	{
279 		TokenIndex index = tok.index;
280 		expectAndConsume(TokenType.IDENTIFIER, after);
281 		Identifier id = makeIdentifier(index);
282 		return id;
283 	}
284 
285 	// temp data is used instead of separate stack to push/pop
286 	ScopeTempData pushScope(string name, ScopeKind kind)
287 	{
288 		ScopeTempData temp;
289 		temp.prevBroadcasted = attribState.broadcasted;
290 
291 		context.assertf(attribState.immediate == ImmediateAttribState.init,
292 			"No immediate attributes should remain before new scope");
293 
294 		if (kind == ScopeKind.no_scope)
295 		{
296 			// no_scope scopes do not effectively introduce a new scope for attributes, nor for declarations/statements
297 			temp.isNonScope = true;
298 
299 			// Outer effective attributes are effective inside no_scope scopes
300 			attribState = AttribState(attribState.broadcasted);
301 		}
302 		else
303 		{
304 			// Outer attributes are not visible inside
305 			attribState = AttribState.init;
306 
307 			ScopeIndex newScopeIndex = context.appendScope;
308 			Scope* newScope = context.getAstScope(newScopeIndex);
309 			newScope.debugName = name;
310 			newScope.kind = kind;
311 			newScope.owner = declarationOwner;
312 
313 			newScope.parentScope = currentScopeIndex;
314 			currentScopeIndex = newScopeIndex;
315 		}
316 
317 		return temp;
318 	}
319 
320 	void popScope(ScopeTempData temp)
321 	{
322 		context.assertf(attribState.immediate == ImmediateAttribState.init,
323 			"No immediate attributes should remain at the end of the scope");
324 
325 		// How many attributes were introduced in the current scope compared to previous
326 		ushort numScopeAttributes = 0;
327 		if (attribState.broadcasted.numBroadcastedAttributes > temp.prevBroadcasted.numBroadcastedAttributes)
328 			numScopeAttributes = cast(ushort)(attribState.broadcasted.numBroadcastedAttributes - temp.prevBroadcasted.numBroadcastedAttributes);
329 
330 		// mark the rest of effective nodes as broadcasted
331 		auto offset = attributeStack.length - numScopeAttributes;
332 		foreach(i; 0..numScopeAttributes) {
333 			AstIndex attrib = attributeStack[offset + i];
334 			attrib.flags(context) |= AnyAttributeFlags.isBroadcasted;
335 		}
336 
337 		// drop broadcasted attributes introduced by this scope at the end of the scope
338 		attributeStack.unput(numScopeAttributes);
339 
340 		if (temp.isNonScope)
341 		{
342 			// no scope was introduced
343 		}
344 		else
345 		{
346 			currentScopeIndex = currentScopeIndex.get_scope(context).parentScope;
347 		}
348 
349 		attribState = AttribState(temp.prevBroadcasted);
350 	}
351 
352 	// ------------------------------ PARSING ----------------------------------
353 
354 	void parseModule(ModuleDeclNode* mod, TokenIndex firstTokenIndex) { // <module> ::= <declaration>*
355 		currentModule = mod;
356 		scope(exit) currentModule = null;
357 
358 		version(print_parse) auto s1 = scop("parseModule");
359 		tok.index = firstTokenIndex;
360 		tok.type = context.tokenBuffer[tok.index];
361 		expectAndConsume(TokenType.SOI);
362 		mod.loc = tok.index;
363 		mod.state = AstNodeState.name_register_self_done;
364 		declarationOwner = context.getAstNodeIndex(mod);
365 
366 		ScopeTempData scope_temp = pushScope("Module", ScopeKind.global);
367 			mod.memberScope = currentScopeIndex;
368 			parse_module_decl();
369 			parse_declarations(mod.declarations, TokenType.EOI);
370 		popScope(scope_temp);
371 	}
372 
373 	void parse_declarations(ref AstNodes declarations, TokenType until) { // <declaration>*
374 		while (tok.type != until)
375 		{
376 			if (tok.type == TokenType.EOI) break;
377 			parse_declaration(declarations);
378 		}
379 	}
380 
381 	void parse_declaration(ref AstNodes items) // <declaration> ::= <func_declaration> / <var_declaration> / <struct_declaration>
382 	{
383 		version(print_parse) auto s1 = scop("parse_declaration %s", loc);
384 
385 		switch(tok.type) with(TokenType)
386 		{
387 			case ALIAS_SYM: // <alias_decl> ::= "alias" <id> "=" <expr> ";"
388 				AstIndex declIndex = parse_alias();
389 				items.put(context.arrayArena, declIndex);
390 				return;
391 			case STRUCT_SYM, UNION_SYM: // <struct_declaration> ::= "struct" <id> "{" <declaration>* "}"
392 				AstIndex declIndex = parse_struct();
393 				items.put(context.arrayArena, declIndex);
394 				return;
395 			case ENUM:
396 				AstIndex declIndex = parse_enum();
397 				items.put(context.arrayArena, declIndex);
398 				return;
399 			case IMPORT_SYM:
400 				AstIndex declIndex = parse_import();
401 				items.put(context.arrayArena, declIndex);
402 				return;
403 			case MODULE_SYM:
404 				context.error(tok.index, "Module declaration can only occur as first declaration of the module");
405 				skipPast(TokenType.SEMICOLON);
406 				AstIndex declIndex = context.getAstNodeIndex(currentModule);
407 				items.put(context.arrayArena, declIndex);
408 				return;
409 			case HASH_IF, HASH_VERSION:
410 				AstIndex declIndex = parse_hash_if();
411 				items.put(context.arrayArena, declIndex);
412 				return;
413 			case HASH_ASSERT:
414 				AstIndex declIndex = parse_hash_assert();
415 				items.put(context.arrayArena, declIndex);
416 				return;
417 			case HASH_FOREACH:
418 				AstIndex declIndex = parse_hash_foreach();
419 				items.put(context.arrayArena, declIndex);
420 				return;
421 			case AT:
422 				parse_attribute(items);
423 				return;
424 			case TYPE_AUTO:
425 				parse_auto_decl(items);
426 				return;
427 			default: // <func_declaration> / <var_declaration>
428 				TokenIndex start = tok.index;
429 				AstIndex body_start = AstIndex(context.astBuffer.uintLength);
430 				AstIndex typeIndex = expr(PreferType.yes, 0);
431 				AstIndex nodeIndex = parse_var_func_declaration_after_type(start, body_start, typeIndex, ConsumeTerminator.yes, TokenType.SEMICOLON);
432 				AstIndex declIndex = nodeIndex;
433 				items.put(context.arrayArena, declIndex);
434 				return;
435 		}
436 		assert(false);
437 	}
438 
439 	void parse_single_attribute(TokenIndex start)
440 	{
441 		Identifier attributeId = expectIdentifier("@");
442 
443 		switch(attributeId.index) {
444 			case CommonIds.id_extern.index:
445 				parse_extern_attribute(start);
446 				break;
447 			case CommonIds.id_static.index:
448 				attribState.immediate.immediateFlagAttributes |= BuiltinFlagAttrib.isStatic;
449 				break;
450 			default:
451 				context.unrecoverable_error(start, "Unknown built-in attribute `%s`", context.idString(attributeId));
452 		}
453 	}
454 
455 	// parses all attributes and one or more declarations that it is attached too
456 	void parse_attribute(ref AstNodes declarations)
457 	{
458 		while(true)
459 		{
460 			TokenIndex start = tok.index;
461 			nextToken; // skip @
462 			parse_single_attribute(start);
463 
464 			switch(tok.type)
465 			{
466 			case TokenType.AT:
467 				break; // next attribute
468 			case TokenType.COLON:
469 				nextToken; // skip :
470 				// Mark all immediate attributes as scoped attributes.
471 				// They will be effective until the end of current scope, then the will be popped by popScope
472 				attribState.broadcasted.numBroadcastedAttributes += attribState.immediate.numImmediateAttributes;
473 				attribState.immediate.numImmediateAttributes = 0;
474 				// Mark all immediate flag attributes as scoped attributes.
475 				attribState.broadcasted.broadcastedFlagAttributes |= attribState.immediate.immediateFlagAttributes;
476 				attribState.immediate.immediateFlagAttributes = 0;
477 				// next comes another attribute or declaration
478 				if (tok.type == TokenType.AT) break; // next attribute
479 				return; // back to declaration/statement parsing
480 			case TokenType.LCURLY:
481 				nextToken; // skip {
482 				// all attributes before {} will be applied to all declarations in {}
483 				// attributes before {} are initially classified as immediate
484 				// Remove them, and then move them into the scope
485 				// @attr1 @attr2 { // number of attributes == numImmediateAttributes
486 				//     decl1;
487 				//     decl2;
488 				// }
489 				// is the same as:
490 				// {
491 				//     @attr1 @attr2:
492 				//     decl1;
493 				//     decl2;
494 				// }
495 
496 				// number of attributes
497 				ushort numImmediateAttributes = attribState.immediate.numImmediateAttributes;
498 				// save immediate flag attributes
499 				auto immediateFlagAttributes = attribState.immediate.immediateFlagAttributes;
500 
501 				// remove attributes from current scope
502 				attribState.immediate.numImmediateAttributes = 0;
503 
504 				// remove flag attributes from current scope
505 				attribState.immediate.immediateFlagAttributes = 0;
506 
507 				// enter the scope
508 				ScopeTempData scope_temp = pushScope("@{}", ScopeKind.no_scope);
509 
510 				// restore flag attributes, but now they are in the nested scope
511 				attribState.immediate.immediateFlagAttributes = immediateFlagAttributes;
512 
513 				// add them as @: attributes
514 				attribState.broadcasted.numBroadcastedAttributes += numImmediateAttributes;
515 
516 				// declarations
517 				parse_declarations(declarations, TokenType.RCURLY);
518 
519 				// @: attributes are cleared by the scope end inside popScope
520 				popScope(scope_temp);
521 
522 				expectAndConsume(TokenType.RCURLY, "@{");
523 				return;
524 			default:
525 				parse_declaration(declarations);
526 				return;
527 			}
528 		}
529 	}
530 
531 	void parse_extern_attribute(TokenIndex start)
532 	{
533 		expectAndConsume(TokenType.LPAREN, "@extern");
534 
535 		Identifier externKindId;
536 		if (tok.type == TokenType.MODULE_SYM) {
537 			externKindId = CommonIds.id_module;
538 			expectAndConsume(TokenType.MODULE_SYM, "@extern(");
539 		} else {
540 			externKindId = expectIdentifier("@extern(");
541 		}
542 
543 		AstIndex attribute;
544 		switch(externKindId.index) {
545 			case CommonIds.id_syscall.index:
546 				expectAndConsume(TokenType.COMMA, "@extern(syscall");
547 				expect(TT.INT_DEC_LITERAL, "@extern(syscall,");
548 				string value = cast(string)context.getTokenString(tok.index);
549 				import std.algorithm.iteration : filter;
550 				uint syscallNumber = value.filter!(c => c != '_').to!uint;
551 				nextToken; // skip integer
552 				attribute = make!BuiltinAttribNode(start, BuiltinAttribSubType.extern_syscall, syscallNumber);
553 				break;
554 			case CommonIds.id_module.index:
555 				expectAndConsume(TokenType.COMMA, "@extern(module");
556 				expect(TT.STRING_LITERAL, "@extern(module,");
557 				string value = cast(string)context.getTokenString(tok.index);
558 				nextToken; // skip lib name
559 				Identifier moduleId = context.idMap.getOrReg(context, value[1..$-1]);
560 				attribute = make!BuiltinAttribNode(start, BuiltinAttribSubType.extern_module, moduleId.index);
561 				break;
562 			default:
563 				context.unrecoverable_error(start, "Unknown @extern kind `%s`", context.idString(externKindId));
564 		}
565 
566 		expectAndConsume(TokenType.RPAREN, "@extern(...");
567 		++attribState.immediate.numImmediateAttributes;
568 		attributeStack.put(context.arrayArena, attribute);
569 	}
570 
571 	/// <alias_decl> ::= "alias" <id> "=" <expr> ";"
572 	AstIndex parse_alias()
573 	{
574 		TokenIndex start = tok.index;
575 		nextToken; // skip "alias"
576 
577 		Identifier aliasId = expectIdentifier();
578 		expectAndConsume(TokenType.EQUAL);
579 
580 		AstIndex initializerIndex = expr(PreferType.no);
581 		expectAndConsume(TokenType.SEMICOLON);
582 
583 		return makeDecl!AliasDeclNode(start, currentScopeIndex, aliasId, initializerIndex);
584 	}
585 
586 	/// Parses expression preferring types, if identifier follows, parses as var/func declaration
587 	AstIndex parse_expr_or_id_decl(ConsumeTerminator consume_terminator, TokenType var_terminator = TokenType.init)
588 	{
589 		TokenIndex start = tok.index;
590 		AstIndex body_start = AstIndex(context.astBuffer.uintLength);
591 		AstIndex expr_or_type = expr(PreferType.yes);
592 
593 		if (tok.type == TokenType.IDENTIFIER)
594 		{
595 			// declaration
596 			return parse_var_func_declaration_after_type(start, body_start, expr_or_type, consume_terminator, var_terminator);
597 		}
598 		else
599 		{
600 			// expression
601 			AstNode* statementNode = context.getAstNode(expr_or_type);
602 			if (consume_terminator) expectAndConsume(var_terminator);
603 			return expr_or_type;
604 		}
605 	}
606 
607 	enum ConsumeTerminator : bool { no, yes }
608 
609 	bool canBeType(AstIndex someExpr)
610 	{
611 		switch(someExpr.astType(context)) with(AstType)
612 		{
613 			case type_basic, type_ptr, type_static_array, type_slice, type_func_sig:
614 			case expr_name_use, expr_member, expr_index, expr_slice:
615 				return true;
616 			default:
617 				return false;
618 		}
619 	}
620 
621 	AstIndex parse_var_func_declaration_after_type(TokenIndex start, AstIndex body_start, AstIndex typeIndex, ConsumeTerminator consume_terminator, TokenType var_terminator)
622 	{
623 		version(print_parse) auto s2 = scop("<func_declaration> / <var_declaration> %s", start);
624 
625 		TokenIndex idPos = tok.index;
626 		Identifier declarationId = expectIdentifier();
627 
628 		if (!canBeType(typeIndex))
629 		{
630 			context.error(idPos,
631 				"Invalid expression. Missing `;` before `%s`", context.idString(declarationId));
632 		}
633 
634 		AstIndex initializerIndex;
635 		if (tok.type == TokenType.EQUAL) // "=" <expression>
636 		{
637 			// <var_decl> = <type> <identifier> ("=" <expression>)? ";"
638 			nextToken; // skip "="
639 			initializerIndex = expr(PreferType.no);
640 		}
641 
642 		if (tok.type == TokenType.SEMICOLON || tok.type == TokenType.COMMA) // <var_declaration> ::= <type> <id> (";" / ",")
643 		{
644 			// variable
645 			version(print_parse) auto s3 = scop("<var_declaration> %s", start);
646 			if (consume_terminator) expectAndConsume(var_terminator);
647 			// leave ";" or "," for parent to decide
648 			AstIndex varIndex = makeDecl!VariableDeclNode(idPos, currentScopeIndex, typeIndex, initializerIndex, declarationId);
649 			return varIndex;
650 		}
651 		else if (tok.type == TokenType.LBRACKET) // <func_declaration> ::= <type> <id> "[" <template_params> "]" "(" <param_list> ")" (<block_statement> / ';')
652 		{
653 			// templated function
654 			AstNodes template_params;
655 			ushort numParamsBeforeVariadic;
656 			parse_template_parameters(template_params, numParamsBeforeVariadic);
657 			AstIndex body = parse_func(idPos, typeIndex, declarationId);
658 			AstIndex after_body = AstIndex(context.astBuffer.uintLength);
659 			return makeDecl!TemplateDeclNode(idPos, currentScopeIndex, template_params, body, body_start, after_body, declarationId, numParamsBeforeVariadic);
660 		}
661 		else if (tok.type == TokenType.LPAREN) // <func_declaration> ::= <type> <id> "(" <param_list> ")" (<block_statement> / ';')
662 		{
663 			// function
664 			return parse_func(idPos, typeIndex, declarationId);
665 		}
666 		else
667 		{
668 			context.unrecoverable_error(tok.index, "Expected '(' or ';', while got '%s'", context.getTokenString(tok.index));
669 		}
670 	}
671 
672 	AstIndex parse_func(TokenIndex start, AstIndex typeIndex, Identifier declarationId)
673 	{
674 		version(print_parse) auto s3 = scop("<func_declaration> %s", start);
675 		AstNodes params;
676 		ushort funcFlags;
677 
678 		// make all attributes apply to both function and the signature
679 		auto beforeAttribState = attribState;
680 
681 		// make all attributes broadcasted, so that they are not removed when function is created
682 		attribState.broadcasted.numBroadcastedAttributes += attribState.immediate.numImmediateAttributes;
683 		attribState.immediate.numImmediateAttributes = 0;
684 		attribState.broadcasted.broadcastedFlagAttributes |= attribState.immediate.immediateFlagAttributes;
685 		attribState.immediate.immediateFlagAttributes = 0;
686 
687 		AstIndex funcIndex = makeDecl!FunctionDeclNode(start, context.getAstNodeIndex(currentModule), ScopeIndex(), AstIndex(), declarationId);
688 		auto func = funcIndex.get!FunctionDeclNode(context);
689 
690 		// no attributes go to the function body or to the parameters
691 		attribState = AttribState.init;
692 
693 		AstIndex prevOwner = declarationOwner;
694 		declarationOwner = funcIndex;
695 		scope(exit) declarationOwner = prevOwner;
696 
697 		ScopeTempData scope_temp = pushScope(context.idString(declarationId), ScopeKind.local);
698 		scope(exit) popScope(scope_temp);
699 
700 		// set scope for a function
701 		ScopeIndex parameterScope = currentScopeIndex;
702 		func.parameterScope = parameterScope;
703 
704 		// add this pointer parameter
705 		if (func.isMember)
706 		{
707 			AstIndex structName = make!NameUseExprNode(start, currentScopeIndex, prevOwner.get!StructDeclNode(context).id);
708 			NameUseExprNode* name = structName.get_name_use(context);
709 			name.resolve(prevOwner, context);
710 			name.flags |= AstFlags.isType;
711 			name.state = AstNodeState.name_resolve_done;
712 			AstIndex thisType = make!PtrTypeNode(start, CommonAstNodes.type_type, structName);
713 
714 			// parameter
715 			AstIndex param = make!VariableDeclNode(start, currentScopeIndex, thisType, AstIndex.init, CommonIds.id_this, ushort(0));
716 			VariableDeclNode* paramNode = param.get!VariableDeclNode(context);
717 			paramNode.flags |= VariableFlags.isParameter;
718 			params.put(context.arrayArena, param);
719 		}
720 
721 		// restore attributes for signature to consume
722 		attribState = beforeAttribState;
723 
724 		CallConvention callConvention = context.defaultCallConvention;
725 		AstIndex signature = makeDecl!FunctionSignatureNode(start, typeIndex, params, callConvention);
726 
727 		// store remaining state back
728 		scope_temp.prevBroadcasted = attribState.broadcasted;
729 		// no attributes go to the parameters and body
730 		attribState = AttribState.init;
731 
732 		parseParameters(signature, NeedRegNames.yes); // functions need to register their param names
733 		func.signature = signature;
734 
735 		currentScopeIndex.get_scope(context).owner = funcIndex;
736 
737 		if (tok.type == TokenType.HASH_INLINE)
738 		{
739 			nextToken; // skip #inline
740 			func.flags |= FuncDeclFlags.isInline;
741 		}
742 
743 		if (tok.type != TokenType.SEMICOLON)
744 		{
745 			func.block_stmt = block_stmt();
746 			signature.flags(context) |= FuncSignatureFlags.attachedToFunctionWithBody;
747 		}
748 		else expectAndConsume(TokenType.SEMICOLON); // external function
749 
750 		return funcIndex;
751 	}
752 
753 	enum NeedRegNames : bool { no, yes }
754 	// if nameReg is `no` parameters are put in name_register_done state
755 	void parseParameters(AstIndex signature, NeedRegNames nameReg)
756 	{
757 		auto sig = signature.get!FunctionSignatureNode(context);
758 		expectAndConsume(TokenType.LPAREN);
759 
760 		ubyte numDefaultArgs = 0;
761 		while (tok.type != TokenType.RPAREN)
762 		{
763 			if (tok.type == TokenType.EOI) break;
764 
765 			// <param> ::= <type> <identifier>?
766 			TokenIndex paramStart = tok.index;
767 			AstIndex paramType = expr(PreferType.yes, 0);
768 			Identifier paramId;
769 			ushort flags = VariableFlags.isParameter;
770 			size_t paramIndex = sig.parameters.length;
771 			AstIndex defaultValue;
772 
773 			if (tok.type == TokenType.DOT_DOT_DOT) // expanded type
774 			{
775 				if (sig.hasExpandedParam) {
776 					context.error(tok.index, "Cannot have two expanded parameters");
777 				}
778 				nextToken; // skip ...
779 				flags |= VariableFlags.isVariadicParam;
780 				sig.flags |= FuncSignatureFlags.hasExpandedParam;
781 				sig.numParamsBeforeVariadic = cast(ushort)paramIndex;
782 			}
783 
784 			if (tok.type == TokenType.IDENTIFIER) // named parameter
785 			{
786 				paramStart = tok.index;
787 				paramId = expectIdentifier();
788 			}
789 			else // anon parameter
790 			{
791 				flags |= VariableFlags.isAnonymous;
792 				paramId = context.idMap.getOrRegFormatted(context, "__param_%s", paramIndex);
793 			}
794 
795 			// default argument
796 			if (tok.type == TokenType.EQUAL)
797 			{
798 				nextToken; // skip =
799 				defaultValue = expr(PreferType.yes, 0);
800 
801 				++sig.numDefaultArgs;
802 			}
803 			else
804 			{
805 				// all default arguments must be at the end of param list
806 				if (sig.numDefaultArgs != 0)
807 					context.error(paramStart,
808 						"Default argument expected for %s", context.idString(paramId));
809 			}
810 
811 			AstIndex param = makeDecl!VariableDeclNode(paramStart, currentScopeIndex, paramType, defaultValue, paramId);
812 			VariableDeclNode* paramNode = param.get!VariableDeclNode(context);
813 			if (paramNode.isGlobal) context.error(paramNode.loc, "Parameters cannot be @static");
814 			paramNode.flags |= flags;
815 			paramNode.scopeIndex = cast(typeof(paramNode.scopeIndex))paramIndex;
816 			if (nameReg == NeedRegNames.no)
817 				paramNode.state = AstNodeState.name_register_nested_done;
818 
819 			sig.parameters.put(context.arrayArena, param);
820 			if (tok.type == TokenType.COMMA) nextToken; // skip ","
821 			else break;
822 		}
823 		if (!sig.hasExpandedParam)
824 			sig.numParamsBeforeVariadic = cast(ushort)sig.parameters.length;
825 
826 		expectAndConsume(TokenType.RPAREN);
827 	}
828 
829 	// 0+ non-variadic params, ? variadic params
830 	void parse_template_parameters(ref AstNodes params, out ushort numParamsBeforeVariadic)
831 	{
832 		expectAndConsume(TokenType.LBRACKET);
833 
834 		bool hasVaridic = false;
835 		while (tok.type != TokenType.RBRACKET)
836 		{
837 			if (tok.type == TokenType.EOI) break;
838 
839 			// <type_param> ::= <identifier>
840 			TokenIndex paramStart = tok.index;
841 			Identifier paramId = expectIdentifier();
842 			ushort paramIndex = cast(ushort)params.length;
843 
844 			AstIndex param = makeDecl!TemplateParamDeclNode(paramStart, paramId, paramIndex);
845 			if (tok.type == TokenType.DOT_DOT_DOT) {
846 				nextToken; // skip "..."
847 				param.flags(context) |= TemplateParamDeclFlags.isVariadic;
848 				if (hasVaridic) {
849 					context.error(param.loc(context),
850 						"Only single variadic template parameter allowed");
851 				}
852 				hasVaridic = true;
853 				numParamsBeforeVariadic = paramIndex;
854 			}
855 			else
856 			{
857 				// In the future we may allow non-variadic template params after variadic one
858 				if (hasVaridic)
859 					context.error(param.loc(context),
860 						"Cannot have template parameters after variadic parameter (WIP)");
861 			}
862 
863 			params.put(context.arrayArena, param);
864 
865 			if (tok.type == TokenType.COMMA) nextToken; // skip ","
866 			else break;
867 		}
868 
869 		if (!hasVaridic) numParamsBeforeVariadic = cast(ushort)params.length;
870 
871 		expectAndConsume(TokenType.RBRACKET);
872 	}
873 
874 	ushort parse_argument_list(ref AstNodes expressions)
875 	{
876 		ushort flags;
877 		// COMMA_PREC is used in `expr` because we don't want to grab the comma, e.g. it is NOT a sequence operator.
878 		while (tok.type != TokenType.RPAREN)
879 		{
880 			AstIndex exprIndex;
881 			if (tok.type == TokenType.IDENTIFIER)
882 			{
883 				Token idToken = tok;
884 				nextToken; // skip id
885 				if (tok.type == TokenType.COLON)
886 				{
887 					flags |= CallExprFlags.hasNamedArgs;
888 					// named argument
889 					nextToken; // skip :
890 					Identifier paramId = makeIdentifier(idToken.index);
891 					AstIndex child = expr(PreferType.no, COMMA_PREC);
892 					exprIndex = make!NamedArgumenExprNode(idToken.index, paramId, child);
893 				}
894 				else
895 				{
896 					// regular expression, undo identifier
897 					tok = idToken;
898 					exprIndex = expr(PreferType.no, COMMA_PREC);
899 				}
900 			}
901 			else
902 			{
903 				exprIndex = expr(PreferType.no, COMMA_PREC);
904 			}
905 			expressions.put(context.arrayArena, exprIndex);
906 
907 			// allows trailing comma too
908 			if (tok.type == TokenType.COMMA)
909 				nextToken;
910 		}
911 		expectAndConsume(TokenType.RPAREN);
912 		return flags;
913 	}
914 
915 	// <struct_declaration> ::= "struct" <id> ("[" <template_params> "]")? "{" <declaration>* "}" /
916 	//                          "struct" <id> ("[" <template_params> "]")? ";"
917 	AstIndex parse_struct()
918 	{
919 		ushort structFlags;
920 		if (tok.type == TokenType.UNION_SYM) {
921 			structFlags |= StructFlags.isUnion;
922 		}
923 
924 		TokenIndex start = tok.index;
925 		AstIndex body_start = AstIndex(context.astBuffer.uintLength);
926 
927 		version(print_parse) auto s2 = scop("struct %s", start);
928 		nextToken; // skip "struct"
929 		Identifier structId = expectIdentifier();
930 
931 		AstIndex parse_rest()
932 		{
933 			if (tok.type == TokenType.SEMICOLON)
934 			{
935 				nextToken; // skip semicolon
936 				AstIndex structIndex = makeDecl!StructDeclNode(start, currentScopeIndex, ScopeIndex(), structId);
937 				StructDeclNode* s = structIndex.get!StructDeclNode(context);
938 				s.flags |= structFlags | StructFlags.isOpaque;
939 				return structIndex;
940 			}
941 
942 			AstIndex structIndex = makeDecl!StructDeclNode(start, currentScopeIndex, ScopeIndex(), structId);
943 			StructDeclNode* s = structIndex.get!StructDeclNode(context);
944 			s.flags |= structFlags;
945 
946 			ScopeTempData scope_temp = pushScope(context.idString(structId), ScopeKind.member);
947 			scope(exit) popScope(scope_temp);
948 
949 			s.memberScope = currentScopeIndex;
950 
951 			// no attributes go to the body
952 			attribState = AttribState.init;
953 
954 			expectAndConsume(TokenType.LCURLY);
955 			{
956 				AstIndex prevOwner = declarationOwner;
957 				declarationOwner = structIndex;
958 				scope(exit) declarationOwner = prevOwner;
959 
960 				parse_declarations(s.declarations, TokenType.RCURLY);
961 
962 				ushort varIndex = 0;
963 				foreach(AstIndex declIndex; s.declarations) {
964 					AstNode* declNode = context.getAstNode(declIndex);
965 					if (declNode.astType == AstType.decl_var) {
966 						declNode.as!VariableDeclNode(context).scopeIndex = varIndex++;
967 					}
968 				}
969 			}
970 			expectAndConsume(TokenType.RCURLY);
971 
972 			return structIndex;
973 		}
974 
975 		AstNodes template_params;
976 		if (tok.type == TokenType.LBRACKET) // <func_declaration> ::= "struct" <id> "[" <template_params> "]"
977 		{
978 			ushort numParamsBeforeVariadic;
979 			parse_template_parameters(template_params, numParamsBeforeVariadic);
980 			AstIndex body = parse_rest();
981 			AstIndex after_body = AstIndex(context.astBuffer.uintLength);
982 			return makeDecl!TemplateDeclNode(start, currentScopeIndex, template_params, body, body_start, after_body, structId, numParamsBeforeVariadic);
983 		}
984 
985 		return parse_rest();
986 	}
987 
988 	// <enum_decl> = <enum_decl_single> / <enum_decl_multi>
989 	// <enum_decl_multi> = "enum" [<identifier>] [":" <type>] {" <identifier> ["=" <expr>] ,* "}"
990 	// <enum_decl_single> = "enum" <identifier> [ "=" <expr> ] ";"
991 
992 	// enum i32 e2; // manifest constant, invalid, need initializer
993 	// enum e3 = 3; // manifest constant
994 	// enum i32 e4 = 4; // manifest constant
995 
996 	// enum { e5 } // anon type
997 	// enum : i32 { e6 } // anon type
998 
999 	// enum e1; // type
1000 	// enum e7 : i32 { e7 } // type
1001 	// enum e8 : i32; // type, body omitted
1002 	// enum e9 { e9 } // type
1003 	AstIndex parse_enum()
1004 	{
1005 		TokenIndex start = tok.index;
1006 		nextToken; // slip `enum`
1007 
1008 		AstIndex intType = CommonAstNodes.type_i32;
1009 
1010 		AstIndex parseColonType()
1011 		{
1012 			nextToken; // skip ":"
1013 			AstIndex type = expr(PreferType.yes, 0);
1014 			if (!type)
1015 				context.unrecoverable_error(tok.index,
1016 					"Expected type after `enum :`, while got `%s`", context.getTokenString(tok.index));
1017 
1018 			return type;
1019 		}
1020 
1021 		AstNodes tryParseEnumBody(AstIndex type)
1022 		{
1023 			if (tok.type == TokenType.SEMICOLON) {
1024 				nextToken; // skip ";"
1025 				return AstNodes();
1026 			} else if (tok.type == TokenType.LCURLY) {
1027 				return parse_enum_body(type);
1028 			} else {
1029 				context.unrecoverable_error(tok.index,
1030 					"Expected `;` or `{` at the end of enum declaration, while got `%s`",
1031 					context.getTokenString(tok.index));
1032 			}
1033 		}
1034 
1035 		// enum T e4 = initializer;
1036 		AstIndex parseTypeEnum()
1037 		{
1038 			AstIndex type = expr(PreferType.yes, 0);
1039 			if (!type)
1040 				context.unrecoverable_error(tok.index,
1041 					"Expected type after `enum`, while got `%s`",
1042 					context.getTokenString(tok.index));
1043 
1044 			Identifier enumId = expectIdentifier;
1045 			expectAndConsume(TokenType.EQUAL); // "="
1046 			AstIndex value = expr(PreferType.no); // initializer
1047 
1048 			auto member = makeDecl!EnumMemberDecl(start, currentScopeIndex, type, value, enumId);
1049 
1050 			expectAndConsume(TokenType.SEMICOLON); // ";"
1051 
1052 			// enum i32 e4 = 4;
1053 			return member;
1054 		}
1055 
1056 		// can be both enum identifier and type identifier
1057 		if (tok.type == TokenType.IDENTIFIER)
1058 		{
1059 			Token copy = tok; // save
1060 			TokenIndex id = tok.index;
1061 			nextToken; // skip identifier
1062 
1063 			// enum type with no type or body
1064 			// enum e1;
1065 			if (tok.type == TokenType.SEMICOLON)
1066 			{
1067 				nextToken; // skip ";"
1068 				Identifier enumId = makeIdentifier(id);
1069 				ScopeIndex memberScope; // no scope
1070 
1071 				return makeDecl!EnumDeclaration(start, currentScopeIndex, memberScope, AstNodes(), intType, enumId);
1072 			}
1073 			else if (tok.type == TokenType.EQUAL)
1074 			{
1075 				nextToken; // skip "="
1076 				Identifier enumId = makeIdentifier(id);
1077 				AstIndex value = expr(PreferType.no);
1078 				// type will be taken from initializer
1079 				auto member = make!EnumMemberDecl(start, currentScopeIndex, AstIndex.init, value, enumId);
1080 
1081 				expectAndConsume(TokenType.SEMICOLON); // ";"
1082 
1083 				// enum e3 = 3;
1084 				return member;
1085 			}
1086 			// enum e7 : i32 ...
1087 			else if (tok.type == TokenType.COLON)
1088 			{
1089 				Identifier enumId = makeIdentifier(id);
1090 				AstIndex memberType = parseColonType;
1091 				ScopeTempData scope_temp = pushScope(context.idString(enumId), ScopeKind.member);
1092 				ScopeIndex memberScope = currentScopeIndex;
1093 				AstIndex enumIndex = makeDecl!EnumDeclaration(start, ScopeIndex.init, memberScope, AstNodes.init, memberType, enumId);
1094 				currentScopeIndex.get_scope(context).owner = enumIndex;
1095 				auto enumNode = enumIndex.get!EnumDeclaration(context);
1096 				AstNodes members = tryParseEnumBody(enumIndex);
1097 				popScope(scope_temp);
1098 				enumNode.declarations = members;
1099 				enumNode.parentScope = currentScopeIndex;
1100 
1101 				// enum e7 : i32 { e7 }
1102 				// enum e8 : i32;
1103 				return enumIndex;
1104 			}
1105 			else if (tok.type == TokenType.LCURLY)
1106 			{
1107 				Identifier enumId = makeIdentifier(id);
1108 				AstIndex memberType = intType;
1109 				ScopeTempData scope_temp = pushScope(context.idString(enumId), ScopeKind.member);
1110 				ScopeIndex memberScope = currentScopeIndex;
1111 				AstIndex enumIndex = makeDecl!EnumDeclaration(start, ScopeIndex.init, memberScope, AstNodes.init, memberType, enumId);
1112 				currentScopeIndex.get_scope(context).owner = enumIndex;
1113 				auto enumNode = enumIndex.get!EnumDeclaration(context);
1114 				AstNodes members = parse_enum_body(enumIndex);
1115 				popScope(scope_temp);
1116 				enumNode.declarations = members;
1117 				enumNode.parentScope = currentScopeIndex;
1118 
1119 				// enum e9 { e9 }
1120 				return enumIndex;
1121 			}
1122 			else
1123 			{
1124 				tok = copy; // restore
1125 				return parseTypeEnum;
1126 			}
1127 		}
1128 		else if (tok.type == TokenType.COLON)
1129 		{
1130 			AstIndex memberType = parseColonType;
1131 			AstNodes members = parse_enum_body(memberType);
1132 			ScopeIndex memberScope; // no scope
1133 
1134 			// enum : i32 { e6 }
1135 			return makeDecl!EnumDeclaration(start, currentScopeIndex, memberScope, members, memberType);
1136 		}
1137 		else if (tok.type == TokenType.LCURLY)
1138 		{
1139 			AstIndex memberType = intType;
1140 			AstNodes members = parse_enum_body(memberType);
1141 			ScopeIndex memberScope; // no scope
1142 
1143 			// enum { e5 }
1144 			return makeDecl!EnumDeclaration(start, currentScopeIndex, memberScope, members, memberType);
1145 		}
1146 		else if (isBasicTypeToken(tok.type))
1147 		{
1148 			return parseTypeEnum;
1149 		}
1150 		else
1151 		{
1152 			context.unrecoverable_error(tok.index,
1153 				"Invalid enum declaration, got %s after `enum`",
1154 				context.getTokenString(tok.index));
1155 		}
1156 	}
1157 
1158 	AstIndex parse_import()
1159 	{
1160 		TokenIndex start = tok.index;
1161 		version(print_parse) auto s = scop("import %s", start);
1162 		nextToken; // skip "import"
1163 		Identifier id;
1164 
1165 		while (true) {
1166 			string after = id.isDefined ? "import" : null;
1167 			id = context.idMap.getOrRegFqn(context, FullyQualifiedName(id, expectIdentifier(after)));
1168 
1169 			if (tok.type == TokenType.DOT) {
1170 				nextToken; // skip "."
1171 			} else if (tok.type == TokenType.SEMICOLON) {
1172 				nextToken; // skip ";"
1173 				break;
1174 			} else {
1175 				context.unrecoverable_error(tok.index,
1176 					"Expected `;` or `.` after identifier, while got `%s`",
1177 					context.getTokenString(tok.index));
1178 			}
1179 		}
1180 		return makeDecl!ImportDeclNode(start, currentScopeIndex, id);
1181 	}
1182 
1183 	void parse_module_decl()
1184 	{
1185 		TokenIndex start = tok.index;
1186 		AstIndex parentPackage = CommonAstNodes.node_root_package;
1187 		AstIndex conflictingModule;
1188 		AstIndex conflictingModPack;
1189 
1190 		// module declaration
1191 		if (tok.type == TokenType.MODULE_SYM)
1192 		{
1193 			nextToken; // skip "module"
1194 
1195 			Identifier lastId;
1196 			while (true) {
1197 				Identifier newId = expectIdentifier();
1198 				lastId = context.idMap.getOrRegFqn(context, FullyQualifiedName(lastId, newId));
1199 
1200 				if (tok.type == TokenType.DOT) {
1201 					nextToken; // skip "."
1202 					auto parentPackageNode = parentPackage.get!PackageDeclNode(context);
1203 					parentPackage = parentPackageNode.getOrCreateSubpackage(start, lastId, conflictingModule, context);
1204 				} else if (tok.type == TokenType.SEMICOLON) {
1205 					nextToken; // skip ";"
1206 					currentModule.fqn = lastId;
1207 					break;
1208 				} else {
1209 					context.unrecoverable_error(tok.index,
1210 						"Expected `;` or `.` after identifier, while got `%s`",
1211 						context.getTokenString(tok.index));
1212 				}
1213 			}
1214 
1215 			currentModule.loc = start;
1216 		}
1217 		else
1218 		{
1219 			currentModule.loc = context.files[currentModule.moduleIndex.fileIndex].firstTokenIndex;
1220 		}
1221 
1222 		currentModule.parentPackage = parentPackage;
1223 		auto parentPackageNode = parentPackage.get!PackageDeclNode(context);
1224 		parentPackageNode.addModule(start, currentModule.fqn, context.getAstNodeIndex(currentModule), conflictingModPack, context);
1225 		context.modules.put(context.arrayArena, currentModule.fqn, context.getAstNodeIndex(currentModule));
1226 		void modConflict(ModuleDeclNode* newMod, ModuleDeclNode* oldMod)
1227 		{
1228 			context.error(newMod.loc,
1229 				"Module `%s` in file %s conflicts with another module `%s` in file %s",
1230 				newMod.fqn.pr(context),
1231 				context.files[newMod.moduleIndex.fileIndex].name,
1232 				oldMod.fqn.pr(context),
1233 				context.files[oldMod.moduleIndex.fileIndex].name, );
1234 		}
1235 
1236 		void modPackConflict(ModuleDeclNode* newMod, PackageDeclNode* oldPack)
1237 		{
1238 			context.error(newMod.loc,
1239 				"Module `%s` in file %s conflicts with package `%s` in files %s",
1240 				newMod.fqn.pr(context),
1241 				context.files[newMod.moduleIndex.fileIndex].name,
1242 				oldPack.fqn.pr(context),
1243 				PackageFilesPrinter(oldPack, context));
1244 		}
1245 
1246 		if (conflictingModule.isDefined) {
1247 			modConflict(currentModule, conflictingModule.get!ModuleDeclNode(context));
1248 		}
1249 
1250 		if (conflictingModPack.isDefined) {
1251 			AstNode* conflictingNode = conflictingModPack.get_node(context);
1252 			if (conflictingNode.astType == AstType.decl_module) {
1253 				modConflict(currentModule, conflictingNode.as!ModuleDeclNode(context));
1254 				// module foo from file bar.d conflicts with another module foo from file foo.d
1255 			} else {
1256 				context.assertf(conflictingNode.astType == AstType.decl_package, "Must be package");
1257 				modPackConflict(currentModule, conflictingNode.as!PackageDeclNode(context));
1258 			}
1259 		}
1260 	}
1261 
1262 	AstIndex parse_hash_assert() /* "#assert(" <condition>, <message> ");"*/
1263 	{
1264 		TokenIndex start = tok.index;
1265 		nextToken; // skip "#assert"
1266 
1267 		if (tok.type != TokenType.LPAREN)
1268 			context.unrecoverable_error(tok.index,
1269 				"Expected `(` after #assert, while got `%s`",
1270 				context.getTokenString(tok.index));
1271 		nextToken; // skip (
1272 
1273 		AstIndex condition = expr(PreferType.no);
1274 		AstIndex message;
1275 
1276 		if (tok.type != TokenType.RPAREN)
1277 		{
1278 			if (tok.type != TokenType.COMMA)
1279 				context.unrecoverable_error(tok.index,
1280 					"Expected `,` after condition of #assert, while got `%s`",
1281 					context.getTokenString(tok.index));
1282 
1283 			nextToken; // skip ,
1284 
1285 			message = expr(PreferType.no);
1286 		}
1287 
1288 		if (tok.type != TokenType.RPAREN)
1289 			context.unrecoverable_error(tok.index,
1290 				"Expected `)` after message of #assert, while got `%s`",
1291 				context.getTokenString(tok.index));
1292 		nextToken; // skip )
1293 
1294 		if (tok.type != TokenType.SEMICOLON)
1295 			context.unrecoverable_error(tok.index,
1296 				"Expected `;` after #assert, while got `%s`",
1297 				context.getTokenString(tok.index));
1298 		nextToken; // skip ;
1299 
1300 		return make!StaticAssertDeclNode(start, condition, message);
1301 	}
1302 
1303 	void parseItems(alias itemParser)(ref AstNodes items, ScopeKind scopeKind)
1304 	{
1305 		TokenIndex start = tok.index;
1306 		if (tok.type == TokenType.LCURLY)
1307 		{
1308 			nextToken; // skip {
1309 			ScopeTempData scope_temp = pushScope(null, scopeKind);
1310 			while (tok.type != TokenType.RCURLY)
1311 			{
1312 				if (tok.type == TokenType.EOI) break;
1313 				itemParser(items);
1314 			}
1315 			popScope(scope_temp);
1316 			expectAndConsume(TokenType.RCURLY);
1317 		}
1318 		else
1319 		{
1320 			itemParser(items);
1321 		}
1322 	}
1323 
1324 	void parseStaticIfThenElse(ref AstNodes thenStatements, ref AstNodes elseStatements)
1325 	{
1326 		if (declarationOwner.astType(context) == AstType.decl_function)
1327 		{
1328 			parseItems!statement(thenStatements, ScopeKind.no_scope);
1329 			if (tok.type == TokenType.ELSE_SYM) { /* ... "else" <statement> */
1330 				nextToken; // skip else
1331 				parseItems!statement(elseStatements, ScopeKind.no_scope);
1332 			}
1333 		}
1334 		else
1335 		{
1336 			parseItems!parse_declaration(thenStatements, ScopeKind.no_scope);
1337 			if (tok.type == TokenType.ELSE_SYM) { /* ... "else" <decl> */
1338 				nextToken; // skip else
1339 				parseItems!parse_declaration(elseStatements, ScopeKind.no_scope);
1340 			}
1341 		}
1342 	}
1343 
1344 	AstIndex parse_hash_if() /* "#if/#version" <paren_expr> <statement/decl> */
1345 	{
1346 		TokenIndex start = tok.index;
1347 		if (tok.type == TokenType.HASH_IF)
1348 		{
1349 			nextToken; // skip #if
1350 			AstIndex condition = paren_expr();
1351 			AstNodes thenStatements;
1352 			AstNodes elseStatements;
1353 			parseStaticIfThenElse(thenStatements, elseStatements);
1354 			return make!StaticIfDeclNode(start, AstIndex.init, AstIndex.init, 0, condition, thenStatements, elseStatements);
1355 		}
1356 		else
1357 		{
1358 			nextToken; // skip #version
1359 			expectAndConsume(TokenType.LPAREN, "#version");
1360 			Identifier versionId = expectIdentifier("#version(");
1361 			expectAndConsume(TokenType.RPAREN, "#version(id");
1362 			AstNodes thenStatements;
1363 			AstNodes elseStatements;
1364 			parseStaticIfThenElse(thenStatements, elseStatements);
1365 			return make!StaticVersionDeclNode(start, AstIndex.init, AstIndex.init, 0, versionId, thenStatements, elseStatements);
1366 		}
1367 	}
1368 
1369 	AstIndex parse_hash_foreach() /* "#foreach" "(" [<index_id>], <val_id> ";" <ct_expr> ")" <statement> */
1370 	{
1371 		TokenIndex start = tok.index;
1372 		nextToken; // skip "#foreach"
1373 
1374 		expectAndConsume(TokenType.LPAREN); // (
1375 
1376 		AstNodes init_statements;
1377 
1378 		// <init>
1379 		Identifier keyId = expectIdentifier;
1380 		Identifier valId;
1381 		if (tok.type == TokenType.COMMA)
1382 		{
1383 			nextToken; // skip ","
1384 			valId = expectIdentifier;
1385 			expectAndConsume(TokenType.SEMICOLON);
1386 		}
1387 		else if (tok.type == TokenType.SEMICOLON)
1388 		{
1389 			valId = keyId;
1390 			keyId = Identifier.init;
1391 			expectAndConsume(TokenType.SEMICOLON);
1392 		}
1393 		else
1394 		{
1395 			context.unrecoverable_error(tok.index,
1396 				"Expected `;` after key and value of #foreach, instead got `%s`",
1397 				context.getTokenString(tok.index));
1398 		}
1399 
1400 		// <ct_expr>
1401 		AstIndex ct_expr = expr(PreferType.no);
1402 		expectAndConsume(TokenType.RPAREN);
1403 
1404 		AstIndex body_start = AstIndex(context.astBuffer.uintLength);
1405 		AstNodes body;
1406 		statement_as_array(body);
1407 		AstIndex after_body = AstIndex(context.astBuffer.uintLength);
1408 		return make!StaticForeachDeclNode(start, AstIndex.init, AstIndex.init, 0, currentScopeIndex, keyId, valId, ct_expr, body, body_start, after_body);
1409 	}
1410 
1411 	AstNodes parse_enum_body(AstIndex type) { // { id [= val], ... }
1412 		expectAndConsume(TokenType.LCURLY);
1413 		AstNodes members;
1414 		ushort varIndex = 0;
1415 		while (tok.type != TokenType.RCURLY)
1416 		{
1417 			if (tok.type == TokenType.EOI) break;
1418 
1419 			TokenIndex start = tok.index;
1420 			Identifier id = expectIdentifier;
1421 			AstIndex value;
1422 
1423 			if (tok.type == TokenType.EQUAL)
1424 			{
1425 				nextToken; // skip "="
1426 				value = expr(PreferType.no);
1427 			}
1428 
1429 			auto member = makeDecl!EnumMemberDecl(start, currentScopeIndex, type, value, id);
1430 			EnumMemberDecl* memberNode = context.getAst!EnumMemberDecl(member);
1431 			memberNode.scopeIndex = varIndex++;
1432 			members.put(context.arrayArena, member);
1433 
1434 			if (tok.type == TokenType.COMMA) {
1435 				nextToken; // skip ","
1436 			} else break;
1437 		}
1438 		expectAndConsume(TokenType.RCURLY);
1439 		return members;
1440 	}
1441 
1442 	void parse_block(ref AstNodes statements) // "{" <statement>* "}"
1443 	{
1444 		expectAndConsume(TokenType.LCURLY);
1445 		while (tok.type != TokenType.RCURLY)
1446 		{
1447 			if (tok.type == TokenType.EOI) break;
1448 			statement(statements);
1449 		}
1450 		expectAndConsume(TokenType.RCURLY);
1451 	}
1452 
1453 	AstIndex block_stmt() // <block_statement> ::= "{" <statement>* "}"
1454 	{
1455 		version(print_parse) auto s1 = scop("block_stmt %s", loc);
1456 		TokenIndex start = tok.index;
1457 		ScopeTempData scope_temp = pushScope("Block", ScopeKind.local);
1458 		AstNodes statements;
1459 		parse_block(statements);
1460 		popScope(scope_temp);
1461 		return make!BlockStmtNode(start, statements);
1462 	}
1463 
1464 	void statement_as_array(ref AstNodes statements)
1465 	{
1466 		if (tok.type == TokenType.LCURLY)
1467 		{
1468 			parse_block(statements);
1469 		}
1470 		else
1471 		{
1472 			statement(statements);
1473 		}
1474 	}
1475 
1476 	void statement(ref AstNodes items)
1477 	{
1478 		version(print_parse) auto s1 = scop("statement %s", loc);
1479 		TokenIndex start = tok.index;
1480 		switch (tok.type)
1481 		{
1482 			// declarations
1483 			case TokenType.ALIAS_SYM:
1484 				items.put(context.arrayArena, parse_alias());
1485 				return;
1486 			case TokenType.STRUCT_SYM, TokenType.UNION_SYM:
1487 				items.put(context.arrayArena, parse_struct());
1488 				return;
1489 			case TokenType.ENUM:
1490 				items.put(context.arrayArena, parse_enum());
1491 				return;
1492 			case TokenType.IMPORT_SYM:
1493 				items.put(context.arrayArena, parse_import());
1494 				return;
1495 			case TokenType.HASH_IF, TokenType.HASH_VERSION:
1496 				items.put(context.arrayArena, parse_hash_if());
1497 				return;
1498 			case TokenType.HASH_ASSERT:
1499 				items.put(context.arrayArena, parse_hash_assert());
1500 				return;
1501 			case TokenType.HASH_FOREACH:
1502 				items.put(context.arrayArena, parse_hash_foreach());
1503 				return;
1504 
1505 			// statements
1506 			case TokenType.IF_SYM: /* "if" <paren_expr> <statement> */
1507 				nextToken;
1508 				AstIndex condition = paren_expr();
1509 				ScopeTempData scope_temp = pushScope("Then", ScopeKind.local);
1510 				AstNodes thenStatements;
1511 				statement_as_array(thenStatements);
1512 				popScope(scope_temp);
1513 				AstNodes elseStatements;
1514 				if (tok.type == TokenType.ELSE_SYM) { /* ... "else" <statement> */
1515 					nextToken;
1516 					ScopeTempData scope_temp2 = pushScope("Else", ScopeKind.local);
1517 					statement_as_array(elseStatements);
1518 					popScope(scope_temp2);
1519 				}
1520 				AstIndex stmt = make!IfStmtNode(start, condition, thenStatements, elseStatements);
1521 				items.put(context.arrayArena, stmt);
1522 				return;
1523 			case TokenType.WHILE_SYM:  /* "while" <paren_expr> <statement> */
1524 				nextToken;
1525 				ScopeTempData scope_temp = pushScope("While", ScopeKind.local);
1526 				AstIndex condition = paren_expr();
1527 				AstNodes statements;
1528 				statement_as_array(statements);
1529 				popScope(scope_temp);
1530 				AstIndex stmt = make!WhileStmtNode(start, condition, statements);
1531 				items.put(context.arrayArena, stmt);
1532 				return;
1533 			case TokenType.DO_SYM:  /* "do" <statement> "while" <paren_expr> ";" */
1534 				nextToken;
1535 				ScopeTempData scope_temp = pushScope("do", ScopeKind.local);
1536 				AstNodes statements;
1537 				statement_as_array(statements);
1538 				expectAndConsume(TokenType.WHILE_SYM);
1539 				AstIndex condition = paren_expr();
1540 				popScope(scope_temp);
1541 				expectAndConsume(TokenType.SEMICOLON);
1542 				AstIndex stmt = make!DoWhileStmtNode(start, condition, statements);
1543 				items.put(context.arrayArena, stmt);
1544 				return;
1545 			case TokenType.FOR_SYM:  /* "for" "(" <statement> ";" <statement> ";" "while" <paren_expr> ";" */
1546 				items.put(context.arrayArena, parse_for());
1547 				return;
1548 			case TokenType.SWITCH_SYM:
1549 				items.put(context.arrayArena, parse_switch());
1550 				return;
1551 			case TokenType.RETURN_SYM:  /* return <expr> */
1552 				nextToken;
1553 				AstIndex expression = tok.type != TokenType.SEMICOLON ? expr(PreferType.no) : AstIndex.init;
1554 				expectAndConsume(TokenType.SEMICOLON);
1555 				context.assertf(declarationOwner.isDefined && declarationOwner.astType(context) == AstType.decl_function, start, "Return statement is not inside function");
1556 				AstIndex stmt = make!ReturnStmtNode(start, declarationOwner, expression);
1557 				items.put(context.arrayArena, stmt);
1558 				return;
1559 			case TokenType.BREAK_SYM:  /* break; */
1560 				nextToken;
1561 				expectAndConsume(TokenType.SEMICOLON);
1562 				AstIndex stmt = make!BreakStmtNode(start);
1563 				items.put(context.arrayArena, stmt);
1564 				return;
1565 			case TokenType.CONTINUE_SYM:  /* continue; */
1566 				nextToken;
1567 				expectAndConsume(TokenType.SEMICOLON);
1568 				AstIndex stmt = make!ContinueStmtNode(start);
1569 				items.put(context.arrayArena, stmt);
1570 				return;
1571 			case TokenType.SEMICOLON:  /* ";" */
1572 				context.error(tok.index, "Cannot use `;` as an empty statement. Use `{}` instead");
1573 				nextToken;
1574 				return;
1575 			case TokenType.LCURLY:  /* "{" { <statement> } "}" */
1576 				items.put(context.arrayArena, block_stmt());
1577 				return;
1578 			case TokenType.AT:
1579 				parse_attribute(items);
1580 				return;
1581 			case TokenType.TYPE_AUTO:
1582 				parse_auto_decl(items);
1583 				return;
1584 			default:
1585 			{
1586 				// expression or var/func declaration
1587 				version(print_parse) auto s2 = scop("default %s", loc);
1588 				// <expr> ";" / var decl / func decl
1589 				AstIndex expression = parse_expr_or_id_decl(ConsumeTerminator.yes, TokenType.SEMICOLON);
1590 				items.put(context.arrayArena, expression);
1591 				return;
1592 			}
1593 		}
1594 	}
1595 
1596 	void parse_auto_decl(ref AstNodes items)
1597 	{
1598 		TokenIndex start = tok.index;
1599 		AstIndex body_start = AstIndex(context.astBuffer.uintLength);
1600 		nextToken; // skip auto
1601 		AstIndex declIndex = parse_var_func_declaration_after_type(start, body_start, CommonAstNodes.type_auto, ConsumeTerminator.yes, TokenType.SEMICOLON);
1602 		AstNode* declNode = declIndex.get_node(context);
1603 		switch(declNode.astType)
1604 		{
1605 			case AstType.decl_var:
1606 				if (declNode.as!VariableDeclNode(context).initializer.isUndefined) {
1607 					context.error(declNode.loc, "variables declared as `auto` must have an initializer");
1608 				}
1609 				break;
1610 			case AstType.decl_template:
1611 			case AstType.decl_function:
1612 				context.error(declNode.loc, "functions cannot return `auto`");
1613 				break;
1614 			default:
1615 				context.internal_error(declNode.loc, "auto declaration of %s", declNode.astType);
1616 		}
1617 		items.put(context.arrayArena, declIndex);
1618 	}
1619 
1620 	AstIndex parse_for() // "for" "(" <init>,... ";" <cond> ";" <increment> ")" <statement>
1621 	{
1622 		TokenIndex start = tok.index;
1623 		nextToken; // skip "for"
1624 
1625 		expectAndConsume(TokenType.LPAREN); // (
1626 
1627 		ScopeTempData scope_temp = pushScope("For", ScopeKind.local);
1628 		scope(exit) popScope(scope_temp);
1629 
1630 		AstNodes init_statements;
1631 
1632 		// <init>
1633 		while (tok.type != TokenType.SEMICOLON) // check after trailing comma
1634 		{
1635 			AstIndex init_stmt = parse_expr_or_id_decl(ConsumeTerminator.no);
1636 			init_statements.put(context.arrayArena, init_stmt);
1637 
1638 			if (tok.type == TokenType.COMMA)
1639 				nextToken; // skip ","
1640 			else break;
1641 		}
1642 		expectAndConsume(TokenType.SEMICOLON);
1643 
1644 		// <cond>
1645 		AstIndex condition;
1646 		if (tok.type != TokenType.SEMICOLON) {
1647 			condition = expr(PreferType.no);
1648 		}
1649 		expectAndConsume(TokenType.SEMICOLON);
1650 
1651 		AstNodes increment_statements;
1652 		// <increment>
1653 		while (tok.type != TokenType.RPAREN) // check after trailing comma
1654 		{
1655 			AstIndex incExpr = expr(PreferType.no);
1656 			AstNode* incExprNode = context.getAstNode(incExpr);
1657 			increment_statements.put(context.arrayArena, incExpr);
1658 
1659 			if (tok.type == TokenType.COMMA)
1660 				nextToken; // skip ","
1661 			else break;
1662 		}
1663 		expectAndConsume(TokenType.RPAREN);
1664 
1665 		AstNodes statements;
1666 		statement_as_array(statements);
1667 
1668 		return make!ForStmtNode(start, init_statements, condition, increment_statements, statements);
1669 	}
1670 
1671 	AstIndex parse_switch() /* "switch" "(" <expr> ")" "{" <switch_case> "}" */
1672 	{
1673 		TokenIndex start = tok.index;
1674 		nextToken; // skip "switch"
1675 
1676 		AstIndex condition = paren_expr();
1677 
1678 		Array!SwitchCase cases;
1679 		AstIndex elseBlock;
1680 		expectAndConsume(TokenType.LCURLY);
1681 		while (tok.type != TokenType.RCURLY)
1682 		{
1683 			if (tok.type == TokenType.EOI) break;
1684 
1685 			// case expression
1686 			if (tok.type != TokenType.ELSE_SYM) /* <expr> <block> */
1687 			{
1688 				auto expr = expr(PreferType.no);
1689 				auto block = block_stmt();
1690 				cases.put(context.arrayArena, SwitchCase(expr, block));
1691 			}
1692 			else /* "else" <block> */
1693 			{
1694 				nextToken; // skip "else"
1695 				if (elseBlock.isDefined)
1696 				{
1697 					// todo: error
1698 					// must occur 0 or 1 times
1699 				}
1700 				elseBlock = block_stmt();
1701 			}
1702 		}
1703 		expectAndConsume(TokenType.RCURLY);
1704 
1705 		return make!SwitchStmtNode(start, condition, elseBlock, cases);
1706 	}
1707 
1708 	AstIndex paren_expr() { /* <paren_expr> ::= "(" <expr> ")" */
1709 		version(print_parse) auto s1 = scop("paren_expr %s", loc);
1710 		expectAndConsume(TokenType.LPAREN);
1711 		auto res = expr(PreferType.no);
1712 		expectAndConsume(TokenType.RPAREN);
1713 		return res;
1714 	}
1715 
1716 	AstIndex expr(PreferType preferType, int rbp = 0)
1717 	{
1718 		Token t = tok;
1719 		nextToken;
1720 
1721 		NullInfo null_info = g_tokenLookups.null_lookup[t.type];
1722 		AstIndex node = null_info.parser_null(this, preferType, t, null_info.rbp);
1723 		int nbp = null_info.nbp; // next bp
1724 		int lbp = g_tokenLookups.left_lookup[tok.type].lbp;
1725 		//writefln("%s %s rbp %s lbp %s nbp %s", t, tok, rbp, lbp, nbp);
1726 
1727 		while (rbp < lbp && lbp < nbp)
1728 		{
1729 			t = tok;
1730 			nextToken;
1731 			LeftInfo left_info = g_tokenLookups.left_lookup[t.type];
1732 			nbp = left_info.nbp; // next bp
1733 			// parser can modify nbp in case infix operator want to become postfix, like *
1734 			node = left_info.parser_left(this, preferType, t, left_info.rbp, node, nbp);
1735 			lbp = g_tokenLookups.left_lookup[tok.type].lbp;
1736 			//writefln("%s %s rbp %s lbp %s nbp %s", t, tok, rbp, lbp, nbp);
1737 		}
1738 
1739 		return node;
1740 	}
1741 }
1742 
1743 /// Controls the expression parser
1744 /// Forces * expression to be parsed as pointer type
1745 /// Disables slice parsing for [] expression
1746 enum PreferType : bool {
1747 	no = false,
1748 	yes = true,
1749 }
1750 
1751 /// min and max binding powers
1752 enum MIN_BP = 0;
1753 enum MAX_BP = 10000;
1754 enum COMMA_PREC = 10;
1755 
1756 alias LeftParser = AstIndex function(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex left, ref int nbp);
1757 alias NullParser = AstIndex function(ref Parser p, PreferType preferType, Token token, int rbp);
1758 
1759 AstIndex left_error_parser(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex left, ref int nbp)
1760 {
1761 	if (token.type == TokenType.EOI)
1762 		p.context.unrecoverable_error(token.index, "Unexpected end of input");
1763 	else
1764 		p.context.unrecoverable_error(token.index, "%s is not an expression", token.type);
1765 }
1766 
1767 AstIndex null_error_parser(ref Parser p, PreferType preferType, Token token, int rbp)
1768 {
1769 	if (token.type == TokenType.EOI)
1770 		p.context.unrecoverable_error(token.index, "Unexpected end of input");
1771 	else
1772 		p.context.unrecoverable_error(token.index, "%s is not an expression", token.type);
1773 }
1774 
1775 struct LeftInfo
1776 {
1777 	LeftParser parser_left = &left_error_parser;
1778 	int lbp = MIN_BP;
1779 	int rbp = MIN_BP;
1780 	int nbp = MIN_BP;
1781 }
1782 
1783 struct NullInfo
1784 {
1785 	NullParser parser_null = &null_error_parser;
1786 	int lbp = MIN_BP;
1787 	int rbp = MIN_BP;
1788 	int nbp = MIN_BP;
1789 }
1790 
1791 struct TokenLookups
1792 {
1793 	LeftInfo[TokenType.max+1] left_lookup;
1794 	NullInfo[TokenType.max+1] null_lookup;
1795 }
1796 
1797 __gshared immutable TokenLookups g_tokenLookups = cexp_parser();
1798 
1799 private TokenLookups cexp_parser()
1800 {
1801 	TokenLookups res;
1802 
1803 	TokenType strToTok(string str)
1804 	{
1805 		import std.algorithm.searching : countUntil;
1806 		ptrdiff_t pos = countUntil(tokStrings, str);
1807 		assert(pos != -1, str ~ " not found");
1808 		return cast(TokenType)pos;
1809 	}
1810 
1811 	void _RegisterNull(int lbp, int rbp, int nbp, NullParser p, string[] tokens...) {
1812 		foreach (string token; tokens) res.null_lookup[strToTok(token)] = NullInfo(p, lbp, rbp, nbp);
1813 	}
1814 
1815 	void _RegisterLeft(int lbp, int rbp, int nbp, LeftParser p, string[] tokens...) {
1816 		foreach (string token; tokens) res.left_lookup[strToTok(token)] = LeftInfo(p, lbp, rbp, nbp);
1817 	}
1818 
1819 	void nilfix(int bp, NullParser nud, string[] tokens...) {
1820 		_RegisterNull(MIN_BP, MIN_BP, MAX_BP, nud, tokens);
1821 	}
1822 
1823 	void prefix(int bp, NullParser nud, string[] tokens...) {
1824 		_RegisterNull(MIN_BP, bp, MAX_BP, nud, tokens);
1825 	}
1826 
1827 	void suffix(int bp, LeftParser led, string[] tokens...) {
1828 		_RegisterLeft(bp, MIN_BP, MAX_BP, led, tokens);
1829 	}
1830 
1831 	void infixL(int bp, LeftParser led, string[] tokens...) {
1832 		_RegisterLeft(bp, bp, bp + 1, led, tokens);
1833 	}
1834 
1835 	void infixR(int bp, LeftParser led, string[] tokens...) {
1836 		_RegisterLeft(bp, bp - 1, bp + 1, led, tokens);
1837 	}
1838 
1839 	void infixN(int bp, LeftParser led, string[] tokens...) {
1840 		_RegisterLeft(bp, bp, bp, led, tokens);
1841 	}
1842 
1843 	// Compare the code below with this table of C operator precedence:
1844 	// http://en.cppreference.com/w/c/language/operator_precedence
1845 
1846 	suffix(310, &leftIncDec, ["++", "--"]);
1847 	infixL(310, &leftFuncCall, "(");
1848 	infixL(310, &leftIndex, "[");
1849 	infixL(310, &leftOpDot, ".");
1850 	//infixL(310, &leftBinaryOp, "->");
1851 
1852 	// 29 -- binds to everything except function call, indexing, postfix ops
1853 	prefix(290, &nullPrefixOp, ["+", "-", "!", "~", "*", "&", "++", "--", "@"]);
1854 	prefix(290, &nullPrefixAttribute, ["@"]);
1855 	prefix(290, &nullCast, "cast");
1856 
1857 	infixL(250, &leftFunctionOp, ["function"]);
1858 	infixL(250, &leftStarOp, ["*"]);
1859 	infixL(250, &leftBinaryOp, ["/", "%"]);
1860 
1861 	infixL(230, &leftBinaryOp, ["+", "-"]);
1862 	infixL(210, &leftBinaryOp, ["<<", ">>", ">>>"]);
1863 	infixL(190, &leftBinaryOp, ["<", ">", "<=", ">="]);
1864 	infixL(170, &leftBinaryOp, ["!=", "=="]);
1865 
1866 	infixL(150, &leftBinaryOp, "&");
1867 	infixL(130, &leftBinaryOp, "^");
1868 	infixL(110, &leftBinaryOp, "|");
1869 	infixL(90, &leftBinaryOp, "&&");
1870 	infixL(70, &leftBinaryOp, "||");
1871 
1872 	// Right associative: a = b = 2 is a = (b = 2)
1873 	infixR(30, &leftAssignOp, ["=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", "&=", "^=", "|="]);
1874 
1875 	// 0 precedence -- doesn"t bind until )
1876 	prefix(0, &nullParen, "("); // for grouping
1877 
1878 	// 0 precedence -- never used
1879 	nilfix(0, &nullLiteral, [
1880 		"#id", "$id",
1881 		"auto", "noreturn","void", "bool", "null",
1882 		"i8", "i16", "i32", "i64",
1883 		"u8", "u16", "u32", "u64",
1884 		"f32", "f64",
1885 		"$alias", "$type",
1886 		"true", "false",
1887 		"#special_kw",
1888 		"#int_dec_lit", "#int_bin_lit", "#int_hex_lit", "#float_dec_lit", "#str_lit", "#char_lit"]
1889 	);
1890 	nilfix(0, &null_error_parser, [")", "]", ":", "#eoi", ";"]);
1891 	return res;
1892 }
1893 
1894 // Null Denotations -- tokens that take nothing on the left
1895 
1896 AstIndex parseIntLiteralType(string suffix, TokenIndex tok, CompilationContext* c) {
1897 	if (suffix.length == 0) return AstIndex();
1898 	switch(suffix) {
1899 		case "i8":  return CommonAstNodes.type_i8;
1900 		case "i16": return CommonAstNodes.type_i16;
1901 		case "i32": return CommonAstNodes.type_i32;
1902 		case "i64": return CommonAstNodes.type_i64;
1903 		case "u8":  return CommonAstNodes.type_u8;
1904 		case "u16": return CommonAstNodes.type_u16;
1905 		case "u32": return CommonAstNodes.type_u32;
1906 		case "u64": return CommonAstNodes.type_u64;
1907 		default: c.internal_error(tok, "Unexpected type suffix `%s`", suffix);
1908 	}
1909 }
1910 
1911 // id, int_literal, string_literal
1912 AstIndex nullLiteral(ref Parser p, PreferType preferType, Token token, int rbp) {
1913 	import std.algorithm : filter;
1914 	import std.range : walkLength;
1915 	import std.conv : parse;
1916 	import std.typecons : Yes;
1917 	CompilationContext* c = p.context;
1918 	switch(token.type) with(TokenType)
1919 	{
1920 		case IDENTIFIER:
1921 			Identifier id = p.makeIdentifier(token.index);
1922 			return p.make!NameUseExprNode(token.index, p.currentScopeIndex, id);
1923 		case CASH_IDENTIFIER:
1924 			Identifier id = p.makeIdentifier(token.index);
1925 			if (id.index >= commonId_builtin_func_first && id.index <= commonId_builtin_func_last)
1926 			{
1927 				uint builtinIndex = id.index - commonId_builtin_func_first;
1928 				return builtinFuncsArray[builtinIndex];
1929 			}
1930 			c.error(token.index, "Invalid $ identifier %s", c.idString(id));
1931 			return p.make!NameUseExprNode(token.index, p.currentScopeIndex, id);
1932 		case SPECIAL_KW:
1933 			Identifier id = p.makeIdentifier(token.index);
1934 			c.assertf(id.index >= commonId_special_keyword_first && id.index <= commonId_special_keyword_last,
1935 				"Invalid special keyword %s", c.idString(id));
1936 			uint keywordIndex = id.index - commonId_special_keyword_first;
1937 			SpecialKeyword kw = cast(SpecialKeyword)keywordIndex;
1938 			IrIndex irValue = eval_literal_special(kw, token.index, p.currentScopeIndex, c);
1939 			return c.appendAst!SpecialLiteralExprNode(token.index, irValue, kw);
1940 		case NULL:
1941 			return p.makeExpr!NullLiteralExprNode(token.index);
1942 		case TRUE_LITERAL:
1943 			return p.makeExpr!BoolLiteralExprNode(token.index, true);
1944 		case FALSE_LITERAL:
1945 			return p.makeExpr!BoolLiteralExprNode(token.index, false);
1946 		case STRING_LITERAL:
1947 			// omit " at the start and end of token
1948 			string value = cast(string)c.getTokenString(token.index)[1..$-1];
1949 
1950 			// handle escape sequences and copy string to RO buffer.
1951 			value = handleEscapedString(c.roStaticDataBuffer, value);
1952 			c.roStaticDataBuffer.put(0); // add zero terminator
1953 
1954 			AstIndex type = CommonAstNodes.type_u8Slice;
1955 			IrIndex irValue = makeStringLiteralIrConstant(value, p.currentModule.objectSymIndex, c);
1956 			return p.make!StringLiteralExprNode(token.index, type, irValue, value);
1957 		case CHAR_LITERAL:
1958 			// omit ' at the start and end of token
1959 			string value = cast(string)c.getTokenString(token.index)[1..$-1];
1960 			dchar charVal = getCharValue(value);
1961 			return p.makeExpr!IntLiteralExprNode(token.index, cast(uint)charVal);
1962 		case INT_DEC_LITERAL:
1963 			string value = cast(string)c.getTokenString(token.index);
1964 			auto filtered = value.filter!(c => c != '_');
1965 			auto result = filtered.parse!(ulong, typeof(filtered), Yes.doCount);
1966 			AstIndex type = parseIntLiteralType(value[$-filtered.walkLength..$], token.index, c);
1967 			return c.appendAst!IntLiteralExprNode(token.index, type, result.data);
1968 		case INT_HEX_LITERAL:
1969 			string value = cast(string)c.getTokenString(token.index);
1970 			auto filtered = value[2..$].filter!(c => c != '_');
1971 			auto result = filtered.parse!(ulong, typeof(filtered), Yes.doCount)(16); // skip 0x, 0X
1972 			AstIndex type = parseIntLiteralType(value[$-filtered.walkLength..$], token.index, c);
1973 			return c.appendAst!IntLiteralExprNode(token.index, type, result.data);
1974 		case INT_BIN_LITERAL:
1975 			string value = cast(string)c.getTokenString(token.index);
1976 			auto filtered = value[2..$].filter!(c => c != '_');
1977 			auto result = filtered.parse!(ulong, typeof(filtered), Yes.doCount)(2); // skip 0b, 0B
1978 			AstIndex type = parseIntLiteralType(value[$-filtered.walkLength..$], token.index, c);
1979 			return c.appendAst!IntLiteralExprNode(token.index, type, result.data);
1980 		case FLOAT_DEC_LITERAL:
1981 			string value = cast(string)c.getTokenString(token.index);
1982 			auto filtered = value.filter!(c => c != '_');
1983 			auto result = filtered.parse!(double, typeof(filtered), Yes.doCount);
1984 			AstIndex type;
1985 			if (!filtered.empty) {
1986 				string suffix = value[$-filtered.walkLength..$];
1987 				if (suffix == "f32")
1988 					type = CommonAstNodes.type_f32;
1989 				else {
1990 					c.assertf(suffix == "f64", token.index, "Unexpected type suffix `%s`", suffix);
1991 					type = CommonAstNodes.type_f64;
1992 				}
1993 			}
1994 			return c.appendAst!FloatLiteralExprNode(token.index, type, result.data);
1995 		case TYPE_AUTO:
1996 			c.error(token.index, "`auto` can only be used to declare varible in a function body");
1997 			BasicType t = token.type.tokenTypeToBasicType;
1998 			return c.basicTypeNodes(t);
1999 		case TYPE_NORETURN, TYPE_VOID, TYPE_BOOL,
2000 			TYPE_I8, TYPE_I16, TYPE_I32, TYPE_I64, TYPE_U8, TYPE_U16, TYPE_U32, TYPE_U64,
2001 			TYPE_F32, TYPE_F64,
2002 			TYPE_ALIAS, TYPE_TYPE:
2003 			BasicType t = token.type.tokenTypeToBasicType;
2004 			return c.basicTypeNodes(t);
2005 		default:
2006 			c.internal_error("nullLiteral %s", token.type);
2007 	}
2008 }
2009 
2010 // Arithmetic grouping
2011 AstIndex nullParen(ref Parser p, PreferType preferType, Token token, int rbp) {
2012 	AstIndex r = p.expr(PreferType.no, rbp);
2013 	p.expectAndConsume(TokenType.RPAREN);
2014 	//r.flags |= NFLG.parenthesis; // NOTE: needed if ternary operator is needed
2015 	return r;
2016 }
2017 
2018 AstIndex nullPrefixAttribute(ref Parser p, PreferType preferType, Token token, int rbp) {
2019 	if (!preferType) p.context.unrecoverable_error(token.index, "Unexpected attribute");
2020 	while(true) {
2021 		p.parse_single_attribute(p.tok.index);
2022 		if (p.tok.type == TokenType.AT) {
2023 			p.nextToken; // skip @
2024 			continue;
2025 		}
2026 		break;
2027 	}
2028 	return p.expr(preferType, rbp);
2029 }
2030 
2031 // Prefix operator
2032 // ["+", "-", "!", "~", "*", "&", "++", "--"] <expr>
2033 AstIndex nullPrefixOp(ref Parser p, PreferType preferType, Token token, int rbp) {
2034 	AstIndex right = p.expr(PreferType.no, rbp);
2035 	UnOp op;
2036 	switch(token.type) with(TokenType)
2037 	{
2038 		case PLUS: return right;
2039 		case MINUS:
2040 			AstNode* rightNode = p.context.getAstNode(right);
2041 			if (rightNode.astType == AstType.literal_int) {
2042 				(cast(IntLiteralExprNode*)rightNode).negate(token.index, *p.context);
2043 				return right;
2044 			} else if (rightNode.astType == AstType.literal_float) {
2045 				(cast(FloatLiteralExprNode*)rightNode).negate(token.index, *p.context);
2046 				return right;
2047 			}
2048 			op = UnOp.GENERIC_MINUS;
2049 			break;
2050 		case NOT: op = UnOp.logicalNot; break;
2051 		case TILDE: op = UnOp.bitwiseNot; break;
2052 		case STAR: op = UnOp.deref; break;
2053 		case AND: op = UnOp.addrOf; break;
2054 		case PLUS_PLUS: op = UnOp.preIncrement; break;
2055 		case MINUS_MINUS: op = UnOp.preDecrement; break;
2056 		default: p.context.unreachable;
2057 	}
2058 	return p.makeExpr!UnaryExprNode(token.index, op, right);
2059 }
2060 
2061 // "cast" "(" <expr> ")" <expr>
2062 AstIndex nullCast(ref Parser p, PreferType preferType, Token token, int rbp) {
2063 	p.expectAndConsume(TokenType.LPAREN);
2064 	AstIndex type = p.expr(PreferType.yes, 0);
2065 	p.expectAndConsume(TokenType.RPAREN);
2066 	AstIndex right = p.expr(PreferType.no, rbp);
2067 	return p.make!TypeConvExprNode(token.index, type, right);
2068 }
2069 
2070 // Left Denotations -- tokens that take an expression on the left
2071 
2072 // <expr> "++" / "--"
2073 AstIndex leftIncDec(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex left, ref int nbp) {
2074 	UnOp op;
2075 	switch(token.type) with(TokenType)
2076 	{
2077 		case PLUS_PLUS: op = UnOp.postIncrement; break;
2078 		case MINUS_MINUS: op = UnOp.postDecrement; break;
2079 		default: p.context.unreachable;
2080 	}
2081 	return p.makeExpr!UnaryExprNode(token.index, op, left);
2082 }
2083 
2084 // <expr> "[" "]"
2085 // <expr> "[" <expr> "," <expr>+ "]"
2086 // <expr> "[" <expr> .. <expr> "]"
2087 AstIndex leftIndex(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex array, ref int nbp) {
2088 	AstNodes indices;
2089 	if (p.tok.type == TokenType.RBRACKET)
2090 	{
2091 		p.nextToken;
2092 		return p.makeExpr!IndexExprNode(token.index, p.currentScopeIndex, array, indices);
2093 	}
2094 	AstIndex index = p.expr(PreferType.no, 0);
2095 	if (p.tok.type == TokenType.RBRACKET)
2096 	{
2097 		p.nextToken;
2098 		indices.put(p.context.arrayArena, index);
2099 		return p.makeExpr!IndexExprNode(token.index, p.currentScopeIndex, array, indices);
2100 	}
2101 
2102 	if (preferType == PreferType.yes)
2103 	{
2104 		// it is type
2105 		p.expectAndConsume(TokenType.RBRACKET);
2106 		assert(false);
2107 	}
2108 	else
2109 	{
2110 		// it is expression
2111 		p.expectAndConsume(TokenType.DOT_DOT);
2112 		AstIndex index2 = p.expr(PreferType.no, 0);
2113 		p.expectAndConsume(TokenType.RBRACKET);
2114 		return p.makeExpr!SliceExprNode(token.index, array, index, index2);
2115 	}
2116 }
2117 
2118 // member access <expr> . <expr>
2119 AstIndex leftOpDot(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex left, ref int nbp)
2120 {
2121 	Identifier id;
2122 	if (p.tok.type == TokenType.IDENTIFIER)
2123 	{
2124 		id = p.makeIdentifier(p.tok.index);
2125 		p.nextToken; // skip id
2126 	}
2127 	else
2128 	{
2129 		p.context.error(token.index,
2130 			"Expected identifier after '.', while got '%s'",
2131 			p.context.getTokenString(p.tok.index));
2132 	}
2133 	return p.make!MemberExprNode(token.index, p.currentScopeIndex, left, id);
2134 }
2135 
2136 AstIndex leftFunctionOp(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex returnType, ref int nbp) {
2137 	CallConvention callConvention = p.context.defaultCallConvention;
2138 	auto sig = p.makeDecl!FunctionSignatureNode(token.index, returnType, AstNodes.init, callConvention);
2139 	AstIndex prevOwner = p.declarationOwner; // change the owner, so that parameters are inferred as local
2140 	p.declarationOwner = sig;
2141 	p.parseParameters(sig, p.NeedRegNames.no); // function types don't need to register their param names
2142 	p.declarationOwner = prevOwner;
2143 	// we don't have to register parameter names, since we have no body
2144 	sig.setState(p.context, AstNodeState.name_register_nested_done);
2145 	return p.make!PtrTypeNode(token.index, CommonAstNodes.type_type, sig);
2146 }
2147 
2148 // multiplication or pointer type
2149 // <expr> * <expr> or <expr>*
2150 AstIndex leftStarOp(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex left, ref int nbp) {
2151 	switch (p.tok.type) with(TokenType)
2152 	{
2153 		case STAR, COMMA, RPAREN, RBRACKET, LBRACKET, SEMICOLON, FUNCTION_SYM /*,DELEGATE_SYM*/:
2154 			// pointer
2155 			nbp = 311; // make current node into a postfix op
2156 			return p.make!PtrTypeNode(token.index, CommonAstNodes.type_type, left);
2157 		case DOT:
2158 			// hack for postfix star followed by dot
2159 			AstIndex ptr = p.make!PtrTypeNode(token.index, CommonAstNodes.type_type, left);
2160 			Token tok = p.tok;
2161 			p.nextToken; // skip dot
2162 			int nbpDot;
2163 			return leftOpDot(p, PreferType.no, tok, 0, ptr, nbpDot);
2164 		default:
2165 			// otherwise it is multiplication
2166 			break;
2167 	}
2168 
2169 	if (preferType)
2170 	{
2171 		// pointer
2172 		return p.make!PtrTypeNode(token.index, CommonAstNodes.type_type, left);
2173 	}
2174 
2175 	// otherwise it is multiplication
2176 	AstIndex right = p.expr(PreferType.no, rbp);
2177 	BinOp op = BinOp.GENERIC_MUL;
2178 	return p.makeExpr!BinaryExprNode(token.index, op, left, right);
2179 }
2180 
2181 // Normal binary operator <expr> op <expr>
2182 AstIndex leftBinaryOp(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex left, ref int nbp) {
2183 	AstIndex right = p.expr(PreferType.no, rbp);
2184 	BinOp op;
2185 	switch(token.type) with(TokenType)
2186 	{
2187 		// logic ops
2188 		case AND_AND: op = BinOp.LOGIC_AND; break;                // &&
2189 		case OR_OR: op = BinOp.LOGIC_OR; break;                   // ||
2190 		case EQUAL_EQUAL: op = BinOp.EQUAL; break;                // ==
2191 		case NOT_EQUAL: op = BinOp.NOT_EQUAL; break;              // !=
2192 		case MORE: op = BinOp.GENERIC_GREATER; break;             // >
2193 		case MORE_EQUAL: op = BinOp.GENERIC_GREATER_EQUAL; break; // >=
2194 		case LESS: op = BinOp.GENERIC_LESS; break;                // <
2195 		case LESS_EQUAL: op = BinOp.GENERIC_LESS_EQUAL; break;    // <=
2196 
2197 		// arithmetic ops
2198 		case AND: op = BinOp.BITWISE_AND; break;                  // &
2199 		case OR: op = BinOp.BITWISE_OR; break;                    // |
2200 		case PERCENT: op = BinOp.GENERIC_INT_REM; break;          // %
2201 		case LESS_LESS: op = BinOp.SHL; break;                    // <<
2202 		case MORE_MORE: op = BinOp.ASHR; break;                   // >>
2203 		case MORE_MORE_MORE: op = BinOp.SHR; break;               // >>>
2204 		case MINUS: op = BinOp.GENERIC_MINUS; break;              // -
2205 		case PLUS: op = BinOp.GENERIC_PLUS; break;                // +
2206 		case SLASH: op = BinOp.GENERIC_DIV; break;                // /
2207 		case XOR: op = BinOp.XOR; break;                          // ^
2208 
2209 		default:
2210 			p.context.internal_error(token.index, "parse leftBinaryOp %s", token.type);
2211 	}
2212 	return p.makeExpr!BinaryExprNode(token.index, op, left, right);
2213 }
2214 
2215 // Binary assignment operator <expr> op= <expr>
2216 AstIndex leftAssignOp(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex left, ref int nbp) {
2217 	AstIndex right = p.expr(PreferType.no, rbp);
2218 	BinOp op;
2219 	switch(token.type) with(TokenType)
2220 	{
2221 		// arithmetic opEquals
2222 		case EQUAL: op = BinOp.ASSIGN; break;                     // =
2223 		case AND_EQUAL: op = BinOp.BITWISE_AND_ASSIGN; break;     // &=
2224 		case OR_EQUAL: op = BinOp.BITWISE_OR_ASSIGN; break;       // |=
2225 		case PERCENT_EQUAL: op = BinOp.GENERIC_INT_REM_ASSIGN; break; // %=
2226 		case LESS_LESS_EQUAL: op = BinOp.SHL_ASSIGN; break;       // <<=
2227 		case MORE_MORE_EQUAL: op = BinOp.ASHR_ASSIGN; break;      // >>=
2228 		case MORE_MORE_MORE_EQUAL: op = BinOp.SHR_ASSIGN; break;  // >>>=
2229 		case MINUS_EQUAL: op = BinOp.GENERIC_MINUS_ASSIGN; break; // -=
2230 		case PLUS_EQUAL: op = BinOp.GENERIC_PLUS_ASSIGN; break;   // +=
2231 		case SLASH_EQUAL: op = BinOp.GENERIC_DIV_ASSIGN; break;   // /=
2232 		case STAR_EQUAL: op = BinOp.GENERIC_MUL_ASSIGN; break;    // *=
2233 		case XOR_EQUAL: op = BinOp.XOR_ASSIGN; break;             // ^=
2234 		default:
2235 			p.context.internal_error(token.index, "parse leftAssignOp %s", token.type);
2236 	}
2237 	AstNode* leftNode = p.context.getAstNode(left);
2238 	leftNode.flags |= AstFlags.isLvalue;
2239 
2240 	AstIndex assignExpr = p.makeExpr!BinaryExprNode(token.index, op, left, right);
2241 	AstNode* assignExprNode = p.context.getAstNode(assignExpr);
2242 	assignExprNode.flags |= BinaryOpFlags.isAssignment;
2243 
2244 	return assignExpr;
2245 }
2246 
2247 // <expr> "(" <expr_list> ")"
2248 AstIndex leftFuncCall(ref Parser p, PreferType preferType, Token token, int unused_rbp, AstIndex callee, ref int nbp) {
2249 	AstNodes args;
2250 	ushort flags = p.parse_argument_list(args);
2251 	AstIndex callExpr = p.makeExpr!CallExprNode(token.index, p.currentScopeIndex, callee, args);
2252 	callExpr.flags(p.context) |= flags;
2253 	return callExpr;
2254 }