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 }