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 }