FileDocCategorySizeDatePackage
Step.javaAPI DocJava SE 5 API14097Fri Aug 26 14:55:36 BST 2005com.sun.org.apache.xalan.internal.xsltc.compiler

Step

public final class Step extends RelativeLocationPath
author
Jacek Ambroziak
author
Santiago Pericas-Geertsen
author
Morten Jorgensen

Fields Summary
private int
_axis
This step's axis as defined in class Axis.
private Vector
_predicates
A vector of predicates (filters) defined on this step - may be null
private boolean
_hadPredicates
Some simple predicates can be handled by this class (and not by the Predicate class) and will be removed from the above vector as they are handled. We use this boolean to remember if we did have any predicates.
private int
_nodeType
Type of the node test.
Constructors Summary
public Step(int axis, int nodeType, Vector predicates)


           
	_axis = axis;
	_nodeType = nodeType;
	_predicates = predicates;
    
Methods Summary
public voidaddPredicates(java.util.Vector predicates)
Returns the vector containing all predicates for this step.

	if (_predicates == null) {
	    _predicates = predicates;
	}
	else {
	    _predicates.addAll(predicates);
	}
    
public intgetAxis()
Define the axis (defined in Axis class) for this step

	return _axis;
    
public intgetNodeType()
Returns the node-type for this step

	return _nodeType;
    
public java.util.VectorgetPredicates()
Returns the vector containing all predicates for this step.

	return _predicates;
    
private booleanhasParentPattern()
Returns 'true' if this step has a parent pattern. This method will return 'false' if this step occurs on its own under an element like or .

	final SyntaxTreeNode parent = getParent();
	return (parent instanceof ParentPattern ||
		parent instanceof ParentLocationPath ||
		parent instanceof UnionPathExpr ||
		parent instanceof FilterParentPath);
    
private booleanhasPredicates()
Returns 'true' if this step has any predicates

	return _predicates != null && _predicates.size() > 0;
    
public booleanisAbbreviatedDDot()
True if this step is the abbreviated step '..'

	return _nodeType == NodeTest.ANODE && _axis == Axis.PARENT;
    
public booleanisAbbreviatedDot()
True if this step is the abbreviated step '.'

	return _nodeType == NodeTest.ANODE && _axis == Axis.SELF;
    
private booleanisPredicate()
Returns 'true' if this step is used within a predicate

	SyntaxTreeNode parent = this;
	while (parent != null) {
	    parent = parent.getParent();
	    if (parent instanceof Predicate) return true;
	}
	return false;
    
public voidsetAxis(int axis)
Get the axis (defined in Axis class) for this step

	_axis = axis;
    
public voidsetParser(com.sun.org.apache.xalan.internal.xsltc.compiler.Parser parser)
Set the parser for this element and all child predicates

	super.setParser(parser);
	if (_predicates != null) {
	    final int n = _predicates.size();
	    for (int i = 0; i < n; i++) {
		final Predicate exp = (Predicate)_predicates.elementAt(i);
		exp.setParser(parser);
		exp.setParent(this);
	    }
	}
    
public java.lang.StringtoString()
Returns a string representation of this step.

	final StringBuffer buffer = new StringBuffer("step(\"");
	buffer.append(Axis.names[_axis]).append("\", ").append(_nodeType);
	if (_predicates != null) {
	    final int n = _predicates.size();
	    for (int i = 0; i < n; i++) {
		final Predicate pred = (Predicate)_predicates.elementAt(i);
		buffer.append(", ").append(pred.toString());
	    }
	}
	return buffer.append(')").toString();
    
public voidtranslate(com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)
Translate a step by pushing the appropriate iterator onto the stack. The abbreviated steps '.' and '@attr' do not create new iterators if they are not part of a LocationPath and have no filters. In these cases a node index instead of an iterator is pushed onto the stack.

	final ConstantPoolGen cpg = classGen.getConstantPool();
	final InstructionList il = methodGen.getInstructionList();

	if (hasPredicates()) {
	    translatePredicates(classGen, methodGen);
	} else {
            int star = 0;
            String name = null;
            final XSLTC xsltc = getParser().getXSLTC();

            if (_nodeType >= DTM.NTYPES) {
		final Vector ni = xsltc.getNamesIndex();
		
                name = (String)ni.elementAt(_nodeType-DTM.NTYPES);
                star = name.lastIndexOf('*");
            }

	    // If it is an attribute, but not '@*', '@pre:*' or '@node()',
            // and has no parent
	    if (_axis == Axis.ATTRIBUTE && _nodeType != NodeTest.ATTRIBUTE
		&& _nodeType != NodeTest.ANODE && !hasParentPattern()
                && star == 0)
	    {
		int iter = cpg.addInterfaceMethodref(DOM_INTF,
						     "getTypedAxisIterator",
						     "(II)"+NODE_ITERATOR_SIG);
		il.append(methodGen.loadDOM());
		il.append(new PUSH(cpg, Axis.ATTRIBUTE));
		il.append(new PUSH(cpg, _nodeType));
		il.append(new INVOKEINTERFACE(iter, 3));
		return;
	    }

	    // Special case for '.'
	    if (isAbbreviatedDot()) {
		if (_type == Type.Node) {
		    // Put context node on stack if using Type.Node
		    il.append(methodGen.loadContextNode());
		}
		else {
		    // Wrap the context node in a singleton iterator if not.
		    int init = cpg.addMethodref(SINGLETON_ITERATOR,
						"<init>", "("+NODE_SIG+")V");
		    il.append(new NEW(cpg.addClass(SINGLETON_ITERATOR)));
		    il.append(DUP);
		    il.append(methodGen.loadContextNode());
		    il.append(new INVOKESPECIAL(init));
		}
		return;
	    }

	    // Special case for /foo/*/bar
	    SyntaxTreeNode parent = getParent();
	    if ((parent instanceof ParentLocationPath) &&
		(parent.getParent() instanceof ParentLocationPath)) {
		if ((_nodeType == NodeTest.ELEMENT) && (!_hadPredicates)) {
		    _nodeType = NodeTest.ANODE;
		}
	    }

	    // "ELEMENT" or "*" or "@*" or ".." or "@attr" with a parent.
	    switch (_nodeType) {
	    case NodeTest.ATTRIBUTE:
		_axis = Axis.ATTRIBUTE;
	    case NodeTest.ANODE:
		// DOM.getAxisIterator(int axis);
		int git = cpg.addInterfaceMethodref(DOM_INTF,
						    "getAxisIterator",
						    "(I)"+NODE_ITERATOR_SIG);
		il.append(methodGen.loadDOM());
		il.append(new PUSH(cpg, _axis));
		il.append(new INVOKEINTERFACE(git, 2));
		break;
	    default:
		if (star > 1) {
		    final String namespace;
		    if (_axis == Axis.ATTRIBUTE)
			namespace = name.substring(0,star-2);
		    else
			namespace = name.substring(0,star-1);

		    final int nsType = xsltc.registerNamespace(namespace);
		    final int ns = cpg.addInterfaceMethodref(DOM_INTF,
						    "getNamespaceAxisIterator",
						    "(II)"+NODE_ITERATOR_SIG);
		    il.append(methodGen.loadDOM());
		    il.append(new PUSH(cpg, _axis));
		    il.append(new PUSH(cpg, nsType));
		    il.append(new INVOKEINTERFACE(ns, 3));
		    break;
		}
	    case NodeTest.ELEMENT:
		// DOM.getTypedAxisIterator(int axis, int type);
		final int ty = cpg.addInterfaceMethodref(DOM_INTF,
						"getTypedAxisIterator",
						"(II)"+NODE_ITERATOR_SIG);
		// Get the typed iterator we're after
		il.append(methodGen.loadDOM());
		il.append(new PUSH(cpg, _axis));
		il.append(new PUSH(cpg, _nodeType));
		il.append(new INVOKEINTERFACE(ty, 3));

		break;
	    }
	}
    
public voidtranslatePredicates(com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)
Translate a sequence of predicates. Each predicate is translated by constructing an instance of CurrentNodeListIterator which is initialized from another iterator (recursive call), a filter and a closure (call to translate on the predicate) and "this".

	final ConstantPoolGen cpg = classGen.getConstantPool();
	final InstructionList il = methodGen.getInstructionList();

	int idx = 0;

	if (_predicates.size() == 0) {
	    translate(classGen, methodGen);
	}
	else {
	    final Predicate predicate = (Predicate)_predicates.lastElement();
	    _predicates.remove(predicate);

	    // Special case for predicates that can use the NodeValueIterator
	    // instead of an auxiliary class. Certain path/predicates pairs
	    // are translated into a base path, on top of which we place a
	    // node value iterator that tests for the desired value:
	    //   foo[@attr = 'str']  ->  foo/@attr + test(value='str')
	    //   foo[bar = 'str']    ->  foo/bar + test(value='str')
	    //   foo/bar[. = 'str']  ->  foo/bar + test(value='str')
	    if (predicate.isNodeValueTest()) {
		Step step = predicate.getStep();

		il.append(methodGen.loadDOM());
		// If the predicate's Step is simply '.' we translate this Step
		// and place the node test on top of the resulting iterator
		if (step.isAbbreviatedDot()) {
		    translate(classGen, methodGen);
		    il.append(new ICONST(DOM.RETURN_CURRENT));
		}
		// Otherwise we create a parent location path with this Step and
		// the predicates Step, and place the node test on top of that
		else {
		    ParentLocationPath path = new ParentLocationPath(this,step);
		    try {
			path.typeCheck(getParser().getSymbolTable());
		    }
		    catch (TypeCheckError e) { }
		    path.translate(classGen, methodGen);
		    il.append(new ICONST(DOM.RETURN_PARENT));
		}
		predicate.translate(classGen, methodGen);
		idx = cpg.addInterfaceMethodref(DOM_INTF,
						GET_NODE_VALUE_ITERATOR,
						GET_NODE_VALUE_ITERATOR_SIG);
		il.append(new INVOKEINTERFACE(idx, 5));
	    }            
	    // Handle '//*[n]' expression
	    else if (predicate.isNthDescendant()) {
		il.append(methodGen.loadDOM());
		// il.append(new ICONST(NodeTest.ELEMENT));
		il.append(new ICONST(predicate.getPosType()));
		predicate.translate(classGen, methodGen);
		il.append(new ICONST(0));
		idx = cpg.addInterfaceMethodref(DOM_INTF,
						"getNthDescendant",
						"(IIZ)"+NODE_ITERATOR_SIG);
		il.append(new INVOKEINTERFACE(idx, 4));
	    }
	    // Handle 'elem[n]' expression
	    else if (predicate.isNthPositionFilter()) {
		idx = cpg.addMethodref(NTH_ITERATOR_CLASS,
				       "<init>",
				       "("+NODE_ITERATOR_SIG+"I)V");
		il.append(new NEW(cpg.addClass(NTH_ITERATOR_CLASS)));
		il.append(DUP);
		translatePredicates(classGen, methodGen); // recursive call
		predicate.translate(classGen, methodGen);
		il.append(new INVOKESPECIAL(idx));
	    }
	    else {
		idx = cpg.addMethodref(CURRENT_NODE_LIST_ITERATOR,
				       "<init>",
				       "("
				       + NODE_ITERATOR_SIG
				       + CURRENT_NODE_LIST_FILTER_SIG
				       + NODE_SIG
				       + TRANSLET_SIG
				       + ")V");
		// create new CurrentNodeListIterator
		il.append(new NEW(cpg.addClass(CURRENT_NODE_LIST_ITERATOR)));
		il.append(DUP);
		translatePredicates(classGen, methodGen); // recursive call
		predicate.translateFilter(classGen, methodGen);
		
		il.append(methodGen.loadCurrentNode());
		il.append(classGen.loadTranslet());
		if (classGen.isExternal()) {
		    final String className = classGen.getClassName();
		    il.append(new CHECKCAST(cpg.addClass(className)));
		}
		il.append(new INVOKESPECIAL(idx));
	    }
	}
    
public com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypetypeCheck(com.sun.org.apache.xalan.internal.xsltc.compiler.SymbolTable stable)
Type check this step. The abbreviated steps '.' and '@attr' are assigned type node if they have no predicates. All other steps have type node-set.


	// Save this value for later - important for testing for special
	// combinations of steps and patterns than can be optimised
	_hadPredicates = hasPredicates();

	// Special case for '.'
 	//   in the case where '.' has a context such as book/. 
	//   or .[false()] we can not optimize the nodeset to a single node. 
	if (isAbbreviatedDot()) {
	    _type =  (hasParentPattern() || hasPredicates() ) ? 
		Type.NodeSet : Type.Node;
	}
	else {
	    _type = Type.NodeSet;
	}

	// Type check all predicates (expressions applied to the step)
	if (_predicates != null) {
	    final int n = _predicates.size();
	    for (int i = 0; i < n; i++) {
		final Expression pred = (Expression)_predicates.elementAt(i);
		pred.typeCheck(stable);
	    }
	}

	// Return either Type.Node or Type.NodeSet
	return _type;