net.sf.saxon.expr.TryCatch Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Saxon-HE Show documentation
Show all versions of Saxon-HE Show documentation
The XSLT and XQuery Processor
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2015 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.*;
import net.sf.saxon.lib.NamespaceConstant;
import net.sf.saxon.om.Item;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.om.SequenceIterator;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.pattern.QNameTest;
import net.sf.saxon.trace.ExpressionPresenter;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.ItemType;
import net.sf.saxon.type.Type;
import net.sf.saxon.value.Cardinality;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* This class implements a try/catch expression. It consists of a try expression, and a sequence of Nametest/Catch
* expression pairs. If the try expression succeeds, its result is returned; otherwise the error code of the
* exception is matched against each of the Nametests in turn, and the first matching catch expression is
* evaluated.
*/
public class TryCatch extends Expression {
private Operand tryOp;
private List catchClauses = new ArrayList();
public TryCatch(Expression tryExpr) {
this.tryOp = new Operand(this, tryExpr, OperandRole.SAME_FOCUS_ACTION);
}
public void addCatchExpression(QNameTest test, Expression catchExpr) {
CatchClause clause = new CatchClause();
clause.catchOp = new Operand(this, catchExpr, OperandRole.SAME_FOCUS_ACTION);
clause.nameTest = test;
catchClauses.add(clause);
}
/**
* Get the "try" expression
*
* @return the primary expression to be evaluated
*/
public Expression getTryExpr() {
return tryOp.getChildExpression();
}
/**
* Get the list of catch clauses
*
* @return the list of catch clauses
*/
public List getCatchClauses() {
return catchClauses;
}
/**
* Determine the cardinality of the function.
*/
public int computeCardinality() {
int card = getTryExpr().getCardinality();
for (CatchClause catchClause : catchClauses) {
card = Cardinality.union(card, catchClause.catchOp.getChildExpression().getCardinality());
}
return card;
}
/**
* Determine the item type of the value returned by the function
*/
/*@NotNull*/
public ItemType getItemType() {
ItemType type = getTryExpr().getItemType();
for (CatchClause catchClause : catchClauses) {
type = Type.getCommonSuperType(type, catchClause.catchOp.getChildExpression().getItemType());
}
return type;
}
/**
* Get the immediate sub-expressions of this expression, with information about the relationship
* of each expression to its parent expression. Default implementation
* returns a zero-length array, appropriate for an expression that has no
* sub-expressions.
*
* @return an iterator containing the sub-expressions of this expression
*/
@Override
public Iterable operands() {
List list = new ArrayList();
list.add(tryOp);
for (CatchClause cc : catchClauses) {
list.add(cc.catchOp);
}
return list;
}
/**
* Offer promotion for this subexpression. The offer will be accepted if the subexpression
* is not dependent on the factors (e.g. the context item) identified in the PromotionOffer.
* By default the offer is not accepted - this is appropriate in the case of simple expressions
* such as constant values and variable references where promotion would give no performance
* advantage. This method is always called at compile time.
*
* This method must be overridden for any Expression that has subexpressions.
*
*
* @param offer details of the offer, for example the offer to move
* expressions that don't depend on the context to an outer level in
* the containing expression
* @return if the offer is not accepted, return this expression unchanged.
* Otherwise return the result of rewriting the expression to promote
* this subexpression
* @throws net.sf.saxon.trans.XPathException
* if any error is detected
*/
public Expression promote(PromotionOffer offer) throws XPathException {
if (offer.action != PromotionOffer.EXTRACT_GLOBAL_VARIABLES &&
offer.action != PromotionOffer.FOCUS_INDEPENDENT) {
Expression exp = offer.accept(this);
if (exp != null) {
return exp;
} else {
//tryOp.setChildExpression(doPromotion(tryOp.getChildExpression(), offer));
for (CatchClause clause : catchClauses) {
clause.catchOp.setChildExpression(doPromotion(clause.catchOp.getChildExpression(), offer));
}
return this;
}
} else {
return this;
}
}
@Override
public Expression optimize(ExpressionVisitor visitor, ContextItemStaticInfo contextInfo) throws XPathException {
optimizeChildren(visitor, contextInfo);
Expression e = getParentExpression();
while (e != null) {
if (e instanceof LetExpression && ExpressionTool.dependsOnVariable(getTryExpr(), new Binding[]{(LetExpression)e})) {
((LetExpression)e).setNeedsEagerEvaluation(true);
}
e = e.getParentExpression();
}
return this;
}
/**
* An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process().
* This method indicates which of these methods is provided directly. The other methods will always be available
* indirectly, using an implementation that relies on one of the other methods.
*
* @return the implementation method, for example {@link #ITERATE_METHOD} or {@link #EVALUATE_METHOD} or
* {@link #PROCESS_METHOD}
*/
@Override
public int getImplementationMethod() {
return ITERATE_METHOD;
}
/**
* Is this expression the same as another expression?
*
* @param other the expression to be compared with this one
* @return true if the two expressions are statically equivalent
*/
@Override
public boolean equals(Object other) {
return other instanceof TryCatch && ((TryCatch)other).tryOp.getChildExpression().equals(tryOp.getChildExpression())
&& ((TryCatch)other).catchClauses.equals(catchClauses);
}
/**
* Hashcode supporting equals()
*/
public int hashCode() {
int h = 0x836b12a0;
for (int i = 0; i < catchClauses.size(); i++) {
h ^= catchClauses.get(i).hashCode()<
© 2015 - 2025 Weber Informatics LLC | Privacy Policy