package org.basex.query.expr; import org.basex.data.ExprInfo; import org.basex.query.QueryContext; import org.basex.query.QueryException; import org.basex.query.flwor.GFLWOR; import org.basex.query.flwor.Group; import org.basex.query.func.Function; import org.basex.query.item.Empty; import org.basex.query.item.Item; import org.basex.query.item.SeqType; import org.basex.query.item.Value; import org.basex.query.iter.Iter; import org.basex.query.path.AxisPath; import org.basex.query.path.MixedPath; import org.basex.query.util.IndexContext; import org.basex.query.util.Var; import org.basex.query.util.VarStack; import org.basex.util.InputInfo; /** * Abstract class for representing XQuery expressions. * Expression are divided into {@link ParseExpr} and {@link Value} classes. * * @author BaseX Team 2005-12, BSD License * @author Christian Gruen */ public abstract class Expr extends ExprInfo { /** Flags that influence query compilation. */ public enum Use { /** Creates new fragments. Example: node constructor. */ CNS, /** Depends on context. Example: context node. */ CTX, /** Non-deterministic. Example: random(). */ NDT, /** Context position. Examples: position(). */ POS, /** Performs updates. Example: insert expression. */ UPD, /** References a variable. Example: {@link VarRef}. */ VAR, /** Based on XQuery 3.0. Example: group by statement. */ X30, } /** * Compiles and optimizes the expression, assigns data types and * cardinalities. * @param ctx query context * @return optimized expression * @throws QueryException query exception */ public abstract Expr comp(final QueryContext ctx) throws QueryException; /** * Evaluates the expression and returns an iterator on the resulting items. * If this method is not overwritten, {@link #item} must be implemented * by an expression, as it may be called by this method. * @param ctx query context * @return resulting item * @throws QueryException query exception */ public abstract Iter iter(final QueryContext ctx) throws QueryException; /** * Evaluates the expression and returns the resulting item or * a {@code null} reference, if the expression yields an empty sequence. * If this method is not overwritten, {@link #iter} must be implemented * by an expression, as it may be called by this method. * @param ctx query context * @param ii input info * @return iterator * @throws QueryException query exception */ public abstract Item item(final QueryContext ctx, final InputInfo ii) throws QueryException; /** * Evaluates the expression and returns the resulting value. * @param ctx query context * @return iterator * @throws QueryException query exception */ public abstract Value value(final QueryContext ctx) throws QueryException; /** * Checks if the iterator can be dissolved into an effective boolean value. * If not, returns an error. If yes, returns the first value - which can be * also be e.g. an integer, which is later evaluated as numeric predicate. * @param ctx query context * @param ii input info * @return item * @throws QueryException query exception */ public abstract Item ebv(final QueryContext ctx, final InputInfo ii) throws QueryException; /** * Performs a predicate test and returns the item if test was successful. * @param ctx query context * @param ii input info * @return item * @throws QueryException query exception */ public abstract Item test(final QueryContext ctx, final InputInfo ii) throws QueryException; /** * Tests if this is an empty sequence. This function is only overwritten * by the {@link Empty} class, which represents the empty sequence. * @return result of check */ public boolean isEmpty() { return false; } /** * Tests if this is a vacuous expression (empty sequence or error function). * This check is needed for updating queries. * @return result of check */ public boolean isVacuous() { return false; } /** * Tests if this is a value. * @return result of check */ public boolean isValue() { return false; } /** * Tests if this is an item. * @return result of check */ public boolean isItem() { return false; } /** * Returns the sequence size or 1. * @return result of check */ public abstract long size(); /** * Indicates if an expression uses the specified type/operation. * This method is called by numerous {@link #comp} methods to test * the properties of sub-expressions. * @param u use type to be checked * @return result of check */ public abstract boolean uses(final Use u); /** * Counts how often the specified variable is used by an expression. * This method is called by: * <ul> * <li> {@link GFLWOR#comp} to rewrite where clauses as predicates and * remove statically bound or unused clauses</li> * <li> {@link GFLWOR#compHoist} to hoist independent variables</li> * </ul> * @param v variable to be checked * @return number of occurrences */ public abstract int count(final Var v); /** * Checks if the specified variable is replaceable by a context item. * The following tests might return false: * <ul> * <li>{@link Preds#removable}, if one of the variables is used within * a predicate.</li> * <li>{@link MixedPath#removable}, if the variable occurs within * the path.</li> * <li>{@link Group#removable}, as the group by expression depends on * variable references.</li> * </ul> * This method is called by {@link GFLWOR#comp} to rewrite where clauses * into predicates. * @param v variable to be replaced * @return result of check */ public abstract boolean removable(final Var v); /** * Substitutes all {@link VarRef} expressions for the given variable * by a {@link Context} reference. This method is called by * {@link GFLWOR#comp} to rewrite where clauses as predicates. * @param v variable to be replaced * @return new expression */ public abstract Expr remove(final Var v); /** * <p>This method is called at compile time by expressions that perform * effective boolean value tests (e.g. {@link If} or {@link Preds}). * If the arguments of the called expression return a boolean anyway, * the expression will be simplified.</p> * <p>Example in {@link CmpV}: * {@code if($x eq true())} is rewritten to {@code if($x)}, if {@code $x} * will always yield a single boolean.</p> * * @param ctx query context * @return optimized expression */ @SuppressWarnings("unused") public Expr compEbv(final QueryContext ctx) { return this; } /** * Returns the sequence type of the evaluated value. For simplicity, * some types have been summarized. E.g., all numbers are treated as integers. * @return result of check */ public abstract SeqType type(); /** * Returns true if the expression is iterable, i.e., if it does not contain * any duplicates and if all results are sorted. * This method is called e.g. by {@link AxisPath}. * @return result of check */ public boolean iterable() { return type().zeroOrOne(); } /** * Checks if an expression can be rewritten to an index access. * If this method is implemented, {@link #indexEquivalent} must be * implemented as well. * @param ic index context * @return true if an index can be used * @throws QueryException query exception */ @SuppressWarnings("unused") public boolean indexAccessible(final IndexContext ic) throws QueryException { return false; } /** * Returns an equivalent expression which accesses an index structure. * Will be called if {@link #indexAccessible} is returns true for an * expression. * @param ic index context * @return equivalent index-expression * @throws QueryException query exception */ @SuppressWarnings("unused") public Expr indexEquivalent(final IndexContext ic) throws QueryException { return null; } /** * Compares the current and specified expression for equality. * @param cmp expression to be compared * @return result of check */ public boolean sameAs(final Expr cmp) { return this == cmp; } /** * Checks if this expression is a certain function. * @param f function definition * @return function, or {@code null} */ @SuppressWarnings("unused") public boolean isFunction(final Function f) { return false; } /** * Optionally adds a text node to an expression for potential index rewriting. * @param ctx query context * @return expression */ @SuppressWarnings("unused") public Expr addText(final QueryContext ctx) { return this; } /** * Checks if this expression has free variables. * @param ctx query context on the level of this expression * @return {@code true} if there are variables which are used but not declared * in this expression, {@code false} otherwise */ public boolean hasFreeVars(final QueryContext ctx) { final VarStack global = ctx.vars.globals(); for(int i = global.size; --i >= 0;) { if(count(global.vars[i]) > 0) return true; } final VarStack vars = ctx.vars.locals(); for(int i = vars.size; --i >= 0;) { if(count(vars.vars[i]) > 0) return true; } return false; } /** * Finds and marks tail calls, enabling TCO. * @return the expression, with tail calls marked */ public Expr markTailCalls() { return this; } }