1 /*
   2  * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.nashorn.internal.parser;
  27 
  28 import static jdk.nashorn.internal.parser.TokenKind.BINARY;
  29 import static jdk.nashorn.internal.parser.TokenKind.BRACKET;
  30 import static jdk.nashorn.internal.parser.TokenKind.FUTURE;
  31 import static jdk.nashorn.internal.parser.TokenKind.FUTURESTRICT;
  32 import static jdk.nashorn.internal.parser.TokenKind.IR;
  33 import static jdk.nashorn.internal.parser.TokenKind.KEYWORD;
  34 import static jdk.nashorn.internal.parser.TokenKind.LITERAL;
  35 import static jdk.nashorn.internal.parser.TokenKind.SPECIAL;
  36 import static jdk.nashorn.internal.parser.TokenKind.UNARY;
  37 
  38 import java.util.Locale;
  39 
  40 /**
  41  * Description of all the JavaScript tokens.
  42  */
  43 @SuppressWarnings("javadoc")
  44 public enum TokenType {
  45     ERROR                (SPECIAL,  null),
  46     EOF                  (SPECIAL,  null),
  47     EOL                  (SPECIAL,  null),
  48     COMMENT              (SPECIAL,  null),
  49     // comments of the form //@ foo=bar or //# foo=bar
  50     // These comments are treated as special instructions
  51     // to the lexer, parser or codegenerator.
  52     DIRECTIVE_COMMENT    (SPECIAL,  null),
  53 
  54     NOT            (UNARY,   "!",    14, false),
  55     NE             (BINARY,  "!=",    9, true),
  56     NE_STRICT      (BINARY,  "!==",   9, true),
  57     MOD            (BINARY,  "%",    13, true),
  58     ASSIGN_MOD     (BINARY,  "%=",    2, false),
  59     BIT_AND        (BINARY,  "&",     8, true),
  60     AND            (BINARY,  "&&",    5, true),
  61     ASSIGN_BIT_AND (BINARY,  "&=",    2, false),
  62     LPAREN         (BRACKET, "(",    16, true),
  63     RPAREN         (BRACKET, ")",     0, true),
  64     MUL            (BINARY,  "*",    13, true),
  65     ASSIGN_MUL     (BINARY,  "*=",    2, false),
  66     ADD            (BINARY,  "+",    12, true),
  67     INCPREFIX      (UNARY,   "++",   15, true),
  68     ASSIGN_ADD     (BINARY,  "+=",    2, false),
  69     COMMARIGHT     (BINARY,  ",",     1, true),
  70     SUB            (BINARY,  "-",    12, true),
  71     DECPREFIX      (UNARY,   "--",   15, true),
  72     ASSIGN_SUB     (BINARY,  "-=",    2, false),
  73     PERIOD         (BRACKET, ".",    17, true),
  74     DIV            (BINARY,  "/",    13, true),
  75     ASSIGN_DIV     (BINARY,  "/=",    2, false),
  76     COLON          (BINARY,  ":"),
  77     SEMICOLON      (BINARY,  ";"),
  78     LT             (BINARY,  "<",    10, true),
  79     SHL            (BINARY,  "<<",   11, true),
  80     ASSIGN_SHL     (BINARY,  "<<=",   2, false),
  81     LE             (BINARY,  "<=",   10, true),
  82     ASSIGN         (BINARY,  "=",     2, false),
  83     EQ             (BINARY,  "==",    9, true),
  84     EQ_STRICT      (BINARY,  "===",   9, true),
  85     ARROW          (BINARY,  "=>",    2, true),
  86     GT             (BINARY,  ">",    10, true),
  87     GE             (BINARY,  ">=",   10, true),
  88     SAR            (BINARY,  ">>",   11, true),
  89     ASSIGN_SAR     (BINARY,  ">>=",   2, false),
  90     SHR            (BINARY,  ">>>",  11, true),
  91     ASSIGN_SHR     (BINARY,  ">>>=",  2, false),
  92     TERNARY        (BINARY,  "?",     3, false),
  93     LBRACKET       (BRACKET, "[",    17, true),
  94     RBRACKET       (BRACKET, "]",     0, true),
  95     BIT_XOR        (BINARY,  "^",     7, true),
  96     ASSIGN_BIT_XOR (BINARY,  "^=",    2, false),
  97     LBRACE         (BRACKET,  "{"),
  98     BIT_OR         (BINARY,  "|",     6, true),
  99     ASSIGN_BIT_OR  (BINARY,  "|=",    2, false),
 100     OR             (BINARY,  "||",    4, true),
 101     RBRACE         (BRACKET, "}"),
 102     BIT_NOT        (UNARY,   "~",     14, false),
 103     ELLIPSIS       (UNARY,   "..."),
 104 
 105     // ECMA 7.6.1.1 Keywords, 7.6.1.2 Future Reserved Words.
 106     // All other Java keywords are commented out.
 107 
 108 //  ABSTRACT       (FUTURE,   "abstract"),
 109 //  BOOLEAN        (FUTURE,   "boolean"),
 110     BREAK          (KEYWORD,  "break"),
 111 //  BYTE           (FUTURE,   "byte"),
 112     CASE           (KEYWORD,  "case"),
 113     CATCH          (KEYWORD,  "catch"),
 114 //  CHAR           (FUTURE,   "char"),
 115     CLASS          (FUTURE,   "class"),
 116     CONST          (KEYWORD,  "const"),
 117     CONTINUE       (KEYWORD,  "continue"),
 118     DEBUGGER       (KEYWORD,  "debugger"),
 119     DEFAULT        (KEYWORD,  "default"),
 120     DELETE         (UNARY,    "delete",     14, false),
 121     DO             (KEYWORD,  "do"),
 122 //  DOUBLE         (FUTURE,   "double"),
 123 //  EACH           (KEYWORD,  "each"),  // Contextual.
 124     ELSE           (KEYWORD,  "else"),
 125     ENUM           (FUTURE,   "enum"),
 126     EXPORT         (FUTURE,   "export"),
 127     EXTENDS        (FUTURE,   "extends"),
 128     FALSE          (LITERAL,  "false"),
 129 //  FINAL          (FUTURE,   "final"),
 130     FINALLY        (KEYWORD,  "finally"),
 131 //  FLOAT          (FUTURE,   "float"),
 132     FOR            (KEYWORD,  "for"),
 133     FUNCTION       (KEYWORD,  "function"),
 134 //  GET            (KEYWORD,  "get"), // Contextual.
 135 //  GOTO           (FUTURE,   "goto"),
 136     IF             (KEYWORD,   "if"),
 137     IMPLEMENTS     (FUTURESTRICT,   "implements"),
 138     IMPORT         (FUTURE,   "import"),
 139     IN             (BINARY,   "in",         10, true),
 140     INSTANCEOF     (BINARY,   "instanceof", 10, true),
 141 //  INT            (FUTURE,   "int"),
 142     INTERFACE      (FUTURESTRICT,   "interface"),
 143     LET            (FUTURESTRICT,   "let"),
 144 //  LONG           (FUTURE,   "long"),
 145 //  NATIVE         (FUTURE,   "native"),
 146     NEW            (UNARY,    "new",        17, false),
 147     NULL           (LITERAL,  "null"),
 148     PACKAGE        (FUTURESTRICT,   "package"),
 149     PRIVATE        (FUTURESTRICT,   "private"),
 150     PROTECTED      (FUTURESTRICT,   "protected"),
 151     PUBLIC         (FUTURESTRICT,   "public"),
 152     RETURN         (KEYWORD,  "return"),
 153 //  SET            (KEYWORD,  "set"), // Contextual.
 154 //  SHORT          (FUTURE,   "short"),
 155     STATIC         (FUTURESTRICT,   "static"),
 156     SUPER          (FUTURE,   "super"),
 157     SWITCH         (KEYWORD,  "switch"),
 158 //  SYNCHRONIZED   (FUTURE,   "synchronized"),
 159     THIS           (KEYWORD,  "this"),
 160     THROW          (KEYWORD,  "throw"),
 161 //  THROWS         (FUTURE,   "throws"),
 162 //  TRANSIENT      (FUTURE,   "transient"),
 163     TRUE           (LITERAL,  "true"),
 164     TRY            (KEYWORD,  "try"),
 165     TYPEOF         (UNARY,    "typeof",     14, false),
 166     VAR            (KEYWORD,  "var"),
 167     VOID           (UNARY,    "void",       14, false),
 168 //  VOLATILE       (FUTURE,   "volatile"),
 169     WHILE          (KEYWORD,  "while"),
 170     WITH           (KEYWORD,  "with"),
 171     YIELD          (FUTURESTRICT,  "yield"),
 172 
 173     DECIMAL        (LITERAL,  null),
 174     HEXADECIMAL    (LITERAL,  null),
 175     OCTAL_LEGACY   (LITERAL,  null),
 176     OCTAL          (LITERAL,  null),
 177     BINARY_NUMBER  (LITERAL,  null),
 178     FLOATING       (LITERAL,  null),
 179     STRING         (LITERAL,  null),
 180     ESCSTRING      (LITERAL,  null),
 181     EXECSTRING     (LITERAL,  null),
 182     IDENT          (LITERAL,  null),
 183     REGEX          (LITERAL,  null),
 184     XML            (LITERAL,  null),
 185     OBJECT         (LITERAL,  null),
 186     ARRAY          (LITERAL,  null),
 187     TEMPLATE       (LITERAL,  null),
 188     TEMPLATE_HEAD  (LITERAL,  null),
 189     TEMPLATE_MIDDLE(LITERAL,  null),
 190     TEMPLATE_TAIL  (LITERAL,  null),
 191 
 192     COMMALEFT      (IR,       null),
 193     DECPOSTFIX     (IR,       null),
 194     INCPOSTFIX     (IR,       null),
 195     SPREAD_ARGUMENT(IR,       null),
 196     SPREAD_ARRAY   (IR,       null),
 197     YIELD_STAR     (IR,       null);
 198 
 199     /** Next token kind in token lookup table. */
 200     private TokenType next;
 201 
 202     /** Classification of token. */
 203     private final TokenKind kind;
 204 
 205     /** Printable name of token. */
 206     private final String name;
 207 
 208     /** Operator precedence. */
 209     private final int precedence;
 210 
 211     /** Left associativity */
 212     private final boolean isLeftAssociative;
 213 
 214     /** Cache values to avoid cloning. */
 215     private static final TokenType[] values;
 216 
 217     TokenType(final TokenKind kind, final String name) {
 218         next              = null;
 219         this.kind         = kind;
 220         this.name         = name;
 221         precedence        = 0;
 222         isLeftAssociative = false;
 223     }
 224 
 225     TokenType(final TokenKind kind, final String name, final int precedence, final boolean isLeftAssociative) {
 226         next                   = null;
 227         this.kind              = kind;
 228         this.name              = name;
 229         this.precedence        = precedence;
 230         this.isLeftAssociative = isLeftAssociative;
 231     }
 232 
 233     /**
 234      * Determines if the token has greater precedence than other.
 235      *
 236      * @param other  Compare token.
 237      * @param isLeft Is to the left of the other.
 238      *
 239      * @return {@code true} if greater precedence.
 240      */
 241     public boolean needsParens(final TokenType other, final boolean isLeft) {
 242         return other.precedence != 0 &&
 243                (precedence > other.precedence ||
 244                precedence == other.precedence && isLeftAssociative && !isLeft);
 245     }
 246 
 247     /**
 248      * Determines if the type is a valid operator.
 249      *
 250      * @param noIn {@code true} if IN operator should be ignored.
 251      *
 252      * @return {@code true} if valid operator.
 253      */
 254     public boolean isOperator(final boolean noIn) {
 255         return kind == BINARY && (!noIn || this != IN) && precedence != 0;
 256     }
 257 
 258     public int getLength() {
 259         assert name != null : "Token name not set";
 260         return name.length();
 261     }
 262 
 263     public String getName() {
 264         return name;
 265     }
 266 
 267     public String getNameOrType() {
 268         return name == null ? super.name().toLowerCase(Locale.ENGLISH) : name;
 269     }
 270 
 271     public TokenType getNext() {
 272         return next;
 273     }
 274 
 275     public void setNext(final TokenType next) {
 276         this.next = next;
 277     }
 278 
 279     public TokenKind getKind() {
 280         return kind;
 281     }
 282 
 283     public int getPrecedence() {
 284         return precedence;
 285     }
 286 
 287     public boolean isLeftAssociative() {
 288         return isLeftAssociative;
 289     }
 290 
 291     boolean startsWith(final char c) {
 292         return name != null && name.length() > 0 && name.charAt(0) == c;
 293     }
 294 
 295     static TokenType[] getValues() {
 296        return values;
 297     }
 298 
 299     @Override
 300     public String toString() {
 301         return getNameOrType();
 302     }
 303 
 304     static {
 305         // Avoid cloning of enumeration.
 306         values = TokenType.values();
 307     }
 308 }