| 340 | | |
|---|
| 341 | | /+ |
|---|
| 342 | | struct Token |
|---|
| 343 | | { |
|---|
| 344 | | public static enum Type |
|---|
| 345 | | { |
|---|
| 346 | | As, |
|---|
| 347 | | Assert, |
|---|
| 348 | | Break, |
|---|
| 349 | | Case, |
|---|
| 350 | | Catch, |
|---|
| 351 | | Continue, |
|---|
| 352 | | Coroutine, |
|---|
| 353 | | Default, |
|---|
| 354 | | Do, |
|---|
| 355 | | Else, |
|---|
| 356 | | False, |
|---|
| 357 | | Finally, |
|---|
| 358 | | For, |
|---|
| 359 | | Foreach, |
|---|
| 360 | | Function, |
|---|
| 361 | | Global, |
|---|
| 362 | | If, |
|---|
| 363 | | Import, |
|---|
| 364 | | In, |
|---|
| 365 | | Is, |
|---|
| 366 | | Local, |
|---|
| 367 | | Module, |
|---|
| 368 | | Namespace, |
|---|
| 369 | | Null, |
|---|
| 370 | | Object, |
|---|
| 371 | | Return, |
|---|
| 372 | | Super, |
|---|
| 373 | | Switch, |
|---|
| 374 | | This, |
|---|
| 375 | | Throw, |
|---|
| 376 | | True, |
|---|
| 377 | | Try, |
|---|
| 378 | | Vararg, |
|---|
| 379 | | While, |
|---|
| 380 | | With, |
|---|
| 381 | | Yield, |
|---|
| 382 | | |
|---|
| 383 | | Add, |
|---|
| 384 | | AddEq, |
|---|
| 385 | | Inc, |
|---|
| 386 | | Sub, |
|---|
| 387 | | SubEq, |
|---|
| 388 | | Dec, |
|---|
| 389 | | Cat, |
|---|
| 390 | | CatEq, |
|---|
| 391 | | Cmp3, |
|---|
| 392 | | Mul, |
|---|
| 393 | | MulEq, |
|---|
| 394 | | DefaultEq, |
|---|
| 395 | | Div, |
|---|
| 396 | | DivEq, |
|---|
| 397 | | Mod, |
|---|
| 398 | | ModEq, |
|---|
| 399 | | LT, |
|---|
| 400 | | LE, |
|---|
| 401 | | Shl, |
|---|
| 402 | | ShlEq, |
|---|
| 403 | | GT, |
|---|
| 404 | | GE, |
|---|
| 405 | | Shr, |
|---|
| 406 | | ShrEq, |
|---|
| 407 | | UShr, |
|---|
| 408 | | UShrEq, |
|---|
| 409 | | And, |
|---|
| 410 | | AndEq, |
|---|
| 411 | | AndAnd, |
|---|
| 412 | | Or, |
|---|
| 413 | | OrEq, |
|---|
| 414 | | OrOr, |
|---|
| 415 | | Xor, |
|---|
| 416 | | XorEq, |
|---|
| 417 | | Assign, |
|---|
| 418 | | EQ, |
|---|
| 419 | | Dot, |
|---|
| 420 | | DotDot, |
|---|
| 421 | | Not, |
|---|
| 422 | | NE, |
|---|
| 423 | | LParen, |
|---|
| 424 | | RParen, |
|---|
| 425 | | LBracket, |
|---|
| 426 | | RBracket, |
|---|
| 427 | | LBrace, |
|---|
| 428 | | RBrace, |
|---|
| 429 | | LAttr, |
|---|
| 430 | | RAttr, |
|---|
| 431 | | Colon, |
|---|
| 432 | | Comma, |
|---|
| 433 | | Semicolon, |
|---|
| 434 | | Length, |
|---|
| 435 | | Question, |
|---|
| 436 | | Backslash, |
|---|
| 437 | | Arrow, |
|---|
| 438 | | Dollar, |
|---|
| 439 | | |
|---|
| 440 | | Ident, |
|---|
| 441 | | CharLiteral, |
|---|
| 442 | | StringLiteral, |
|---|
| 443 | | IntLiteral, |
|---|
| 444 | | FloatLiteral, |
|---|
| 445 | | EOF |
|---|
| 446 | | } |
|---|
| 447 | | |
|---|
| 448 | | public static const dchar[][] tokenStrings = |
|---|
| 449 | | [ |
|---|
| 450 | | Type.As: "as", |
|---|
| 451 | | Type.Assert: "assert", |
|---|
| 452 | | Type.Break: "break", |
|---|
| 453 | | Type.Case: "case", |
|---|
| 454 | | Type.Catch: "catch", |
|---|
| 455 | | Type.Continue: "continue", |
|---|
| 456 | | Type.Coroutine: "coroutine", |
|---|
| 457 | | Type.Default: "default", |
|---|
| 458 | | Type.Do: "do", |
|---|
| 459 | | Type.Else: "else", |
|---|
| 460 | | Type.False: "false", |
|---|
| 461 | | Type.Finally: "finally", |
|---|
| 462 | | Type.For: "for", |
|---|
| 463 | | Type.Foreach: "foreach", |
|---|
| 464 | | Type.Function: "function", |
|---|
| 465 | | Type.Global: "global", |
|---|
| 466 | | Type.If: "if", |
|---|
| 467 | | Type.Import: "import", |
|---|
| 468 | | Type.In: "in", |
|---|
| 469 | | Type.Is: "is", |
|---|
| 470 | | Type.Local: "local", |
|---|
| 471 | | Type.Module: "module", |
|---|
| 472 | | Type.Namespace: "namespace", |
|---|
| 473 | | Type.Null: "null", |
|---|
| 474 | | Type.Object: "object", |
|---|
| 475 | | Type.Return: "return", |
|---|
| 476 | | Type.Super: "super", |
|---|
| 477 | | Type.Switch: "switch", |
|---|
| 478 | | Type.This: "this", |
|---|
| 479 | | Type.Throw: "throw", |
|---|
| 480 | | Type.True: "true", |
|---|
| 481 | | Type.Try: "try", |
|---|
| 482 | | Type.Vararg: "vararg", |
|---|
| 483 | | Type.While: "while", |
|---|
| 484 | | Type.With: "with", |
|---|
| 485 | | Type.Yield: "yield", |
|---|
| 486 | | |
|---|
| 487 | | Type.Add: "+", |
|---|
| 488 | | Type.AddEq: "+=", |
|---|
| 489 | | Type.Inc: "++", |
|---|
| 490 | | Type.Sub: "-", |
|---|
| 491 | | Type.SubEq: "-=", |
|---|
| 492 | | Type.Dec: "--", |
|---|
| 493 | | Type.Cat: "~", |
|---|
| 494 | | Type.CatEq: "~=", |
|---|
| 495 | | Type.Cmp3: "<=>", |
|---|
| 496 | | Type.Mul: "*", |
|---|
| 497 | | Type.MulEq: "*=", |
|---|
| 498 | | Type.DefaultEq: "?=", |
|---|
| 499 | | Type.Div: "/", |
|---|
| 500 | | Type.DivEq: "/=", |
|---|
| 501 | | Type.Mod: "%", |
|---|
| 502 | | Type.ModEq: "%=", |
|---|
| 503 | | Type.LT: "<", |
|---|
| 504 | | Type.LE: "<=", |
|---|
| 505 | | Type.Shl: "<<", |
|---|
| 506 | | Type.ShlEq: "<<=", |
|---|
| 507 | | Type.GT: ">", |
|---|
| 508 | | Type.GE: ">=", |
|---|
| 509 | | Type.Shr: ">>", |
|---|
| 510 | | Type.ShrEq: ">>=", |
|---|
| 511 | | Type.UShr: ">>>", |
|---|
| 512 | | Type.UShrEq: ">>>=", |
|---|
| 513 | | Type.And: "&", |
|---|
| 514 | | Type.AndEq: "&=", |
|---|
| 515 | | Type.AndAnd: "&&", |
|---|
| 516 | | Type.Or: "|", |
|---|
| 517 | | Type.OrEq: "|=", |
|---|
| 518 | | Type.OrOr: "||", |
|---|
| 519 | | Type.Xor: "^", |
|---|
| 520 | | Type.XorEq: "^=", |
|---|
| 521 | | Type.Assign: "=", |
|---|
| 522 | | Type.EQ: "==", |
|---|
| 523 | | Type.Dot: ".", |
|---|
| 524 | | Type.DotDot: "..", |
|---|
| 525 | | Type.Not: "!", |
|---|
| 526 | | Type.NE: "!=", |
|---|
| 527 | | Type.LParen: "(", |
|---|
| 528 | | Type.RParen: ")", |
|---|
| 529 | | Type.LBracket: "[", |
|---|
| 530 | | Type.RBracket: "]", |
|---|
| 531 | | Type.LBrace: "{", |
|---|
| 532 | | Type.RBrace: "}", |
|---|
| 533 | | Type.LAttr: "</", |
|---|
| 534 | | Type.RAttr: "/>", |
|---|
| 535 | | Type.Colon: ":", |
|---|
| 536 | | Type.Comma: ",", |
|---|
| 537 | | Type.Semicolon: ";", |
|---|
| 538 | | Type.Length: "#", |
|---|
| 539 | | Type.Question: "?", |
|---|
| 540 | | Type.Backslash: "\\", |
|---|
| 541 | | Type.Arrow: "->", |
|---|
| 542 | | Type.Dollar: "$", |
|---|
| 543 | | |
|---|
| 544 | | Type.Ident: "Identifier", |
|---|
| 545 | | Type.CharLiteral: "Char Literal", |
|---|
| 546 | | Type.StringLiteral: "String Literal", |
|---|
| 547 | | Type.IntLiteral: "Int Literal", |
|---|
| 548 | | Type.FloatLiteral: "Float Literal", |
|---|
| 549 | | Type.EOF: "<EOF>" |
|---|
| 550 | | ]; |
|---|
| 551 | | |
|---|
| 552 | | public static Type[dchar[]] stringToType; |
|---|
| 553 | | |
|---|
| 554 | | static this() |
|---|
| 555 | | { |
|---|
| 556 | | foreach(i, val; tokenStrings[0 .. Type.Ident]) |
|---|
| 557 | | stringToType[val] = cast(Type)i; |
|---|
| 558 | | |
|---|
| 559 | | stringToType.rehash; |
|---|
| 560 | | } |
|---|
| 561 | | |
|---|
| 562 | | public char[] toString() |
|---|
| 563 | | { |
|---|
| 564 | | switch(type) |
|---|
| 565 | | { |
|---|
| 566 | | case Type.Ident: return "Identifier: " ~ utf.toString(stringValue); |
|---|
| 567 | | case Type.CharLiteral: return "Character Literal"; |
|---|
| 568 | | case Type.StringLiteral: return "String Literal"; |
|---|
| 569 | | case Type.IntLiteral: return "Integer Literal: " ~ Integer.toString(intValue); |
|---|
| 570 | | case Type.FloatLiteral: return "Float Literal: " ~ Float.toString(floatValue); |
|---|
| 571 | | default: return utf.toString(tokenStrings[cast(uint)type]); |
|---|
| 572 | | } |
|---|
| 573 | | |
|---|
| 574 | | assert(false); |
|---|
| 575 | | } |
|---|
| 576 | | |
|---|
| 577 | | public void expect(Type t) |
|---|
| 578 | | { |
|---|
| 579 | | if(type != t) |
|---|
| 580 | | expected(tokenStrings[t]); |
|---|
| 581 | | } |
|---|
| 582 | | |
|---|
| 583 | | public void expected(dchar[] message) |
|---|
| 584 | | { |
|---|
| 585 | | auto e = new OldCompileException(location, "'{}' expected; found '{}' instead", message, tokenStrings[type]); |
|---|
| 586 | | e.atEOF = type == Type.EOF; |
|---|
| 587 | | throw e; |
|---|
| 588 | | } |
|---|
| 589 | | |
|---|
| 590 | | public bool isOpAssign() |
|---|
| 591 | | { |
|---|
| 592 | | switch(type) |
|---|
| 593 | | { |
|---|
| 594 | | case Token.AddEq, |
|---|
| 595 | | Token.SubEq, |
|---|
| 596 | | Token.CatEq, |
|---|
| 597 | | Token.MulEq, |
|---|
| 598 | | Token.DivEq, |
|---|
| 599 | | Token.ModEq, |
|---|
| 600 | | Token.ShlEq, |
|---|
| 601 | | Token.ShrEq, |
|---|
| 602 | | Token.UShrEq, |
|---|
| 603 | | Token.OrEq, |
|---|
| 604 | | Token.XorEq, |
|---|
| 605 | | Token.AndEq, |
|---|
| 606 | | Token.DefaultEq: |
|---|
| 607 | | return true; |
|---|
| 608 | | |
|---|
| 609 | | default: |
|---|
| 610 | | return false; |
|---|
| 611 | | } |
|---|
| 612 | | |
|---|
| 613 | | assert(false); |
|---|
| 614 | | } |
|---|
| 615 | | |
|---|
| 616 | | public Type type; |
|---|
| 617 | | |
|---|
| 618 | | union |
|---|
| 619 | | { |
|---|
| 620 | | public bool boolValue; |
|---|
| 621 | | public dchar[] stringValue; |
|---|
| 622 | | public int intValue; |
|---|
| 623 | | public mdfloat floatValue; |
|---|
| 624 | | } |
|---|
| 625 | | |
|---|
| 626 | | public CompileLoc location; |
|---|
| 627 | | } |
|---|
| 628 | | |
|---|
| 629 | | class Lexer |
|---|
| 630 | | { |
|---|
| 631 | | protected dchar[] mSource; |
|---|
| 632 | | protected CompileLoc mLoc; |
|---|
| 633 | | protected uword mPosition; |
|---|
| 634 | | protected dchar mCharacter; |
|---|
| 635 | | protected dchar mLookaheadCharacter; |
|---|
| 636 | | protected bool mHaveLookahead = false; |
|---|
| 637 | | protected bool mIsJSON = false; |
|---|
| 638 | | protected Token mTok; |
|---|
| 639 | | protected Token mPeekTok; |
|---|
| 640 | | protected bool mHavePeekTok = false; |
|---|
| 641 | | protected bool mNewlineSinceLastTok = false; |
|---|
| 642 | | |
|---|
| 643 | | public this(char[] name, dchar[] source, bool isJSON = false) |
|---|
| 644 | | { |
|---|
| 645 | | mLoc = CompileLoc(utf.toString32(name), 1, 0); |
|---|
| 646 | | |
|---|
| 647 | | mSource = source; |
|---|
| 648 | | mPosition = 0; |
|---|
| 649 | | mIsJSON = isJSON; |
|---|
| 650 | | |
|---|
| 651 | | nextChar(); |
|---|
| 652 | | |
|---|
| 653 | | if(mSource.length >= 2 && mSource[0 .. 2] == "#!") |
|---|
| 654 | | while(!isEOL()) |
|---|
| 655 | | nextChar(); |
|---|
| 656 | | |
|---|
| 657 | | next(); |
|---|
| 658 | | } |
|---|
| 659 | | |
|---|
| 660 | | public final Token* tok() |
|---|
| 661 | | { |
|---|
| 662 | | return &mTok; |
|---|
| 663 | | } |
|---|
| 664 | | |
|---|
| 665 | | public final CompileLoc loc() |
|---|
| 666 | | { |
|---|
| 667 | | return mTok.location; |
|---|
| 668 | | } |
|---|
| 669 | | |
|---|
| 670 | | public final Token.Type type() |
|---|
| 671 | | { |
|---|
| 672 | | return mTok.type; |
|---|
| 673 | | } |
|---|
| 674 | | |
|---|
| 675 | | public final Token expect(Token.Type t) |
|---|
| 676 | | { |
|---|
| 677 | | mTok.expect(t); |
|---|
| 678 | | Token ret = mTok; |
|---|
| 679 | | |
|---|
| 680 | | if(t != Token.EOF) |
|---|
| 681 | | next(); |
|---|
| 682 | | |
|---|
| 683 | | return ret; |
|---|
| 684 | | } |
|---|
| 685 | | |
|---|
| 686 | | public final bool isStatementTerm() |
|---|
| 687 | | { |
|---|
| 688 | | return mNewlineSinceLastTok || |
|---|
| 689 | | mTok.type == Token.EOF || |
|---|
| 690 | | mTok.type == Token.Semicolon || |
|---|
| 691 | | mTok.type == Token.RBrace || |
|---|
| 692 | | mTok.type == Token.RParen || |
|---|
| 693 | | mTok.type == Token.RBracket; |
|---|
| 694 | | } |
|---|
| 695 | | |
|---|
| 696 | | public final void statementTerm() |
|---|
| 697 | | { |
|---|
| 698 | | if(mNewlineSinceLastTok) |
|---|
| 699 | | return; |
|---|
| 700 | | else |
|---|
| 701 | | { |
|---|
| 702 | | if(mTok.type == Token.EOF || mTok.type == Token.RBrace || mTok.type == Token.RParen || mTok.type == Token.RBracket) |
|---|
| 703 | | return; |
|---|
| 704 | | else if(mTok.type == Token.Semicolon) |
|---|
| 705 | | next(); |
|---|
| 706 | | else |
|---|
| 707 | | throw new OldCompileException(mLoc, "Statement terminator expected, not '{}'", mTok.toString()); |
|---|
| 708 | | } |
|---|
| 709 | | } |
|---|
| 710 | | |
|---|
| 711 | | public final Token peek() |
|---|
| 712 | | { |
|---|
| 713 | | if(mHavePeekTok) |
|---|
| 714 | | return mPeekTok; |
|---|
| 715 | | |
|---|
| 716 | | auto t = mTok; |
|---|
| 717 | | nextToken(); |
|---|
| 718 | | mHavePeekTok = true; |
|---|
| 719 | | mPeekTok = mTok; |
|---|
| 720 | | mTok = t; |
|---|
| 721 | | |
|---|
| 722 | | return mPeekTok; |
|---|
| 723 | | } |
|---|
| 724 | | |
|---|
| 725 | | public final void next() |
|---|
| 726 | | { |
|---|
| 727 | | if(mHavePeekTok) |
|---|
| 728 | | { |
|---|
| 729 | | mHavePeekTok = false; |
|---|
| 730 | | mTok = mPeekTok; |
|---|
| 731 | | } |
|---|
| 732 | | else |
|---|
| 733 | | nextToken(); |
|---|
| 734 | | } |
|---|
| 735 | | |
|---|
| 736 | | protected final bool isEOF() |
|---|
| 737 | | { |
|---|
| 738 | | return (mCharacter == '\0') || (mCharacter == dchar.init); |
|---|
| 739 | | } |
|---|
| 740 | | |
|---|
| 741 | | protected final bool isEOL() |
|---|
| 742 | | { |
|---|
| 743 | | return isNewline() || isEOF(); |
|---|
| 744 | | } |
|---|
| 745 | | |
|---|
| 746 | | protected final bool isWhitespace() |
|---|
| 747 | | { |
|---|
| 748 | | return (mCharacter == ' ') || (mCharacter == '\t') || (mCharacter == '\v') || (mCharacter == '\u000C') || isEOL(); |
|---|
| 749 | | } |
|---|
| 750 | | |
|---|
| 751 | | protected final bool isNewline() |
|---|
| 752 | | { |
|---|
| 753 | | return (mCharacter == '\r') || (mCharacter == '\n'); |
|---|
| 754 | | } |
|---|
| 755 | | |
|---|
| 756 | | protected final bool isBinaryDigit() |
|---|
| 757 | | { |
|---|
| 758 | | return (mCharacter == '0') || (mCharacter == '1'); |
|---|
| 759 | | } |
|---|
| 760 | | |
|---|
| 761 | | protected final bool isOctalDigit() |
|---|
| 762 | | { |
|---|
| 763 | | return (mCharacter >= '0') && (mCharacter <= '7'); |
|---|
| 764 | | } |
|---|
| 765 | | |
|---|
| 766 | | protected final bool isHexDigit() |
|---|
| 767 | | { |
|---|
| 768 | | return ((mCharacter >= '0') && (mCharacter <= '9')) || |
|---|
| 769 | | ((mCharacter >= 'a') && (mCharacter <= 'f')) || |
|---|
| 770 | | ((mCharacter >= 'A') && (mCharacter <= 'F')); |
|---|
| 771 | | } |
|---|
| 772 | | |
|---|
| 773 | | protected final bool isDecimalDigit() |
|---|
| 774 | | { |
|---|
| 775 | | return (mCharacter >= '0') && (mCharacter <= '9'); |
|---|
| 776 | | } |
|---|
| 777 | | |
|---|
| 778 | | protected final bool isAlpha() |
|---|
| 779 | | { |
|---|
| 780 | | return ((mCharacter >= 'a') && (mCharacter <= 'z')) || ((mCharacter >= 'A') && (mCharacter <= 'Z')); |
|---|
| 781 | | } |
|---|
| 782 | | |
|---|
| 783 | | protected final ubyte hexDigitToInt(dchar c) |
|---|
| 784 | | { |
|---|
| 785 | | assert((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'), "hexDigitToInt"); |
|---|
| 786 | | |
|---|
| 787 | | if(c >= '0' && c <= '9') |
|---|
| 788 | | return cast(ubyte)(c - '0'); |
|---|
| 789 | | |
|---|
| 790 | | if(Uni.isUpper(c)) |
|---|
| 791 | | return cast(ubyte)(c - 'A' + 10); |
|---|
| 792 | | else |
|---|
| 793 | | return cast(ubyte)(c - 'a' + 10); |
|---|
| 794 | | } |
|---|
| 795 | | |
|---|
| 796 | | protected final dchar readChar() |
|---|
| 797 | | { |
|---|
| 798 | | if(mPosition >= mSource.length) |
|---|
| 799 | | return dchar.init; |
|---|
| 800 | | else |
|---|
| 801 | | return mSource[mPosition++]; |
|---|
| 802 | | } |
|---|
| 803 | | |
|---|
| 804 | | protected final dchar lookaheadChar() |
|---|
| 805 | | { |
|---|
| 806 | | assert(mHaveLookahead == false, "looking ahead too far"); |
|---|
| 807 | | |
|---|
| 808 | | mLookaheadCharacter = readChar(); |
|---|
| 809 | | mHaveLookahead = true; |
|---|
| 810 | | return mLookaheadCharacter; |
|---|
| 811 | | } |
|---|
| 812 | | |
|---|
| 813 | | protected final void nextChar() |
|---|
| 814 | | { |
|---|
| 815 | | mLoc.column++; |
|---|
| 816 | | |
|---|
| 817 | | if(mHaveLookahead) |
|---|
| 818 | | { |
|---|
| 819 | | mCharacter = mLookaheadCharacter; |
|---|
| 820 | | mHaveLookahead = false; |
|---|
| 821 | | } |
|---|
| 822 | | else |
|---|
| 823 | | { |
|---|
| 824 | | mCharacter = readChar(); |
|---|
| 825 | | } |
|---|
| 826 | | } |
|---|
| 827 | | |
|---|
| 828 | | protected final void nextLine() |
|---|
| 829 | | { |
|---|
| 830 | | while(isNewline() && !isEOF()) |
|---|
| 831 | | { |
|---|
| 832 | | dchar old = mCharacter; |
|---|
| 833 | | |
|---|
| 834 | | nextChar(); |
|---|
| 835 | | |
|---|
| 836 | | if(isNewline() && mCharacter != old) |
|---|
| 837 | | nextChar(); |
|---|
| 838 | | |
|---|
| 839 | | mLoc.line++; |
|---|
| 840 | | mLoc.column = 1; |
|---|
| 841 | | } |
|---|
| 842 | | } |
|---|
| 843 | | |
|---|
| 844 | | protected final bool readNumLiteral(bool prependPoint, out mdfloat fret, out int iret) |
|---|
| 845 | | { |
|---|
| 846 | | CompileLoc beginning = mLoc; |
|---|
| 847 | | dchar[100] buf; |
|---|
| 848 | | uint i = 0; |
|---|
| 849 | | |
|---|
| 850 | | void add(dchar c) |
|---|
| 851 | | { |
|---|
| 852 | | buf[i] = c; |
|---|
| 853 | | i++; |
|---|
| 854 | | } |
|---|
| 855 | | |
|---|
| 856 | | bool hasPoint = false; |
|---|
| 857 | | |
|---|
| 858 | | if(prependPoint) |
|---|
| 859 | | { |
|---|
| 860 | | hasPoint = true; |
|---|
| 861 | | add('.'); |
|---|
| 862 | | } |
|---|
| 863 | | else |
|---|
| 864 | | { |
|---|
| 865 | | if(mCharacter == '0') |
|---|
| 866 | | { |
|---|
| 867 | | nextChar(); |
|---|
| 868 | | |
|---|
| 869 | | switch(mCharacter) |
|---|
| 870 | | { |
|---|
| 871 | | case 'b', 'B': |
|---|
| 872 | | nextChar(); |
|---|
| 873 | | |
|---|
| 874 | | if(!isBinaryDigit() && mCharacter != '_') |
|---|
| 875 | | throw new OldCompileException(mLoc, "Binary digit expected, not '{}'", mCharacter); |
|---|
| 876 | | |
|---|
| 877 | | while(isBinaryDigit() || mCharacter == '_') |
|---|
| 878 | | { |
|---|
| 879 | | if(mCharacter != '_') |
|---|
| 880 | | add(mCharacter); |
|---|
| 881 | | |
|---|
| 882 | | nextChar(); |
|---|
| 883 | | } |
|---|
| 884 | | |
|---|
| 885 | | try |
|---|
| 886 | | iret = Integer.toInt(buf[0 .. i], 2); |
|---|
| 887 | | catch(IllegalArgumentException e) |
|---|
| 888 | | throw new OldCompileException(beginning, e.toString()); |
|---|
| 889 | | |
|---|
| 890 | | return true; |
|---|
| 891 | | |
|---|
| 892 | | case 'c', 'C': |
|---|
| 893 | | nextChar(); |
|---|
| 894 | | |
|---|
| 895 | | if(!isOctalDigit() && mCharacter != '_') |
|---|
| 896 | | throw new OldCompileException(mLoc, "Octal digit expected, not '{}'", mCharacter); |
|---|
| 897 | | |
|---|
| 898 | | while(isOctalDigit() || mCharacter == '_') |
|---|
| 899 | | { |
|---|
| 900 | | if(mCharacter != '_') |
|---|
| 901 | | add(mCharacter); |
|---|
| 902 | | |
|---|
| 903 | | nextChar(); |
|---|
| 904 | | } |
|---|
| 905 | | |
|---|
| 906 | | try |
|---|
| 907 | | iret = Integer.toInt(buf[0 .. i], 8); |
|---|
| 908 | | catch(IllegalArgumentException e) |
|---|
| 909 | | throw new OldCompileException(beginning, e.toString()); |
|---|
| 910 | | |
|---|
| 911 | | return true; |
|---|
| 912 | | |
|---|
| 913 | | case 'x', 'X': |
|---|
| 914 | | nextChar(); |
|---|
| 915 | | |
|---|
| 916 | | if(!isHexDigit() && mCharacter != '_') |
|---|
| 917 | | throw new OldCompileException(mLoc, "Hexadecimal digit expected, not '{}'", mCharacter); |
|---|
| 918 | | |
|---|
| 919 | | while(isHexDigit() || mCharacter == '_') |
|---|
| 920 | | { |
|---|
| 921 | | if(mCharacter != '_') |
|---|
| 922 | | add(mCharacter); |
|---|
| 923 | | |
|---|
| 924 | | nextChar(); |
|---|
| 925 | | } |
|---|
| 926 | | |
|---|
| 927 | | try |
|---|
| 928 | | iret = Integer.toInt(buf[0 .. i], 16); |
|---|
| 929 | | catch(IllegalArgumentException e) |
|---|
| 930 | | throw new OldCompileException(beginning, e.toString()); |
|---|
| 931 | | |
|---|
| 932 | | return true; |
|---|
| 933 | | |
|---|
| 934 | | default: |
|---|
| 935 | | add('0'); |
|---|
| 936 | | break; |
|---|
| 937 | | } |
|---|
| 938 | | } |
|---|
| 939 | | } |
|---|
| 940 | | |
|---|
| 941 | | while(hasPoint == false) |
|---|
| 942 | | { |
|---|
| 943 | | if(isDecimalDigit()) |
|---|
| 944 | | { |
|---|
| 945 | | add(mCharacter); |
|---|
| 946 | | nextChar(); |
|---|
| 947 | | } |
|---|
| 948 | | else if(mCharacter == '.') |
|---|
| 949 | | { |
|---|
| 950 | | auto ch = lookaheadChar(); |
|---|
| 951 | | |
|---|
| 952 | | if((ch >= '0' && ch <= '9') || ch == '_') |
|---|
| 953 | | { |
|---|
| 954 | | hasPoint = true; |
|---|
| 955 | | add(mCharacter); |
|---|
| 956 | | nextChar(); |
|---|
| 957 | | } |
|---|
| 958 | | else |
|---|
| 959 | | { |
|---|
| 960 | | // next token is either a .. or maybe it's .something |
|---|
| 961 | | break; |
|---|
| 962 | | } |
|---|
| 963 | | } |
|---|
| 964 | | else if(mCharacter == '_') |
|---|
| 965 | | { |
|---|
| 966 | | //REACHABLE? |
|---|
| 967 | | nextChar(); |
|---|
| 968 | | continue; |
|---|
| 969 | | } |
|---|
| 970 | | else |
|---|
| 971 | | // this will still handle exponents on literals without a decimal point |
|---|
| 972 | | break; |
|---|
| 973 | | } |
|---|
| 974 | | |
|---|
| 975 | | if(hasPoint) |
|---|
| 976 | | { |
|---|
| 977 | | if(isDecimalDigit()) |
|---|
| 978 | | { |
|---|
| 979 | | add(mCharacter); |
|---|
| 980 | | nextChar(); |
|---|
| 981 | | } |
|---|
| 982 | | else if(mCharacter == '_') |
|---|
| 983 | | nextChar(); |
|---|
| 984 | | else |
|---|
| 985 | | { |
|---|
| 986 | | // REACHABLE? |
|---|
| 987 | | throw new OldCompileException(mLoc, "Floating point literal '{}' must have at least one digit after decimal point", buf[0 .. i]); |
|---|
| 988 | | } |
|---|
| 989 | | } |
|---|
| 990 | | |
|---|
| 991 | | bool hasExponent = false; |
|---|
| 992 | | |
|---|
| 993 | | while(true) |
|---|
| 994 | | { |
|---|
| 995 | | if(isDecimalDigit()) |
|---|
| 996 | | { |
|---|
| 997 | | add(mCharacter); |
|---|
| 998 | | nextChar(); |
|---|
| 999 | | } |
|---|
| 1000 | | else if(mCharacter == 'e' || mCharacter == 'E') |
|---|
| 1001 | | { |
|---|
| 1002 | | hasExponent = true; |
|---|
| 1003 | | |
|---|
| 1004 | | add(mCharacter); |
|---|
| 1005 | | |
|---|
| 1006 | | nextChar(); |
|---|
| 1007 | | |
|---|
| 1008 | | if(mCharacter == '-' || mCharacter == '+') |
|---|
| 1009 | | { |
|---|
| 1010 | | add(mCharacter); |
|---|
| 1011 | | nextChar(); |
|---|
| 1012 | | } |
|---|
| 1013 | | |
|---|
| 1014 | | if(!isDecimalDigit() && mCharacter != '_') |
|---|
| 1015 | | throw new OldCompileException(mLoc, "Exponent value expected in float literal '{}'", buf[0 .. i]); |
|---|
| 1016 | | |
|---|
| 1017 | | while(isDecimalDigit() || mCharacter == '_') |
|---|
| 1018 | | { |
|---|
| 1019 | | if(mCharacter != '_') |
|---|
| 1020 | | add(mCharacter); |
|---|
| 1021 | | |
|---|
| 1022 | | nextChar(); |
|---|
| 1023 | | } |
|---|
| 1024 | | |
|---|
| 1025 | | break; |
|---|
| 1026 | | } |
|---|
| 1027 | | else if(mCharacter == '_') |
|---|
| 1028 | | { |
|---|
| 1029 | | nextChar(); |
|---|
| 1030 | | continue; |
|---|
| 1031 | | } |
|---|
| 1032 | | else |
|---|
| 1033 | | break; |
|---|
| 1034 | | } |
|---|
| 1035 | | |
|---|
| 1036 | | if(hasPoint == false && hasExponent == false) |
|---|
| 1037 | | { |
|---|
| 1038 | | try |
|---|
| 1039 | | iret = Integer.toInt(buf[0 .. i], 10); |
|---|
| 1040 | | catch(IllegalArgumentException e) |
|---|
| 1041 | | throw new OldCompileException(beginning, e.toString()); |
|---|
| 1042 | | |
|---|
| 1043 | | return true; |
|---|
| 1044 | | } |
|---|
| 1045 | | else |
|---|
| 1046 | | { |
|---|
| 1047 | | try |
|---|
| 1048 | | fret = Float.toFloat(utf.toString(buf[0 .. i])); |
|---|
| 1049 | | catch(IllegalArgumentException e) |
|---|
| 1050 | | throw new OldCompileException(beginning, e.toString()); |
|---|
| 1051 | | |
|---|
| 1052 | | return false; |
|---|
| 1053 | | } |
|---|
| 1054 | | } |
|---|
| 1055 | | |
|---|
| 1056 | | protected final dchar readEscapeSequence(CompileLoc beginning) |
|---|
| 1057 | | { |
|---|
| 1058 | | uint readHexDigits(uint num) |
|---|
| 1059 | | { |
|---|
| 1060 | | uint ret = 0; |
|---|
| 1061 | | |
|---|
| 1062 | | for(uint i = 0; i < num; i++) |
|---|
| 1063 | | { |
|---|
| 1064 | | if(isHexDigit() == false) |
|---|
| 1065 | | throw new OldCompileException(mLoc, "Hexadecimal escape digits expected"); |
|---|
| 1066 | | |
|---|
| 1067 | | ret <<= 4; |
|---|
| 1068 | | ret |= hexDigitToInt(mCharacter); |
|---|
| 1069 | | nextChar(); |
|---|
| 1070 | | } |
|---|
| 1071 | | |
|---|
| 1072 | | return ret; |
|---|
| 1073 | | } |
|---|
| 1074 | | |
|---|
| 1075 | | dchar ret; |
|---|
| 1076 | | |
|---|
| 1077 | | assert(mCharacter == '\\', "escape seq - must start on backslash"); |
|---|
| 1078 | | |
|---|
| 1079 | | nextChar(); |
|---|
| 1080 | | if(isEOF()) |
|---|
| 1081 | | { |
|---|
| 1082 | | auto e = new OldCompileException(beginning, "Unterminated string or character literal"); |
|---|
| 1083 | | e.atEOF = true; |
|---|
| 1084 | | throw e; |
|---|
| 1085 | | } |
|---|
| 1086 | | |
|---|
| 1087 | | switch(mCharacter) |
|---|
| 1088 | | { |
|---|
| 1089 | | case 'a': nextChar(); return '\a'; |
|---|
| 1090 | | case 'b': nextChar(); return '\b'; |
|---|
| 1091 | | &nb |
|---|