/**
* Copyright 2011-2017 Asakusa Framework Team.
*
* 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.asakusafw.utils.java.model.syntax;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Represents infix operators.
*/
public enum InfixOperator {
/**
* Assignment operator.
*/
ASSIGN(
"=", //$NON-NLS-1$
EnumSet.of(Context.ASSIGNMENT),
Category.ASSIGNMENT),
/**
* Add operator.
*/
PLUS(
"+", //$NON-NLS-1$
EnumSet.of(Context.INFIX, Context.ASSIGNMENT),
Category.ADDITIVE),
/**
* Subtract operator.
*/
MINUS(
"-", //$NON-NLS-1$
EnumSet.of(Context.INFIX, Context.ASSIGNMENT),
Category.ADDITIVE),
/**
* Multiply operator.
*/
TIMES(
"*", //$NON-NLS-1$
EnumSet.of(Context.INFIX, Context.ASSIGNMENT),
Category.MULTIPLICATIVE),
/**
* Division operator.
*/
DIVIDE(
"/", //$NON-NLS-1$
EnumSet.of(Context.INFIX, Context.ASSIGNMENT),
Category.MULTIPLICATIVE),
/**
* Remainder operator.
*/
REMAINDER(
"%", //$NON-NLS-1$
EnumSet.of(Context.INFIX, Context.ASSIGNMENT),
Category.MULTIPLICATIVE),
/**
* Left shift operator.
*/
LEFT_SHIFT(
"<<", //$NON-NLS-1$
EnumSet.of(Context.INFIX, Context.ASSIGNMENT),
Category.SHIFT),
/**
* Signed right shift operator.
*/
RIGHT_SHIFT_SIGNED(
">>", //$NON-NLS-1$
EnumSet.of(Context.INFIX, Context.ASSIGNMENT),
Category.SHIFT),
/**
* Unsigned right shift operator.
*/
RIGHT_SHIFT_UNSIGNED(
">>>", //$NON-NLS-1$
EnumSet.of(Context.INFIX, Context.ASSIGNMENT),
Category.SHIFT),
/**
* Bitwise/logical or operator.
*/
OR(
"|", //$NON-NLS-1$
EnumSet.of(Context.INFIX, Context.ASSIGNMENT),
Category.BITWISE),
/**
* Bitwise/logical and operator.
*/
AND(
"&", //$NON-NLS-1$
EnumSet.of(Context.INFIX, Context.ASSIGNMENT),
Category.BITWISE),
/**
* Bitwise/logical exclusive or operator.
*/
XOR(
"^", //$NON-NLS-1$
EnumSet.of(Context.INFIX, Context.ASSIGNMENT),
Category.BITWISE),
/**
* Equal operator.
*/
EQUALS(
"==", //$NON-NLS-1$
EnumSet.of(Context.INFIX),
Category.EQUALITY),
/**
* Not equal operator.
*/
NOT_EQUALS(
"!=", //$NON-NLS-1$
EnumSet.of(Context.INFIX),
Category.EQUALITY),
/**
* Greater than operator.
*/
GREATER(
">", //$NON-NLS-1$
EnumSet.of(Context.INFIX),
Category.RELATIONAL),
/**
* Less than operator.
*/
LESS(
"<", //$NON-NLS-1$
EnumSet.of(Context.INFIX),
Category.RELATIONAL),
/**
* Greater than or equal to operator.
*/
GREATER_EQUALS(
">=", //$NON-NLS-1$
EnumSet.of(Context.INFIX),
Category.RELATIONAL),
/**
* Less than or equal to operator.
*/
LESS_EQUALS(
"<=", //$NON-NLS-1$
EnumSet.of(Context.INFIX),
Category.RELATIONAL),
/**
* Conditional or operator.
*/
CONDITIONAL_OR(
"||", //$NON-NLS-1$
EnumSet.of(Context.INFIX),
Category.CONDITIONAL),
/**
* Conditional and operator.
*/
CONDITIONAL_AND(
"&&", //$NON-NLS-1$
EnumSet.of(Context.INFIX),
Category.CONDITIONAL),
;
private final String symbol;
private final Set<Context> permittedContexts;
private final Category category;
/**
* Creates a new instance.
* @param symbol the operator symbol
* @param permitted set of the permitted contexts
* @param category the operator category
*/
InfixOperator(String symbol, EnumSet<Context> permitted, Category category) {
assert symbol != null;
assert permitted != null;
assert category != null;
this.symbol = symbol;
this.permittedContexts = Collections.unmodifiableSet(permitted);
this.category = category;
}
/**
* Returns the infix operator symbol.
* @return the infix operator symbol
*/
public String getSymbol() {
return this.symbol;
}
/**
* Returns the assignment operator symbol.
* @return the assignment operator symbol
*/
public String getAssignmentSymbol() {
if (this == ASSIGN) {
return ASSIGN.getSymbol();
} else {
return getSymbol() + ASSIGN.getSymbol();
}
}
/**
* Returns an operator from its symbol.
* @param symbol the target operator symbol
* @return the corresponded operator, or {@code null} if there is no such the operator
* @throws IllegalArgumentException if the parameter is {@code null}
*/
public static InfixOperator fromSymbol(String symbol) {
if (symbol == null) {
throw new IllegalArgumentException("symbol must not be null"); //$NON-NLS-1$
}
return SymbolToInfixOperator.get(symbol);
}
/**
* Returns whether this operator can be used in the specified context or not.
* @param context the target context
* @return {@code true} if this operator can be used in the specified context, otherwise {@code false}
* @throws IllegalArgumentException if the parameter is {@code null}
*/
public boolean isPermitted(Context context) {
if (context == null) {
throw new IllegalArgumentException("context must not be null"); //$NON-NLS-1$
}
return permittedContexts.contains(context);
}
/**
* Returns the operator category.
* @return the operator category
*/
public InfixOperator.Category getCategory() {
return this.category;
}
/**
* Represents a kind of permissive context.
*/
enum Context {
/**
* The operator can be used as infix operator.
*/
INFIX,
/**
*
* The operator can be used as assignment operator.
*/
ASSIGNMENT,
}
/**
* Represents an operator kind.
*/
enum Category {
/**
* multiplicative operators ({@literal 15.17}).
*/
MULTIPLICATIVE,
/**
* additive operators ({@literal 15.18}).
*/
ADDITIVE,
/**
* shift operators ({@literal 15.19}).
*/
SHIFT,
/**
* relational operators ({@literal 15.20}).
*/
RELATIONAL,
/**
* equality operators ({@literal 15.21}).
*/
EQUALITY,
/**
* bitwise/logical operators ({@literal 15.22}).
*/
BITWISE,
/**
* conditional operator ({@literal 15.23}, {@literal 15.24}).
*/
CONDITIONAL,
/**
* assignment operators ({@literal 15.23}, {@literal 15.26}).
*/
ASSIGNMENT,
}
private static class SymbolToInfixOperator {
private static final Map<String, InfixOperator> REVERSE_DICTIONARY;
static {
Map<String, InfixOperator> map = new HashMap<>();
for (InfixOperator elem : InfixOperator.values()) {
map.put(elem.getSymbol(), elem);
}
REVERSE_DICTIONARY = Collections.unmodifiableMap(map);
}
static InfixOperator get(String key) {
return REVERSE_DICTIONARY.get(key);
}
}
}