package jeql.engine.function;
import java.util.List;
import jeql.engine.Scope;
import jeql.engine.query.QueryScope;
import jeql.syntax.ParseTreeNode;
/**
* Implements the KEEP pseudo-function semantics.
* Keep returns the value of an expression evaluated
* on the most recent previous row for which the value
* of a condition expression is true.
*
* Syntax:
* <pre>
* KEEP(valueExpr, condExpr [, initValueExpr] )
* </pre>
* A KEEP function must always have a value expression and a
* condition expression.
* An optional expression for the initial value of the function may be supplied.
*
* @author Martin Davis
*
*/
public class KeepFunctionEvaluator
implements FunctionEvaluator
{
private ParseTreeNode valueExpr;
private ParseTreeNode condExpr = null;
private ParseTreeNode initExpr = null;
// builtins
public static final String FN_KEEP = "keep";
public KeepFunctionEvaluator()
{
}
public void bind(Scope scope, List args)
{
valueExpr = (ParseTreeNode) args.get(0);
if (args.size() >= 2)
condExpr = (ParseTreeNode) args.get(1);
if (args.size() >= 3)
initExpr = (ParseTreeNode) args.get(2);
}
public Object eval(Scope scope)
{
// if this fails, KEEP is being called outside of a SELECT => error
QueryScope qScope = (QueryScope) scope;
// set initial value if present
if (! qScope.hasValue(this) && initExpr != null) {
Object initValue = initExpr.eval(scope);
qScope.setValue(this, initValue);
}
// compute new possible result, and save if condition is true
Object result = null;
if (isCondTrue(scope)) {
result = valueExpr.eval(scope);
qScope.setValue(this, result);
}
else {
result = qScope.getValue(this);
}
return result;
}
private boolean isCondTrue(Scope scope)
{
if (condExpr == null) return true;
Boolean condVal = (Boolean) condExpr.eval(scope);
return condVal.booleanValue();
}
public Class getType(Scope scope)
{
return valueExpr.getType(scope);
}
}