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 }