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: FilterExpr.java,v 1.11 2004/02/16 22:24:29 minchau Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.xsltc.compiler;
  20. import java.util.Vector;
  21. import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  22. import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  23. import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
  24. import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
  25. import com.sun.org.apache.bcel.internal.generic.InstructionList;
  26. import com.sun.org.apache.bcel.internal.generic.NEW;
  27. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  28. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  29. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType;
  30. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
  31. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  32. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  33. /**
  34. * @author Jacek Ambroziak
  35. * @author Santiago Pericas-Geertsen
  36. * @author Morten Jorgensen
  37. */
  38. class FilterExpr extends Expression {
  39. /**
  40. * Primary expression of this filter. I.e., 'e' in '(e)[p1]...[pn]'.
  41. */
  42. private Expression _primary;
  43. /**
  44. * Array of predicates in '(e)[p1]...[pn]'.
  45. */
  46. private final Vector _predicates;
  47. public FilterExpr(Expression primary, Vector predicates) {
  48. _primary = primary;
  49. _predicates = predicates;
  50. primary.setParent(this);
  51. }
  52. protected Expression getExpr() {
  53. if (_primary instanceof CastExpr)
  54. return ((CastExpr)_primary).getExpr();
  55. else
  56. return _primary;
  57. }
  58. public void setParser(Parser parser) {
  59. super.setParser(parser);
  60. _primary.setParser(parser);
  61. if (_predicates != null) {
  62. final int n = _predicates.size();
  63. for (int i = 0; i < n; i++) {
  64. final Expression exp = (Expression)_predicates.elementAt(i);
  65. exp.setParser(parser);
  66. exp.setParent(this);
  67. }
  68. }
  69. }
  70. public String toString() {
  71. return "filter-expr(" + _primary + ", " + _predicates + ")";
  72. }
  73. /**
  74. * Type check a FilterParentPath. If the filter is not a node-set add a
  75. * cast to node-set only if it is of reference type. This type coercion
  76. * is needed for expressions like $x where $x is a parameter reference.
  77. * All optimizations are turned off before type checking underlying
  78. * predicates.
  79. */
  80. public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  81. Type ptype = _primary.typeCheck(stable);
  82. if (ptype instanceof NodeSetType == false) {
  83. if (ptype instanceof ReferenceType) {
  84. _primary = new CastExpr(_primary, Type.NodeSet);
  85. }
  86. else {
  87. throw new TypeCheckError(this);
  88. }
  89. }
  90. // Type check predicates and turn all optimizations off
  91. int n = _predicates.size();
  92. for (int i = 0; i < n; i++) {
  93. Predicate pred = (Predicate) _predicates.elementAt(i);
  94. pred.dontOptimize();
  95. pred.typeCheck(stable);
  96. }
  97. return _type = Type.NodeSet;
  98. }
  99. /**
  100. * Translate a filter expression by pushing the appropriate iterator
  101. * onto the stack.
  102. */
  103. public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
  104. if (_predicates.size() > 0) {
  105. translatePredicates(classGen, methodGen);
  106. }
  107. else {
  108. _primary.translate(classGen, methodGen);
  109. }
  110. }
  111. /**
  112. * Translate a sequence of predicates. Each predicate is translated
  113. * by constructing an instance of <code>CurrentNodeListIterator</code>
  114. * which is initialized from another iterator (recursive call), a
  115. * filter and a closure (call to translate on the predicate) and "this".
  116. */
  117. public void translatePredicates(ClassGenerator classGen,
  118. MethodGenerator methodGen) {
  119. final ConstantPoolGen cpg = classGen.getConstantPool();
  120. final InstructionList il = methodGen.getInstructionList();
  121. // If not predicates left, translate primary expression
  122. if (_predicates.size() == 0) {
  123. translate(classGen, methodGen);
  124. }
  125. else {
  126. // Translate predicates from right to left
  127. final int initCNLI = cpg.addMethodref(CURRENT_NODE_LIST_ITERATOR,
  128. "<init>",
  129. "("+NODE_ITERATOR_SIG+"Z"+
  130. CURRENT_NODE_LIST_FILTER_SIG +
  131. NODE_SIG+TRANSLET_SIG+")V");
  132. Predicate predicate = (Predicate)_predicates.lastElement();
  133. _predicates.remove(predicate);
  134. // Create a CurrentNodeListIterator
  135. il.append(new NEW(cpg.addClass(CURRENT_NODE_LIST_ITERATOR)));
  136. il.append(DUP);
  137. // Translate the rest of the predicates from right to left
  138. translatePredicates(classGen, methodGen);
  139. // Initialize CurrentNodeListIterator
  140. il.append(ICONST_1);
  141. predicate.translate(classGen, methodGen);
  142. il.append(methodGen.loadCurrentNode());
  143. il.append(classGen.loadTranslet());
  144. il.append(new INVOKESPECIAL(initCNLI));
  145. }
  146. }
  147. }