Expression e2 = ExpressionTool.tryToFactorOutDot(this, contextItemType);
if (e2 != null) {
return e2;
}
}
final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy();
final Optimizer opt = visitor.getConfiguration().getOptimizer();
Expression head = null;
Expression selection = sequence;
ItemType selectionContextItemType = contextItemType;
if (sequence instanceof PathExpression) {
if (((PathExpression)sequence).isAbsolute(th)) {
head = ((PathExpression)sequence).getFirstStep();
selection = ((PathExpression)sequence).getRemainingSteps();
selectionContextItemType = head.getItemType(th);
} else {
PathExpression p = ((PathExpression)sequence).tryToMakeAbsolute(th);
if (p != null) {
sequence = p;
adoptChildExpression(p);
head = ((PathExpression)sequence).getFirstStep();
selection = ((PathExpression)sequence).getRemainingSteps();
selectionContextItemType = head.getItemType(th);
}
}
}
boolean changed = false;
Expression condition = ((Choose)action).getConditions()[0];
List list = new ArrayList(4);
BooleanExpression.listAndComponents(condition, list);
for (int t=list.size()-1; t>=0; t--) {
// Process each term in the where clause independently
Expression term = (Expression)list.get(t);
if (positionVariable != null &&
(term instanceof ValueComparison || term instanceof SingletonComparison)) {
BinaryExpression comp = (BinaryExpression)term;
Expression[] operands = comp.getOperands();
for (int op=0; op<2; op++) {
// If the where clause is a simple test on the position variable, for example
// for $x at $p in EXPR where $p = 5 return A
// then absorb the where condition into a predicate, rewriting it as
// for $x in EXPR[position() = 5] return A
// This takes advantage of the optimizations applied to positional filter expressions
// Only do this if the sequence expression has not yet been changed, because
// the position in a predicate after the first is different.
Binding[] thisVar = {this};
if (positionVariable != null && operands[op] instanceof VariableReference && !changed) {
List varRefs = new ArrayList();
ExpressionTool.gatherVariableReferences(action, positionVariable, varRefs);
if (varRefs.size() == 1 && varRefs.get(0) == operands[op] &&
!ExpressionTool.dependsOnFocus(operands[1-op]) &&
!ExpressionTool.dependsOnVariable(operands[1-op], thisVar)) {
FunctionCall position =
SystemFunction.makeSystemFunction("position", SimpleExpression.NO_ARGUMENTS);
Expression predicate;
if (term instanceof ValueComparison) {
if (op==0) {
predicate = new ValueComparison(position, comp.getOperator(), operands[1]);
} else {
predicate = new ValueComparison(operands[0], comp.getOperator(), position);
}
} else { // term instanceof SingletonComparison
boolean checkTypes = ((SingletonComparison)term).needsRuntimeComparabilityCheck();
if (op==0) {
predicate = new SingletonComparison(
position, comp.getOperator(), operands[1], checkTypes);
} else {
predicate = new SingletonComparison(
operands[0], comp.getOperator(), position, checkTypes);
}
}
selection = new FilterExpression(selection, predicate);
ExpressionTool.copyLocationInfo(this, selection);
selection = visitor.typeCheck(selection, selectionContextItemType);
positionVariable = null;
list.remove(t);
changed = true;
break;
}
}
}
}
if (positionVariable == null) {
Binding[] thisVar = {this};
if (opt.isVariableReplaceableByDot(term, thisVar) && !ExpressionTool.dependsOnFocus(term)) {
boolean useDotDirectly = opt.isVariableReplaceableByDot(term, thisVar);
Expression replacement;
// When rewriting the where expression as a filter, we have to replace references to the
// range variable by references to the context item. If we can do this directly, we do. But
// if the reference to the range variable occurs inside a predicate, or on the rhs of slash,
// we have to bind a new variable to the context item. So for example "for $x in S where
// T[abc = $x]" gets rewritten as "for $x in S[let $dot := . return T[abc = $dot]]"
if (useDotDirectly) {
replacement = new ContextItemExpression();
} else {
LetExpression let = new LetExpression();
let.setVariableQName(
new StructuredQName("saxon", NamespaceConstant.SAXON, "dot" + hashCode()));
let.setRequiredType(SequenceType.makeSequenceType(contextItemType, StaticProperty.EXACTLY_ONE));
let.setSequence(new ContextItemExpression());
let.setAction(term);
term = let;
replacement = new VariableReference(let);
}
PromotionOffer offer = new PromotionOffer(visitor.getConfiguration().getOptimizer());
offer.action = PromotionOffer.INLINE_VARIABLE_REFERENCES;
offer.bindingList = thisVar;
offer.containingExpression = replacement;
Expression newTerm = term.promote(offer, this);
if (newTerm != null && offer.accepted) {
Expression predicate = visitor.typeCheck(newTerm, sequence.getItemType(th));
// If the result of the predicate might be a number, wrap it in a call of boolean()
int rel = th.relationship(predicate.getItemType(th), BuiltInAtomicType.INTEGER);
if (rel != TypeHierarchy.DISJOINT) {
predicate = SystemFunction.makeSystemFunction("boolean", new Expression[]{predicate});
}
selection = new FilterExpression(selection, predicate);
ExpressionTool.copyLocationInfo(this, selection);