// Copyright (C) 2005 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.caja.parser.js; import com.google.caja.SomethingWidgyHappenedError; import java.util.EnumMap; import java.util.HashMap; import java.util.Map; /** * Information about a javascript operator including its precedence and * associativity. * * @author mikesamuel@gmail.com */ public enum Operator { // from precedence tables at // http://www.codehouse.com/javascript/precedence/ SQUARE_BRACKET(OperatorType.BRACKET, OperatorCategory.SPECIAL, 1, Associativity.LEFT, "[]"), MEMBER_ACCESS(OperatorType.INFIX, OperatorCategory.SPECIAL, 1, Associativity.LEFT, "."), CONSTRUCTOR(OperatorType.PREFIX, OperatorCategory.SPECIAL, 1, Associativity.RIGHT, "new"), FUNCTION_CALL(OperatorType.BRACKET, OperatorCategory.SPECIAL, 2, Associativity.LEFT, "()"), POST_INCREMENT(OperatorType.POSTFIX, OperatorCategory.ASSIGNMENT, 3, null, "++"), POST_DECREMENT(OperatorType.POSTFIX, OperatorCategory.ASSIGNMENT, 3, null, "--"), DELETE(OperatorType.PREFIX, OperatorCategory.SPECIAL, 4, Associativity.RIGHT, "delete"), VOID(OperatorType.PREFIX, OperatorCategory.SPECIAL, 4, Associativity.RIGHT, "void"), TYPEOF(OperatorType.PREFIX, OperatorCategory.SPECIAL, 4, Associativity.RIGHT, "typeof"), IN(OperatorType.INFIX, OperatorCategory.SPECIAL, 8, Associativity.LEFT, "in"), PRE_INCREMENT(OperatorType.PREFIX, OperatorCategory.ASSIGNMENT, 4, Associativity.RIGHT, "++"), PRE_DECREMENT(OperatorType.PREFIX, OperatorCategory.ASSIGNMENT, 4, Associativity.RIGHT, "--"), TO_NUMBER(OperatorType.PREFIX, OperatorCategory.SIMPLE, 4, Associativity.RIGHT, "+"), NEGATION(OperatorType.PREFIX, OperatorCategory.SIMPLE, 4, Associativity.RIGHT, "-"), INVERSE(OperatorType.PREFIX, OperatorCategory.SIMPLE, 4, Associativity.RIGHT, "~"), NOT(OperatorType.PREFIX, OperatorCategory.SIMPLE, 4, Associativity.RIGHT, "!"), MULTIPLICATION(OperatorType.INFIX, OperatorCategory.SIMPLE, 5, Associativity.LEFT, "*"), DIVISION(OperatorType.INFIX, OperatorCategory.SIMPLE, 5, Associativity.LEFT, "/"), MODULUS(OperatorType.INFIX, OperatorCategory.SIMPLE, 5, Associativity.LEFT, "%"), ADDITION(OperatorType.INFIX, OperatorCategory.SIMPLE, 6, Associativity.LEFT, "+"), SUBTRACTION(OperatorType.INFIX, OperatorCategory.SIMPLE, 6, Associativity.LEFT, "-"), LSHIFT(OperatorType.INFIX, OperatorCategory.SIMPLE, 7, Associativity.LEFT, "<<"), RSHIFT(OperatorType.INFIX, OperatorCategory.SIMPLE, 7, Associativity.LEFT, ">>"), RUSHIFT(OperatorType.INFIX, OperatorCategory.SIMPLE, 7, Associativity.LEFT, ">>>"), LESS_THAN(OperatorType.INFIX, OperatorCategory.SIMPLE, 8, Associativity.LEFT, "<"), GREATER_THAN(OperatorType.INFIX, OperatorCategory.SIMPLE, 8, Associativity.LEFT, ">"), LESS_EQUALS(OperatorType.INFIX, OperatorCategory.SIMPLE, 8, Associativity.LEFT, "<="), GREATER_EQUALS(OperatorType.INFIX, OperatorCategory.SIMPLE, 8, Associativity.LEFT, ">="), INSTANCE_OF(OperatorType.INFIX, OperatorCategory.SIMPLE, 8, Associativity.LEFT, "instanceof"), EQUAL(OperatorType.INFIX, OperatorCategory.SIMPLE, 9, Associativity.LEFT, "=="), NOT_EQUAL(OperatorType.INFIX, OperatorCategory.SIMPLE, 9, Associativity.LEFT, "!="), STRICTLY_EQUAL(OperatorType.INFIX, OperatorCategory.SIMPLE, 9, Associativity.LEFT, "==="), STRICTLY_NOT_EQUAL(OperatorType.INFIX, OperatorCategory.SIMPLE, 9, Associativity.LEFT, "!=="), BITWISE_AND(OperatorType.INFIX, OperatorCategory.SIMPLE, 10, Associativity.LEFT, "&"), BITWISE_XOR(OperatorType.INFIX, OperatorCategory.SIMPLE, 11, Associativity.LEFT, "^"), BITWISE_OR(OperatorType.INFIX, OperatorCategory.SIMPLE, 12, Associativity.LEFT, "|"), LOGICAL_AND(OperatorType.INFIX, OperatorCategory.CONTROL, 13, Associativity.LEFT, "&&"), LOGICAL_OR(OperatorType.INFIX, OperatorCategory.CONTROL, 14, Associativity.LEFT, "||"), TERNARY(OperatorType.TERNARY, OperatorCategory.CONTROL, 15, Associativity.RIGHT, "?:"), ASSIGN(OperatorType.INFIX, OperatorCategory.ASSIGNMENT, 16, Associativity.RIGHT, "="), ASSIGN_MUL(OperatorType.INFIX, OperatorCategory.ASSIGNMENT, 16, Associativity.RIGHT, "*=", Operator.MULTIPLICATION), ASSIGN_DIV(OperatorType.INFIX, OperatorCategory.ASSIGNMENT, 16, Associativity.RIGHT, "/=", Operator.DIVISION), ASSIGN_MOD(OperatorType.INFIX, OperatorCategory.ASSIGNMENT, 16, Associativity.RIGHT, "%=", Operator.MODULUS), ASSIGN_SUM(OperatorType.INFIX, OperatorCategory.ASSIGNMENT, 16, Associativity.RIGHT, "+=", Operator.ADDITION), ASSIGN_SUB(OperatorType.INFIX, OperatorCategory.ASSIGNMENT, 16, Associativity.RIGHT, "-=", Operator.SUBTRACTION), ASSIGN_LSH(OperatorType.INFIX, OperatorCategory.ASSIGNMENT, 16, Associativity.RIGHT, "<<=", Operator.LSHIFT), ASSIGN_RSH(OperatorType.INFIX, OperatorCategory.ASSIGNMENT, 16, Associativity.RIGHT, ">>=", Operator.RSHIFT), ASSIGN_USH(OperatorType.INFIX, OperatorCategory.ASSIGNMENT, 16, Associativity.RIGHT, ">>>=", Operator.RUSHIFT), ASSIGN_AND(OperatorType.INFIX, OperatorCategory.ASSIGNMENT, 16, Associativity.RIGHT, "&=", Operator.BITWISE_AND), ASSIGN_XOR(OperatorType.INFIX, OperatorCategory.ASSIGNMENT, 16, Associativity.RIGHT, "^=", Operator.BITWISE_XOR), ASSIGN_OR(OperatorType.INFIX, OperatorCategory.ASSIGNMENT, 16, Associativity.RIGHT, "|=", Operator.BITWISE_OR), COMMA(OperatorType.INFIX, OperatorCategory.SPECIAL, 17, Associativity.LEFT, ","), ; private OperatorType type; private OperatorCategory category; private int precedence; private Associativity associativity; private String symbol; /** * null or the non assignment operator that performs the non assignment * portion of this operators function. */ private Operator assignmentDelegate; Operator(OperatorType type, OperatorCategory category, int precedence, Associativity assoc, String symbol) { this(type, category, precedence, assoc, symbol, null); } Operator(OperatorType type, OperatorCategory category, int precedence, Associativity assoc, String symbol, Operator assignmentDelegate) { if (assignmentDelegate != null && assignmentDelegate.getType() != OperatorType.INFIX) { throw new IllegalArgumentException( assignmentDelegate + " cannot be used as an assignment delegate"); } this.type = type; this.category = category; this.precedence = precedence; this.associativity = assoc; this.symbol = symbol; this.assignmentDelegate = assignmentDelegate; } public OperatorType getType() { return type; } public OperatorCategory getCategory() { return category; } public int getPrecedence() { return precedence; } public Associativity getAssociativity() { return associativity; } public String getSymbol() { return symbol; } public String getClosingSymbol() { switch (type) { default: return null; case BRACKET: case TERNARY: return symbol.substring(symbol.length() / 2); // "()" -> ")" } } public String getOpeningSymbol() { switch (type) { default: return symbol; case BRACKET: case TERNARY: return symbol.substring(0, symbol.length() / 2); // "()" -> "(" } } public Operator getAssignmentDelegate() { return assignmentDelegate; } // Group operations by OperationType so that we can query for infix // operators matching a given symbol. private static Map<OperatorType, Map<String, Operator> > symbolsByType; public static Operator lookupOperation(String symbol, OperatorType type) { Initializer.initSymbols(); return symbolsByType.get(type).get(symbol); } private static class Initializer { static void initSymbols() { // placeholder method to force loading of this class } static { symbolsByType = new EnumMap<OperatorType, Map<String, Operator>>( OperatorType.class); for (OperatorType opType : OperatorType.values()) { Map<String, Operator> symbolMap = new HashMap<String, Operator>(); symbolsByType.put(opType, symbolMap); } for (Operator op : Operator.values()) { if (null != symbolsByType.get(op.getType()) .put(op.getOpeningSymbol(), op)) { throw new SomethingWidgyHappenedError( "Duplicate symbol " + op.getSymbol() + " for type " + op.getType()); } } } } static { for (Operator op : values()) { Operator assignmentDelegate = op.assignmentDelegate; if (assignmentDelegate != null && (assignmentDelegate == ASSIGN || assignmentDelegate.assignmentDelegate != null)) { throw new SomethingWidgyHappenedError( op + " cannot delegate assignment to an assignment operator: " + assignmentDelegate); } } } }