package org.basex.query.func;
import org.basex.query.QueryContext;
import org.basex.query.QueryException;
import org.basex.query.expr.Expr;
import org.basex.query.item.Item;
import org.basex.query.item.QNm;
import org.basex.query.item.Value;
import org.basex.query.iter.Iter;
import org.basex.query.util.VarStack;
import org.basex.util.InputInfo;
/**
* A tail-recursive function call.
*
* @author BaseX Team 2005-12, BSD License
* @author Leo Woerteler
*/
final class TailFuncCall extends UserFuncCall {
/**
* Constructor.
* @param ii input info
* @param nm name of the function to call
* @param f function
* @param arg arguments
*/
TailFuncCall(final InputInfo ii, final QNm nm, final UserFunc f,
final Expr[] arg) {
super(ii, nm, arg);
func = f;
}
@Override
public Item item(final QueryContext ctx, final InputInfo ii)
throws QueryException {
checkHeight(ctx);
// cache arguments, evaluate function and reset variable scope
final VarStack cs = addArgs(ctx, args(ctx));
final Item it = func.item(ctx, ii);
ctx.vars.reset(cs);
return it;
}
@Override
public Value value(final QueryContext ctx) throws QueryException {
checkHeight(ctx);
// cache arguments, evaluate function and reset variable scope
final VarStack cs = addArgs(ctx, args(ctx));
final Value v = ctx.value(func);
ctx.vars.reset(cs);
return v;
}
@Override
public Iter iter(final QueryContext ctx) throws QueryException {
checkHeight(ctx);
// [LW] make result streamable
return value(ctx).iter();
}
/**
* Checks is the maximum number of successive tail calls is reached, and
* triggers a continuation exception if this happens.
* @param ctx query context
* @throws QueryException query exception
*/
private void checkHeight(final QueryContext ctx) throws QueryException {
final int max = ctx.maxCalls;
if(max >= 0 && ctx.tailCalls++ > max) throw new Continuation(args(ctx));
}
}