Fix #1475484 - code formatter: bad result for array() embedding func calls
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / UnaryExpression.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.phpdt.internal.compiler.ast;
12
13 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
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.BlockScope;
18 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
19
20 public class UnaryExpression extends OperatorExpression {
21
22         public Expression expression;
23
24         public Constant optimizedBooleanConstant;
25
26         public UnaryExpression(Expression expression, int operator) {
27                 this.expression = expression;
28                 this.bits |= operator << OperatorSHIFT; // encode operator
29         }
30
31         public FlowInfo analyseCode(BlockScope currentScope,
32                         FlowContext flowContext, FlowInfo flowInfo) {
33
34                 if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
35                         return this.expression.analyseCode(currentScope, flowContext,
36                                         flowInfo).asNegatedCondition();
37                 } else {
38                         return this.expression.analyseCode(currentScope, flowContext,
39                                         flowInfo);
40                 }
41         }
42
43         public Constant optimizedBooleanConstant() {
44
45                 return this.optimizedBooleanConstant == null ? this.constant
46                                 : this.optimizedBooleanConstant;
47         }
48
49         /**
50          * Code generation for an unary operation
51          * 
52          * @param currentScope
53          *            net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
54          * @param codeStream
55          *            net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
56          * @param valueRequired
57          *            boolean
58          */
59         // public void generateCode(
60         // BlockScope currentScope,
61         // CodeStream codeStream,
62         // boolean valueRequired) {
63         //                      
64         // int pc = codeStream.position;
65         // Label falseLabel, endifLabel;
66         // if (this.constant != Constant.NotAConstant) {
67         // // inlined value
68         // if (valueRequired) {
69         // codeStream.generateConstant(this.constant, this.implicitConversion);
70         // }
71         // codeStream.recordPositionsFrom(pc, this.sourceStart);
72         // return;
73         // }
74         // switch ((bits & OperatorMASK) >> OperatorSHIFT) {
75         // case NOT :
76         // switch (this.expression.implicitConversion >> 4) /* runtime type */ {
77         // case T_boolean :
78         // // ! <boolean>
79         // // Generate code for the condition
80         // this.expression.generateOptimizedBoolean(
81         // currentScope,
82         // codeStream,
83         // null,
84         // (falseLabel = new Label(codeStream)),
85         // valueRequired);
86         // if (valueRequired) {
87         // codeStream.iconst_0();
88         // if (falseLabel.hasForwardReferences()) {
89         // codeStream.goto_(endifLabel = new Label(codeStream));
90         // codeStream.decrStackSize(1);
91         // falseLabel.place();
92         // codeStream.iconst_1();
93         // endifLabel.place();
94         // }
95         // } else { // 6596: if (!(a && b)){} - must still place falseLabel
96         // falseLabel.place();
97         // }
98         // break;
99         // }
100         // break;
101         // case TWIDDLE :
102         // switch (this.expression.implicitConversion >> 4 /* runtime */
103         // ) {
104         // case T_int :
105         // // ~int
106         // this.expression.generateCode(currentScope, codeStream, valueRequired);
107         // if (valueRequired) {
108         // codeStream.iconst_m1();
109         // codeStream.ixor();
110         // }
111         // break;
112         // case T_long :
113         // this.expression.generateCode(currentScope, codeStream, valueRequired);
114         // if (valueRequired) {
115         // codeStream.ldc2_w(-1L);
116         // codeStream.lxor();
117         // }
118         // }
119         // break;
120         // case MINUS :
121         // // - <num>
122         // if (this.constant != NotAConstant) {
123         // if (valueRequired) {
124         // switch (this.expression.implicitConversion >> 4){ /* runtime */
125         // case T_int :
126         // codeStream.generateInlinedValue(this.constant.intValue() * -1);
127         // break;
128         // case T_float :
129         // codeStream.generateInlinedValue(this.constant.floatValue() * -1.0f);
130         // break;
131         // case T_long :
132         // codeStream.generateInlinedValue(this.constant.longValue() * -1L);
133         // break;
134         // case T_double :
135         // codeStream.generateInlinedValue(this.constant.doubleValue() * -1.0);
136         // }
137         // }
138         // } else {
139         // this.expression.generateCode(currentScope, codeStream, valueRequired);
140         // if (valueRequired) {
141         // switch (expression.implicitConversion >> 4){ /* runtime type */
142         // case T_int :
143         // codeStream.ineg();
144         // break;
145         // case T_float :
146         // codeStream.fneg();
147         // break;
148         // case T_long :
149         // codeStream.lneg();
150         // break;
151         // case T_double :
152         // codeStream.dneg();
153         // }
154         // }
155         // }
156         // break;
157         // case PLUS :
158         // this.expression.generateCode(currentScope, codeStream, valueRequired);
159         // }
160         // if (valueRequired) {
161         // codeStream.generateImplicitConversion(this.implicitConversion);
162         // }
163         // codeStream.recordPositionsFrom(pc, this.sourceStart);
164         // }
165         //
166         // /**
167         // * Boolean operator code generation
168         // * Optimized operations are: &&, ||, <, <=, >, >=, &, |, ^
169         // */
170         // public void generateOptimizedBoolean(
171         // BlockScope currentScope,
172         // CodeStream codeStream,
173         // Label trueLabel,
174         // Label falseLabel,
175         // boolean valueRequired) {
176         //
177         // if ((this.constant != Constant.NotAConstant) && (this.constant.typeID()
178         // == T_boolean)) {
179         // super.generateOptimizedBoolean(
180         // currentScope,
181         // codeStream,
182         // trueLabel,
183         // falseLabel,
184         // valueRequired);
185         // return;
186         // }
187         // if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
188         // this.expression.generateOptimizedBoolean(
189         // currentScope,
190         // codeStream,
191         // falseLabel,
192         // trueLabel,
193         // valueRequired);
194         // } else {
195         // super.generateOptimizedBoolean(
196         // currentScope,
197         // codeStream,
198         // trueLabel,
199         // falseLabel,
200         // valueRequired);
201         // }
202         // }
203         public TypeBinding resolveType(BlockScope scope) {
204
205                 TypeBinding expressionType = this.expression.resolveType(scope);
206                 if (expressionType == null) {
207                         this.constant = NotAConstant;
208                         return null;
209                 }
210                 int expressionId = expressionType.id;
211                 if (expressionId > 15) {
212                         this.constant = NotAConstant;
213                         scope.problemReporter().invalidOperator(this, expressionType);
214                         return null;
215                 }
216
217                 int tableId;
218                 switch ((bits & OperatorMASK) >> OperatorSHIFT) {
219                 case NOT:
220                         tableId = AND_AND;
221                         break;
222                 case TWIDDLE:
223                         tableId = LEFT_SHIFT;
224                         break;
225                 default:
226                         tableId = MINUS;
227                 } // + and - cases
228
229                 // the code is an int
230                 // (cast) left Op (cast) rigth --> result
231                 // 0000 0000 0000 0000 0000
232                 // <<16 <<12 <<8 <<4 <<0
233                 int result = ResolveTypeTables[tableId][(expressionId << 4)
234                                 + expressionId];
235                 this.expression.implicitConversion = result >>> 12;
236                 this.bits |= result & 0xF;
237                 switch (result & 0xF) { // only switch on possible result type.....
238                 case T_boolean:
239                         this.resolvedType = BooleanBinding;
240                         break;
241                 case T_byte:
242                         this.resolvedType = ByteBinding;
243                         break;
244                 case T_char:
245                         this.resolvedType = CharBinding;
246                         break;
247                 case T_double:
248                         this.resolvedType = DoubleBinding;
249                         break;
250                 case T_float:
251                         this.resolvedType = FloatBinding;
252                         break;
253                 case T_int:
254                         this.resolvedType = IntBinding;
255                         break;
256                 case T_long:
257                         this.resolvedType = LongBinding;
258                         break;
259                 default: // error........
260                         this.constant = Constant.NotAConstant;
261                         if (expressionId != T_undefined)
262                                 scope.problemReporter().invalidOperator(this, expressionType);
263                         return null;
264                 }
265                 // compute the constant when valid
266                 if (this.expression.constant != Constant.NotAConstant) {
267                         this.constant = Constant.computeConstantOperation(
268                                         this.expression.constant, expressionId,
269                                         (bits & OperatorMASK) >> OperatorSHIFT);
270                 } else {
271                         this.constant = Constant.NotAConstant;
272                         if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
273                                 Constant cst = expression.optimizedBooleanConstant();
274                                 if (cst != Constant.NotAConstant)
275                                         this.optimizedBooleanConstant = Constant.fromValue(!cst
276                                                         .booleanValue());
277                         }
278                 }
279                 return this.resolvedType;
280         }
281
282         public StringBuffer printExpressionNoParenthesis(int indent,
283                         StringBuffer output) {
284
285                 output.append(operatorToString()).append(' ');
286                 return this.expression.printExpression(0, output);
287         }
288
289         public String toStringExpressionNoParenthesis() {
290
291                 return operatorToString() + " " + this.expression.toStringExpression(); //$NON-NLS-1$
292         }
293
294         public void traverse(ASTVisitor visitor, BlockScope blockScope) {
295
296                 if (visitor.visit(this, blockScope)) {
297                         this.expression.traverse(visitor, blockScope);
298                 }
299                 visitor.endVisit(this, blockScope);
300         }
301 }