improved PHP parser
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / 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.phpeclipse.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
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         /**
32          * ArrayAllocationExpression constructor comment.
33          */
34         public ArrayAllocationExpression() {
35                 super();
36         }
37
38         public FlowInfo analyseCode(
39                 BlockScope currentScope,
40                 FlowContext flowContext,
41                 FlowInfo flowInfo) {
42                 for (int i = 0, max = dimensions.length; i < max; i++) {
43                         Expression dim;
44                         if ((dim = dimensions[i]) != null) {
45                                 flowInfo = dim.analyseCode(currentScope, flowContext, flowInfo);
46                         }
47                 }
48                 if (initializer != null) {
49                         return initializer.analyseCode(currentScope, flowContext, flowInfo);
50                 } else {
51                         return flowInfo;
52                 }
53         }
54
55         /**
56          * Code generation for a array allocation expression
57          */
58 //      public void generateCode(
59 //              BlockScope currentScope,
60 //              CodeStream codeStream,
61 //              boolean valueRequired) {
62 //
63 //              int pc = codeStream.position;
64 //
65 //              if (initializer != null) {
66 //                      initializer.generateCode(currentScope, codeStream, valueRequired);
67 //                      return;
68 //              }
69 //
70 //              int nonNullDimensionsLength = 0;
71 //              for (int i = 0, max = dimensions.length; i < max; i++)
72 //                      if (dimensions[i] != null) {
73 //                              dimensions[i].generateCode(currentScope, codeStream, true);
74 //                              nonNullDimensionsLength++;
75 //                      }
76 //
77 //              // Generate a sequence of bytecodes corresponding to an array allocation
78 //              if (this.resolvedType.dimensions() == 1) {
79 //                      // Mono-dimensional array
80 //                      codeStream.newArray(currentScope, (ArrayBinding)this.resolvedType);
81 //              } else {
82 //                      // Multi-dimensional array
83 //                      codeStream.multianewarray(this.resolvedType, nonNullDimensionsLength);
84 //              }
85 //
86 //              if (valueRequired) {
87 //                      codeStream.generateImplicitConversion(implicitConversion);
88 //              } else {
89 //                      codeStream.pop();
90 //              }
91 //
92 //              codeStream.recordPositionsFrom(pc, this.sourceStart);
93 //      }
94         public StringBuffer printExpression(int indent, StringBuffer output) {
95
96                 output.append("new "); //$NON-NLS-1$
97                 type.print(0, output); 
98                 for (int i = 0; i < dimensions.length; i++) {
99                         if (dimensions[i] == null)
100                                 output.append("[]"); //$NON-NLS-1$
101                         else {
102                                 output.append('[');
103                                 dimensions[i].printExpression(0, output);
104                                 output.append(']');
105                         }
106                 } 
107                 if (initializer != null) initializer.printExpression(0, output);
108                 return output;
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 int[][4][]
115                 // so this must be checked here......(this comes from a reduction to LL1 grammar)
116
117                 TypeBinding referenceType = type.resolveType(scope);
118                 
119                 // will check for null after dimensions are checked
120                 constant = Constant.NotAConstant;
121                 if (referenceType == VoidBinding) {
122                         scope.problemReporter().cannotAllocateVoidArray(this);
123                         referenceType = null;
124                 }
125
126                 // check the validity of the dimension syntax (and test for all null dimensions)
127                 int explicitDimIndex = -1;
128                 for (int i = dimensions.length; --i >= 0;) {
129                         if (dimensions[i] != null) {
130                                 if (explicitDimIndex < 0) explicitDimIndex = i;
131                         } else if (explicitDimIndex> 0) {
132                                 // should not have an empty dimension before an non-empty one
133                                 scope.problemReporter().incorrectLocationForEmptyDimension(this, i);
134                         }
135                 }
136
137                 // explicitDimIndex < 0 says if all dimensions are nulled
138                 // when an initializer is given, no dimension must be specified
139                 if (initializer == null) {
140                         if (explicitDimIndex < 0) {
141                                 scope.problemReporter().mustDefineDimensionsOrInitializer(this);
142                         }
143                 } else if (explicitDimIndex >= 0) {
144                         scope.problemReporter().cannotDefineDimensionsAndInitializer(this);
145                 }
146
147                 // dimensions resolution 
148                 for (int i = 0; i <= explicitDimIndex; i++) {
149                         if (dimensions[i] != null) {
150                                 TypeBinding dimensionType = dimensions[i].resolveTypeExpecting(scope, IntBinding);
151                                 if (dimensionType != null) {
152                                         dimensions[i].implicitWidening(IntBinding, dimensionType);
153                                 }
154                         }
155                 }
156
157                 // building the array binding
158                 if (referenceType != null) {
159                         if (dimensions.length > 255) {
160                                 scope.problemReporter().tooManyDimensions(this);
161                         }
162                         this.resolvedType = scope.createArray(referenceType, dimensions.length);
163
164                         // check the initializer
165                         if (initializer != null) {
166                                 if ((initializer.resolveTypeExpecting(scope, this.resolvedType)) != null)
167                                         initializer.binding = (ArrayBinding)this.resolvedType;
168                         }
169                 }
170                 return this.resolvedType;
171         }
172
173         public String toStringExpression() {
174
175                 String s = "new " + type.toString(0); //$NON-NLS-1$
176                 for (int i = 0; i < dimensions.length; i++) {
177                         if (dimensions[i] == null)
178                                 s = s + "[]"; //$NON-NLS-1$
179                         else
180                                 s = s + "[" + dimensions[i].toStringExpression() + "]"; //$NON-NLS-2$ //$NON-NLS-1$
181                 } 
182                 if (initializer != null)
183                         s = s + initializer.toStringExpression();
184                 return s;
185         }
186
187         public void traverse(ASTVisitor visitor, BlockScope scope) {
188
189                 if (visitor.visit(this, scope)) {
190                         int dimensionsLength = dimensions.length;
191                         type.traverse(visitor, scope);
192                         for (int i = 0; i < dimensionsLength; i++) {
193                                 if (dimensions[i] != null)
194                                         dimensions[i].traverse(visitor, scope);
195                         }
196                         if (initializer != null)
197                                 initializer.traverse(visitor, scope);
198                 }
199                 visitor.endVisit(this, scope);
200         }
201 }