// We distinguish three cases for the second operand: either it is known statically to deliver
// nodes only (a traditional path expression), or it is known statically to deliver atomic values
// only (a simple mapping expression), or we don't yet know.
ItemType stepType = step.getItemType(th);
if (th.isSubType(stepType, Type.NODE_TYPE)) {
if ((step.getSpecialProperties() & StaticProperty.NON_CREATIVE) != 0) {
// A traditional path expression
// We don't need the operands to be sorted; any sorting that's needed
// will be done at the top level
Optimizer opt = visitor.getConfiguration().getOptimizer();
setStartExpression(ExpressionTool.unsorted(opt, start, false));
setStepExpression(ExpressionTool.unsorted(opt, step, false));
// Try to simplify expressions such as a//b
PathExpression p = simplifyDescendantPath(visitor.getStaticContext());
if (p != null) {
ExpressionTool.copyLocationInfo(this, p);
return visitor.typeCheck(visitor.simplify(p), contextItemType);
} else {
// a failed attempt to simplify the expression may corrupt the parent pointers
adoptChildExpression(start);
adoptChildExpression(step);
}
}
// Decide whether the result needs to be wrapped in a sorting
// expression to deliver the results in document order
int props = getSpecialProperties();
if ((props & StaticProperty.ORDERED_NODESET) != 0) {
return this;
} else if ((props & StaticProperty.REVERSE_DOCUMENT_ORDER) != 0) {
return SystemFunction.makeSystemFunction("reverse", new Expression[]{this});
} else {
return new DocumentSorter(this);
}
} else if (stepType.isAtomicType()) {
// This is a simple mapping expression: a/b where b returns atomic values
SimpleMappingExpression sme = new SimpleMappingExpression(start, step, false);
ExpressionTool.copyLocationInfo(this, sme);
return visitor.typeCheck(visitor.simplify(sme), contextItemType);
} else {