Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.strobel.decompiler.languages.java.ast.JavaResolver Maven / Gradle / Ivy
/*
* JavaResolver.java
*
* Copyright (c) 2013 Mike Strobel
*
* This source code is based on Mono.Cecil from Jb Evain, Copyright (c) Jb Evain;
* and ILSpy/ICSharpCode from SharpDevelop, Copyright (c) AlphaSierraPapa.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0.
* A copy of the license can be found in the License.html file at the root of this distribution.
* By using this source code in any fashion, you are agreeing to be bound by the terms of the
* Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*/
package com.strobel.decompiler.languages.java.ast;
import com.strobel.assembler.metadata.*;
import com.strobel.core.Comparer;
import com.strobel.core.StringUtilities;
import com.strobel.core.VerifyArgument;
import com.strobel.decompiler.DecompilerContext;
import com.strobel.decompiler.ast.Variable;
import com.strobel.decompiler.semantics.ResolveResult;
import com.strobel.functions.Function;
public class JavaResolver implements Function {
private final DecompilerContext _context;
public JavaResolver(final DecompilerContext context) {
_context = VerifyArgument.notNull(context, "context");
}
@Override
public ResolveResult apply(final AstNode input) {
return input.acceptVisitor(new ResolveVisitor(_context), null);
}
private final static class ResolveVisitor extends ContextTrackingVisitor {
protected ResolveVisitor(final DecompilerContext context) {
super(context);
}
@Override
public ResolveResult visitVariableDeclaration(final VariableDeclarationStatement node, final Void data) {
return resolveType(node.getType());
}
@Override
public ResolveResult visitVariableInitializer(final VariableInitializer node, final Void data) {
return node.getInitializer().acceptVisitor(this, data);
}
@Override
public ResolveResult visitObjectCreationExpression(final ObjectCreationExpression node, final Void _) {
/*
final ResolveResult result = resolveTypeFromMember(node.getUserData(Keys.MEMBER_REFERENCE));
if (result != null) {
return result;
}
*/
return node.getType().acceptVisitor(this, _);
}
@Override
public ResolveResult visitAnonymousObjectCreationExpression(final AnonymousObjectCreationExpression node, final Void _) {
final ResolveResult result = resolveTypeFromMember(node.getUserData(Keys.MEMBER_REFERENCE));
if (result != null) {
return result;
}
return node.getType().acceptVisitor(this, _);
}
@Override
public ResolveResult visitComposedType(final ComposedType node, final Void _) {
return resolveType(node.toTypeReference());
}
@Override
public ResolveResult visitSimpleType(final SimpleType node, final Void _) {
return resolveType(node.toTypeReference());
}
@Override
public ResolveResult visitThisReferenceExpression(final ThisReferenceExpression node, final Void data) {
if (node.getTarget().isNull()) {
return resolveType(node.getUserData(Keys.TYPE_REFERENCE));
}
return node.getTarget().acceptVisitor(this, data);
}
@Override
public ResolveResult visitSuperReferenceExpression(final SuperReferenceExpression node, final Void data) {
if (node.getTarget().isNull()) {
return resolveType(node.getUserData(Keys.TYPE_REFERENCE));
}
return node.getTarget().acceptVisitor(this, data);
}
@Override
public ResolveResult visitTypeReference(final TypeReferenceExpression node, final Void _) {
return resolveType(node.getType().getUserData(Keys.TYPE_REFERENCE));
}
@Override
public ResolveResult visitWildcardType(final WildcardType node, final Void _) {
return resolveType(node.toTypeReference());
}
@Override
public ResolveResult visitIdentifier(final Identifier node, final Void _) {
final ResolveResult result = resolveTypeFromMember(node.getUserData(Keys.MEMBER_REFERENCE));
if (result != null) {
return result;
}
return resolveTypeFromVariable(node.getUserData(Keys.VARIABLE));
}
@Override
public ResolveResult visitIdentifierExpression(final IdentifierExpression node, final Void data) {
ResolveResult result = resolveTypeFromMember(node.getUserData(Keys.MEMBER_REFERENCE));
if (result != null) {
return result;
}
final Variable variable = node.getUserData(Keys.VARIABLE);
if (variable == null) {
return null;
}
/*
if (variable.isParameter()) {
for (final AstNode n : node.getAncestors()) {
final AstNodeCollection parameters = n.getChildrenByRole(Roles.PARAMETER);
if (parameters.isEmpty()) {
continue;
}
for (final ParameterDeclaration p : parameters) {
final ParameterDefinition definition = p.getUserData(Keys.PARAMETER_DEFINITION);
if (definition != null) {
if (StringUtilities.equals(p.getName(), variable.getName())) {
return resolveType(definition.getParameterType());
}
}
}
}
}
*/
result = resolveTypeFromVariable(variable);
if (result != null) {
return result;
}
return super.visitIdentifierExpression(node, data);
}
protected ResolveResult resolveLambda(final AstNode node) {
final TypeReference lambdaType = node.getUserData(Keys.TYPE_REFERENCE);
if (lambdaType != null) {
return resolveType(lambdaType);
}
final DynamicCallSite callSite = node.getUserData(Keys.DYNAMIC_CALL_SITE);
if (callSite != null) {
return resolveType(callSite.getMethodType().getReturnType());
}
return null;
}
@Override
public ResolveResult visitMethodGroupExpression(final MethodGroupExpression node, final Void data) {
return resolveLambda(node);
}
@Override
public ResolveResult visitLambdaExpression(final LambdaExpression node, final Void data) {
return resolveLambda(node);
}
@Override
public ResolveResult visitMemberReferenceExpression(final MemberReferenceExpression node, final Void _) {
final ResolveResult targetResult = node.getTarget().acceptVisitor(this, _);
MemberReference memberReference = node.getUserData(Keys.MEMBER_REFERENCE);
if (memberReference == null) {
if (StringUtilities.equals(node.getMemberName(), "length")) {
if (targetResult != null &&
targetResult.getType() != null &&
targetResult.getType().isArray()) {
return new ResolveResult(BuiltinTypes.Integer);
}
}
if (node.getParent() instanceof InvocationExpression) {
memberReference = node.getParent().getUserData(Keys.MEMBER_REFERENCE);
}
}
else if (targetResult != null &&
targetResult.getType() != null) {
if (memberReference instanceof FieldReference) {
final FieldDefinition resolvedField = ((FieldReference) memberReference).resolve();
memberReference = MetadataHelper.asMemberOf(
resolvedField != null ? resolvedField : (FieldReference) memberReference,
targetResult.getType()
);
}
else {
final MethodDefinition resolvedMethod = ((MethodReference) memberReference).resolve();
memberReference = MetadataHelper.asMemberOf(
resolvedMethod != null ? resolvedMethod : (MethodReference) memberReference,
targetResult.getType()
);
}
}
return resolveTypeFromMember(memberReference);
}
@Override
public ResolveResult visitInvocationExpression(final InvocationExpression node, final Void _) {
final ResolveResult result = resolveTypeFromMember(node.getUserData(Keys.MEMBER_REFERENCE));
if (result != null) {
return result;
}
return node.getTarget().acceptVisitor(this, _);
}
@Override
protected ResolveResult visitChildren(final AstNode node, final Void _) {
ResolveResult result = null;
AstNode next;
for (AstNode child = node.getFirstChild(); child != null; child = next) {
//
// Store next to allow the loop to continue if the visitor removes/replaces child.
//
next = child.getNextSibling();
if (child instanceof JavaTokenNode) {
continue;
}
final ResolveResult childResult = child.acceptVisitor(this, _);
if (childResult == null) {
return null;
}
else if (result == null) {
result = childResult;
}
else if (result.isCompileTimeConstant() &&
childResult.isCompileTimeConstant() &&
Comparer.equals(result.getConstantValue(), childResult.getConstantValue())) {
//noinspection UnnecessaryContinue
continue;
}
else {
final TypeReference commonSuperType = doBinaryPromotion(result, childResult);
if (commonSuperType != null) {
result = new ResolveResult(commonSuperType);
}
else {
return null;
}
}
}
return null;
}
private TypeReference doBinaryPromotion(final ResolveResult left, final ResolveResult right) {
final TypeReference leftType = left.getType();
final TypeReference rightType = right.getType();
if (leftType == null) {
return rightType;
}
if (rightType == null) {
return leftType;
}
if (StringUtilities.equals(leftType.getInternalName(), "java/lang/String")) {
return leftType;
}
if (StringUtilities.equals(rightType.getInternalName(), "java/lang/String")) {
return rightType;
}
return MetadataHelper.findCommonSuperType(leftType, rightType);
}
private TypeReference doBinaryPromotionStrict(final ResolveResult left, final ResolveResult right) {
if (left == null || right == null) {
return null;
}
TypeReference leftType = left.getType();
TypeReference rightType = right.getType();
if (leftType == null || rightType == null) {
return null;
}
leftType = MetadataHelper.getUnderlyingPrimitiveTypeOrSelf(leftType);
rightType = MetadataHelper.getUnderlyingPrimitiveTypeOrSelf(rightType);
if (StringUtilities.equals(leftType.getInternalName(), "java/lang/String")) {
return leftType;
}
if (StringUtilities.equals(rightType.getInternalName(), "java/lang/String")) {
return rightType;
}
return MetadataHelper.findCommonSuperType(leftType, rightType);
}
@Override
public ResolveResult visitPrimitiveExpression(final PrimitiveExpression node, final Void _) {
final String literalValue = node.getLiteralValue();
final Object value = node.getValue();
final TypeReference primitiveType;
if (value instanceof String || value == null && literalValue != null) {
final TypeDefinition currentType = context.getCurrentType();
final IMetadataResolver resolver = currentType != null ? currentType.getResolver() : MetadataSystem.instance();
primitiveType = resolver.lookupType("java/lang/String");
}
else if (value instanceof Number) {
if (value instanceof Byte) {
primitiveType = BuiltinTypes.Byte;
}
else if (value instanceof Short) {
primitiveType = BuiltinTypes.Short;
}
else if (value instanceof Integer) {
primitiveType = BuiltinTypes.Integer;
}
else if (value instanceof Long) {
primitiveType = BuiltinTypes.Long;
}
else if (value instanceof Float) {
primitiveType = BuiltinTypes.Float;
}
else if (value instanceof Double) {
primitiveType = BuiltinTypes.Double;
}
else {
primitiveType = null;
}
}
else if (value instanceof Character) {
primitiveType = BuiltinTypes.Character;
}
else if (value instanceof Boolean) {
primitiveType = BuiltinTypes.Boolean;
}
else {
primitiveType = null;
}
if (primitiveType == null) {
return null;
}
return new PrimitiveResolveResult(
primitiveType,
value != null ? value : literalValue
);
}
@Override
public ResolveResult visitClassOfExpression(final ClassOfExpression node, final Void data) {
final TypeReference type = node.getType().getUserData(Keys.TYPE_REFERENCE);
if (type == null) {
return null;
}
if (BuiltinTypes.Class.isGenericType()) {
return new ResolveResult(BuiltinTypes.Class.makeGenericType(type));
}
return new ResolveResult(BuiltinTypes.Class);
}
@Override
public ResolveResult visitCastExpression(final CastExpression node, final Void data) {
final ResolveResult childResult = node.getExpression().acceptVisitor(this, data);
final ResolveResult typeResult = resolveType(node.getType());
if (typeResult == null) {
return childResult;
}
final TypeReference resolvedType = typeResult.getType();
if (resolvedType != null) {
if (resolvedType.isPrimitive() &&
childResult != null &&
childResult.isCompileTimeConstant()) {
return new PrimitiveResolveResult(
resolvedType,
JavaPrimitiveCast.cast(resolvedType.getSimpleType(), childResult.getConstantValue())
);
}
return new ResolveResult(resolvedType);
}
return typeResult;
}
@Override
public ResolveResult visitNullReferenceExpression(final NullReferenceExpression node, final Void data) {
return new ResolveResult(BuiltinTypes.Null);
}
@Override
public ResolveResult visitBinaryOperatorExpression(final BinaryOperatorExpression node, final Void data) {
final ResolveResult leftResult = node.getLeft().acceptVisitor(this, data);
final ResolveResult rightResult = node.getRight().acceptVisitor(this, data);
if (leftResult == null || rightResult == null) {
return null;
}
final TypeReference leftType = leftResult.getType();
final TypeReference rightType = rightResult.getType();
if (leftType == null || rightType == null) {
return null;
}
final TypeReference operandType = doBinaryPromotionStrict(leftResult, rightResult);
if (operandType == null) {
return null;
}
final TypeReference resultType;
switch (node.getOperator()) {
case LOGICAL_AND:
case LOGICAL_OR:
case GREATER_THAN:
case GREATER_THAN_OR_EQUAL:
case EQUALITY:
case INEQUALITY:
case LESS_THAN:
case LESS_THAN_OR_EQUAL: {
resultType = BuiltinTypes.Boolean;
break;
}
default: {
switch (operandType.getSimpleType()) {
case Byte:
case Character:
case Short:
resultType = BuiltinTypes.Integer;
break;
default:
resultType = operandType;
break;
}
}
}
if (leftResult.isCompileTimeConstant() && rightResult.isCompileTimeConstant()) {
if (operandType.isPrimitive()) {
final Object result = BinaryOperations.doBinary(
node.getOperator(),
operandType.getSimpleType(),
leftResult.getConstantValue(),
rightResult.getConstantValue()
);
if (result != null) {
return new PrimitiveResolveResult(resultType, result);
}
}
}
return new ResolveResult(resultType);
}
@Override
public ResolveResult visitInstanceOfExpression(final InstanceOfExpression node, final Void data) {
final ResolveResult childResult = node.getExpression().acceptVisitor(this, data);
if (childResult == null) {
return new ResolveResult(BuiltinTypes.Boolean);
}
final TypeReference childType = childResult.getType();
final ResolveResult typeResult = resolveType(node.getType());
if (childType == null || typeResult == null || typeResult.getType() == null) {
return new ResolveResult(BuiltinTypes.Boolean);
}
return new PrimitiveResolveResult(
BuiltinTypes.Boolean,
MetadataHelper.isSubType(typeResult.getType(), childType)
);
}
@Override
public ResolveResult visitIndexerExpression(final IndexerExpression node, final Void data) {
final ResolveResult childResult = node.getTarget().acceptVisitor(this, data);
if (childResult == null || childResult.getType() == null || !childResult.getType().isArray()) {
return null;
}
final TypeReference elementType = childResult.getType().getElementType();
if (elementType == null) {
return null;
}
return new ResolveResult(elementType);
}
@Override
public ResolveResult visitUnaryOperatorExpression(final UnaryOperatorExpression node, final Void data) {
final ResolveResult childResult = node.getExpression().acceptVisitor(this, data);
if (childResult == null || childResult.getType() == null) {
return null;
}
final TypeReference resultType;
switch (childResult.getType().getSimpleType()) {
case Byte:
case Character:
case Short:
case Integer:
resultType = BuiltinTypes.Integer;
break;
default:
resultType = childResult.getType();
}
if (childResult.isCompileTimeConstant()) {
final Object resultValue = UnaryOperations.doUnary(node.getOperator(), childResult.getConstantValue());
if (resultValue != null) {
return new PrimitiveResolveResult(resultType, resultValue);
}
}
return new ResolveResult(resultType);
}
@Override
public ResolveResult visitConditionalExpression(final ConditionalExpression node, final Void data) {
final ResolveResult conditionResult = node.getCondition().acceptVisitor(this, data);
if (conditionResult != null &&
conditionResult.isCompileTimeConstant()) {
if (Boolean.TRUE.equals(conditionResult.getConstantValue())) {
return node.getTrueExpression().acceptVisitor(this, data);
}
if (Boolean.FALSE.equals(conditionResult.getConstantValue())) {
return node.getFalseExpression().acceptVisitor(this, data);
}
}
final ResolveResult leftResult = node.getTrueExpression().acceptVisitor(this, data);
if (leftResult == null || leftResult.getType() == null) {
return null;
}
final ResolveResult rightResult = node.getFalseExpression().acceptVisitor(this, data);
if (rightResult == null || rightResult.getType() == null) {
return null;
}
final TypeReference resultType = MetadataHelper.findCommonSuperType(
leftResult.getType(),
rightResult.getType()
);
if (resultType != null) {
if (leftResult.getType().isPrimitive() || rightResult.getType().isPrimitive()) {
return new ResolveResult(MetadataHelper.getUnderlyingPrimitiveTypeOrSelf(resultType));
}
return new ResolveResult(resultType);
}
return null;
}
@Override
public ResolveResult visitArrayCreationExpression(final ArrayCreationExpression node, final Void data) {
final TypeReference elementType = node.getType().toTypeReference();
if (elementType == null) {
return null;
}
final int rank = node.getDimensions().size() + node.getAdditionalArraySpecifiers().size();
TypeReference arrayType = elementType;
for (int i = 0; i < rank; i++) {
arrayType = arrayType.makeArrayType();
}
return new ResolveResult(arrayType);
}
@Override
public ResolveResult visitAssignmentExpression(final AssignmentExpression node, final Void data) {
final ResolveResult leftResult = node.getLeft().acceptVisitor(this, data);
if (leftResult != null && leftResult.getType() != null) {
return new ResolveResult(leftResult.getType());
}
return null;
}
@Override
public ResolveResult visitParenthesizedExpression(final ParenthesizedExpression node, final Void data) {
return node.getExpression().acceptVisitor(this, data);
}
}
private static ResolveResult resolveTypeFromVariable(final Variable variable) {
if (variable == null) {
return null;
}
TypeReference type = variable.getType();
if (type == null) {
type = variable.isParameter() ? variable.getOriginalParameter().getParameterType()
: variable.getOriginalVariable().getVariableType();
}
if (type != null) {
return new ResolveResult(type);
}
return null;
}
private static ResolveResult resolveType(final AstType type) {
if (type == null || type.isNull()) {
return null;
}
return resolveType(type.toTypeReference());
}
private static ResolveResult resolveType(final TypeReference type) {
return type == null ? null : new ResolveResult(type);
}
private static ResolveResult resolveTypeFromMember(final MemberReference member) {
if (member == null) {
return null;
}
if (member instanceof FieldReference) {
return new ResolveResult(((FieldReference) member).getFieldType());
}
if (member instanceof MethodReference) {
final MethodReference method = (MethodReference) member;
if (method.isConstructor()) {
return new ResolveResult(method.getDeclaringType());
}
return new ResolveResult(method.getReturnType());
}
return null;
}
private final static class PrimitiveResolveResult extends ResolveResult {
private final Object _value;
private PrimitiveResolveResult(final TypeReference type, final Object value) {
super(type);
_value = value;
}
@Override
public boolean isCompileTimeConstant() {
return true;
}
@Override
public Object getConstantValue() {
return _value;
}
}
private final static class BinaryOperations {
static Object doBinary(final BinaryOperatorType operator, final JvmType type, final Object left, final Object right) {
switch (operator) {
case BITWISE_AND:
return and(type, left, right);
case BITWISE_OR:
return or(type, left, right);
case EXCLUSIVE_OR:
return xor(type, left, right);
case LOGICAL_AND:
return andAlso(left, right);
case LOGICAL_OR:
return orElse(left, right);
case GREATER_THAN:
return greaterThan(type, left, right);
case GREATER_THAN_OR_EQUAL:
return greaterThanOrEqual(type, left, right);
case EQUALITY:
return equal(type, left, right);
case INEQUALITY:
return notEqual(type, left, right);
case LESS_THAN:
return lessThan(type, left, right);
case LESS_THAN_OR_EQUAL:
return lessThanOrEqual(type, left, right);
case ADD:
return add(type, left, right);
case SUBTRACT:
return subtract(type, left, right);
case MULTIPLY:
return multiply(type, left, right);
case DIVIDE:
return divide(type, left, right);
case MODULUS:
return remainder(type, left, right);
case SHIFT_LEFT:
return leftShift(type, left, right);
case SHIFT_RIGHT:
return rightShift(type, left, right);
case UNSIGNED_SHIFT_RIGHT:
return unsignedRightShift(type, left, right);
default:
return null;
}
}
private static Object add(final JvmType type, final Object left, final Object right) {
if (left instanceof Number && right instanceof Number) {
switch (type) {
case Byte:
return (byte) (((Number) left).intValue() + ((Number) right).intValue());
case Character:
return (char) ((Number) left).intValue() + ((Number) right).intValue();
case Short:
return (short) ((Number) left).intValue() + ((Number) right).intValue();
case Integer:
return ((Number) left).intValue() + ((Number) right).intValue();
case Long:
return ((Number) left).longValue() + ((Number) right).longValue();
case Float:
return ((Number) left).floatValue() + ((Number) right).floatValue();
case Double:
return ((Number) left).doubleValue() + ((Number) right).doubleValue();
}
}
return null;
}
private static Object subtract(final JvmType type, final Object left, final Object right) {
if (left instanceof Number && right instanceof Number) {
switch (type) {
case Byte:
return (byte) (((Number) left).intValue() - ((Number) right).intValue());
case Character:
return (char) ((Number) left).intValue() - ((Number) right).intValue();
case Short:
return (short) ((Number) left).intValue() - ((Number) right).intValue();
case Integer:
return ((Number) left).intValue() - ((Number) right).intValue();
case Long:
return ((Number) left).longValue() - ((Number) right).longValue();
case Float:
return ((Number) left).floatValue() - ((Number) right).floatValue();
case Double:
return ((Number) left).doubleValue() - ((Number) right).doubleValue();
}
}
return null;
}
private static Object multiply(final JvmType type, final Object left, final Object right) {
if (left instanceof Number && right instanceof Number) {
switch (type) {
case Byte:
return (byte) (((Number) left).intValue() * ((Number) right).intValue());
case Character:
return (char) ((Number) left).intValue() * ((Number) right).intValue();
case Short:
return (short) ((Number) left).intValue() * ((Number) right).intValue();
case Integer:
return ((Number) left).intValue() * ((Number) right).intValue();
case Long:
return ((Number) left).longValue() * ((Number) right).longValue();
case Float:
return ((Number) left).floatValue() * ((Number) right).floatValue();
case Double:
return ((Number) left).doubleValue() * ((Number) right).doubleValue();
}
}
return null;
}
private static Object divide(final JvmType type, final Object left, final Object right) {
if (left instanceof Number && right instanceof Number) {
if (type.isIntegral() && ((Number) right).longValue() == 0L) {
return null;
}
switch (type) {
case Byte:
return (byte) (((Number) left).intValue() / ((Number) right).intValue());
case Character:
return (char) ((Number) left).intValue() / ((Number) right).intValue();
case Short:
return (short) ((Number) left).intValue() / ((Number) right).intValue();
case Integer:
return ((Number) left).intValue() / ((Number) right).intValue();
case Long:
return ((Number) left).longValue() / ((Number) right).longValue();
case Float:
return ((Number) left).floatValue() / ((Number) right).floatValue();
case Double:
return ((Number) left).doubleValue() / ((Number) right).doubleValue();
}
}
return null;
}
private static Object remainder(final JvmType type, final Object left, final Object right) {
if (left instanceof Number && right instanceof Number) {
switch (type) {
case Byte:
return (byte) (((Number) left).intValue() % ((Number) right).intValue());
case Character:
return (char) ((Number) left).intValue() % ((Number) right).intValue();
case Short:
return (short) ((Number) left).intValue() % ((Number) right).intValue();
case Integer:
return ((Number) left).intValue() % ((Number) right).intValue();
case Long:
return ((Number) left).longValue() % ((Number) right).longValue();
case Float:
return ((Number) left).floatValue() % ((Number) right).floatValue();
case Double:
return ((Number) left).doubleValue() % ((Number) right).doubleValue();
}
}
return null;
}
private static Object and(final JvmType type, final Object left, final Object right) {
if (left instanceof Number && right instanceof Number) {
switch (type) {
case Byte:
return (byte) (((Number) left).intValue() & ((Number) right).intValue());
case Character:
return (char) ((Number) left).intValue() & ((Number) right).intValue();
case Short:
return (short) ((Number) left).intValue() & ((Number) right).intValue();
case Integer:
return ((Number) left).intValue() & ((Number) right).intValue();
case Long:
return ((Number) left).longValue() & ((Number) right).longValue();
}
}
return null;
}
private static Object or(final JvmType type, final Object left, final Object right) {
if (left instanceof Number && right instanceof Number) {
switch (type) {
case Byte:
return (byte) (((Number) left).intValue() | ((Number) right).intValue());
case Character:
return (char) ((Number) left).intValue() | ((Number) right).intValue();
case Short:
return (short) ((Number) left).intValue() | ((Number) right).intValue();
case Integer:
return ((Number) left).intValue() | ((Number) right).intValue();
case Long:
return ((Number) left).longValue() | ((Number) right).longValue();
}
}
return null;
}
private static Object xor(final JvmType type, final Object left, final Object right) {
if (left instanceof Number && right instanceof Number) {
switch (type) {
case Byte:
return (byte) (((Number) left).intValue() ^ ((Number) right).intValue());
case Character:
return (char) ((Number) left).intValue() ^ ((Number) right).intValue();
case Short:
return (short) ((Number) left).intValue() ^ ((Number) right).intValue();
case Integer:
return ((Number) left).intValue() ^ ((Number) right).intValue();
case Long:
return ((Number) left).longValue() ^ ((Number) right).longValue();
}
}
return null;
}
private static Object leftShift(final JvmType type, final Object left, final Object right) {
if (left instanceof Number && right instanceof Number) {
switch (type) {
case Byte:
return (byte) (((Number) left).intValue() << ((Number) right).intValue());
case Character:
return (char) ((Number) left).intValue() << ((Number) right).intValue();
case Short:
return (short) ((Number) left).intValue() << ((Number) right).intValue();
case Integer:
return ((Number) left).intValue() << ((Number) right).intValue();
case Long:
return ((Number) left).longValue() << ((Number) right).longValue();
}
}
return null;
}
private static Object rightShift(final JvmType type, final Object left, final Object right) {
if (left instanceof Number && right instanceof Number) {
switch (type) {
case Byte:
return (byte) (((Number) left).intValue() >> ((Number) right).intValue());
case Character:
return (char) ((Number) left).intValue() >> ((Number) right).intValue();
case Short:
return (short) ((Number) left).intValue() >> ((Number) right).intValue();
case Integer:
return ((Number) left).intValue() >> ((Number) right).intValue();
case Long:
return ((Number) left).longValue() >> ((Number) right).longValue();
}
}
return null;
}
private static Object unsignedRightShift(final JvmType type, final Object left, final Object right) {
if (left instanceof Number && right instanceof Number) {
switch (type) {
case Byte:
return (byte) (((Number) left).intValue() >>> ((Number) right).intValue());
case Character:
return (char) ((Number) left).intValue() >>> ((Number) right).intValue();
case Short:
return (short) ((Number) left).intValue() >>> ((Number) right).intValue();
case Integer:
return ((Number) left).intValue() >>> ((Number) right).intValue();
case Long:
return ((Number) left).longValue() >>> ((Number) right).longValue();
}
}
return null;
}
private static Object andAlso(final Object left, final Object right) {
return Boolean.TRUE.equals(asBoolean(left)) &&
Boolean.TRUE.equals(asBoolean(right));
}
private static Object orElse(final Object left, final Object right) {
return Boolean.TRUE.equals(asBoolean(left)) ||
Boolean.TRUE.equals(asBoolean(right));
}
private static Boolean asBoolean(final Object o) {
if (o instanceof Boolean) {
return (Boolean) o;
}
else if (o instanceof Number) {
final Number n = (Number) o;
if (o instanceof Float) {
return n.floatValue() != 0f;
}
else if (o instanceof Double) {
return n.doubleValue() != 0f;
}
else {
return n.longValue() != 0L;
}
}
return null;
}
private static Boolean lessThan(final JvmType type, final Object left, final Object right) {
if (left instanceof Number && right instanceof Number) {
switch (type) {
case Byte:
case Character:
case Short:
case Integer:
case Long:
return ((Number) left).longValue() < ((Number) right).longValue();
case Float:
return ((Number) left).floatValue() < ((Number) right).floatValue();
case Double:
return ((Number) left).doubleValue() < ((Number) right).doubleValue();
}
}
return null;
}
private static Boolean lessThanOrEqual(final JvmType type, final Object left, final Object right) {
if (left instanceof Number && right instanceof Number) {
switch (type) {
case Byte:
case Character:
case Short:
case Integer:
case Long:
return ((Number) left).longValue() <= ((Number) right).longValue();
case Float:
return ((Number) left).floatValue() <= ((Number) right).floatValue();
case Double:
return ((Number) left).doubleValue() <= ((Number) right).doubleValue();
}
}
return null;
}
private static Boolean greaterThan(final JvmType type, final Object left, final Object right) {
if (left instanceof Number && right instanceof Number) {
switch (type) {
case Byte:
case Character:
case Short:
case Integer:
case Long:
return ((Number) left).longValue() > ((Number) right).longValue();
case Float:
return ((Number) left).floatValue() > ((Number) right).floatValue();
case Double:
return ((Number) left).doubleValue() > ((Number) right).doubleValue();
}
}
return null;
}
private static Boolean greaterThanOrEqual(final JvmType type, final Object left, final Object right) {
if (left instanceof Number && right instanceof Number) {
switch (type) {
case Byte:
case Character:
case Short:
case Integer:
case Long:
return ((Number) left).longValue() >= ((Number) right).longValue();
case Float:
return ((Number) left).floatValue() >= ((Number) right).floatValue();
case Double:
return ((Number) left).doubleValue() >= ((Number) right).doubleValue();
}
}
return null;
}
private static Boolean equal(final JvmType type, final Object left, final Object right) {
if (left instanceof Number && right instanceof Number) {
switch (type) {
case Byte:
case Character:
case Short:
case Integer:
case Long:
return ((Number) left).longValue() == ((Number) right).longValue();
case Float:
return ((Number) left).floatValue() == ((Number) right).floatValue();
case Double:
return ((Number) left).doubleValue() == ((Number) right).doubleValue();
}
}
return null;
}
private static Boolean notEqual(final JvmType type, final Object left, final Object right) {
if (left instanceof Number && right instanceof Number) {
switch (type) {
case Byte:
case Character:
case Short:
case Integer:
case Long:
return ((Number) left).longValue() != ((Number) right).longValue();
case Float:
return ((Number) left).floatValue() != ((Number) right).floatValue();
case Double:
return ((Number) left).doubleValue() != ((Number) right).doubleValue();
}
}
return null;
}
}
private final static class UnaryOperations {
static Object doUnary(final UnaryOperatorType operator, final Object operand) {
switch (operator) {
case NOT:
return isFalse(operand);
case BITWISE_NOT:
return not(operand);
case MINUS:
return minus(operand);
case PLUS:
return plus(operand);
case INCREMENT:
return preIncrement(operand);
case DECREMENT:
return preDecrement(operand);
case POST_INCREMENT:
return postIncrement(operand);
case POST_DECREMENT:
return postDecrement(operand);
}
return null;
}
private static Object isFalse(final Object operand) {
if (Boolean.TRUE.equals(operand)) {
return Boolean.FALSE;
}
if (Boolean.FALSE.equals(operand)) {
return Boolean.TRUE;
}
if (operand instanceof Number) {
final Number n = (Number) operand;
if (n instanceof Float) {
return n.floatValue() != 0f;
}
if (n instanceof Double) {
return n.doubleValue() != 0d;
}
return n.longValue() != 0L;
}
return null;
}
private static Object not(final Object operand) {
if (operand instanceof Number) {
final Number n = (Number) operand;
if (n instanceof Byte) {
return ~n.byteValue();
}
if (n instanceof Short) {
return ~n.shortValue();
}
if (n instanceof Integer) {
return ~n.intValue();
}
if (n instanceof Long) {
return ~n.longValue();
}
}
else if (operand instanceof Character) {
return ~((Character) operand);
}
return null;
}
private static Object minus(final Object operand) {
if (operand instanceof Number) {
final Number n = (Number) operand;
if (n instanceof Byte) {
return -n.byteValue();
}
if (n instanceof Short) {
return -n.shortValue();
}
if (n instanceof Integer) {
return -n.intValue();
}
if (n instanceof Long) {
return -n.longValue();
}
}
else if (operand instanceof Character) {
return -((Character) operand);
}
return null;
}
private static Object plus(final Object operand) {
if (operand instanceof Number) {
final Number n = (Number) operand;
if (n instanceof Byte) {
return +n.byteValue();
}
if (n instanceof Short) {
return +n.shortValue();
}
if (n instanceof Integer) {
return +n.intValue();
}
if (n instanceof Long) {
return +n.longValue();
}
}
else if (operand instanceof Character) {
return +((Character) operand);
}
return null;
}
private static Object preIncrement(final Object operand) {
if (operand instanceof Number) {
final Number n = (Number) operand;
if (n instanceof Byte) {
byte b = n.byteValue();
return ++b;
}
if (n instanceof Short) {
short s = n.shortValue();
return ++s;
}
if (n instanceof Integer) {
int i = n.intValue();
return ++i;
}
if (n instanceof Long) {
long l = n.longValue();
return ++l;
}
}
else if (operand instanceof Character) {
char c = ((Character) operand);
return ++c;
}
return null;
}
private static Object preDecrement(final Object operand) {
if (operand instanceof Number) {
final Number n = (Number) operand;
if (n instanceof Byte) {
byte b = n.byteValue();
return --b;
}
if (n instanceof Short) {
short s = n.shortValue();
return --s;
}
if (n instanceof Integer) {
int i = n.intValue();
return --i;
}
if (n instanceof Long) {
long l = n.longValue();
return --l;
}
}
else if (operand instanceof Character) {
char c = ((Character) operand);
return --c;
}
return null;
}
private static Object postIncrement(final Object operand) {
if (operand instanceof Number) {
return operand;
}
else if (operand instanceof Character) {
return operand;
}
return null;
}
private static Object postDecrement(final Object operand) {
if (operand instanceof Number) {
return operand;
}
else if (operand instanceof Character) {
return operand;
}
return null;
}
}
}