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..5de7507 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,312 +1,67 @@ -/******************************************************************************* - * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v0.5 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v05.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 java.util.List; +/** + * @author Matthieu Casanova + */ public class SwitchStatement extends Statement { - public Expression testExpression; - public Statement[] statements; - public BlockScope scope; - public int explicitDeclarations; - public Label breakLabel; - public Case[] 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) { - flowInfo = testExpression.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; - // in case of statements before the first case - preSwitchInitStateIndex = - currentScope.methodScope().recordInitializationStates(flowInfo); - int caseIndex = 0; - if (statements != null) { - 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 - caseIndex++; - caseInits = caseInits.mergedWith(flowInfo.copy().unconditionalInits()); - } else { - if (statement == defaultCase) { - caseInits = caseInits.mergedWith(flowInfo.copy().unconditionalInits()); - } - } - if (!caseInits.complainIfUnreachable(statement, scope)) { - caseInits = statement.analyseCode(scope, switchContext, caseInits); - } - } - } - - // 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); - return flowInfo; - } - - // merge all branches inits - FlowInfo mergedInfo = caseInits.mergedWith(switchContext.initsOnBreak); - mergedInitStateIndex = - currentScope.methodScope().recordInitializationStates(mergedInfo); - return mergedInfo; - } - /** - * Switch code generation - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.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 - 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; - 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() { - - this.breakLabel.resetStateForCodeGeneration(); - } - - public void resolve(BlockScope upperScope) { - - TypeBinding testType = testExpression.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); - return; - } - } - if (statements != null) { - 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]; - 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------------ - if (cst != NotAConstant) { - int key = cst.intValue(); - for (int j = 0; j < counter; j++) { - if (casesValues[j] == key) { - scope.problemReporter().duplicateCase((Case) statements[i], cst); - } - } - casesValues[counter++] = key; - } - } - } - } - } - public String toString(int tab) { - - String inFront, s = tabString(tab); - inFront = s; - s = s + "switch (" + testExpression.toStringExpression() + ") "; //$NON-NLS-1$ //$NON-NLS-2$ - if (statements == null) { - s = s + "{}"; //$NON-NLS-1$ - 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$ - - 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. - if (statements[i] instanceof Expression) - s = s + "\n" + inFront + tabulation; //$NON-NLS-1$ - if (statements[i] instanceof Break) - s = s + statements[i].toString(0); - else - s = s + "\n" + statements[i].toString(tab + 2); //$NON-NLS-1$ - //============= - if ((statements[i] instanceof Case) - || (statements[i] instanceof DefaultCase)) { - i++; - while (!((statements[i] instanceof Case) - || (statements[i] instanceof DefaultCase))) { - if ((statements[i] instanceof Expression) || (statements[i] instanceof Break)) - s = s + statements[i].toString(0) + " ; "; //$NON-NLS-1$ - else - s = s + "\n" + statements[i].toString(tab + 6) + " ; "; //$NON-NLS-1$ //$NON-NLS-2$ - i++; - } - } else { - s = s + " ;"; //$NON-NLS-1$ - i++; - } - } - } catch (IndexOutOfBoundsException e) { - }; - s = s + "}"; //$NON-NLS-1$ - return s; - } - - public void traverse( - IAbstractSyntaxTreeVisitor visitor, - BlockScope blockScope) { - - if (visitor.visit(this, blockScope)) { - testExpression.traverse(visitor, scope); - if (statements != null) { - int statementsLength = statements.length; - for (int i = 0; i < statementsLength; i++) - statements[i].traverse(visitor, scope); - } - } - 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 - // location (the argument label). - // we know at this point that the breakLabel already got placed - if (this.breakLabel.hasForwardReferences()) { - label.appendForwardReferencesFrom(this.breakLabel); - } - } -} \ No newline at end of file + public Expression variable; + public AbstractCase[] cases; + + public SwitchStatement(final Expression variable, + final AbstractCase[] cases, + final int sourceStart, + final int sourceEnd) { + super(sourceStart, sourceEnd); + this.variable = variable; + this.cases = cases; + } + + /** + * Return the object into String. + * @param tab how many tabs (not used here + * @return a String + */ + public String toString(final int tab) { + final StringBuffer buff = new StringBuffer(tabString(tab)); + buff.append("switch (").append(variable.toStringExpression()).append(") {\n"); + for (int i = 0; i < cases.length; i++) { + final AbstractCase cas = cases[i]; + buff.append(cas.toString(tab + 1)); + buff.append('\n'); + } + buff.append('}'); + return buff.toString(); + } + + /** + * Get the variables from outside (parameters, globals ...) + */ + public void getOutsideVariable(final List list) { + for (int i = 0; i < cases.length; i++) { + cases[i].getOutsideVariable(list); + } + } + + /** + * get the modified variables. + */ + public void getModifiedVariable(final List list) { + for (int i = 0; i < cases.length; i++) { + cases[i].getModifiedVariable(list); + } + variable.getModifiedVariable(list); + } + + /** + * Get the variables used. + */ + public void getUsedVariable(final List list) { + for (int i = 0; i < cases.length; i++) { + cases[i].getUsedVariable(list); + } + variable.getUsedVariable(list); + } +}