Added error "Unreachable code" for if statements
[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.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
21 public class UnaryExpression extends OperatorExpression {
22         
23         public Expression expression;
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(
32                 BlockScope currentScope,
33                 FlowContext flowContext,
34                 FlowInfo flowInfo) {
35                         
36                 if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
37                         return this.expression
38                                 .analyseCode(currentScope, flowContext, flowInfo)
39                                 .asNegatedCondition();
40                 } else {
41                         return this.expression.analyseCode(currentScope, flowContext, flowInfo);
42                 }
43         }
44
45         public Constant optimizedBooleanConstant() {
46                 
47                 return this.optimizedBooleanConstant == null 
48                                 ? this.constant 
49                                 : this.optimizedBooleanConstant;
50         }
51
52         /**
53          * Code generation for an unary operation
54          *
55          * @param currentScope net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
56          * @param codeStream net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
57          * @param valueRequired 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() == T_boolean)) {
178 //                      super.generateOptimizedBoolean(
179 //                              currentScope,
180 //                              codeStream,
181 //                              trueLabel,
182 //                              falseLabel,
183 //                              valueRequired);
184 //                      return;
185 //              }
186 //              if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
187 //                      this.expression.generateOptimizedBoolean(
188 //                              currentScope,
189 //                              codeStream,
190 //                              falseLabel,
191 //                              trueLabel,
192 //                              valueRequired);
193 //              } else {
194 //                      super.generateOptimizedBoolean(
195 //                              currentScope,
196 //                              codeStream,
197 //                              trueLabel,
198 //                              falseLabel,
199 //                              valueRequired);
200 //              }
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) + expressionId];
234                 this.expression.implicitConversion = result >>> 12;
235                 this.bits |= result & 0xF;
236                 switch (result & 0xF) { // only switch on possible result type.....
237                         case T_boolean :
238                                 this.resolvedType = BooleanBinding;
239                                 break;
240                         case T_byte :
241                                 this.resolvedType = ByteBinding;
242                                 break;
243                         case T_char :
244                                 this.resolvedType = CharBinding;
245                                 break;
246                         case T_double :
247                                 this.resolvedType = DoubleBinding;
248                                 break;
249                         case T_float :
250                                 this.resolvedType = FloatBinding;
251                                 break;
252                         case T_int :
253                                 this.resolvedType = IntBinding;
254                                 break;
255                         case T_long :
256                                 this.resolvedType = LongBinding;
257                                 break;
258                         default : //error........
259                                 this.constant = Constant.NotAConstant;
260                                 if (expressionId != T_undefined)
261                                         scope.problemReporter().invalidOperator(this, expressionType);
262                                 return null;
263                 }
264                 // compute the constant when valid
265                 if (this.expression.constant != Constant.NotAConstant) {
266                         this.constant =
267                                 Constant.computeConstantOperation(
268                                         this.expression.constant,
269                                         expressionId,
270                                         (bits & OperatorMASK) >> OperatorSHIFT);
271                 } else {
272                         this.constant = Constant.NotAConstant;
273                         if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
274                                 Constant cst = expression.optimizedBooleanConstant();
275                                 if (cst != Constant.NotAConstant) 
276                                         this.optimizedBooleanConstant = Constant.fromValue(!cst.booleanValue());
277                         }
278                 }
279                 return this.resolvedType;
280         }
281         public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) {
282                 
283                 output.append(operatorToString()).append(' ');
284                 return this.expression.printExpression(0, output);
285         } 
286         public String toStringExpressionNoParenthesis() {
287                 
288                 return operatorToString() + " " + this.expression.toStringExpression(); //$NON-NLS-1$
289         } 
290         
291         public void traverse(
292             ASTVisitor visitor,
293                 BlockScope blockScope) {
294                         
295                 if (visitor.visit(this, blockScope)) {
296                         this.expression.traverse(visitor, blockScope);
297                 }
298                 visitor.endVisit(this, blockScope);
299         }
300 }