1 package net.sf.saxon.expr; 2 import net.sf.saxon.om.Item; 3 import net.sf.saxon.om.NamePool; 4 import net.sf.saxon.om.SequenceIterator; 5 import net.sf.saxon.om.ValueRepresentation; 6 import net.sf.saxon.trace.Location; 7 import net.sf.saxon.trans.XPathException; 8 import net.sf.saxon.type.ItemType; 9 import net.sf.saxon.type.SchemaType; 10 import net.sf.saxon.value.Cardinality; 11 import net.sf.saxon.value.EmptySequence; 12 import net.sf.saxon.value.IntegerValue; 13 import net.sf.saxon.value.SequenceType; 14 import net.sf.saxon.functions.SystemFunction; 15 16 import java.io.PrintStream ; 17 import java.util.ArrayList ; 18 import java.util.List ; 19 20 24 25 public class ForExpression extends Assignation { 26 27 private transient RangeVariableDeclaration positionVariable = null; 28 private PositionBinding positionBinding = null; 29 30 31 public ForExpression() { 32 } 33 34 37 38 public void setPositionVariable (RangeVariableDeclaration decl) { 39 positionVariable = decl; 40 if (decl != null) { 41 positionBinding = new PositionBinding(); 42 } 43 } 44 45 public void setAction(Expression action) { 46 super.setAction(action); 47 if (positionVariable != null) { 48 positionVariable.fixupReferences(positionBinding); 49 } 50 } 51 52 55 56 public void setSlotNumber(int nr) { 57 super.setSlotNumber(nr); 58 if (positionBinding != null) { 59 positionBinding.setSlotNumber(nr+1); 60 } 61 } 62 63 66 67 public int getRequiredSlots() { 68 return (positionBinding == null ? 1 : 2); 69 } 70 71 74 75 public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException { 76 77 81 sequence = sequence.typeCheck(env, contextItemType); 82 if (sequence instanceof EmptySequence) { 83 return EmptySequence.getInstance(); 84 } 85 86 if (declaration != null) { 87 SequenceType decl = declaration.getRequiredType(); 89 SequenceType sequenceType = SequenceType.makeSequenceType( 90 decl.getPrimaryType(), StaticProperty.ALLOWS_ZERO_OR_MORE); 91 RoleLocator role = new RoleLocator(RoleLocator.VARIABLE, new Integer (nameCode), 0, env.getNamePool()); 92 role.setSourceLocator(this); 93 sequence = TypeChecker.strictTypeCheck( 94 sequence, sequenceType, role, env); 95 ItemType actualItemType = sequence.getItemType(); 96 declaration.refineTypeInformation(actualItemType, 97 StaticProperty.EXACTLY_ONE, 98 null, 99 sequence.getSpecialProperties()); 100 } 101 102 action = action.typeCheck(env, contextItemType); 103 if (action instanceof EmptySequence) { 104 return EmptySequence.getInstance(); 105 } 106 107 return this; 108 } 109 110 113 114 public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException { 115 116 117 118 120 Expression p = promoteWhereClause(positionBinding); 121 if (p != null) { 122 return p.optimize(opt, env, contextItemType); 123 } 124 125 127 Expression pred = convertWhereToPredicate(opt, env, contextItemType); 128 if (pred != null && pred != this) { 129 return pred.optimize(opt, env, contextItemType); 130 } 131 132 int tries = 0; 133 while (tries++ < 5) { 134 Expression seq2 = sequence.optimize(opt, env, contextItemType); 135 if (seq2 == sequence) { 136 break; 137 } 138 sequence = seq2; 139 adoptChildExpression(sequence); 140 resetStaticProperties(); 141 } 142 if (sequence instanceof EmptySequence) { 143 return EmptySequence.getInstance(); 144 } 145 146 tries = 0; 147 while (tries++ < 5) { 148 Expression act2 = action.optimize(opt, env, contextItemType); 149 if (act2 == action) { 150 break; 151 } 152 action = act2; 153 adoptChildExpression(action); 154 resetStaticProperties(); 155 } 156 if (action instanceof EmptySequence) { 157 return EmptySequence.getInstance(); 158 } 159 160 Expression e2 = extractLoopInvariants(opt, env, contextItemType); 161 if (e2 != null && e2 != this) { 162 return e2.optimize(opt, env, contextItemType); 163 } 164 165 168 if (declaration != null && positionVariable==null && 169 sequence instanceof PathExpression && action instanceof PathExpression) { 170 int count = declaration.getReferenceCount(this); 171 PathExpression path2 = (PathExpression)action; 172 Expression s2 = path2.getStartExpression(); 173 if (count == 1 && s2 instanceof VariableReference && ((VariableReference)s2).getBinding() == this) { 174 PathExpression newPath = new PathExpression(sequence, path2.getStepExpression()); 175 return newPath.simplify(env).typeCheck(env, contextItemType).optimize(opt, env, contextItemType); 176 } 177 } 178 179 182 if (action instanceof VariableReference && ((VariableReference)action).getBinding() == this) { 183 return sequence; 184 } 185 186 declaration = null; 188 189 190 return this; 191 } 192 193 194 197 198 private Expression extractLoopInvariants(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException { 199 207 if (positionVariable == null) { 208 PromotionOffer offer = new PromotionOffer(opt); 209 offer.containingExpression = this; 210 offer.action = PromotionOffer.RANGE_INDEPENDENT; 211 Binding[] bindingList = {this}; 212 offer.bindingList = bindingList; 213 Container container = getParentExpression(); 214 action = doPromotion(action, offer); 215 if (offer.containingExpression instanceof LetExpression) { 216 ((ComputedExpression)offer.containingExpression).setParentExpression(container); 218 offer.containingExpression = offer.containingExpression.simplify(env).typeCheck(env, contextItemType); 220 } 221 return offer.containingExpression; 222 } 223 return null; 224 225 } 226 227 231 232 public Expression convertWhereToPredicate(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException { 233 if (action instanceof IfExpression && ((IfExpression)action).getElseExpression() instanceof EmptySequence) { 234 Expression head = null; 235 Expression selection = sequence; 236 if (sequence instanceof PathExpression && ((PathExpression)sequence).isAbsolute()) { 237 head = ((PathExpression)sequence).getFirstStep(); 238 selection = ((PathExpression)sequence).getRemainingSteps(); 239 } 240 241 boolean changed = false; 242 IfExpression condAction = (IfExpression)action; 243 List list = new ArrayList (4); 244 BooleanExpression.listAndComponents(condAction.getCondition(), list); 245 for (int t=list.size()-1; t>=0; t--) { 246 Expression term = (Expression)list.get(t); 248 249 if (term instanceof ValueComparison) { 250 ValueComparison comp = (ValueComparison)term; 251 Expression[] operands = comp.getOperands(); 252 for (int op=0; op<2; op++) { 253 254 262 if (positionVariable != null && positionVariable.getReferenceList().size() == 1 && !changed) { 263 if (operands[op] instanceof VariableReference && 264 ((VariableReference)operands[op]).getBinding() == positionBinding && 265 (operands[1-op].getDependencies() & StaticProperty.DEPENDS_ON_FOCUS) == 0) { 266 FunctionCall position = 267 SystemFunction.makeSystemFunction("position", 1, env.getNamePool()); 268 position.setArguments(SimpleExpression.NO_ARGUMENTS); 269 Expression predicate; 270 if (op==0) { 271 predicate = new ValueComparison(position, comp.getOperator(), operands[1]); 272 } else { 273 predicate = new ValueComparison(operands[0], comp.getOperator(), position); 274 } 275 selection = new FilterExpression(selection, predicate, env); 276 positionVariable = null; 278 positionBinding = null; 279 list.remove(t); 280 changed = true; 281 break; 282 } 284 } 285 286 293 Binding[] thisVar = {this}; 294 if ( positionVariable == null && 295 ExpressionTool.isVariableReplaceableByDot(term, thisVar) && 296 (term.getDependencies() & StaticProperty.DEPENDS_ON_FOCUS) == 0 && 297 ExpressionTool.dependsOnVariable(operands[op], thisVar) && 298 !ExpressionTool.dependsOnVariable(operands[1-op], thisVar)) { 299 PromotionOffer offer = new PromotionOffer(opt); 300 offer.action = PromotionOffer.INLINE_VARIABLE_REFERENCES; 301 offer.bindingList = thisVar; 302 offer.containingExpression = new ContextItemExpression(); 303 Expression newOperand = operands[op].promote(offer); 304 if (newOperand != null && offer.accepted) { 305 Expression predicate; 306 if (op==0) { 307 predicate = new ValueComparison(newOperand, comp.getOperator(), operands[1]); 308 } else { 309 predicate = new ValueComparison(operands[0], comp.getOperator(), newOperand); 310 } 311 predicate = predicate.typeCheck(env, sequence.getItemType()); 312 selection = new FilterExpression(selection, predicate, env); 313 changed = true; 314 positionVariable = null; 315 positionBinding = null; 316 list.remove(t); 317 } 318 } 319 } 320 } else if (term instanceof GeneralComparison) { 321 GeneralComparison comp = (GeneralComparison)term; 322 Expression[] operands = comp.getOperands(); 323 for (int op=0; op<2; op++) { 324 325 332 Binding[] thisVar = {this}; 333 if (positionVariable == null && 334 ExpressionTool.isVariableReplaceableByDot(term, thisVar) && 335 (term.getDependencies() & StaticProperty.DEPENDS_ON_FOCUS) == 0 && 336 ExpressionTool.dependsOnVariable(operands[op], thisVar) && 337 !ExpressionTool.dependsOnVariable(operands[1-op], thisVar)) { 338 PromotionOffer offer = new PromotionOffer(opt); 339 offer.action = PromotionOffer.INLINE_VARIABLE_REFERENCES; 340 offer.bindingList = thisVar; 341 offer.containingExpression = new ContextItemExpression(); 342 Expression newOperand = operands[op].promote(offer); 343 if (newOperand != null && !ExpressionTool.dependsOnVariable(newOperand, thisVar)) { 344 if (newOperand instanceof ComputedExpression) { 345 ((ComputedExpression)newOperand).resetStaticProperties(); 346 } 347 Expression predicate; 348 if (op==0) { 350 predicate = new GeneralComparison(newOperand, comp.getOperator(), operands[1]); 352 } else { 353 predicate = new GeneralComparison(operands[0], comp.getOperator(), newOperand); 354 } 355 selection = new FilterExpression(selection, predicate, env); 356 resetStaticProperties(); 357 positionVariable = null; 359 positionBinding = null; 360 list.remove(t); 362 changed = true; 363 break; 364 } 365 } 366 367 } 401 } 402 } 403 if (changed) { 404 if (list.isEmpty()) { 405 action = condAction.getThenExpression(); 406 adoptChildExpression(action); 407 } else { 408 Expression term = (Expression)list.get(0); 409 for (int t=1; t<list.size(); t++) { 410 term = new BooleanExpression(term, Token.AND, (Expression)list.get(t)); 411 } 412 condAction.setCondition(term); 413 } 414 if (head == null) { 415 sequence = selection; 416 } else { 417 PathExpression path = new PathExpression(head, selection); 418 path.setParentExpression(this); 419 Expression k = opt.convertPathExpressionToKey(path, env); 420 if (k == null) { 421 sequence = path; 422 } else { 423 sequence = k; 424 } 425 sequence = sequence.simplify(env).typeCheck(env, contextItemType).optimize(opt, env, contextItemType); 426 adoptChildExpression(sequence); 427 } 428 return this; 429 } 430 } 431 return null; 432 } 433 434 438 439 public boolean markTailFunctionCalls() { 440 if (!Cardinality.allowsMany(sequence.getCardinality())) { 441 return ExpressionTool.markTailFunctionCalls(action); 442 } else { 443 return false; 444 } 445 } 446 447 450 451 protected Binding[] extendBindingList(Binding[] in) { 452 if (positionBinding == null) { 453 return super.extendBindingList(in); 454 } 455 Binding[] newBindingList = new Binding[in.length+2]; 456 System.arraycopy(in, 0, newBindingList, 0, in.length); 457 newBindingList[in.length] = this; 458 newBindingList[in.length+1] = positionBinding; 459 return newBindingList; 460 } 461 462 467 468 public int getImplementationMethod() { 469 return ITERATE_METHOD | PROCESS_METHOD; 470 } 471 472 479 480 public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { 481 action.checkPermittedContents(parentType, env, false); 482 } 483 484 487 488 public SequenceIterator iterate(XPathContext context) throws XPathException { 489 490 492 497 SequenceIterator base = sequence.iterate(context); 498 499 MappingFunction map = new MappingAction(context, slotNumber, positionBinding, action); 500 return new MappingIterator(base, map, null); 501 } 502 503 507 508 public void process(XPathContext context) throws XPathException { 509 SequenceIterator iter = sequence.iterate(context); 510 int position = 1; 511 while (true) { 512 Item item = iter.next(); 513 if (item == null) break; 514 context.setLocalVariable(slotNumber, item); 515 if (positionBinding != null) { 516 positionBinding.setPosition(position++, context); 517 } 518 action.process(context); 519 } 520 } 521 522 527 528 public ItemType getItemType() { 529 return action.getItemType(); 530 } 531 532 535 536 public int computeCardinality() { 537 int c1 = sequence.getCardinality(); 538 int c2 = action.getCardinality(); 539 return Cardinality.multiply(c1, c2); 540 } 541 542 545 546 public void display(int level, NamePool pool, PrintStream out) { 547 out.println(ExpressionTool.indent(level) + 548 "for $" + getVariableName(pool) + 549 (positionVariable == null ? "" : " at $?") + 550 " in"); 551 sequence.display(level+1, pool, out); 552 out.println(ExpressionTool.indent(level) + "return"); 553 action.display(level+1, pool, out); 554 } 555 556 561 562 private static class MappingAction implements MappingFunction { 563 564 private XPathContext context; 565 private int slotNumber; 566 private Expression action; 567 private PositionBinding positionBinding; 568 private int position = 1; 569 570 public MappingAction(XPathContext context, 571 int slotNumber, 572 PositionBinding positionBinding, 573 Expression action) { 574 this.context = context; 575 this.slotNumber = slotNumber; 576 this.positionBinding = positionBinding; 577 this.action = action; 578 } 579 580 public Object map(Item item, XPathContext c) throws XPathException { 581 context.setLocalVariable(slotNumber, item); 582 if (positionBinding != null) { 583 positionBinding.setPosition(position++, context); 584 } 585 return action.iterate(context); 586 } 587 } 588 589 593 594 protected int getConstructType() { 595 return Location.FOR_EXPRESSION; 596 } 597 598 604 605 private static class PositionBinding implements Binding { 606 607 private int slotNumber; 608 609 private void setSlotNumber(int slot) { 610 this.slotNumber = slot; 611 } 612 613 private void setPosition(int position, XPathContext context) { 614 context.setLocalVariable(slotNumber, new IntegerValue(position)); 615 } 616 617 621 622 public final boolean isGlobal() { 623 return false; 624 } 625 626 631 632 public final boolean isAssignable() { 633 return false; 634 } 635 636 640 641 public int getLocalSlotNumber() { 642 return slotNumber; 643 } 644 645 public ValueRepresentation evaluateVariable(XPathContext context) throws XPathException { 646 return context.evaluateLocalVariable(slotNumber); 647 } 648 649 } 650 651 } 652 653 654 655 | Popular Tags |