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