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