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     HEXADECIMAL    (LITERAL,  null),
 174     OCTAL_LEGACY   (LITERAL,  null),
 175     OCTAL          (LITERAL,  null),
 176     BINARY_NUMBER  (LITERAL,  null),
 177     FLOATING       (LITERAL,  null),
 178     STRING         (LITERAL,  null),
 179     ESCSTRING      (LITERAL,  null),
 180     EXECSTRING     (LITERAL,  null),
 181     IDENT          (LITERAL,  null),
 182     REGEX          (LITERAL,  null),
 183     XML            (LITERAL,  null),
 184     OBJECT         (LITERAL,  null),
 185     ARRAY          (LITERAL,  null),
 186     TEMPLATE       (LITERAL,  null),
 187     TEMPLATE_HEAD  (LITERAL,  null),
 188     TEMPLATE_MIDDLE(LITERAL,  null),
 189     TEMPLATE_TAIL  (LITERAL,  null),
 190 
 191     COMMALEFT      (IR,       null),
 192     DECPOSTFIX     (IR,       null),
 193     INCPOSTFIX     (IR,       null);
 194 
 195     /** Next token kind in token lookup table. */
 196     private TokenType next;
 197 
 198     /** Classification of token. */
 199     private final TokenKind kind;
 200 
 201     /** Printable name of token. */
 202     private final String name;
 203 
 204     /** Operator precedence. */
 205     private final int precedence;
 206 
 207     /** Left associativity */
 208     private final boolean isLeftAssociative;
 209 
 210     /** Cache values to avoid cloning. */
 211     private static final TokenType[] values;
 212 
 213     TokenType(final TokenKind kind, final String name) {
 214         next              = null;
 215         this.kind         = kind;
 216         this.name         = name;
 217         precedence        = 0;
 218         isLeftAssociative = false;
 219     }
 220 
 221     TokenType(final TokenKind kind, final String name, final int precedence, final boolean isLeftAssociative) {
 222         next                   = null;
 223         this.kind              = kind;
 224         this.name              = name;
 225         this.precedence        = precedence;
 226         this.isLeftAssociative = isLeftAssociative;
 227     }
 228 
 229     /**
 230      * Determines if the token has greater precedence than other.
 231      *
 232      * @param other  Compare token.
 233      * @param isLeft Is to the left of the other.
 234      *
 235      * @return {@code true} if greater precedence.
 236      */
 237     public boolean needsParens(final TokenType other, final boolean isLeft) {
 238         return other.precedence != 0 &&
 239                (precedence > other.precedence ||
 240                precedence == other.precedence && isLeftAssociative && !isLeft);
 241     }
 242 
 243     /**
 244      * Determines if the type is a valid operator.
 245      *
 246      * @param noIn {@code true} if IN operator should be ignored.
 247      *
 248      * @return {@code true} if valid operator.
 249      */
 250     public boolean isOperator(final boolean noIn) {
 251         return kind == BINARY && (!noIn || this != IN) && precedence != 0;
 252     }
 253 
 254 
 255     public int getLength() {
 256         assert name != null : "Token name not set";
 257         return name.length();
 258     }
 259 
 260     public String getName() {
 261         return name;
 262     }
 263 
 264     public String getNameOrType() {
 265         return name == null ? super.name().toLowerCase(Locale.ENGLISH) : name;
 266     }
 267 
 268     public TokenType getNext() {
 269         return next;
 270     }
 271 
 272     public void setNext(final TokenType next) {
 273         this.next = next;
 274     }
 275 
 276     public TokenKind getKind() {
 277         return kind;
 278     }
 279 
 280     public int getPrecedence() {
 281         return precedence;
 282     }
 283 
 284     public boolean isLeftAssociative() {
 285         return isLeftAssociative;
 286     }
 287 
 288     boolean startsWith(final char c) {
 289         return name != null && name.length() > 0 && name.charAt(0) == c;
 290     }
 291 
 292     static TokenType[] getValues() {
 293        return values;
 294     }
 295 
 296     @Override
 297     public String toString() {
 298         return getNameOrType();
 299     }
 300 
 301     static {
 302         // Avoid cloning of enumeration.
 303         values = TokenType.values();
 304     }
 305 }