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: RelationalExpr.java,v 1.19 2004/02/16 22:24:28 minchau Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.xsltc.compiler;
  20. import com.sun.org.apache.bcel.internal.generic.BranchInstruction;
  21. import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  22. import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
  23. import com.sun.org.apache.bcel.internal.generic.InstructionList;
  24. import com.sun.org.apache.bcel.internal.generic.PUSH;
  25. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType;
  26. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  27. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  28. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.IntType;
  29. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  30. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType;
  31. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType;
  32. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeType;
  33. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.RealType;
  34. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
  35. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ResultTreeType;
  36. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  37. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  38. import com.sun.org.apache.xalan.internal.xsltc.runtime.Operators;
  39. /**
  40. * @author Jacek Ambroziak
  41. * @author Santiago Pericas-Geertsen
  42. */
  43. final class RelationalExpr extends Expression implements Operators {
  44. private int _op;
  45. private Expression _left, _right;
  46. public RelationalExpr(int op, Expression left, Expression right) {
  47. _op = op;
  48. (_left = left).setParent(this);
  49. (_right = right).setParent(this);
  50. }
  51. public void setParser(Parser parser) {
  52. super.setParser(parser);
  53. _left.setParser(parser);
  54. _right.setParser(parser);
  55. }
  56. /**
  57. * Returns true if this expressions contains a call to position(). This is
  58. * needed for context changes in node steps containing multiple predicates.
  59. */
  60. public boolean hasPositionCall() {
  61. if (_left.hasPositionCall()) return true;
  62. if (_right.hasPositionCall()) return true;
  63. return false;
  64. }
  65. /**
  66. * Returns true if this expressions contains a call to last()
  67. */
  68. public boolean hasLastCall() {
  69. return (_left.hasLastCall() || _right.hasLastCall());
  70. }
  71. public boolean hasReferenceArgs() {
  72. return _left.getType() instanceof ReferenceType ||
  73. _right.getType() instanceof ReferenceType;
  74. }
  75. public boolean hasNodeArgs() {
  76. return _left.getType() instanceof NodeType ||
  77. _right.getType() instanceof NodeType;
  78. }
  79. public boolean hasNodeSetArgs() {
  80. return _left.getType() instanceof NodeSetType ||
  81. _right.getType() instanceof NodeSetType;
  82. }
  83. public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  84. Type tleft = _left.typeCheck(stable);
  85. Type tright = _right.typeCheck(stable);
  86. //bug fix # 2838, cast to reals if both are result tree fragments
  87. if (tleft instanceof ResultTreeType &&
  88. tright instanceof ResultTreeType )
  89. {
  90. _right = new CastExpr(_right, Type.Real);
  91. _left = new CastExpr(_left, Type.Real);
  92. return _type = Type.Boolean;
  93. }
  94. // If one is of reference type, then convert the other too
  95. if (hasReferenceArgs()) {
  96. Type type = null;
  97. Type typeL = null;
  98. Type typeR = null;
  99. if (tleft instanceof ReferenceType) {
  100. if (_left instanceof VariableRefBase) {
  101. VariableRefBase ref = (VariableRefBase)_left;
  102. VariableBase var = ref.getVariable();
  103. typeL = var.getType();
  104. }
  105. }
  106. if (tright instanceof ReferenceType) {
  107. if (_right instanceof VariableRefBase) {
  108. VariableRefBase ref = (VariableRefBase)_right;
  109. VariableBase var = ref.getVariable();
  110. typeR = var.getType();
  111. }
  112. }
  113. // bug fix # 2838
  114. if (typeL == null)
  115. type = typeR;
  116. else if (typeR == null)
  117. type = typeL;
  118. else {
  119. type = Type.Real;
  120. }
  121. if (type == null) type = Type.Real;
  122. _right = new CastExpr(_right, type);
  123. _left = new CastExpr(_left, type);
  124. return _type = Type.Boolean;
  125. }
  126. if (hasNodeSetArgs()) {
  127. // Ensure that the node-set is the left argument
  128. if (tright instanceof NodeSetType) {
  129. final Expression temp = _right; _right = _left; _left = temp;
  130. _op = (_op == Operators.GT) ? Operators.LT :
  131. (_op == Operators.LT) ? Operators.GT :
  132. (_op == Operators.GE) ? Operators.LE : Operators.GE;
  133. tright = _right.getType();
  134. }
  135. // Promote nodes to node sets
  136. if (tright instanceof NodeType) {
  137. _right = new CastExpr(_right, Type.NodeSet);
  138. }
  139. // Promote integer to doubles to have fewer compares
  140. if (tright instanceof IntType) {
  141. _right = new CastExpr(_right, Type.Real);
  142. }
  143. // Promote result-trees to strings
  144. if (tright instanceof ResultTreeType) {
  145. _right = new CastExpr(_right, Type.String);
  146. }
  147. return _type = Type.Boolean;
  148. }
  149. // In the node-boolean case, convert node to boolean first
  150. if (hasNodeArgs()) {
  151. if (tleft instanceof BooleanType) {
  152. _right = new CastExpr(_right, Type.Boolean);
  153. tright = Type.Boolean;
  154. }
  155. if (tright instanceof BooleanType) {
  156. _left = new CastExpr(_left, Type.Boolean);
  157. tleft = Type.Boolean;
  158. }
  159. }
  160. // Lookup the table of primops to find the best match
  161. MethodType ptype = lookupPrimop(stable, Operators.names[_op],
  162. new MethodType(Type.Void,
  163. tleft, tright));
  164. if (ptype != null) {
  165. Type arg1 = (Type) ptype.argsType().elementAt(0);
  166. if (!arg1.identicalTo(tleft)) {
  167. _left = new CastExpr(_left, arg1);
  168. }
  169. Type arg2 = (Type) ptype.argsType().elementAt(1);
  170. if (!arg2.identicalTo(tright)) {
  171. _right = new CastExpr(_right, arg1);
  172. }
  173. return _type = ptype.resultType();
  174. }
  175. throw new TypeCheckError(this);
  176. }
  177. public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
  178. if (hasNodeSetArgs() || hasReferenceArgs()) {
  179. final ConstantPoolGen cpg = classGen.getConstantPool();
  180. final InstructionList il = methodGen.getInstructionList();
  181. // Call compare() from the BasisLibrary
  182. _left.translate(classGen, methodGen);
  183. _left.startIterator(classGen, methodGen);
  184. _right.translate(classGen, methodGen);
  185. _right.startIterator(classGen, methodGen);
  186. il.append(new PUSH(cpg, _op));
  187. il.append(methodGen.loadDOM());
  188. int index = cpg.addMethodref(BASIS_LIBRARY_CLASS, "compare",
  189. "("
  190. + _left.getType().toSignature()
  191. + _right.getType().toSignature()
  192. + "I"
  193. + DOM_INTF_SIG
  194. + ")Z");
  195. il.append(new INVOKESTATIC(index));
  196. }
  197. else {
  198. translateDesynthesized(classGen, methodGen);
  199. synthesize(classGen, methodGen);
  200. }
  201. }
  202. public void translateDesynthesized(ClassGenerator classGen,
  203. MethodGenerator methodGen) {
  204. if (hasNodeSetArgs() || hasReferenceArgs()) {
  205. translate(classGen, methodGen);
  206. desynthesize(classGen, methodGen);
  207. }
  208. else {
  209. BranchInstruction bi = null;
  210. final InstructionList il = methodGen.getInstructionList();
  211. _left.translate(classGen, methodGen);
  212. _right.translate(classGen, methodGen);
  213. // TODO: optimize if one of the args is 0
  214. boolean tozero = false;
  215. Type tleft = _left.getType();
  216. if (tleft instanceof RealType) {
  217. il.append(tleft.CMP(_op == LT || _op == LE));
  218. tleft = Type.Int;
  219. tozero = true;
  220. }
  221. switch (_op) {
  222. case LT:
  223. bi = tleft.GE(tozero);
  224. break;
  225. case GT:
  226. bi = tleft.LE(tozero);
  227. break;
  228. case LE:
  229. bi = tleft.GT(tozero);
  230. break;
  231. case GE:
  232. bi = tleft.LT(tozero);
  233. break;
  234. default:
  235. ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_RELAT_OP_ERR,this);
  236. getParser().reportError(Constants.FATAL, msg);
  237. }
  238. _falseList.add(il.append(bi)); // must be backpatched
  239. }
  240. }
  241. public String toString() {
  242. return Operators.names[_op] + '(' + _left + ", " + _right + ')';
  243. }
  244. }