1 module d.parser.ambiguous;
2 
3 import d.ast.declaration;
4 import d.ast.expression;
5 import d.ast.identifier;
6 import d.ast.statement;
7 import d.ast.type;
8 
9 import d.parser.base;
10 import d.parser.declaration;
11 import d.parser.expression;
12 import d.parser.type;
13 import d.parser.identifier;
14 import source.parserutil;
15 
16 /**
17  * Branch to the right code depending if we have a type,
18  * an expression or an identifier.
19  */
20 typeof(handler(AstExpression.init)) parseAmbiguous(
21 	alias handler,
22 	AmbiguousParseMode M = AmbiguousParseMode.Regular,
23 )(ref TokenRange trange) {
24 	switch (trange.front.type) with(TokenType) {
25 		case Identifier:
26 			auto i = trange.parseIdentifier();
27 			return trange.parseAmbiguousSuffix!(handler, M)(i);
28 		
29 		case Dot:
30 			auto i = trange.parseDotIdentifier();
31 			return trange.parseAmbiguousSuffix!(handler, M)(i);
32 		
33 		// Types
34 		case Typeof:
35 		case Bool:
36 		case Byte, Ubyte:
37 		case Short, Ushort:
38 		case Int, Uint:
39 		case Long, Ulong:
40 		case Cent, Ucent:
41 		case Char, Wchar, Dchar:
42 		case Float, Double, Real:
43 		case Void:
44 		
45 		// Type qualifiers
46 		case Const, Immutable, Inout, Shared:
47 			auto location = trange.front.location;
48 			auto t = trange.parseType!(ParseMode.Reluctant)();
49 			return trange.parseAmbiguousSuffix!(handler, M)(location, t);
50 		
51 		case New:
52 		case This:
53 		case Super:
54 		case True:
55 		case False:
56 		case Null:
57 		case IntegerLiteral:
58 		case StringLiteral:
59 		case CharacterLiteral:
60 		case OpenBracket:
61 		case OpenBrace:
62 		case Function:
63 		case Delegate:
64 		case __File__:
65 		case __Line__:
66 		case Dollar:
67 		case Typeid:
68 		case Is:
69 		
70 		// XXX: Should assert really be an expression ?
71 		case Assert:
72 		
73 		// Prefixes.
74 		case Ampersand:
75 		case PlusPlus:
76 		case MinusMinus:
77 		case Star:
78 		case Plus:
79 		case Minus:
80 		case Bang:
81 		case Tilde:
82 		case Cast:
83 			auto e = trange.parseExpression!(ParseMode.Reluctant)();
84 			return trange.parseAmbiguousSuffix!(handler, M)(e);
85 		
86 		case OpenParen:
87 			auto matchingParen = trange.getLookahead();
88 			matchingParen.popMatchingDelimiter!OpenParen();
89 			
90 			switch (matchingParen.front.type) {
91 				case OpenBrace, EqualMore:
92 					// Delegates.
93 					assert(0, "Ambiguous delegates not implemented");
94 				
95 				default:
96 					auto location = trange.front.location;
97 					trange.popFront();
98 					
99 					// Use ambiguousHandler to avoid infinite recursion
100 					return trange.parseAmbiguous!ambiguousHandler()
101 						.apply!((parsed) {
102 							location.spanTo(trange.front.location);
103 							trange.match(CloseParen);
104 							
105 							alias T = typeof(parsed);
106 							static if (is(T : AstType)) {
107 								return trange.parseAmbiguousSuffix!(handler, M)(location, parsed);
108 							} else static if (is(T : AstExpression)) {
109 								auto e = new ParenExpression(location, parsed);
110 								return trange.parseAmbiguousSuffix!(handler, M)(e);
111 							} else {
112 								// XXX: Consider adding ParenIdentifier for AST fidelity.
113 								return trange.parseAmbiguousSuffix!(handler, M)(parsed);
114 							}
115 						})();
116 			}
117 		
118 		default:
119 			trange.match(Begin);
120 			// TODO: handle.
121 			// Erreur, unexpected.
122 			assert(0);
123 	}
124 }
125 
126 struct IdentifierStarName {
127 	import source.name;
128 	Name name;
129 
130 	Identifier identifier;
131 	AstExpression value;
132 }
133 
134 auto parseAmbiguousStatement(ref TokenRange trange) {
135 	switch (trange.front.type) with (TokenType) {
136 		case Interface, Class, Struct, Union, Enum:
137 		case Import, Template, Extern, Alias:
138 		case Auto, Static, Const, Immutable, Inout, Shared:
139 			auto d = trange.parseDeclaration();
140 			return trange.finalizeStatement(d.location, d);
141 		
142 		default:
143 			auto location = trange.front.location;
144 			return trange.parseAmbiguous!(
145 				parsed => trange.finalizeStatement(location, parsed),
146 				AmbiguousParseMode.Declaration,
147 			)();
148 	}
149 }
150 
151 auto parseStatementSuffix(ref TokenRange trange, AstExpression e) {
152 	return trange.parseAmbiguousSuffix!(
153 		parsed => trange.finalizeStatement(e.location, parsed),
154 		AmbiguousParseMode.Declaration,
155 	)(e);
156 }
157 
158 private:
159 
160 Declaration finalizeDeclaration(T)(
161 	ref TokenRange trange,
162 	Location location,
163 	T parsed,
164 ) {
165 	static if (is(T : AstType)) {
166 		alias t = parsed;
167 	} else {
168 		auto t = AstType.get(parsed);
169 	}
170 	
171 	return trange.parseTypedDeclaration(location, defaultStorageClass, t);
172 }
173 
174 Statement finalizeStatement(T)(
175 	ref TokenRange trange,
176 	Location location,
177 	T parsed,
178 ) {
179 	static if (is(T : AstType)) {
180 		return trange.finalizeStatement(
181 			location,
182 			trange.finalizeDeclaration(location, parsed),
183 		);
184 	} else static if (is(T : Declaration)) {
185 		return new DeclarationStatement(parsed);
186 	} else static if (is(T : AstExpression)) {
187 		trange.match(TokenType.Semicolon);
188 		return new ExpressionStatement(parsed);
189 	} else static if (is(T : IdentifierStarName)) {
190 		trange.match(TokenType.Semicolon);
191 		location.spanTo(trange.previous);
192 		return new IdentifierStarNameStatement(
193 			location,
194 			parsed.identifier,
195 			parsed.name,
196 			parsed.value,
197 		);
198 	} else {
199 		// Identifier follow by another identifier is a declaration.
200 		if (trange.front.type == TokenType.Identifier) {
201 			return trange.finalizeStatement(
202 				location,
203 				trange.finalizeDeclaration(location, parsed),
204 			);
205 		} else {
206 			return trange.finalizeStatement(
207 				location,
208 				new IdentifierExpression(parsed),
209 			);
210 		}
211 	}
212 }
213 
214 /**
215  * Indicate if we are looking for something that may be a declaration.
216  * This is relevent for statements, which can be expression or declaration,
217  * but not true in the general case. This is relevent for special cases such
218  * as:
219  *   Identifier * Identifier = Expression.
220  *
221  * Such statement can either be a declaration or an expression if the mode
222  * is declaration, but will be considered an expression if it is regular.
223  */
224 enum AmbiguousParseMode {
225 	Regular,
226 	Declaration,
227 }
228 
229 // XXX: Workaround template recurence instanciation bug.
230 alias Ambiguous = AstType.UnionType!(Identifier, AstExpression);
231 
232 auto apply(alias handler)(Ambiguous a) {
233 	alias Tag = typeof(a.tag);
234 	final switch (a.tag) with(Tag) {
235 		case Identifier :
236 			return handler(a.get!Identifier);
237 		
238 		case AstExpression :
239 			return handler(a.get!AstExpression);
240 		
241 		case AstType :
242 			return handler(a.get!AstType);
243 	}
244 }
245 
246 Ambiguous ambiguousHandler(T)(T t) {
247 	static if(is(T == typeof(null))) {
248 		assert(0);
249 	} else {
250 		return Ambiguous(t);
251 	}
252 }
253 
254 bool indicateExpression(TokenType t) {
255 	switch(t) with(TokenType) {
256 		case PlusPlus:
257 		case MinusMinus:
258 		case Equal:
259 		case PlusEqual:
260 		case MinusEqual:
261 		case StarEqual:
262 		case SlashEqual:
263 		case PercentEqual:
264 		case AmpersandEqual:
265 		case PipeEqual:
266 		case CaretEqual:
267 		case TildeEqual:
268 		case LessLessEqual:
269 		case MoreMoreEqual:
270 		case MoreMoreMoreEqual:
271 		case CaretCaretEqual:
272 		case QuestionMark:
273 		case PipePipe:
274 		case AmpersandAmpersand:
275 		case Pipe:
276 		case Caret:
277 		case Ampersand:
278 		case EqualEqual:
279 		case BangEqual:
280 		case More:
281 		case MoreEqual:
282 		case Less:
283 		case LessEqual:
284 		case BangLessMoreEqual:
285 		case BangLessMore:
286 		case LessMore:
287 		case LessMoreEqual:
288 		case BangMore:
289 		case BangMoreEqual:
290 		case BangLess:
291 		case BangLessEqual:
292 		case Is:
293 		case In:
294 		case Bang:
295 		case LessLess:
296 		case MoreMore:
297 		case MoreMoreMore:
298 		case Plus:
299 		case Minus:
300 		case Tilde:
301 		case Slash:
302 		case Percent:
303 		case OpenParen:
304 			return true;
305 		
306 		default:
307 			return false;
308 	}
309 }
310 
311 typeof(handler(AstExpression.init)) parseAmbiguousSuffix(
312 	alias handler,
313 	AmbiguousParseMode M = AmbiguousParseMode.Type,
314 )(ref TokenRange trange, Identifier i) {
315 	auto tt = trange.front.type;
316 	if (tt.indicateExpression()) {
317 		auto e = trange.parseIdentifierExpression(i);
318 		return trange.parseAmbiguousSuffix!handler(e);
319 	}
320 	
321 	switch (tt) with(TokenType) {
322 		case OpenBracket:
323 			trange.popFront();
324 			
325 			// This is a slice type
326 			if (trange.front.type == CloseBracket) {
327 				trange.popFront();
328 				return trange.parseAmbiguousSuffix!handler(
329 					i.location,
330 					AstType.get(i).getSlice(),
331 				);
332 			}
333 			
334 			return trange.parseAmbiguous!ambiguousHandler().apply!((parsed) {
335 				auto location = i.location;
336 				location.spanTo(trange.front.location);
337 				trange.match(CloseBracket);
338 				
339 				alias T = typeof(parsed);
340 				static if (is(T : AstType)) {
341 					auto t = AstType.get(i).getMap(parsed);
342 					return trange.parseAmbiguousSuffix!handler(i.location, t);
343 				} else {
344 					static if (is(T : AstExpression)) {
345 						auto id = new IdentifierBracketExpression(location, i, parsed);
346 					} else {
347 						auto id = new IdentifierBracketIdentifier(location, i, parsed);
348 					}
349 					
350 					return trange.parseAmbiguousSuffix!(handler, M)(id);
351 				}
352 			})();
353 		
354 		case Star:
355 			auto lookahead = trange.getLookahead();
356 			lookahead.popFront();
357 			
358 			switch (lookahead.front.type) {
359 				Type:
360 					return trange.parseAmbiguousSuffix!handler(
361 						i.location,
362 						AstType.get(i),
363 					);
364 				
365 				Expression: {
366 					auto lhs = new IdentifierExpression(i);
367 					auto e = trange.parseMulExpression(lhs);
368 					return trange.parseAmbiguousSuffix!handler(e);
369 				}
370 				case Star:
371 					// Identifier** is a pointer to a pointer.
372 					goto Type;
373 				
374 				case OpenBracket:
375 					// XXX: Array literal or array/slice/map of pointer ?
376 					assert(0, "Not supported");
377 				
378 				case Function, Delegate:
379 					lookahead.popFront();
380 					
381 					if (lookahead.front.type == OpenParen) {
382 						// Function type returning a pointer.
383 						goto Type;
384 					}
385 					
386 					// IdentifierExpression * function Type(...)
387 					goto Expression;
388 				
389 				case New:
390 				case This, Super:
391 				case True, False:
392 				case Null:
393 				case IntegerLiteral:
394 				case StringLiteral:
395 				case CharacterLiteral:
396 				case OpenBrace:
397 				case __File__, __Line__:
398 				case Dollar:
399 				case Typeid:
400 				case Is:
401 				case Assert:
402 					// These indicate an expression.
403 					goto Expression;
404 				
405 				case Identifier:
406 					/**
407 					 * Deal with:
408 					 *     Identifier * Name = Initializer
409 					 *     Identifier * identifier(
410 					 * As both can be expression or declaration depending
411 					 * on identifier resolution.
412 					 */
413 					static if (M == AmbiguousParseMode.Declaration) {
414 						auto name = lookahead.front.name;
415 						auto rloc = lookahead.front.location;
416 						
417 						lookahead.popFront();
418 						auto rtt = lookahead.front.type;
419 						switch (rtt) {
420 							case Equal:
421 								/**
422 								 * Identifier * Name = Initializer can be
423 								 * an expression or a declaration. Create
424 								 * a special node and let identifier resolution
425 								 * deal with it.
426 								 */
427 								trange.moveTo(lookahead);
428 								trange.popFront();
429 								auto v = trange.parseInitializer();
430 								return handler(IdentifierStarName(name, i, v));
431 							
432 							case OpenParen:
433 								/**
434 								 * We are faced with Identifier * Identifier(
435 								 * It is either the start of an expression or
436 								 * the start of the declaration of a function
437 								 * that returns a pointer.
438 								 * In any case, we'll assume the later.
439 								 */
440 								trange.popFront();
441 								return handler(trange.parseTypedDeclaration(
442 									i.location,
443 									defaultStorageClass,
444 									AstType.get(i).getPointer(),
445 								));
446 							
447 							default:
448 								// FIXME: This is most likely broken.
449 								// Cases like *, . and ! are not handled.
450 								if (!rtt.indicateExpression()) {
451 									trange.moveTo(lookahead);
452 									return handler(IdentifierStarName(name, i, null));
453 								}
454 						}
455 					}
456 					
457 					// Otherwize, it is an expression.
458 					goto Expression;
459 				
460 				case Semicolon:
461 					// This indicate an end of statement, so we have a type.
462 					goto Type;
463 				
464 				default:
465 					// XXX: have a proper error message.
466 					trange.match(Begin);
467 					assert(0);
468 			}
469 		
470 		case Dot:
471 			trange.popFront();
472 			
473 			auto id = trange.parseQualifiedIdentifier(i.location, i);
474 			return trange.parseAmbiguousSuffix!(handler, M)(id);
475 		
476 		case Function, Delegate:
477 			return trange.parseAmbiguousSuffix!handler(
478 				i.location,
479 				AstType.get(i),
480 			);
481 		
482 		default:
483 			return handler(i);
484 	}
485 }
486 
487 typeof(handler(AstExpression.init)) parseAmbiguousSuffix(
488 	alias handler,
489 	AmbiguousParseMode M = AmbiguousParseMode.Regular,
490 )(ref TokenRange trange, Location location, AstType t) {
491 	t = trange.parseTypeSuffix!(ParseMode.Reluctant)(t);
492 	
493 	switch (trange.front.type) with(TokenType) {
494 		case OpenParen:
495 			assert(0, "Constructor not implemented");
496 		
497 		case Dot:
498 			trange.popFront();
499 			
500 			auto i = trange.parseQualifiedIdentifier(location, t);
501 			return trange.parseAmbiguousSuffix!(handler, M)(i);
502 		
503 		default:
504 			return handler(t);
505 	}
506 }
507 
508 typeof(handler(AstExpression.init)) parseAmbiguousSuffix(
509 	alias handler,
510 	AmbiguousParseMode M = AmbiguousParseMode.Regular,
511 )(ref TokenRange trange, AstExpression e) {
512 	e = trange.parsePostfixExpression!(ParseMode.Reluctant)(e);
513 	
514 	while (true) {
515 		switch (trange.front.type) with(TokenType) {
516 			case Equal:
517 			case PlusEqual:
518 			case MinusEqual:
519 			case StarEqual:
520 			case SlashEqual:
521 			case PercentEqual:
522 			case AmpersandEqual:
523 			case PipeEqual:
524 			case CaretEqual:
525 			case TildeEqual:
526 			case LessLessEqual:
527 			case MoreMoreEqual:
528 			case MoreMoreMoreEqual:
529 			case CaretCaretEqual:
530 				e = trange.parseAssignExpression(e);
531 				continue;
532 			
533 			case QuestionMark:
534 				e = trange.parseTernaryExpression(e);
535 				continue;
536 			
537 			case PipePipe:
538 				e = trange.parseLogicalOrExpression(e);
539 				continue;
540 			
541 			case AmpersandAmpersand:
542 				e = trange.parseLogicalAndExpression(e);
543 				continue;
544 			
545 			case Pipe:
546 				e = trange.parseBitwiseOrExpression(e);
547 				continue;
548 			
549 			case Caret:
550 				e = trange.parseBitwiseXorExpression(e);
551 				continue;
552 			
553 			case Ampersand:
554 				e = trange.parseBitwiseAndExpression(e);
555 				continue;
556 			
557 			case EqualEqual:
558 			case BangEqual:
559 			case More:
560 			case MoreEqual:
561 			case Less:
562 			case LessEqual:
563 			case BangLessMoreEqual:
564 			case BangLessMore:
565 			case LessMore:
566 			case LessMoreEqual:
567 			case BangMore:
568 			case BangMoreEqual:
569 			case BangLess:
570 			case BangLessEqual:
571 			case Is:
572 			case In:
573 			case Bang:
574 				e = trange.parseComparaisonExpression(e);
575 				continue;
576 			
577 			case LessLess, MoreMore, MoreMoreMore:
578 				e = trange.parseShiftExpression(e);
579 				continue;
580 			
581 			case Plus, Minus, Tilde:
582 				e = trange.parseAddExpression(e);
583 				continue;
584 			
585 			case Star, Slash, Percent:
586 				e = trange.parseMulExpression(e);
587 				continue;
588 			
589 			case Dot:
590 				trange.popFront();
591 				
592 				auto i = trange.parseQualifiedIdentifier(e.location, e);
593 				return trange.parseAmbiguousSuffix!(handler, M)(i);
594 			
595 			default:
596 				return handler(e);
597 		}
598 	}
599 }