package client.net.sf.saxon.ce.expr;
import client.net.sf.saxon.ce.event.SequenceReceiver;
import client.net.sf.saxon.ce.om.Item;
import client.net.sf.saxon.ce.om.NodeInfo;
import client.net.sf.saxon.ce.om.SequenceIterator;
import client.net.sf.saxon.ce.trans.XPathException;
import client.net.sf.saxon.ce.type.ItemType;
import client.net.sf.saxon.ce.type.TypeHierarchy;
import client.net.sf.saxon.ce.value.*;
import client.net.sf.saxon.ce.value.StringValue;
/**
* A Literal is an expression whose value is constant: it is a class that implements the {@link Expression}
* interface as a wrapper around a {@link Value}. This may derive from an actual literal in an XPath expression
* or query, or it may be the result of evaluating a constant subexpression such as true() or xs:date('2007-01-16')
*/
public class Literal extends Expression {
private Value value;
/**
* Create a literal as a wrapper around a Value
* @param value the value of this literal
*/
public Literal(Value value) {
this.value = value;
}
/**
* Create a literal as a wrapper around a Value (factory method)
* @param value the value of this literal
* @return the Literal
*/
public static Literal makeLiteral(Value value) {
if (value instanceof StringValue) {
return new StringLiteral((StringValue)value);
} else {
return new Literal(value);
}
}
/**
* Make an empty-sequence literal
* @return a literal whose value is the empty sequence
*/
public static Literal makeEmptySequence() {
return new Literal(EmptySequence.getInstance());
}
/**
* Get the value represented by this Literal
* @return the constant value
*/
public Value getValue() {
return value;
}
/**
* Simplify an expression
* @return for a Value, this always returns the value unchanged
* @param visitor an expression visitor
*/
public Expression simplify(ExpressionVisitor visitor) {
try {
value = value.reduce();
} catch (XPathException err) {
throw new AssertionError();
}
return this;
}
/**
* TypeCheck an expression
* @return for a Value, this always returns the value unchanged
*/
public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) {
return this;
}
/**
* Optimize an expression
* @return for a Value, this always returns the value unchanged
*/
public final Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) {
return this;
}
/**
* Determine the data type of the items in the expression, if possible
* @return for the default implementation: AnyItemType (not known)
* @param th The TypeHierarchy. Can be null if the target is an AtomicValue.
*/
public ItemType getItemType(TypeHierarchy th) {
return value.getItemType(th);
}
/**
* Determine the cardinality
*/
public int computeCardinality() {
if (value instanceof EmptySequence) {
return StaticProperty.EMPTY;
} else if (value instanceof AtomicValue) {
return StaticProperty.EXACTLY_ONE;
}
try {
SequenceIterator iter = value.iterate();
Item next = iter.next();
if (next == null) {
return StaticProperty.EMPTY;
} else {
if (iter.next() != null) {
return StaticProperty.ALLOWS_ONE_OR_MORE;
} else {
return StaticProperty.EXACTLY_ONE;
}
}
} catch (XPathException err) {
// can't actually happen
return StaticProperty.ALLOWS_ZERO_OR_MORE;
}
}
/**
* Compute the static properties of this expression (other than its type). For a
* Value, the only special property is {@link StaticProperty#NON_CREATIVE}.
* @return the value {@link StaticProperty#NON_CREATIVE}
*/
public int computeSpecialProperties() {
if (getValue() instanceof EmptySequence) {
// An empty sequence has all special properties except "has side effects".
return StaticProperty.SPECIAL_PROPERTY_MASK &~ StaticProperty.HAS_SIDE_EFFECTS;
}
return StaticProperty.NON_CREATIVE;
}
/**
* Copy an expression. This makes a deep copy.
*
* @return the copy of the original expression
*/
private Expression copy() {
return new Literal(value);
}
/**
* Determine which aspects of the context the expression depends on. The result is
* a bitwise-or'ed value composed from constants such as StaticProperty.VARIABLES and
* StaticProperty.CURRENT_NODE
* @return for a Value, this always returns zero.
*/
public final int getDependencies() {
return 0;
}
/**
* Return an Iterator to iterate over the values of a sequence. The value of every
* expression can be regarded as a sequence, so this method is supported for all
* expressions. This default implementation handles iteration for expressions that
* return singleton values: for non-singleton expressions, the subclass must
* provide its own implementation.
*
* @param context supplies the context for evaluation
* @return a SequenceIterator that can be used to iterate over the result
* of the expression
* @throws client.net.sf.saxon.ce.trans.XPathException
* if any dynamic error occurs evaluating the
* expression
*/
public SequenceIterator iterate(XPathContext context) throws XPathException {
return value.iterate();
}
/**
* Evaluate as a singleton item (or empty sequence). Note: this implementation returns
* the first item in the sequence. The method should not be used unless appropriate type-checking
* has been done to ensure that the value will be a singleton.
*/
public Item evaluateItem(XPathContext context) throws XPathException {
if (value instanceof AtomicValue) {
return (AtomicValue)value;
}
return value.iterate().next();
}
/**
* Process the value as an instruction, without returning any tail calls
* @param context The dynamic context, giving access to the current node,
* the current variables, etc.
*/
public void process(XPathContext context) throws XPathException {
SequenceIterator iter = value.iterate();
SequenceReceiver out = context.getReceiver();
while (true) {
Item it = iter.next();
if (it==null) break;
out.append(it, NodeInfo.ALL_NAMESPACES);
}
}
/*
* Evaluate an expression as a String. This function must only be called in contexts
* where it is known that the expression will return a single string (or where an empty sequence
* is to be treated as a zero-length string). Implementations should not attempt to convert
* the result to a string, other than converting () to "". This method is used mainly to
* evaluate expressions produced by compiling an attribute value template.
*
* @exception client.net.sf.saxon.ce.trans.XPathException if any dynamic error occurs evaluating the
* expression
* @exception ClassCastException if the result type of the
* expression is not xs:string?
* @param context The context in which the expression is to be evaluated
* @return the value of the expression, evaluated in the current context.
* The expression must return a string or (); if the value of the
* expression is (), this method returns "".
*/
public CharSequence evaluateAsString(XPathContext context) throws XPathException {
AtomicValue value = (AtomicValue) evaluateItem(context);
if (value == null) return "";
return value.getStringValueCS();
}
/**
* Determine whether two literals are equal, when considered as expressions.
* @param obj the other expression
* @return true if the two literals are equal. The test here requires (a) identity in the
* sense defined by XML Schema (same value in the same value space), and (b) identical type
* annotations. For example the literal xs:int(3) is not equal (as an expression) to xs:short(3),
* because the two expressions are not interchangeable.
*/
public boolean equals(Object obj) {
if (!(obj instanceof Literal)) {
return false;
}
Value v0 = value;
Value v1 = ((Literal)obj).value;
try {
SequenceIterator i0 = v0.iterate();
SequenceIterator i1 = v1.iterate();
while (true) {
Item m0 = i0.next();
Item m1 = i1.next();
if (m0==null && m1==null) {
return true;
}
if (m0==null || m1==null) {
return false;
}
boolean n0 = (m0 instanceof NodeInfo);
boolean n1 = (m1 instanceof NodeInfo);
if (n0 != n1) {
return false;
}
if (n0 && n1 && !((NodeInfo)m0).isSameNodeInfo((NodeInfo)m1)) {
return false;
}
// added test for atomicValue types - using getStringValue ensures that a collator
// will be used once collators are supported
// assertion: m0 != null && m1 != null
if(m0 instanceof StringValue && m1 instanceof StringValue){
if (!(((StringValue)m0).getStringValue().equals(((StringValue)m1).getStringValue()))) {
return false;
}
} else if(m0 instanceof AtomicValue && m1 instanceof AtomicValue){
if (!n0 && !n1 && (!((AtomicValue)m0).equals((AtomicValue)m1)) ||
((AtomicValue)m0).getTypeLabel() != ((AtomicValue)m1).getTypeLabel()) {
return false;
}
}
}
} catch (XPathException err) {
return false;
}
}
/**
* Return a hash code to support the equals() function
*/
public int hashCode() {
return value.hashCode(); //TODO:CLAXON maybe too crude?
}
/**
* 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
*/
public String toString() {
return value.toString();
}
/**
* Test whether the literal wraps an atomic value. (Note, if this method returns false,
* this still leaves the possibility that the literal wraps a sequence that happens to contain
* a single atomic value).
* @param exp an expression
* @return if the expression is a literal and the literal wraps an AtomicValue
*/
public static boolean isAtomic(Expression exp) {
return exp instanceof Literal && ((Literal)exp).getValue() instanceof AtomicValue;
}
/**
* Test whether the literal explicitly wraps an empty sequence. (Note, if this method returns false,
* this still leaves the possibility that the literal wraps a sequence that happens to be empty).
* @param exp an expression
* @return if the expression is a literal and the literal wraps an AtomicValue
*/
public static boolean isEmptySequence(Expression exp) {
return exp instanceof Literal && ((Literal)exp).getValue() instanceof EmptySequence;
}
/**
* Test if a literal represents the boolean value true
* @param exp an expression
* @param value true or false
* @return if the expression is a literal and the literal represents the boolean value given in the
* second argument
*/
public static boolean isConstantBoolean(Expression exp, boolean value) {
if (exp instanceof Literal) {
Value b = ((Literal)exp).getValue();
return (b instanceof BooleanValue && ((BooleanValue)b).getBooleanValue() == value);
}
return false;
}
/**
* Test if a literal represents the integer value 1
* @param exp an expression
* @return if the expression is a literal and the literal represents the integer value 1
*/
public static boolean isConstantOne(Expression exp) {
try {
if (exp instanceof Literal) {
Value v = ((Literal)exp).getValue();
return (v instanceof IntegerValue && ((IntegerValue)v).intValue() == 1);
}
return false;
} catch (XPathException e) {
// overflow
return false;
}
}
/**
* Determine whether the expression can be evaluated without reference to the part of the context
* document outside the subtree rooted at the context node.
* @return true if the expression has no dependencies on the context node, or if the only dependencies
* on the context node are downward selections using the self, child, descendant, attribute, and namespace
* axes.
*/
public boolean isSubtreeExpression() {
return true;
}
}
// 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.