1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 2001-2004 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * You may obtain a copy of the License at
  11  *
  12  *     http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 /*
  21  * $Id: EqualityExpr.java,v 1.2.4.1 2005/09/12 10:16:52 pvedula Exp $
  22  */
  23 
  24 package com.sun.org.apache.xalan.internal.xsltc.compiler;
  25 
  26 import com.sun.org.apache.bcel.internal.generic.BranchHandle;
  27 import com.sun.org.apache.bcel.internal.generic.BranchInstruction;
  28 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  29 import com.sun.org.apache.bcel.internal.generic.GOTO;
  30 import com.sun.org.apache.bcel.internal.generic.IFEQ;
  31 import com.sun.org.apache.bcel.internal.generic.IFNE;
  32 import com.sun.org.apache.bcel.internal.generic.IF_ICMPEQ;
  33 import com.sun.org.apache.bcel.internal.generic.IF_ICMPNE;
  34 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
  35 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  36 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  37 import com.sun.org.apache.bcel.internal.generic.PUSH;
  38 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType;
  39 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  40 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.IntType;
  41 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  42 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType;
  43 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeType;
  44 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NumberType;
  45 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.RealType;
  46 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
  47 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ResultTreeType;
  48 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.StringType;
  49 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  50 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  51 import com.sun.org.apache.xalan.internal.xsltc.runtime.Operators;
  52 
  53 /**
  54  * @author Jacek Ambroziak
  55  * @author Santiago Pericas-Geertsen
  56  * @author Morten Jorgensen
  57  * @author Erwin Bolwidt <ejb@klomp.org>
  58  */
  59 final class EqualityExpr extends Expression {
  60 
  61     private final int _op;
  62     private Expression _left;
  63     private Expression _right;
  64 
  65     public EqualityExpr(int op, Expression left, Expression right) {
  66         _op = op;
  67         (_left = left).setParent(this);
  68         (_right = right).setParent(this);
  69     }
  70 
  71     public void setParser(Parser parser) {
  72         super.setParser(parser);
  73         _left.setParser(parser);
  74         _right.setParser(parser);
  75     }
  76 
  77     public String toString() {
  78         return Operators.getOpNames(_op) + '(' + _left + ", " + _right + ')';
  79     }
  80 
  81     public Expression getLeft() {
  82         return _left;
  83     }
  84 
  85     public Expression getRight() {
  86         return _right;
  87     }
  88 
  89     public boolean getOp() {
  90         return (_op != Operators.NE);
  91     }
  92 
  93     /**
  94      * Returns true if this expressions contains a call to position(). This is
  95      * needed for context changes in node steps containing multiple predicates.
  96      */
  97     public boolean hasPositionCall() {
  98         if (_left.hasPositionCall()) return true;
  99         if (_right.hasPositionCall()) return true;
 100         return false;
 101     }
 102 
 103     public boolean hasLastCall() {
 104         if (_left.hasLastCall()) return true;
 105         if (_right.hasLastCall()) return true;
 106         return false;
 107     }
 108 
 109     private void swapArguments() {
 110         final Expression temp = _left;
 111         _left = _right;
 112         _right = temp;
 113     }
 114 
 115     /**
 116      * Typing rules: see XSLT Reference by M. Kay page 345.
 117      */
 118     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
 119         final Type tleft = _left.typeCheck(stable);
 120         final Type tright = _right.typeCheck(stable);
 121 
 122         if (tleft.isSimple() && tright.isSimple()) {
 123             if (tleft != tright) {
 124                 if (tleft instanceof BooleanType) {
 125                     _right = new CastExpr(_right, Type.Boolean);
 126                 }
 127                 else if (tright instanceof BooleanType) {
 128                     _left = new CastExpr(_left, Type.Boolean);
 129                 }
 130                 else if (tleft instanceof NumberType ||
 131                          tright instanceof NumberType) {
 132                     _left = new CastExpr(_left, Type.Real);
 133                     _right = new CastExpr(_right, Type.Real);
 134                 }
 135                 else {          // both compared as strings
 136                     _left = new CastExpr(_left,   Type.String);
 137                     _right = new CastExpr(_right, Type.String);
 138                 }
 139             }
 140         }
 141         else if (tleft instanceof ReferenceType) {
 142             _right = new CastExpr(_right, Type.Reference);
 143         }
 144         else if (tright instanceof ReferenceType) {
 145             _left = new CastExpr(_left, Type.Reference);
 146         }
 147         // the following 2 cases optimize @attr|.|.. = 'string'
 148         else if (tleft instanceof NodeType && tright == Type.String) {
 149             _left = new CastExpr(_left, Type.String);
 150         }
 151         else if (tleft == Type.String && tright instanceof NodeType) {
 152             _right = new CastExpr(_right, Type.String);
 153         }
 154         // optimize node/node
 155         else if (tleft instanceof NodeType && tright instanceof NodeType) {
 156             _left = new CastExpr(_left, Type.String);
 157             _right = new CastExpr(_right, Type.String);
 158         }
 159         else if (tleft instanceof NodeType && tright instanceof NodeSetType) {
 160             // compare(Node, NodeSet) will be invoked
 161         }
 162         else if (tleft instanceof NodeSetType && tright instanceof NodeType) {
 163             swapArguments();    // for compare(Node, NodeSet)
 164         }
 165         else {
 166             // At least one argument is of type node, node-set or result-tree
 167 
 168             // Promote an expression of type node to node-set
 169             if (tleft instanceof NodeType) {
 170                 _left = new CastExpr(_left, Type.NodeSet);
 171             }
 172             if (tright instanceof NodeType) {
 173                 _right = new CastExpr(_right, Type.NodeSet);
 174             }
 175 
 176             // If one arg is a node-set then make it the left one
 177             if (tleft.isSimple() ||
 178                 tleft instanceof ResultTreeType &&
 179                 tright instanceof NodeSetType) {
 180                 swapArguments();
 181             }
 182 
 183             // Promote integers to doubles to have fewer compares
 184             if (_right.getType() instanceof IntType) {
 185                 _right = new CastExpr(_right, Type.Real);
 186             }
 187         }
 188         return _type = Type.Boolean;
 189     }
 190 
 191     public void translateDesynthesized(ClassGenerator classGen,
 192                                        MethodGenerator methodGen) {
 193         final Type tleft = _left.getType();
 194         final InstructionList il = methodGen.getInstructionList();
 195 
 196         if (tleft instanceof BooleanType) {
 197             _left.translate(classGen, methodGen);
 198             _right.translate(classGen, methodGen);
 199         _falseList.add(il.append(_op == Operators.EQ ?
 200                                      (BranchInstruction)new IF_ICMPNE(null) :
 201                                      (BranchInstruction)new IF_ICMPEQ(null)));
 202         }
 203         else if (tleft instanceof NumberType) {
 204             _left.translate(classGen, methodGen);
 205             _right.translate(classGen, methodGen);
 206 
 207             if (tleft instanceof RealType) {
 208                 il.append(DCMPG);
 209         _falseList.add(il.append(_op == Operators.EQ ?
 210                                          (BranchInstruction)new IFNE(null) :
 211                                          (BranchInstruction)new IFEQ(null)));
 212             }
 213             else {
 214             _falseList.add(il.append(_op == Operators.EQ ?
 215                                          (BranchInstruction)new IF_ICMPNE(null) :
 216                                          (BranchInstruction)new IF_ICMPEQ(null)));
 217             }
 218         }
 219         else {
 220             translate(classGen, methodGen);
 221             desynthesize(classGen, methodGen);
 222         }
 223     }
 224 
 225     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
 226         final ConstantPoolGen cpg = classGen.getConstantPool();
 227         final InstructionList il = methodGen.getInstructionList();
 228 
 229         final Type tleft = _left.getType();
 230         Type tright = _right.getType();
 231 
 232         if (tleft instanceof BooleanType || tleft instanceof NumberType) {
 233             translateDesynthesized(classGen, methodGen);
 234             synthesize(classGen, methodGen);
 235             return;
 236         }
 237 
 238         if (tleft instanceof StringType) {
 239             final int equals = cpg.addMethodref(STRING_CLASS,
 240                                                 "equals",
 241                                                 "(" + OBJECT_SIG +")Z");
 242             _left.translate(classGen, methodGen);
 243             _right.translate(classGen, methodGen);
 244             il.append(new INVOKEVIRTUAL(equals));
 245 
 246         if (_op == Operators.NE) {
 247                 il.append(ICONST_1);
 248                 il.append(IXOR);                        // not x <-> x xor 1
 249             }
 250             return;
 251         }
 252 
 253         BranchHandle truec, falsec;
 254 
 255         if (tleft instanceof ResultTreeType) {
 256             if (tright instanceof BooleanType) {
 257                 _right.translate(classGen, methodGen);
 258         if (_op == Operators.NE) {
 259                     il.append(ICONST_1);
 260                     il.append(IXOR); // not x <-> x xor 1
 261                 }
 262                 return;
 263             }
 264 
 265             if (tright instanceof RealType) {
 266                 _left.translate(classGen, methodGen);
 267                 tleft.translateTo(classGen, methodGen, Type.Real);
 268                 _right.translate(classGen, methodGen);
 269 
 270                 il.append(DCMPG);
 271         falsec = il.append(_op == Operators.EQ ?
 272                                    (BranchInstruction) new IFNE(null) :
 273                                    (BranchInstruction) new IFEQ(null));
 274                 il.append(ICONST_1);
 275                 truec = il.append(new GOTO(null));
 276                 falsec.setTarget(il.append(ICONST_0));
 277                 truec.setTarget(il.append(NOP));
 278                 return;
 279             }
 280 
 281             // Next, result-tree/string and result-tree/result-tree comparisons
 282 
 283             _left.translate(classGen, methodGen);
 284             tleft.translateTo(classGen, methodGen, Type.String);
 285             _right.translate(classGen, methodGen);
 286 
 287             if (tright instanceof ResultTreeType) {
 288                 tright.translateTo(classGen, methodGen, Type.String);
 289             }
 290 
 291             final int equals = cpg.addMethodref(STRING_CLASS,
 292                                                 "equals",
 293                                                 "(" +OBJECT_SIG+ ")Z");
 294             il.append(new INVOKEVIRTUAL(equals));
 295 
 296         if (_op == Operators.NE) {
 297                 il.append(ICONST_1);
 298                 il.append(IXOR);                        // not x <-> x xor 1
 299             }
 300             return;
 301         }
 302 
 303         if (tleft instanceof NodeSetType && tright instanceof BooleanType) {
 304             _left.translate(classGen, methodGen);
 305             _left.startIterator(classGen, methodGen);
 306             Type.NodeSet.translateTo(classGen, methodGen, Type.Boolean);
 307             _right.translate(classGen, methodGen);
 308 
 309             il.append(IXOR); // x != y <-> x xor y
 310         if (_op == Operators.EQ) {
 311                 il.append(ICONST_1);
 312                 il.append(IXOR); // not x <-> x xor 1
 313             }
 314             return;
 315         }
 316 
 317         if (tleft instanceof NodeSetType && tright instanceof StringType) {
 318             _left.translate(classGen, methodGen);
 319             _left.startIterator(classGen, methodGen); // needed ?
 320             _right.translate(classGen, methodGen);
 321             il.append(new PUSH(cpg, _op));
 322             il.append(methodGen.loadDOM());
 323             final int cmp = cpg.addMethodref(BASIS_LIBRARY_CLASS,
 324                                              "compare",
 325                                              "("
 326                                              + tleft.toSignature()
 327                                              + tright.toSignature()
 328                                              + "I"
 329                                              + DOM_INTF_SIG
 330                                              + ")Z");
 331             il.append(new INVOKESTATIC(cmp));
 332             return;
 333         }
 334 
 335         // Next, node-set/t for t in {real, string, node-set, result-tree}
 336         _left.translate(classGen, methodGen);
 337         _left.startIterator(classGen, methodGen);
 338         _right.translate(classGen, methodGen);
 339         _right.startIterator(classGen, methodGen);
 340 
 341         // Cast a result tree to a string to use an existing compare
 342         if (tright instanceof ResultTreeType) {
 343             tright.translateTo(classGen, methodGen, Type.String);
 344             tright = Type.String;
 345         }
 346 
 347         // Call the appropriate compare() from the BasisLibrary
 348         il.append(new PUSH(cpg, _op));
 349         il.append(methodGen.loadDOM());
 350 
 351         final int compare = cpg.addMethodref(BASIS_LIBRARY_CLASS,
 352                                              "compare",
 353                                              "("
 354                                              + tleft.toSignature()
 355                                              + tright.toSignature()
 356                                              + "I"
 357                                              + DOM_INTF_SIG
 358                                              + ")Z");
 359         il.append(new INVOKESTATIC(compare));
 360     }
 361 }