e9054fa37a35934ade208b118a81ab19949be8b8
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / ArrayInitializer.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.NullConstant;
18 import net.sourceforge.phpdt.internal.compiler.lookup.ArrayBinding;
19 import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypeBinding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
21 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
22
23 public class ArrayInitializer extends Expression {
24         public Expression[] expressions;
25         public ArrayBinding binding; //the type of the { , , , }
26
27 /**
28  * ArrayInitializer constructor comment.
29  */
30 public ArrayInitializer() {
31         super();
32 }
33 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
34         if (expressions != null) {
35                 for (int i = 0, max = expressions.length; i < max; i++) {
36                         flowInfo = expressions[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
37                 }
38         }
39         return flowInfo;
40 }
41 /**
42  * Code generation for a array initializer
43  */
44 public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
45         // Flatten the values and compute the dimensions, by iterating in depth into nested array initializers
46
47         int pc = codeStream.position;
48         int expressionLength = (expressions == null) ? 0: expressions.length;
49         codeStream.generateInlinedValue(expressionLength);
50         codeStream.newArray(currentScope, binding);
51         if (expressions != null) {
52                 // binding is an ArrayType, so I can just deal with the dimension
53                 int elementsTypeID = binding.dimensions > 1 ? -1 : binding.leafComponentType.id;
54                 for (int i = 0; i < expressionLength; i++) {
55                         Expression expr;
56                         if ((expr = expressions[i]).constant != NotAConstant) {
57                                 switch (elementsTypeID) { // filter out initializations to default values
58                                         case T_int :
59                                         case T_short :
60                                         case T_byte :
61                                         case T_char :
62                                         case T_float :
63                                         case T_long :
64                                         case T_double :
65                                                 if (expr.constant.doubleValue() != 0) {
66                                                         codeStream.dup();
67                                                         codeStream.generateInlinedValue(i);
68                                                         expr.generateCode(currentScope, codeStream, true);
69                                                         codeStream.arrayAtPut(elementsTypeID, false);
70                                                 }
71                                                 break;
72                                         case T_boolean :
73                                                 if (expr.constant.booleanValue() != false) {
74                                                         codeStream.dup();
75                                                         codeStream.generateInlinedValue(i);
76                                                         expr.generateCode(currentScope, codeStream, true);
77                                                         codeStream.arrayAtPut(elementsTypeID, false);
78                                                 }
79                                                 break;
80                                         default :
81                                                 if (expr.constant != NullConstant.Default) {
82                                                         codeStream.dup();
83                                                         codeStream.generateInlinedValue(i);
84                                                         expr.generateCode(currentScope, codeStream, true);
85                                                         codeStream.arrayAtPut(elementsTypeID, false);
86                                                 }
87                                 }
88                         } else {
89                                 codeStream.dup();
90                                 codeStream.generateInlinedValue(i);
91                                 expr.generateCode(currentScope, codeStream, true);
92                                 codeStream.arrayAtPut(elementsTypeID, false);
93                         }
94                 }
95         }
96         if (!valueRequired) {
97                 codeStream.pop();
98         }
99         codeStream.recordPositionsFrom(pc, this.sourceStart);
100 }
101 public TypeBinding resolveTypeExpecting(BlockScope scope, TypeBinding expectedTb) {
102         // Array initializers can only occur on the right hand side of an assignment
103         // expression, therefore the expected type contains the valid information
104         // concerning the type that must be enforced by the elements of the array initializer.
105
106         // this method is recursive... (the test on isArrayType is the stop case)
107
108         constant = NotAConstant;
109         if (expectedTb.isArrayType()) {
110                 binding = (ArrayBinding) expectedTb;
111                 if (expressions == null)
112                         return binding;
113                 TypeBinding expectedElementsTb = binding.elementsType(scope);
114                 if (expectedElementsTb.isBaseType()) {
115                         for (int i = 0, length = expressions.length; i < length; i++) {
116                                 Expression expression = expressions[i];
117                                 TypeBinding expressionTb =
118                                         (expression instanceof ArrayInitializer)
119                                                 ? expression.resolveTypeExpecting(scope, expectedElementsTb)
120                                                 : expression.resolveType(scope);
121                                 if (expressionTb == null)
122                                         return null;
123
124                                 // Compile-time conversion required?
125                                 if (expression.isConstantValueOfTypeAssignableToType(expressionTb, expectedElementsTb)) {
126                                         expression.implicitWidening(expectedElementsTb, expressionTb);
127                                 } else if (BaseTypeBinding.isWidening(expectedElementsTb.id, expressionTb.id)) {
128                                         expression.implicitWidening(expectedElementsTb, expressionTb);
129                                 } else {
130                                         scope.problemReporter().typeMismatchErrorActualTypeExpectedType(expression, expressionTb, expectedElementsTb);
131                                         return null;
132                                 }
133                         }
134                 } else {
135                         for (int i = 0, length = expressions.length; i < length; i++)
136                                 if (expressions[i].resolveTypeExpecting(scope, expectedElementsTb) == null)
137                                         return null;
138                 }
139                 return binding;
140         }
141         
142         // infer initializer type for error reporting based on first element
143         TypeBinding leafElementType = null;
144         int dim = 1;
145         if (expressions == null) {
146                 leafElementType = scope.getJavaLangObject();
147         } else {
148                 Expression currentExpression = expressions[0];
149                 while(currentExpression != null && currentExpression instanceof ArrayInitializer) {
150                         dim++;
151                         Expression[] subExprs = ((ArrayInitializer) currentExpression).expressions;
152                         if (subExprs == null){
153                                 leafElementType = scope.getJavaLangObject();
154                                 currentExpression = null;
155                                 break;
156                         }
157                         currentExpression = ((ArrayInitializer) currentExpression).expressions[0];
158                 }
159                 if (currentExpression != null) {
160                         leafElementType = currentExpression.resolveType(scope);
161                 }
162         }
163         if (leafElementType != null) {
164                 TypeBinding probableTb = scope.createArray(leafElementType, dim);
165                 scope.problemReporter().typeMismatchErrorActualTypeExpectedType(this, probableTb, expectedTb);
166         }
167         return null;
168 }
169 public String toStringExpression() {
170
171         String s = "{" ; //$NON-NLS-1$
172         if (expressions != null)
173         {       int j = 20 ; 
174                 for (int i = 0 ; i < expressions.length ; i++)
175                 {       s = s + expressions[i].toStringExpression() + "," ; //$NON-NLS-1$
176                         j -- ;
177                         if (j == 0)
178                         {       s = s + "\n                "; j = 20;}}}; //$NON-NLS-1$
179         s = s + "}"; //$NON-NLS-1$
180         return s;}
181
182 public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
183         if (visitor.visit(this, scope)) {
184                 if (expressions != null) {
185                         int expressionsLength = expressions.length;
186                         for (int i = 0; i < expressionsLength; i++)
187                                 expressions[i].traverse(visitor, scope);
188                 }
189         }
190         visitor.endVisit(this, scope);
191 }
192 }