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     BIND           (BINARY,  "=>",    9, 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 
 104     // ECMA 7.6.1.1 Keywords, 7.6.1.2 Future Reserved Words.
 105     // All other Java keywords are commented out.
 106 
 107 //  ABSTRACT       (FUTURE,   "abstract"),
 108 //  BOOLEAN        (FUTURE,   "boolean"),
 109     BREAK          (KEYWORD,  "break"),
 110 //  BYTE           (FUTURE,   "byte"),
 111     CASE           (KEYWORD,  "case"),
 112     CATCH          (KEYWORD,  "catch"),
 113 //  CHAR           (FUTURE,   "char"),
 114     CLASS          (FUTURE,   "class"),
 115     CONST          (KEYWORD,  "const"),
 116     CONTINUE       (KEYWORD,  "continue"),
 117     DEBUGGER       (KEYWORD,  "debugger"),
 118     DEFAULT        (KEYWORD,  "default"),
 119     DELETE         (UNARY,    "delete",     14, false),
 120     DO             (KEYWORD,  "do"),
 121 //  DOUBLE         (FUTURE,   "double"),
 122 //  EACH           (KEYWORD,  "each"),  // Contextual.
 123     ELSE           (KEYWORD,  "else"),
 124     ENUM           (FUTURE,   "enum"),
 125     EXPORT         (FUTURE,   "export"),
 126     EXTENDS        (FUTURE,   "extends"),
 127     FALSE          (LITERAL,  "false"),
 128 //  FINAL          (FUTURE,   "final"),
 129     FINALLY        (KEYWORD,  "finally"),
 130 //  FLOAT          (FUTURE,   "float"),
 131     FOR            (KEYWORD,  "for"),
 132     FUNCTION       (KEYWORD,  "function"),
 133 //  GET            (KEYWORD,  "get"), // Contextual.
 134 //  GOTO           (FUTURE,   "goto"),
 135     IF             (KEYWORD,   "if"),
 136     IMPLEMENTS     (FUTURESTRICT,   "implements"),
 137     IMPORT         (FUTURE,   "import"),
 138     IN             (BINARY,   "in",         10, true),
 139     INSTANCEOF     (BINARY,   "instanceof", 10, true),
 140 //  INT            (FUTURE,   "int"),
 141     INTERFACE      (FUTURESTRICT,   "interface"),
 142     LET            (FUTURESTRICT,   "let"),
 143 //  LONG           (FUTURE,   "long"),
 144 //  NATIVE         (FUTURE,   "native"),
 145     NEW            (UNARY,    "new",        17, false),
 146     NULL           (LITERAL,  "null"),
 147     PACKAGE        (FUTURESTRICT,   "package"),
 148     PRIVATE        (FUTURESTRICT,   "private"),
 149     PROTECTED      (FUTURESTRICT,   "protected"),
 150     PUBLIC         (FUTURESTRICT,   "public"),
 151     RETURN         (KEYWORD,  "return"),
 152 //  SET            (KEYWORD,  "set"), // Contextual.
 153 //  SHORT          (FUTURE,   "short"),
 154     STATIC         (FUTURESTRICT,   "static"),
 155     SUPER          (FUTURE,   "super"),
 156     SWITCH         (KEYWORD,  "switch"),
 157 //  SYNCHRONIZED   (FUTURE,   "synchronized"),
 158     THIS           (KEYWORD,  "this"),
 159     THROW          (KEYWORD,  "throw"),
 160 //  THROWS         (FUTURE,   "throws"),
 161 //  TRANSIENT      (FUTURE,   "transient"),
 162     TRUE           (LITERAL,  "true"),
 163     TRY            (KEYWORD,  "try"),
 164     TYPEOF         (UNARY,    "typeof",     14, false),
 165     VAR            (KEYWORD,  "var"),
 166     VOID           (UNARY,    "void",       14, false),
 167 //  VOLATILE       (FUTURE,   "volatile"),
 168     WHILE          (KEYWORD,  "while"),
 169     WITH           (KEYWORD,  "with"),
 170     YIELD          (FUTURESTRICT,  "yield"),
 171 
 172     DECIMAL        (LITERAL,  null),
 173     OCTAL          (LITERAL,  null),
 174     HEXADECIMAL    (LITERAL,  null),
 175     FLOATING       (LITERAL,  null),
 176     STRING         (LITERAL,  null),
 177     ESCSTRING      (LITERAL,  null),
 178     EXECSTRING     (LITERAL,  null),
 179     IDENT          (LITERAL,  null),
 180     REGEX          (LITERAL,  null),
 181     XML            (LITERAL,  null),
 182     OBJECT         (LITERAL,  null),
 183     ARRAY          (LITERAL,  null),
 184 
 185     COMMALEFT      (IR,       null),
 186     DECPOSTFIX     (IR,       null),
 187     INCPOSTFIX     (IR,       null);
 188 
 189     /** Next token kind in token lookup table. */
 190     private TokenType next;
 191 
 192     /** Classification of token. */
 193     private final TokenKind kind;
 194 
 195     /** Printable name of token. */
 196     private final String name;
 197 
 198     /** Operator precedence. */
 199     private final int precedence;
 200 
 201     /** Left associativity */
 202     private final boolean isLeftAssociative;
 203 
 204     /** Cache values to avoid cloning. */
 205     private static final TokenType[] values;
 206 
 207     TokenType(final TokenKind kind, final String name) {
 208         next              = null;
 209         this.kind         = kind;
 210         this.name         = name;
 211         precedence        = 0;
 212         isLeftAssociative = false;
 213     }
 214 
 215     TokenType(final TokenKind kind, final String name, final int precedence, final boolean isLeftAssociative) {
 216         next                   = null;
 217         this.kind              = kind;
 218         this.name              = name;
 219         this.precedence        = precedence;
 220         this.isLeftAssociative = isLeftAssociative;
 221     }
 222 
 223     /**
 224      * Determines if the token has greater precedence than other.
 225      *
 226      * @param other  Compare token.
 227      * @param isLeft Is to the left of the other.
 228      *
 229      * @return {@code true} if greater precedence.
 230      */
 231     public boolean needsParens(final TokenType other, final boolean isLeft) {
 232         return other.precedence != 0 &&
 233                (precedence > other.precedence ||
 234                precedence == other.precedence && isLeftAssociative && !isLeft);
 235     }
 236 
 237     /**
 238      * Determines if the type is a valid operator.
 239      *
 240      * @param noIn {@code true} if IN operator should be ignored.
 241      *
 242      * @return {@code true} if valid operator.
 243      */
 244     public boolean isOperator(final boolean noIn) {
 245         return kind == BINARY && (!noIn || this != IN) && precedence != 0;
 246     }
 247 
 248 
 249     public int getLength() {
 250         assert name != null : "Token name not set";
 251         return name.length();
 252     }
 253 
 254     public String getName() {
 255         return name;
 256     }
 257 
 258     public String getNameOrType() {
 259         return name == null ? super.name().toLowerCase(Locale.ENGLISH) : name;
 260     }
 261 
 262     public TokenType getNext() {
 263         return next;
 264     }
 265 
 266     public void setNext(final TokenType next) {
 267         this.next = next;
 268     }
 269 
 270     public TokenKind getKind() {
 271         return kind;
 272     }
 273 
 274     public int getPrecedence() {
 275         return precedence;
 276     }
 277 
 278     public boolean isLeftAssociative() {
 279         return isLeftAssociative;
 280     }
 281 
 282     boolean startsWith(final char c) {
 283         return name != null && name.length() > 0 && name.charAt(0) == c;
 284     }
 285 
 286     static TokenType[] getValues() {
 287        return values;
 288     }
 289 
 290     @Override
 291     public String toString() {
 292         return getNameOrType();
 293     }
 294 
 295     static {
 296         // Avoid cloning of enumeration.
 297         values = TokenType.values();
 298     }
 299 }