package org.basex.query.expr;
import java.io.IOException;
import org.basex.io.serial.Serializer;
import org.basex.query.QueryContext;
import org.basex.query.QueryException;
import org.basex.query.item.Value;
import org.basex.query.iter.Iter;
import org.basex.query.util.Var;
import org.basex.util.InputInfo;
/**
* Project specific try/catch expression.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
*/
public final class Try extends Single {
/** Query exception. */
private QueryException qe;
/** Catches. */
private final Catch[] ctch;
/**
* Constructor.
* @param ii input info
* @param t try expression
* @param c catch expressions
*/
public Try(final InputInfo ii, final Expr t, final Catch[] c) {
super(ii, t);
ctch = c;
}
@Override
public Expr comp(final QueryContext ctx) throws QueryException {
// check if none or all try/catch expressions are updating
final Expr[] tmp = new Expr[ctch.length + 1];
tmp[0] = expr;
for(int c = 0; c < ctch.length; ++c) tmp[c + 1] = ctch[c].expr;
checkUp(ctx, tmp);
// compile expression
try {
super.comp(ctx);
// return value, which will never throw an error
if(expr.isValue()) return expr;
} catch(final QueryException ex) {
// catch exception for evaluation if expression fails at compile time
qe = ex;
}
// compile catch expressions
for(final Catch c : ctch) c.comp(ctx);
// evaluate result type
type = expr.type();
for(final Catch c : ctch) type = type.intersect(c.type());
return this;
}
@Override
public Iter iter(final QueryContext ctx) throws QueryException {
return value(ctx).iter();
}
@Override
public Value value(final QueryContext ctx) throws QueryException {
final int s = ctx.vars.size();
try {
// don't catch errors from error handlers
if(qe != null) return err(ctx, qe);
try {
return ctx.value(expr);
} catch(final QueryException ex) {
return err(ctx, ex);
}
} finally {
// always reset the scope
ctx.vars.size(s);
}
}
/**
* Handles an exception.
* @param ctx query context
* @param ex query exception
* @return result
* @throws QueryException query exception
*/
private Value err(final QueryContext ctx, final QueryException ex)
throws QueryException {
for(final Catch c : ctch) {
final Value val = c.value(ctx, ex);
if(val != null) return val;
}
throw ex;
}
@Override
public int count(final Var v) {
int c = super.count(v);
for(final Catch ct : ctch) c += ct.count(v);
return c;
}
@Override
public boolean uses(final Use u) {
for(final Catch c : ctch) if(c.uses(u)) return true;
return super.uses(u);
}
@Override
public boolean removable(final Var v) {
for(final Catch c : ctch) if(!c.removable(v)) return false;
return super.removable(v);
}
@Override
public Expr remove(final Var v) {
for(final Catch c : ctch) c.remove(v);
return super.remove(v);
}
@Override
public void plan(final Serializer ser) throws IOException {
ser.openElement(this);
expr.plan(ser);
for(final Catch c : ctch) c.plan(ser);
ser.closeElement();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("try { " + expr + " }");
for(final Catch c : ctch) sb.append(' ').append(c);
return sb.toString();
}
}