DataFilter User Symbols and '<-' assign

.. allow users to introduce their own symbols
   into a datafilter with:

   symbol <- expression

   Which will initialise symbol and evaluate it
   with the expression. The symbol can override
   a metric name, but that would be rather dumb!
This commit is contained in:
Mark Liversedge
2015-12-04 18:15:21 +00:00
parent 94b5af33ba
commit 10e1c12dbd
4 changed files with 88 additions and 23 deletions

View File

@@ -799,6 +799,7 @@ bool Leaf::isNumber(DataFilter *df, Leaf *leaf)
case Leaf::Symbol :
{
QString symbol = *(leaf->lvalue.n);
if (df->symbols.contains(symbol)) return true;
if (symbol == "isRun") return true;
if (symbol == "x") return true;
else if (symbol == "isSwim") return true;
@@ -875,8 +876,12 @@ void Leaf::validateFilter(DataFilter *df, Leaf *leaf)
symbol.compare("Current", Qt::CaseInsensitive) &&
!df->dataSeriesSymbols.contains(symbol) &&
symbol != "isSwim" && symbol != "isRun" && !isCoggan(symbol)) {
DataFiltererrors << QString(tr("%1 is unknown")).arg(symbol);
leaf->inerror = true;
// unknown, is it user defined ?
if (!df->symbols.contains(symbol)) {
DataFiltererrors << QString(tr("%1 is unknown")).arg(symbol);
leaf->inerror = true;
}
}
if (symbol.compare("Current", Qt::CaseInsensitive))
@@ -1094,23 +1099,51 @@ void Leaf::validateFilter(DataFilter *df, Leaf *leaf)
case Leaf::BinaryOperation :
case Leaf::Operation :
{
// first lets make sure the lhs and rhs are of the same type
bool lhsType = Leaf::isNumber(df, leaf->lvalue.l);
bool rhsType = Leaf::isNumber(df, leaf->rvalue.l);
if (lhsType != rhsType) {
DataFiltererrors << QString(tr("comparing strings with numbers"));
leaf->inerror = true;
}
if (leaf->op == ASSIGN) {
// what about using string operations on a lhs/rhs that
// are numeric?
if ((lhsType || rhsType) && leaf->op >= MATCHES && leaf->op <= CONTAINS) {
DataFiltererrors << tr("using a string operations with a number");
leaf->inerror = true;
}
// add the symbol first
if (leaf->lvalue.l->type == Leaf::Symbol) {
validateFilter(df, leaf->lvalue.l);
validateFilter(df, leaf->rvalue.l);
// add symbol
QString symbol = *(leaf->lvalue.l->lvalue.n);
df->symbols.insert(symbol, Result(0));
// validate rhs is numeric
bool rhsType = Leaf::isNumber(df, leaf->rvalue.l);
if (!rhsType) {
DataFiltererrors << QString(tr("variables must be numeric."));
leaf->inerror = true;
}
} else {
DataFiltererrors << QString(tr("assignment must be to a symbol."));
leaf->inerror = true;
}
// and check the rhs is good too
validateFilter(df, leaf->rvalue.l);
} else {
// first lets make sure the lhs and rhs are of the same type
bool lhsType = Leaf::isNumber(df, leaf->lvalue.l);
bool rhsType = Leaf::isNumber(df, leaf->rvalue.l);
if (lhsType != rhsType) {
DataFiltererrors << QString(tr("comparing strings with numbers"));
leaf->inerror = true;
}
// what about using string operations on a lhs/rhs that
// are numeric?
if ((lhsType || rhsType) && leaf->op >= MATCHES && leaf->op <= CONTAINS) {
DataFiltererrors << tr("using a string operations with a number");
leaf->inerror = true;
}
validateFilter(df, leaf->lvalue.l);
validateFilter(df, leaf->rvalue.l);
}
}
break;
@@ -1235,6 +1268,7 @@ QStringList DataFilter::parseFilter(QString query, QStringList *list)
this->list = list;
isdynamic=false;
snips.clear();
symbols.clear();
// regardless of fail/pass set the signature
setSignature(query);
@@ -1985,6 +2019,9 @@ Result Leaf::eval(Context *context, DataFilter *df, Leaf *leaf, float x, RideIte
QString rename;
QString symbol = *(leaf->lvalue.n);
// user defined symbols override all others !
if (df->symbols.contains(symbol)) return Result(df->symbols.value(symbol));
// is it isRun ?
if (symbol == "x") {
@@ -2106,10 +2143,11 @@ Result Leaf::eval(Context *context, DataFilter *df, Leaf *leaf, float x, RideIte
case Leaf::Operation :
{
// lhs and rhs
Result lhs = eval(context, df, leaf->lvalue.l, x, m, p);
Result rhs;
Result lhs;
if (leaf->op != ASSIGN) lhs = eval(context, df, leaf->lvalue.l, x, m, p);
// if elvis we only evaluate rhs if we are null
Result rhs;
if (leaf->op != ELVIS || lhs.number == 0) {
rhs = eval(context, df, leaf->rvalue.l, x, m, p);
}
@@ -2117,6 +2155,21 @@ Result Leaf::eval(Context *context, DataFilter *df, Leaf *leaf, float x, RideIte
// NOW PERFORM OPERATION
switch (leaf->op) {
case ASSIGN:
{
// LHS MUST be a symbol...
if (leaf->lvalue.l->type == Leaf::Symbol) {
QString symbol = *(leaf->lvalue.l->lvalue.n);
Result value(rhs.isNumber ? rhs.number : 0);
df->symbols.insert(symbol, value);
return value;
}
return Result(0);
}
break;
case ADD:
{
if (lhs.isNumber) return Result(lhs.number + rhs.number);