001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 /*
019 * $Id: ProcessingInstructionPattern.java 468650 2006-10-28 07:03:30Z minchau $
020 */
021
022 package org.apache.xalan.xsltc.compiler;
023
024 import org.apache.bcel.generic.BranchHandle;
025 import org.apache.bcel.generic.ConstantPoolGen;
026 import org.apache.bcel.generic.GOTO;
027 import org.apache.bcel.generic.IFEQ;
028 import org.apache.bcel.generic.IF_ICMPEQ;
029 import org.apache.bcel.generic.INVOKEINTERFACE;
030 import org.apache.bcel.generic.INVOKEVIRTUAL;
031 import org.apache.bcel.generic.InstructionHandle;
032 import org.apache.bcel.generic.InstructionList;
033 import org.apache.bcel.generic.PUSH;
034 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
035 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
036 import org.apache.xalan.xsltc.compiler.util.Type;
037 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
038 import org.apache.xml.dtm.Axis;
039 import org.apache.xml.dtm.DTM;
040
041 /**
042 * @author Morten Jorgensen
043 */
044 final class ProcessingInstructionPattern extends StepPattern {
045
046 private String _name = null;
047 private boolean _typeChecked = false;
048
049 /**
050 * Handles calls with no parameter (current node is implicit parameter).
051 */
052 public ProcessingInstructionPattern(String name) {
053 super(Axis.CHILD, DTM.PROCESSING_INSTRUCTION_NODE, null);
054 _name = name;
055 //if (_name.equals("*")) _typeChecked = true; no wildcard allowed!
056 }
057
058 /**
059 *
060 */
061 public double getDefaultPriority() {
062 return (_name != null) ? 0.0 : -0.5;
063 }
064 public String toString() {
065 if (_predicates == null)
066 return "processing-instruction("+_name+")";
067 else
068 return "processing-instruction("+_name+")"+_predicates;
069 }
070
071 public void reduceKernelPattern() {
072 _typeChecked = true;
073 }
074
075 public boolean isWildcard() {
076 return false;
077 }
078
079 public Type typeCheck(SymbolTable stable) throws TypeCheckError {
080 if (hasPredicates()) {
081 // Type check all the predicates (e -> position() = e)
082 final int n = _predicates.size();
083 for (int i = 0; i < n; i++) {
084 final Predicate pred = (Predicate)_predicates.elementAt(i);
085 pred.typeCheck(stable);
086 }
087 }
088 return Type.NodeSet;
089 }
090
091 public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
092 final ConstantPoolGen cpg = classGen.getConstantPool();
093 final InstructionList il = methodGen.getInstructionList();
094
095 // context node is on the stack
096 int gname = cpg.addInterfaceMethodref(DOM_INTF,
097 "getNodeName",
098 "(I)Ljava/lang/String;");
099 int cmp = cpg.addMethodref(STRING_CLASS,
100 "equals", "(Ljava/lang/Object;)Z");
101
102 // Push current node on the stack
103 il.append(methodGen.loadCurrentNode());
104 il.append(SWAP);
105
106 // Overwrite current node with matching node
107 il.append(methodGen.storeCurrentNode());
108
109 // If pattern not reduced then check kernel
110 if (!_typeChecked) {
111 il.append(methodGen.loadCurrentNode());
112 final int getType = cpg.addInterfaceMethodref(DOM_INTF,
113 "getExpandedTypeID",
114 "(I)I");
115 il.append(methodGen.loadDOM());
116 il.append(methodGen.loadCurrentNode());
117 il.append(new INVOKEINTERFACE(getType, 2));
118 il.append(new PUSH(cpg, DTM.PROCESSING_INSTRUCTION_NODE));
119 _falseList.add(il.append(new IF_ICMPEQ(null)));
120 }
121
122 // Load the requested processing instruction name
123 il.append(new PUSH(cpg, _name));
124 // Load the current processing instruction's name
125 il.append(methodGen.loadDOM());
126 il.append(methodGen.loadCurrentNode());
127 il.append(new INVOKEINTERFACE(gname, 2));
128 // Compare the two strings
129 il.append(new INVOKEVIRTUAL(cmp));
130 _falseList.add(il.append(new IFEQ(null)));
131
132 // Compile the expressions within the predicates
133 if (hasPredicates()) {
134 final int n = _predicates.size();
135 for (int i = 0; i < n; i++) {
136 Predicate pred = (Predicate)_predicates.elementAt(i);
137 Expression exp = pred.getExpr();
138 exp.translateDesynthesized(classGen, methodGen);
139 _trueList.append(exp._trueList);
140 _falseList.append(exp._falseList);
141 }
142 }
143
144 // Backpatch true list and restore current iterator/node
145 InstructionHandle restore;
146 restore = il.append(methodGen.storeCurrentNode());
147 backPatchTrueList(restore);
148 BranchHandle skipFalse = il.append(new GOTO(null));
149
150 // Backpatch false list and restore current iterator/node
151 restore = il.append(methodGen.storeCurrentNode());
152 backPatchFalseList(restore);
153 _falseList.add(il.append(new GOTO(null)));
154
155 // True list falls through
156 skipFalse.setTarget(il.append(NOP));
157 }
158 }