package org.basex.query.flwor; import static org.basex.query.QueryText.*; import org.basex.query.QueryContext; import org.basex.query.QueryException; import org.basex.query.expr.Expr; import org.basex.query.expr.Single; import org.basex.query.util.Var; import org.basex.util.InputInfo; /** * Abstract For/Let Clause. * * @author BaseX Team 2005-12, BSD License * @author Christian Gruen */ public abstract class ForLet extends Single { /** Variable. */ public final Var var; /** * Constructor. * @param ii input info * @param e variable input * @param v variable */ ForLet(final InputInfo ii, final Expr e, final Var v) { super(ii, e); var = v; } /** * If possible, binds the variable at compile time. * @param ctx query context * @throws QueryException query exception */ final void bind(final QueryContext ctx) throws QueryException { if(!simple(true)) return; /* don't bind variable if expression... - has free variables, eg: for $a in 1 to 2 let $b := $a return $b - is non-deterministic, eg: let $x := random() return ($x, $x) - creates fragments, eg: let $x := <x/> return $x is $x - depends on context, eg: (<a/>,<b/>)/(let $a := position() return $a=last()) */ if(expr.hasFreeVars(ctx) || expr.uses(Use.NDT) || expr.uses(Use.CTX) || expr.uses(Use.CNS) || ctx.grouping) return; ctx.compInfo(OPTBIND, var); var.bind(expr, ctx); } @Override public abstract ForLet comp(final QueryContext ctx) throws QueryException; /** * Checks if the clause contains a simple variable declaration, using * no scoring and no positioning. * @param one clause must not return more than one value * @return result of check */ abstract boolean simple(final boolean one); /** * Returns the total number of occurrences of all variables that are * defined in the specified clause. * @param fl clause to be checked * @return total number of occurrences */ final int count(final ForLet fl) { int c = expr.count(fl.var); if(fl instanceof For) { final For f = (For) fl; if(f.pos != null) c += expr.count(f.pos); if(f.score != null) c += expr.count(f.score); } return c; } @Override public final boolean uses(final Use u) { return u == Use.VAR || super.uses(u); } /** * Checks if the given variable is declared by this clause. * @param v variable * @return declaration flag */ public abstract boolean declares(final Var v); /** * Gathers all variables declared by this clause. * @return variables */ public abstract Var[] vars(); }