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: ProcessingInstructionPattern.java,v 1.7 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.ConstantPoolGen;
  22. import com.sun.org.apache.bcel.internal.generic.GOTO;
  23. import com.sun.org.apache.bcel.internal.generic.IFEQ;
  24. import com.sun.org.apache.bcel.internal.generic.IF_ICMPEQ;
  25. import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  26. import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  27. import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
  28. import com.sun.org.apache.bcel.internal.generic.InstructionList;
  29. import com.sun.org.apache.bcel.internal.generic.PUSH;
  30. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  31. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  32. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  33. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  34. import com.sun.org.apache.xalan.internal.xsltc.dom.Axis;
  35. import com.sun.org.apache.xml.internal.dtm.DTM;
  36. /**
  37. * @author Morten Jorgensen
  38. */
  39. final class ProcessingInstructionPattern extends StepPattern {
  40. private String _name = null;
  41. private boolean _typeChecked = false;
  42. /**
  43. * Handles calls with no parameter (current node is implicit parameter).
  44. */
  45. public ProcessingInstructionPattern(String name) {
  46. super(Axis.CHILD, DTM.PROCESSING_INSTRUCTION_NODE, null);
  47. _name = name;
  48. //if (_name.equals("*")) _typeChecked = true; no wildcard allowed!
  49. }
  50. /**
  51. *
  52. */
  53. public double getDefaultPriority() {
  54. return (_name != null) ? 0.0 : -0.5;
  55. }
  56. public String toString() {
  57. if (_predicates == null)
  58. return "processing-instruction("+_name+")";
  59. else
  60. return "processing-instruction("+_name+")"+_predicates;
  61. }
  62. public void reduceKernelPattern() {
  63. _typeChecked = true;
  64. }
  65. public boolean isWildcard() {
  66. return false;
  67. }
  68. public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  69. if (hasPredicates()) {
  70. // Type check all the predicates (e -> position() = e)
  71. final int n = _predicates.size();
  72. for (int i = 0; i < n; i++) {
  73. final Predicate pred = (Predicate)_predicates.elementAt(i);
  74. pred.typeCheck(stable);
  75. }
  76. }
  77. return Type.NodeSet;
  78. }
  79. public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
  80. final ConstantPoolGen cpg = classGen.getConstantPool();
  81. final InstructionList il = methodGen.getInstructionList();
  82. // context node is on the stack
  83. int gname = cpg.addInterfaceMethodref(DOM_INTF,
  84. "getNodeName",
  85. "(I)Ljava/lang/String;");
  86. int cmp = cpg.addMethodref(STRING_CLASS,
  87. "equals", "(Ljava/lang/Object;)Z");
  88. // Push current node on the stack
  89. il.append(methodGen.loadCurrentNode());
  90. il.append(SWAP);
  91. // Overwrite current node with matching node
  92. il.append(methodGen.storeCurrentNode());
  93. // If pattern not reduced then check kernel
  94. if (!_typeChecked) {
  95. il.append(methodGen.loadCurrentNode());
  96. final int getType = cpg.addInterfaceMethodref(DOM_INTF,
  97. "getExpandedTypeID",
  98. "(I)I");
  99. il.append(methodGen.loadDOM());
  100. il.append(methodGen.loadCurrentNode());
  101. il.append(new INVOKEINTERFACE(getType, 2));
  102. il.append(new PUSH(cpg, DTM.PROCESSING_INSTRUCTION_NODE));
  103. _falseList.add(il.append(new IF_ICMPEQ(null)));
  104. }
  105. // Load the requested processing instruction name
  106. il.append(new PUSH(cpg, _name));
  107. // Load the current processing instruction's name
  108. il.append(methodGen.loadDOM());
  109. il.append(methodGen.loadCurrentNode());
  110. il.append(new INVOKEINTERFACE(gname, 2));
  111. // Compare the two strings
  112. il.append(new INVOKEVIRTUAL(cmp));
  113. _falseList.add(il.append(new IFEQ(null)));
  114. // Compile the expressions within the predicates
  115. if (hasPredicates()) {
  116. final int n = _predicates.size();
  117. for (int i = 0; i < n; i++) {
  118. Predicate pred = (Predicate)_predicates.elementAt(i);
  119. Expression exp = pred.getExpr();
  120. exp.translateDesynthesized(classGen, methodGen);
  121. _trueList.append(exp._trueList);
  122. _falseList.append(exp._falseList);
  123. }
  124. }
  125. // Backpatch true list and restore current iterator/node
  126. InstructionHandle restore;
  127. restore = il.append(methodGen.storeCurrentNode());
  128. backPatchTrueList(restore);
  129. BranchHandle skipFalse = il.append(new GOTO(null));
  130. // Backpatch false list and restore current iterator/node
  131. restore = il.append(methodGen.storeCurrentNode());
  132. backPatchFalseList(restore);
  133. _falseList.add(il.append(new GOTO(null)));
  134. // True list falls through
  135. skipFalse.setTarget(il.append(NOP));
  136. }
  137. }