Fix bug #672
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / ArrayAllocationExpression.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
12
13 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
14 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
16 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
17 import net.sourceforge.phpdt.internal.compiler.lookup.ArrayBinding;
18 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
19 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
20
21 public class ArrayAllocationExpression extends Expression {
22
23         public TypeReference type;
24
25         // dimensions.length gives the number of dimensions, but the
26         // last ones may be nulled as in new int[4][5][][]
27         public Expression[] dimensions;
28
29         public ArrayInitializer initializer;
30
31         /**
32          * ArrayAllocationExpression constructor comment.
33          */
34         public ArrayAllocationExpression() {
35                 super();
36         }
37
38         public FlowInfo analyseCode(BlockScope currentScope,
39                         FlowContext flowContext, FlowInfo flowInfo) {
40                 for (int i = 0, max = dimensions.length; i < max; i++) {
41                         Expression dim;
42                         if ((dim = dimensions[i]) != null) {
43                                 flowInfo = dim.analyseCode(currentScope, flowContext, flowInfo);
44                         }
45                 }
46                 if (initializer != null) {
47                         return initializer.analyseCode(currentScope, flowContext, flowInfo);
48                 } else {
49                         return flowInfo;
50                 }
51         }
52
53         /**
54          * Code generation for a array allocation expression
55          */
56         // public void generateCode(
57         // BlockScope currentScope,
58         // CodeStream codeStream,
59         // boolean valueRequired) {
60         //
61         // int pc = codeStream.position;
62         //
63         // if (initializer != null) {
64         // initializer.generateCode(currentScope, codeStream, valueRequired);
65         // return;
66         // }
67         //
68         // int nonNullDimensionsLength = 0;
69         // for (int i = 0, max = dimensions.length; i < max; i++)
70         // if (dimensions[i] != null) {
71         // dimensions[i].generateCode(currentScope, codeStream, true);
72         // nonNullDimensionsLength++;
73         // }
74         //
75         // // Generate a sequence of bytecodes corresponding to an array allocation
76         // if (this.resolvedType.dimensions() == 1) {
77         // // Mono-dimensional array
78         // codeStream.newArray(currentScope, (ArrayBinding)this.resolvedType);
79         // } else {
80         // // Multi-dimensional array
81         // codeStream.multianewarray(this.resolvedType, nonNullDimensionsLength);
82         // }
83         //
84         // if (valueRequired) {
85         // codeStream.generateImplicitConversion(implicitConversion);
86         // } else {
87         // codeStream.pop();
88         // }
89         //
90         // codeStream.recordPositionsFrom(pc, this.sourceStart);
91         // }
92         public StringBuffer printExpression(int indent, StringBuffer output) {
93
94                 output.append("new "); //$NON-NLS-1$
95                 type.print(0, output);
96                 for (int i = 0; i < dimensions.length; i++) {
97                         if (dimensions[i] == null)
98                                 output.append("[]"); //$NON-NLS-1$
99                         else {
100                                 output.append('[');
101                                 dimensions[i].printExpression(0, output);
102                                 output.append(']');
103                         }
104                 }
105                 if (initializer != null)
106                         initializer.printExpression(0, output);
107                 return output;
108         }
109
110         public TypeBinding resolveType(BlockScope scope) {
111
112                 // Build an array type reference using the current dimensions
113                 // The parser does not check for the fact that dimension may be null
114                 // only at the -end- like new int [4][][]. The parser allows new
115                 // int[][4][]
116                 // so this must be checked here......(this comes from a reduction to LL1
117                 // grammar)
118
119                 TypeBinding referenceType = type.resolveType(scope);
120
121                 // will check for null after dimensions are checked
122                 constant = Constant.NotAConstant;
123                 if (referenceType == VoidBinding) {
124                         scope.problemReporter().cannotAllocateVoidArray(this);
125                         referenceType = null;
126                 }
127
128                 // check the validity of the dimension syntax (and test for all null
129                 // dimensions)
130                 int explicitDimIndex = -1;
131                 for (int i = dimensions.length; --i >= 0;) {
132                         if (dimensions[i] != null) {
133                                 if (explicitDimIndex < 0)
134                                         explicitDimIndex = i;
135                         } else if (explicitDimIndex > 0) {
136                                 // should not have an empty dimension before an non-empty one
137                                 scope.problemReporter().incorrectLocationForEmptyDimension(
138                                                 this, i);
139                         }
140                 }
141
142                 // explicitDimIndex < 0 says if all dimensions are nulled
143                 // when an initializer is given, no dimension must be specified
144                 if (initializer == null) {
145                         if (explicitDimIndex < 0) {
146                                 scope.problemReporter().mustDefineDimensionsOrInitializer(this);
147                         }
148                 } else if (explicitDimIndex >= 0) {
149                         scope.problemReporter().cannotDefineDimensionsAndInitializer(this);
150                 }
151
152                 // dimensions resolution
153                 for (int i = 0; i <= explicitDimIndex; i++) {
154                         if (dimensions[i] != null) {
155                                 TypeBinding dimensionType = dimensions[i].resolveTypeExpecting(
156                                                 scope, IntBinding);
157                                 if (dimensionType != null) {
158                                         dimensions[i].implicitWidening(IntBinding, dimensionType);
159                                 }
160                         }
161                 }
162
163                 // building the array binding
164                 if (referenceType != null) {
165                         if (dimensions.length > 255) {
166                                 scope.problemReporter().tooManyDimensions(this);
167                         }
168                         this.resolvedType = scope.createArray(referenceType,
169                                         dimensions.length);
170
171                         // check the initializer
172                         if (initializer != null) {
173                                 if ((initializer.resolveTypeExpecting(scope, this.resolvedType)) != null)
174                                         initializer.binding = (ArrayBinding) this.resolvedType;
175                         }
176                 }
177                 return this.resolvedType;
178         }
179
180         public String toStringExpression() {
181
182                 String s = "new " + type.toString(0); //$NON-NLS-1$
183                 for (int i = 0; i < dimensions.length; i++) {
184                         if (dimensions[i] == null)
185                                 s = s + "[]"; //$NON-NLS-1$
186                         else
187                                 s = s + "[" + dimensions[i].toStringExpression() + "]"; //$NON-NLS-2$ //$NON-NLS-1$
188                 }
189                 if (initializer != null)
190                         s = s + initializer.toStringExpression();
191                 return s;
192         }
193
194         public void traverse(ASTVisitor visitor, BlockScope scope) {
195
196                 if (visitor.visit(this, scope)) {
197                         int dimensionsLength = dimensions.length;
198                         type.traverse(visitor, scope);
199                         for (int i = 0; i < dimensionsLength; i++) {
200                                 if (dimensions[i] != null)
201                                         dimensions[i].traverse(visitor, scope);
202                         }
203                         if (initializer != null)
204                                 initializer.traverse(visitor, scope);
205                 }
206                 visitor.endVisit(this, scope);
207         }
208 }