code-template needs new context type
[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.IAbstractSyntaxTreeVisitor;
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
95         public TypeBinding resolveType(BlockScope scope) {
96
97                 // Build an array type reference using the current dimensions
98                 // The parser does not check for the fact that dimension may be null
99                 // only at the -end- like new int [4][][]. The parser allows new int[][4][]
100                 // so this must be checked here......(this comes from a reduction to LL1 grammar)
101
102                 TypeBinding referenceType = type.resolveType(scope);
103                 
104                 // will check for null after dimensions are checked
105                 constant = Constant.NotAConstant;
106                 if (referenceType == VoidBinding) {
107                         scope.problemReporter().cannotAllocateVoidArray(this);
108                         referenceType = null;
109                 }
110
111                 // check the validity of the dimension syntax (and test for all null dimensions)
112                 int explicitDimIndex = -1;
113                 for (int i = dimensions.length; --i >= 0;) {
114                         if (dimensions[i] != null) {
115                                 if (explicitDimIndex < 0) explicitDimIndex = i;
116                         } else if (explicitDimIndex> 0) {
117                                 // should not have an empty dimension before an non-empty one
118                                 scope.problemReporter().incorrectLocationForEmptyDimension(this, i);
119                         }
120                 }
121
122                 // explicitDimIndex < 0 says if all dimensions are nulled
123                 // when an initializer is given, no dimension must be specified
124                 if (initializer == null) {
125                         if (explicitDimIndex < 0) {
126                                 scope.problemReporter().mustDefineDimensionsOrInitializer(this);
127                         }
128                 } else if (explicitDimIndex >= 0) {
129                         scope.problemReporter().cannotDefineDimensionsAndInitializer(this);
130                 }
131
132                 // dimensions resolution 
133                 for (int i = 0; i <= explicitDimIndex; i++) {
134                         if (dimensions[i] != null) {
135                                 TypeBinding dimensionType = dimensions[i].resolveTypeExpecting(scope, IntBinding);
136                                 if (dimensionType != null) {
137                                         dimensions[i].implicitWidening(IntBinding, dimensionType);
138                                 }
139                         }
140                 }
141
142                 // building the array binding
143                 if (referenceType != null) {
144                         if (dimensions.length > 255) {
145                                 scope.problemReporter().tooManyDimensions(this);
146                         }
147                         this.resolvedType = scope.createArray(referenceType, dimensions.length);
148
149                         // check the initializer
150                         if (initializer != null) {
151                                 if ((initializer.resolveTypeExpecting(scope, this.resolvedType)) != null)
152                                         initializer.binding = (ArrayBinding)this.resolvedType;
153                         }
154                 }
155                 return this.resolvedType;
156         }
157
158         public String toStringExpression() {
159
160                 String s = "new " + type.toString(0); //$NON-NLS-1$
161                 for (int i = 0; i < dimensions.length; i++) {
162                         if (dimensions[i] == null)
163                                 s = s + "[]"; //$NON-NLS-1$
164                         else
165                                 s = s + "[" + dimensions[i].toStringExpression() + "]"; //$NON-NLS-2$ //$NON-NLS-1$
166                 } 
167                 if (initializer != null)
168                         s = s + initializer.toStringExpression();
169                 return s;
170         }
171
172         public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
173
174                 if (visitor.visit(this, scope)) {
175                         int dimensionsLength = dimensions.length;
176                         type.traverse(visitor, scope);
177                         for (int i = 0; i < dimensionsLength; i++) {
178                                 if (dimensions[i] != null)
179                                         dimensions[i].traverse(visitor, scope);
180                         }
181                         if (initializer != null)
182                                 initializer.traverse(visitor, scope);
183                 }
184                 visitor.endVisit(this, scope);
185         }
186 }