001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.ast;
011:
012: import org.eclipse.jdt.internal.compiler.codegen.*;
013: import org.eclipse.jdt.internal.compiler.flow.*;
014: import org.eclipse.jdt.internal.compiler.impl.Constant;
015: import org.eclipse.jdt.internal.compiler.lookup.*;
016:
017: public abstract class Statement extends ASTNode {
018:
019: public abstract FlowInfo analyseCode(BlockScope currentScope,
020: FlowContext flowContext, FlowInfo flowInfo);
021:
022: /**
023: * INTERNAL USE ONLY.
024: * This is used to redirect inter-statements jumps.
025: */
026: public void branchChainTo(BranchLabel label) {
027: // do nothing by default
028: }
029:
030: // Report an error if necessary
031: public boolean complainIfUnreachable(FlowInfo flowInfo,
032: BlockScope scope, boolean didAlreadyComplain) {
033:
034: if ((flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0) {
035: this .bits &= ~ASTNode.IsReachable;
036: boolean reported = flowInfo == FlowInfo.DEAD_END;
037: if (!didAlreadyComplain && reported) {
038: scope.problemReporter().unreachableCode(this );
039: }
040: return reported; // keep going for fake reachable
041: }
042: return false;
043: }
044:
045: /**
046: * Generate invocation arguments, considering varargs methods
047: */
048: public void generateArguments(MethodBinding binding,
049: Expression[] arguments, BlockScope currentScope,
050: CodeStream codeStream) {
051:
052: if (binding.isVarargs()) {
053: // 5 possibilities exist for a call to the vararg method foo(int i, int ... value) :
054: // foo(1), foo(1, null), foo(1, 2), foo(1, 2, 3, 4) & foo(1, new int[] {1, 2})
055: TypeBinding[] params = binding.parameters;
056: int paramLength = params.length;
057: int varArgIndex = paramLength - 1;
058: for (int i = 0; i < varArgIndex; i++) {
059: arguments[i].generateCode(currentScope, codeStream,
060: true);
061: }
062:
063: ArrayBinding varArgsType = (ArrayBinding) params[varArgIndex]; // parameterType has to be an array type
064: ArrayBinding codeGenVarArgsType = (ArrayBinding) binding.parameters[varArgIndex]
065: .erasure();
066: int elementsTypeID = varArgsType.elementsType().id;
067: int argLength = arguments == null ? 0 : arguments.length;
068:
069: if (argLength > paramLength) {
070: // right number but not directly compatible or too many arguments - wrap extra into array
071: // called with (argLength - lastIndex) elements : foo(1, 2) or foo(1, 2, 3, 4)
072: // need to gen elements into an array, then gen each remaining element into created array
073: codeStream
074: .generateInlinedValue(argLength - varArgIndex);
075: codeStream.newArray(codeGenVarArgsType); // create a mono-dimensional array
076: for (int i = varArgIndex; i < argLength; i++) {
077: codeStream.dup();
078: codeStream.generateInlinedValue(i - varArgIndex);
079: arguments[i].generateCode(currentScope, codeStream,
080: true);
081: codeStream.arrayAtPut(elementsTypeID, false);
082: }
083: } else if (argLength == paramLength) {
084: // right number of arguments - could be inexact - pass argument as is
085: TypeBinding lastType = arguments[varArgIndex].resolvedType;
086: if (lastType == TypeBinding.NULL
087: || (varArgsType.dimensions() == lastType
088: .dimensions() && lastType
089: .isCompatibleWith(varArgsType))) {
090: // foo(1, new int[]{2, 3}) or foo(1, null) --> last arg is passed as-is
091: arguments[varArgIndex].generateCode(currentScope,
092: codeStream, true);
093: } else {
094: // right number but not directly compatible or too many arguments - wrap extra into array
095: // need to gen elements into an array, then gen each remaining element into created array
096: codeStream.generateInlinedValue(1);
097: codeStream.newArray(codeGenVarArgsType); // create a mono-dimensional array
098: codeStream.dup();
099: codeStream.generateInlinedValue(0);
100: arguments[varArgIndex].generateCode(currentScope,
101: codeStream, true);
102: codeStream.arrayAtPut(elementsTypeID, false);
103: }
104: } else { // not enough arguments - pass extra empty array
105: // scenario: foo(1) --> foo(1, new int[0])
106: // generate code for an empty array of parameterType
107: codeStream.generateInlinedValue(0);
108: codeStream.newArray(codeGenVarArgsType); // create a mono-dimensional array
109: }
110: } else if (arguments != null) { // standard generation for method arguments
111: for (int i = 0, max = arguments.length; i < max; i++)
112: arguments[i].generateCode(currentScope, codeStream,
113: true);
114: }
115: }
116:
117: public abstract void generateCode(BlockScope currentScope,
118: CodeStream codeStream);
119:
120: public boolean isEmptyBlock() {
121: return false;
122: }
123:
124: public boolean isValidJavaStatement() {
125: //the use of this method should be avoid in most cases
126: //and is here mostly for documentation purpose.....
127: //while the parser is responsable for creating
128: //welled formed expression statement, which results
129: //in the fact that java-non-semantic-expression-used-as-statement
130: //should not be parsable...thus not being built.
131: //It sounds like the java grammar as help the compiler job in removing
132: //-by construction- some statement that would have no effect....
133: //(for example all expression that may do side-effects are valid statement
134: // -this is an appromative idea.....-)
135:
136: return true;
137: }
138:
139: public StringBuffer print(int indent, StringBuffer output) {
140: return printStatement(indent, output);
141: }
142:
143: public abstract StringBuffer printStatement(int indent,
144: StringBuffer output);
145:
146: public abstract void resolve(BlockScope scope);
147:
148: /**
149: * Returns case constant associated to this statement (NotAConstant if none)
150: */
151: public Constant resolveCase(BlockScope scope, TypeBinding testType,
152: SwitchStatement switchStatement) {
153: // statement within a switch that are not case are treated as normal statement....
154:
155: resolve(scope);
156: return Constant.NotAConstant;
157: }
158:
159: }
|