All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.saxon.expr.RangeExpression Maven / Gradle / Ivy

There is a newer version: 10.5
Show newest version
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2013 Saxonica Limited.
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package net.sf.saxon.expr;



import net.sf.saxon.expr.parser.ExpressionTool;
import net.sf.saxon.expr.parser.ExpressionVisitor;
import net.sf.saxon.expr.parser.RoleLocator;
import net.sf.saxon.expr.parser.TypeChecker;
import net.sf.saxon.om.GroundedValue;
import net.sf.saxon.om.SequenceIterator;
import net.sf.saxon.trans.SaxonErrorCode;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.BuiltInAtomicType;
import net.sf.saxon.type.ItemType;
import net.sf.saxon.type.TypeHierarchy;
import net.sf.saxon.value.Int64Value;
import net.sf.saxon.value.IntegerRange;
import net.sf.saxon.value.IntegerValue;
import net.sf.saxon.value.SequenceType;



/**
* A RangeExpression is an expression that represents an integer sequence as
* a pair of end-points (for example "x to y").
* If the end-points are equal, the sequence is of length one.
 * 

From Saxon 7.8, the sequence must be ascending; if the end-point is less * than the start-point, an empty sequence is returned. This is to allow * expressions of the form "for $i in 1 to count($seq) return ...."

*/ public class RangeExpression extends BinaryExpression { /** * Construct a RangeExpression * @param start expression that computes the start of the range * @param op represents the operator "to", needed only because this class is a subclass of * BinaryExpression which needs an operator * @param end expression that computes the end of the range */ public RangeExpression(Expression start, int op, Expression end) { super(start, op, end); } /** * Type-check the expression */ /*@NotNull*/ public Expression typeCheck(ExpressionVisitor visitor, ExpressionVisitor.ContextItemType contextItemType) throws XPathException { operand0 = visitor.typeCheck(operand0, contextItemType); operand1 = visitor.typeCheck(operand1, contextItemType); boolean backCompat = visitor.getStaticContext().isInBackwardsCompatibleMode(); RoleLocator role0 = new RoleLocator(RoleLocator.BINARY_EXPR, "to", 0); //role0.setSourceLocator(this); operand0 = TypeChecker.staticTypeCheck( operand0, SequenceType.OPTIONAL_INTEGER, backCompat, role0, visitor); RoleLocator role1 = new RoleLocator(RoleLocator.BINARY_EXPR, "to", 1); //role1.setSourceLocator(this); operand1 = TypeChecker.staticTypeCheck( operand1, SequenceType.OPTIONAL_INTEGER, backCompat, role1, visitor); return makeConstantRange(); } /** * Perform optimisation of an expression and its subexpressions. *

*

This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

* * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ /*@NotNull*/ public Expression optimize(ExpressionVisitor visitor, ExpressionVisitor.ContextItemType contextItemType) throws XPathException { operand0 = visitor.optimize(operand0, contextItemType); operand1 = visitor.optimize(operand1, contextItemType); return makeConstantRange(); } private Expression makeConstantRange() throws XPathException { if (operand0 instanceof Literal && operand1 instanceof Literal) { GroundedValue v0 = ((Literal)operand0).getValue(); GroundedValue v1 = ((Literal)operand1).getValue(); if (v0 instanceof Int64Value && v1 instanceof Int64Value) { long i0 = ((Int64Value)v0).longValue(); long i1 = ((Int64Value)v1).longValue(); Literal result; if (i0 > i1) { result = Literal.makeEmptySequence(); } else if (i0 == i1) { result = Literal.makeLiteral(Int64Value.makeIntegerValue(i0)); } else { if (i1 - i0 > Integer.MAX_VALUE) { throw new XPathException("Maximum length of sequence in Saxon is " + Integer.MAX_VALUE, SaxonErrorCode.SXXP0006); } result = Literal.makeLiteral(new IntegerRange(i0, i1)); } ExpressionTool.copyLocationInfo(this, result); return result; } } return this; } /** * Get the data type of the items returned * @param th the type hierarchy cache */ /*@NotNull*/ public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.INTEGER; } /** * Determine the static cardinality */ public int computeCardinality() { return StaticProperty.ALLOWS_ZERO_OR_MORE; } /** * For an expression that returns an integer or a sequence of integers, get * a lower and upper bound on the values of the integers that may be returned, from * static analysis. The default implementation returns null, meaning "unknown" or * "not applicable". Other implementations return an array of two IntegerValue objects, * representing the lower and upper bounds respectively. The values * UNBOUNDED_LOWER and UNBOUNDED_UPPER are used by convention to indicate that * the value may be arbitrarily large. The values MAX_STRING_LENGTH and MAX_SEQUENCE_LENGTH * are used to indicate values limited by the size of a string or the size of a sequence. * * @return the lower and upper bounds of integer values in the result, or null to indicate * unknown or not applicable. */ /*@Nullable*/@Override public IntegerValue[] getIntegerBounds() { IntegerValue[] start = operand0.getIntegerBounds(); IntegerValue[] end = operand0.getIntegerBounds(); if (start == null || end == null) { return null; } else { // range is from the smallest possible start value to the largest possible end value return new IntegerValue[]{start[0], end[1]}; } } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ /*@NotNull*/ public Expression copy() { return new RangeExpression(operand0.copy(), operator, operand1.copy()); } /** * Return an iteration over the sequence */ /*@NotNull*/ public SequenceIterator iterate(XPathContext context) throws XPathException { IntegerValue av1 = (IntegerValue)operand0.evaluateItem(context); IntegerValue av2 = (IntegerValue)operand1.evaluateItem(context); return RangeIterator.makeRangeIterator(av1, av2); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy