1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Copyright 2001-2005 The Apache Software Foundation. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 /* 21 * $Id: FilterParentPath.java,v 1.2.4.1 2005/09/12 10:24:55 pvedula Exp $ 22 */ 23 24 package com.sun.org.apache.xalan.internal.xsltc.compiler; 25 26 import com.sun.org.apache.bcel.internal.generic.ALOAD; 27 import com.sun.org.apache.bcel.internal.generic.ASTORE; 28 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; 29 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; 30 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL; 31 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; 32 import com.sun.org.apache.bcel.internal.generic.InstructionList; 33 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; 34 import com.sun.org.apache.bcel.internal.generic.NEW; 35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; 36 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; 37 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType; 38 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeType; 39 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType; 40 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; 41 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; 42 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util; 43 44 /** 45 * @author Jacek Ambroziak 46 * @author Santiago Pericas-Geertsen 47 */ 48 final class FilterParentPath extends Expression { 49 50 private Expression _filterExpr; 51 private Expression _path; 52 private boolean _hasDescendantAxis = false; 53 54 public FilterParentPath(Expression filterExpr, Expression path) { 55 (_path = path).setParent(this); 56 (_filterExpr = filterExpr).setParent(this); 57 } 58 59 public void setParser(Parser parser) { 60 super.setParser(parser); 61 _filterExpr.setParser(parser); 62 _path.setParser(parser); 63 } 64 65 public String toString() { 66 return "FilterParentPath(" + _filterExpr + ", " + _path + ')'; 67 } 68 69 public void setDescendantAxis() { 70 _hasDescendantAxis = true; 71 } 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 is 76 * needed for expressions like $x/LINE where $x is a parameter reference. 77 */ 78 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 79 final Type ftype = _filterExpr.typeCheck(stable); 80 if (ftype instanceof NodeSetType == false) { 81 if (ftype instanceof ReferenceType) { 82 _filterExpr = new CastExpr(_filterExpr, Type.NodeSet); 83 } 84 /* 85 else if (ftype instanceof ResultTreeType) { 86 _filterExpr = new CastExpr(_filterExpr, Type.NodeSet); 87 } 88 */ 89 else if (ftype instanceof NodeType) { 90 _filterExpr = new CastExpr(_filterExpr, Type.NodeSet); 91 } 92 else { 93 throw new TypeCheckError(this); 94 } 95 } 96 97 // Wrap single node path in a node set 98 final Type ptype = _path.typeCheck(stable); 99 if (!(ptype instanceof NodeSetType)) { 100 _path = new CastExpr(_path, Type.NodeSet); 101 } 102 103 return _type = Type.NodeSet; 104 } 105 106 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 107 final ConstantPoolGen cpg = classGen.getConstantPool(); 108 final InstructionList il = methodGen.getInstructionList(); 109 // Create new StepIterator 110 final int initSI = cpg.addMethodref(STEP_ITERATOR_CLASS, 111 "<init>", 112 "(" 113 +NODE_ITERATOR_SIG 114 +NODE_ITERATOR_SIG 115 +")V"); 116 117 // Backwards branches are prohibited if an uninitialized object is 118 // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed. 119 // We don't know whether this code might contain backwards branches, 120 // so we mustn't create the new object until after we've created 121 // the suspect arguments to its constructor. Instead we calculate 122 // the values of the arguments to the constructor first, store them 123 // in temporary variables, create the object and reload the 124 // arguments from the temporaries to avoid the problem. 125 126 // Recursively compile 2 iterators 127 _filterExpr.translate(classGen, methodGen); 128 LocalVariableGen filterTemp = 129 methodGen.addLocalVariable("filter_parent_path_tmp1", 130 Util.getJCRefType(NODE_ITERATOR_SIG), 131 null, null); 132 filterTemp.setStart(il.append(new ASTORE(filterTemp.getIndex()))); 133 134 _path.translate(classGen, methodGen); 135 LocalVariableGen pathTemp = 136 methodGen.addLocalVariable("filter_parent_path_tmp2", 137 Util.getJCRefType(NODE_ITERATOR_SIG), 138 null, null); 139 pathTemp.setStart(il.append(new ASTORE(pathTemp.getIndex()))); 140 141 il.append(new NEW(cpg.addClass(STEP_ITERATOR_CLASS))); 142 il.append(DUP); 143 filterTemp.setEnd(il.append(new ALOAD(filterTemp.getIndex()))); 144 pathTemp.setEnd(il.append(new ALOAD(pathTemp.getIndex()))); 145 146 // Initialize StepIterator with iterators from the stack 147 il.append(new INVOKESPECIAL(initSI)); 148 149 // This is a special case for the //* path with or without predicates 150 if (_hasDescendantAxis) { 151 final int incl = cpg.addMethodref(NODE_ITERATOR_BASE, 152 "includeSelf", 153 "()" + NODE_ITERATOR_SIG); 154 il.append(new INVOKEVIRTUAL(incl)); 155 } 156 157 SyntaxTreeNode parent = getParent(); 158 159 boolean parentAlreadyOrdered = 160 (parent instanceof RelativeLocationPath) 161 || (parent instanceof FilterParentPath) 162 || (parent instanceof KeyCall) 163 || (parent instanceof CurrentCall) 164 || (parent instanceof DocumentCall); 165 166 if (!parentAlreadyOrdered) { 167 final int order = cpg.addInterfaceMethodref(DOM_INTF, 168 ORDER_ITERATOR, 169 ORDER_ITERATOR_SIG); 170 il.append(methodGen.loadDOM()); 171 il.append(SWAP); 172 il.append(methodGen.loadContextNode()); 173 il.append(new INVOKEINTERFACE(order, 3)); 174 } 175 } 176 }