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