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 22package com.sun.org.apache.xalan.internal.xsltc.compiler; 23 24import com.sun.org.apache.bcel.internal.generic.ALOAD; 25import com.sun.org.apache.bcel.internal.generic.ASTORE; 26import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; 27import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; 28import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL; 29import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; 30import com.sun.org.apache.bcel.internal.generic.InstructionList; 31import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; 32import com.sun.org.apache.bcel.internal.generic.NEW; 33import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; 34import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; 35import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; 36import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; 37import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util; 38import com.sun.org.apache.xml.internal.dtm.Axis; 39import com.sun.org.apache.xml.internal.dtm.DTM; 40 41/** 42 * @author Jacek Ambroziak 43 * @author Santiago Pericas-Geertsen 44 */ 45final class ParentLocationPath extends RelativeLocationPath { 46 private Expression _step; 47 private final RelativeLocationPath _path; 48 private Type stype; 49 private boolean _orderNodes = false; 50 private boolean _axisMismatch = false; 51 52 public ParentLocationPath(RelativeLocationPath path, Expression step) { 53 _path = path; 54 _step = step; 55 _path.setParent(this); 56 _step.setParent(this); 57 58 if (_step instanceof Step) { 59 _axisMismatch = checkAxisMismatch(); 60 } 61 } 62 63 public void setAxis(int axis) { 64 _path.setAxis(axis); 65 } 66 67 public int getAxis() { 68 return _path.getAxis(); 69 } 70 71 public RelativeLocationPath getPath() { 72 return(_path); 73 } 74 75 public Expression getStep() { 76 return(_step); 77 } 78 79 public void setParser(Parser parser) { 80 super.setParser(parser); 81 _step.setParser(parser); 82 _path.setParser(parser); 83 } 84 85 public String toString() { 86 return "ParentLocationPath(" + _path + ", " + _step + ')'; 87 } 88 89 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 90 stype = _step.typeCheck(stable); 91 _path.typeCheck(stable); 92 93 if (_axisMismatch) enableNodeOrdering(); 94 95 return _type = Type.NodeSet; 96 } 97 98 public void enableNodeOrdering() { 99 SyntaxTreeNode parent = getParent(); 100 if (parent instanceof ParentLocationPath) 101 ((ParentLocationPath)parent).enableNodeOrdering(); 102 else { 103 _orderNodes = true; 104 } 105 } 106 107 /** 108 * This method is used to determine if this parent location path is a 109 * combination of two step's with axes that will create duplicate or 110 * unordered nodes. 111 */ 112 public boolean checkAxisMismatch() { 113 114 int left = _path.getAxis(); 115 int right = ((Step)_step).getAxis(); 116 117 if (((left == Axis.ANCESTOR) || (left == Axis.ANCESTORORSELF)) && 118 ((right == Axis.CHILD) || 119 (right == Axis.DESCENDANT) || 120 (right == Axis.DESCENDANTORSELF) || 121 (right == Axis.PARENT) || 122 (right == Axis.PRECEDING) || 123 (right == Axis.PRECEDINGSIBLING))) 124 return true; 125 126 if ((left == Axis.CHILD) && 127 (right == Axis.ANCESTOR) || 128 (right == Axis.ANCESTORORSELF) || 129 (right == Axis.PARENT) || 130 (right == Axis.PRECEDING)) 131 return true; 132 133 if ((left == Axis.DESCENDANT) || (left == Axis.DESCENDANTORSELF)) 134 return true; 135 136 if (((left == Axis.FOLLOWING) || (left == Axis.FOLLOWINGSIBLING)) && 137 ((right == Axis.FOLLOWING) || 138 (right == Axis.PARENT) || 139 (right == Axis.PRECEDING) || 140 (right == Axis.PRECEDINGSIBLING))) 141 return true; 142 143 if (((left == Axis.PRECEDING) || (left == Axis.PRECEDINGSIBLING)) && 144 ((right == Axis.DESCENDANT) || 145 (right == Axis.DESCENDANTORSELF) || 146 (right == Axis.FOLLOWING) || 147 (right == Axis.FOLLOWINGSIBLING) || 148 (right == Axis.PARENT) || 149 (right == Axis.PRECEDING) || 150 (right == Axis.PRECEDINGSIBLING))) 151 return true; 152 153 if ((right == Axis.FOLLOWING) && (left == Axis.CHILD)) { 154 // Special case for '@*/following::*' expressions. The resulting 155 // iterator is initialised with the parent's first child, and this 156 // can cause duplicates in the output if the parent has more than 157 // one attribute that matches the left step. 158 if (_path instanceof Step) { 159 int type = ((Step)_path).getNodeType(); 160 if (type == DTM.ATTRIBUTE_NODE) return true; 161 } 162 } 163 164 return false; 165 } 166 167 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 168 169 // Compile path iterator 170 _path.translate(classGen, methodGen); // iterator on stack.... 171 172 translateStep(classGen, methodGen); 173 } 174 175 public void translateStep(ClassGenerator classGen, MethodGenerator methodGen) { 176 final ConstantPoolGen cpg = classGen.getConstantPool(); 177 final InstructionList il = methodGen.getInstructionList(); 178 179 // Backwards branches are prohibited if an uninitialized object is 180 // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed. 181 // We don't know whether this code might contain backwards branches 182 // so we mustn't create the new object until after we've created 183 // the suspect arguments to its constructor. Instead we calculate 184 // the values of the arguments to the constructor first, store them 185 // in temporary variables, create the object and reload the 186 // arguments from the temporaries to avoid the problem. 187 188 LocalVariableGen pathTemp 189 = methodGen.addLocalVariable("parent_location_path_tmp1", 190 Util.getJCRefType(NODE_ITERATOR_SIG), 191 null, null); 192 pathTemp.setStart(il.append(new ASTORE(pathTemp.getIndex()))); 193 194 _step.translate(classGen, methodGen); 195 LocalVariableGen stepTemp 196 = methodGen.addLocalVariable("parent_location_path_tmp2", 197 Util.getJCRefType(NODE_ITERATOR_SIG), 198 null, null); 199 stepTemp.setStart(il.append(new ASTORE(stepTemp.getIndex()))); 200 201 // Create new StepIterator 202 final int initSI = cpg.addMethodref(STEP_ITERATOR_CLASS, 203 "<init>", 204 "(" 205 +NODE_ITERATOR_SIG 206 +NODE_ITERATOR_SIG 207 +")V"); 208 il.append(new NEW(cpg.addClass(STEP_ITERATOR_CLASS))); 209 il.append(DUP); 210 211 pathTemp.setEnd(il.append(new ALOAD(pathTemp.getIndex()))); 212 stepTemp.setEnd(il.append(new ALOAD(stepTemp.getIndex()))); 213 214 // Initialize StepIterator with iterators from the stack 215 il.append(new INVOKESPECIAL(initSI)); 216 217 // This is a special case for the //* path with or without predicates 218 Expression stp = _step; 219 if (stp instanceof ParentLocationPath) 220 stp = ((ParentLocationPath)stp).getStep(); 221 222 if ((_path instanceof Step) && (stp instanceof Step)) { 223 final int path = ((Step)_path).getAxis(); 224 final int step = ((Step)stp).getAxis(); 225 if ((path == Axis.DESCENDANTORSELF && step == Axis.CHILD) || 226 (path == Axis.PRECEDING && step == Axis.PARENT)) { 227 final int incl = cpg.addMethodref(NODE_ITERATOR_BASE, 228 "includeSelf", 229 "()" + NODE_ITERATOR_SIG); 230 il.append(new INVOKEVIRTUAL(incl)); 231 } 232 } 233 234 /* 235 * If this pattern contains a sequence of descendant iterators we 236 * run the risk of returning the same node several times. We put 237 * a new iterator on top of the existing one to assure node order 238 * and prevent returning a single node multiple times. 239 */ 240 if (_orderNodes) { 241 final int order = cpg.addInterfaceMethodref(DOM_INTF, 242 ORDER_ITERATOR, 243 ORDER_ITERATOR_SIG); 244 il.append(methodGen.loadDOM()); 245 il.append(SWAP); 246 il.append(methodGen.loadContextNode()); 247 il.append(new INVOKEINTERFACE(order, 3)); 248 } 249 } 250} 251