001 /* This file was generated with JastAdd2 (http://jastadd.org) version 2.1.13-12-g880e696 */ 002 package org.extendj.ast; 003 004 import java.util.HashSet; 005 import java.io.File; 006 import java.util.Set; 007 import java.util.Collections; 008 import java.util.Collection; 009 import java.util.ArrayList; 010 import beaver.*; 011 import java.util.*; 012 import java.io.ByteArrayOutputStream; 013 import java.io.PrintStream; 014 import java.lang.reflect.InvocationTargetException; 015 import java.lang.reflect.Method; 016 import org.jastadd.util.*; 017 import java.util.zip.*; 018 import java.io.*; 019 import org.jastadd.util.PrettyPrintable; 020 import org.jastadd.util.PrettyPrinter; 021 import java.io.FileNotFoundException; 022 import java.io.BufferedInputStream; 023 import java.io.DataInputStream; 024 /** 025 * A NumericLiteral is a raw literal, produced by the parser. 026 * NumericLiterals are rewritten to the best matching concrete 027 * numeric literal kind, or IllegalLiteral. 028 * @ast node 029 * @declaredat /home/jesper/git/extendj/java7/grammar/Literals.ast:18 030 * @production NumericLiteral : {@link Literal}; 031 032 */ 033 public class NumericLiteral extends Literal implements Cloneable { 034 /** 035 * @aspect Java7Literals 036 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:360 037 */ 038 public static final int DECIMAL = 0; 039 /** 040 * @aspect Java7Literals 041 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:361 042 */ 043 public static final int HEXADECIMAL = 1; 044 /** 045 * @aspect Java7Literals 046 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:362 047 */ 048 public static final int OCTAL = 2; 049 /** 050 * @aspect Java7Literals 051 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:363 052 */ 053 public static final int BINARY = 3; 054 /** 055 * The trimmed digits. 056 * @aspect Java7Literals 057 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:421 058 */ 059 protected String digits = ""; 060 /** 061 * Sets the trimmed digits of this literal. 062 * @aspect Java7Literals 063 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:426 064 */ 065 public void setDigits(String digits) { 066 this.digits = digits; 067 } 068 /** 069 * The literal kind tells which kind of literal it is; 070 * either a DECIMAL, HEXADECIMAL, OCTAL or BINARY literal. 071 * @aspect Java7Literals 072 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:440 073 */ 074 protected int kind = NumericLiteral.DECIMAL; 075 /** 076 * Sets the literal kind. 077 * @aspect Java7Literals 078 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:445 079 */ 080 public void setKind(int kind) { 081 this.kind = kind; 082 } 083 /** 084 * @aspect Java7Literals 085 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:528 086 */ 087 088 private StringBuffer buf = new StringBuffer(); 089 /** 090 * @aspect Java7Literals 091 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:529 092 */ 093 094 private int idx = 0; 095 /** 096 * @aspect Java7Literals 097 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:530 098 */ 099 100 private boolean whole; 101 /** 102 * @aspect Java7Literals 103 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:531 104 */ 105 // have whole part? 106 private boolean fraction; 107 /** 108 * @aspect Java7Literals 109 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:532 110 */ 111 // have fraction part? 112 private boolean exponentSpecifier; 113 /** 114 * @aspect Java7Literals 115 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:533 116 */ 117 // have exponent specifier? 118 private boolean exponent; 119 /** 120 * @aspect Java7Literals 121 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:534 122 */ 123 // have exponent part? 124 private boolean floating; 125 /** 126 * @aspect Java7Literals 127 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:535 128 */ 129 // is floating point? 130 private boolean isFloat; 131 /** 132 * @aspect Java7Literals 133 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:536 134 */ 135 136 private boolean isLong; 137 /** 138 * @return a readable name to describe this literal. 139 * @aspect Java7Literals 140 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:541 141 */ 142 143 144 /** 145 * @return a readable name to describe this literal. 146 */ 147 private String name() { 148 String name; 149 switch (kind) { 150 case DECIMAL: 151 name = "decimal"; 152 break; 153 case HEXADECIMAL: 154 name = "hexadecimal"; 155 break; 156 case OCTAL: 157 name = "octal"; 158 break; 159 case BINARY: 160 default: 161 name = "binary"; 162 break; 163 } 164 if (floating) { 165 return name + " floating point"; 166 } else { 167 return name; 168 } 169 } 170 /** 171 * The next character in the literal is a significant character; 172 * push it onto the buffer. 173 * @aspect Java7Literals 174 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:569 175 */ 176 177 178 /** 179 * The next character in the literal is a significant character; 180 * push it onto the buffer. 181 */ 182 private void pushChar() { 183 buf.append(getLITERAL().charAt(idx++)); 184 } 185 /** 186 * Skip ahead n chracters in the literal. 187 * @aspect Java7Literals 188 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:576 189 */ 190 191 192 /** 193 * Skip ahead n chracters in the literal. 194 */ 195 private void skip(int n) { 196 idx += n; 197 } 198 /** 199 * @return true if there exists at least n more characters 200 * in the literal 201 * @aspect Java7Literals 202 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:584 203 */ 204 205 206 /** 207 * @return true if there exists at least n more characters 208 * in the literal 209 */ 210 private boolean have(int n) { 211 return getLITERAL().length() >= idx + n; 212 } 213 /** 214 * Look at the n'th next character. 215 * @aspect Java7Literals 216 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:591 217 */ 218 219 220 /** 221 * Look at the n'th next character. 222 */ 223 private char peek(int n) { 224 return getLITERAL().charAt(idx + n); 225 } 226 /** 227 * @return true if the character c is a decimal digit 228 * @aspect Java7Literals 229 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:598 230 */ 231 232 233 /** 234 * @return true if the character c is a decimal digit 235 */ 236 private static final boolean isDecimalDigit(char c) { 237 return c == '_' || c >= '0' && c <= '9'; 238 } 239 /** 240 * @return true if the character c is a hexadecimal digit 241 * @aspect Java7Literals 242 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:605 243 */ 244 245 246 /** 247 * @return true if the character c is a hexadecimal digit 248 */ 249 private static final boolean isHexadecimalDigit(char c) { 250 return c == '_' || c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F'; 251 } 252 /** 253 * @return true if the character c is a binary digit 254 * @aspect Java7Literals 255 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:612 256 */ 257 258 259 /** 260 * @return true if the character c is a binary digit 261 */ 262 private static final boolean isBinaryDigit(char c) { 263 return c == '_' || c == '0' || c == '1'; 264 } 265 /** 266 * @return true if the character c is an underscore 267 * @aspect Java7Literals 268 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:619 269 */ 270 271 272 /** 273 * @return true if the character c is an underscore 274 */ 275 private static final boolean isUnderscore(char c) { 276 return c == '_'; 277 } 278 /** 279 * Parse a literal. If there is a syntax error in the literal, 280 * an IllegalLiteral will be returned. 281 * @aspect Java7Literals 282 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:627 283 */ 284 285 286 /** 287 * Parse a literal. If there is a syntax error in the literal, 288 * an IllegalLiteral will be returned. 289 */ 290 public Literal parse() { 291 if (getLITERAL().length() == 0) { 292 throw new IllegalStateException("Empty NumericLiteral"); 293 } 294 295 kind = classifyLiteral(); 296 297 Literal literal; 298 if (!floating) { 299 literal = parseDigits(); 300 } else { 301 literal = parseFractionPart(); 302 } 303 literal.setStart(LITERALstart); 304 literal.setEnd(LITERALend); 305 return literal; 306 } 307 /** 308 * Classify the literal. 309 * 310 * @return either DECIMAL, HEXADECIMAL or BINARY 311 * @aspect Java7Literals 312 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:650 313 */ 314 315 316 /** 317 * Classify the literal. 318 * 319 * @return either DECIMAL, HEXADECIMAL or BINARY 320 */ 321 private int classifyLiteral() { 322 if (peek(0) == '.') { 323 floating = true; 324 return DECIMAL; 325 } else if (peek(0) == '0') { 326 if (!have(2)) { 327 // the only 1-length string that starts with 0 (obvious!) 328 return DECIMAL; 329 } else if (peek(1) == 'x' || peek(1) == 'X') { 330 skip(2); 331 return HEXADECIMAL; 332 } else if (peek(1) == 'b' || peek(1) == 'B') { 333 skip(2); 334 return BINARY; 335 } else { 336 return DECIMAL; 337 } 338 } else { 339 return DECIMAL; 340 } 341 } 342 /** 343 * If the current character is an underscore, the previous and next 344 * characters need to be valid digits or underscores. 345 * 346 * @return true if the underscore is misplaced 347 * @aspect Java7Literals 348 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:678 349 */ 350 351 352 /** 353 * If the current character is an underscore, the previous and next 354 * characters need to be valid digits or underscores. 355 * 356 * @return true if the underscore is misplaced 357 */ 358 private boolean misplacedUnderscore() { 359 // first and last characters are never allowed to be an underscore 360 if (idx == 0 || idx+1 == getLITERAL().length()) { 361 return true; 362 } 363 364 switch (kind) { 365 case DECIMAL: 366 return !(isDecimalDigit(peek(-1)) && isDecimalDigit(peek(1))); 367 case HEXADECIMAL: 368 return !(isHexadecimalDigit(peek(-1)) && isHexadecimalDigit(peek(1))); 369 case BINARY: 370 return !(isBinaryDigit(peek(-1)) && isBinaryDigit(peek(1))); 371 } 372 throw new IllegalStateException("Unexpected literal kind"); 373 } 374 /** 375 * Report an illegal digit. 376 * @aspect Java7Literals 377 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:698 378 */ 379 380 381 /** 382 * Report an illegal digit. 383 */ 384 private Literal syntaxError(String msg) { 385 return new IllegalLiteral( 386 String.format("in %s literal \"%s\": %s", name(), getLITERAL(), msg)); 387 } 388 /** 389 * @aspect Java7Literals 390 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:703 391 */ 392 393 394 private Literal unexpectedCharacter(char c) { 395 return syntaxError("unexpected character '" + c + "'; not a valid digit"); 396 } 397 /** 398 * Returns a string of only the lower case digits of the 399 * parsed numeric literal. 400 * @aspect Java7Literals 401 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:711 402 */ 403 404 405 /** 406 * Returns a string of only the lower case digits of the 407 * parsed numeric literal. 408 */ 409 private String getLiteralString() { 410 return buf.toString().toLowerCase(); 411 } 412 /** 413 * Parse and build an IntegerLiteral, LongLiteral, 414 * FloatingPointLiteral or DoubleLiteral. Returns an 415 * IllegalLiteral if the numeric literal can not be 416 * parsed. 417 * 418 * Note: does not perform bounds checks. 419 * 420 * @return a concrete literal on success, or an IllegalLiteral if there is a syntax error 421 * @aspect Java7Literals 422 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:725 423 */ 424 425 426 /** 427 * Parse and build an IntegerLiteral, LongLiteral, 428 * FloatingPointLiteral or DoubleLiteral. Returns an 429 * IllegalLiteral if the numeric literal can not be 430 * parsed. 431 * 432 * Note: does not perform bounds checks. 433 * 434 * @return a concrete literal on success, or an IllegalLiteral if there is a syntax error 435 */ 436 private Literal buildLiteral() { 437 NumericLiteral literal; 438 setDigits(buf.toString().toLowerCase()); 439 440 if (!floating) { 441 if (!whole) { 442 return syntaxError("at least one digit is required"); 443 } 444 445 // check if the literal is octal, and if so report illegal digits 446 if (kind == DECIMAL) { 447 if (digits.charAt(0) == '0') { 448 kind = OCTAL; 449 for (int idx = 1; idx < digits.length(); ++idx) { 450 char c = digits.charAt(idx); 451 if (c < '0' || c > '7') { 452 return unexpectedCharacter(c); 453 } 454 } 455 } 456 } 457 458 if (isLong) { 459 literal = new LongLiteral(getLITERAL()); 460 } else { 461 literal = new IntegerLiteral(getLITERAL()); 462 } 463 } else { 464 if (kind == HEXADECIMAL && !exponent) { 465 return syntaxError("exponent is missing"); 466 } 467 468 if (exponentSpecifier && !exponent) { 469 return syntaxError("expected exponent after exponent specifier"); 470 } 471 472 if (!(whole || fraction)) { 473 return syntaxError("at least one digit is required in " 474 + "either the whole or fraction part"); 475 } 476 477 if (kind == HEXADECIMAL) { 478 digits = "0x"+digits;// digits parsed with Float or Double 479 } 480 481 if (isFloat) { 482 literal = new FloatingPointLiteral(getLITERAL()); 483 } else { 484 literal = new DoubleLiteral(getLITERAL()); 485 } 486 } 487 488 literal.setDigits(getDigits()); 489 literal.setKind(getKind()); 490 return literal; 491 } 492 /** 493 * @aspect Java7Literals 494 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:782 495 */ 496 497 498 private Literal parseDigits() { 499 // While we have at least one more character/digit 500 while (have(1)) { 501 char c = peek(0); 502 switch (c) { 503 case '_': 504 if (misplacedUnderscore()) { 505 return syntaxError("misplaced underscore - underscores may only " 506 + "be used within sequences of digits"); 507 } 508 skip(1); 509 continue; 510 case '.': 511 if (kind != DECIMAL && kind != HEXADECIMAL) { 512 return unexpectedCharacter(c); 513 } 514 return parseFractionPart(); 515 case 'l': 516 case 'L': 517 if (have(2)) { 518 return syntaxError("extra digits/characters after suffix " + c); 519 } 520 isLong = true; 521 skip(1); 522 continue; 523 case 'f': 524 case 'F': 525 if (kind == BINARY) { 526 return unexpectedCharacter(c); 527 } 528 isFloat = true; 529 case 'd': 530 case 'D': 531 if (kind == BINARY) { 532 return unexpectedCharacter(c); 533 } 534 if (kind != HEXADECIMAL) { 535 if (have(2)) { 536 return syntaxError("extra digits/characters after type suffix " + c); 537 } 538 floating = true; 539 skip(1); 540 } else { 541 whole = true; 542 pushChar(); 543 } 544 continue; 545 } 546 547 switch (kind) { 548 case DECIMAL: 549 if (c == 'e' || c == 'E') { 550 return parseExponentPart(); 551 552 } else if (c == 'f' || c == 'F') { 553 if (have(2)) { 554 return syntaxError("extra digits/characters after type suffix " + c); 555 } 556 floating = true; 557 isFloat = true; 558 skip(1); 559 } else if (c == 'd' || c == 'D') { 560 if (have(2)) { 561 return syntaxError("extra digits/characters after type suffix " + c); 562 } 563 floating = true; 564 skip(1); 565 } else { 566 if (!isDecimalDigit(c)) { 567 return unexpectedCharacter(c); 568 } 569 whole = true; 570 pushChar(); 571 } 572 continue; 573 case HEXADECIMAL: 574 if (c == 'p' || c == 'P') { 575 return parseExponentPart(); 576 } 577 578 if (!isHexadecimalDigit(c)) { 579 return unexpectedCharacter(c); 580 } 581 whole = true; 582 pushChar(); 583 continue; 584 case BINARY: 585 if (!isBinaryDigit(c)) { 586 return unexpectedCharacter(c); 587 } 588 whole = true; 589 pushChar(); 590 continue; 591 } 592 } 593 594 return buildLiteral(); 595 } 596 /** 597 * @aspect Java7Literals 598 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:881 599 */ 600 601 602 private Literal parseFractionPart() { 603 floating = true; 604 605 // Current char is the decimal period. 606 pushChar(); 607 608 // While we have at least one more character/digit. 609 while (have(1)) { 610 char c = peek(0); 611 switch (c) { 612 case '_': 613 if (misplacedUnderscore()) { 614 return syntaxError("misplaced underscore - underscores may only " 615 + "be used as separators within sequences of valid digits"); 616 } 617 skip(1); 618 continue; 619 case '.': 620 return syntaxError("multiple decimal periods are not allowed"); 621 } 622 623 if (kind == DECIMAL) { 624 if (c == 'e' || c == 'E') { 625 return parseExponentPart(); 626 627 } else if (c == 'f' || c == 'F') { 628 if (have(2)) { 629 return syntaxError("extra digits/characters after type suffix " + c); 630 } 631 floating = true; 632 isFloat = true; 633 skip(1); 634 } else if (c == 'd' || c == 'D') { 635 if (have(2)) { 636 return syntaxError("extra digits/characters after type suffix " + c); 637 } 638 floating = true; 639 skip(1); 640 } else { 641 if (!isDecimalDigit(c)) { 642 return unexpectedCharacter(c); 643 } 644 pushChar(); 645 fraction = true; 646 } 647 } else { // kind == HEXADECIMAL 648 if (c == 'p' || c == 'P') { 649 return parseExponentPart(); 650 } 651 652 if (!isHexadecimalDigit(c)) { 653 return unexpectedCharacter(c); 654 } 655 fraction = true; 656 pushChar(); 657 } 658 } 659 660 return buildLiteral(); 661 } 662 /** 663 * @aspect Java7Literals 664 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:942 665 */ 666 667 668 private Literal parseExponentPart() { 669 floating = true; 670 671 // Current char is the exponent specifier char. 672 pushChar(); 673 674 exponentSpecifier = true; 675 676 // Exponent sign. 677 if (have(1) && (peek(0) == '+' || peek(0) == '-')) { 678 pushChar(); 679 } 680 681 // While we have at least one more character/digit. 682 while (have(1)) { 683 char c = peek(0); 684 switch (c) { 685 case '_': 686 if (misplacedUnderscore()) { 687 return syntaxError("misplaced underscore - underscores may only " 688 + "be used as separators within sequences of valid digits"); 689 } 690 skip(1); 691 continue; 692 case '-': 693 case '+': 694 return syntaxError("exponent sign character is only allowed as " 695 + "the first character of the exponent part of a " 696 + "floating point literal"); 697 case '.': 698 return syntaxError("multiple decimal periods are not allowed"); 699 case 'p': 700 case 'P': 701 case 'e': 702 case 'E': 703 return syntaxError("multiple exponent specifiers are not allowed"); 704 case 'f': 705 case 'F': 706 isFloat = true; 707 case 'd': 708 case 'D': 709 if (have(2)) { 710 return syntaxError("extra digits/characters after type suffix " + c); 711 } 712 skip(1); 713 continue; 714 } 715 716 // Exponent is a signed integer. 717 if (!isDecimalDigit(c)) { 718 return unexpectedCharacter(c); 719 } 720 pushChar(); 721 exponent = true; 722 } 723 724 return buildLiteral(); 725 } 726 /** 727 * @declaredat ASTNode:1 728 */ 729 public NumericLiteral() { 730 super(); 731 } 732 /** 733 * Initializes the child array to the correct size. 734 * Initializes List and Opt nta children. 735 * @apilevel internal 736 * @ast method 737 * @declaredat ASTNode:10 738 */ 739 public void init$Children() { 740 } 741 /** 742 * @declaredat ASTNode:12 743 */ 744 public NumericLiteral(String p0) { 745 setLITERAL(p0); 746 } 747 /** 748 * @declaredat ASTNode:15 749 */ 750 public NumericLiteral(beaver.Symbol p0) { 751 setLITERAL(p0); 752 } 753 /** 754 * @apilevel low-level 755 * @declaredat ASTNode:21 756 */ 757 protected int numChildren() { 758 return 0; 759 } 760 /** 761 * @apilevel internal 762 * @declaredat ASTNode:27 763 */ 764 public boolean mayHaveRewrite() { 765 return true; 766 } 767 /** 768 * @apilevel internal 769 * @declaredat ASTNode:33 770 */ 771 public void flushAttrCache() { 772 super.flushAttrCache(); 773 type_reset(); 774 } 775 /** 776 * @apilevel internal 777 * @declaredat ASTNode:40 778 */ 779 public void flushCollectionCache() { 780 super.flushCollectionCache(); 781 } 782 /** 783 * @apilevel internal 784 * @declaredat ASTNode:46 785 */ 786 public void flushRewriteCache() { 787 super.flushRewriteCache(); 788 } 789 /** 790 * @apilevel internal 791 * @declaredat ASTNode:52 792 */ 793 public NumericLiteral clone() throws CloneNotSupportedException { 794 NumericLiteral node = (NumericLiteral) super.clone(); 795 return node; 796 } 797 /** 798 * @apilevel internal 799 * @declaredat ASTNode:59 800 */ 801 public NumericLiteral copy() { 802 try { 803 NumericLiteral node = (NumericLiteral) clone(); 804 node.parent = null; 805 if (children != null) { 806 node.children = (ASTNode[]) children.clone(); 807 } 808 return node; 809 } catch (CloneNotSupportedException e) { 810 throw new Error("Error: clone not supported for " + getClass().getName()); 811 } 812 } 813 /** 814 * Create a deep copy of the AST subtree at this node. 815 * The copy is dangling, i.e. has no parent. 816 * @return dangling copy of the subtree at this node 817 * @apilevel low-level 818 * @deprecated Please use treeCopy or treeCopyNoTransform instead 819 * @declaredat ASTNode:78 820 */ 821 @Deprecated 822 public NumericLiteral fullCopy() { 823 return treeCopyNoTransform(); 824 } 825 /** 826 * Create a deep copy of the AST subtree at this node. 827 * The copy is dangling, i.e. has no parent. 828 * @return dangling copy of the subtree at this node 829 * @apilevel low-level 830 * @declaredat ASTNode:88 831 */ 832 public NumericLiteral treeCopyNoTransform() { 833 NumericLiteral tree = (NumericLiteral) copy(); 834 if (children != null) { 835 for (int i = 0; i < children.length; ++i) { 836 ASTNode child = (ASTNode) children[i]; 837 if (child != null) { 838 child = child.treeCopyNoTransform(); 839 tree.setChild(child, i); 840 } 841 } 842 } 843 return tree; 844 } 845 /** 846 * Create a deep copy of the AST subtree at this node. 847 * The subtree of this node is traversed to trigger rewrites before copy. 848 * The copy is dangling, i.e. has no parent. 849 * @return dangling copy of the subtree at this node 850 * @apilevel low-level 851 * @declaredat ASTNode:108 852 */ 853 public NumericLiteral treeCopy() { 854 doFullTraversal(); 855 return treeCopyNoTransform(); 856 } 857 /** 858 * @apilevel internal 859 * @declaredat ASTNode:115 860 */ 861 protected boolean is$Equal(ASTNode node) { 862 return super.is$Equal(node) && (tokenString_LITERAL == ((NumericLiteral)node).tokenString_LITERAL); 863 } 864 /** 865 * Replaces the lexeme LITERAL. 866 * @param value The new value for the lexeme LITERAL. 867 * @apilevel high-level 868 */ 869 public void setLITERAL(String value) { 870 tokenString_LITERAL = value; 871 } 872 /** 873 * JastAdd-internal setter for lexeme LITERAL using the Beaver parser. 874 * @param symbol Symbol containing the new value for the lexeme LITERAL 875 * @apilevel internal 876 */ 877 public void setLITERAL(beaver.Symbol symbol) { 878 if (symbol.value != null && !(symbol.value instanceof String)) 879 throw new UnsupportedOperationException("setLITERAL is only valid for String lexemes"); 880 tokenString_LITERAL = (String)symbol.value; 881 LITERALstart = symbol.getStart(); 882 LITERALend = symbol.getEnd(); 883 } 884 /** 885 * Retrieves the value for the lexeme LITERAL. 886 * @return The value for the lexeme LITERAL. 887 * @apilevel high-level 888 */ 889 @ASTNodeAnnotation.Token(name="LITERAL") 890 public String getLITERAL() { 891 return tokenString_LITERAL != null ? tokenString_LITERAL : ""; 892 } 893 /** 894 * This is a refactored version of Literal.parseLong which supports 895 * binary literals. This version of parseLong is implemented as an 896 * attribute rather than a static method. Perhaps some slight 897 * performance boost could be gained from keeping it static, but with 898 * the loss of declarative- and ReRAGness. 899 * 900 * There exists only a parseLong, and not a parseInteger. Parsing 901 * of regular integer literals works the same, but with stricter 902 * bounds requirements on the resulting parsed value. 903 * @attribute syn 904 * @aspect Java7Literals 905 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:241 906 */ 907 @ASTNodeAnnotation.Attribute 908 public long parseLong() { 909 { 910 switch (getKind()) { 911 case HEXADECIMAL: 912 return parseLongHexadecimal(); 913 case OCTAL: 914 return parseLongOctal(); 915 case BINARY: 916 return parseLongBinary(); 917 case DECIMAL: 918 default: 919 return parseLongDecimal(); 920 } 921 } 922 } 923 /** 924 * Parse a hexadecimal long literal. 925 * 926 * @throws NumberFormatException if the literal is too large. 927 * @attribute syn 928 * @aspect Java7Literals 929 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:260 930 */ 931 @ASTNodeAnnotation.Attribute 932 public long parseLongHexadecimal() { 933 { 934 long val = 0; 935 if (digits.length() > 16) { 936 for (int i = 0; i < digits.length()-16; i++) 937 if (digits.charAt(i) != '0') { 938 throw new NumberFormatException(""); 939 } 940 } 941 for (int i = 0; i < digits.length(); i++) { 942 int c = digits.charAt(i); 943 if (c >= 'a' && c <= 'f') { 944 c = c - 'a' + 10; 945 } else { 946 c = c - '0'; 947 } 948 val = val * 16 + c; 949 } 950 return val; 951 } 952 } 953 /** 954 * Parse an octal long literal. 955 * 956 * @throws NumberFormatException if the literal is too large. 957 * @attribute syn 958 * @aspect Java7Literals 959 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:285 960 */ 961 @ASTNodeAnnotation.Attribute 962 public long parseLongOctal() { 963 { 964 long val = 0; 965 if (digits.length() > 21) { 966 for (int i = 0; i < digits.length() - 21; i++) 967 if (i == digits.length() - 21 - 1) { 968 if (digits.charAt(i) != '0' && digits.charAt(i) != '1') { 969 throw new NumberFormatException(""); 970 } 971 } else { 972 if (digits.charAt(i) != '0') { 973 throw new NumberFormatException(""); 974 } 975 } 976 } 977 for (int i = 0; i < digits.length(); i++) { 978 int c = digits.charAt(i) - '0'; 979 val = val * 8 + c; 980 } 981 return val; 982 } 983 } 984 /** 985 * Parse a binary long literal. 986 * 987 * @throws NumberFormatException if the literal is too large. 988 * @attribute syn 989 * @aspect Java7Literals 990 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:311 991 */ 992 @ASTNodeAnnotation.Attribute 993 public long parseLongBinary() { 994 { 995 long val = 0; 996 if (digits.length() > 64) { 997 for (int i = 0; i < digits.length()-64; i++) 998 if (digits.charAt(i) != '0') { 999 throw new NumberFormatException(""); 1000 } 1001 } 1002 for (int i = 0; i < digits.length(); ++i) { 1003 if (digits.charAt(i) == '1') { 1004 val |= 1L << (digits.length()-i-1); 1005 } 1006 } 1007 return val; 1008 } 1009 } 1010 /** 1011 * Parse a decimal long literal. 1012 * @throws NumberFormatException if the literal is too large. 1013 * @attribute syn 1014 * @aspect Java7Literals 1015 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:331 1016 */ 1017 @ASTNodeAnnotation.Attribute 1018 public long parseLongDecimal() { 1019 { 1020 long val = 0; 1021 long prev = 0; 1022 for (int i = 0; i < digits.length(); i++) { 1023 prev = val; 1024 int c = digits.charAt(i); 1025 if (c >= '0' && c <= '9') { 1026 c = c - '0'; 1027 } else { 1028 throw new NumberFormatException("unexpected digit: " + c); 1029 } 1030 val = val * 10 + c; 1031 if (val < prev) { 1032 boolean negMinValue = i == (digits.length()-1) && 1033 isNegative() && val == Long.MIN_VALUE; 1034 if (!negMinValue) { 1035 throw new NumberFormatException(""); 1036 } 1037 } 1038 } 1039 if (val == Long.MIN_VALUE) { 1040 return val; 1041 } 1042 if (val < 0) { 1043 throw new NumberFormatException(""); 1044 } 1045 return isNegative() ? -val : val; 1046 } 1047 } 1048 /** 1049 * Utility attribute for literal rewriting. 1050 * Any of the NumericLiteral subclasses have already 1051 * been rewritten and/or parsed, and should not be 1052 * rewritten again. 1053 * 1054 * @return true if this literal is a "raw", not-yet-parsed NumericLiteral 1055 * @attribute syn 1056 * @aspect Java7Literals 1057 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:373 1058 */ 1059 @ASTNodeAnnotation.Attribute 1060 public boolean needsRewrite() { 1061 boolean needsRewrite_value = true; 1062 1063 return needsRewrite_value; 1064 } 1065 /** 1066 * @attribute syn 1067 * @aspect Java7Literals 1068 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:410 1069 */ 1070 @ASTNodeAnnotation.Attribute 1071 public boolean isNegative() { 1072 boolean isNegative_value = getLITERAL().charAt(0) == '-'; 1073 1074 return isNegative_value; 1075 } 1076 /** 1077 * Get the trimmed digits of this literal, excluding 1078 * underscore, prefix and suffix. 1079 * @attribute syn 1080 * @aspect Java7Literals 1081 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:416 1082 */ 1083 @ASTNodeAnnotation.Attribute 1084 public String getDigits() { 1085 String getDigits_value = digits; 1086 1087 return getDigits_value; 1088 } 1089 /** 1090 * The literal kind tells which kind of literal it is; 1091 * either a DECIMAL, HEXADECIMAL, OCTAL or BINARY literal. 1092 * @attribute syn 1093 * @aspect Java7Literals 1094 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:434 1095 */ 1096 @ASTNodeAnnotation.Attribute 1097 public int getKind() { 1098 int getKind_value = kind; 1099 1100 return getKind_value; 1101 } 1102 /** 1103 * Get the radix of this literal. 1104 * @return 16 (hex), 10 (decimal), 8 (octal) or 2 (binary) 1105 * @attribute syn 1106 * @aspect Java7Literals 1107 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:453 1108 */ 1109 @ASTNodeAnnotation.Attribute 1110 public int getRadix() { 1111 { 1112 switch (kind) { 1113 case HEXADECIMAL: 1114 return 16; 1115 case OCTAL: 1116 return 8; 1117 case BINARY: 1118 return 2; 1119 case DECIMAL: 1120 default: 1121 return 10; 1122 } 1123 } 1124 } 1125 /** 1126 * @return true if the literal is a decimal literal 1127 * @attribute syn 1128 * @aspect Java7Literals 1129 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:470 1130 */ 1131 @ASTNodeAnnotation.Attribute 1132 public boolean isDecimal() { 1133 boolean isDecimal_value = kind == DECIMAL; 1134 1135 return isDecimal_value; 1136 } 1137 /** 1138 * @return true if the literal is a hexadecimal literal 1139 * @attribute syn 1140 * @aspect Java7Literals 1141 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:475 1142 */ 1143 @ASTNodeAnnotation.Attribute 1144 public boolean isHex() { 1145 boolean isHex_value = kind == HEXADECIMAL; 1146 1147 return isHex_value; 1148 } 1149 /** 1150 * @return true if the literal is an octal literal 1151 * @attribute syn 1152 * @aspect Java7Literals 1153 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:480 1154 */ 1155 @ASTNodeAnnotation.Attribute 1156 public boolean isOctal() { 1157 boolean isOctal_value = kind == OCTAL; 1158 1159 return isOctal_value; 1160 } 1161 /** 1162 * @return true if the literal is a binary literal 1163 * @attribute syn 1164 * @aspect Java7Literals 1165 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:485 1166 */ 1167 @ASTNodeAnnotation.Attribute 1168 public boolean isBinary() { 1169 boolean isBinary_value = kind == BINARY; 1170 1171 return isBinary_value; 1172 } 1173 /** 1174 * @apilevel internal 1175 */ 1176 protected boolean type_computed = false; 1177 /** 1178 * @apilevel internal 1179 */ 1180 protected TypeDecl type_value; 1181 /** 1182 * @apilevel internal 1183 */ 1184 private void type_reset() { 1185 type_computed = false; 1186 type_value = null; 1187 } 1188 /** 1189 * @attribute syn 1190 * @aspect TypeAnalysis 1191 * @declaredat /home/jesper/git/extendj/java4/frontend/TypeAnalysis.jrag:302 1192 */ 1193 @ASTNodeAnnotation.Attribute 1194 public TypeDecl type() { 1195 ASTNode$State state = state(); 1196 if (type_computed) { 1197 return type_value; 1198 } 1199 boolean intermediate = state.INTERMEDIATE_VALUE; 1200 state.INTERMEDIATE_VALUE = false; 1201 int num = state.boundariesCrossed; 1202 boolean isFinal = this.is$Final(); 1203 type_value = unknownType(); 1204 if (isFinal && num == state().boundariesCrossed) { 1205 type_computed = true; 1206 } else { 1207 } 1208 state.INTERMEDIATE_VALUE |= intermediate; 1209 1210 return type_value; 1211 } 1212 /** 1213 * @apilevel internal 1214 */ 1215 public ASTNode rewriteTo() { 1216 // Declared at /home/jesper/git/extendj/java7/frontend/Literals.jrag:404 1217 if (needsRewrite()) { 1218 return rewriteRule0(); 1219 } 1220 return super.rewriteTo(); 1221 } 1222 /** 1223 * @declaredat /home/jesper/git/extendj/java7/frontend/Literals.jrag:404 1224 * @apilevel internal 1225 */ 1226 private Literal rewriteRule0() { 1227 { 1228 return parse(); 1229 } } 1230 }