/** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression * @param rebindings variables whose binding needs to change */ /*@NotNull*/ public Expression copy(RebindingMap rebindings) { LetExpression let = new LetExpression(); ExpressionTool.copyLocationInfo(this, let); let.isIndexedVariable = isIndexedVariable; let.hasLoopingReference = hasLoopingReference; let.setNeedsEagerEvaluation(needsEagerEvaluation); let.setNeedsLazyEvaluation(needsLazyEvaluation); let.setVariableQName(variableName); let.setRequiredType(requiredType); let.setSequence(getSequence().copy(rebindings)); let.setInstruction(isInstruction()); Expression newAction = getAction().copy(rebindings); let.setAction(newAction); ExpressionTool.rebindVariableReferences(newAction, this, let); return let; }
/** * Type-check the expression. This also has the side-effect of counting the number of references * to the variable (treating references that occur within a loop specially) */ /*@NotNull*/ public Expression typeCheck(ExpressionVisitor visitor, ContextItemStaticInfo contextInfo) throws XPathException { // The order of events is critical here. First we ensure that the type of the // sequence expression is established. This is used to establish the type of the variable, // which in turn is required when type-checking the action part. getSequenceOp().typeCheck(visitor, contextInfo); RoleDiagnostic role = new RoleDiagnostic(RoleDiagnostic.VARIABLE, getVariableQName().getDisplayName(), 0); //role.setSourceLocator(this); setSequence(TypeChecker.strictTypeCheck( getSequence(), requiredType, role, visitor.getStaticContext())); final ItemType actualItemType = getSequence().getItemType(); refineTypeInformation(actualItemType, getSequence().getCardinality(), getSequence() instanceof Literal ? ((Literal) getSequence()).getValue() : null, getSequence().getSpecialProperties(), this); getActionOp().typeCheck(visitor, contextInfo); return this; }
/** * Evaluate the expression as a singleton */ public Item evaluateItem(XPathContext context) throws XPathException { // minimize stack consumption by evaluating nested LET expressions iteratively LetExpression let = this; while (true) { Sequence<?> val = let.eval(context); context.setLocalVariable(let.getLocalSlotNumber(), val); if (let.getAction() instanceof LetExpression) { let = (LetExpression) let.getAction(); } else { break; } } return let.getAction().evaluateItem(context); }
public void setEvaluator() { if (needsEagerEvaluation) { setEvaluator(ExpressionTool.eagerEvaluator(getSequence())); } else if (isIndexedVariable()) { setEvaluator(Evaluator.MAKE_INDEXED_VARIABLE); } else if (evaluator == null) { setEvaluator(ExpressionTool.lazyEvaluator(getSequence(), getNominalReferenceCount() > 1)); } }
/** * The toString() method for an expression attempts to give a representation of the expression * in an XPath-like form, but there is no guarantee that the syntax will actually be true XPath. * In the case of XSLT instructions, the toString() method gives an abstracted view of the syntax * * @return a representation of the expression as a string */ public String toString() { return "let $" + getVariableEQName() + " := " + getSequence() + " return " + ExpressionTool.parenthesize(getAction()); }
@Override public void resetLocalStaticProperties() { super.resetLocalStaticProperties(); references = new ArrayList<>(); // bug 3233 if (evaluator == Evaluator.VARIABLE && !(getSequence() instanceof VariableReference)) { evaluator = null; setEvaluator(); } }
/** * Copy an expression. This makes a deep copy. * @return the copy of the original expression */ public Expression copy() { LetExpression let = new LetExpression(); let.setVariableQName(variableName); let.setRequiredType(requiredType); let.setSequence(sequence.copy()); Expression newAction = action.copy(); let.setAction(newAction); ExpressionTool.rebindVariableReferences(newAction, this, let); return let; }
if (getAction() instanceof VariableReference && ((VariableReference) getAction()).getBinding() == this && !ExpressionTool.changesXsltContext(getSequence())) { getSequenceOp().optimize(visitor, contextItemType); opt.trace("Eliminated trivial variable " + getVariableName(), getSequence()); return getSequence(); if (getSequence() instanceof Literal && opt.isOptionSet(OptimizerOptions.INLINE_VARIABLES)) { opt.trace("Inlined constant variable " + getVariableName(), getSequence()); replaceVariable(getSequence()); return getAction().optimize(visitor, contextItemType); if (getSequence() instanceof DocumentInstr && ((DocumentInstr) getSequence()).isTextOnly()) { verifyReferences(); if (allReferencesAreFlattened()) { Expression stringValueExpression = ((DocumentInstr) getSequence()).getStringValueExpression(); stringValueExpression = stringValueExpression.typeCheck(visitor, contextItemType); setSequence(stringValueExpression); requiredType = SequenceType.SINGLE_UNTYPED_ATOMIC; adoptChildExpression(getSequence()); refineTypeInformation(requiredType.getPrimaryType(), requiredType.getCardinality(), null, 0, this); if (getSequence().hasSpecialProperty(StaticProperty.HAS_SIDE_EFFECTS)) { needsEagerEvaluation = true; hasLoopingReference |= removeDeadReferences();
LetExpression let = new LetExpression(); let.setVariableQName(new StructuredQName("zz", NamespaceConstant.SAXON, "zz" + let.hashCode())); SequenceType type = SequenceType.makeSequenceType(child.getItemType(th), child.getCardinality()); let.setRequiredType(type); ExpressionTool.copyLocationInfo(containingExpression, let); let.setSequence(LazyExpression.makeLazyExpression(child)); let.setAction(containingExpression); let.adoptChildExpression(containingExpression); if (indexed) { let.setIndexedVariable();
LetExpression let = new LetExpression(); let.setVariableQName(variableName); let.setRequiredType(SequenceType.makeSequenceType( sequence.getItemType(visitor.getConfiguration().getTypeHierarchy()), StaticProperty.EXACTLY_ONE)); let.setSequence(sequence); let.setAction(action); let.setSlotNumber(slotNumber); ExpressionTool.rebindVariableReferences(action, this, let); return let.optimize(visitor, contextItemType);
LetExpression letExpr = new LetExpression(); letExpr.setLocation(letClause.getLocation()); letExpr.setRetainedStaticContext(getRetainedStaticContext()); letExpr.setAction(action); letExpr.setSequence(letClause.getSequence()); letExpr.setVariableQName(letClause.getRangeVariable().getVariableQName()); letExpr.setRequiredType(letClause.getRangeVariable().getRequiredType()); if (letClause.getRangeVariable().isIndexedVariable()) { letExpr.setIndexedVariable(); action = injector.inject(action, visitor.getStaticContext(), LocationKind.LET_EXPRESSION, letExpr.getVariableQName());
if (exp instanceof ContextItemExpression) { return null; } else if (exp instanceof LetExpression && ((LetExpression) exp).getSequence() instanceof ContextItemExpression) { Expression action = ((LetExpression) exp).getAction(); boolean changed = factorOutDot(action, (LetExpression) exp); if (changed) { } else if ((exp.getDependencies() & (StaticProperty.DEPENDS_ON_CONTEXT_ITEM | StaticProperty.DEPENDS_ON_CONTEXT_DOCUMENT)) != 0) { LetExpression let = new LetExpression(); let.setVariableQName( new StructuredQName("saxon", NamespaceConstant.SAXON, "dot" + exp.hashCode())); let.setRequiredType(SequenceType.makeSequenceType(contextItemType, StaticProperty.EXACTLY_ONE)); let.setSequence(new ContextItemExpression()); let.setAction(exp); boolean changed = factorOutDot(exp, let); if (changed) {
assert oldOperand != null; LetExpression let = new LetExpression(); let.setVariableQName(new StructuredQName("vv", NamespaceConstant.SAXON_GENERATED_VARIABLE, "v" + sequence++)); SequenceType type = SequenceType.makeSequenceType(child.getItemType(), child.getCardinality()); let.setRequiredType(type); ExpressionTool.copyLocationInfo(child, let); let.setSequence(child); let.setNeedsLazyEvaluation(true); let.setEvaluationMode(Cardinality.allowsMany(child.getCardinality()) ? ExpressionTool.MAKE_MEMO_CLOSURE : ExpressionTool.MAKE_SINGLETON_CLOSURE); let.setAction(newAction); let.adoptChildExpression(newAction); var.setStaticType(type, null, properties); var.setInLoop(true); let.addReference(var, true); ExpressionTool.copyLocationInfo(child, var); oldOperand.setChildExpression(var);
if (allReferencesAreFlattened()) { sequence = ((DocumentInstr) sequence).getStringValueExpression(env); adoptChildExpression(sequence); if (!isIndexedVariable()) { refCount = ExpressionTool.getReferenceCount(action, this, false); replaceVariable(opt, sequence); return visitor.optimize(action, contextItemType); adoptChildExpression(sequence); visitor.resetStaticProperties(); adoptChildExpression(action); visitor.resetStaticProperties(); Expression p = promoteWhereClause(null); if (p != null) { return p; evaluationMode = (isIndexedVariable() ? ExpressionTool.MAKE_CLOSURE : ExpressionTool.lazyEvaluationMode(sequence));
/** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void export(ExpressionPresenter out) throws XPathException { out.startElement("let", this); out.emitAttribute("var", variableName); out.emitAttribute("as", getSequence().getStaticType().toExportString()); if (isIndexedVariable()) { out.emitAttribute("indexable", "true"); } out.emitAttribute("slot", getLocalSlotNumber() + ""); if (evaluator == null) { setEvaluator(ExpressionTool.lazyEvaluator(getSequence(), getNominalReferenceCount() > 1)); } out.emitAttribute("eval", getEvaluator().getCode() + ""); getSequence().export(out); getAction().export(out); out.endElement(); }
/** * Iterate over the result of the expression to return a sequence of items */ public SequenceIterator iterate(XPathContext context) throws XPathException { // minimize stack consumption by evaluating nested LET expressions iteratively LetExpression let = this; while (true) { ValueRepresentation val = let.eval(context); context.setLocalVariable(let.getLocalSlotNumber(), val); if (let.action instanceof LetExpression) { let = (LetExpression) let.action; } else { break; } } return let.action.iterate(context); }
/** * Replace all references to the variable bound by this let expression, * that occur within the action expression, with the given expression * * @param opt The optimizer * @param seq the expression * @throws XPathException */ private void replaceVariable(Optimizer opt, Expression seq) throws XPathException { PromotionOffer offer2 = new PromotionOffer(opt); offer2.action = PromotionOffer.INLINE_VARIABLE_REFERENCES; offer2.bindingList = new Binding[] {this}; offer2.containingExpression = seq; action = doPromotion(action, offer2); if (offer2.accepted) { // there might be further references to the variable offer2.accepted = false; replaceVariable(opt, seq); } if (isIndexedVariable()) { Binding newBinding = ((VariableReference) seq).getBinding(); if (newBinding instanceof LetExpression) { ((LetExpression) newBinding).setIndexedVariable(); } } }
public AbstractExpression exprFor (LetExpression let) { StructuredQName var = let.getVariableQName(); Expression seq = let.getSequence(); Expression returns = let.getAction(); return new FLWOR(exprFor(returns), new LetClause (new Variable(qnameFor(var), getTypeDescription(let.getRequiredType())), exprFor(seq))); }
/** * Return the estimated cost of evaluating an expression. This is a very crude measure based * on the syntactic form of the expression (we have no knowledge of data values). We take * the cost of evaluating a simple scalar comparison or arithmetic expression as 1 (one), * and we assume that a sequence has length 5. The resulting estimates may be used, for * example, to reorder the predicates in a filter expression so cheaper predicates are * evaluated first. */ @Override public int getCost() { return getSequence().getCost() + getAction().getCost(); }
/** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { // The order of events is critical here. First we ensure that the type of the // sequence expression is established. This is used to establish the type of the variable, // which in turn is required when type-checking the action part. sequence = visitor.typeCheck(sequence, contextItemType); RoleLocator role = new RoleLocator(RoleLocator.VARIABLE, getVariableQName(), 0); //role.setSourceLocator(this); sequence = TypeChecker.strictTypeCheck( sequence, requiredType, role, visitor.getStaticContext()); final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); final ItemType actualItemType = sequence.getItemType(th); refineTypeInformation(actualItemType, sequence.getCardinality(), (sequence instanceof Literal ? ((Literal) sequence).getValue() : null), sequence.getSpecialProperties(), visitor, this); action = visitor.typeCheck(action, contextItemType); return this; }