/* * reserved comment block * DO NOT REMOVE OR ALTER! */ /* * Copyright 2001-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Id: ParentLocationPath.java,v 1.2.4.1 2005/09/12 10:56:30 pvedula Exp $ */ package com.sun.org.apache.xalan.internal.xsltc.compiler; import com.sun.org.apache.bcel.internal.generic.ALOAD; import com.sun.org.apache.bcel.internal.generic.ASTORE; import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL; import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; import com.sun.org.apache.bcel.internal.generic.InstructionList; import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; import com.sun.org.apache.bcel.internal.generic.NEW; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util; import com.sun.org.apache.xml.internal.dtm.Axis; import com.sun.org.apache.xml.internal.dtm.DTM; /** * @author Jacek Ambroziak * @author Santiago Pericas-Geertsen */ final class ParentLocationPath extends RelativeLocationPath { private Expression _step; private final RelativeLocationPath _path; private Type stype; private boolean _orderNodes = false; private boolean _axisMismatch = false; public ParentLocationPath(RelativeLocationPath path, Expression step) { _path = path; _step = step; _path.setParent(this); _step.setParent(this); if (_step instanceof Step) { _axisMismatch = checkAxisMismatch(); } } public void setAxis(int axis) { _path.setAxis(axis); } public int getAxis() { return _path.getAxis(); } public RelativeLocationPath getPath() { return(_path); } public Expression getStep() { return(_step); } public void setParser(Parser parser) { super.setParser(parser); _step.setParser(parser); _path.setParser(parser); } public String toString() { return "ParentLocationPath(" + _path + ", " + _step + ')'; } public Type typeCheck(SymbolTable stable) throws TypeCheckError { stype = _step.typeCheck(stable); _path.typeCheck(stable); if (_axisMismatch) enableNodeOrdering(); return _type = Type.NodeSet; } public void enableNodeOrdering() { SyntaxTreeNode parent = getParent(); if (parent instanceof ParentLocationPath) ((ParentLocationPath)parent).enableNodeOrdering(); else { _orderNodes = true; } } /** * This method is used to determine if this parent location path is a * combination of two step's with axes that will create duplicate or * unordered nodes. */ public boolean checkAxisMismatch() { int left = _path.getAxis(); int right = ((Step)_step).getAxis(); if (((left == Axis.ANCESTOR) || (left == Axis.ANCESTORORSELF)) && ((right == Axis.CHILD) || (right == Axis.DESCENDANT) || (right == Axis.DESCENDANTORSELF) || (right == Axis.PARENT) || (right == Axis.PRECEDING) || (right == Axis.PRECEDINGSIBLING))) return true; if ((left == Axis.CHILD) && (right == Axis.ANCESTOR) || (right == Axis.ANCESTORORSELF) || (right == Axis.PARENT) || (right == Axis.PRECEDING)) return true; if ((left == Axis.DESCENDANT) || (left == Axis.DESCENDANTORSELF)) return true; if (((left == Axis.FOLLOWING) || (left == Axis.FOLLOWINGSIBLING)) && ((right == Axis.FOLLOWING) || (right == Axis.PARENT) || (right == Axis.PRECEDING) || (right == Axis.PRECEDINGSIBLING))) return true; if (((left == Axis.PRECEDING) || (left == Axis.PRECEDINGSIBLING)) && ((right == Axis.DESCENDANT) || (right == Axis.DESCENDANTORSELF) || (right == Axis.FOLLOWING) || (right == Axis.FOLLOWINGSIBLING) || (right == Axis.PARENT) || (right == Axis.PRECEDING) || (right == Axis.PRECEDINGSIBLING))) return true; if ((right == Axis.FOLLOWING) && (left == Axis.CHILD)) { // Special case for '@*/following::*' expressions. The resulting // iterator is initialised with the parent's first child, and this // can cause duplicates in the output if the parent has more than // one attribute that matches the left step. if (_path instanceof Step) { int type = ((Step)_path).getNodeType(); if (type == DTM.ATTRIBUTE_NODE) return true; } } return false; } public void translate(ClassGenerator classGen, MethodGenerator methodGen) { // Compile path iterator _path.translate(classGen, methodGen); // iterator on stack.... translateStep(classGen, methodGen); } public void translateStep(ClassGenerator classGen, MethodGenerator methodGen) { final ConstantPoolGen cpg = classGen.getConstantPool(); final InstructionList il = methodGen.getInstructionList(); // Backwards branches are prohibited if an uninitialized object is // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed. // We don't know whether this code might contain backwards branches // so we mustn't create the new object until after we've created // the suspect arguments to its constructor. Instead we calculate // the values of the arguments to the constructor first, store them // in temporary variables, create the object and reload the // arguments from the temporaries to avoid the problem. LocalVariableGen pathTemp = methodGen.addLocalVariable("parent_location_path_tmp1", Util.getJCRefType(NODE_ITERATOR_SIG), null, null); pathTemp.setStart(il.append(new ASTORE(pathTemp.getIndex()))); _step.translate(classGen, methodGen); LocalVariableGen stepTemp = methodGen.addLocalVariable("parent_location_path_tmp2", Util.getJCRefType(NODE_ITERATOR_SIG), null, null); stepTemp.setStart(il.append(new ASTORE(stepTemp.getIndex()))); // Create new StepIterator final int initSI = cpg.addMethodref(STEP_ITERATOR_CLASS, "<init>", "(" +NODE_ITERATOR_SIG +NODE_ITERATOR_SIG +")V"); il.append(new NEW(cpg.addClass(STEP_ITERATOR_CLASS))); il.append(DUP); pathTemp.setEnd(il.append(new ALOAD(pathTemp.getIndex()))); stepTemp.setEnd(il.append(new ALOAD(stepTemp.getIndex()))); // Initialize StepIterator with iterators from the stack il.append(new INVOKESPECIAL(initSI)); // This is a special case for the //* path with or without predicates Expression stp = _step; if (stp instanceof ParentLocationPath) stp = ((ParentLocationPath)stp).getStep(); if ((_path instanceof Step) && (stp instanceof Step)) { final int path = ((Step)_path).getAxis(); final int step = ((Step)stp).getAxis(); if ((path == Axis.DESCENDANTORSELF && step == Axis.CHILD) || (path == Axis.PRECEDING && step == Axis.PARENT)) { final int incl = cpg.addMethodref(NODE_ITERATOR_BASE, "includeSelf", "()" + NODE_ITERATOR_SIG); il.append(new INVOKEVIRTUAL(incl)); } } /* * If this pattern contains a sequence of descendant iterators we * run the risk of returning the same node several times. We put * a new iterator on top of the existing one to assure node order * and prevent returning a single node multiple times. */ if (_orderNodes) { final int order = cpg.addInterfaceMethodref(DOM_INTF, ORDER_ITERATOR, ORDER_ITERATOR_SIG); il.append(methodGen.loadDOM()); il.append(SWAP); il.append(methodGen.loadContextNode()); il.append(new INVOKEINTERFACE(order, 3)); } } }