blob: d41c6b227c846e4b73e05da21354afc61e1c3971 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
*
* Contributors:
* IBM Corporation - initial API and implementation
* Jesper Steen Moller - Bug 427089
*******************************************************************************/
package org.eclipse.jdt.internal.debug.eval.ast.engine;
import java.util.ArrayList;
import java.util.EmptyStackException;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugException;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.*;
import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
import org.eclipse.jdt.internal.debug.eval.ExpressionBinder;
import org.eclipse.jdt.internal.debug.eval.RemoteEvaluator;
import org.eclipse.jdt.internal.debug.eval.RemoteEvaluatorBuilder;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.AndAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.AndOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.ArrayAllocation;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.ArrayInitializerInstruction;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.AssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.Cast;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.CompoundInstruction;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.ConditionalJump;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.Constructor;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.DivideAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.DivideOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.Dup;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.DupX1;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.EqualEqualOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.GreaterEqualOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.GreaterOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.InstanceOfOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.Instruction;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.InstructionSequence;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.Jump;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.LeftShiftAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.LeftShiftOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.LessEqualOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.LessOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.LocalVariableCreation;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.MinusAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.MinusOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.MultiplyAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.MultiplyOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.NoOp;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.NotOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.OrAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.OrOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PlusAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PlusOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.Pop;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PostfixMinusMinusOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PostfixPlusPlusOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PrefixMinusMinusOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PrefixPlusPlusOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushArrayLength;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushArrayType;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushBoolean;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushChar;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushClassLiteralValue;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushDouble;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushFieldVariable;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushFloat;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushInt;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushLocalVariable;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushLong;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushNull;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushPrimitiveType;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushStaticFieldVariable;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushString;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushThis;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushType;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.RemainderAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.RemainderOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.RemoteOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.ReturnInstruction;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.RightShiftAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.RightShiftOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.SendMessage;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.SendStaticMessage;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.ThrowInstruction;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.TwiddleOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.UnaryMinusOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.UnaryPlusOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.UnsignedRightShiftAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.UnsignedRightShiftOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.Value;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.XorAssignmentOperator;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.XorOperator;
import org.eclipse.osgi.util.NLS;
import com.ibm.icu.text.MessageFormat;
/**
* The AST instruction compiler generates a sequence of instructions
* (InstructionSequence) from a DOM AST.
*/
public class ASTInstructionCompiler extends ASTVisitor {
/**
* Represent a break or a continue instruction. These instructions needs are
* stored and managed later by their related statement.
*/
class CompleteInstruction {
Jump fInstruction;
String fLabel;
boolean fIsBreak;
public CompleteInstruction(Jump instruction, String label,
boolean isBreak) {
fInstruction = instruction;
fLabel = label;
fIsBreak = isBreak;
}
}
/**
* Whether to print debug messages to the console
*/
private static boolean VERBOSE = false;
private InstructionSequence fInstructions;
/**
* The list of pending break and continue instruction.
*/
private List<CompleteInstruction> fCompleteInstructions;
private int fStartPosition;
private boolean fActive;
private boolean fHasErrors;
private Stack<Instruction> fStack;
private int fCounter;
// internal index used to create unique variable name
private int fUniqueIdIndex = 0;
private IJavaProject fJavaProject;
/**
* Create a new AST instruction compiler
*/
public ASTInstructionCompiler(int startPosition, String snippet, IJavaProject javaProject) {
fStartPosition = startPosition;
fInstructions = new InstructionSequence(snippet);
fStack = new Stack<>();
fCompleteInstructions = new ArrayList<>();
fJavaProject = javaProject;
}
/**
* Returns the instruction sequence generated by this AST instruction
* compiler
*/
public InstructionSequence getInstructions() {
return fInstructions;
}
/**
* Returns whether the generated instruction sequence has errors. Errors
* include:
* <ol>
* <li>AST contains unimplemented operations (features which will be
* supported, but aren't yet)</li>
* <li>AST contains unsupported operations (features which are not yet
* implemented and are likely NOT to be implemented)</li>
* </ol>
*/
public boolean hasErrors() {
return fHasErrors;
}
private void setHasError(boolean value) {
fHasErrors = value;
}
private void addErrorMessage(String message) {
fInstructions.addError(message);
}
private boolean isActive() {
return fActive;
}
private void setActive(boolean active) {
fActive = active;
}
private void push(Instruction i) {
fStack.push(i);
}
private void storeInstruction() {
Instruction instruction = null;
try {
instruction = fStack.pop();
}
catch(EmptyStackException ese) {
JDIDebugPlugin.log(new Status(
IStatus.WARNING,
JDIDebugPlugin.getUniqueIdentifier(),
NLS.bind(EvaluationEngineMessages.ASTInstructionCompiler_4, fCounter),
ese));
}
if(instruction != null) {
fCounter++;
if (instruction instanceof CompoundInstruction) {
((CompoundInstruction) instruction).setEnd(fCounter);
}
fInstructions.add(instruction);
//System.out.println("Added: " + instruction.toString()); //$NON-NLS-1$
verbose("Add " + instruction.toString()); //$NON-NLS-1$
}
}
/**
* Prints the given message to the console if verbose mode is on.
*
* @param message
* the message to display
*/
private void verbose(String message) {
if (VERBOSE) {
System.out.println(message);
}
}
private String getTypeName(ITypeBinding typeBinding) {
if (typeBinding.isRawType()) {
typeBinding = typeBinding.getErasure();
}
if (typeBinding.isTypeVariable()) {
ITypeBinding[] typeBounds = typeBinding.getTypeBounds();
if (typeBounds.length > 0) {
String name = getTypeName(typeBounds[0]);
if (typeBounds.length > 1 && "java.lang.Object".equals(name)) { //$NON-NLS-1$
return getTypeName(typeBounds[1]);
}
return name;
}
return "java.lang.Object"; //$NON-NLS-1$
}
StringBuilder name;
if (typeBinding.isArray()) {
name = new StringBuilder(getTypeName(typeBinding.getElementType()));
int dimensions = typeBinding.getDimensions();
for (int i = 0; i < dimensions; i++) {
name.append("[]"); //$NON-NLS-1$
}
return name.toString();
}
//try it the old way
name = new StringBuilder(Signature.getTypeErasure(typeBinding.getName()));
IPackageBinding packageBinding = typeBinding.getPackage();
typeBinding = typeBinding.getDeclaringClass();
while (typeBinding != null) {
name.insert(0, '$').insert(0, Signature.getTypeErasure(typeBinding.getName()));
typeBinding = typeBinding.getDeclaringClass();
}
if (packageBinding != null && !packageBinding.isUnnamed()) {
name.insert(0, '.').insert(0, packageBinding.getName());
}
return name.toString();
}
private String getTypeSignature(ITypeBinding typeBinding) {
return Signature.createTypeSignature(getTypeName(typeBinding), true)
.replace('.', '/');
}
private boolean isALocalType(ITypeBinding typeBinding) {
while (typeBinding != null) {
if (typeBinding.isLocal()) {
return true;
}
typeBinding = typeBinding.getDeclaringClass();
}
return false;
}
private boolean containsALocalType(IMethodBinding methodBinding) {
ITypeBinding[] typeBindings = methodBinding.getParameterTypes();
for (ITypeBinding typeBinding : typeBindings) {
if (isALocalType(typeBinding)) {
return true;
}
}
return false;
}
private int getEnclosingLevel(ASTNode node,
ITypeBinding referenceTypeBinding) {
ASTNode parent = node;
ITypeBinding refbinding = referenceTypeBinding.isParameterizedType() ? referenceTypeBinding
.getTypeDeclaration() : referenceTypeBinding;
do {
parent = parent.getParent();
} while (parent != null
&& !(parent instanceof AbstractTypeDeclaration || parent instanceof AnonymousClassDeclaration));
if (parent == null) {
return 0;
}
ITypeBinding parentBinding = null;
if (parent instanceof AbstractTypeDeclaration) {
parentBinding = ((AbstractTypeDeclaration) parent).resolveBinding();
} else if (parent instanceof AnonymousClassDeclaration) {
parentBinding = ((AnonymousClassDeclaration) parent)
.resolveBinding();
}
if (parentBinding != null
&& (parentBinding.isEqualTo(refbinding) || parentBinding
.isCastCompatible(refbinding))) {
return 0;
}
return getEnclosingLevel(parent, referenceTypeBinding) + 1;
}
private int getSuperLevel(ITypeBinding current, ITypeBinding reference) {
if (current.equals(reference)) {
return 0;
}
return getSuperLevel(current.getSuperclass(), reference);
}
/**
* Return the label associated with the given statement.
*
* @param statement
* the statement.
* @return the associated label, or <code>null</code> if there is none.
*/
private String getLabel(Statement statement) {
ASTNode parent = statement.getParent();
if (parent instanceof LabeledStatement) {
return ((LabeledStatement) parent).getLabel().getIdentifier();
}
return null;
}
/**
* Append a pop instruction in the instruction list if needed. A pop
* instruction is added when the expression has a return value, i.e. all
* expressions expect method invocation expressions which have
* <code>void</code> as return type and variable declaration expression.
*
* @param expression
* the expression to test.
*/
private void addPopInstructionIfNeeded(Expression expression) {
boolean pop = true;
if (expression instanceof MethodInvocation) {
IMethodBinding methodBinding = (IMethodBinding) ((MethodInvocation) expression)
.getName().resolveBinding();
if (methodBinding != null
&& "void".equals(methodBinding.getReturnType().getName())) { //$NON-NLS-1$
pop = false;
}
} else if (expression instanceof SuperMethodInvocation) {
IMethodBinding methodBinding = (IMethodBinding) ((SuperMethodInvocation) expression)
.getName().resolveBinding();
if (methodBinding != null
&& "void".equals(methodBinding.getReturnType().getName())) { //$NON-NLS-1$
pop = false;
}
} else if (expression instanceof VariableDeclarationExpression) {
pop = false;
}
if (pop) {
addPopInstruction();
}
}
/**
*
*/
private void addPopInstruction() {
Instruction lastInstruction = fInstructions
.getInstruction(fInstructions.getEnd());
push(new Pop(lastInstruction.getSize() + 1));
storeInstruction();
}
/**
* Check the current type of a value and the requested type to decide if
* boxing/un-boxing is required. If needed, the correct instruction is added
* to the stack Returns true if a storeInstruction() is needed after
* visiting the expression
*/
private boolean checkAutoBoxing(ITypeBinding valueBinding,
ITypeBinding requestedBinding) {
if (valueBinding == null) {
return false; // unresolved
}
if (valueBinding.isPrimitive() == requestedBinding.isPrimitive()) {
return false;
}
if (requestedBinding.isPrimitive()) {
unBoxing(valueBinding);
} else {
boxing(requestedBinding, valueBinding);
}
return true;
}
/**
* Add to the stack the instruction to box a primitive value.
*/
private void boxing(ITypeBinding requestedBinding, ITypeBinding valueBinding) {
String requestedTypeName = requestedBinding.getQualifiedName();
if ("java.lang.Object".equals(requestedTypeName)) { //$NON-NLS-1$
switch (valueBinding.getBinaryName().charAt(0)) {
case 'I':
push(new SendStaticMessage(
"java.lang.Integer", "valueOf", "(I)Ljava/lang/Integer;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
break;
case 'C':
push(new SendStaticMessage(
"java.lang.Character", "valueOf", "(C)Ljava/lang/Character;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
break;
case 'B':
push(new SendStaticMessage(
"java.lang.Byte", "valueOf", "(B)Ljava/lang/Byte;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
break;
case 'S':
push(new SendStaticMessage(
"java.lang.Short", "valueOf", "(S)Ljava/lang/Short;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
break;
case 'J':
push(new SendStaticMessage(
"java.lang.Long", "valueOf", "(J)Ljava/lang/Long;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
break;
case 'F':
push(new SendStaticMessage(
"java.lang.Float", "valueOf", "(F)Ljava/lang/Float;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
break;
case 'D':
push(new SendStaticMessage(
"java.lang.Double", "valueOf", "(D)Ljava/lang/Double;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
break;
case 'Z':
push(new SendStaticMessage(
"java.lang.Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
break;
}
} else if ("java.lang.Integer".equals(requestedTypeName)) { //$NON-NLS-1$
push(new SendStaticMessage(requestedTypeName,
"valueOf", "(I)Ljava/lang/Integer;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Character".equals(requestedTypeName)) { //$NON-NLS-1$
push(new SendStaticMessage(requestedTypeName,
"valueOf", "(C)Ljava/lang/Character;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Byte".equals(requestedTypeName)) { //$NON-NLS-1$
push(new SendStaticMessage(requestedTypeName,
"valueOf", "(B)Ljava/lang/Byte;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Short".equals(requestedTypeName)) { //$NON-NLS-1$
push(new SendStaticMessage(requestedTypeName,
"valueOf", "(S)Ljava/lang/Short;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Long".equals(requestedTypeName)) { //$NON-NLS-1$
push(new SendStaticMessage(requestedTypeName,
"valueOf", "(J)Ljava/lang/Long;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Float".equals(requestedTypeName)) { //$NON-NLS-1$
push(new SendStaticMessage(requestedTypeName,
"valueOf", "(F)Ljava/lang/Float;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Double".equals(requestedTypeName)) { //$NON-NLS-1$
push(new SendStaticMessage(requestedTypeName,
"valueOf", "(D)Ljava/lang/Double;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Boolean".equals(requestedTypeName)) { //$NON-NLS-1$
push(new SendStaticMessage(requestedTypeName,
"valueOf", "(Z)Ljava/lang/Boolean;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
}
}
/**
* Add the instruction to un-box a non-primitive value if needed. Returns
* true if a storeInstruction() is needed after visiting the expression
*/
private boolean unBoxing(ITypeBinding valueBinding) {
String valueTypeName = valueBinding.getQualifiedName();
if ("java.lang.Integer".equals(valueTypeName)) { //$NON-NLS-1$
push(new SendMessage("intValue", "()I", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Character".equals(valueTypeName)) { //$NON-NLS-1$
push(new SendMessage("charValue", "()C", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Byte".equals(valueTypeName)) { //$NON-NLS-1$
push(new SendMessage("byteValue", "()B", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Short".equals(valueTypeName)) { //$NON-NLS-1$
push(new SendMessage("shortValue", "()S", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Long".equals(valueTypeName)) { //$NON-NLS-1$
push(new SendMessage("longValue", "()J", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Float".equals(valueTypeName)) { //$NON-NLS-1$
push(new SendMessage("floatValue", "()F", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Double".equals(valueTypeName)) { //$NON-NLS-1$
push(new SendMessage("doubleValue", "()D", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else if ("java.lang.Boolean".equals(valueTypeName)) { //$NON-NLS-1$
push(new SendMessage("booleanValue", "()Z", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else {
return false;
}
return true;
}
/**
* End visit methods
*
* There are two paths to ending a visit to a node:
* <ol>
* <li>For control statements, the necessary control instructions (jump,
* conditional jump) are inserted into the instruction sequence</li>
* <li>For other cases, we simply remove the node's instruction from the
* stack and add it to the instruction sequence.</li>
* </ol>
*/
/**
* @see ASTVisitor#endVisit(AnonymousClassDeclaration)
*/
@Override
public void endVisit(AnonymousClassDeclaration node) {
}
/**
* @see ASTVisitor#endVisit(ArrayAccess)
*/
@Override
public void endVisit(ArrayAccess node) {
if (!isActive() || hasErrors()) {
return;
}
ITypeBinding typeBinding = node.getIndex().resolveTypeBinding();
if (typeBinding != null && unBoxing(typeBinding)) {
// un-box the index, if required
storeInstruction();
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ArrayCreation)
*/
@Override
public void endVisit(ArrayCreation node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ArrayInitializer)
*/
@Override
public void endVisit(ArrayInitializer node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ArrayType)
*/
@Override
public void endVisit(ArrayType node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(AssertStatement)
*/
@Override
public void endVisit(AssertStatement node) {
}
/**
* @see ASTVisitor#endVisit(Assignment)
*/
@Override
public void endVisit(Assignment node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(Block)
*/
@Override
public void endVisit(Block node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(BooleanLiteral)
*/
@Override
public void endVisit(BooleanLiteral node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(BreakStatement)
*/
@Override
public void endVisit(BreakStatement node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(CastExpression)
*/
@Override
public void endVisit(CastExpression node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(CatchClause)
*/
@Override
public void endVisit(CatchClause node) {
}
/**
* @see ASTVisitor#endVisit(CharacterLiteral)
*/
@Override
public void endVisit(CharacterLiteral node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ClassInstanceCreation)
*/
@Override
public void endVisit(ClassInstanceCreation node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(CompilationUnit)
*/
@Override
public void endVisit(CompilationUnit node) {
while(!fStack.isEmpty()) {
storeInstruction();
}
}
/**
* @see ASTVisitor#endVisit(ConditionalExpression)
*/
@Override
public void endVisit(ConditionalExpression node) {
if (!isActive() || hasErrors()) {
return;
}
// Get the instructions
int ifFalseAddress = fInstructions.getEnd();
Instruction ifFalse = fInstructions.get(ifFalseAddress);
int ifTrueAddress = ifFalseAddress - ifFalse.getSize();
Instruction ifTrue = fInstructions.get(ifTrueAddress);
int conditionalAddress = ifTrueAddress - ifTrue.getSize();
// Insert the conditional jump
ConditionalJump conditionalJump = new ConditionalJump(false);
fInstructions.insert(conditionalJump, conditionalAddress + 1);
// Insert the jump
int jumpAddress = ifTrueAddress + 2;
Jump jump = new Jump();
fInstructions.insert(jump, jumpAddress);
// Set the jump offsets
conditionalJump.setOffset(ifTrue.getSize() + 1);
jump.setOffset(ifFalse.getSize() + 1);
fCounter += 2;
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ConstructorInvocation)
*/
@Override
public void endVisit(ConstructorInvocation node) {
}
/**
* @see ASTVisitor#endVisit(ContinueStatement)
*/
@Override
public void endVisit(ContinueStatement node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(DoStatement)
*/
@Override
public void endVisit(DoStatement node) {
if (!isActive() || hasErrors()) {
return;
}
/*
* The structure of generated instructions is :
*
* -- | body -- -- |condition -- - jump to the first instruction of the
* body if the condition is true.
*/
String label = getLabel(node);
// get address of each part
int conditionAddress = fInstructions.getEnd();
Instruction condition = fInstructions.getInstruction(conditionAddress);
int bodyAddress = conditionAddress - condition.getSize();
Instruction body = fInstructions.getInstruction(bodyAddress);
int bodyStartAddress = bodyAddress - body.getSize();
// add the conditionnalJump
ConditionalJump conditionalJump = new ConditionalJump(true);
fInstructions.add(conditionalJump);
fCounter++;
// set jump offsets
conditionalJump.setOffset(-(condition.getSize() + body.getSize() + 1));
// for each pending break or continue instruction which are related to
// this loop, set the offset of the corresponding jump.
for (Iterator<CompleteInstruction> iter = fCompleteInstructions.iterator(); iter.hasNext();) {
CompleteInstruction instruction = iter.next();
Jump jumpInstruction = instruction.fInstruction;
int instructionAddress = fInstructions.indexOf(jumpInstruction);
if (instructionAddress > bodyStartAddress
&& (instruction.fLabel == null || instruction.fLabel
.equals(label))) {
iter.remove();
if (instruction.fIsBreak) {
// jump to the instruction after the last jump
jumpInstruction
.setOffset((conditionAddress - instructionAddress) + 1);
} else {
// jump to the first instruction of the condition
jumpInstruction.setOffset(bodyAddress - instructionAddress);
}
}
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(EmptyStatement)
*/
@Override
public void endVisit(EmptyStatement node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom
* .EnhancedForStatement)
*/
@Override
public void endVisit(EnhancedForStatement node) {
if (!isActive() || hasErrors()) {
return;
}
/*
* The structure of generated instructions is :
*
* For an array: -- | <ParameterType>[] a= Expression | int i= 0 |
* <ParameterType> <ParameterName> -- -- | i < a.length - jump to the
* instruction after the last jump if the condition is false. -- -- | s=
* a[i] | Body -- -- - jump to the first instruction of the condition.
*
* For an Iterable: -- | Iterator i= Expression.iterator() |
* <ParameterType> <ParameterName> -- -- | i.hasNext() - jump to the
* instruction after the last jump if the condition is false. -- -- | s=
* i.next() | Body -- -- - jump to the first instruction of the
* condition.
*/
int bodyAddress = fInstructions.getEnd();
Instruction body = fInstructions.getInstruction(bodyAddress);
int conditionAddress = bodyAddress - body.getSize();
Instruction condition = fInstructions.getInstruction(conditionAddress);
int initAddress = conditionAddress - condition.getSize();
// add conditional jump
ConditionalJump condJump = new ConditionalJump(false);
fInstructions.insert(condJump, conditionAddress + 1);
bodyAddress++;
fCounter++;
condJump.setOffset(body.getSize() + 1);
// add jump
Jump jump = new Jump();
fInstructions.add(jump);
fCounter++;
jump.setOffset(initAddress - (bodyAddress + 1));
// for each pending break or continue instruction which are related to
// this loop, set the offset of the corresponding jump.
String label = getLabel(node);
for (Iterator<CompleteInstruction> iter = fCompleteInstructions.iterator(); iter.hasNext();) {
CompleteInstruction instruction = iter.next();
Jump jumpInstruction = instruction.fInstruction;
int instructionAddress = fInstructions.indexOf(jumpInstruction);
if (instructionAddress > conditionAddress
&& (instruction.fLabel == null || instruction.fLabel
.equals(label))) {
iter.remove();
if (instruction.fIsBreak) {
// jump to the instruction after the last jump
jumpInstruction
.setOffset((bodyAddress - instructionAddress) + 1);
} else {
// jump to the first instruction of the condition
jumpInstruction.setOffset(initAddress - instructionAddress);
}
}
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ExpressionStatement)
*/
@Override
public void endVisit(ExpressionStatement node) {
if (!isActive() || hasErrors()) {
return;
}
addPopInstructionIfNeeded(node.getExpression());
}
/**
* @see ASTVisitor#endVisit(FieldAccess)
*/
@Override
public void endVisit(FieldAccess node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(FieldDeclaration)
*/
@Override
public void endVisit(FieldDeclaration node) {
}
/**
* @see ASTVisitor#endVisit(ForStatement)
*/
@Override
public void endVisit(ForStatement node) {
if (!isActive() || hasErrors()) {
return;
}
/*
* The structure of generated instructions is :
*
* -- |initialization -- -- |condition -- - jump to the instruction
* after the last jump if the condition is false. -- | body -- -- |
* updaters -- - jump to the first instruction of the condition.
*/
String label = getLabel(node);
boolean hasCondition = node.getExpression() != null;
// get address of each part
int updatersAddress = fInstructions.getEnd();
Instruction updaters = fInstructions.getInstruction(updatersAddress);
int bodyAddress = updatersAddress - updaters.getSize();
Instruction body = fInstructions.getInstruction(bodyAddress);
int bodyStartAddress = bodyAddress - body.getSize();
int conditionAddress;
Instruction condition;
if (hasCondition) {
conditionAddress = bodyStartAddress;
condition = fInstructions.getInstruction(conditionAddress);
} else {
conditionAddress = 0;
condition = null;
}
// add jump
Jump jump = new Jump();
fInstructions.add(jump);
fCounter++;
if (hasCondition) {
// add conditional jump
ConditionalJump condJump = new ConditionalJump(false);
fInstructions.insert(condJump, conditionAddress + 1);
bodyAddress++;
bodyStartAddress++;
updatersAddress++;
fCounter++;
// set conditional jump offset
condJump.setOffset(body.getSize() + updaters.getSize() + 1);
}
// set jump offset
jump.setOffset(-((hasCondition && (condition != null) ? condition
.getSize() : 0) + body.getSize() + updaters.getSize() + 2));
// for each pending break or continue instruction which are related to
// this loop, set the offset of the corresponding jump.
for (Iterator<CompleteInstruction> iter = fCompleteInstructions.iterator(); iter.hasNext();) {
CompleteInstruction instruction = iter.next();
Jump jumpInstruction = instruction.fInstruction;
int instructionAddress = fInstructions.indexOf(jumpInstruction);
if (instructionAddress > bodyStartAddress
&& (instruction.fLabel == null || instruction.fLabel
.equals(label))) {
iter.remove();
if (instruction.fIsBreak) {
// jump to the instruction after the last jump
jumpInstruction
.setOffset((updatersAddress - instructionAddress) + 1);
} else {
// jump to the first instruction of the condition
jumpInstruction.setOffset(bodyAddress - instructionAddress);
}
}
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(IfStatement)
*/
@Override
public void endVisit(IfStatement node) {
if (!isActive() || hasErrors()) {
return;
}
boolean hasElseStatement = node.getElseStatement() != null;
// Get the instructions
int ifFalseAddress = 0;
Instruction ifFalse = null;
int ifTrueAddress = 0;
Instruction ifTrue = null;
if (hasElseStatement) {
ifFalseAddress = fInstructions.getEnd();
ifFalse = fInstructions.get(ifFalseAddress);
ifTrueAddress = ifFalseAddress - ifFalse.getSize();
ifTrue = fInstructions.get(ifTrueAddress);
} else {
ifTrueAddress = fInstructions.getEnd();
ifTrue = fInstructions.get(ifTrueAddress);
}
int conditionalAddress = ifTrueAddress - ifTrue.getSize();
// Insert the conditional jump
ConditionalJump conditionalJump = new ConditionalJump(false);
fInstructions.insert(conditionalJump, conditionalAddress + 1);
// Set the jump offset
conditionalJump.setOffset(ifTrue.getSize()
+ ((hasElseStatement) ? 1 : 0));
fCounter++;
if (hasElseStatement) {
// Insert the jump
int jumpAddress = ifTrueAddress + 2;
Jump jump = new Jump();
fInstructions.insert(jump, jumpAddress);
// Set the jump offset
jump.setOffset(ifFalse.getSize() + 1);
fCounter++;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ImportDeclaration)
*/
@Override
public void endVisit(ImportDeclaration node) {
}
/**
* @see ASTVisitor#endVisit(InfixExpression)
*/
@Override
public void endVisit(InfixExpression node) {
}
/**
* @see ASTVisitor#endVisit(Initializer)
*/
@Override
public void endVisit(Initializer node) {
}
/**
* @see ASTVisitor#endVisit(InstanceofExpression)
*/
@Override
public void endVisit(InstanceofExpression node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(Javadoc)
*/
@Override
public void endVisit(Javadoc node) {
}
/**
* @see ASTVisitor#endVisit(LabeledStatement)
*/
@Override
public void endVisit(LabeledStatement node) {
if (!isActive() || hasErrors()) {
return;
}
String label = node.getLabel().getIdentifier();
// for each pending continue instruction which are related to
// this statement, set the offset of the corresponding jump.
for (Iterator<CompleteInstruction> iter = fCompleteInstructions.iterator(); iter.hasNext();) {
CompleteInstruction instruction = iter.next();
if (instruction.fLabel != null && instruction.fLabel.equals(label)) {
iter.remove();
Jump jumpInstruction = instruction.fInstruction;
int instructionAddress = fInstructions.indexOf(jumpInstruction);
if (instruction.fIsBreak) {
// jump to the instruction after the statement
jumpInstruction.setOffset(fInstructions.getEnd()
- instructionAddress);
}
}
}
}
/**
* @see ASTVisitor#endVisit(MethodDeclaration)
*/
@Override
public void endVisit(MethodDeclaration node) {
setActive(false);
}
/**
* @see ASTVisitor#endVisit(MethodInvocation)
*/
@Override
public void endVisit(MethodInvocation node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(NullLiteral)
*/
@Override
public void endVisit(NullLiteral node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(NumberLiteral)
*/
@Override
public void endVisit(NumberLiteral node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(PackageDeclaration)
*/
@Override
public void endVisit(PackageDeclaration node) {
}
/**
* @see ASTVisitor#endVisit(SimpleType)
*/
@Override
public void endVisit(ParameterizedType node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ParenthesizedExpression)
*/
@Override
public void endVisit(ParenthesizedExpression node) {
}
/**
* @see ASTVisitor#endVisit(PostfixExpression)
*/
@Override
public void endVisit(PostfixExpression node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(PrefixExpression)
*/
@Override
public void endVisit(PrefixExpression node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(PrimitiveType)
*/
@Override
public void endVisit(PrimitiveType node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(QualifiedName)
*/
@Override
public void endVisit(QualifiedName node) {
}
/**
* @see ASTVisitor#endVisit(SimpleType)
*/
@Override
public void endVisit(QualifiedType node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ReturnStatement)
*/
@Override
public void endVisit(ReturnStatement node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(SimpleName)
*/
@Override
public void endVisit(SimpleName node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(SimpleType)
*/
@Override
public void endVisit(SimpleType node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(SingleVariableDeclaration)
*/
@Override
public void endVisit(SingleVariableDeclaration node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(StringLiteral)
*/
@Override
public void endVisit(StringLiteral node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
@Override
public void endVisit(TextBlock node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(SuperConstructorInvocation)
*/
@Override
public void endVisit(SuperConstructorInvocation node) {
}
/**
* @see ASTVisitor#endVisit(SuperFieldAccess)
*/
@Override
public void endVisit(SuperFieldAccess node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(SuperMethodInvocation)
*/
@Override
public void endVisit(SuperMethodInvocation node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(SwitchCase)
*/
@Override
public void endVisit(SwitchCase node) {
// never called
}
/**
* @see ASTVisitor#endVisit(SwitchStatement)
*/
@Override
public void endVisit(SwitchStatement node) {
// nothing to do
}
/**
* @see ASTVisitor#endVisit(SynchronizedStatement)
*/
@Override
public void endVisit(SynchronizedStatement node) {
}
/**
* @see ASTVisitor#endVisit(ThisExpression)
*/
@Override
public void endVisit(ThisExpression node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(ThrowStatement)
*/
@Override
public void endVisit(ThrowStatement node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(TryStatement)
*/
@Override
public void endVisit(TryStatement node) {
}
/**
* @see ASTVisitor#endVisit(TypeDeclaration)
*/
@Override
public void endVisit(TypeDeclaration node) {
}
/**
* @see ASTVisitor#endVisit(TypeDeclarationStatement)
*/
@Override
public void endVisit(TypeDeclarationStatement node) {
}
/**
* @see ASTVisitor#endVisit(TypeLiteral)
*/
@Override
public void endVisit(TypeLiteral node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(VariableDeclarationExpression)
*/
@Override
public void endVisit(VariableDeclarationExpression node) {
}
/**
* @see ASTVisitor#endVisit(VariableDeclarationFragment)
*/
@Override
public void endVisit(VariableDeclarationFragment node) {
if (!isActive() || hasErrors()) {
return;
}
storeInstruction();
}
/**
* @see ASTVisitor#endVisit(VariableDeclarationStatement)
*/
@Override
public void endVisit(VariableDeclarationStatement node) {
}
/**
* @see ASTVisitor#endVisit(WhileStatement)
*/
@Override
public void endVisit(WhileStatement node) {
if (!isActive() || hasErrors()) {
return;
}
/*
* The structure of generated instructions is :
*
* -- |condition -- - jump to the instruction after the last jump if the
* condition is false. -- | body -- - jump to the first instruction of
* the condition.
*/
String label = getLabel(node);
// get address of each part
int bodyAddress = fInstructions.getEnd();
Instruction body = fInstructions.getInstruction(bodyAddress);
int conditionAddress = bodyAddress - body.getSize();
Instruction condition = fInstructions.getInstruction(conditionAddress);
// add the conditionnalJump
ConditionalJump conditionalJump = new ConditionalJump(false);
fInstructions.insert(conditionalJump, conditionAddress + 1);
// add the jump
Jump jump = new Jump();
fInstructions.add(jump);
// set jump offsets
conditionalJump.setOffset(body.getSize() + 1);
jump.setOffset(-(condition.getSize() + body.getSize() + 2));
// for each pending break or continue instruction which are related to
// this loop, set the offset of the corresponding jump.
for (Iterator<CompleteInstruction> iter = fCompleteInstructions.iterator(); iter.hasNext();) {
CompleteInstruction instruction = iter.next();
Jump jumpInstruction = instruction.fInstruction;
int instructionAddress = fInstructions.indexOf(jumpInstruction);
if (instructionAddress > conditionAddress
&& (instruction.fLabel == null || instruction.fLabel
.equals(label))) {
iter.remove();
if (instruction.fIsBreak) {
// jump to the instruction after the last jump
jumpInstruction
.setOffset((bodyAddress - instructionAddress) + 2);
} else {
// jump to the first instruction of the condition
jumpInstruction.setOffset((conditionAddress - condition
.getSize()) - instructionAddress);
}
}
}
fCounter += 2;
storeInstruction();
}
/*
* Visit methods
*
* There are two variations of node visiting: <ol> <li>Push the instruction
* corresponding to the node onto the stack and return <code>true</code> to
* visit the children of the node.</li> <li>Push the instruction
* corresponding to the node onto the stack and visit the children of the
* node manually (return <code>false</code> to avoid the default child
* visiting implementation).</li> </ol>
*/
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.
* AnnotationTypeDeclaration)
*/
@Override
public boolean visit(AnnotationTypeDeclaration node) {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.
* AnnotationTypeMemberDeclaration)
*/
@Override
public boolean visit(AnnotationTypeMemberDeclaration node) {
return false;
}
/**
* @see ASTVisitor#visit(AnonymousClassDeclaration)
*/
@Override
public boolean visit(AnonymousClassDeclaration node) {
if (!isActive()) {
return true;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Anonymous_type_declaration_cannot_be_used_in_an_evaluation_expression_2);
return false;
}
/**
* @see ASTVisitor#visit(ArrayAccess)
*/
@Override
public boolean visit(ArrayAccess node) {
if (!isActive()) {
return false;
}
push(new org.eclipse.jdt.internal.debug.eval.ast.instructions.ArrayAccess(
fCounter));
return true;
}
/**
* @see ASTVisitor#visit(ArrayCreation)
*/
@Override
public boolean visit(ArrayCreation node) {
if (!isActive()) {
return false;
}
ArrayType arrayType = node.getType();
ITypeBinding binding = resolveTypeBinding(arrayType);
if (binding != null && isALocalType(binding.getElementType())) {
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Local_type_array_instance_creation_cannot_be_used_in_an_evaluation_expression_29);
setHasError(true);
return false;
}
push(new ArrayAllocation(arrayType.getDimensions(), node.dimensions()
.size(), node.getInitializer() != null, fCounter));
return true;
}
/**
* @see ASTVisitor#visit(ArrayInitializer)
*/
@Override
public boolean visit(ArrayInitializer node) {
if (!isActive()) {
return false;
}
ITypeBinding typeBinding = resolveTypeBinding(node);
if (typeBinding != null) {
int dimension = typeBinding.getDimensions();
String signature = getTypeSignature(typeBinding.getElementType());
push(new ArrayInitializerInstruction(signature, node.expressions()
.size(), dimension, fCounter));
}
return true;
}
/**
* @see ASTVisitor#visit(ArrayType)
*/
@Override
public boolean visit(ArrayType node) {
if (!isActive()) {
return false;
}
ITypeBinding arrayTypeBinding = resolveTypeBinding(node);
if (arrayTypeBinding != null) {
int dimension = arrayTypeBinding.getDimensions();
String signature = getTypeSignature(arrayTypeBinding
.getElementType());
push(new PushArrayType(signature, dimension, fCounter));
}
return false;
}
/**
* @see ASTVisitor#visit(AssertStatement)
*/
@Override
public boolean visit(AssertStatement node) {
if (!isActive()) {
return false;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Assert_statement_cannot_be_used_in_an_evaluation_expression_3);
return false;
}
/**
* @see ASTVisitor#visit(Assignment)
*/
@Override
public boolean visit(Assignment node) {
if (!isActive()) {
return false;
}
Expression leftHandSide = node.getLeftHandSide();
Expression rightHandSide = node.getRightHandSide();
int variableTypeId = getTypeId(leftHandSide);
int valueTypeId = getTypeId(rightHandSide);
String opToken = node.getOperator().toString();
int opTokenLength = opToken.length();
char char0 = opToken.charAt(0);
char char2 = '\0';
if (opTokenLength > 2) {
char2 = opToken.charAt(2);
}
ITypeBinding rightBinding = resolveTypeBinding(rightHandSide);
if (rightBinding == null) {
return false;
}
ITypeBinding leftBinding = resolveTypeBinding(leftHandSide);
if (leftBinding == null) {
return false;
}
if (variableTypeId == Instruction.T_Object) {
// If the variable is an object, the value may need to be boxed for
// the simple assignment.
// For the compound assignment operators, the value of the variable
// have to be un-boxed before the operation is done, then re-boxed
// to
// to be stored in the variable.
int unboxedVariableTypeId = getUnBoxedTypeId(leftHandSide);
int unboxedValueTypeId = getUnBoxedTypeId(rightHandSide);
int unboxedResultTypeId = Instruction.getBinaryPromotionType(
unboxedVariableTypeId, unboxedValueTypeId);
push(new AssignmentOperator(variableTypeId, variableTypeId,
fCounter));
leftHandSide.accept(this);
if (char0 == '=') {
boolean storeRequired = false;
if (rightBinding.isPrimitive()) {
boxing(leftBinding, rightBinding);
storeRequired = true;
}
rightHandSide.accept(this);
if (storeRequired) {
storeInstruction(); // boxing
}
} else {
boolean unrecognized = false;
boxing(leftBinding, rightBinding);
switch (char0) {
case '=': // equal
break;
case '+': // plus equal
push(new PlusOperator(unboxedVariableTypeId,
unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '-': // minus equal
push(new MinusOperator(unboxedVariableTypeId,
unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '*': // multiply equal
push(new MultiplyOperator(unboxedVariableTypeId,
unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '/': // divide equal
push(new DivideOperator(unboxedVariableTypeId,
unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '%': // remainder equal
push(new RemainderOperator(unboxedVariableTypeId,
unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '^': // XOr equal
push(new XorOperator(unboxedVariableTypeId,
unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '|': // or equal
push(new OrOperator(unboxedVariableTypeId,
unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '&': // and equal
push(new AndOperator(unboxedVariableTypeId,
unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '<': // left shift equal
push(new LeftShiftOperator(unboxedVariableTypeId,
unboxedValueTypeId, unboxedResultTypeId, fCounter));
break;
case '>': // right shift equal or unsigned right shift equal
switch (char2) {
case '=': // right shift equal
push(new RightShiftOperator(unboxedVariableTypeId,
unboxedValueTypeId, unboxedResultTypeId,
fCounter));
break;
case '>': // unsigned right shift equal
push(new UnsignedRightShiftOperator(
unboxedVariableTypeId, unboxedValueTypeId,
unboxedResultTypeId, fCounter));
break;
default:
unrecognized = true;
break;
}
break;
default:
unrecognized = true;
break;
}
if (unrecognized) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Unrecognized_assignment_operator____4
+ opToken);
return false;
}
unBoxing(leftBinding);
push(new Dup());
storeInstruction(); // dupe
storeInstruction(); // un-boxing
boolean storeRequired = unBoxing(rightBinding);
rightHandSide.accept(this);
if (storeRequired) {
storeInstruction(); // un-boxing
}
storeInstruction(); // operation
storeInstruction(); // boxing
}
} else {
boolean unrecognized = false;
switch (char0) {
case '=': // equal
push(new AssignmentOperator(variableTypeId, valueTypeId,
fCounter));
break;
case '+': // plus equal
push(new PlusAssignmentOperator(variableTypeId, valueTypeId,
fCounter));
break;
case '-': // minus equal
push(new MinusAssignmentOperator(variableTypeId, valueTypeId,
fCounter));
break;
case '*': // multiply equal
push(new MultiplyAssignmentOperator(variableTypeId,
valueTypeId, fCounter));
break;
case '/': // divide equal
push(new DivideAssignmentOperator(variableTypeId, valueTypeId,
fCounter));
break;
case '%': // remainder equal
push(new RemainderAssignmentOperator(variableTypeId,
valueTypeId, fCounter));
break;
case '^': // XOr equal
push(new XorAssignmentOperator(variableTypeId, valueTypeId,
fCounter));
break;
case '|': // or equal
push(new OrAssignmentOperator(variableTypeId, valueTypeId,
fCounter));
break;
case '&': // and equal
push(new AndAssignmentOperator(variableTypeId, valueTypeId,
fCounter));
break;
case '<': // left shift equal
push(new LeftShiftAssignmentOperator(variableTypeId,
valueTypeId, fCounter));
break;
case '>': // right shift equal or unsigned right shift equal
switch (char2) {
case '=': // right shift equal
push(new RightShiftAssignmentOperator(variableTypeId,
valueTypeId, fCounter));
break;
case '>': // unsigned right shift equal
push(new UnsignedRightShiftAssignmentOperator(
variableTypeId, valueTypeId, fCounter));
break;
default:
unrecognized = true;
break;
}
break;
default:
unrecognized = true;
break;
}
if (unrecognized) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Unrecognized_assignment_operator____4
+ opToken);
return false;
}
leftHandSide.accept(this);
boolean storeRequired = unBoxing(rightBinding);
rightHandSide.accept(this);
if (storeRequired) {
storeInstruction();
}
}
return false;
}
/**
* @see ASTVisitor#visit(Block)
*/
@Override
public boolean visit(Block node) {
int start = node.getStartPosition();
if (start == fStartPosition || start == (fStartPosition + 1)) {
setActive(true);
}
if (!isActive()) {
return true;
}
push(new NoOp(fCounter));
return true;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.
* BlockComment)
*/
@Override
public boolean visit(BlockComment node) {
return false;
}
/**
* @see ASTVisitor#visit(BooleanLiteral)
*/
@Override
public boolean visit(BooleanLiteral node) {
if (!isActive()) {
return false;
}
push(new PushBoolean(node.booleanValue()));
return true;
}
/**
* @see ASTVisitor#visit(BreakStatement)
*/
@Override
public boolean visit(BreakStatement node) {
if (!isActive()) {
return false;
}
// create the equivalent jump instruction in the instruction
// and add an element in the list of pending break and continue
// instructions
Jump instruction = new Jump();
SimpleName labelName = node.getLabel();
String label = null;
if (labelName != null) {
label = labelName.getIdentifier();
}
push(instruction);
fCompleteInstructions.add(new CompleteInstruction(instruction, label,
true));
return false;
}
/**
* @see ASTVisitor#visit(CastExpression)
*/
@Override
public boolean visit(CastExpression node) {
if (!isActive()) {
return false;
}
Type type = node.getType();
int typeId = getTypeId(type);
ITypeBinding typeBinding = resolveTypeBinding(type);
if (typeBinding != null) {
String baseTypeSignature;
int dimension = typeBinding.getDimensions();
if (typeBinding.isArray()) {
typeBinding = typeBinding.getElementType();
}
baseTypeSignature = getTypeName(typeBinding);
push(new Cast(typeId, baseTypeSignature, dimension, fCounter));
node.getExpression().accept(this);
}
return false;
}
/**
* @see ASTVisitor#visit(CatchClause)
*/
@Override
public boolean visit(CatchClause node) {
if (!isActive()) {
return false;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Catch_clause_cannot_be_used_in_an_evaluation_expression_6);
return false;
}
/**
* @see ASTVisitor#visit(CharacterLiteral)
*/
@Override
public boolean visit(CharacterLiteral node) {
if (!isActive()) {
return false;
}
push(new PushChar(node.charValue()));
return true;
}
/**
* return false, visit expression, type name & arguments, don't visit body
* declaration
*
* @see ASTVisitor#visit(ClassInstanceCreation)
*/
@Override
public boolean visit(ClassInstanceCreation node) {
if (!isActive()) {
return true;
}
if (node.getAnonymousClassDeclaration() != null) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Anonymous_type_declaration_cannot_be_used_in_an_evaluation_expression_7);
}
IMethodBinding methodBinding = node.resolveConstructorBinding();
if (methodBinding == null) {
setHasError(true);
addErrorMessage(MessageFormat.format(
EvaluationEngineMessages.ASTInstructionCompiler_1,
new Object[] { node.toString() }));
return false;
}
ITypeBinding typeBinding = methodBinding.getDeclaringClass();
boolean isInstanceMemberType = typeBinding.isMember()
&& !Modifier.isStatic(typeBinding.getModifiers());
if (isALocalType(typeBinding)) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Constructor_of_a_local_type_cannot_be_used_in_an_evaluation_expression_8);
}
if (containsALocalType(methodBinding)) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Constructor_which_contains_a_local_type_as_parameter_cannot_be_used_in_an_evaluation_expression_30);
}
if (hasErrors()) {
return false;
}
int paramCount = methodBinding.getParameterTypes().length;
String enclosingTypeSignature = null;
ITypeBinding enclosingTypeBinding = null;
if (isInstanceMemberType) {
enclosingTypeBinding = typeBinding.getDeclaringClass();
if (enclosingTypeBinding == null) {
setHasError(true);
addErrorMessage(MessageFormat.format(
EvaluationEngineMessages.ASTInstructionCompiler_2,
new Object[] { typeBinding.getQualifiedName() }));
return false;
}
enclosingTypeSignature = getTypeSignature(enclosingTypeBinding);
paramCount++;
}
String signature = getMethodSignature(methodBinding,
enclosingTypeSignature).replace('.', '/');
push(new Constructor(signature, paramCount, fCounter));
push(new PushType(getTypeName(typeBinding)));
storeInstruction();
if (isInstanceMemberType) {
Expression optionalExpression = node.getExpression();
if (optionalExpression != null) {
optionalExpression.accept(this);
} else {
// for a non-static inner class, check if we are not in a static
// context (method)
ASTNode parent = node;
do {
parent = parent.getParent();
} while (!(parent instanceof MethodDeclaration));
if (Modifier.isStatic(((MethodDeclaration) parent)
.getModifiers())) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Must_explicitly_qualify_the_allocation_with_an_instance_of_the_enclosing_type_33);
return false;
}
push(new PushThis(getEnclosingLevel(node, enclosingTypeBinding)));
storeInstruction();
}
}
List<Expression> arguments = node.arguments();
pushMethodArguments(methodBinding, arguments);
return false;
}
/**
* @see ASTVisitor#visit(CompilationUnit)
*/
@Override
public boolean visit(CompilationUnit node) {
return true;
}
/**
* @see ASTVisitor#visit(ConditionalExpression)
*/
@Override
public boolean visit(ConditionalExpression node) {
if (!isActive()) {
return true;
}
push(new NoOp(fCounter));
return true;
}
/**
* @see ASTVisitor#visit(ConstructorInvocation)
*/
@Override
public boolean visit(ConstructorInvocation node) {
if (!isActive()) {
return false;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_this_constructor_invocation_cannot_be_used_in_an_evaluation_expression_9);
return false;
}
/**
* @see ASTVisitor#visit(ContinueStatement)
*/
@Override
public boolean visit(ContinueStatement node) {
if (!isActive()) {
return false;
}
// create the equivalent jump instruction in the instruction
// and add an element in the list of pending break and continue
// instructions
Jump instruction = new Jump();
SimpleName labelName = node.getLabel();
String label = null;
if (labelName != null) {
label = labelName.getIdentifier();
}
push(instruction);
fCompleteInstructions.add(new CompleteInstruction(instruction, label,
false));
return false;
}
/**
* @see ASTVisitor#visit(CreationReference)
*/
@Override
public boolean visit(CreationReference node) {
if (!isActive()) {
return true;
}
try {
RemoteEvaluatorBuilder builder = makeBuilder(node);
builder.acceptMethodReference(node, node.resolveTypeBinding());
RemoteEvaluator remoteEvaluator = builder.build();
push(new RemoteOperator(builder.getSnippet(), node.getStartPosition(), remoteEvaluator));
storeInstruction();
} catch (JavaModelException | DebugException e) {
addErrorMessage(e.getMessage());
setHasError(true);
}
return false;
}
/**
* @see ASTVisitor#visit(DoStatement)
*/
@Override
public boolean visit(DoStatement node) {
if (!isActive()) {
return false;
}
push(new NoOp(fCounter));
return true;
}
/**
* @see ASTVisitor#visit(EmptyStatement)
*/
@Override
public boolean visit(EmptyStatement node) {
if (!isActive()) {
return false;
}
push(new NoOp(fCounter));
return true;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.
* EnhancedForStatement)
*/
@Override
public boolean visit(EnhancedForStatement node) {
if (!isActive()) {
return false;
}
push(new NoOp(fCounter));
ITypeBinding typeBinding = resolveTypeBinding(node.getExpression());
if (typeBinding == null) {
return false;
}
Type paramType = node.getParameter().getType();
ITypeBinding paramBinding = resolveTypeBinding(paramType);
if (paramBinding == null) {
return false;
}
String typeSignature = getTypeSignature(paramBinding);
int paramTypeId = getTypeId(paramType);
boolean isParamPrimitiveType = paramTypeId != Instruction.T_Object
&& paramTypeId != Instruction.T_String;
String paramIdentifier = node.getParameter().getName().getIdentifier();
if (typeBinding.isArray()) {
// the expression returns an array
int idIndex = fUniqueIdIndex++;
String arrayIdentifier = "#a" + idIndex; //$NON-NLS-1$
String varIdentifier = "#i" + idIndex; //$NON-NLS-1$
push(new LocalVariableCreation(arrayIdentifier, typeSignature, 1,
isParamPrimitiveType, true, fCounter));
node.getExpression().accept(this);
storeInstruction();
push(new LocalVariableCreation(varIdentifier,
"I", 0, true, true, fCounter)); //$NON-NLS-1$
push(new PushInt(0));
storeInstruction();
storeInstruction();
push(new LocalVariableCreation(paramIdentifier, typeSignature, 0,
isParamPrimitiveType, false, fCounter));
storeInstruction();
push(new LessOperator(Instruction.T_int, Instruction.T_int,
fCounter));
push(new PushLocalVariable(varIdentifier));
storeInstruction();
push(new PushArrayLength(fCounter));
push(new PushLocalVariable(arrayIdentifier));
storeInstruction();
storeInstruction();
storeInstruction();
// conditional jump will be added here
push(new NoOp(fCounter));
push(new AssignmentOperator(paramTypeId, paramTypeId, fCounter));
push(new PushLocalVariable(paramIdentifier));
storeInstruction();
push(new org.eclipse.jdt.internal.debug.eval.ast.instructions.ArrayAccess(
fCounter));
push(new PushLocalVariable(arrayIdentifier));
storeInstruction();
push(new PostfixPlusPlusOperator(Instruction.T_int, fCounter));
push(new PushLocalVariable(varIdentifier));
storeInstruction();
storeInstruction();
storeInstruction();
if (checkAutoBoxing(typeBinding.getElementType(), paramBinding)) {
storeInstruction();
}
storeInstruction();
addPopInstruction();
node.getBody().accept(this);
storeInstruction();
// jump will be added here
} else {
// the expression returns a collection
String iteratorIdentifier = "#i" + fUniqueIdIndex++; //$NON-NLS-1$
push(new LocalVariableCreation(iteratorIdentifier,
"Ljava/util/Iterator;", 0, false, true, fCounter)); //$NON-NLS-1$
push(new SendMessage(
"iterator", "()Ljava/util/Iterator;", 0, null, fCounter)); //$NON-NLS-1$//$NON-NLS-2$
node.getExpression().accept(this);
storeInstruction();
storeInstruction();
push(new LocalVariableCreation(paramIdentifier, typeSignature, 0,
isParamPrimitiveType, false, fCounter));
storeInstruction();
push(new SendMessage("hasNext", "()Z", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
push(new PushLocalVariable(iteratorIdentifier));
storeInstruction();
storeInstruction();
// conditional jump will be added here
push(new NoOp(fCounter));
push(new AssignmentOperator(paramTypeId, paramTypeId, fCounter));
push(new PushLocalVariable(paramIdentifier));
storeInstruction();
push(new SendMessage(
"next", "()Ljava/lang/Object;", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
push(new PushLocalVariable(iteratorIdentifier));
storeInstruction();
storeInstruction();
ITypeBinding[] typeArguments = typeBinding.getTypeArguments();
if (typeArguments != null && typeArguments.length > 0) {
if (checkAutoBoxing(typeArguments[0], paramBinding)) {
storeInstruction();
}
}
storeInstruction();
addPopInstruction();
node.getBody().accept(this);
storeInstruction();
// jump will be added here
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.
* EnumConstantDeclaration)
*/
@Override
public boolean visit(EnumConstantDeclaration node) {
if (!isActive()) {
return true;
}
// nothing to do, we shouldn't hit this node
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.
* EnumDeclaration)
*/
@Override
public boolean visit(EnumDeclaration node) {
if (!isActive()) {
return true;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_0);
return false;
}
/**
* @see ASTVisitor#visit(ExpressionMethodReference)
*/
@Override
public boolean visit(ExpressionMethodReference node) {
if (!isActive()) {
return true;
}
try {
RemoteEvaluatorBuilder builder = makeBuilder(node);
builder.acceptMethodReference(node, node.resolveTypeBinding());
RemoteEvaluator remoteEvaluator = builder.build();
push(new RemoteOperator(builder.getSnippet(), node.getStartPosition(), remoteEvaluator));
storeInstruction();
} catch (JavaModelException | DebugException e) {
addErrorMessage(e.getMessage());
setHasError(true);
}
return false;
}
private RemoteEvaluatorBuilder makeBuilder(ASTNode node) throws DebugException {
RemoteEvaluatorBuilder builder = new RemoteEvaluatorBuilder(fJavaProject, new ExpressionBinder() {
@Override
public void bind(IVariableBinding variableBinding, String asVariableName) {
String variableId = variableBinding.getName();
push(new PushLocalVariable(variableId));
storeInstruction();
}
@Override
public void bindThis(ITypeBinding typeBinding, String asVariableName) {
push(new PushThis(getEnclosingLevel(node, typeBinding)));
storeInstruction();
}
}, getEnclosingClass(node), isStaticContext(node), false);
return builder;
}
private ITypeBinding getEnclosingClass(ASTNode node) {
while (node != null) {
if (node instanceof MethodDeclaration) {
return ((MethodDeclaration) node).resolveBinding().getDeclaringClass();
}
if (node instanceof TypeDeclaration) {
return ((TypeDeclaration) node).resolveBinding();
}
node = node.getParent();
}
return null;
}
private boolean isStaticContext(ASTNode node) {
while (node != null) {
if (node instanceof MethodDeclaration) {
return Modifier.isStatic(((MethodDeclaration) node).getModifiers());
} else if (node instanceof Initializer) {
return Modifier.isStatic(((Initializer) node).getModifiers());
}
node = node.getParent();
}
return false;
}
/**
* @see ASTVisitor#visit(ExpressionStatement)
*/
@Override
public boolean visit(ExpressionStatement node) {
return true;
}
/**
* return false, visit expression, don't visit name
*
* @see ASTVisitor#visit(FieldAccess)
*/
@Override
public boolean visit(FieldAccess node) {
if (!isActive()) {
return false;
}
SimpleName fieldName = node.getName();
IVariableBinding fieldBinding = (IVariableBinding) fieldName
.resolveBinding();
if (fieldBinding != null) {
ITypeBinding declaringTypeBinding = fieldBinding
.getDeclaringClass();
Expression expression = node.getExpression();
String fieldId = fieldName.getIdentifier();
if (Modifier.isStatic(fieldBinding.getModifiers())) {
push(new PushStaticFieldVariable(fieldId,
getTypeName(declaringTypeBinding), fCounter));
expression.accept(this);
addPopInstruction();
} else {
if (declaringTypeBinding == null) { // it is a field without
// declaring type => it is
// the special length array
// field
push(new PushArrayLength(fCounter));
} else {
if (isALocalType(declaringTypeBinding)) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Qualified_local_type_field_access_cannot_be_used_in_an_evaluation_expression_31);
return false;
}
push(new PushFieldVariable(fieldId,
getTypeSignature(declaringTypeBinding), fCounter));
}
expression.accept(this);
}
}
return false;
}
/**
* @see ASTVisitor#visit(FieldDeclaration)
*/
@Override
public boolean visit(FieldDeclaration node) {
return true;
}
/**
* @see ASTVisitor#visit(ForStatement) return <code>false</code>, don't use
* the standard accept order. order used for visiting children :
* initializers, condition, body, updaters
*/
@Override
public boolean visit(ForStatement node) {
if (!isActive()) {
return false;
}
push(new NoOp(fCounter));
push(new NoOp(fCounter));
for (Iterator<Expression> iter = node.initializers().iterator(); iter.hasNext();) {
Expression expr = iter.next();
expr.accept(this);
addPopInstructionIfNeeded(expr);
}
storeInstruction();
Expression condition = node.getExpression();
if (condition != null) {
condition.accept(this);
}
node.getBody().accept(this);
push(new NoOp(fCounter));
for (Iterator<Expression> iter = node.updaters().iterator(); iter.hasNext();) {
Expression expr = iter.next();
expr.accept(this);
addPopInstructionIfNeeded(expr);
}
storeInstruction();
return false;
}
/**
* @see ASTVisitor#visit(IfStatement)
*/
@Override
public boolean visit(IfStatement node) {
if (!isActive()) {
return false;
}
push(new NoOp(fCounter));
return true;
}
/**
* @see ASTVisitor#visit(ImportDeclaration)
*/
@Override
public boolean visit(ImportDeclaration node) {
return false;
}
/**
* return <code>false</code>, don't use the standard accept order.
*
* @see ASTVisitor#visit(InfixExpression)
*/
@Override
public boolean visit(InfixExpression node) {
if (!isActive()) {
return false;
}
String opToken = node.getOperator().toString();
int opTokenLength = opToken.length();
char char0 = opToken.charAt(0);
char char1 = '\0';
char char2 = '\0';
if (opTokenLength > 1) {
char1 = opToken.charAt(1);
if (opTokenLength > 2) {
char2 = opToken.charAt(2);
}
}
List<Expression> extendedOperands = node.extendedOperands();
int operatorNumber = extendedOperands.size() + 1;
int[][] types = new int[operatorNumber][3];
Iterator<Expression> iterator = extendedOperands.iterator();
Expression leftOperand = node.getLeftOperand();
Expression rightOperand = node.getRightOperand();
int leftTypeId;
int rightTypeId;
boolean unbox = false;
// for == and != un-box when at least operand is primitive (otherwise
// compare the objects)
ITypeBinding leftBinding = resolveTypeBinding(leftOperand);
if (leftBinding == null) {
return false;
}
ITypeBinding rightBinding = resolveTypeBinding(rightOperand);
if (rightBinding == null) {
return false;
}
if ((char0 == '=' || char0 == '!') && char1 == '=') {
unbox = leftBinding.isPrimitive() || rightBinding.isPrimitive();
} else {
unbox = true;
}
if (unbox) {
leftTypeId = getUnBoxedTypeId(leftOperand);
rightTypeId = getUnBoxedTypeId(rightOperand);
} else {
leftTypeId = getTypeId(leftOperand);
rightTypeId = getTypeId(rightOperand);
}
int resultTypeId = Instruction.getBinaryPromotionType(leftTypeId,
rightTypeId);
types[0][0] = resultTypeId;
types[0][1] = leftTypeId;
types[0][2] = rightTypeId;
for (int i = 1; i < operatorNumber; i++) {
Expression operand = iterator.next();
leftTypeId = resultTypeId;
rightTypeId = getUnBoxedTypeId(operand);
resultTypeId = Instruction.getBinaryPromotionType(leftTypeId,
rightTypeId);
types[i][0] = resultTypeId;
types[i][1] = leftTypeId;
types[i][2] = rightTypeId;
}
boolean unrecognized = false;
switch (char0) {
case '*': // multiply
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new MultiplyOperator(types[i][0], types[i][1],
types[i][2], fCounter));
}
break;
case '/': // divide
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new DivideOperator(types[i][0], types[i][1], types[i][2],
fCounter));
}
break;
case '%': // remainder
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new RemainderOperator(types[i][0], types[i][1],
types[i][2], fCounter));
}
break;
case '+': // plus
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new PlusOperator(types[i][0], types[i][1], types[i][2],
fCounter));
}
break;
case '-': // minus
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new MinusOperator(types[i][0], types[i][1], types[i][2],
fCounter));
}
break;
case '<': // left shift or less or less equal
switch (char1) {
case '\0': // less
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new LessOperator(types[i][1], types[i][2], fCounter));
}
break;
case '<': // left shift
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new LeftShiftOperator(
Instruction.getUnaryPromotionType(types[i][1]),
types[i][1], types[i][2], fCounter));
}
break;
case '=': // less equal
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new LessEqualOperator(types[i][1], types[i][2],
fCounter));
}
break;
default:
unrecognized = true;
break;
}
break;
case '>': // right shift or unsigned right shift or greater or greater
// equal
switch (char1) {
case '\0': // greater
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new GreaterOperator(types[i][1], types[i][2], fCounter));
}
break;
case '>': // right shift or unsigned right shift
switch (char2) {
case '\0': // right shift
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new RightShiftOperator(
Instruction.getUnaryPromotionType(types[i][1]),
types[i][1], types[i][2], fCounter));
}
break;
case '>': // unsigned right shift
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new UnsignedRightShiftOperator(
Instruction.getUnaryPromotionType(types[i][1]),
types[i][1], types[i][2], fCounter));
}
break;
}
break;
case '=': // greater equal
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new GreaterEqualOperator(types[i][1], types[i][2],
fCounter));
}
break;
default:
unrecognized = true;
break;
}
break;
case '=': // equal equal
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new EqualEqualOperator(types[i][1], types[i][2], true,
fCounter));
}
break;
case '!': // not equal
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new EqualEqualOperator(types[i][1], types[i][2], false,
fCounter));
}
break;
case '^': // XOr
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new XorOperator(types[i][0], types[i][1], types[i][2],
fCounter));
}
break;
case '|': // or or or or
switch (char1) {
case '\0': // or
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new OrOperator(types[i][0], types[i][1], types[i][2],
fCounter));
}
break;
case '|': // or or
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new NoOp(fCounter));
}
break;
default:
unrecognized = true;
break;
}
break;
case '&': // and or and and
switch (char1) {
case '\0': // and
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new AndOperator(types[i][0], types[i][1], types[i][2],
fCounter));
}
break;
case '&': // and and
for (int i = operatorNumber - 1; i >= 0; i--) {
push(new NoOp(fCounter));
}
break;
default:
unrecognized = true;
break;
}
break;
default:
unrecognized = true;
break;
}
if (unrecognized) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Unrecognized_infix_operator____13
+ opToken);
}
if (hasErrors()) {
return false;
}
iterator = extendedOperands.iterator();
if ((char0 == '&' && char1 == '&') || (char0 == '|' && char1 == '|')) {
boolean isOrOr = char0 == '|';
ConditionalJump[] conditionalJumps = new ConditionalJump[operatorNumber];
int[] conditionalJumpAddresses = new int[operatorNumber];
boolean storeRequired = unBoxing(leftBinding);
leftOperand.accept(this);
if (storeRequired) {
storeInstruction();
}
ConditionalJump conditionalJump = new ConditionalJump(isOrOr);
conditionalJumps[0] = conditionalJump;
conditionalJumpAddresses[0] = fCounter;
push(conditionalJump);
storeInstruction();
storeRequired = unBoxing(rightBinding);
rightOperand.accept(this);
if (storeRequired) {
storeInstruction();
}
for (int i = 1; i < operatorNumber; i++) {
conditionalJump = new ConditionalJump(isOrOr);
conditionalJumps[i] = conditionalJump;
conditionalJumpAddresses[i] = fCounter;
push(conditionalJump);
storeInstruction();
Expression operand = iterator.next();
ITypeBinding typeBinding = resolveTypeBinding(operand);
if (typeBinding == null) {
return false;
}
storeRequired = unBoxing(typeBinding);
operand.accept(this);
if (storeRequired) {
storeInstruction();
}
}
Jump jump = new Jump();
jump.setOffset(1);
push(jump);
storeInstruction();
for (int i = 0; i < operatorNumber; i++) {
conditionalJumps[i].setOffset(fCounter
- conditionalJumpAddresses[i] - 1);
}
push(new PushBoolean(isOrOr));
storeInstruction();
// store the no-op
storeInstruction();
} else { // other operators
boolean storeRequired = false;
if (unbox) {
storeRequired = unBoxing(leftBinding);
}
leftOperand.accept(this);
if (storeRequired) {
storeInstruction();
}
if (unbox) {
storeRequired = unBoxing(rightBinding);
}
rightOperand.accept(this);
if (storeRequired) {
storeInstruction();
}
storeInstruction();
for (int i = 1; i < operatorNumber; i++) {
Expression operand = iterator.next();
if (unbox) {
ITypeBinding typeBinding = resolveTypeBinding(operand);
if (typeBinding == null) {
return false;
}
storeRequired = unBoxing(typeBinding);
}
operand.accept(this);
if (storeRequired) {
storeInstruction();
}
storeInstruction();
}
}
return false;
}
/**
* @see ASTVisitor#visit(Initializer)
*/
@Override
public boolean visit(Initializer node) {
return true;
}
/**
* @see ASTVisitor#visit(InstanceofExpression)
*/
@Override
public boolean visit(InstanceofExpression node) {
if (!isActive()) {
return false;
}
push(new InstanceOfOperator(fCounter));
return true;
}
/**
* @see ASTVisitor#visit(Javadoc)
*/
@Override
public boolean visit(Javadoc node) {
return false;
}
/**
* @see ASTVisitor#visit(LabeledStatement) return <code>false</code>, don't
* use the standard accept order.
*/
@Override
public boolean visit(LabeledStatement node) {
node.getBody().accept(this);
return false;
}
/**
* @see ASTVisitor#visit(LambdaExpression)
*/
@Override
public boolean visit(LambdaExpression node) {
if (!isActive()) {
return true;
}
try {
RemoteEvaluatorBuilder builder = makeBuilder(node);
builder.acceptLambda(node, node.resolveTypeBinding());
RemoteEvaluator remoteEvaluator = builder.build();
push(new RemoteOperator(builder.getSnippet(), node.getStartPosition(), remoteEvaluator));
storeInstruction();
} catch (JavaModelException | DebugException e) {
addErrorMessage(e.getMessage());
setHasError(true);
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.
* LineComment)
*/
@Override
public boolean visit(LineComment node) {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.
* MarkerAnnotation)
*/
@Override
public boolean visit(MarkerAnnotation node) {
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MemberRef
* )
*/
@Override
public boolean visit(MemberRef node) {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.
* MemberValuePair)
*/
@Override
public boolean visit(MemberValuePair node) {
return false;
}
/**
* @see ASTVisitor#visit(MethodDeclaration)
*/
@Override
public boolean visit(MethodDeclaration node) {
int start = node.getStartPosition();
int end = start + node.getLength();
if (start < fStartPosition && end > fStartPosition) {
return true;
}
return false;
}
/**
* return false, don't visit name, visit expression & arguments
*
* @see ASTVisitor#visit(MethodInvocation)
*/
@Override
public boolean visit(MethodInvocation node) {
if (!isActive()) {
return false;
}
IMethodBinding methodBinding = (IMethodBinding) node.getName().resolveBinding();
if (methodBinding == null) {
// could be the receiver is not visible - for example a private
// field access from super class
ASTNode root = node.getRoot();
if (root instanceof CompilationUnit) {
CompilationUnit cu = (CompilationUnit) root;
IProblem[] problems = cu.getProblems();
for (IProblem problem : problems) {
setHasError(true);
addErrorMessage(problem.getMessage());
}
}
}
if (hasErrors()) {
return false;
}
if (containsALocalType(methodBinding)) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Method_which_contains_a_local_type_as_parameter_cannot_be_used_in_an_evaluation_expression_32);
return false;
}
int paramCount = methodBinding.getParameterTypes().length;
String selector = methodBinding.getName();
String signature = getMethodSignature(methodBinding, null).replace('.',
'/');
boolean isStatic = Flags.isStatic(methodBinding.getModifiers());
Expression expression = node.getExpression();
if (isStatic) {
String typeName = getTypeName(methodBinding.getDeclaringClass());
push(new SendStaticMessage(typeName, selector, signature,
paramCount, fCounter));
if (expression != null) {
node.getExpression().accept(this);
addPopInstruction();
}
} else {
push(new SendMessage(selector, signature, paramCount, null,
fCounter));
if (expression == null) {
push(new PushThis(getEnclosingLevel(node,
methodBinding.getDeclaringClass())));
storeInstruction();
} else {
node.getExpression().accept(this);
}
}
List<Expression> arguments = node.arguments();
pushMethodArguments(methodBinding, arguments);
return false;
}
/**
* Pushes method arguments onto the stack for a method or constructor
* invocation taking variable arguments and auto-boxing into consideration.
*
* @param methodBinding
* method or constructor being called
* @param arguments
* argument list
*/
private void pushMethodArguments(IMethodBinding methodBinding, List<Expression> arguments) {
int argCount = arguments.size();
ITypeBinding[] parameterTypes = methodBinding.getParameterTypes();
int paramCount = parameterTypes.length;
ITypeBinding lastArgBinding = null;
if (methodBinding.isVarargs()) {
Expression lastArg = arguments.get(argCount - 1);
lastArgBinding = resolveTypeBinding(lastArg);
if (lastArgBinding == null) {
return;
}
}
if (methodBinding.isVarargs() &&
!(paramCount == argCount &&
parameterTypes[paramCount - 1].getDimensions() == lastArgBinding.getDimensions())) {
// if this method is a varargs, and if the method is invoked using
// the varargs syntax
// (multiple arguments) and not an array
Iterator<Expression> iterator = arguments.iterator();
// process the first arguments (no part of the variable argument)
for (int i = 0; i < paramCount - 1; i++) {
Expression argument = iterator.next();
boolean storeRequired = checkAutoBoxing(
argument.resolveTypeBinding(), parameterTypes[i]);
argument.accept(this);
if (storeRequired) {
storeInstruction();
}
}
// create a array of the remainder arguments
ITypeBinding varargsParameterType = parameterTypes[paramCount - 1];
ITypeBinding varargsElementType = varargsParameterType
.getElementType();
push(new ArrayInitializerInstruction(
getTypeSignature(varargsElementType), argCount - paramCount
+ 1, varargsParameterType.getDimensions(), fCounter));
while (iterator.hasNext()) {
Expression argument = iterator.next();
boolean storeRequired = checkAutoBoxing(
argument.resolveTypeBinding(), varargsElementType);
argument.accept(this);
if (storeRequired) {
storeInstruction();
}
}
storeInstruction();
} else {
Iterator<Expression> iterator = arguments.iterator();
int i = 0;
while (iterator.hasNext()) {
Expression argument = iterator.next();
boolean storeRequired = checkAutoBoxing(
argument.resolveTypeBinding(), parameterTypes[i++]);
argument.accept(this);
if (storeRequired) {
storeInstruction();
}
}
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodRef
* )
*/
@Override
public boolean visit(MethodRef node) {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.
* MethodRefParameter)
*/
@Override
public boolean visit(MethodRefParameter node) {
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Modifier
* )
*/
@Override
public boolean visit(Modifier node) {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.
* NormalAnnotation)
*/
@Override
public boolean visit(NormalAnnotation node) {
return false;
}
/**
* @see ASTVisitor#visit(NullLiteral)
*/
@Override
public boolean visit(NullLiteral node) {
if (!isActive()) {
return false;
}
push(new PushNull());
return true;
}
/**
* @see ASTVisitor#visit(NumberLiteral)
*/
@Override
public boolean visit(NumberLiteral node) {
if (!isActive()) {
return false;
}
int literalType = getTypeId(node);
String token = node.getToken();
int tokenLastCharOffset = token.length() - 1;
char lastChar = token.charAt(tokenLastCharOffset);
String subToken = token.substring(0, tokenLastCharOffset);
switch (literalType) {
case Instruction.T_byte:
push(new PushInt(parseByteValue(token)));
break;
case Instruction.T_short:
push(new PushInt(parseShortValue(token)));
break;
case Instruction.T_int:
push(new PushInt(parseIntValue(token)));
break;
case Instruction.T_long:
push(new PushLong(parseLongValue(subToken)));
break;
case Instruction.T_float:
push(new PushFloat(
Float.parseFloat(removePrefixZerosAndUnderscores(subToken,
false))));
break;
case Instruction.T_double:
if (lastChar == 'D' || lastChar == 'd') {
push(new PushDouble(
Double.parseDouble(removePrefixZerosAndUnderscores(
subToken, false))));
} else {
push(new PushDouble(
Double.parseDouble(removePrefixZerosAndUnderscores(
token, false))));
}
break;
}
return true;
}
/**
* Removes all preamble typing and underscores and returns the base integer
* value
*
* @param token
* the token to parse
* @return the int value of the token
*/
public static int parseIntValue(String token) {
token = removePrefixZerosAndUnderscores(token, false);
switch (getBase(token)) {
case 8:
return Integer.valueOf(token.substring(1), 8).intValue();
case 16:
return Integer.valueOf(token.substring(2), 16).intValue();
case 2:
return Integer.valueOf(token.substring(2), 2).intValue();
default:
return Integer.valueOf(token, 10).intValue();
}
}
/**
* Removes all preamble typing and underscores and returns the base short
* value
*
* @param token
* the token to parse
* @return the short value of the token
*/
public static short parseShortValue(String token) {
token = removePrefixZerosAndUnderscores(token, false);
switch (getBase(token)) {
case 8:
return Short.valueOf(token.substring(1), 8).shortValue();
case 16:
return Short.valueOf(token.substring(2), 16).shortValue();
case 2:
return Short.valueOf(token.substring(2), 2).shortValue();
default:
return Short.valueOf(token, 10).shortValue();
}
}
/**
* Removes all preamble typing and underscores and returns the base byte
* value
*
* @param token
* the token to parse
* @return the byte value of the token
*/
public static byte parseByteValue(String token) {
token = removePrefixZerosAndUnderscores(token, false);
switch (getBase(token)) {
case 8:
return Byte.valueOf(token.substring(1), 8).byteValue();
case 16:
return Byte.valueOf(token.substring(2), 16).byteValue();
case 2:
return Byte.valueOf(token.substring(2), 2).byteValue();
default:
return Byte.valueOf(token, 10).byteValue();
}
}
/**
* Removes all preamble typing and underscores and returns the base long
* value
*
* @param token
* the token to parse
* @return the long value of the token
*/
public static long parseLongValue(String token) {
token = removePrefixZerosAndUnderscores(token, true);
switch (getBase(token)) {
case 8:
return Long.valueOf(token.substring(1), 8).longValue();
case 16:
return Long.valueOf(token.substring(2), 16).longValue();
case 2:
return Long.valueOf(token.substring(2), 2).longValue();
default:
return Long.valueOf(token, 10).longValue();
}
}
/**
* Returns the numeric base for the given token according to the Java
* specification. Returns 8, 10, or 16.
*
* @param token
* the token to get the base from
* @return the numeric base for the given token
*/
public static int getBase(String token) {
if (token.charAt(0) == '0' && (token.length() > 1)) {
switch (token.charAt(1)) {
case 'x':
case 'X':
// "0x" prefix: Hexadecimal
return 16;
case 'b':
case 'B':
// "0b" prefix: binary
return 2;
default:
// "0" prefix: Octal
return 8;
}
}
return 10; // No prefix: Decimal
}
/**
* @see ASTVisitor#visit(PackageDeclaration)
*/
@Override
public boolean visit(PackageDeclaration node) {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.
* ParameterizedType)
*/
@Override
public boolean visit(ParameterizedType node) {
if (!isActive()) {
return false;
}
ITypeBinding typeBinding = resolveTypeBinding(node);
if (typeBinding != null) {
push(new PushType(getTypeName(typeBinding)));
}
return false;
}
/**
* @see ASTVisitor#visit(ParenthesizedExpression)
*/
@Override
public boolean visit(ParenthesizedExpression node) {
if (!isActive()) {
return false;
}
return true;
}
/**
* @see ASTVisitor#visit(PostfixExpression)
*/
@Override
public boolean visit(PostfixExpression node) {
if (!isActive()) {
return false;
}
Expression operand = node.getOperand();
int expressionTypeId = getTypeId(operand);
String opToken = node.getOperator().toString();
char char0 = opToken.charAt(0);
if (expressionTypeId == Instruction.T_Object) {
int expressionUnBoxedTypeId = getUnBoxedTypeId(operand);
AssignmentOperator assignmentInstruction = new AssignmentOperator(
Instruction.T_Object, Instruction.T_Object, fCounter);
push(assignmentInstruction);
operand.accept(this);
switch (char0) {
case '+': // plus plus
push(new PlusOperator(expressionUnBoxedTypeId,
expressionUnBoxedTypeId, expressionUnBoxedTypeId,
fCounter));
break;
case '-': // minus minus
push(new MinusOperator(expressionUnBoxedTypeId,
expressionUnBoxedTypeId, expressionUnBoxedTypeId,
fCounter));
break;
default:
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_unrecognized_postfix_operator____15
+ opToken);
return false;
}
push(new Value(fCounter));
push(new Dup());
storeInstruction(); // dupe
storeInstruction(); // value
push(new DupX1());
storeInstruction(); // dup_x1
ITypeBinding typeBinding = resolveTypeBinding(operand);
if (typeBinding == null) {
return false;
}
unBoxing(typeBinding);
storeInstruction(); // un-boxing
push(new PushInt(1));
storeInstruction(); // push 1
storeInstruction(); // operator
boxing(typeBinding, null);
storeInstruction(); // boxing
storeInstruction(); // assignment
push(new Pop(assignmentInstruction.getSize() + 1));
return false;
}
switch (char0) {
case '+': // plus plus
push(new PostfixPlusPlusOperator(expressionTypeId, fCounter));
break;
case '-': // minus minus
push(new PostfixMinusMinusOperator(expressionTypeId, fCounter));
break;
default:
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_unrecognized_postfix_operator____15
+ opToken);
return false;
}
return true;
}
/**
* @see ASTVisitor#visit(PrefixExpression)
*/
@Override
public boolean visit(PrefixExpression node) {
if (!isActive()) {
return false;
}
Expression operand = node.getOperand();
int expressionTypeId = getTypeId(operand);
String opToken = node.getOperator().toString();
int opTokenLength = opToken.length();
char char0 = opToken.charAt(0);
char char1 = '\0';
if (opTokenLength > 1) {
char1 = opToken.charAt(1);
}
boolean unrecognized = false;
if (expressionTypeId == Instruction.T_Object) {
int expressionUnBoxedTypeId = getUnBoxedTypeId(operand);
ITypeBinding typeBinding = resolveTypeBinding(operand);
if (typeBinding == null) {
return false;
}
if (char1 == '\0') {
switch (char0) {
case '+': // unary plus
push(new UnaryPlusOperator(expressionUnBoxedTypeId,
fCounter));
break;
case '-': // unary minus
push(new UnaryMinusOperator(expressionUnBoxedTypeId,
fCounter));
break;
case '~': // twiddle
push(new TwiddleOperator(expressionUnBoxedTypeId, fCounter));
break;
case '!': // not
push(new NotOperator(expressionUnBoxedTypeId, fCounter));
break;
default:
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_unrecognized_prefix_operator____16
+ opToken);
return false;
}
unBoxing(typeBinding);
operand.accept(this);
storeInstruction(); // un-boxing
} else {
// plus plus and minus minus operators
push(new AssignmentOperator(Instruction.T_Object,
Instruction.T_Object, fCounter));
operand.accept(this);
boxing(typeBinding, null);
switch (char1) {
case '+':
push(new PlusOperator(expressionUnBoxedTypeId,
expressionUnBoxedTypeId, expressionUnBoxedTypeId,
fCounter));
break;
case '-':
push(new MinusOperator(expressionUnBoxedTypeId,
expressionUnBoxedTypeId, expressionUnBoxedTypeId,
fCounter));
break;
default:
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_unrecognized_prefix_operator____16
+ opToken);
return false;
}
unBoxing(typeBinding);
push(new Dup());
storeInstruction(); // dupe
storeInstruction(); // un-boxing
push(new PushInt(1));
storeInstruction(); // push 1
storeInstruction(); // operator
storeInstruction(); // boxing
}
return false;
}
switch (char0) {
case '+': // plus plus or unary plus
switch (char1) {
case '\0': // unary plus
push(new UnaryPlusOperator(expressionTypeId, fCounter));
break;
case '+': // plus plus
push(new PrefixPlusPlusOperator(expressionTypeId, fCounter));
break;
default:
unrecognized = true;
break;
}
break;
case '-': // minus minus or unary minus
switch (char1) {
case '\0': // unary minus
push(new UnaryMinusOperator(expressionTypeId, fCounter));
break;
case '-': // minus minus
push(new PrefixMinusMinusOperator(expressionTypeId, fCounter));
break;
default:
unrecognized = true;
break;
}
break;
case '~': // twiddle
push(new TwiddleOperator(expressionTypeId, fCounter));
break;
case '!': // not
push(new NotOperator(expressionTypeId, fCounter));
break;
default:
unrecognized = true;
break;
}
if (unrecognized) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_unrecognized_prefix_operator____16
+ opToken);
return false;
}
return true;
}
/**
* @see ASTVisitor#visit(PrimitiveType)
*/
@Override
public boolean visit(PrimitiveType node) {
if (!isActive()) {
return false;
}
ITypeBinding typeBinding = resolveTypeBinding(node);
if (typeBinding != null) {
push(new PushPrimitiveType(getTypeName(typeBinding)));
}
return false;
}
/**
* @see ASTVisitor#visit(QualifiedName)
*/
@Override
public boolean visit(QualifiedName node) {
if (!isActive()) {
return false;
}
if (hasErrors()) {
return true;
}
IBinding binding = resolveBinding(node);
if (binding == null) {
return false;
}
switch (binding.getKind()) {
case IBinding.TYPE:
node.getName().accept(this);
break;
case IBinding.VARIABLE:
SimpleName fieldName = node.getName();
IVariableBinding fieldBinding = (IVariableBinding) resolveBinding(fieldName);
if (fieldBinding == null) {
return false;
}
ITypeBinding declaringTypeBinding = fieldBinding
.getDeclaringClass();
String fieldId = fieldName.getIdentifier();
if (Modifier.isStatic(fieldBinding.getModifiers())) {
push(new PushStaticFieldVariable(fieldId,
getTypeName(declaringTypeBinding), fCounter));
} else {
if (declaringTypeBinding == null) {
push(new PushArrayLength(fCounter));
} else {
push(new PushFieldVariable(fieldId,
getTypeSignature(declaringTypeBinding), fCounter));
}
node.getQualifier().accept(this);
}
storeInstruction();
break;
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.
* QualifiedType)
*/
@Override
public boolean visit(QualifiedType node) {
if (!isActive()) {
return false;
}
ITypeBinding typeBinding = resolveTypeBinding(node);
if (typeBinding != null) {
push(new PushType(getTypeName(typeBinding)));
}
return false;
}
/**
* @see ASTVisitor#visit(ReturnStatement)
*/
@Override
public boolean visit(ReturnStatement node) {
if (!isActive()) {
return false;
}
push(new ReturnInstruction(fCounter));
return true;
}
/**
* @see ASTVisitor#visit(SimpleName)
*/
@Override
public boolean visit(SimpleName node) {
if (!isActive()) {
return false;
}
if (hasErrors()) {
return true;
}
IBinding binding = resolveBinding(node);
if (binding == null) {
return true;
}
String variableId = node.getIdentifier();
switch (binding.getKind()) {
case IBinding.TYPE:
ITypeBinding typeBinding = (ITypeBinding) binding;
push(new PushType(getTypeName(typeBinding)));
break;
case IBinding.VARIABLE:
IVariableBinding variableBinding = (IVariableBinding) binding;
ITypeBinding declaringTypeBinding = variableBinding
.getDeclaringClass();
if (variableBinding.isField()) {
if (Modifier.isStatic(variableBinding.getModifiers())) {
push(new PushStaticFieldVariable(variableId,
getTypeName(declaringTypeBinding), fCounter));
} else {
push(new PushFieldVariable(variableId,
getTypeSignature(declaringTypeBinding), fCounter));
push(new PushThis(getEnclosingLevel(node,
declaringTypeBinding)));
storeInstruction();
}
} else {
push(new PushLocalVariable(variableId));
}
break;
}
return true;
}
/**
* return false, don't visit child
*
* @see ASTVisitor#visit(SimpleType)
*/
@Override
public boolean visit(SimpleType node) {
if (!isActive()) {
return false;
}
ITypeBinding typeBinding = resolveTypeBinding(node);
if (typeBinding != null) {
push(new PushType(getTypeName(typeBinding)));
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.
* SingleMemberAnnotation)
*/
@Override
public boolean visit(SingleMemberAnnotation node) {
return false;
}
/**
* @see ASTVisitor#visit(SingleVariableDeclaration) return
* <code>false</code>, don't use the standard accept order.
*/
@Override
public boolean visit(SingleVariableDeclaration node) {
if (!isActive()) {
return false;
}
ITypeBinding typeBinding = resolveTypeBinding(node.getType());
if (typeBinding != null) {
int typeDimension = typeBinding.getDimensions();
if (typeDimension != 0) {
typeBinding = typeBinding.getElementType();
}
Expression initializer = node.getInitializer();
push(new LocalVariableCreation(node.getName().getIdentifier(),
getTypeSignature(typeBinding), typeDimension,
typeBinding.isPrimitive(), initializer != null, fCounter));
if (initializer != null) {
initializer.accept(this);
}
}
return false;
}
/**
* @see ASTVisitor#visit(StringLiteral)
*/
@Override
public boolean visit(StringLiteral node) {
if (!isActive()) {
return false;
}
push(new PushString(node.getLiteralValue()));
return true;
}
@Override
public boolean visit(TextBlock node) {
if (!isActive()) {
return false;
}
push(new PushString(node.getLiteralValue()));
return true;
}
/**
* @see ASTVisitor#visit(SuperConstructorInvocation)
*/
@Override
public boolean visit(SuperConstructorInvocation node) {
if (!isActive()) {
return false;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_super_constructor_invocation_cannot_be_used_in_an_evaluation_expression_19);
return false;
}
/**
* @see ASTVisitor#visit(SuperFieldAccess)
*/
@Override
public boolean visit(SuperFieldAccess node) {
if (!isActive()) {
return false;
}
SimpleName fieldName = node.getName();
IVariableBinding fieldBinding = (IVariableBinding) resolveBinding(fieldName);
if (fieldBinding == null) {
return false;
}
ITypeBinding declaringTypeBinding = fieldBinding.getDeclaringClass();
String fieldId = fieldName.getIdentifier();
if (Modifier.isStatic(fieldBinding.getModifiers())) {
push(new PushStaticFieldVariable(fieldId,
getTypeName(declaringTypeBinding), fCounter));
} else {
Name qualifier = node.getQualifier();
int superLevel = 1;
int enclosingLevel = 0;
if (qualifier != null) {
ITypeBinding typeBinding = resolveTypeBinding(qualifier);
if (typeBinding == null) {
return false;
}
superLevel = getSuperLevel(typeBinding, declaringTypeBinding);
ITypeBinding binding = (ITypeBinding) resolveBinding(qualifier);
if (binding == null) {
return false;
}
enclosingLevel = getEnclosingLevel(node, binding);
}
push(new PushFieldVariable(fieldId, superLevel, fCounter));
push(new PushThis(enclosingLevel));
storeInstruction();
}
return false;
}
/**
* return false, don't visit name, visit arguments
*
* @see ASTVisitor#visit(SuperMethodInvocation)
*/
@Override
public boolean visit(SuperMethodInvocation node) {
if (!isActive()) {
return false;
}
IMethodBinding methodBinding = (IMethodBinding) resolveBinding(node
.getName());
if (methodBinding == null) {
return false;
}
if (containsALocalType(methodBinding)) {
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Method_which_contains_a_local_type_as_parameter_cannot_be_used_in_an_evaluation_expression_32);
return false;
}
ITypeBinding[] parameterTypes = methodBinding.getParameterTypes();
int paramCount = parameterTypes.length;
String selector = methodBinding.getName();
String signature = getMethodSignature(methodBinding, null);
Name qualifier = node.getQualifier();
if (Modifier.isStatic(methodBinding.getModifiers())) {
push(new SendStaticMessage(
getTypeName(methodBinding.getDeclaringClass()), selector,
signature, paramCount, fCounter));
} else {
push(new SendMessage(selector, signature, paramCount,
getTypeSignature(methodBinding.getDeclaringClass()),
fCounter));
int enclosingLevel = 0;
if (qualifier != null) {
ITypeBinding typeBinding = (ITypeBinding) resolveBinding(qualifier);
if (typeBinding == null) {
return false;
}
enclosingLevel = getEnclosingLevel(node, typeBinding);
}
push(new PushThis(enclosingLevel));
storeInstruction();
}
List<Expression> arguments = node.arguments();
int argCount = arguments.size();
ITypeBinding lastArgBinding = null;
if (methodBinding.isVarargs()) {
lastArgBinding = resolveTypeBinding(arguments.get(argCount - 1));
if (lastArgBinding == null) {
return false;
}
}
if (methodBinding.isVarargs() &&
!(paramCount == argCount &&
parameterTypes[paramCount - 1].getDimensions() == lastArgBinding.getDimensions())) {
// if this method is a varargs, and if the method is invoked using
// the varargs syntax
// (multiple arguments) and not an array
Iterator<Expression> iterator = arguments.iterator();
// process the first arguments (no part of the variable argument)
for (int i = 0; i < paramCount - 1; i++) {
Expression argument = iterator.next();
boolean storeRequired = checkAutoBoxing(
argument.resolveTypeBinding(), parameterTypes[i]);
argument.accept(this);
if (storeRequired) {
storeInstruction();
}
}
// create a array of the remainder arguments
ITypeBinding varargsParameterType = parameterTypes[paramCount - 1];
ITypeBinding varargsElementType = varargsParameterType
.getElementType();
push(new ArrayInitializerInstruction(
getTypeSignature(varargsElementType), argCount - paramCount
+ 1, varargsParameterType.getDimensions(), fCounter));
while (iterator.hasNext()) {
Expression argument = iterator.next();
boolean storeRequired = checkAutoBoxing(
argument.resolveTypeBinding(), varargsElementType);
argument.accept(this);
if (storeRequired) {
storeInstruction();
}
}
storeInstruction();
} else {
Iterator<Expression> iterator = arguments.iterator();
int i = 0;
while (iterator.hasNext()) {
Expression argument = iterator.next();
boolean storeRequired = checkAutoBoxing(
argument.resolveTypeBinding(), parameterTypes[i++]);
argument.accept(this);
if (storeRequired) {
storeInstruction();
}
}
}
return false;
}
/**
* @see ASTVisitor#visit(SuperMethodReference)
*/
@Override
public boolean visit(SuperMethodReference node) {
if (!isActive()) {
return true;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Reference_expressions_cannot_be_used_in_an_evaluation_expression);
return false;
}
@Override
public boolean visit(SwitchExpression node) {
if (!isActive()) {
return true;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Switch_expressions_cannot_be_used_in_an_evaluation_expression);
return false;
}
/**
* @see ASTVisitor#visit(SwitchCase)
*/
@Override
public boolean visit(SwitchCase node) {
// never called
return false;
}
class slot {
ArrayList<ConditionalJump> jumps = new ArrayList<>();
ArrayList<Statement> stmts = null;
}
/**
* @see ASTVisitor#visit(SwitchStatement)
*/
@SuppressWarnings("deprecation")
@Override
public boolean visit(SwitchStatement node) {
if (!isActive()) {
return false;
}
push(new NoOp(fCounter));
int switchStart = fCounter;
node.getExpression().accept(this);
ArrayList<Statement> statementsDefault = null;
Jump jumpDefault = null;
ArrayList<slot> jumpsStatements = new ArrayList<>();
slot currentslot = new slot();
jumpsStatements.add(currentslot);
for (Iterator<Statement> iter = node.statements().iterator(); iter.hasNext();) {
Statement statement = iter.next();
if (statement instanceof SwitchCase) {
SwitchCase switchCase = (SwitchCase) statement;
if (switchCase.isDefault()) {
jumpDefault = new Jump();
push(jumpDefault);
storeInstruction(); // jump
statementsDefault = new ArrayList<>();
} else {
if (node.getAST().apiLevel() == AST.JLS13) {
for (Object expression : switchCase.expressions()) {
if (expression instanceof StringLiteral || expression instanceof TextBlock) {
push(new SendMessage("equals", "(Ljava/lang/Object;)Z", 1, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else {
push(new EqualEqualOperator(Instruction.T_int, Instruction.T_int, true, fCounter));
}
push(new Dup());
storeInstruction(); // dupe
((Expression) expression).accept(this);
storeInstruction(); // equal-equal
}
} else {
if (switchCase.getExpression() instanceof StringLiteral || switchCase.getExpression() instanceof TextBlock) {
push(new SendMessage("equals", "(Ljava/lang/Object;)Z", 1, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$
} else {
push(new EqualEqualOperator(Instruction.T_int, Instruction.T_int, true, fCounter));
}
push(new Dup());
storeInstruction(); // dupe
switchCase.getExpression().accept(this);
storeInstruction(); // equal-equal
}
ConditionalJump condJump = new ConditionalJump(true);
push(condJump);
storeInstruction(); // conditional jump
if (currentslot.stmts != null) {
currentslot = new slot();
jumpsStatements.add(currentslot);
}
currentslot.jumps.add(condJump);
}
} else {
if (statementsDefault != null) {
statementsDefault.add(statement);
} else {
if (currentslot.stmts == null) {
currentslot.stmts = new ArrayList<>();
}
currentslot.stmts.add(statement);
}
}
}
Jump jumpEnd = null;
if (jumpDefault == null) {
push(new Pop(0));
storeInstruction(); // pop
jumpEnd = new Jump();
push(jumpEnd);
storeInstruction(); // jump
}
for (slot slot : jumpsStatements) {
for (ConditionalJump condJump : slot.jumps) {
condJump.setOffset((fCounter - fInstructions.indexOf(condJump)) - 1);
}
if (currentslot.stmts != null) {
push(new Pop(0));
storeInstruction(); // pop
for (Statement statement : currentslot.stmts) {
statement.accept(this);
}
}
}
// default case
if (jumpDefault != null) {
jumpDefault.setOffset((fCounter - fInstructions.indexOf(jumpDefault)) - 1);
push(new Pop(0));
storeInstruction(); // pop
for (Statement statement : statementsDefault) {
statement.accept(this);
}
} else if(jumpEnd != null){
jumpEnd.setOffset((fCounter - fInstructions.indexOf(jumpEnd)) - 1);
}
// for each pending break or continue instruction which are related to
// this loop, set the offset of the corresponding jump.
String label = getLabel(node);
for (Iterator<CompleteInstruction> iter = fCompleteInstructions.iterator(); iter.hasNext();) {
CompleteInstruction instruction = iter.next();
Jump jumpInstruction = instruction.fInstruction;
int instructionAddress = fInstructions.indexOf(jumpInstruction);
if (instructionAddress > switchStart && (instruction.fLabel == null || instruction.fLabel.equals(label))) {
iter.remove();
if (instruction.fIsBreak) {
// jump to the instruction after the last instruction of the
// switch
jumpInstruction.setOffset((fCounter - instructionAddress) - 1);
}
}
}
return false;
}
/**
* @see ASTVisitor#visit(SynchronizedStatement)
*/
@Override
public boolean visit(SynchronizedStatement node) {
if (!isActive()) {
return false;
}
return true;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TagElement
* )
*/
@Override
public boolean visit(TagElement node) {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.
* TextElement)
*/
@Override
public boolean visit(TextElement node) {
return false;
}
/**
* @see ASTVisitor#visit(ThisExpression)
*/
@Override
public boolean visit(ThisExpression node) {
if (!isActive()) {
return false;
}
Name qualifier = node.getQualifier();
int enclosingLevel = 0;
if (qualifier != null) {
ITypeBinding binding = (ITypeBinding) resolveBinding(qualifier);
if (binding == null) {
return false;
}
enclosingLevel = getEnclosingLevel(node, binding);
}
push(new PushThis(enclosingLevel));
return false;
}
/**
* @see ASTVisitor#visit(ThrowStatement)
*/
@Override
public boolean visit(ThrowStatement node) {
if (!isActive()) {
return false;
}
push(new ThrowInstruction(fCounter));
return true;
}
/**
* @see ASTVisitor#visit(TryStatement)
*/
@Override
public boolean visit(TryStatement node) {
if (!isActive()) {
return false;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Try_statement_cannot_be_used_in_an_evaluation_expression_23);
return false;
}
/**
* @see ASTVisitor#visit(TypeDeclaration)
*/
@Override
public boolean visit(TypeDeclaration node) {
if (!isActive()) {
return true;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Type_declaration_cannot_be_used_in_an_evaluation_expression_24);
return false;
}
/**
* @see ASTVisitor#visit(TypeDeclarationStatement)
*/
@Override
public boolean visit(TypeDeclarationStatement node) {
if (!isActive()) {
return true;
}
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Type_declaration_statement_cannot_be_used_in_an_evaluation_expression_25);
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.
* TypeParameter)
*/
@Override
public boolean visit(TypeParameter node) {
return false;
}
/**
* @see ASTVisitor#visit(TypeLiteral)
*/
@Override
public boolean visit(TypeLiteral node) {
if (!isActive()) {
return false;
}
push(new PushClassLiteralValue(fCounter));
return true;
}
/**
* @see ASTVisitor#visit(TypeMethodReference)
*/
@Override
public boolean visit(TypeMethodReference node) {
if (!isActive()) {
return true;
}
try {
RemoteEvaluatorBuilder builder = makeBuilder(node);
builder.acceptMethodReference(node, node.resolveTypeBinding());
RemoteEvaluator remoteEvaluator = builder.build();
push(new RemoteOperator(builder.getSnippet(), node.getStartPosition(), remoteEvaluator));
storeInstruction();
} catch (JavaModelException | DebugException e) {
addErrorMessage(e.getMessage());
setHasError(true);
}
return false;
}
/**
* @see ASTVisitor#visit(VariableDeclarationExpression)
*/
@Override
public boolean visit(VariableDeclarationExpression node) {
/*
* if it is in the code to execute, return <code>false</code>, we don't
* use the standard accept order. Otherwise, return true. We want to
* search the code to execute in variable declarations (in case of inner
* classes).
*/
if (!isActive()) {
return true;
}
for (Iterator<VariableDeclarationFragment> iter = node.fragments().iterator(); iter.hasNext();) {
iter.next().accept(this);
}
return false;
}
/**
* @see ASTVisitor#visit(VariableDeclarationFragment)
*/
@Override
public boolean visit(VariableDeclarationFragment node) {
/*
* if it is in the code to execute, return <code>false</code>, we don't
* use the standard accept order. Otherwise, return true. We want to
* search the code to execute in variable declarations (in case of inner
* classes).
*/
if (!isActive()) {
return true;
}
// get the type of the variable
ITypeBinding varTypeBinding;
ASTNode parent = node.getParent();
switch (parent.getNodeType()) {
case ASTNode.VARIABLE_DECLARATION_EXPRESSION:
varTypeBinding = resolveTypeBinding(((VariableDeclarationExpression) parent)
.getType());
break;
case ASTNode.VARIABLE_DECLARATION_STATEMENT:
varTypeBinding = resolveTypeBinding(((VariableDeclarationStatement) parent)
.getType());
break;
default:
setHasError(true);
addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Error_in_type_declaration_statement);
return false;
}
if (varTypeBinding == null) {
return false;
}
int typeDimension = varTypeBinding.getDimensions();
ITypeBinding elementBinding = varTypeBinding;
if (typeDimension != 0) {
elementBinding = elementBinding.getElementType();
}
Expression initializer = node.getInitializer();
push(new LocalVariableCreation(node.getName().getIdentifier(),
getTypeSignature(elementBinding), typeDimension,
elementBinding.isPrimitive(), initializer != null, fCounter));
if (initializer != null) {
initializer.accept(this);
ITypeBinding expBindnig = initializer.resolveTypeBinding();
if (expBindnig != null) {
if (checkAutoBoxing(expBindnig, varTypeBinding)) {
storeInstruction();
}
}
}
return false;
}
/**
* @see ASTVisitor#visit(VariableDeclarationStatement)
*/
@Override
public boolean visit(VariableDeclarationStatement node) {
/*
* if it is in the code to execute, return <code>false</code>, we don't
* use the standard accept order. Otherwise, return true. We want to
* search the code to execute in variable declarations (in case of inner
* classes).
*/
if (!isActive()) {
return true;
}
for (Iterator<VariableDeclarationFragment> iter = node.fragments().iterator(); iter.hasNext();) {
iter.next().accept(this);
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.
* WildcardType)
*/
@Override
public boolean visit(WildcardType node) {
// we shouldn't have to do anything
return false;
}
/**
* @see ASTVisitor#visit(WhileStatement)
*/
@Override
public boolean visit(WhileStatement node) {
if (!isActive()) {
return false;
}
push(new NoOp(fCounter));
return true;
}
// --------------------------
private int getTypeId(Expression expression) {
ITypeBinding typeBinding = expression.resolveTypeBinding();
if (typeBinding == null) {
return Instruction.T_undefined;
}
String typeName = typeBinding.getQualifiedName();
if (typeBinding.isPrimitive()) {
return getPrimitiveTypeId(typeName);
} else if ("java.lang.String".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_String;
} else {
return Instruction.T_Object;
}
}
private int getUnBoxedTypeId(Expression expression) {
ITypeBinding typeBinding = expression.resolveTypeBinding();
if (typeBinding == null) {
return Instruction.T_undefined;
}
String typeName = typeBinding.getQualifiedName();
if (typeBinding.isPrimitive()) {
return getPrimitiveTypeId(typeName);
} else if ("java.lang.String".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_String;
} else {
// un-boxing
if ("java.lang.Integer".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_int;
} else if ("java.lang.Character".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_char;
} else if ("java.lang.Byte".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_byte;
} else if ("java.lang.Short".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_short;
} else if ("java.lang.Long".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_long;
} else if ("java.lang.Float".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_float;
} else if ("java.lang.Double".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_double;
} else if ("java.lang.Boolean".equals(typeName)) { //$NON-NLS-1$
return Instruction.T_boolean;
}
return Instruction.T_Object;
}
}
private int getTypeId(Type type) {
if (type.isPrimitiveType()) {
return getPrimitiveTypeId(((PrimitiveType) type)
.getPrimitiveTypeCode().toString());
} else if (type.isSimpleType()) {
SimpleType simpleType = (SimpleType) type;
if ("java.lang.String".equals(simpleType.getName().getFullyQualifiedName())) { //$NON-NLS-1$
return Instruction.T_String;
}
return Instruction.T_Object;
} else if (type.isArrayType()) {
return Instruction.T_Object;
} else if (type.isParameterizedType()) {
return Instruction.T_Object;
} else {
return Instruction.T_undefined;
}
}
public static String removePrefixZerosAndUnderscores(String tokenString,
boolean isLong) {
char[] token = tokenString.toCharArray();
int max = token.length;
int start = 0;
int end = max - 1;
if (isLong) {
end--; // remove the 'L' or 'l'
}
if (max > 1 && token[0] == '0') {
if (max > 2 && (token[1] == 'x' || token[1] == 'X')) {
start = 2;
} else if (max > 2 && (token[1] == 'b' || token[1] == 'B')) {
start = 2;
} else {
start = 1;
}
}
boolean modified = false;
boolean ignore = true;
loop: for (int i = start; i < max; i++) {
char currentChar = token[i];
switch (currentChar) {
case '0':
// this is a prefix '0'
if (ignore && !modified && (i < end)) {
modified = true;
}
break;
case '_':
modified = true;
break loop;
default:
ignore = false;
}
}
if (!modified) {
return tokenString;
}
ignore = true;
StringBuilder buffer = new StringBuilder();
buffer.append(token, 0, start);
loop: for (int i = start; i < max; i++) {
char currentChar = token[i];
switch (currentChar) {
case '0':
if (ignore && (i < end)) {
// this is a prefix '0'
continue loop;
}
break;
case '_':
continue loop;
default:
ignore = false;
}
buffer.append(currentChar);
}
return buffer.toString();
}
/**
* Returns the method signature given the binding and the enclosing type
* signature (if there is one)
*
* @param methodBinding
* the binding to get the signature for
* @param enclosingTypeSignature
* the enclosing type signature or <code>null</code>
* @return the method signature for the given binding and enclosing type
* signature
*/
private String getMethodSignature(IMethodBinding methodBinding,
String enclosingTypeSignature) {
methodBinding = methodBinding.getMethodDeclaration();
ITypeBinding[] parameterTypes = methodBinding.getParameterTypes();
int offset = 0;
int argCount;
String[] parameterSignatures;
if (enclosingTypeSignature == null) {
argCount = parameterTypes.length;
parameterSignatures = new String[argCount];
} else {
offset = 1;
argCount = parameterTypes.length + 1;
parameterSignatures = new String[argCount];
parameterSignatures[0] = enclosingTypeSignature;
}
for (int i = 0; i < parameterTypes.length; i++) {
parameterSignatures[i + offset] = getTypeSignature(parameterTypes[i]);
}
String signature = Signature.createMethodSignature(parameterSignatures,
getTypeSignature(methodBinding.getReturnType()));
return signature;
}
public static int getPrimitiveTypeId(String typeName) {
switch (typeName.charAt(0)) {
case 'b': // byte or boolean
switch (typeName.charAt(1)) {
case 'o': // boolean;
return Instruction.T_boolean;
case 'y': // byte
return Instruction.T_byte;
}
break;
case 'c': // char
return Instruction.T_char;
case 'd': // double
return Instruction.T_double;
case 'f': // float
return Instruction.T_float;
case 'i': // int
return Instruction.T_int;
case 'l': // long
return Instruction.T_long;
case 'n':
return Instruction.T_null;
case 's': // short
return Instruction.T_short;
case 'v': // void
return Instruction.T_void;
}
return Instruction.T_undefined;
}
/**
* Resolves and returns the type binding from the given expression reporting
* an error if the binding is <code>null</code>.
*
* @param expression
* expression to resolve type binding for
* @return type binding or <code>null</code> if not available
*/
private ITypeBinding resolveTypeBinding(Expression expression) {
ITypeBinding typeBinding = expression.resolveTypeBinding();
if (typeBinding == null) {
setHasError(true);
addErrorMessage(MessageFormat.format(
EvaluationEngineMessages.ASTInstructionCompiler_3,
new Object[] { expression.toString() }));
}
return typeBinding;
}
/**
* Resolves and returns the type binding for the give type reporting an
* error if the binding is <code>null</code>.
*
* @param type
* type to resolve binding for
* @return type binding or <code>null</code> if not available
*/
private ITypeBinding resolveTypeBinding(Type type) {
ITypeBinding typeBinding = type.resolveBinding();
if (typeBinding == null) {
setHasError(true);
addErrorMessage(MessageFormat.format(
EvaluationEngineMessages.ASTInstructionCompiler_3,
new Object[] { type.toString() }));
}
return typeBinding;
}
/**
* Resolves and returns the binding for the given name reporting an error if
* the binding is <code>null</code>.
*
* @param name
* name to resolve binding for
* @return binding or <code>null</code> if not available
*/
private IBinding resolveBinding(Name name) {
IBinding binding = name.resolveBinding();
if (binding == null) {
setHasError(true);
addErrorMessage(MessageFormat.format(
EvaluationEngineMessages.ASTInstructionCompiler_5,
new Object[] { name.getFullyQualifiedName() }));
}
return binding;
}
/**
* Resolves and returns the type binding for the given name reporting an
* error if the binding is <code>null</code>.
*
* @param name
* name to resolve type binding for
* @return type binding or <code>null</code> if not available
*/
private ITypeBinding resolveTypeBinding(Name name) {
ITypeBinding typeBinding = name.resolveTypeBinding();
if (typeBinding == null) {
setHasError(true);
addErrorMessage(MessageFormat.format(
EvaluationEngineMessages.ASTInstructionCompiler_3,
new Object[] { name.getFullyQualifiedName() }));
}
return typeBinding;
}
}