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.VarRef; import org.basex.query.item.Item; import org.basex.query.iter.Iter; import org.basex.query.util.Var; import org.basex.util.InputInfo; /** * FLWR clause. * * @author BaseX Team 2005-12, BSD License * @author Christian Gruen */ public final class FLWR extends GFLWOR { /** * Constructor. * @param f variable inputs * @param w where clause * @param r return expression * @param ii input info */ FLWR(final ForLet[] f, final Expr w, final Expr r, final InputInfo ii) { super(f, w, null, null, r, ii); } @Override public Expr comp(final QueryContext ctx) throws QueryException { final Expr ex = super.comp(ctx); if(ex != this) return ex; // simplify basic GFLWOR expression (for $i in A return $i -> A) if(fl.length == 1 && where == null && ret instanceof VarRef) { final Var v = ((VarRef) ret).var; if(v.type == null && fl[0].var.is(v)) { ctx.compInfo(OPTFLWOR); return fl[0].expr; } } return this; } @Override public Iter iter(final QueryContext ctx) { return new Iter() { private Iter[] iter; private Iter rtrn; private int p; @Override public Item next() throws QueryException { init(); while(true) { if(rtrn != null) { final Item i = rtrn.next(); if(i != null) return i; rtrn = null; } else { while(iter[p].next() != null) { if(p + 1 != fl.length) { ++p; } else if(where == null || where.ebv(ctx, input).bool(input)) { rtrn = ctx.iter(ret); break; } } if(rtrn == null && p-- == 0) return null; } } } @Override public boolean reset() { if(iter != null) { for(final Iter i : iter) i.reset(); iter = null; rtrn = null; p = 0; } return true; } /** * Initializes the iterator. * @throws QueryException query exception */ private void init() throws QueryException { if(iter != null) return; iter = new Iter[fl.length]; for(int f = 0; f < fl.length; ++f) iter[f] = ctx.iter(fl[f]); } }; } @Override public Expr markTailCalls() { for(final ForLet f : fl) if(f instanceof For) return this; ret = ret.markTailCalls(); return this; } }