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.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.ArrayBinding;
19 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
20 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
21 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
22 import net.sourceforge.phpdt.internal.compiler.lookup.Scope;
23 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
25 public class EqualExpression extends BinaryExpression {
27 public EqualExpression(Expression left, Expression right,int operator) {
28 super(left,right,operator);
30 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
31 if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
32 if ((left.constant != NotAConstant) && (left.constant.typeID() == T_boolean)) {
33 if (left.constant.booleanValue()) { // true == anything
34 // this is equivalent to the right argument inits
35 return right.analyseCode(currentScope, flowContext, flowInfo);
36 } else { // false == anything
37 // this is equivalent to the right argument inits negated
38 return right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
41 if ((right.constant != NotAConstant) && (right.constant.typeID() == T_boolean)) {
42 if (right.constant.booleanValue()) { // anything == true
43 // this is equivalent to the right argument inits
44 return left.analyseCode(currentScope, flowContext, flowInfo);
45 } else { // anything == false
46 // this is equivalent to the right argument inits negated
47 return left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
50 return right.analyseCode(
51 currentScope, flowContext,
52 left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).unconditionalInits();
53 } else { //NOT_EQUAL :
54 if ((left.constant != NotAConstant) && (left.constant.typeID() == T_boolean)) {
55 if (!left.constant.booleanValue()) { // false != anything
56 // this is equivalent to the right argument inits
57 return right.analyseCode(currentScope, flowContext, flowInfo);
58 } else { // true != anything
59 // this is equivalent to the right argument inits negated
60 return right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
63 if ((right.constant != NotAConstant) && (right.constant.typeID() == T_boolean)) {
64 if (!right.constant.booleanValue()) { // anything != false
65 // this is equivalent to the right argument inits
66 return left.analyseCode(currentScope, flowContext, flowInfo);
67 } else { // anything != true
68 // this is equivalent to the right argument inits negated
69 return left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
72 return right.analyseCode(
73 currentScope, flowContext,
74 left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).asNegatedCondition().unconditionalInits();
77 public final boolean areTypesCastCompatible(BlockScope scope, TypeBinding castType, TypeBinding expressionType) {
78 //see specifications 5.5
79 //A more complete version of this method is provided on
80 //CastExpression (it deals with constant and need runtime checkcast)
82 if (castType == expressionType) return true;
84 //========ARRAY===============
85 if (expressionType.isArrayType()) {
86 if (castType.isArrayType()) { //------- (castTb.isArray) expressionTb.isArray -----------
87 TypeBinding expressionEltType = ((ArrayBinding) expressionType).elementsType(scope);
88 if (expressionEltType.isBaseType())
89 // <---stop the recursion-------
90 return ((ArrayBinding) castType).elementsType(scope) == expressionEltType;
91 //recursivly on the elts...
92 return areTypesCastCompatible(scope, ((ArrayBinding) castType).elementsType(scope), expressionEltType);
94 if (castType.isBaseType()) {
97 if (castType.isClass()) { //------(castTb.isClass) expressionTb.isArray ---------------
98 if (scope.isJavaLangObject(castType))
102 if (castType.isInterface()) { //------- (castTb.isInterface) expressionTb.isArray -----------
103 if (scope.isJavaLangCloneable(castType) || scope.isJavaIoSerializable(castType)) {
112 //------------(castType) null--------------
113 if (expressionType == NullBinding) {
114 return !castType.isBaseType();
117 //========BASETYPE==============
118 if (expressionType.isBaseType()) {
123 //========REFERENCE TYPE===================
125 if (expressionType.isClass()) {
126 if (castType.isArrayType()) { // ---- (castTb.isArray) expressionTb.isClass -------
127 if (scope.isJavaLangObject(expressionType))
130 if (castType.isBaseType()) {
133 if (castType.isClass()) { // ----- (castTb.isClass) expressionTb.isClass ------
134 if (expressionType.isCompatibleWith(castType))
137 if (castType.isCompatibleWith(expressionType)) {
143 if (castType.isInterface()) { // ----- (castTb.isInterface) expressionTb.isClass -------
144 if (((ReferenceBinding) expressionType).isFinal()) { //no subclass for expressionTb, thus compile-time check is valid
145 if (expressionType.isCompatibleWith(castType))
155 if (expressionType.isInterface()) {
156 if (castType.isArrayType()) { // ----- (castTb.isArray) expressionTb.isInterface ------
157 if (scope.isJavaLangCloneable(expressionType) || scope.isJavaIoSerializable(expressionType))
158 //potential runtime error
164 if (castType.isBaseType()) {
167 if (castType.isClass()) { // ----- (castTb.isClass) expressionTb.isInterface --------
168 if (scope.isJavaLangObject(castType))
170 if (((ReferenceBinding) castType).isFinal()) { //no subclass for castTb, thus compile-time check is valid
171 if (castType.isCompatibleWith(expressionType)) {
178 if (castType.isInterface()) { // ----- (castTb.isInterface) expressionTb.isInterface -------
179 if (Scope.compareTypes(castType, expressionType) == NotRelated) {
180 MethodBinding[] castTbMethods = ((ReferenceBinding) castType).methods();
181 int castTbMethodsLength = castTbMethods.length;
182 MethodBinding[] expressionTbMethods = ((ReferenceBinding) expressionType).methods();
183 int expressionTbMethodsLength = expressionTbMethods.length;
184 for (int i = 0; i < castTbMethodsLength; i++) {
185 for (int j = 0; j < expressionTbMethodsLength; j++) {
186 if (castTbMethods[i].selector == expressionTbMethods[j].selector) {
187 if (castTbMethods[i].returnType != expressionTbMethods[j].returnType) {
188 if (castTbMethods[i].areParametersEqual(expressionTbMethods[j])) {
204 public final void computeConstant(TypeBinding leftType, TypeBinding rightType) {
205 if ((this.left.constant != NotAConstant) && (this.right.constant != NotAConstant)) {
207 Constant.computeConstantOperationEQUAL_EQUAL(
213 if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT_EQUAL)
214 constant = Constant.fromValue(!constant.booleanValue());
216 this.constant = NotAConstant;
217 // no optimization for null == null
221 * Normal == or != code generation.
223 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
224 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
225 * @param valueRequired boolean
227 //public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
229 // if (constant != NotAConstant) {
230 // int pc = codeStream.position;
231 // if (valueRequired)
232 // codeStream.generateConstant(constant, implicitConversion);
233 // codeStream.recordPositionsFrom(pc, this.sourceStart);
237 // bits |= OnlyValueRequiredMASK;
238 // generateOptimizedBoolean(
242 // falseLabel = new Label(codeStream),
244 // if (falseLabel.hasForwardReferences()) {
245 // if (valueRequired){
246 // // comparison is TRUE
247 // codeStream.iconst_1();
248 // if ((bits & ValueForReturnMASK) != 0){
249 // codeStream.ireturn();
250 // // comparison is FALSE
251 // falseLabel.place();
252 // codeStream.iconst_0();
254 // Label endLabel = new Label(codeStream);
255 // codeStream.goto_(endLabel);
256 // codeStream.decrStackSize(1);
257 // // comparison is FALSE
258 // falseLabel.place();
259 // codeStream.iconst_0();
263 // falseLabel.place();
268 * Boolean operator code generation
269 * Optimized operations are: == and !=
271 //public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) {
273 // if (constant != Constant.NotAConstant) {
274 // super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
277 // if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
278 // if ((left.implicitConversion & 0xF) /*compile-time*/ == T_boolean) {
279 // generateOptimizedBooleanEqual(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
281 // generateOptimizedNonBooleanEqual(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
284 // if ((left.implicitConversion & 0xF) /*compile-time*/ == T_boolean) {
285 // generateOptimizedBooleanEqual(currentScope, codeStream, falseLabel, trueLabel, valueRequired);
287 // generateOptimizedNonBooleanEqual(currentScope, codeStream, falseLabel, trueLabel, valueRequired);
292 * Boolean generation for == with boolean operands
294 * Note this code does not optimize conditional constants !!!!
296 //public void generateOptimizedBooleanEqual(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) {
298 // // optimized cases: true == x, false == x
299 // if (left.constant != NotAConstant) {
300 // boolean inline = left.constant.booleanValue();
301 // right.generateOptimizedBoolean(currentScope, codeStream, (inline ? trueLabel : falseLabel), (inline ? falseLabel : trueLabel), valueRequired);
303 // } // optimized cases: x == true, x == false
304 // if (right.constant != NotAConstant) {
305 // boolean inline = right.constant.booleanValue();
306 // left.generateOptimizedBoolean(currentScope, codeStream, (inline ? trueLabel : falseLabel), (inline ? falseLabel : trueLabel), valueRequired);
310 // left.generateCode(currentScope, codeStream, valueRequired);
311 // right.generateCode(currentScope, codeStream, valueRequired);
312 // if (valueRequired) {
313 // if (falseLabel == null) {
314 // if (trueLabel != null) {
315 // // implicit falling through the FALSE case
316 // codeStream.if_icmpeq(trueLabel);
319 // // implicit falling through the TRUE case
320 // if (trueLabel == null) {
321 // codeStream.if_icmpne(falseLabel);
323 // // no implicit fall through TRUE/FALSE --> should never occur
327 // // reposition the endPC
328 // codeStream.updateLastRecordedEndPC(codeStream.position);
331 // * Boolean generation for == with non-boolean operands
334 //public void generateOptimizedNonBooleanEqual(BlockScope currentScope, CodeStream codeStream, Label trueLabel, Label falseLabel, boolean valueRequired) {
336 // int pc = codeStream.position;
338 // if ((inline = right.constant) != NotAConstant) {
339 // // optimized case: x == 0
340 // if (((left.implicitConversion >> 4) == T_int) && (inline.intValue() == 0)) {
341 // left.generateCode(currentScope, codeStream, valueRequired);
342 // if (valueRequired) {
343 // if (falseLabel == null) {
344 // if (trueLabel != null) {
345 // // implicit falling through the FALSE case
346 // codeStream.ifeq(trueLabel);
349 // // implicit falling through the TRUE case
350 // if (trueLabel == null) {
351 // codeStream.ifne(falseLabel);
353 // // no implicit fall through TRUE/FALSE --> should never occur
357 // codeStream.recordPositionsFrom(pc, this.sourceStart);
361 // if ((inline = left.constant) != NotAConstant) {
362 // // optimized case: 0 == x
363 // if (((left.implicitConversion >> 4) == T_int)
364 // && (inline.intValue() == 0)) {
365 // right.generateCode(currentScope, codeStream, valueRequired);
366 // if (valueRequired) {
367 // if (falseLabel == null) {
368 // if (trueLabel != null) {
369 // // implicit falling through the FALSE case
370 // codeStream.ifeq(trueLabel);
373 // // implicit falling through the TRUE case
374 // if (trueLabel == null) {
375 // codeStream.ifne(falseLabel);
377 // // no implicit fall through TRUE/FALSE --> should never occur
381 // codeStream.recordPositionsFrom(pc, this.sourceStart);
386 // // optimized case: x == null
387 // if (right instanceof NullLiteral) {
388 // if (left instanceof NullLiteral) {
390 // if (valueRequired) {
391 // if ((bits & OnlyValueRequiredMASK) != 0) {
392 // if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
393 // codeStream.iconst_1();
395 // codeStream.iconst_0();
398 // if (falseLabel == null) {
399 // // implicit falling through the FALSE case
400 // if (trueLabel != null) {
401 // codeStream.goto_(trueLabel);
407 // left.generateCode(currentScope, codeStream, valueRequired);
408 // if (valueRequired) {
409 // if (falseLabel == null) {
410 // if (trueLabel != null) {
411 // // implicit falling through the FALSE case
412 // codeStream.ifnull(trueLabel);
415 // // implicit falling through the TRUE case
416 // if (trueLabel == null) {
417 // codeStream.ifnonnull(falseLabel);
419 // // no implicit fall through TRUE/FALSE --> should never occur
424 // codeStream.recordPositionsFrom(pc, this.sourceStart);
426 // } else if (left instanceof NullLiteral) { // optimized case: null == x
427 // right.generateCode(currentScope, codeStream, valueRequired);
428 // if (valueRequired) {
429 // if (falseLabel == null) {
430 // if (trueLabel != null) {
431 // // implicit falling through the FALSE case
432 // codeStream.ifnull(trueLabel);
435 // // implicit falling through the TRUE case
436 // if (trueLabel == null) {
437 // codeStream.ifnonnull(falseLabel);
439 // // no implicit fall through TRUE/FALSE --> should never occur
443 // codeStream.recordPositionsFrom(pc, this.sourceStart);
448 // left.generateCode(currentScope, codeStream, valueRequired);
449 // right.generateCode(currentScope, codeStream, valueRequired);
450 // if (valueRequired) {
451 // if (falseLabel == null) {
452 // if (trueLabel != null) {
453 // // implicit falling through the FALSE case
454 // switch (left.implicitConversion >> 4) { // operand runtime type
456 // codeStream.if_icmpeq(trueLabel);
459 // codeStream.fcmpl();
460 // codeStream.ifeq(trueLabel);
463 // codeStream.lcmp();
464 // codeStream.ifeq(trueLabel);
467 // codeStream.dcmpl();
468 // codeStream.ifeq(trueLabel);
471 // codeStream.if_acmpeq(trueLabel);
475 // // implicit falling through the TRUE case
476 // if (trueLabel == null) {
477 // switch (left.implicitConversion >> 4) { // operand runtime type
479 // codeStream.if_icmpne(falseLabel);
482 // codeStream.fcmpl();
483 // codeStream.ifne(falseLabel);
486 // codeStream.lcmp();
487 // codeStream.ifne(falseLabel);
490 // codeStream.dcmpl();
491 // codeStream.ifne(falseLabel);
494 // codeStream.if_acmpne(falseLabel);
497 // // no implicit fall through TRUE/FALSE --> should never occur
501 // codeStream.recordPositionsFrom(pc, this.sourceStart);
503 public boolean isCompactableOperation() {
506 public TypeBinding resolveType(BlockScope scope) {
507 // always return BooleanBinding
508 TypeBinding leftType = left.resolveType(scope);
509 TypeBinding rightType = right.resolveType(scope);
510 if (leftType == null || rightType == null){
511 constant = NotAConstant;
516 if (leftType.isBaseType() && rightType.isBaseType()) {
517 // the code is an int
518 // (cast) left == (cast) rigth --> result
519 // 0000 0000 0000 0000 0000
520 // <<16 <<12 <<8 <<4 <<0
521 int result = ResolveTypeTables[EQUAL_EQUAL][ (leftType.id << 4) + rightType.id];
522 left.implicitConversion = result >>> 12;
523 right.implicitConversion = (result >>> 4) & 0x000FF;
524 bits |= result & 0xF;
525 if ((result & 0x0000F) == T_undefined) {
526 constant = Constant.NotAConstant;
527 scope.problemReporter().invalidOperator(this, leftType, rightType);
530 computeConstant(leftType, rightType);
531 this.resolvedType = BooleanBinding;
532 return BooleanBinding;
537 if (areTypesCastCompatible(scope, rightType, leftType) || areTypesCastCompatible(scope, leftType, rightType)) {
538 // (special case for String)
539 if ((rightType.id == T_String) && (leftType.id == T_String))
540 computeConstant(leftType, rightType);
542 constant = NotAConstant;
543 if (rightType.id == T_String)
544 right.implicitConversion = String2String;
545 if (leftType.id == T_String)
546 left.implicitConversion = String2String;
547 this.resolvedType = BooleanBinding;
548 return BooleanBinding;
550 constant = NotAConstant;
551 scope.problemReporter().notCompatibleTypesError(this, leftType, rightType);
554 public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
555 if (visitor.visit(this, scope)) {
556 left.traverse(visitor, scope);
557 right.traverse(visitor, scope);
559 visitor.endVisit(this, scope);