X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SwitchStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SwitchStatement.java index b63fb4f..91984b0 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SwitchStatement.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/SwitchStatement.java @@ -1,28 +1,31 @@ /******************************************************************************* - * 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; @@ -39,31 +42,33 @@ public class SwitchStatement extends Statement { 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; } } } @@ -87,121 +92,147 @@ public class SwitchStatement extends Statement { /** * 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; } } @@ -209,7 +240,7 @@ public class SwitchStatement extends Statement { 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++) { @@ -220,7 +251,7 @@ public class SwitchStatement extends Statement { 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; @@ -233,7 +264,7 @@ public class SwitchStatement extends Statement { 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; @@ -253,17 +284,17 @@ public class SwitchStatement extends Statement { //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$ @@ -281,11 +312,11 @@ public class SwitchStatement extends Statement { } 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++) @@ -309,4 +340,4 @@ public class SwitchStatement extends Statement { label.appendForwardReferencesFrom(this.breakLabel); } } -} \ No newline at end of file +}