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