package org.basex.query.expr;
import static org.basex.query.QueryText.*;
import java.io.IOException;
import org.basex.io.serial.Serializer;
import org.basex.query.QueryContext;
import org.basex.query.QueryException;
import org.basex.query.flwor.For;
import org.basex.query.flwor.ForLet;
import org.basex.query.item.Bln;
import org.basex.query.item.SeqType;
import org.basex.query.iter.Iter;
import org.basex.query.util.Var;
import org.basex.util.InputInfo;
import org.basex.util.Token;
/**
* Some/Every satisfier clause.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
*/
public final class Quantifier extends ParseExpr {
/** Every flag. */
private final boolean every;
/** For/Let expressions. */
private final For[] fl;
/** Satisfier. */
private Expr sat;
/**
* Constructor.
* @param ii input info
* @param f variable inputs
* @param s satisfier
* @param e every flag
*/
public Quantifier(final InputInfo ii, final For[] f, final Expr s,
final boolean e) {
super(ii);
sat = s;
fl = f;
every = e;
type = SeqType.BLN;
}
@Override
public Expr comp(final QueryContext ctx) throws QueryException {
// compile for clauses
final int vs = ctx.vars.size();
for(final For f : fl) f.comp(ctx);
sat = checkUp(sat, ctx).comp(ctx).compEbv(ctx);
ctx.vars.size(vs);
// find empty sequences
boolean empty = sat.isEmpty();
for(final For f : fl) empty |= f.isEmpty();
// return pre-evaluated result
return empty ? optPre(Bln.get(every), ctx) : this;
}
@Override
public Bln item(final QueryContext ctx, final InputInfo ii)
throws QueryException {
final Iter[] iter = new Iter[fl.length];
for(int f = 0; f < fl.length; ++f) iter[f] = ctx.iter(fl[f]);
return Bln.get(iter(ctx, iter, 0));
}
/**
* Performs a recursive iteration on the specified variable position.
* @param ctx query context
* @param it iterator
* @param p variable position
* @return satisfied flag
* @throws QueryException query exception
*/
private boolean iter(final QueryContext ctx, final Iter[] it,
final int p) throws QueryException {
final boolean last = p + 1 == fl.length;
while(it[p].next() != null) {
if(every ^ (last ? sat.ebv(ctx, input).bool(input) :
iter(ctx, it, p + 1))) {
for(final Iter ri : it) ri.reset();
return !every;
}
}
return every;
}
@Override
public boolean uses(final Use u) {
return u == Use.VAR || sat.uses(u);
}
@Override
public int count(final Var v) {
int c = 0;
for(final ForLet f : fl) c += f.count(v);
return c + sat.count(v);
}
@Override
public boolean removable(final Var v) {
for(final ForLet f : fl) if(!f.removable(v)) return false;
return sat.removable(v);
}
@Override
public Expr remove(final Var v) {
for(final ForLet f : fl) f.remove(v);
sat = sat.remove(v);
return this;
}
@Override
public void plan(final Serializer ser) throws IOException {
ser.openElement(this, TYP, Token.token(every ? EVERY : SOME));
for(final Expr f : fl) f.plan(ser);
sat.plan(ser);
ser.closeElement();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder(every ? EVERY : SOME);
for(final For f : fl) sb.append(' ').append(f);
return sb.append(' ' + SATISFIES + ' ' + sat).toString();
}
}