net.sourceforge.pmd.lang.java.ast.BinaryOp Maven / Gradle / Ivy
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.ast;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.lang.java.ast.internal.JavaAstUtils;
import net.sourceforge.pmd.util.CollectionUtil;
/**
* Represents the operator of an {@linkplain ASTInfixExpression infix expression}.
* Constants are roughly ordered by precedence, except some of them have the same
* precedence.
*
* All of those operators are left-associative.
*
* @see UnaryOp
* @see AssignmentOp
*/
public enum BinaryOp implements InternalInterfaces.OperatorLike {
// shortcut boolean ops
/** Conditional (shortcut) OR {@code "||"} operator. */
CONDITIONAL_OR("||"),
/** Conditional (shortcut) AND {@code "&&"} operator. */
CONDITIONAL_AND("&&"),
// non-shortcut (also bitwise)
/** OR {@code "|"} operator. Either logical or bitwise depending on the type of the operands. */
OR("|"),
/** XOR {@code "^"} operator. Either logical or bitwise depending on the type of the operands. */
XOR("^"),
/** AND {@code "&"} operator. Either logical or bitwise depending on the type of the operands. */
AND("&"),
// equality
/** Equals {@code "=="} operator. */
EQ("=="),
/** Not-equals {@code "!="} operator. */
NE("!="),
// relational
/** Lower-or-equal {@code "<="} operator. */
LE("<="),
/** Greater-or-equal {@code ">="} operator. */
GE(">="),
/** Greater-than {@code ">"} operator. */
GT(">"),
/** Lower-than {@code "<"} operator. */
LT("<"),
/** Type test {@code "instanceof"} operator. */
INSTANCEOF("instanceof"),
// shift
/** Left shift {@code "<<"} operator. */
LEFT_SHIFT("<<"),
/** Right shift {@code ">>"} operator. */
RIGHT_SHIFT(">>"),
/** Unsigned right shift {@code ">>>"} operator. */
UNSIGNED_RIGHT_SHIFT(">>>"),
// additive
/** Addition {@code "+"} operator, or string concatenation. */
ADD("+"),
/** Subtraction {@code "-"} operator. */
SUB("-"),
// multiplicative
/** Multiplication {@code "*"} operator. */
MUL("*"),
/** Division {@code "/"} operator. */
DIV("/"),
/** Modulo {@code "%"} operator. */
MOD("%");
/** Set of {@code &&} and {@code ||}. Use with {@link JavaAstUtils#isInfixExprWithOperator(JavaNode, Set)}. */
public static final Set CONDITIONAL_OPS =
CollectionUtil.immutableEnumSet(CONDITIONAL_AND, CONDITIONAL_OR);
/** Set of {@code <}, {@code <=}, {@code >=} and {@code >}. Use with {@link JavaAstUtils#isInfixExprWithOperator(JavaNode, Set)}. */
public static final Set COMPARISON_OPS = CollectionUtil.immutableEnumSet(LE, GE, GT, LT);
/** Set of {@code ==} and {@code !=}. Use with {@link JavaAstUtils#isInfixExprWithOperator(JavaNode, Set)}. */
public static final Set EQUALITY_OPS = CollectionUtil.immutableEnumSet(EQ, NE);
/** Set of {@code <<}, {@code >>} and {@code >>>}. Use with {@link JavaAstUtils#isInfixExprWithOperator(JavaNode, Set)}. */
public static final Set SHIFT_OPS = CollectionUtil.immutableEnumSet(LEFT_SHIFT, RIGHT_SHIFT, UNSIGNED_RIGHT_SHIFT);
private final String code;
BinaryOp(String code) {
this.code = code;
}
@Override
public String getToken() {
return code;
}
@Override
public String toString() {
return this.code;
}
/**
* Compare the precedence of this operator with that of the other,
* as if with a {@link Comparator}. Returns a positive integer if
* this operator has a higher precedence as the argument, zero if
* they have the same precedence, etc.
*
* @throws NullPointerException If the argument is null
*/
public int comparePrecedence(@NonNull BinaryOp other) {
// arguments are flipped because precedence class decreases
return Integer.compare(other.precedenceClass(), this.precedenceClass());
}
/**
* Returns true if this operator has the same relative precedence
* as the argument. For example, {@link #ADD} and {@link #SUB} have
* the same precedence.
*
* @throws NullPointerException If the argument is null
*/
public boolean hasSamePrecedenceAs(@NonNull BinaryOp other) {
return comparePrecedence(other) == 0;
}
/**
* Returns the ops with strictly greater precedence than the given op.
* This may return an empty set.
*/
public static Set opsWithGreaterPrecedence(BinaryOp op) {
Set range = EnumSet.range(op, MOD);
range.remove(op);
return range;
}
private int precedenceClass() {
switch (this) {
case CONDITIONAL_OR:
return 9;
case CONDITIONAL_AND:
return 8;
case OR:
return 7;
case XOR:
return 6;
case AND:
return 5;
case EQ:
case NE:
return 4;
case LE:
case GE:
case GT:
case LT:
case INSTANCEOF:
return 3;
case LEFT_SHIFT:
case RIGHT_SHIFT:
case UNSIGNED_RIGHT_SHIFT:
return 2;
case ADD:
case SUB:
return 1;
case MUL:
case DIV:
case MOD:
return 0;
default:
return -1;
}
}
/**
* Complement, for boolean operators. Eg for {@code ==}, return {@code !=},
* for {@code <=}, returns {@code >}. Returns null if this is another kind
* of operator.
*/
public @Nullable BinaryOp getComplement() {
switch (this) {
case CONDITIONAL_OR: return CONDITIONAL_AND;
case CONDITIONAL_AND: return CONDITIONAL_OR;
case OR: return AND;
case AND: return OR;
case EQ: return NE;
case NE: return EQ;
case LE: return GT;
case GE: return LT;
case GT: return LE;
case LT: return GE;
default: return null;
}
}
}