package org.basex.query.expr;
import static org.basex.query.QueryText.*;
import static org.basex.util.Token.*;
import java.io.IOException;
import org.basex.io.serial.Serializer;
import org.basex.query.QueryContext;
import org.basex.query.QueryException;
import org.basex.query.func.UserFuncCall;
import org.basex.query.item.Item;
import org.basex.query.item.Value;
import org.basex.query.iter.Iter;
import org.basex.query.util.Var;
import org.basex.util.InputInfo;
import org.basex.util.TokenBuilder;
/**
* Variable Reference expression.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
*/
public final class VarRef extends ParseExpr {
/** Variable name. */
public Var var;
/**
* Constructor.
* @param ii input info
* @param v variable
*/
public VarRef(final InputInfo ii, final Var v) {
super(ii);
var = v;
}
@Override
public Expr comp(final QueryContext ctx) throws QueryException {
var = ctx.vars.get(var);
type = var.type();
size = var.size();
// return if variable expression has not yet been assigned
Expr e = var.expr();
if(e == null) return this;
/* Choose expressions to be pre-evaluated.
* If a variable is pre-evaluated, it may not be available for further
* optimizations (index access, count, ...). On the other hand, repeated
* evaluation of the same expression is avoided.
*
* [CG][LW] Variables are currently pre-evaluated if...
* - they are global (mandatory)
* - namespaces are used
* - they are given a type
* - they contain an element constructor (mandatory)
* - they contain a function call
*/
if(var.global || var.type != null || e.uses(Use.CNS) ||
e instanceof UserFuncCall) {
e = var.value(ctx);
}
return e;
}
@Override
public Item item(final QueryContext ctx, final InputInfo ii)
throws QueryException {
var = ctx.vars.get(var);
return var.item(ctx, ii);
}
@Override
public Iter iter(final QueryContext ctx) throws QueryException {
var = ctx.vars.get(var);
return ctx.iter(var);
}
@Override
public Value value(final QueryContext ctx) throws QueryException {
var = ctx.vars.get(var);
return ctx.value(var);
}
@Override
public boolean uses(final Use u) {
return u == Use.VAR || u != Use.CTX && u != Use.NDT &&
var.expr() != null && var.expr().uses(u);
}
@Override
public int count(final Var v) {
return var.is(v) ? 1 : 0;
}
@Override
public boolean removable(final Var v) {
return true;
}
@Override
public Expr remove(final Var v) {
return var.is(v) ? new Context(input) : this;
}
@Override
public boolean sameAs(final Expr cmp) {
return cmp instanceof VarRef && var.sameAs(((VarRef) cmp).var);
}
@Override
public void plan(final Serializer ser) throws IOException {
ser.emptyElement(this, NAM, token(var.toString()));
}
@Override
public String description() {
return VARBL;
}
@Override
public String toString() {
return new TokenBuilder(DOLLAR).add(var.name.string()).toString();
}
}