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 91984b0..55cdca7 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 @@ -21,185 +21,213 @@ import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; public class SwitchStatement extends Statement { public Expression expression; + public Statement[] statements; + public BlockScope scope; + public int explicitDeclarations; + public Label breakLabel; + public CaseStatement[] cases; + public DefaultCase defaultCase; + public int caseCount = 0; // for local variables table attributes int preSwitchInitStateIndex = -1; + int mergedInitStateIndex = -1; + /** * SwitchStatement constructor comment. */ public SwitchStatement() { super(); } - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { + + public FlowInfo analyseCode(BlockScope currentScope, + FlowContext flowContext, FlowInfo flowInfo) { flowInfo = expression.analyseCode(currentScope, flowContext, flowInfo); - SwitchFlowContext switchContext = - new SwitchFlowContext(flowContext, this, (breakLabel = new Label())); + SwitchFlowContext switchContext = new SwitchFlowContext(flowContext, + this, (breakLabel = new Label())); - // analyse the block by considering specially the case/default statements (need to bind them + // analyse the block by considering specially the case/default + // statements (need to bind them // to the entry point) FlowInfo caseInits = FlowInfo.DEAD_END; // in case of statements before the first case - preSwitchInitStateIndex = - currentScope.methodScope().recordInitializationStates(flowInfo); + 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])) { // statement is a case + if ((caseIndex < caseCount) && (statement == cases[caseIndex])) { // statement + // is a + // case caseIndex++; - caseInits = caseInits.mergedWith(flowInfo.copy().unconditionalInits()); + 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()); + } else if (statement == defaultCase) { // statement is the + // default case + caseInits = caseInits.mergedWith(flowInfo.copy() + .unconditionalInits()); didAlreadyComplain = false; // reset complaint } - if (!caseInits.complainIfUnreachable(statement, scope, didAlreadyComplain)) { - caseInits = statement.analyseCode(scope, switchContext, caseInits); + if (!caseInits.complainIfUnreachable(statement, scope, + didAlreadyComplain)) { + caseInits = statement.analyseCode(scope, switchContext, + caseInits); } else { didAlreadyComplain = true; } } } - // if no default case, then record it may jump over the block directly to the end + // if no default case, then record it may jump over the block directly + // to the end if (defaultCase == null) { // only retain the potential initializations - flowInfo.addPotentialInitializationsFrom( - caseInits.mergedWith(switchContext.initsOnBreak)); - mergedInitStateIndex = - currentScope.methodScope().recordInitializationStates(flowInfo); + flowInfo.addPotentialInitializationsFrom(caseInits + .mergedWith(switchContext.initsOnBreak)); + mergedInitStateIndex = currentScope.methodScope() + .recordInitializationStates(flowInfo); return flowInfo; } // merge all branches inits FlowInfo mergedInfo = caseInits.mergedWith(switchContext.initsOnBreak); - mergedInitStateIndex = - currentScope.methodScope().recordInitializationStates(mergedInfo); + mergedInitStateIndex = currentScope.methodScope() + .recordInitializationStates(mergedInfo); return mergedInfo; } + /** * Switch code generation - * - * @param currentScope net.sourceforge.phpdt.internal.compiler.lookup.BlockScope - * @param codeStream net.sourceforge.phpdt.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; -// -// // 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); -// } - + // 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); + // } public void resetStateForCodeGeneration() { if (this.breakLabel != null) { @@ -217,41 +245,55 @@ public class SwitchStatement extends Statement { if (statements[i] instanceof CaseStatement) { statements[i].printStatement(indent, output); } else { - statements[i].printStatement(indent+2, output); + statements[i].printStatement(indent + 2, output); } } } output.append("\n"); //$NON-NLS-1$ return printIndent(indent, output).append('}'); } + public void resolve(BlockScope upperScope) { TypeBinding testType = expression.resolveType(upperScope); if (testType == null) return; expression.implicitWidening(testType, testType); - if (!(expression.isConstantValueOfTypeAssignableToType(testType, IntBinding))) { + if (!(expression.isConstantValueOfTypeAssignableToType(testType, + IntBinding))) { if (!testType.isCompatibleWith(IntBinding)) { - upperScope.problemReporter().incorrectSwitchType(expression, testType); + upperScope.problemReporter().incorrectSwitchType(expression, + testType); return; } } if (statements != null) { - scope = explicitDeclarations == 0 ? upperScope : new BlockScope(upperScope); + scope = explicitDeclarations == 0 ? upperScope : new BlockScope( + upperScope); int length; - // collection of cases is too big but we will only iterate until caseCount + // collection of cases is too big but we will only iterate until + // caseCount cases = new CaseStatement[length = statements.length]; int[] casesValues = new int[length]; int counter = 0; for (int i = 0; i < length; i++) { Constant cst; if ((cst = statements[i].resolveCase(scope, testType, this)) != null) { - //----check for duplicate case statement------------ + // ----check for duplicate case statement------------ if (cst != NotAConstant) { int key = cst.intValue(); for (int j = 0; j < counter; j++) { if (casesValues[j] == key) { - scope.problemReporter().duplicateCase((CaseStatement) statements[i], cst); //TODO: (philippe) could improve diagnosis to indicate colliding case + scope.problemReporter().duplicateCase( + (CaseStatement) statements[i], cst); // TODO: + // (philippe) + // could + // improve + // diagnosis + // to + // indicate + // colliding + // case } } casesValues[counter++] = key; @@ -260,6 +302,7 @@ public class SwitchStatement extends Statement { } } } + public String toString(int tab) { String inFront, s = tabString(tab); @@ -270,34 +313,35 @@ public class SwitchStatement extends Statement { return s; } else s = s + "{"; //$NON-NLS-1$ - s = s - + (explicitDeclarations != 0 - ? "// ---scope needed for " //$NON-NLS-1$ - + String.valueOf(explicitDeclarations) - + " locals------------ \n"//$NON-NLS-1$ - : "// ---NO scope needed------ \n"); //$NON-NLS-1$ + s = s + + (explicitDeclarations != 0 ? "// ---scope needed for " //$NON-NLS-1$ + + String.valueOf(explicitDeclarations) + + " locals------------ \n"//$NON-NLS-1$ + : "// ---NO scope needed------ \n"); //$NON-NLS-1$ int i = 0; String tabulation = " "; //$NON-NLS-1$ try { while (true) { - //use instanceof in order not to polluate classes with behavior only needed for printing purpose. + // 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 BreakStatement) s = s + statements[i].toString(0); else s = s + "\n" + statements[i].toString(tab + 2); //$NON-NLS-1$ - //============= + // ============= if ((statements[i] instanceof CaseStatement) - || (statements[i] instanceof DefaultCase)) { + || (statements[i] instanceof DefaultCase)) { i++; - while (!((statements[i] instanceof CaseStatement) - || (statements[i] instanceof DefaultCase))) { - if ((statements[i] instanceof Expression) || (statements[i] instanceof BreakStatement)) + while (!((statements[i] instanceof CaseStatement) || (statements[i] instanceof DefaultCase))) { + 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$ + s = s + + "\n" + statements[i].toString(tab + 6) + " ; "; //$NON-NLS-1$ //$NON-NLS-2$ i++; } } else { @@ -306,14 +350,13 @@ public class SwitchStatement extends Statement { } } } catch (IndexOutOfBoundsException e) { - }; + } + ; s = s + "}"; //$NON-NLS-1$ return s; } - public void traverse( - ASTVisitor visitor, - BlockScope blockScope) { + public void traverse(ASTVisitor visitor, BlockScope blockScope) { if (visitor.visit(this, blockScope)) { expression.traverse(visitor, scope); @@ -325,12 +368,12 @@ public class SwitchStatement extends Statement { } visitor.endVisit(this, blockScope); } - + /** * Dispatch the call on its last statement. */ public void branchChainTo(Label label) { - + // in order to improve debug attributes for stepping (11431) // we want to inline the jumps to #breakLabel which already got // generated (if any), and have them directly branch to a better