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: ParentLocationPath.java,v 1.23 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.ConstantPoolGen;
  21. import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  22. import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
  23. import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  24. import com.sun.org.apache.bcel.internal.generic.InstructionList;
  25. import com.sun.org.apache.bcel.internal.generic.NEW;
  26. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  27. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  28. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  29. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  30. import com.sun.org.apache.xalan.internal.xsltc.dom.Axis;
  31. import com.sun.org.apache.xml.internal.dtm.DTM;
  32. /**
  33. * @author Jacek Ambroziak
  34. * @author Santiago Pericas-Geertsen
  35. */
  36. final class ParentLocationPath extends RelativeLocationPath {
  37. private Expression _step;
  38. private final RelativeLocationPath _path;
  39. private Type stype;
  40. private boolean _orderNodes = false;
  41. private boolean _axisMismatch = false;
  42. public ParentLocationPath(RelativeLocationPath path, Expression step) {
  43. _path = path;
  44. _step = step;
  45. _path.setParent(this);
  46. _step.setParent(this);
  47. if (_step instanceof Step) {
  48. _axisMismatch = checkAxisMismatch();
  49. }
  50. }
  51. public void setAxis(int axis) {
  52. _path.setAxis(axis);
  53. }
  54. public int getAxis() {
  55. return _path.getAxis();
  56. }
  57. public RelativeLocationPath getPath() {
  58. return(_path);
  59. }
  60. public Expression getStep() {
  61. return(_step);
  62. }
  63. public void setParser(Parser parser) {
  64. super.setParser(parser);
  65. _step.setParser(parser);
  66. _path.setParser(parser);
  67. }
  68. public String toString() {
  69. return "ParentLocationPath(" + _path + ", " + _step + ')';
  70. }
  71. public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  72. stype = _step.typeCheck(stable);
  73. _path.typeCheck(stable);
  74. if (_axisMismatch) enableNodeOrdering();
  75. return _type = Type.NodeSet;
  76. }
  77. public void enableNodeOrdering() {
  78. SyntaxTreeNode parent = getParent();
  79. if (parent instanceof ParentLocationPath)
  80. ((ParentLocationPath)parent).enableNodeOrdering();
  81. else {
  82. _orderNodes = true;
  83. }
  84. }
  85. /**
  86. * This method is used to determine if this parent location path is a
  87. * combination of two step's with axes that will create duplicate or
  88. * unordered nodes.
  89. */
  90. public boolean checkAxisMismatch() {
  91. int left = _path.getAxis();
  92. int right = ((Step)_step).getAxis();
  93. if (((left == Axis.ANCESTOR) || (left == Axis.ANCESTORORSELF)) &&
  94. ((right == Axis.CHILD) ||
  95. (right == Axis.DESCENDANT) ||
  96. (right == Axis.DESCENDANTORSELF) ||
  97. (right == Axis.PARENT) ||
  98. (right == Axis.PRECEDING) ||
  99. (right == Axis.PRECEDINGSIBLING)))
  100. return true;
  101. if ((left == Axis.CHILD) &&
  102. (right == Axis.ANCESTOR) ||
  103. (right == Axis.ANCESTORORSELF) ||
  104. (right == Axis.PARENT) ||
  105. (right == Axis.PRECEDING))
  106. return true;
  107. if ((left == Axis.DESCENDANT) || (left == Axis.DESCENDANTORSELF))
  108. return true;
  109. if (((left == Axis.FOLLOWING) || (left == Axis.FOLLOWINGSIBLING)) &&
  110. ((right == Axis.FOLLOWING) ||
  111. (right == Axis.PARENT) ||
  112. (right == Axis.PRECEDING) ||
  113. (right == Axis.PRECEDINGSIBLING)))
  114. return true;
  115. if (((left == Axis.PRECEDING) || (left == Axis.PRECEDINGSIBLING)) &&
  116. ((right == Axis.DESCENDANT) ||
  117. (right == Axis.DESCENDANTORSELF) ||
  118. (right == Axis.FOLLOWING) ||
  119. (right == Axis.FOLLOWINGSIBLING) ||
  120. (right == Axis.PARENT) ||
  121. (right == Axis.PRECEDING) ||
  122. (right == Axis.PRECEDINGSIBLING)))
  123. return true;
  124. if ((right == Axis.FOLLOWING) && (left == Axis.CHILD)) {
  125. // Special case for '@*/following::*' expressions. The resulting
  126. // iterator is initialised with the parent's first child, and this
  127. // can cause duplicates in the output if the parent has more than
  128. // one attribute that matches the left step.
  129. if (_path instanceof Step) {
  130. int type = ((Step)_path).getNodeType();
  131. if (type == DTM.ATTRIBUTE_NODE) return true;
  132. }
  133. }
  134. return false;
  135. }
  136. public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
  137. final ConstantPoolGen cpg = classGen.getConstantPool();
  138. final InstructionList il = methodGen.getInstructionList();
  139. // Create new StepIterator
  140. final int initSI = cpg.addMethodref(STEP_ITERATOR_CLASS,
  141. "<init>",
  142. "("
  143. +NODE_ITERATOR_SIG
  144. +NODE_ITERATOR_SIG
  145. +")V");
  146. il.append(new NEW(cpg.addClass(STEP_ITERATOR_CLASS)));
  147. il.append(DUP);
  148. // Compile path iterator
  149. _path.translate(classGen, methodGen); // iterator on stack....
  150. _step.translate(classGen, methodGen);
  151. // Initialize StepIterator with iterators from the stack
  152. il.append(new INVOKESPECIAL(initSI));
  153. // This is a special case for the //* path with or without predicates
  154. Expression stp = _step;
  155. if (stp instanceof ParentLocationPath)
  156. stp = ((ParentLocationPath)stp).getStep();
  157. if ((_path instanceof Step) && (stp instanceof Step)) {
  158. final int path = ((Step)_path).getAxis();
  159. final int step = ((Step)stp).getAxis();
  160. if ((path == Axis.DESCENDANTORSELF && step == Axis.CHILD) ||
  161. (path == Axis.PRECEDING && step == Axis.PARENT)) {
  162. final int incl = cpg.addMethodref(NODE_ITERATOR_BASE,
  163. "includeSelf",
  164. "()" + NODE_ITERATOR_SIG);
  165. il.append(new INVOKEVIRTUAL(incl));
  166. }
  167. }
  168. /*
  169. * If this pattern contains a sequence of descendant iterators we
  170. * run the risk of returning the same node several times. We put
  171. * a new iterator on top of the existing one to assure node order
  172. * and prevent returning a single node multiple times.
  173. */
  174. if (_orderNodes) {
  175. final int order = cpg.addInterfaceMethodref(DOM_INTF,
  176. ORDER_ITERATOR,
  177. ORDER_ITERATOR_SIG);
  178. il.append(methodGen.loadDOM());
  179. il.append(SWAP);
  180. il.append(methodGen.loadContextNode());
  181. il.append(new INVOKEINTERFACE(order, 3));
  182. }
  183. }
  184. }