/*******************************************************************************
- * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v0.5
+ * are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v05.html
+ * http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
- ******************************************************************************/
+ *******************************************************************************/
package net.sourceforge.phpdt.internal.compiler.ast;
-import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
-import net.sourceforge.phpdt.internal.compiler.impl.*;
-import net.sourceforge.phpdt.internal.compiler.codegen.*;
-import net.sourceforge.phpdt.internal.compiler.flow.*;
-import net.sourceforge.phpdt.internal.compiler.lookup.*;
+import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
+import net.sourceforge.phpdt.internal.compiler.codegen.Label;
+import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
+import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
+import net.sourceforge.phpdt.internal.compiler.flow.SwitchFlowContext;
+import net.sourceforge.phpdt.internal.compiler.impl.Constant;
+import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
+import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
public class SwitchStatement extends Statement {
- public Expression testExpression;
+ public Expression expression;
public Statement[] statements;
public BlockScope scope;
public int explicitDeclarations;
public Label breakLabel;
- public Case[] cases;
+ public CaseStatement[] cases;
public DefaultCase defaultCase;
public int caseCount = 0;
BlockScope currentScope,
FlowContext flowContext,
FlowInfo flowInfo) {
- flowInfo = testExpression.analyseCode(currentScope, flowContext, flowInfo);
+ flowInfo = expression.analyseCode(currentScope, flowContext, flowInfo);
SwitchFlowContext switchContext =
new SwitchFlowContext(flowContext, this, (breakLabel = new Label()));
// analyse the block by considering specially the case/default statements (need to bind them
// to the entry point)
- FlowInfo caseInits = FlowInfo.DeadEnd;
+ FlowInfo caseInits = FlowInfo.DEAD_END;
// in case of statements before the first case
preSwitchInitStateIndex =
currentScope.methodScope().recordInitializationStates(flowInfo);
int caseIndex = 0;
if (statements != null) {
+ boolean didAlreadyComplain = false;
for (int i = 0, max = statements.length; i < max; i++) {
Statement statement = statements[i];
- if ((caseIndex < caseCount)
- && (statement == cases[caseIndex])) { // statements[i] is a case or a default case
+ if ((caseIndex < caseCount) && (statement == cases[caseIndex])) { // statement is a case
caseIndex++;
caseInits = caseInits.mergedWith(flowInfo.copy().unconditionalInits());
- } else {
- if (statement == defaultCase) {
- caseInits = caseInits.mergedWith(flowInfo.copy().unconditionalInits());
- }
+ didAlreadyComplain = false; // reset complaint
+ } else if (statement == defaultCase) { // statement is the default case
+ caseInits = caseInits.mergedWith(flowInfo.copy().unconditionalInits());
+ didAlreadyComplain = false; // reset complaint
}
- if (!caseInits.complainIfUnreachable(statement, scope)) {
+ if (!caseInits.complainIfUnreachable(statement, scope, didAlreadyComplain)) {
caseInits = statement.analyseCode(scope, switchContext, caseInits);
+ } else {
+ didAlreadyComplain = true;
}
}
}
/**
* Switch code generation
*
- * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
- * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+ * @param currentScope net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
+ * @param codeStream net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
*/
- public void generateCode(BlockScope currentScope, CodeStream codeStream) {
- int[] sortedIndexes = new int[caseCount];
- int[] localKeysCopy;
- if ((bits & IsReachableMASK) == 0) {
- return;
- }
- int pc = codeStream.position;
+// public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+// int[] sortedIndexes = new int[caseCount];
+// int[] localKeysCopy;
+// if ((bits & IsReachableMASK) == 0) {
+// return;
+// }
+// int pc = codeStream.position;
+//
+// // prepare the labels and constants
+// breakLabel.codeStream = codeStream;
+// CaseLabel[] caseLabels = new CaseLabel[caseCount];
+// int[] constants = new int[caseCount];
+// boolean needSwitch = caseCount != 0;
+// for (int i = 0; i < caseCount; i++) {
+// constants[i] = cases[i].constantExpression.constant.intValue();
+// cases[i].targetLabel = (caseLabels[i] = new CaseLabel(codeStream));
+// }
+//
+// // we sort the keys to be able to generate the code for tableswitch or lookupswitch
+// for (int i = 0; i < caseCount; i++) {
+// sortedIndexes[i] = i;
+// }
+// System.arraycopy(
+// constants,
+// 0,
+// (localKeysCopy = new int[caseCount]),
+// 0,
+// caseCount);
+// CodeStream.sort(localKeysCopy, 0, caseCount - 1, sortedIndexes);
+// CaseLabel defaultLabel = new CaseLabel(codeStream);
+// if (defaultCase != null) {
+// defaultCase.targetLabel = defaultLabel;
+// }
+// // generate expression testes
+// testExpression.generateCode(currentScope, codeStream, needSwitch);
+//
+// // generate the appropriate switch table/lookup bytecode
+// if (needSwitch) {
+// int max = localKeysCopy[caseCount - 1];
+// int min = localKeysCopy[0];
+// if ((long) (caseCount * 2.5) > ((long) max - (long) min)) {
+//
+// // work-around 1.3 VM bug, if max>0x7FFF0000, must use lookup bytecode
+// // see http://dev.eclipse.org/bugs/show_bug.cgi?id=21557
+// if (max > 0x7FFF0000 && currentScope.environment().options.complianceLevel < CompilerOptions.JDK1_4) {
+// codeStream.lookupswitch(defaultLabel, constants, sortedIndexes, caseLabels);
+//
+// } else {
+// codeStream.tableswitch(
+// defaultLabel,
+// min,
+// max,
+// constants,
+// sortedIndexes,
+// caseLabels);
+// }
+// } else {
+// codeStream.lookupswitch(defaultLabel, constants, sortedIndexes, caseLabels);
+// }
+// codeStream.updateLastRecordedEndPC(codeStream.position);
+// }
+//
+// // generate the switch block statements
+// int caseIndex = 0;
+// if (statements != null) {
+// for (int i = 0, maxCases = statements.length; i < maxCases; i++) {
+// Statement statement = statements[i];
+// if ((caseIndex < caseCount)
+// && (statement == cases[caseIndex])) { // statements[i] is a case
+// if (preSwitchInitStateIndex != -1) {
+// codeStream.removeNotDefinitelyAssignedVariables(
+// currentScope,
+// preSwitchInitStateIndex);
+// caseIndex++;
+// }
+// } else {
+// if (statement == defaultCase) { // statements[i] is a case or a default case
+// if (preSwitchInitStateIndex != -1) {
+// codeStream.removeNotDefinitelyAssignedVariables(
+// currentScope,
+// preSwitchInitStateIndex);
+// }
+// }
+// }
+// statement.generateCode(scope, codeStream);
+// }
+// }
+// // place the trailing labels (for break and default case)
+// breakLabel.place();
+// if (defaultCase == null) {
+// defaultLabel.place();
+// }
+// // May loose some local variable initializations : affecting the local variable attributes
+// if (mergedInitStateIndex != -1) {
+// codeStream.removeNotDefinitelyAssignedVariables(
+// currentScope,
+// mergedInitStateIndex);
+// codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
+// }
+// if (scope != currentScope) {
+// codeStream.exitUserScope(scope);
+// }
+// codeStream.recordPositionsFrom(pc, this.sourceStart);
+// }
- // prepare the labels and constants
- breakLabel.codeStream = codeStream;
- CaseLabel[] caseLabels = new CaseLabel[caseCount];
- int[] constants = new int[caseCount];
- boolean needSwitch = caseCount != 0;
- for (int i = 0; i < caseCount; i++) {
- constants[i] = cases[i].constantExpression.constant.intValue();
- cases[i].targetLabel = (caseLabels[i] = new CaseLabel(codeStream));
- }
- // we sort the keys to be able to generate the code for tableswitch or lookupswitch
- for (int i = 0; i < caseCount; i++) {
- sortedIndexes[i] = i;
- }
- System.arraycopy(
- constants,
- 0,
- (localKeysCopy = new int[caseCount]),
- 0,
- caseCount);
- CodeStream.sort(localKeysCopy, 0, caseCount - 1, sortedIndexes);
- CaseLabel defaultLabel = new CaseLabel(codeStream);
- if (defaultCase != null) {
- defaultCase.targetLabel = defaultLabel;
+ public void resetStateForCodeGeneration() {
+ if (this.breakLabel != null) {
+ this.breakLabel.resetStateForCodeGeneration();
}
- // generate expression testes
- testExpression.generateCode(currentScope, codeStream, needSwitch);
+ }
- // generate the appropriate switch table
- if (needSwitch) {
- int max = localKeysCopy[caseCount - 1];
- int min = localKeysCopy[0];
- if ((long) (caseCount * 2.5) > ((long) max - (long) min)) {
- codeStream.tableswitch(
- defaultLabel,
- min,
- max,
- constants,
- sortedIndexes,
- caseLabels);
- } else {
- codeStream.lookupswitch(defaultLabel, constants, sortedIndexes, caseLabels);
- }
- codeStream.updateLastRecordedEndPC(codeStream.position);
- }
- // generate the switch block statements
- int caseIndex = 0;
+ public StringBuffer printStatement(int indent, StringBuffer output) {
+
+ printIndent(indent, output).append("switch ("); //$NON-NLS-1$
+ expression.printExpression(0, output).append(") {"); //$NON-NLS-1$
if (statements != null) {
- for (int i = 0, maxCases = statements.length; i < maxCases; i++) {
- Statement statement = statements[i];
- if ((caseIndex < caseCount)
- && (statement == cases[caseIndex])) { // statements[i] is a case
- if (preSwitchInitStateIndex != -1) {
- codeStream.removeNotDefinitelyAssignedVariables(
- currentScope,
- preSwitchInitStateIndex);
- caseIndex++;
- }
+ for (int i = 0; i < statements.length; i++) {
+ output.append('\n');
+ if (statements[i] instanceof CaseStatement) {
+ statements[i].printStatement(indent, output);
} else {
- if (statement == defaultCase) { // statements[i] is a case or a default case
- if (preSwitchInitStateIndex != -1) {
- codeStream.removeNotDefinitelyAssignedVariables(
- currentScope,
- preSwitchInitStateIndex);
- }
- }
+ statements[i].printStatement(indent+2, output);
}
- statement.generateCode(scope, codeStream);
}
}
- // place the trailing labels (for break and default case)
- breakLabel.place();
- if (defaultCase == null) {
- defaultLabel.place();
- }
- // May loose some local variable initializations : affecting the local variable attributes
- if (mergedInitStateIndex != -1) {
- codeStream.removeNotDefinitelyAssignedVariables(
- currentScope,
- mergedInitStateIndex);
- codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
- }
- if (scope != currentScope) {
- codeStream.exitUserScope(scope);
- }
- codeStream.recordPositionsFrom(pc, this.sourceStart);
+ output.append("\n"); //$NON-NLS-1$
+ return printIndent(indent, output).append('}');
}
-
-
- public void resetStateForCodeGeneration() {
-
- this.breakLabel.resetStateForCodeGeneration();
- }
-
public void resolve(BlockScope upperScope) {
- TypeBinding testType = testExpression.resolveType(upperScope);
+ TypeBinding testType = expression.resolveType(upperScope);
if (testType == null)
return;
- testExpression.implicitWidening(testType, testType);
- if (!(testExpression
- .isConstantValueOfTypeAssignableToType(testType, IntBinding))) {
- if (!upperScope.areTypesCompatible(testType, IntBinding)) {
- upperScope.problemReporter().incorrectSwitchType(testExpression, testType);
+ expression.implicitWidening(testType, testType);
+ if (!(expression.isConstantValueOfTypeAssignableToType(testType, IntBinding))) {
+ if (!testType.isCompatibleWith(IntBinding)) {
+ upperScope.problemReporter().incorrectSwitchType(expression, testType);
return;
}
}
scope = explicitDeclarations == 0 ? upperScope : new BlockScope(upperScope);
int length;
// collection of cases is too big but we will only iterate until caseCount
- cases = new Case[length = statements.length];
+ cases = new CaseStatement[length = statements.length];
int[] casesValues = new int[length];
int counter = 0;
for (int i = 0; i < length; i++) {
int key = cst.intValue();
for (int j = 0; j < counter; j++) {
if (casesValues[j] == key) {
- scope.problemReporter().duplicateCase((Case) statements[i], cst);
+ scope.problemReporter().duplicateCase((CaseStatement) statements[i], cst); //TODO: (philippe) could improve diagnosis to indicate colliding case
}
}
casesValues[counter++] = key;
String inFront, s = tabString(tab);
inFront = s;
- s = s + "switch (" + testExpression.toStringExpression() + ") "; //$NON-NLS-1$ //$NON-NLS-2$
+ s = s + "switch (" + expression.toStringExpression() + ") "; //$NON-NLS-1$ //$NON-NLS-2$
if (statements == null) {
s = s + "{}"; //$NON-NLS-1$
return s;
//use instanceof in order not to polluate classes with behavior only needed for printing purpose.
if (statements[i] instanceof Expression)
s = s + "\n" + inFront + tabulation; //$NON-NLS-1$
- if (statements[i] instanceof Break)
+ if (statements[i] instanceof BreakStatement)
s = s + statements[i].toString(0);
else
s = s + "\n" + statements[i].toString(tab + 2); //$NON-NLS-1$
//=============
- if ((statements[i] instanceof Case)
+ if ((statements[i] instanceof CaseStatement)
|| (statements[i] instanceof DefaultCase)) {
i++;
- while (!((statements[i] instanceof Case)
+ while (!((statements[i] instanceof CaseStatement)
|| (statements[i] instanceof DefaultCase))) {
- if ((statements[i] instanceof Expression) || (statements[i] instanceof Break))
+ if ((statements[i] instanceof Expression) || (statements[i] instanceof BreakStatement))
s = s + statements[i].toString(0) + " ; "; //$NON-NLS-1$
else
s = s + "\n" + statements[i].toString(tab + 6) + " ; "; //$NON-NLS-1$ //$NON-NLS-2$
}
public void traverse(
- IAbstractSyntaxTreeVisitor visitor,
+ ASTVisitor visitor,
BlockScope blockScope) {
if (visitor.visit(this, blockScope)) {
- testExpression.traverse(visitor, scope);
+ expression.traverse(visitor, scope);
if (statements != null) {
int statementsLength = statements.length;
for (int i = 0; i < statementsLength; i++)
label.appendForwardReferencesFrom(this.breakLabel);
}
}
-}
\ No newline at end of file
+}