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