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