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