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