- /*
- * Copyright 2001-2004 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.23 2004/02/16 22:24:29 minchau Exp $
- */
-
- package com.sun.org.apache.xalan.internal.xsltc.compiler;
-
- 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.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.dom.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) {
- final ConstantPoolGen cpg = classGen.getConstantPool();
- final InstructionList il = methodGen.getInstructionList();
-
- // 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);
-
- // Compile path iterator
- _path.translate(classGen, methodGen); // iterator on stack....
- _step.translate(classGen, methodGen);
-
- // 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));
- }
- }
- }