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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpeclipse.internal.compiler.ast;
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;
21 public class UnaryExpression extends OperatorExpression {
23 public Expression expression;
24 public Constant optimizedBooleanConstant;
26 public UnaryExpression(Expression expression, int operator) {
27 this.expression = expression;
28 this.bits |= operator << OperatorSHIFT; // encode operator
31 public FlowInfo analyseCode(
32 BlockScope currentScope,
33 FlowContext flowContext,
36 if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
37 return this.expression
38 .analyseCode(currentScope, flowContext, flowInfo)
39 .asNegatedCondition();
41 return this.expression.analyseCode(currentScope, flowContext, flowInfo);
45 public Constant optimizedBooleanConstant() {
47 return this.optimizedBooleanConstant == null
49 : this.optimizedBooleanConstant;
53 * Code generation for an unary operation
55 * @param currentScope net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
56 * @param codeStream net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
57 * @param valueRequired boolean
59 // public void generateCode(
60 // BlockScope currentScope,
61 // CodeStream codeStream,
62 // boolean valueRequired) {
64 // int pc = codeStream.position;
65 // Label falseLabel, endifLabel;
66 // if (this.constant != Constant.NotAConstant) {
68 // if (valueRequired) {
69 // codeStream.generateConstant(this.constant, this.implicitConversion);
71 // codeStream.recordPositionsFrom(pc, this.sourceStart);
74 // switch ((bits & OperatorMASK) >> OperatorSHIFT) {
76 // switch (this.expression.implicitConversion >> 4) /* runtime type */ {
79 // // Generate code for the condition
80 // this.expression.generateOptimizedBoolean(
84 // (falseLabel = new Label(codeStream)),
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();
95 // } else { // 6596: if (!(a && b)){} - must still place falseLabel
96 // falseLabel.place();
102 // switch (this.expression.implicitConversion >> 4 /* runtime */
106 // this.expression.generateCode(currentScope, codeStream, valueRequired);
107 // if (valueRequired) {
108 // codeStream.iconst_m1();
109 // codeStream.ixor();
113 // this.expression.generateCode(currentScope, codeStream, valueRequired);
114 // if (valueRequired) {
115 // codeStream.ldc2_w(-1L);
116 // codeStream.lxor();
122 // if (this.constant != NotAConstant) {
123 // if (valueRequired) {
124 // switch (this.expression.implicitConversion >> 4){ /* runtime */
126 // codeStream.generateInlinedValue(this.constant.intValue() * -1);
129 // codeStream.generateInlinedValue(this.constant.floatValue() * -1.0f);
132 // codeStream.generateInlinedValue(this.constant.longValue() * -1L);
135 // codeStream.generateInlinedValue(this.constant.doubleValue() * -1.0);
139 // this.expression.generateCode(currentScope, codeStream, valueRequired);
140 // if (valueRequired) {
141 // switch (expression.implicitConversion >> 4){ /* runtime type */
143 // codeStream.ineg();
146 // codeStream.fneg();
149 // codeStream.lneg();
152 // codeStream.dneg();
158 // this.expression.generateCode(currentScope, codeStream, valueRequired);
160 // if (valueRequired) {
161 // codeStream.generateImplicitConversion(this.implicitConversion);
163 // codeStream.recordPositionsFrom(pc, this.sourceStart);
167 // * Boolean operator code generation
168 // * Optimized operations are: &&, ||, <, <=, >, >=, &, |, ^
170 // public void generateOptimizedBoolean(
171 // BlockScope currentScope,
172 // CodeStream codeStream,
175 // boolean valueRequired) {
177 // if ((this.constant != Constant.NotAConstant) && (this.constant.typeID() == T_boolean)) {
178 // super.generateOptimizedBoolean(
186 // if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
187 // this.expression.generateOptimizedBoolean(
194 // super.generateOptimizedBoolean(
203 public TypeBinding resolveType(BlockScope scope) {
205 TypeBinding expressionType = this.expression.resolveType(scope);
206 if (expressionType == null) {
207 this.constant = NotAConstant;
210 int expressionId = expressionType.id;
211 if (expressionId > 15) {
212 this.constant = NotAConstant;
213 scope.problemReporter().invalidOperator(this, expressionType);
218 switch ((bits & OperatorMASK) >> OperatorSHIFT) {
223 tableId = LEFT_SHIFT;
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.....
238 this.resolvedType = BooleanBinding;
241 this.resolvedType = ByteBinding;
244 this.resolvedType = CharBinding;
247 this.resolvedType = DoubleBinding;
250 this.resolvedType = FloatBinding;
253 this.resolvedType = IntBinding;
256 this.resolvedType = LongBinding;
258 default : //error........
259 this.constant = Constant.NotAConstant;
260 if (expressionId != T_undefined)
261 scope.problemReporter().invalidOperator(this, expressionType);
264 // compute the constant when valid
265 if (this.expression.constant != Constant.NotAConstant) {
267 Constant.computeConstantOperation(
268 this.expression.constant,
270 (bits & OperatorMASK) >> OperatorSHIFT);
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());
279 return this.resolvedType;
281 public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) {
283 output.append(operatorToString()).append(' ');
284 return this.expression.printExpression(0, output);
286 public String toStringExpressionNoParenthesis() {
288 return operatorToString() + " " + this.expression.toStringExpression(); //$NON-NLS-1$
291 public void traverse(
293 BlockScope blockScope) {
295 if (visitor.visit(this, blockScope)) {
296 this.expression.traverse(visitor, blockScope);
298 visitor.endVisit(this, blockScope);