From 4fca40fc692d6cf612be21d63d578b595c8b1cc6 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Thu, 16 Jun 2011 20:30:48 -0400 Subject: [PATCH] Expressions - Added Expression::eval short-circuit. - Added int/number exlclusions for Nibbler::getDOM. - Added Variant::boolean for exatracting filter results. --- src/Expression.cpp | 52 ++++++++++++++++++++++++++++++++++++++-------- src/Nibbler.cpp | 11 ++++++++++ src/Variant.cpp | 8 +++++++ src/Variant.h | 1 + 4 files changed, 63 insertions(+), 9 deletions(-) diff --git a/src/Expression.cpp b/src/Expression.cpp index cf1c6041b..b81aa90d8 100644 --- a/src/Expression.cpp +++ b/src/Expression.cpp @@ -27,6 +27,7 @@ #include // TODO Remove. #include +#include #include #include #include @@ -70,6 +71,12 @@ Expression::~Expression () //////////////////////////////////////////////////////////////////////////////// bool Expression::eval (Task& task) { + // If there are no elements in the filter, then all tasks pass. + if (_args.size () == 0) + return true; + + // There are elements in the filter, so the expression must be evaluated + // against each task. std::vector value_stack; std::vector >::iterator arg; @@ -88,18 +95,19 @@ bool Expression::eval (Task& task) // TODO Need helpers that pop, and error out if necessary. if (arg->first == "+") { - // TODO This needs to be type-aware. Variant right (value_stack.back ()); value_stack.pop_back (); Variant left (value_stack.back ()); value_stack.pop_back (); + context.debug ("eval left=" + left.format ()); + context.debug ("eval right=" + right.format ()); left = left + right; + context.debug ("eval + --> " + left.format ()); value_stack.push_back (left); } - else if (arg->first == "and") { } @@ -183,15 +191,41 @@ bool Expression::eval (Task& task) else throw std::string ("Unsupported operator '") + arg->first + "'."; } -/* + + // It's not an operator, it's either and lvalue or some form of rvalue. else - value_stack.push_back (Variant (*arg)); -*/ + { + if (arg->second == "lvalue") + value_stack.push_back (Variant (context.dom.get (arg->first))); + + else if (arg->second == "int") + value_stack.push_back (Variant ((int) strtol (arg->first.c_str (), NULL, 10))); + + else if (arg->second == "number") + value_stack.push_back (Variant (strtod (arg->first.c_str (), NULL))); + + else if (arg->second == "rvalue" || + arg->second == "string" || + arg->second == "rx") + value_stack.push_back (Variant (arg->first)); + + else + throw std::string ("Error: Expression::eval unrecognized operand '") + + "'."; + } + } - // TODO Any more values on stack? Error. - // TODO Return the value that is on the stack. - return false; + // Coerce stack element to boolean. + Variant result (value_stack.back ()); + context.debug ("eval result=" + result.format ()); + value_stack.pop_back (); + bool pass_fail = result.boolean (); + + // Check for stack remnants. + if (value_stack.size ()) + throw std::string ("Error: Expression::eval found extra items on the stack."); + + return pass_fail; } //////////////////////////////////////////////////////////////////////////////// @@ -316,7 +350,7 @@ void Expression::expand_tokens () temp.push_back (std::make_pair (s, "op")); else if (n.getDOM (s)) - temp.push_back (std::make_pair (s, "dom")); + temp.push_back (std::make_pair (s, "lvalue")); else if (n.getNumber (d)) temp.push_back (std::make_pair (format (d), "number")); diff --git a/src/Nibbler.cpp b/src/Nibbler.cpp index 33454c315..a1f22dab1 100644 --- a/src/Nibbler.cpp +++ b/src/Nibbler.cpp @@ -927,6 +927,17 @@ bool Nibbler::getDOM (std::string& found) if (i > mCursor) { found = mInput.substr (start, i - start); + + // If found is simple a number, then it is not a DOM reference. + double d; + Nibbler exclusion (found); + if (exclusion.getNumber (d) && exclusion.depleted ()) + return false; + + int in; + if (exclusion.getInt (in) && exclusion.depleted ()) + return false; + mCursor = i; return true; } diff --git a/src/Variant.cpp b/src/Variant.cpp index c4eb03abb..7317b39fb 100644 --- a/src/Variant.cpp +++ b/src/Variant.cpp @@ -852,4 +852,12 @@ void Variant::promote (Variant& lhs, Variant& rhs) } //////////////////////////////////////////////////////////////////////////////// +// Casts to boolean and returns the value. Used to evaluating expression +// results. +bool Variant::boolean () +{ + cast (v_boolean); + return mBool; +} +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/Variant.h b/src/Variant.h index d222d4118..70fc616f8 100644 --- a/src/Variant.h +++ b/src/Variant.h @@ -90,6 +90,7 @@ public: void cast (const variant_type); variant_type type (); void promote (Variant&, Variant&); + bool boolean (); private: variant_type mType;