Splits EvaluationValue class impl into various base classes 25/167425/44
authorRadoslaw Cybulski <r.cybulski@partner.samsung.com>
Mon, 15 Jan 2018 09:14:20 +0000 (10:14 +0100)
committerRadoslaw Cybulski <r.cybulski@partner.samsung.com>
Thu, 25 Jan 2018 15:11:43 +0000 (16:11 +0100)
Note, this patch requires next one (Adds Args struct for getting all
arguments unprocessed in batch mode) to work properly.

Change-Id: I4ac0f78e716e314a3079baf788858f6dbeacd0c9

22 files changed:
src/UIElement.cpp
src/UIElement.hpp
src/batch/BatchRunner.cpp
src/batch/EvaluationContext.cpp
src/batch/EvaluationContext.hpp
src/batch/EvaluationValue.cpp
src/batch/EvaluationValue.hpp
src/batch/EvaluationValueBase.cpp [new file with mode: 0644]
src/batch/EvaluationValueBase.hpp [new file with mode: 0644]
src/batch/EvaluationValueBoolean.cpp [new file with mode: 0644]
src/batch/EvaluationValueDict.cpp [new file with mode: 0644]
src/batch/EvaluationValueDouble.cpp [new file with mode: 0644]
src/batch/EvaluationValueFunction.cpp [new file with mode: 0644]
src/batch/EvaluationValueInteger.cpp [new file with mode: 0644]
src/batch/EvaluationValuePoint.cpp [new file with mode: 0644]
src/batch/EvaluationValueSet.cpp [new file with mode: 0644]
src/batch/EvaluationValueString.cpp [new file with mode: 0644]
src/batch/EvaluationValueUIElement.cpp [new file with mode: 0644]
src/batch/EvaluationValueVector.cpp [new file with mode: 0644]
src/batch/Evaluator.cpp
src/batch/Evaluator.hpp
tests/no-ui-scenarios/BatchExecTests.cpp

index 76b5ed6..def19e5 100644 (file)
@@ -25,7 +25,7 @@
 #define NUMBER_OF_STEPS 10
 
 
-UIElement::UIElement(std::shared_ptr<AtspiAccessible> ptr, Optional<Point> scanningCoordinates,
+UIElement::UIElement(std::shared_ptr<AtspiAccessible> ptr, Point scanningCoordinates,
                                         ApplicationCategory appCategory) : atspi(Singleton<UniversalSwitch>::instance().getAtspi()), obj(std::move(ptr)),
        appCategory(appCategory), scanningCoordinates(std::move(scanningCoordinates))
 {
@@ -83,19 +83,7 @@ void UIElement::getAttributeAsync(const std::string &key, std::function<void(std
 
 Point UIElement::getScanningCoordinates() const
 {
-       if (scanningCoordinates)
-               return *scanningCoordinates;
-
-       ASSERT(obj, "No object and scanningCoordinates");
-
-       auto comp = atspi_accessible_get_component(obj.get());
-       ASSERT(comp, "No component in AT-SPI object");
-
-       auto rect = atspi_component_get_extents(comp, ATSPI_COORD_TYPE_WINDOW, nullptr);
-       ASSERT(rect, "No extents");
-
-       // central point of rectangle
-       return {rect->x + (rect->width / 2), rect->y + (rect->height / 2)};
+       return scanningCoordinates;
 }
 
 namespace
index 148ed81..5cf2ca2 100644 (file)
@@ -36,7 +36,7 @@ public:
                OTHER,
        };
 
-       UIElement(std::shared_ptr<AtspiAccessible> ptr, Optional<Point> scanningCoordinates, ApplicationCategory appCategory);
+       UIElement(std::shared_ptr<AtspiAccessible> ptr, Point scanningCoordinates, ApplicationCategory appCategory);
 
        std::shared_ptr<AtspiAccessible> getObject() const;
 
@@ -58,7 +58,7 @@ private:
        ApplicationCategory appCategory;
 
        Optional<std::unordered_map<std::string, std::string>> attributes;
-       Optional<Point> scanningCoordinates;
+       Point scanningCoordinates;
 };
 
 #endif
index 010785a..251ffb7 100644 (file)
@@ -20,6 +20,7 @@
 #include "Lexer.hpp"
 #include "Parser.hpp"
 #include "EvaluationContext.hpp"
+#include "EvaluationValue.hpp"
 #include "Evaluator.hpp"
 #include "../ActivityFactory.hpp"
 #include "../Observer.hpp"
@@ -194,16 +195,6 @@ template <typename T, typename MONITORED_TYPE> MONITORED_TYPE executeOnMainThrea
        return h->takeValue();
 }
 
-namespace std
-{
-       template <> struct hash<std::pair<detail::Kind, std::string>> {
-               size_t operator()(const std::pair<detail::Kind, std::string> &p) const
-               {
-                       return std::hash<std::string>()(p.second) ^ (unsigned char)p.first;
-               }
-       };
-}
-
 struct TestExecutor : ExecutorInterface {
        NavigationInterface::CallbackHandle contextChangedHandle;
        struct ContextInfo {
@@ -217,9 +208,7 @@ struct TestExecutor : ExecutorInterface {
                bool found = false;
        };
        Monitor<TTSInfo> ttsInfo;
-       std::unordered_map<std::string, EvaluationValue> variables;
-       std::unordered_map<std::pair<detail::Kind, std::string>, EvaluationValue> setters;
-       std::unordered_map<std::pair<detail::Kind, std::string>, EvaluationValue> getters;
+       std::unordered_map<std::string, EvaluationValue_> variables;
        std::ostream &output;
 
        // NOTE: constructor of TestExecutor must be called on main thread
@@ -229,49 +218,40 @@ struct TestExecutor : ExecutorInterface {
        {
                insertRoleConstants();
                insertStateConstants();
-               variables["sleep"] = detail::UserFunctionType<double> {
-                       [&](double tm) -> EvaluationValue {
-                               if (tm > 0)
-                               {
-                                       auto sleepTime = std::chrono::milliseconds{ static_cast<int>(std::floor(1000.0 * tm + 0.5)) };
-                                       std::this_thread::sleep_for(sleepTime);
-                               }
-                               return {};
+               variables["sleep"] = [&](double tm) -> EvaluationValue_ {
+                       if (tm > 0)
+                       {
+                               auto sleepTime = std::chrono::milliseconds{ static_cast<int>(std::floor(1000.0 * tm + 0.5)) };
+                               std::this_thread::sleep_for(sleepTime);
                        }
+                       return {};
                };
-               variables["print"] = detail::UserFunctionType<std::string> {
-                       [&](std::string txt) -> EvaluationValue {
-                               output << txt << "\n";
-                               return {};
-                       }
+               variables["print"] = [&](std::string txt) -> EvaluationValue_ {
+                       output << txt << "\n";
+                       return {};
                };
-               variables["get_at_point"] = detail::UserFunctionType<Point> {
-                       [&](Point pt) -> EvaluationValue {
-                               return convert(pt);
-                       }
+               variables["get_at_point"] = [&](Point pt) -> EvaluationValue_ {
+                       return convertToUIElement(pt);
                };
-               variables["assert"] = detail::UserFunctionType<bool> {
-                       [&](bool condition) -> EvaluationValue {
-                               if (!condition) throw EvaluationFailure{} << "assertion failed";
-                               return {};
-                       }
+               variables["assert"] = [&](bool condition) -> EvaluationValue_ {
+                       if (!condition) throw EvaluationFailure{} << "assertion failed";
+                       return {};
                };
-               variables["wait_for_tts"] = detail::UserFunctionType<std::string> {
-                       [&](std::string pattern) -> EvaluationValue {
-                               std::regex regex;
-                               try
-                               {
-                                       regex = std::regex {
-                                               pattern,
-                                               std::regex_constants::nosubs |
-                                               std::regex_constants::optimize |
-                                               std::regex_constants::ECMAScript
-                                       };
-                               } catch (...)
-                               {
-                                       throw EvaluationFailure{} << "invalid regex pattern '" << pattern << "'";
-                               }
-
+               variables["wait_for_tts"] = [&](std::string pattern) -> EvaluationValue_ {
+                       std::regex regex;
+                       try
+                       {
+                               regex = std::regex {
+                                       pattern,
+                                       std::regex_constants::nosubs |
+                                       std::regex_constants::optimize |
+                                       std::regex_constants::ECMAScript
+                               };
+                       } catch (...)
+                       {
+                               throw EvaluationFailure{} << "invalid regex pattern '" << pattern << "'";
+                       }
+                       {
                                auto h = ttsInfo.lock();
                                h->searchLine = std::move(regex);
                                h->found = false;
@@ -285,128 +265,85 @@ struct TestExecutor : ExecutorInterface {
                                return {};
                        }
                };
-               variables["wait_for_application"] = detail::UserFunctionType<std::string> {
-                       [&](std::string name) -> EvaluationValue {
-                               auto h = contextInfo.lock();
-                               auto untilMoment = std::chrono::high_resolution_clock::now() + 3000ms;
-                               auto success = h.waitForCondition(untilMoment, [&]()
-                               {
-                                       return h->rootName == name;
-                               });
-                               if (!success)
-                                       throw EvaluationFailure{} << "wait_for_application('" << name << "'): operation timeouted, " <<
-                                                                                 "current root name is '" << h->rootName << "'";
-                               return {};
-                       }
-               };
-               variables["find_by_name"] = detail::UserFunctionType<std::string, std::vector<int>, std::vector<int>> {
-                       [&](std::string name, std::vector<int> roles, std::vector<int> states) -> EvaluationValue {
-                               auto root = getVisibleRoot();
-                               if (!root) throw EvaluationFailure{} << "no visible root (context changed didn't happen)";
-                               ASSERT(root->getObject());
-                               Monitor<BatchValueOrError<std::vector<std::shared_ptr<UIElement>>>> monitor;
-
-                               return executeOnMainThread([&]()
-                               {
-                                       getAllObjects(root->getObject(), wrap(monitor, [ = ](DBus::ValueOrError<std::vector<AtspiAccessiblePtr>> allElements) {
-                                               findByName(std::get<0>(allElements), name, wrap(monitor, [ = ](DBus::ValueOrError<std::vector<AtspiAccessiblePtr>> elements) {
-                                                       auto &elems = std::get<0>(elements);
-                                                       makeUIElements(std::move(elems), wrap(monitor, [ = ](DBus::ValueOrError<std::vector<std::shared_ptr<UIElement>>> uiElems) {
-                                                               auto h = monitor.lock();
-                                                               h->setValue(std::move(std::get<0>(uiElems)));
-                                                       }));
-                                               }));
-                                       }), std::move(roles), std::move(states));
-                               }, monitor);
-                       }
+               variables["wait_for_application"] = [&](std::string name) -> EvaluationValue_ {
+                       auto h = contextInfo.lock();
+                       auto untilMoment = std::chrono::high_resolution_clock::now() + 3000ms;
+                       auto success = h.waitForCondition(untilMoment, [&]() {
+                               return h->rootName == name;
+                       });
+                       if (!success)
+                               throw EvaluationFailure{} << "wait_for_application('" << name << "'): operation timeouted, " <<
+                                                                                               "current root name is '" << h->rootName << "'";
+                       return {};
                };
-               getters[ { detail::Kind::UIELEMENT, "name" }] = detail::UserFunctionType<std::shared_ptr<UIElement>> {
-                       [&](std::shared_ptr<UIElement> uiElem)
+               variables["find_by_name"] = [&](std::string name, std::vector<int> roles, std::vector<int> states) -> EvaluationValue_ {
+                       auto root = getVisibleRoot();
+                       if (!root) throw EvaluationFailure{} << "no visible root (context changed didn't happen)";
+                       ASSERT(root->getObject());
+                       Monitor<BatchValueOrError<std::vector<std::shared_ptr<UIElement>>>> monitor;
+
+                       return executeOnMainThread([&]()
                        {
-                               ASSERT(uiElem->getObject());
-                               return executeOnMainThread([&]() {
-                                       auto root = getVisibleRoot();
-                                       auto atspi = Singleton<UniversalSwitch>::instance().getAtspi();
-                                       auto found = atspi->getName(uiElem->getObject());
-                                       if (found)
-                                               return std::move(*found);
-                                       throw EvaluationFailure{} << "failed to get at-spi object's name (use dlogutil to get at-spi error message)";
-                               });
-                       }
-               };
-               getters[ { detail::Kind::POINT, "x" }] = detail::UserFunctionType<Point> {
-                       [&](Point p) -> EvaluationValue {
-                               return p.x;
-                       }
-               };
-               getters[ { detail::Kind::POINT, "y" }] = detail::UserFunctionType<Point> {
-                       [&](Point p) -> EvaluationValue {
-                               return p.y;
-                       }
+                               getAllObjects(root->getObject(), wrap(monitor, [ = ](DBus::ValueOrError<std::vector<AtspiAccessiblePtr>> allElements) {
+                                       findByName(std::get<0>(allElements), name, wrap(monitor, [ = ](DBus::ValueOrError<std::vector<AtspiAccessiblePtr>> elements) {
+                                               auto &elems = std::get<0>(elements);
+                                               makeUIElements(std::move(elems), wrap(monitor, [ = ](DBus::ValueOrError<std::vector<std::shared_ptr<UIElement>>> uiElems) {
+                                                       auto h = monitor.lock();
+                                                       h->setValue(std::move(std::get<0>(uiElems)));
+                                               }));
+                                       }));
+                               }), std::move(roles), std::move(states));
+                       }, monitor);
                };
-               getters[ { detail::Kind::UIELEMENT, "middle_point" }] = detail::UserFunctionType<std::shared_ptr<UIElement>> {
-                       [&](std::shared_ptr<UIElement> uiElem) -> EvaluationValue {
-                               ASSERT(uiElem->getObject());
-                               Optional<Rectangle> result;
-                               return executeOnMainThread([&]()
+               for (auto activityName : ActivityFactory::getInstance()->getAllActivityTypes()) {
+                       variables[activityName] = [ = ](std::vector<EvaluationValue_> args) -> EvaluationValue_ {
+                               auto activity = executeOnMainThread([&]()
                                {
-                                       auto atspi = Singleton<UniversalSwitch>::instance().getAtspi();
-                                       auto comp = atspi->getComponentInterface(uiElem->getObject());
-                                       if (comp) {
-                                               auto found = atspi->getScreenPosition(comp);
-                                               if (found)
-                                                       return (*found).getCenterPoint();
-                                       }
-                                       throw EvaluationFailure{} << "failed to get at-spi object's screen position (use dlogutil to get at-spi error message)";
+                                       return ActivityFactory::getInstance()->createActivity(activityName);
                                });
-                       }
-               };
-               for (auto activityName : ActivityFactory::getInstance()->getAllActivityTypes()) {
-                       variables[activityName] = detail::FunctionType::Type{
-                               [ = ](std::vector<EvaluationValue> args) -> EvaluationValue {
-                                       auto activity = executeOnMainThread([&]()
-                                       {
-                                               return ActivityFactory::getInstance()->createActivity(activityName);
-                                       });
-                                       if (!activity)
-                                               throw EvaluationFailure{} << "failed to construct '" << activityName << "' activity";
-                                       auto numOfArgs = activity->getRequiredNumberOfArgumentsIfAllowedInBatchProcessing();
-                                       if (!numOfArgs)
-                                               throw EvaluationFailure{} << "activity '" << activityName << "' is not supported";
-                                       if (*numOfArgs != args.size())
-                                               throw EvaluationFailure{} << "invalid number of arguments for activity '" << activityName <<
-                                                                                         "', got " << args.size() << ", expected " << *numOfArgs;
-                                       auto uiActivity = std::dynamic_pointer_cast<UIActivity>(activity);
-                                       if (!args.empty() && !uiActivity)
-                                               throw EvaluationFailure{} << "activity '" << activityName << "' doesn't inherit from Observer<UIElement>, "
-                                                                                         "which it must, becuase it expects arguments";
-                                       std::vector<std::shared_ptr<UIElement>> uiArgs(args.size());
-                                       for (size_t i = 0; i < args.size(); ++i)
-                                       {
-                                               ASSERT(uiActivity);
-                                               uiArgs[i] = detail::ConvertTo<std::shared_ptr<UIElement>>::convert(std::move(args[i]));
-                                               if (!uiArgs[i])
-                                                       throw EvaluationFailure{} << "can't convert argument " << (i + 1) <<
-                                                                                                 " of kind " << EvaluationValue::toString(args[i].kind()) << " to UIElement";
-                                       }
-                                       Monitor<BatchValueOrError<bool>> monitor;
+                               if (!activity)
+                                       throw EvaluationFailure{} << "failed to construct '" << activityName << "' activity";
+                               auto numOfArgs = activity->getRequiredNumberOfArgumentsIfAllowedInBatchProcessing();
+                               if (!numOfArgs)
+                                       throw EvaluationFailure{} << "activity '" << activityName << "' is not supported";
+                               if (*numOfArgs != args.size())
+                                       throw EvaluationFailure{} << "invalid number of arguments for activity '" << activityName <<
+                                                                                 "', got " << args.size() << ", expected " << *numOfArgs;
+                               auto uiActivity = std::dynamic_pointer_cast<Observer<UIElement>>(activity);
+                               if (!args.empty() && !uiActivity)
+                                       throw EvaluationFailure{} << "activity '" << activityName << "' doesn't inherit from Observer<UIElement>, "
+                                                                                 "which it must, becuase it expects arguments";
+                               std::vector<std::shared_ptr<UIElement>> uiArgs(args.size());
+                               for (size_t i = 0; i < args.size(); ++i)
+                               {
+                                       ASSERT(uiActivity);
+                                       uiArgs[i] = args[i].convertToUIElement();
+                                       if (!uiArgs[i])
+                                               throw EvaluationFailure{} << "can't convert argument " << (i + 1) <<
+                                                                                         " of kind " << args[i].typeName() << " to UIElement";
+                               }
+                               Monitor<BatchValueOrError<bool>> monitor;
+                               {
+                                       executeOnMainThread([&]()
                                        {
-                                               executeOnMainThread([&]()
-                                               {
-                                                       DEBUG("calling activity %s", activityName.c_str());
-                                                       for (auto &arg : uiArgs) {
-                                                               ASSERT(uiActivity);
-                                                               uiActivity->update(std::move(arg));
-                                                       }
-                                                       activity->process(DoneCallback{ [ = ] {
-                                                                       auto h = monitor.lock();
-                                                                       h->setValue(true);
-                                                               } });
-                                                       DEBUG("calling activity %s done", activityName.c_str());
-                                               }, monitor);
-                                       }
-                                       return {};
-                               } };
+                                               DEBUG("calling activity %s", activityName.c_str());
+                                               for (auto &arg : uiArgs) {
+                                                       ASSERT(uiActivity);
+                                                       uiActivity->update(std::move(arg));
+                                               }
+                                               activity->process(DoneCallback{ [ = ] {
+                                                               auto h = monitor.lock();
+                                                               h->setValue(true);
+                                                       } });
+                                               if (!activity->isCompleted())
+                                                       throw EvaluationFailure{} << "not enough arguments for activity '" << activityName << "'";
+                                               DEBUG("calling activity %s done", activityName.c_str());
+                                       }, monitor);
+                                       auto h = monitor.lock();
+                                       ASSERT(*h); // sanity check, must be set, otherwise an exception was throw
+                               }
+                               return {};
+                       };
                }
 
                auto updateContextInfo = [this](std::shared_ptr<UIElement> root, std::shared_ptr<NavigationElement> navigationContext) {
@@ -428,7 +365,7 @@ struct TestExecutor : ExecutorInterface {
                                                           registerCb<NavigationCallbackType::ContextChanged>(std::move(updateContextInfo));
        }
        ~TestExecutor() = default;
-       EvaluationValue getVariableByName(const std::string &name) override
+       EvaluationValue_ getVariableByName(const std::string &name) override
        {
                auto it = variables.find(name);
                if (it != variables.end())
@@ -436,24 +373,6 @@ struct TestExecutor : ExecutorInterface {
                throw EvaluationFailure{} << "unknown variable '" << name << "'";
        }
 
-       EvaluationValue setAttribute(const EvaluationValue &self, const std::string &name, EvaluationValue value) override
-       {
-               auto it = setters.find({ self.kind(), name });
-               if (it != setters.end()) {
-                       return it->second.as<detail::FunctionType>()(self, std::move(value));
-               }
-               return ExecutorInterface::setAttribute(self, name, std::move(value));
-       }
-
-       EvaluationValue getAttribute(const EvaluationValue &self, const std::string &name) override
-       {
-               auto it = getters.find({ self.kind(), name });
-               if (it != getters.end()) {
-                       return it->second.as<detail::FunctionType>()(self);
-               }
-               return ExecutorInterface::getAttribute(self, name);
-       }
-
        std::shared_ptr<UIElement> getVisibleRoot() override
        {
                auto h = contextInfo.lock();
@@ -464,15 +383,34 @@ struct TestExecutor : ExecutorInterface {
        {
                return output;
        }
-       std::shared_ptr<UIElement> convert(Point pt) override
+       std::shared_ptr<UIElement> convertToUIElement(Point pt) override
        {
                return executeOnMainThread([&]() {
                        auto root = getVisibleRoot();
                        auto atspi = Singleton<UniversalSwitch>::instance().getAtspi();
                        auto found = atspi->getAtPoint(pt, Atspi::CoordType::Screen, root->getObject());
+                       if (!found) throw EvaluationFailure{} << "no at-spi object found at position <" <<
+                                                                                                         pt.x << ", " << pt.y << ">";
                        return std::make_shared<UIElement>(std::move(found), pt, root->getApplicationCategory());
                });
        }
+
+       std::string getUIElementName(const std::shared_ptr<UIElement> &uiElem) override
+       {
+               return executeOnMainThread([&]() {
+                       auto atspi = Singleton<UniversalSwitch>::instance().getAtspi();
+                       auto found = atspi->getName(uiElem->getObject());
+                       if (found)
+                               return std::move(*found);
+                       throw EvaluationFailure{} << "failed to get at-spi object's name (use dlogutil to get at-spi error message)";
+               });
+       }
+       std::string getUIElementUniqueId(const std::shared_ptr<UIElement> &uiElem) override
+       {
+               return executeOnMainThread([&]() {
+                       return Atspi::getUniqueId(uiElem->getObject());
+               });
+       }
        void findByName(const std::vector<AtspiAccessiblePtr> &elems, std::string requestedName, std::function<void(DBus::ValueOrError<std::vector<AtspiAccessiblePtr>>)> callback)
        {
                struct Exec {
@@ -572,7 +510,7 @@ struct TestExecutor : ExecutorInterface {
                }
        }
 
-       std::shared_ptr<UIElement> convert(const std::string &requestedName) override
+       std::shared_ptr<UIElement> convertToUIElement(const std::string &requestedName) override
        {
                Monitor<BatchValueOrError<std::shared_ptr<UIElement>>> monitor;
 
index 26801fc..3681cf6 100644 (file)
 
 #include "EvaluationContext.hpp"
 
-using detail::VectorType;
-using detail::SetType;
-using detail::FunctionType;
-using detail::DictType;
-
-namespace std
-{
-       template <> struct hash<std::pair<detail::Kind, detail::Kind>> {
-               size_t operator()(std::pair<detail::Kind, detail::Kind> p) const
-               {
-                       return ((unsigned char)p.first << 8) | (unsigned char)p.second;
-               }
-       };
-}
 struct EvaluationContext::GlobalContext {
        ExecutorInterface &executionInterface;
 };
@@ -70,12 +56,12 @@ ExecutorInterface &EvaluationContext::executionInterface() const
        return globalContext->executionInterface;
 }
 
-void EvaluationContext::setVariable(const std::string &ident, EvaluationValue val)
+void EvaluationContext::setVariable(const std::string &ident, EvaluationValue_ val)
 {
        variables[ident] = std::move(val);
 }
 
-EvaluationValue EvaluationContext::getVariable(const Optional<TokenLocation> &loc, const std::string &ident)
+EvaluationValue_ EvaluationContext::getVariable(const Optional<TokenLocation> &loc, const std::string &ident)
 {
        EvaluationContext *self = this;
        while (self) {
@@ -91,312 +77,28 @@ EvaluationValue EvaluationContext::getVariable(const Optional<TokenLocation> &lo
        }
 }
 
-EvaluationValue EvaluationContext::callFunction(const Optional<TokenLocation> &loc, EvaluationValue function, std::vector<EvaluationValue> values)
-{
-       Optional<EvaluationValue> v;
-
-       switch (function.kind()) {
-       case detail::Kind::FUNCTION:
-               try {
-                       return function.as<detail::FunctionType>()(std::move(values));
-               } catch (EvaluationFailure &e) {
-                       if (loc) e.setLocationIfMissing(*loc);
-                       throw;
-               }
-       case detail::Kind::STRING:
-       case detail::Kind::INTEGER:
-       case detail::Kind::DOUBLE:
-       case detail::Kind::UIELEMENT:
-       case detail::Kind::BOOLEAN:
-       case detail::Kind::POINT:
-       case detail::Kind::EMPTY:
-       case detail::Kind::VECTOR:
-       case detail::Kind::SET:
-       case detail::Kind::DICT:
-               break;
-       }
-       throw EvaluationFailure{loc} << "value of kind " << EvaluationValue::toString(function.kind()) <<
-                                                                " is not callable";
-}
-
-EvaluationValue ExecutorInterface::getVariableByName(const std::string &name)
-{
-       throw EvaluationFailure{} << "unknown variable '" << name << "'";
-}
-
-EvaluationValue ExecutorInterface::setAttribute(const EvaluationValue &self, const std::string &name, EvaluationValue value)
-{
-       throw EvaluationFailure{} << "value of kind " << EvaluationValue::toString(self.kind()) <<
-                                                         " doesn't accept attribute '" << name << "'";
-}
-
-EvaluationValue ExecutorInterface::getAttribute(const EvaluationValue &self, const std::string &name)
-{
-       throw EvaluationFailure{} << "value of kind " << EvaluationValue::toString(self.kind()) <<
-                                                         " doesn't have attribute '" << name << "'";
-}
-
-std::shared_ptr<UIElement> ExecutorInterface::convert(Point pt)
-{
-       throw EvaluationFailure{} << "no at-spi object found at position " << pt.toString();
-}
-
-std::shared_ptr<UIElement> ExecutorInterface::convert(const std::string &txt)
-{
-       throw EvaluationFailure{} << "no at-spi object found with name '" << txt << "'";
-}
-
-EvaluationValue EvaluationContext::getAttribute(const Optional<TokenLocation> &loc, EvaluationValue self, const std::string &identifier)
-{
-       try {
-               return globalContext->executionInterface.getAttribute(self, identifier);
-       } catch (EvaluationFailure &e) {
-               if (loc) e.setLocationIfMissing(*loc);
-               throw;
-       }
-}
-
-EvaluationValue EvaluationContext::setAttribute(const Optional<TokenLocation> &loc, EvaluationValue self, const std::string &identifier, EvaluationValue value)
-{
-       try {
-               return globalContext->executionInterface.setAttribute(self, identifier, std::move(value));
-       } catch (EvaluationFailure &e) {
-               if (loc) e.setLocationIfMissing(*loc);
-               throw;
-       }
-}
-
-EvaluationValue EvaluationContext::convert(const Optional<TokenLocation> &loc, const EvaluationValue &value, detail::Kind targetType)
+std::string ExecutorInterface::getUIElementName(const std::shared_ptr<UIElement> &elem)
 {
-       if (value.kind() == targetType) return value;
-
-       try {
-               switch (value.kind()) {
-               case detail::Kind::FUNCTION:
-               case detail::Kind::STRING:
-                       return detail::ConvertTo<std::string>::convert(value);
-               case detail::Kind::INTEGER:
-                       return detail::ConvertTo<int>::convert(value);
-               case detail::Kind::DOUBLE:
-                       return detail::ConvertTo<double>::convert(value);
-               case detail::Kind::UIELEMENT:
-                       return detail::ConvertTo<std::shared_ptr<UIElement>>::convert(value);
-               case detail::Kind::BOOLEAN:
-                       return detail::ConvertTo<bool>::convert(value);
-               case detail::Kind::POINT:
-                       return detail::ConvertTo<Point>::convert(value);
-               case detail::Kind::EMPTY:
-                       return {};
-               case detail::Kind::VECTOR:
-               case detail::Kind::SET:
-               case detail::Kind::DICT:
-                       break;
-               }
-       } catch (EvaluationFailure &e) {
-               if (loc) e.setLocationIfMissing(*loc);
-               throw;
-       }
-       throw EvaluationFailure{loc} << "can't convert from " << EvaluationValue::toString(value.kind()) <<
-                                                                " to " << EvaluationValue::toString(detail::Kind::FUNCTION);
+       throw EvaluationFailure{} << "getUIElementName not implemeneted";
 }
 
-int EvaluationContext::getSingleIndex(const std::vector<EvaluationValue> &args, int size, std::string typeName)
+std::string ExecutorInterface::getUIElementUniqueId(const std::shared_ptr<UIElement> &elem)
 {
-       ASSERT(args.size() >= 2);
-       auto index = detail::ConvertTo<int>::convert(args[1]);
-       auto origIndex = index;
-       if (index < 0) index += size;
-       if (index < 0 || index >= size) throw EvaluationFailure{} << origIndex << " is out of range for " << typeName << " of size " << size;
-       return index;
+       throw EvaluationFailure{} << "getUIElementUniqueId not implemeneted";
 }
 
-std::pair<int, int> EvaluationContext::getDoubleIndexes(const std::vector<EvaluationValue> &args, int size)
+std::shared_ptr<UIElement> ExecutorInterface::convertToUIElement(Point pt)
 {
-       ASSERT(args.size() >= 3);
-       auto index1 = detail::ConvertTo<int>::convert(args[1]);
-       auto index2 = detail::ConvertTo<int>::convert(args[2]);
-       if (index1 < 0) index1 += size;
-       if (index2 < 0) index2 += size;
-
-       if (index1 < 0) index1 = 0;
-       else if (index1 > size) index1 = size;
-       if (index2 < index1) index2 = index1;
-       else if (index2 > size) index2 = size;
-       return std::pair<int, int> { index1, index2 };
+       throw EvaluationFailure{} << "convertToUIElement from Point not implemeneted";
 }
 
-EvaluationValue EvaluationContext::evaluateAccessGet(const Optional<TokenLocation> &loc, const std::vector<EvaluationValue> &args)
+std::shared_ptr<UIElement> ExecutorInterface::convertToUIElement(const std::string &txt)
 {
-       try {
-               ASSERT(!args.empty());
-               auto &self = args[0];
-               switch (self.kind()) {
-               case detail::Kind::STRING:
-                       if (args.size() == 2) {
-                               auto index = getSingleIndex(args, static_cast<int>(self.as<std::string>().size()), "string");
-                               return self.as<std::string>().substr(index, 1);
-                       } else if (args.size() == 3) {
-                               auto indexes = getDoubleIndexes(args, static_cast<int>(self.as<std::string>().size()));
-                               return self.as<std::string>().substr(indexes.first, indexes.second - indexes.first);
-                       }
-                       break;
-               case detail::Kind::FUNCTION:
-               case detail::Kind::INTEGER:
-               case detail::Kind::DOUBLE:
-               case detail::Kind::UIELEMENT:
-               case detail::Kind::BOOLEAN:
-               case detail::Kind::POINT:
-               case detail::Kind::EMPTY:
-               case detail::Kind::SET:
-                       break;
-               case detail::Kind::VECTOR:
-                       if (args.size() == 2) {
-                               auto index = getSingleIndex(args, static_cast<int>(self.as<VectorType>().size()), "vector");
-                               return self.as<VectorType>()[index];
-                       } else if (args.size() == 3) {
-                               auto indexes = getDoubleIndexes(args, static_cast<int>(self.as<VectorType>().size()));
-                               std::vector<EvaluationValue> tmp;
-                               tmp.reserve(indexes.second - indexes.first);
-                               for (auto i = indexes.first; i < indexes.second; ++i)
-                                       tmp.push_back(self.as<VectorType>()[i]);
-                               return std::move(tmp);
-                       }
-                       break;
-               case detail::Kind::DICT:
-                       if (args.size() == 2) {
-                               auto key = EvaluationValueKey{ args[1] };
-                               auto it = self.as<detail::DictType>().find(key);
-                               if (it == self.as<detail::DictType>().end()) throw EvaluationFailure{loc} << "key not found";
-                               return it->second;
-                       }
-                       break;
-               }
-       } catch (EvaluationFailure &e) {
-               if (loc) e.setLocationIfMissing(*loc);
-               throw;
-       }
-
-       std::ostringstream tmp;
-       tmp << EvaluationValue::toString(args[0].kind()) << "[";
-       for (auto i = 1u; i < args.size(); ++i) {
-               if (i != 1) tmp << ", ";
-               tmp << EvaluationValue::toString(args[i].kind());
-       }
-       tmp << "]";
-       throw EvaluationFailure{loc} << "unable to evaluate " << tmp.str();
-}
-
-EvaluationValue EvaluationContext::evaluateAccessSet(const Optional<TokenLocation> &loc, std::vector<EvaluationValue> args)
-{
-       try {
-               ASSERT(!args.empty());
-               auto &self = args[0];
-               switch (self.kind()) {
-               case detail::Kind::STRING:
-               case detail::Kind::FUNCTION:
-               case detail::Kind::INTEGER:
-               case detail::Kind::DOUBLE:
-               case detail::Kind::UIELEMENT:
-               case detail::Kind::BOOLEAN:
-               case detail::Kind::POINT:
-               case detail::Kind::EMPTY:
-               case detail::Kind::SET:
-                       break;
-               case detail::Kind::VECTOR:
-                       if (args.size() == 3) {
-                               auto index = getSingleIndex(args, static_cast<int>(self.as<VectorType>().size()), "vector");
-                               self.as<VectorType>()[index] = args[2];
-                               return std::move(args[2]);
-                       } else if (args.size() == 4 && args[3].kind() == detail::Kind::VECTOR) {
-                               auto indexes = getDoubleIndexes(args, static_cast<int>(self.as<VectorType>().size()));
-                               std::vector<EvaluationValue> tmp;
-                               tmp.reserve(self.as<VectorType>().size() - (indexes.second - indexes.first) + args[3].as<VectorType>().size());
-                               for (auto i = 0; i < indexes.first; ++i) tmp.push_back(std::move(self.as<VectorType>()[i]));
-                               for (auto &v : args[3].as<VectorType>()) tmp.push_back(v);
-                               for (auto i = indexes.second; i < static_cast<int>(self.as<VectorType>().size()); ++i) tmp.push_back(std::move(self.as<VectorType>()[i]));
-                               self.as<VectorType>() = std::move(tmp);
-                               return {};
-                       }
-                       break;
-               case detail::Kind::DICT:
-                       if (args.size() == 3) {
-                               self.as<DictType>()[std::move(args[1])] = args[2];
-                               return std::move(args[2]);
-                       }
-                       break;
-               }
-       } catch (EvaluationFailure &e) {
-               if (loc) e.setLocationIfMissing(*loc);
-               throw;
-       }
-
-       std::ostringstream tmp;
-       tmp << EvaluationValue::toString(args[0].kind()) << "[";
-       for (auto i = 1; i < (int)args.size() - 1; ++i) {
-               if (i != 1) tmp << ", ";
-               tmp << EvaluationValue::toString(args[i].kind());
-       }
-       tmp << "] = " << EvaluationValue::toString(args.back().kind());
-       throw EvaluationFailure{loc} << "unable to evaluate " << tmp.str();
+       throw EvaluationFailure{} << "convertToUIElement from String not implemeneted";
 }
 
-
-EvaluationValue EvaluationContext::evaluateMinus(const Optional<TokenLocation> &loc, const EvaluationValue &self)
+EvaluationValue_ ExecutorInterface::getVariableByName(const std::string &name)
 {
-       try {
-               switch (self.kind()) {
-               case detail::Kind::INTEGER:
-                       return -self.as<int>();
-               case detail::Kind::DOUBLE:
-                       return -self.as<double>();
-               case detail::Kind::STRING:
-               case detail::Kind::SET:
-               case detail::Kind::DICT:
-               case detail::Kind::VECTOR:
-               case detail::Kind::FUNCTION:
-               case detail::Kind::UIELEMENT:
-               case detail::Kind::BOOLEAN:
-               case detail::Kind::POINT:
-               case detail::Kind::EMPTY:
-                       break;
-               }
-       } catch (EvaluationFailure &e) {
-               if (loc) e.setLocationIfMissing(*loc);
-               throw;
-       }
-       throw EvaluationFailure{loc} << "unable to negate value of type " << EvaluationValue::toString(self.kind());
+       throw EvaluationFailure{} << "getVariableByName not implemeneted";
 }
 
-bool EvaluationContext::evaluateIn(const Optional<TokenLocation> &loc, const EvaluationValue &self, const EvaluationValue &value)
-{
-       try {
-               switch (self.kind()) {
-               case detail::Kind::STRING: {
-                       auto val = detail::ConvertTo<std::string>::convert(value);
-                       return self.as<std::string>().find(val) != std::string::npos;
-               }
-               case detail::Kind::SET: {
-                       return self.as<SetType>().find(value) != self.as<SetType>().end();
-               }
-               case detail::Kind::DICT: {
-                       return self.as<DictType>().find(value) != self.as<DictType>().end();
-               }
-               case detail::Kind::VECTOR:
-                       for (auto &v : self.as<VectorType>())
-                               if (v == value) return true;
-                       return false;
-               case detail::Kind::FUNCTION:
-               case detail::Kind::INTEGER:
-               case detail::Kind::DOUBLE:
-               case detail::Kind::UIELEMENT:
-               case detail::Kind::BOOLEAN:
-               case detail::Kind::POINT:
-               case detail::Kind::EMPTY:
-                       break;
-               }
-       } catch (EvaluationFailure &e) {
-               if (loc) e.setLocationIfMissing(*loc);
-               throw;
-       }
-       throw EvaluationFailure{loc} << "value of type " << EvaluationValue::toString(self.kind()) << " is not a collection";
-}
index b5502c1..6f5c0d5 100644 (file)
 
 class UIElement;
 
+/**
+ * @brief Interface class for providing external world functionality (at-spi queries and so on)
+ * 
+ * User should reimplement all methods. Default implementations will throw "not implemented" exceptions.
+ */
 struct ExecutorInterface {
        virtual ~ExecutorInterface() = default;
 
-       virtual EvaluationValue getVariableByName(const std::string &name);
-       virtual EvaluationValue setAttribute(const EvaluationValue &self, const std::string &name, EvaluationValue value);
-       virtual EvaluationValue getAttribute(const EvaluationValue &self, const std::string &name);
-       virtual std::shared_ptr<UIElement> convert(Point pt);
-       virtual std::shared_ptr<UIElement> convert(const std::string &);
+       /**
+        * @brief Finds variable by name
+        * 
+        * Fallback method, when variable is not found in any script's scopes.
+        * This is sort of global variables implementation.
+        * Note, while variable found by this found can't be overwritten (can be updated)
+        * it can be shadowed in batch. For example:
+        * {
+        *   foo = 1
+        *   print(foo)
+        * }
+        * will print 1 even if getVariableByName would return different value for foo.
+        */
+       virtual EvaluationValue_ getVariableByName(const std::string &name);
+
+       /**
+        * @brief Finds object on screen by position
+        * 
+        * Implementation is expected to return object "closest" to user at position
+        * given as argument. Batch implementation queries visible at-spi objects
+        * for their position and "walk" all objects in tree-like fashion, until
+        * single object is found. If the object is not found, then exception
+        * should be raised.
+        */
+       virtual std::shared_ptr<UIElement> convertToUIElement(Point pt);
+
+       /**
+        * @brief Finds object on screen by name
+        * 
+        * Implementation is expected to return object with at-spi name
+        * exactly matching one given, but only if there's only one. Otherwise an
+        * exception should be raised.
+        */
+       virtual std::shared_ptr<UIElement> convertToUIElement(const std::string &);
+
+       /**
+        * @brief Returns at-spi name of given object
+        */
+       virtual std::string getUIElementName(const std::shared_ptr<UIElement> &);
+
+       /**
+        * @brief Returns string uniquely identifying given at-spi object
+        */
+       virtual std::string getUIElementUniqueId(const std::shared_ptr<UIElement> &);
+
+       /**
+        * @brief Returns at-spi object, which is root of visible at-spi elements
+        * 
+        * Visible root is expected to be some descendant of application's root element.
+        */
        virtual std::shared_ptr<UIElement> getVisibleRoot() = 0;
+
+       /**
+        * @brief Returns stream, which should be used for writing any kind of output
+        * 
+        * Note, that this stream should be only used from batch's thread.
+        * Stream might as well point to /dev/null.
+        * There's only single stream for all kinds of output, debug or not.
+        */
        virtual std::ostream &outputStream() = 0;
 };
 
@@ -73,7 +131,7 @@ public:
         * This variables hides variable with the same name from some parent EvaluationContext,
         * but it doesn't overwrite it.
         */
-       void setVariable(const std::string &ident, EvaluationValue val);
+       void setVariable(const std::string &ident, EvaluationValue_ val);
 
        /**
         * @brief Returns variable with name
@@ -82,16 +140,7 @@ public:
         * order until value is found. At last ExecutionInterface object will be requested to provide the value
         * by calling getVariableByName.
         */
-       EvaluationValue getVariable(const Optional<TokenLocation> &loc, const std::string &ident);
-
-       EvaluationValue callFunction(const Optional<TokenLocation> &loc, EvaluationValue function, std::vector<EvaluationValue> values);
-       EvaluationValue getAttribute(const Optional<TokenLocation> &loc, EvaluationValue self, const std::string &identifier);
-       EvaluationValue setAttribute(const Optional<TokenLocation> &loc, EvaluationValue self, const std::string &identifier, EvaluationValue value);
-       EvaluationValue convert(const Optional<TokenLocation> &loc, const EvaluationValue &value, detail::Kind targetType);
-       EvaluationValue evaluateAccessGet(const Optional<TokenLocation> &loc, const std::vector<EvaluationValue> &args);
-       EvaluationValue evaluateAccessSet(const Optional<TokenLocation> &loc, std::vector<EvaluationValue> args);
-       bool evaluateIn(const Optional<TokenLocation> &loc, const EvaluationValue &self, const EvaluationValue &value);
-       EvaluationValue evaluateMinus(const Optional<TokenLocation> &loc, const EvaluationValue &self);
+       EvaluationValue_ getVariable(const Optional<TokenLocation> &loc, const std::string &ident);
 
        /**
         * @brief Returns reference to ExecutionInterface object
@@ -113,10 +162,8 @@ public:
        static EvaluationContext &getCurrentEvaluationContext();
 private:
        void initializeGlobalContext(ExecutorInterface &ei);
-       int getSingleIndex(const std::vector<EvaluationValue> &args, int size, std::string typeName);
-       std::pair<int, int> getDoubleIndexes(const std::vector<EvaluationValue> &args, int size);
 
-       std::unordered_map<std::string, EvaluationValue> variables;
+       std::unordered_map<std::string, EvaluationValue_> variables;
        EvaluationContext *parent = nullptr;
        std::shared_ptr<GlobalContext> globalContext;
 };
index 65bd87c..d873085 100644 (file)
  */
 
 #include "EvaluationValue.hpp"
+#include "EvaluationValueBase.hpp"
 #include "EvaluationContext.hpp"
 #include "../UniversalSwitch.hpp"
 #include <cmath>
 
-EvaluationFailure::EvaluationFailure(Optional<TokenLocation> loc) : location_(std::move(loc))
+EvaluationValue_::EvaluationValue_() : value(EvaluationValueBase::create())
 {
 }
 
-void EvaluationFailure::setLocationIfMissing(TokenLocation loc)
+EvaluationValue_::EvaluationValue_(std::nullptr_t) : value(EvaluationValueBase::create())
 {
-       if (!location_) location_ = std::move(loc);
 }
 
-std::string EvaluationFailure::message() const
+EvaluationValue_::EvaluationValue_(EvaluationValuePtr v) : value(std::move(v))
 {
-       return text->str();
 }
 
-bool EvaluationFailure::hasLocation() const
+void EvaluationValue_::convertTo(int &v) const
 {
-       return bool(location_);
+       EvaluationValueInteger tmp = {};
+       convertTo(tmp);
+       v = static_cast<std::remove_reference<decltype(v)>::type>(tmp);
 }
-
-TokenLocation EvaluationFailure::location()
+void EvaluationValue_::convertTo(unsigned int &v) const
 {
-       ASSERT(hasLocation());
-       return *location_;
+       EvaluationValueInteger tmp = {};
+       convertTo(tmp);
+       v = static_cast<std::remove_reference<decltype(v)>::type>(tmp);
 }
-
-EvaluationValue detail::FunctionType::operator()(std::vector<EvaluationValue> args) const
+void EvaluationValue_::convertTo(short &v) const
 {
-       return function(std::move(args));
+       EvaluationValueInteger tmp = {};
+       convertTo(tmp);
+       v = static_cast<std::remove_reference<decltype(v)>::type>(tmp);
 }
-
-std::string EvaluationValue::toString(detail::Kind k)
-{
-       switch (k) {
-       case detail::Kind::EMPTY:
-               return "EMPTY";
-       case detail::Kind::STRING:
-               return "STRING";
-       case detail::Kind::INTEGER:
-               return "INTEGER";
-       case detail::Kind::DOUBLE:
-               return "DOUBLE";
-       case detail::Kind::UIELEMENT:
-               return "UIELEMENT";
-       case detail::Kind::BOOLEAN:
-               return "BOOLEAN";
-       case detail::Kind::POINT:
-               return "POINT";
-       case detail::Kind::FUNCTION:
-               return "FUNCTION";
-       case detail::Kind::VECTOR:
-               return "VECTOR";
-       case detail::Kind::SET:
-               return "SET";
-       case detail::Kind::DICT:
-               return "DICT";
-       }
-       return "";
+void EvaluationValue_::convertTo(unsigned short &v) const
+{
+       EvaluationValueInteger tmp = {};
+       convertTo(tmp);
+       v = static_cast<std::remove_reference<decltype(v)>::type>(tmp);
+}
+void EvaluationValue_::convertTo(signed char &v) const
+{
+       EvaluationValueInteger tmp = {};
+       convertTo(tmp);
+       v = static_cast<std::remove_reference<decltype(v)>::type>(tmp);
+}
+void EvaluationValue_::convertTo(unsigned char &v) const
+{
+       EvaluationValueInteger tmp = {};
+       convertTo(tmp);
+       v = static_cast<std::remove_reference<decltype(v)>::type>(tmp);
 }
 
-detail::Data::Data(int t) : integer(t) { }
-detail::Data::Data(double t) : double_(t) { }
-detail::Data::Data(bool t) : boolean(t) { }
-detail::Data::Data(std::string t) : string(std::move(t)) { }
-detail::Data::Data(std::shared_ptr<UIElement> t) : uiElement(std::move(t)) { }
-detail::Data::Data(Point t) : point(t) { }
-detail::Data::Data(FunctionType t) : function(std::move(t)) { }
-detail::Data::Data(VectorType t) : vector(std::make_shared<VectorType>(std::move(t))) { }
-detail::Data::Data(SetType t) : set(std::make_shared<SetType>(std::move(t))) { }
-detail::Data::Data(DictType t) : dict(std::make_shared<DictType>(std::move(t))) { }
+#define Q(type) \
+       EvaluationValue_::EvaluationValue_(EvaluationValue ## type v) : value(EvaluationValueBase::create(std::move(v))) { } \
+       EvaluationValue ## type EvaluationValue_::convertTo ## type() const { \
+               EvaluationValue ## type tmp; \
+               convertTo(tmp); \
+               return std::move(tmp); \
+       } \
+       const EvaluationValue ## type &EvaluationValue_::as ## type() { return value->as ## type(); } \
+       bool EvaluationValue_::is ## type() const { return value->is ## type(); } \
+       void EvaluationValue_::convertTo(EvaluationValue ## type &r) const { \
+               auto t = value->convertTo ## type(); \
+               if (t.get() == value.get()) r = value->as ## type(); \
+               else r = std::move(t->as ## type()); \
+       }
 
+Q(String)
+Q(Integer)
+Q(Double)
+Q(UIElement)
+Q(Boolean)
+Q(Point)
+Q(Function)
+Q(Vector)
+Q(Set)
+Q(Dict)
+#undef Q
 
-size_t EvaluationValueKey::calculateHash(const EvaluationValue &self)
-{
-       switch (self.kind()) {
-       case detail::Kind::STRING:
-               return std::hash<std::string>()(self.as<std::string>());
-       case detail::Kind::INTEGER:
-               return std::hash<int>()(self.as<int>());
-       case detail::Kind::DOUBLE:
-               return std::hash<double>()(self.as<double>());
-       case detail::Kind::UIELEMENT:
-               return std::hash<std::string>()(Atspi::getUniqueId(self.as<std::shared_ptr<UIElement>>()->getObject()));
-       case detail::Kind::BOOLEAN:
-               return std::hash<bool>()(self.as<bool>());
-       case detail::Kind::POINT:
-               return (std::hash<size_t>()(self.as<Point>().x) << 16) ^ std::hash<size_t>()(self.as<Point>().y);
-       case detail::Kind::EMPTY:
-               return 0;
-       case detail::Kind::FUNCTION:
-       case detail::Kind::SET:
-       case detail::Kind::VECTOR:
-       case detail::Kind::DICT:
-               break;
-       }
-       throw EvaluationFailure{} << "can't calculate hash for value of type " << EvaluationValue::toString(self.kind());
+std::string EvaluationValue_::typeName() const
+{
+       return value->typeName();
 }
 
-EvaluationValueKey::EvaluationValueKey(EvaluationValue val) :
-       value(std::make_shared<EvaluationValue>(std::move(val)))
+bool EvaluationValue_::operator == (const EvaluationValue_ &other) const
 {
-       hash = calculateHash(getValue());
+       return value->oper_cmp(EvaluationValueBase::Cmp::Equal, other.value);
 }
-
-EvaluationValueKey::EvaluationValueKey(EvaluationValue val, size_t hash) :
-       value(std::make_shared<EvaluationValue>(std::move(val))), hash(hash)
-{}
-
-bool EvaluationValueKey::operator == (const EvaluationValueKey &k) const
+bool EvaluationValue_::operator != (const EvaluationValue_ &other) const
 {
-       return getValue() == k.getValue();
+       return value->oper_cmp(EvaluationValueBase::Cmp::NotEqual, other.value);
 }
-
-std::ostream &operator << (std::ostream &s, const EvaluationValue &v)
-{
-       switch (v.kind()) {
-       case detail::Kind::EMPTY:
-               s << "{}";
-               break;
-       case detail::Kind::STRING:
-               s << "'" << v.data.string << "'";
-               break;
-       case detail::Kind::INTEGER:
-               s << v.data.integer;
-               break;
-       case detail::Kind::DOUBLE:
-               s << v.data.double_;
-               break;
-       case detail::Kind::UIELEMENT:
-               s << Atspi::getUniqueId(v.data.uiElement->getObject());
-               break;
-       case detail::Kind::BOOLEAN:
-               s << (v.data.boolean ? "true" : "false");
-               break;
-       case detail::Kind::POINT:
-               s << "<" << v.data.point.x << ", " << v.data.point.y << ">";
-               break;
-       case detail::Kind::FUNCTION:
-               s << "functor";
-               break;
-       case detail::Kind::VECTOR: {
-               s << "[";
-               bool first = true;
-               for (auto &a : *v.data.vector) {
-                       if (first) {
-                               s << " ";
-                               first = false;
-                       } else {
-                               s << ", ";
-                       }
-                       s << a;
-               }
-               s << " ]";
-               break;
-       }
-       case detail::Kind::SET: {
-               s << "{";
-               bool first = true;
-               for (auto &a : *v.data.set) {
-                       if (first) {
-                               s << " ";
-                               first = false;
-                       } else {
-                               s << ", ";
-                       }
-                       s << a;
-               }
-               s << " }";
-               break;
-       }
-       case detail::Kind::DICT: {
-               s << "{";
-               bool first = true;
-               for (auto &a : *v.data.dict) {
-                       if (first) {
-                               s << " ";
-                               first = false;
-                       } else {
-                               s << ", ";
-                       }
-                       s << "{ " << a.first << ": " << a.second << " }";
-               }
-               s << " }";
-               break;
-       }
-       }
-       return s;
+bool EvaluationValue_::operator < (const EvaluationValue_ &other) const
+{
+       return value->oper_order(EvaluationValueBase::Order::Less, other.value);
+}
+bool EvaluationValue_::operator > (const EvaluationValue_ &other) const
+{
+       return value->oper_order(EvaluationValueBase::Order::More, other.value);
+}
+bool EvaluationValue_::operator <= (const EvaluationValue_ &other) const
+{
+       return value->oper_order(EvaluationValueBase::Order::LessThan, other.value);
+}
+bool EvaluationValue_::operator >= (const EvaluationValue_ &other) const
+{
+       return value->oper_order(EvaluationValueBase::Order::MoreThan, other.value);
 }
 
-std::ostream &operator << (std::ostream &s, const EvaluationValueKey &v)
+size_t EvaluationValue_::hash() const
 {
-       return s << v.getValue();
+       return value->oper_hash();
+}
+bool EvaluationValue_::contains(const EvaluationValue_ &val) const
+{
+       return value->oper_contains(val.value);
 }
 
-detail::Kind EvaluationValue::kind() const
+EvaluationValue_::operator bool() const
 {
-       return kind_;
+       return value->oper_is_true();
 }
 
-bool EvaluationValue::operator == (const EvaluationValue &other) const
-{
-       if (kind() != other.kind()) {
-               if (kind() == detail::Kind::INTEGER && other.kind() == detail::Kind::DOUBLE)
-                       return static_cast<double>(as<int>()) == other.as<double>();
-               if (kind() == detail::Kind::DOUBLE && other.kind() == detail::Kind::INTEGER)
-                       return static_cast<double>(other.as<int>()) == as<double>();
-               return false;
-       }
-       switch (kind()) {
-       case detail::Kind::EMPTY:
-               return true;
-       case detail::Kind::STRING:
-               return as<std::string>() == other.as<std::string>();
-       case detail::Kind::INTEGER:
-               return as<int>() == other.as<int>();
-       case detail::Kind::DOUBLE:
-               return as<int>() == other.as<int>();
-       case detail::Kind::UIELEMENT:
-               return Atspi::getUniqueId(as<std::shared_ptr<UIElement>>()->getObject()) ==
-                          Atspi::getUniqueId(other.as<std::shared_ptr<UIElement>>()->getObject());
-       case detail::Kind::BOOLEAN:
-               return as<bool>() == other.as<bool>();
-       case detail::Kind::POINT:
-               return as<Point>() == other.as<Point>();
-       case detail::Kind::VECTOR:
-               return as<detail::VectorType>() == other.as<detail::VectorType>();
-       case detail::Kind::SET:
-               return as<detail::SetType>() == other.as<detail::SetType>();
-       case detail::Kind::DICT:
-               return as<detail::DictType>() == other.as<detail::DictType>();
-       case detail::Kind::FUNCTION:
-               throw EvaluationFailure{} << "can't compare " << EvaluationValue::toString(kind()) <<
-                                                                 " with " << EvaluationValue::toString(other.kind());
-       };
-       return false;
+EvaluationValue_ EvaluationValue_::operator()(const std::vector<EvaluationValue_> &values)
+{
+       return value->oper_call(values);
+}
+EvaluationValue_ EvaluationValue_::index_get(const EvaluationValue_ &i1) const
+{
+       return value->oper_index_get(i1.value);
+}
+EvaluationValue_ EvaluationValue_::index_get(const EvaluationValue_ &i1, const EvaluationValue_ &i2) const
+{
+       return value->oper_index_get(i1.value, i2.value);
+}
+EvaluationValue_ EvaluationValue_::index_set(const EvaluationValue_ &i1, const EvaluationValue_ &val)
+{
+       return value->oper_index_set(i1.value, val.value);
+}
+EvaluationValue_ EvaluationValue_::index_set(const EvaluationValue_ &i1, const EvaluationValue_ &i2, const EvaluationValue_ &val)
+{
+       return value->oper_index_set(i1.value, i2.value, val.value);
 }
 
-bool EvaluationValue::operator < (const EvaluationValue &other) const
-{
-       if (kind() != other.kind()) {
-               if (kind() == detail::Kind::INTEGER && other.kind() == detail::Kind::DOUBLE)
-                       return static_cast<double>(as<int>()) < other.as<double>();
-               if (kind() == detail::Kind::DOUBLE && other.kind() == detail::Kind::INTEGER)
-                       return as<double>() < static_cast<double>(other.as<int>());
-       } else {
-               switch (kind()) {
-               case detail::Kind::EMPTY:
-                       break;
-               case detail::Kind::STRING:
-                       return as<std::string>() < other.as<std::string>();
-               case detail::Kind::INTEGER:
-                       return as<int>() < other.as<int>();
-               case detail::Kind::DOUBLE:
-                       return as<double>() < other.as<double>();
-               case detail::Kind::UIELEMENT:
-                       break;
-               case detail::Kind::BOOLEAN:
-                       break;
-               case detail::Kind::POINT:
-                       break;
-               case detail::Kind::FUNCTION:
-                       break;
-               case detail::Kind::VECTOR:
-                       for (auto i = 0u; i < std::min(as<detail::VectorType>().size(), other.as<detail::VectorType>().size()); ++i) {
-                               if (as<detail::VectorType>()[i] < other.as<detail::VectorType>()[i]) return true;
-                               if (!(as<detail::VectorType>()[i] == other.as<detail::VectorType>()[i])) return false;
-                       }
-                       return as<detail::VectorType>().size() < other.as<detail::VectorType>().size();
-               case detail::Kind::SET:
-                       break;
-               case detail::Kind::DICT:
-                       break;
-               };
-       }
-       throw EvaluationFailure{} << "can't order values of type " << EvaluationValue::toString(kind()) <<
-                                                         " and " << EvaluationValue::toString(other.kind());
+EvaluationValue_ EvaluationValue_::operator - () const
+{
+       return value->oper_negate();
 }
 
-EvaluationValue::operator bool () const
-{
-       switch (kind()) {
-       case detail::Kind::INTEGER:
-               return as<int>() != 0;
-       case detail::Kind::DOUBLE:
-               return as<double>() != 0;
-       case detail::Kind::BOOLEAN:
-               return as<bool>();
-       case detail::Kind::STRING:
-               return !as<std::string>().empty();
-       case detail::Kind::UIELEMENT:
-               return true;
-       case detail::Kind::FUNCTION:
-               return true;
-       case detail::Kind::POINT:
-               return true;
-       case detail::Kind::VECTOR:
-               return !as<detail::VectorType>().empty();
-       case detail::Kind::SET:
-               return !as<detail::SetType>().empty();
-       case detail::Kind::DICT:
-               return !as<detail::DictType>().empty();
-       case detail::Kind::EMPTY:
-               return false;
-       }
-       ASSERT(0); // every type has a true / false value in boolean context
-       return false;
+EvaluationValue_ EvaluationValue_::attr_get(const std::string &name) const
+{
+       return value->oper_attr_get(name);
+}
+EvaluationValue_ EvaluationValue_::attr_set(const std::string &name, const EvaluationValue_ &val)
+{
+       return value->oper_attr_set(name, val.value);
 }
 
-bool EvaluationValue::operator != (const EvaluationValue &other) const
+std::ostream &operator << (std::ostream &s, const EvaluationValue_ &v)
 {
-       return !(*this == other);
+       return s << v.value;
 }
 
-bool EvaluationValue::operator > (const EvaluationValue &other) const
+EvaluationFailure::EvaluationFailure(Optional<TokenLocation> loc) : location_(std::move(loc))
 {
-       return (other < *this);
 }
 
-bool EvaluationValue::operator <= (const EvaluationValue &other) const
+void EvaluationFailure::setLocationIfMissing(TokenLocation loc)
 {
-       return !(other < *this);
+       if (!location_) location_ = std::move(loc);
 }
 
-bool EvaluationValue::operator >= (const EvaluationValue &other) const
+std::string EvaluationFailure::message() const
 {
-       return !(*this < other);
+       return text->str();
 }
 
-namespace detail
-{
-       int ConvertTo<int>::convert(EvaluationValue e)
-       {
-               if (e.kind() == detail::Kind::INTEGER) return e.as<int>();
-               if (e.kind() == detail::Kind::DOUBLE) {
-                       if (static_cast<double>(static_cast<int>(e.as<double>())) == e.as<double>()) {
-                               return static_cast<int>(e.as<double>());
-                       }
-               } else if (e.kind() == detail::Kind::STRING) {
-                       auto text = e.as<std::string>();
-                       size_t pos = 0;
-                       auto value = std::stoi(text, &pos);
-                       if (pos == text.size())
-                               return value;
-               }
-               throw EvaluationFailure{} << "can't convert from " << EvaluationValue::toString(e.kind()) <<
-                                                                 " to " << EvaluationValue::toString(detail::Kind::INTEGER);
-       }
-       double ConvertTo<double>::convert(EvaluationValue e)
-       {
-               if (e.kind() == detail::Kind::INTEGER) return e.as<int>();
-               if (e.kind() == detail::Kind::DOUBLE) return e.as<double>();
-               if (e.kind() == detail::Kind::STRING) {
-                       auto text = e.as<std::string>();
-                       size_t pos = 0;
-                       auto value = std::stod(text, &pos);
-                       if (pos == text.size())
-                               return value;
-               }
-               throw EvaluationFailure{} << "can't convert from " << EvaluationValue::toString(e.kind()) <<
-                                                                 " to " << EvaluationValue::toString(detail::Kind::DOUBLE);
-       }
-       std::string ConvertTo<std::string>::convert(EvaluationValue e)
-       {
-               if (e.kind() == detail::Kind::INTEGER) return std::to_string(e.as<int>());
-               if (e.kind() == detail::Kind::BOOLEAN) return e.as<bool>() ? "true" : "false";
-               if (e.kind() == detail::Kind::STRING) return e.as<std::string>();
-               if (e.kind() == detail::Kind::POINT)
-                       return "<" + std::to_string(e.as<Point>().x) + ", " + std::to_string(e.as<Point>().y) + ">";
-               throw EvaluationFailure{} << "can't convert from " << EvaluationValue::toString(e.kind()) <<
-                                                                 " to " << EvaluationValue::toString(detail::Kind::STRING);
-       }
-       bool ConvertTo<bool>::convert(EvaluationValue e)
-       {
-               return bool(e);
-       }
-       std::shared_ptr<UIElement> ConvertTo<std::shared_ptr<UIElement>>::convert(EvaluationValue e)
-       {
-               if (e.kind() == detail::Kind::UIELEMENT) return std::move(e.as<std::shared_ptr<UIElement>>());
-               if (e.kind() == detail::Kind::POINT)
-                       return EvaluationContext::getCurrentEvaluationContext().executionInterface().convert(e.as<Point>());
-               if (e.kind() == detail::Kind::STRING)
-                       return EvaluationContext::getCurrentEvaluationContext().executionInterface().convert(e.as<std::string>());
-               throw EvaluationFailure{} << "can't convert from " << EvaluationValue::toString(e.kind()) <<
-                                                                 " to " << EvaluationValue::toString(detail::Kind::UIELEMENT);
-       }
-       EvaluationValue ConvertTo<EvaluationValue>::convert(EvaluationValue e)
-       {
-               return std::move(e);
-       }
-       Point ConvertTo<Point>::convert(EvaluationValue e)
-       {
-               if (e.kind() == detail::Kind::POINT) return e.as<Point>();
-               throw EvaluationFailure{} << "can't convert from " << EvaluationValue::toString(e.kind()) <<
-                                                                 " to " << EvaluationValue::toString(detail::Kind::POINT);
-       }
+bool EvaluationFailure::hasLocation() const
+{
+       return bool(location_);
+}
 
-       template <> std::string &get<std::string>(detail::Data &d)
-       {
-               return d.string;
-       }
-       template <> int &get<int>(detail::Data &d)
-       {
-               return d.integer;
-       }
-       template <> std::shared_ptr<UIElement> &get<std::shared_ptr<UIElement>>(detail::Data &d)
-       {
-               return d.uiElement;
-       }
-       template <> bool &get<bool>(detail::Data &d)
-       {
-               return d.boolean;
-       }
-       template <> double &get<double>(detail::Data &d)
-       {
-               return d.double_;
-       }
-       template <> Point &get<Point>(detail::Data &d)
-       {
-               return d.point;
-       }
-       template <> FunctionType &get<detail::FunctionType>(detail::Data &d)
-       {
-               return d.function;
-       }
-       template <> VectorType &get<detail::VectorType>(detail::Data &d)
-       {
-               return *d.vector;
-       }
-       template <> SetType &get<detail::SetType>(detail::Data &d)
-       {
-               return *d.set;
-       }
-       template <> DictType &get<detail::DictType>(detail::Data &d)
-       {
-               return *d.dict;
-       }
+TokenLocation EvaluationFailure::location()
+{
+       ASSERT(hasLocation());
+       return *location_;
+}
 
-       template <> std::string get<std::string>(const detail::Data &d)
-       {
-               return d.string;
-       }
-       template <> int get<int>(const detail::Data &d)
-       {
-               return d.integer;
-       }
-       template <> std::shared_ptr<UIElement> get<std::shared_ptr<UIElement>>(const detail::Data &d)
-       {
-               return d.uiElement;
-       }
-       template <> bool get<bool>(const detail::Data &d)
-       {
-               return d.boolean;
-       }
-       template <> double get<double>(const detail::Data &d)
-       {
-               return d.double_;
-       }
-       template <> Point get<Point>(const detail::Data &d)
-       {
-               return d.point;
-       }
-       template <> FunctionType get<detail::FunctionType>(const detail::Data &d)
-       {
-               return d.function;
-       }
-       template <> VectorType get<detail::VectorType>(const detail::Data &d)
-       {
-               return *d.vector;
-       }
-       template <> SetType get<detail::SetType>(const detail::Data &d)
-       {
-               return *d.set;
-       }
-       template <> DictType get<detail::DictType>(const detail::Data &d)
-       {
-               return *d.dict;
-       }
-};
index 07eb2fb..be03628 100644 (file)
 #include <unordered_map>
 #include <tuple>
 #include <ostream>
-
-class EvaluationContext;
-
-class EvaluationFailure;
-class EvaluationValue;
-class EvaluationValueKey
-{
-public:
-       EvaluationValueKey() = default;
-       EvaluationValueKey(EvaluationValue val);
-       EvaluationValueKey(EvaluationValue val, size_t hash);
-
-       const EvaluationValue &getValue() const
-       {
-               return *value;
-       }
-       operator const EvaluationValue &() const
-       {
-               return *value;
-       }
-
-       size_t getHash() const
-       {
-               return hash;
-       }
-
-       bool operator == (const EvaluationValueKey &k) const;
-
-       friend std::ostream &operator << (std::ostream &s, const EvaluationValue &v);
-
-       static size_t calculateHash(const EvaluationValue &v);
-private:
-       std::shared_ptr<EvaluationValue> value;
-       size_t hash = 0;
-};
-
-namespace std
-{
-       template <> struct hash<EvaluationValueKey> {
-               size_t operator()(const EvaluationValueKey &v) const
-               {
-                       return v.getHash();
-               }
-       };
-}
+#include <type_traits>
 
 class EvaluationFailure : public std::exception
 {
@@ -104,9 +60,158 @@ private:
        mutable std::string cachedText;
 };
 
+class EvaluationValue_;
+
+namespace std
+{
+       template <> struct hash<EvaluationValue_> {
+               size_t operator()(const EvaluationValue_ &) const;
+       };
+}
+
+class EvaluationContext;
+class EvaluationValueBase;
+using EvaluationValuePtr = std::shared_ptr<EvaluationValueBase>;
+using EvaluationValueEmpty = std::nullptr_t;
+using EvaluationValueString = std::string;
+using EvaluationValueInteger = int64_t;
+using EvaluationValueDouble = double;
+using EvaluationValueUIElement = std::shared_ptr<UIElement>;
+using EvaluationValueBoolean = bool;
+using EvaluationValuePoint = Point;
+class EvaluationValueFunction;
+using EvaluationValueVector = std::vector<EvaluationValue_>;
+using EvaluationValueSet = std::unordered_set<EvaluationValue_>;
+using EvaluationValueDict = std::unordered_map<EvaluationValue_, EvaluationValue_>;
+
+/**
+ * @brief Wrapper class containing batch script value 
+ * 
+ * This is a wrapper, contaiing a value from batch script. It can hold any type of supported value.
+ * Any functionality requested from object of this class will be redirected to correct implementation
+ * method in the EvaluationValueBase interface. Classes inheriting from EvaluationValueBase are classes
+ * implementing values of all supported types (see EvaluationValue***.cpp files). Those classes
+ * override virtual methods of the EvaluationValueBase interface to add required functionality.
+ * 
+ * EvaluationValue_ supports implicit cast from C++ types, which can be used in batch script (for example
+ * chars shorts and ints can be converted to EvaluationValueInteger, std::string can be converted to 
+ * EvaluationValueString and so on).
+ */
+class EvaluationValue_
+{
+public:
+       EvaluationValue_();
+       EvaluationValue_(const EvaluationValue_ &) = default;
+       EvaluationValue_(EvaluationValue_ &&) = default;
+       EvaluationValue_(std::nullptr_t);
+       EvaluationValue_(EvaluationValuePtr v);
+       EvaluationValue_(unsigned char v) : EvaluationValue_(static_cast<EvaluationValueInteger>(v)) { }
+       EvaluationValue_(signed char v) : EvaluationValue_(static_cast<EvaluationValueInteger>(v)) { }
+       EvaluationValue_(unsigned short v) : EvaluationValue_(static_cast<EvaluationValueInteger>(v)) { }
+       EvaluationValue_(short v) : EvaluationValue_(static_cast<EvaluationValueInteger>(v)) { }
+       EvaluationValue_(unsigned int v) : EvaluationValue_(static_cast<EvaluationValueInteger>(v)) { }
+       EvaluationValue_(int v) : EvaluationValue_(static_cast<EvaluationValueInteger>(v)) { }
+       template <typename T> EvaluationValue_(std::vector<T> tmp) : EvaluationValue_(fromVector(std::move(tmp))) { }
+       template <typename T> EvaluationValue_(std::unordered_set<T> tmp) : EvaluationValue_(fromSet(std::move(tmp))) { }
+       template <typename K, typename EvaluationValuePtr> EvaluationValue_(std::unordered_map<K, EvaluationValuePtr> tmp) : EvaluationValue_(fromMap(std::move(tmp))) { }
+
+       EvaluationValue_ &operator = (const EvaluationValue_ &) = default;
+       EvaluationValue_ &operator = (EvaluationValue_ &&) = default;
+       template <typename T> EvaluationValue_ &operator = (T &&t)
+       {
+               *this = EvaluationValue_{ std::forward<T>(t) };
+               return *this;
+       }
+
+       void convertTo(EvaluationValue_ &o) const
+       {
+               o = *this;
+       }
+       void convertTo(int &v) const;
+       void convertTo(unsigned int &v) const;
+       void convertTo(short &v) const;
+       void convertTo(unsigned short &v) const;
+       void convertTo(signed char &v) const;
+       void convertTo(unsigned char &v) const;
+       template <typename T> void convertTo(std::vector<T> &v) const {
+               
+       }
+#define Q(type) \
+       EvaluationValue_(EvaluationValue ## type); \
+       EvaluationValue ## type convertTo ## type() const; \
+       void convertTo(EvaluationValue ## type &) const; \
+       const EvaluationValue ## type &as ## type(); \
+       bool is ## type() const;
+
+       Q(String)
+       Q(Integer)
+       Q(Double)
+       Q(UIElement)
+       Q(Boolean)
+       Q(Point)
+       Q(Function)
+       Q(Vector)
+       Q(Set)
+       Q(Dict)
+#undef Q
+
+       std::string typeName() const;
+       bool operator == (const EvaluationValue_ &) const;
+       bool operator != (const EvaluationValue_ &) const;
+       bool operator < (const EvaluationValue_ &) const;
+       bool operator > (const EvaluationValue_ &) const;
+       bool operator <= (const EvaluationValue_ &) const;
+       bool operator >= (const EvaluationValue_ &) const;
+
+       size_t hash() const;
+       bool contains(const EvaluationValue_ &) const;
+       explicit operator bool() const;
+
+       EvaluationValue_ operator()(const std::vector<EvaluationValue_> &values);
+       EvaluationValue_ index_get(const EvaluationValue_ &) const;
+       EvaluationValue_ index_get(const EvaluationValue_ &, const EvaluationValue_ &) const;
+       EvaluationValue_ index_set(const EvaluationValue_ &, const EvaluationValue_ &value);
+       EvaluationValue_ index_set(const EvaluationValue_ &, const EvaluationValue_ &, const EvaluationValue_ &value);
+
+       EvaluationValue_ operator - () const;
+
+       EvaluationValue_ attr_get(const std::string &name) const;
+       EvaluationValue_ attr_set(const std::string &name, const EvaluationValue_ &value);
+
+       auto getInternalValue() const
+       {
+               return value;
+       }
+
+       friend std::ostream &operator << (std::ostream &s, const EvaluationValue_ &v);
+private:
+       EvaluationValuePtr value;
+
+       template <typename T> static EvaluationValueVector fromVector(std::vector<T> tmp) {
+               EvaluationValueVector res;
+               res.reserve(tmp.size());
+               for(auto &t : tmp)
+                       res.push_back(std::move(t));
+               return res;
+       }
+       template <typename T> static EvaluationValueSet fromSet(std::unordered_set<T> tmp) {
+               EvaluationValueSet res;
+               res.reserve(tmp.size());
+               for(auto &t : tmp)
+                       res.insert(std::move(t));
+               return res;
+       }
+       template <typename K, typename EvaluationValuePtr> static EvaluationValueDict fromMap(std::unordered_map<K, EvaluationValuePtr> tmp) {
+               EvaluationValueDict res;
+               res.reserve(tmp.size());
+               for(auto &t : tmp)
+                       res.insert({ t.first, std::move(t.second) });
+               return res;
+       }
+};
+
 namespace detail
 {
-       // TODO: check licence
        template<int ...> struct sequence {};
        template<int N, int ...S> struct sequence_gen : sequence_gen < N - 1, N - 1, S... > {};
        template<int ...S> struct sequence_gen<0, S...> {
@@ -130,43 +235,11 @@ namespace detail
                apply_helper<C, ARGS...> ah { c, args };
                return ah.apply_1();
        }
-       template <typename T> struct ConvertTo;
-       template <> struct ConvertTo<int> {
-               static int convert(EvaluationValue e);
-       };
-       template <> struct ConvertTo<double> {
-               static double convert(EvaluationValue e);
-       };
-       template <> struct ConvertTo<std::string> {
-               static std::string convert(EvaluationValue e);
-       };
-       template <> struct ConvertTo<bool> {
-               static bool convert(EvaluationValue e);
-       };
-       template <> struct ConvertTo<std::shared_ptr<UIElement>> {
-               static std::shared_ptr<UIElement> convert(EvaluationValue e);
-       };
-       template <> struct ConvertTo<EvaluationValue> {
-               static EvaluationValue convert(EvaluationValue e);
-       };
-       template <> struct ConvertTo<Point> {
-               static Point convert(EvaluationValue e);
-       };
-       template <typename T> struct ConvertTo<std::vector<T>> {
-               static std::vector<T> convert(EvaluationValue e);
-       };
-       template <typename T> struct ConvertTo<std::unordered_set<T>> {
-               static std::unordered_set<T> convert(EvaluationValue e);
-       };
-       template <typename K, typename V> struct ConvertTo<std::unordered_map<K, V>> {
-               static std::unordered_map<K, V> convert(EvaluationValue e);
-       };
        template <size_t I, size_t S> struct Converter {
-               template <typename ... ARGS> static void convert(std::tuple<ARGS...> &dst, std::vector<EvaluationValue> &sourceArgs)
+               template <typename ... ARGS> static void convert(std::tuple<ARGS...> &dst, const std::vector<EvaluationValue_> &sourceArgs)
                {
-                       using T = typename std::tuple_element<I, std::tuple<ARGS...>>::type;
                        try {
-                               std::get<I>(dst) = ConvertTo<typename std::decay<T>::type>::convert(std::move(sourceArgs[I]));
+                               sourceArgs[I].convertTo(std::get<I>(dst));
                        } catch (EvaluationFailure &e) {
                                e << ", when converting " << (I + 1) << " argument";
                                throw;
@@ -175,283 +248,119 @@ namespace detail
                }
        };
        template <size_t S> struct Converter<S, S> {
-               template <typename ... ARGS> static void convert(std::tuple<ARGS...> &, std::vector<EvaluationValue> &)
+               template <typename ... ARGS> static void convert(std::tuple<ARGS...> &, const std::vector<EvaluationValue_> &)
                {
                }
        };
-       class FunctionType
-       {
-       public:
-               using Type = std::function<EvaluationValue(std::vector<EvaluationValue>)>;
 
-               FunctionType() = default;
-               FunctionType(Type t) : function(std::move(t)) { }
-
-               explicit operator bool () const
-               {
-                       return bool(function);
-               }
-
-               template <typename ... ARGS> auto operator()(ARGS &&... args) const
-               {
-                       std::vector<EvaluationValue> tmp;
-                       pack(tmp, std::forward<ARGS>(args)...);
-                       return function(std::move(tmp));
-               }
-               EvaluationValue operator()(std::vector<EvaluationValue> args) const;
-       private:
-               Type function;
-
-               template <typename T, typename ... ARGS> static void pack(std::vector<EvaluationValue> &tmp, T &&t, ARGS &&... args)
-               {
-                       tmp.push_back(std::forward<T>(t));
-                       pack(tmp, std::forward<ARGS>(args)...);
-               }
-               static void pack(std::vector<EvaluationValue> &tmp)
-               {
-               }
-       };
-       template <typename ... ARGS> class UserFunctionType : public FunctionType
+       template <typename T, typename A = void, typename ... ARGS> struct is_one_of_types {
+               enum { value = std::is_same<T, A>::value || is_one_of_types<T, ARGS...>::value };
+       };
+       template <typename T> struct is_one_of_types<T> {
+               enum { value = 0 };
+       };
+
+       template <typename T> struct is_allowed_evaluatation_value_type { enum { value = 0 }; };
+       template <typename T> struct is_allowed_evaluatation_value_type<T&> { enum { value = is_allowed_evaluatation_value_type<T>::value }; };
+       template <typename T> struct is_allowed_evaluatation_value_type<const T&> { enum { value = is_allowed_evaluatation_value_type<T>::value }; };
+       template <typename T> struct is_allowed_evaluatation_value_type<const T> { enum { value = is_allowed_evaluatation_value_type<T>::value }; };
+       template <> struct is_allowed_evaluatation_value_type<int> { enum { value = 1 }; };
+       template <> struct is_allowed_evaluatation_value_type<unsigned int> { enum { value = 1 }; };
+       template <> struct is_allowed_evaluatation_value_type<short> { enum { value = 1 }; };
+       template <> struct is_allowed_evaluatation_value_type<unsigned short> { enum { value = 1 }; };
+       template <> struct is_allowed_evaluatation_value_type<signed char> { enum { value = 1 }; };
+       template <> struct is_allowed_evaluatation_value_type<unsigned char> { enum { value = 1 }; };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValue_> { enum { value = 1 }; };        
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueEmpty> { enum { value = 1 }; };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueString> { enum { value = 1 }; };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueInteger> { enum { value = 1 }; };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueDouble> { enum { value = 1 }; };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueUIElement> { enum { value = 1 }; };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueBoolean> { enum { value = 1 }; };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValuePoint> { enum { value = 1 }; };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueFunction> { enum { value = 1 }; };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueVector> { enum { value = 1 }; };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueSet> { enum { value = 1 }; };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueDict> { enum { value = 1 }; };
+       template <typename T> struct is_allowed_evaluatation_value_type<std::vector<T>> {
+               enum { value = is_allowed_evaluatation_value_type<T>::value };
+       };
+       template <typename T> struct is_allowed_evaluatation_value_type<std::unordered_set<T>> {
+               enum { value = is_allowed_evaluatation_value_type<T>::value };
+       };
+       template <typename K, typename EvaluationValuePtr> struct is_allowed_evaluatation_value_type<std::unordered_map<K, EvaluationValuePtr>> {
+               enum { value = is_allowed_evaluatation_value_type<K>::value && is_allowed_evaluatation_value_type<EvaluationValuePtr>::value };
+       };
+       template <typename T = void, typename ... ARGS> struct are_args_allowed_evaluation_value {
+               enum { value = is_allowed_evaluatation_value_type<T>::value && are_args_allowed_evaluation_value<ARGS...>::value };
+       };
+       template <> struct are_args_allowed_evaluation_value<> {
+               enum { value = 1 };
+       };
+       template <typename T> struct are_args_allowed_evaluation_value_from_tuple;
+       template <typename ... ARGS> struct are_args_allowed_evaluation_value_from_tuple<std::tuple<ARGS...>> {
+               enum { value = are_args_allowed_evaluation_value<ARGS...>::value };
+       };
+       namespace get_type_from_lambda_impl
        {
-       public:
-               UserFunctionType(std::function<EvaluationValue(ARGS...)> f) :
-                       FunctionType(constructConvertingArgsFunction(std::move(f))) { }
-       private:
-               static Type constructConvertingArgsFunction(std::function<EvaluationValue(ARGS...)> f);
-       };
-
-       using VectorType = std::vector<EvaluationValue>;
-       using SetType = std::unordered_set<EvaluationValueKey>;
-       using DictType = std::unordered_map<EvaluationValueKey, EvaluationValue>;
-
-       enum class Kind : unsigned char {
-               EMPTY = 0,
-               STRING, INTEGER, DOUBLE, UIELEMENT, BOOLEAN, POINT, FUNCTION, VECTOR, SET, DICT
-       };
-
-       template <typename T> struct TypeToKind;
-       template <> struct TypeToKind<std::string> {
-               static constexpr auto kind = Kind::STRING;
-       };
-       template <> struct TypeToKind<int> {
-               static constexpr auto kind = Kind::INTEGER;
-       };
-       template <> struct TypeToKind<double> {
-               static constexpr auto kind = Kind::DOUBLE;
-       };
-       template <> struct TypeToKind<std::shared_ptr<UIElement>> {
-               static constexpr auto kind = Kind::UIELEMENT;
-       };
-       template <> struct TypeToKind<bool> {
-               static constexpr auto kind = Kind::BOOLEAN;
-       };
-       template <> struct TypeToKind<Point> {
-               static constexpr auto kind = Kind::STRING;
-       };
-       template <> struct TypeToKind<FunctionType> {
-               static constexpr auto kind = Kind::FUNCTION;
-       };
-       template <> struct TypeToKind<VectorType> {
-               static constexpr auto kind = Kind::VECTOR;
-       };
-       template <> struct TypeToKind<SetType> {
-               static constexpr auto kind = Kind::SET;
-       };
-       template <> struct TypeToKind<DictType> {
-               static constexpr auto kind = Kind::DICT;
-       };
-       template <typename ... ARGS> struct TypeToKind<UserFunctionType<ARGS...>> {
-               static constexpr auto kind = Kind::FUNCTION;
-       };
-       template <typename R, typename ... ARGS> struct TypeToKind<std::function<R(ARGS...)>> {
-               static constexpr auto kind = Kind::FUNCTION;
-       };
-       template <typename T> struct TypeToKind<std::vector<T>> {
-               static constexpr auto kind = Kind::VECTOR;
-       };
-       template <typename T> struct TypeToKind<std::unordered_set<T>> {
-               static constexpr auto kind = Kind::SET;
-       };
-       template <typename K, typename V> struct TypeToKind<std::unordered_map<K, V>> {
-               static constexpr auto kind = Kind::DICT;
-       };
-       // TODO: turn it into c++17 std::variant, when we upgrade to c++17
-       // although current version ain't optimal, it's not big of a deal
-       // as it's only used for testing and any DBUS call will be
-       // order of magnitude slower
-       struct Data {
-               std::string string;
-               int integer = 0;
-               std::shared_ptr<UIElement> uiElement;
-               bool boolean = false;
-               double double_ = 0;
-               Point point;
-               FunctionType function;
-               std::shared_ptr<VectorType> vector;
-               std::shared_ptr<SetType> set;
-               std::shared_ptr<DictType> dict;
-
-               Data() = default;
-               Data(int integer);
-               Data(bool boolean);
-               Data(std::string);
-               Data(double);
-               Data(std::shared_ptr<UIElement>);
-               Data(Point);
-               Data(FunctionType);
-               Data(SetType);
-               Data(DictType);
-               Data(VectorType);
-               template <typename T> Data(std::vector<T> t) : Data(VectorType{ t.begin(), t.end() }) { }
-               template <typename T> Data(std::unordered_set<T> t) : Data(SetType{ t.begin(), t.end() }) { }
-               template <typename K, typename V> Data(std::unordered_map<K, V> t) : Data(DictType{ t.begin(), t.end() }) { }
+               template<typename T> struct make_tuple_from_args { };
+               template<typename C, typename ... ARGS>
+               struct make_tuple_from_args<EvaluationValue_(C::*)(ARGS...)> {
+                       using type = std::tuple<ARGS...>;
+               };
+               template<typename C, typename ... ARGS>
+               struct make_tuple_from_args<EvaluationValue_(C::*)(ARGS...) const> {
+                       using type = std::tuple<ARGS...>;
+               };
+       }
+       template <typename T, typename OPER = decltype(&std::remove_reference<T>::type::operator())> struct get_args_as_tuple_from_lambda {
+               using type = typename get_type_from_lambda_impl::make_tuple_from_args<OPER>::type;
        };
-
-       template <typename T> T &get(detail::Data &d) = delete;
-       template <> std::string &get<std::string>(detail::Data &d);
-       template <> int &get<int>(detail::Data &d);
-       template <> std::shared_ptr<UIElement> &get<std::shared_ptr<UIElement>>(detail::Data &d);
-       template <> bool &get<bool>(detail::Data &d);
-       template <> double &get<double>(detail::Data &d);
-       template <> Point &get<Point>(detail::Data &d);
-       template <> FunctionType &get<detail::FunctionType>(detail::Data &d);
-       template <> VectorType &get<detail::VectorType>(detail::Data &d);
-       template <> SetType &get<detail::SetType>(detail::Data &d);
-       template <> DictType &get<detail::DictType>(detail::Data &d);
-
-       template <typename T> T get(const detail::Data &d) = delete;
-       template <> std::string get<std::string>(const detail::Data &d);
-       template <> int get<int>(const detail::Data &d);
-       template <> std::shared_ptr<UIElement> get<std::shared_ptr<UIElement>>(const detail::Data &d);
-       template <> bool get<bool>(const detail::Data &d);
-       template <> double get<double>(const detail::Data &d);
-       template <> Point get<Point>(const detail::Data &d);
-       template <> FunctionType get<detail::FunctionType>(const detail::Data &d);
-       template <> VectorType get<detail::VectorType>(const detail::Data &d);
-       template <> SetType get<detail::SetType>(const detail::Data &d);
-       template <> DictType get<detail::DictType>(const detail::Data &d);
 }
 
-class EvaluationValue
+class EvaluationValueFunction
 {
 public:
-       static std::string toString(detail::Kind k);
-
-       EvaluationValue() = default;
-       EvaluationValue(std::nullptr_t) {}
-       template <typename T, typename = typename std::enable_if<std::is_constructible<detail::Data, T>::value, void *>::type>
-       EvaluationValue(T && t) : data(std::move(t)), kind_(detail::TypeToKind<typename std::decay<T>::type>::kind) { }
-       EvaluationValue(const EvaluationValue &) = default;
-       EvaluationValue(EvaluationValue &&) = default;
-       ~EvaluationValue() = default;
+       using Type = std::function<EvaluationValue_(const std::vector<EvaluationValue_>&)>;
 
-       EvaluationValue &operator = (const EvaluationValue &) = default;
-       EvaluationValue &operator = (EvaluationValue &&) = default;
+       EvaluationValueFunction() = default;
+       template <typename T, typename ARGS_TUPLE = typename detail::get_args_as_tuple_from_lambda<T>::type,
+               typename = typename std::enable_if<detail::are_args_allowed_evaluation_value_from_tuple<ARGS_TUPLE>::value>::type> 
+       EvaluationValueFunction(T && f) : function(constructConvertingArgsFunction<ARGS_TUPLE>(std::move(f))) { }
+       EvaluationValueFunction(std::function<EvaluationValue_(const std::vector<EvaluationValue_> &)> f) : function(std::move(f)) {}
 
-       detail::Kind kind() const;
-       template <typename T> auto &as()
+       explicit operator bool () const
        {
-               ASSERT(kind() == detail::TypeToKind<typename std::decay<T>::type>::kind);
-               return detail::get<T>(data);
+               return bool(function);
        }
-       template <typename T> auto as() const
-       {
-               ASSERT(kind() == detail::TypeToKind<typename std::decay<T>::type>::kind);
-               return detail::get<T>(data);
-       }
-
-       bool operator == (const EvaluationValue &other) const;
-       bool operator < (const EvaluationValue &other) const;
-       bool operator != (const EvaluationValue &other) const;
-       bool operator > (const EvaluationValue &other) const;
-       bool operator <= (const EvaluationValue &other) const;
-       bool operator >= (const EvaluationValue &other) const;
-
-       explicit operator bool () const;
 
-       friend std::ostream &operator << (std::ostream &s, const EvaluationValue &v);
-private:
-       detail::Data data;
-       detail::Kind kind_ = detail::Kind::EMPTY;
-};
-
-namespace detail
-{
-       template <typename T> std::vector<T> ConvertTo<std::vector<T>>::convert(EvaluationValue e)
+       EvaluationValue_ operator () (const std::vector<EvaluationValue_> &args) const
        {
-               std::vector<T> result;
-
-               if (e.kind() == detail::Kind::VECTOR) {
-                       result.reserve(e.as<VectorType>().size());
-                       for (auto &e : e.as<VectorType>()) {
-                               result.push_back(ConvertTo<T>::convert(e));
-                       }
-               } else if (e.kind() == detail::Kind::SET) {
-                       result.reserve(e.as<SetType>().size());
-                       for (auto &e : e.as<SetType>()) {
-                               result.push_back(ConvertTo<T>::convert(e));
-                       }
-               } else if (e.kind() == detail::Kind::DICT) {
-                       result.reserve(e.as<DictType>().size());
-                       for (auto &e : e.as<DictType>()) {
-                               result.push_back(ConvertTo<T>::convert(e.first));
-                       }
-               } else throw EvaluationFailure{} << "can't convert from " << EvaluationValue::toString(e.kind()) <<
-                                                                                        " to " << EvaluationValue::toString(detail::Kind::VECTOR);
-               return std::move(result);
+               return function(args);
        }
-       template <typename T> std::unordered_set<T> ConvertTo<std::unordered_set<T>>::convert(EvaluationValue e)
-       {
-               std::unordered_set<T> result;
+protected:     
+       Type function;
 
-               if (e.kind() == detail::Kind::VECTOR) {
-                       result.reserve(e.as<VectorType>().size());
-                       for (auto &e : e.as<VectorType>()) {
-                               result.insert(ConvertTo<T>::convert(e));
-                       }
-               } else if (e.kind() == detail::Kind::SET) {
-                       result.reserve(e.as<SetType>().size());
-                       for (auto &e : e.as<SetType>()) {
-                               result.insert(ConvertTo<T>::convert(e));
-                       }
-               } else if (e.kind() == detail::Kind::DICT) {
-                       result.reserve(e.as<DictType>().size());
-                       for (auto &e : e.as<DictType>()) {
-                               result.insert(ConvertTo<T>::convert(e.first));
-                       }
-               } else throw EvaluationFailure{} << "can't convert from " << EvaluationValue::toString(e.kind()) <<
-                                                                                        " to " << EvaluationValue::toString(detail::Kind::VECTOR);
-               return std::move(result);
-       }
-       template <typename K, typename V> std::unordered_map<K, V> ConvertTo<std::unordered_map<K, V>>::convert(EvaluationValue e)
+       static void validateArgumentCount(size_t expected, size_t got)
        {
-               std::unordered_map<K, V> result;
-
-               if (e.kind() == detail::Kind::DICT) {
-                       result.reserve(e.as<DictType>().size());
-                       for (auto &e : e.as<DictType>()) {
-                               auto k = ConvertTo<K>::convert(e.first);
-                               auto v = ConvertTo<V>::convert(e.second);
-                               result.insert({ k, v });
-                       }
-               } else throw EvaluationFailure{} << "can't convert from " << EvaluationValue::toString(e.kind()) <<
-                                                                                        " to " << EvaluationValue::toString(detail::Kind::VECTOR);
-               return std::move(result);
+               if (got < expected)
+                       throw EvaluationFailure{} << "not enough arguments, expected " << expected << ", got " << got;
+               if (got > expected)
+                       throw EvaluationFailure{} << "too many arguments, expected " << expected << ", got " << got;
        }
-       template <typename ... ARGS>
-       auto UserFunctionType<ARGS...>::constructConvertingArgsFunction(std::function<EvaluationValue(ARGS...)> f) -> Type
+private:
+       template <typename ARGS_TUPLE, typename T>
+       static EvaluationValueFunction::Type constructConvertingArgsFunction(T &&f)
        {
-               return [f = std::move(f)](std::vector<EvaluationValue> sourceArgs) -> EvaluationValue {
-                       constexpr auto expectedArgs = sizeof...(ARGS);
-                       if (sourceArgs.size() < expectedArgs)
-                               throw EvaluationFailure{} << "not enough arguments, expected " << expectedArgs << ", got " << sourceArgs.size();
-                       if (sourceArgs.size() > expectedArgs)
-                               throw EvaluationFailure{} << "too many arguments, expected " << expectedArgs << ", got " << sourceArgs.size();
-                       std::tuple<ARGS...> args;
-                       detail::Converter<0, sizeof...(ARGS)>::convert(args, sourceArgs);
+               return [f = std::move(f)](const std::vector<EvaluationValue_> &sourceArgs) -> EvaluationValue_ {
+                       constexpr auto expectedArgs = std::tuple_size<ARGS_TUPLE>::value;
+                       validateArgumentCount(expectedArgs, sourceArgs.size());
+                       //std::tuple<ARGS...>
+                       ARGS_TUPLE args;
+                       detail::Converter<0, expectedArgs>::convert(args, sourceArgs);
                        return detail::apply(f, args);
                };
        }
-}
+};
 
 #endif
diff --git a/src/batch/EvaluationValueBase.cpp b/src/batch/EvaluationValueBase.cpp
new file mode 100644 (file)
index 0000000..1e1f229
--- /dev/null
@@ -0,0 +1,191 @@
+#include "EvaluationValueBase.hpp"
+#include "EvaluationValue.hpp"
+#include "../UniversalSwitchLog.hpp"
+
+namespace std
+{
+       size_t hash<EvaluationValue_>::operator()(const EvaluationValue_ &v) const
+       {
+               return v.hash();
+       }
+}
+
+#define Q(type) \
+       void EvaluationValueBase::as(EvaluationValue ## type &v, const EvaluationValuePtr &q) { v = q->as ## type(); } \
+       void EvaluationValueBase::convertTo(EvaluationValue ## type &v, const EvaluationValuePtr &q) { v = q->convertTo ## type()->as ## type(); } \
+       const EvaluationValue ## type &EvaluationValueBase::as ## type() { throw EvaluationFailure{} << \
+                               "unsupported operation, type " << typeName() << " can't be represented as " #type; } \
+       EvaluationValuePtr EvaluationValueBase::convertTo ## type() { throw EvaluationFailure{} << \
+                               "unsupported operation, can't convert " << typeName() << " to " #type; }
+
+Q(String)
+Q(Integer)
+Q(Double)
+Q(UIElement)
+Q(Boolean)
+Q(Point)
+Q(Function)
+Q(Vector)
+Q(Set)
+Q(Dict)
+#undef Q
+
+std::ostream &operator << (std::ostream &s, const EvaluationValuePtr &v)
+{
+       v->writeToStream(s);
+       return s;
+}
+
+size_t EvaluationValueBase::oper_hash()
+{
+       throw EvaluationFailure{} << "unsupported operation, can't calculate hash for " << typeName();
+}
+
+bool EvaluationValueBase::oper_cmp(Cmp cmp, const EvaluationValuePtr &o)
+{
+       auto v = oper_equal(o);
+       return cmp == Cmp::Equal ? v : !v;
+}
+
+bool EvaluationValueBase::oper_order(Order order, const EvaluationValuePtr &o)
+{
+       auto cmp = [](const EvaluationValuePtr & l, const EvaluationValuePtr & r) -> int {
+               try
+               {
+                       return l->oper_order(r);
+               } catch (EvaluationFailure &ev)
+               {
+                       try {
+                               return -r->oper_order(l);
+                       } catch (EvaluationFailure) { }
+                       throw;
+               }
+       };
+       auto v = cmp(shared_from_this(), o);
+       switch (order) {
+       case Order::Less:
+               return v < 0;
+       case Order::LessThan:
+               return v <= 0;
+       case Order::More:
+               return v > 0;
+       case Order::MoreThan:
+               return v >= 0;
+       }
+       ASSERT(0);
+       return false;
+}
+
+int EvaluationValueBase::oper_order(const EvaluationValuePtr &o)
+{
+       throw EvaluationFailure{} << "unsupported operation, can't order values " << o->typeName() << " and " << typeName();
+}
+
+size_t EvaluationValueBase::getSingleIndex(const EvaluationValuePtr &index, size_t size) const
+{
+       auto i = index->convertToInteger()->asInteger();
+       auto origIndex = i;
+       if (i < 0) i += static_cast<EvaluationValueInteger>(size);
+       if (i < 0 || i >= static_cast<EvaluationValueInteger>(size))
+               throw EvaluationFailure{} << origIndex << " is out of range for " << typeName() << " of size " << size;
+       return static_cast<size_t>(i);
+}
+
+std::pair<size_t, size_t> EvaluationValueBase::getDoubleIndexes(const EvaluationValuePtr &from, const EvaluationValuePtr &to, size_t size_) const
+{
+       auto index1 = from->convertToInteger()->asInteger();
+       auto index2 = to->convertToInteger()->asInteger();
+       auto size = static_cast<EvaluationValueInteger>(size_);
+
+       if (index1 < 0) index1 += size;
+       if (index2 < 0) index2 += size;
+
+       if (index1 < 0) index1 = 0;
+       else if (index1 > size) index1 = size;
+
+       if (index2 < index1) index2 = index1;
+       else if (index2 > size) index2 = size;
+
+       return { static_cast<size_t>(index1), static_cast<size_t>(index2) };
+}
+
+bool EvaluationValueBase::oper_contains(const EvaluationValuePtr &value)
+{
+       throw EvaluationFailure{} << "unsupported operation, " << typeName() << " is not a container";
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_call(const std::vector<EvaluationValue_> &args)
+{
+       throw EvaluationFailure{} << "unsupported operation, " << typeName() << " is not a callable";
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_attr_get(const std::string &name)
+{
+       throw EvaluationFailure{} << "unsupported operation, " << typeName() << " doesn't have a " << name << " attribute";
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_attr_set(const std::string &name, const EvaluationValuePtr &)
+{
+       throw EvaluationFailure{} << "unsupported operation, " << typeName() << " doesn't have a " << name << " attribute";
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_negate()
+{
+       throw EvaluationFailure{} << "unsupported operation, " << typeName() << " is not a number";
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_index_get(const EvaluationValuePtr &index)
+{
+       throw EvaluationFailure{} << "unsupported operation, " << typeName() << " is not a container";
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_index_get(const EvaluationValuePtr &from, const EvaluationValuePtr &to)
+{
+       throw EvaluationFailure{} << "unsupported operation, " << typeName() << " is not a container";
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_index_set(const EvaluationValuePtr &index, const EvaluationValuePtr &value)
+{
+       throw EvaluationFailure{} << "unsupported operation, " << typeName() << " is not a wrte-able container";
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_index_set(const EvaluationValuePtr &from, const EvaluationValuePtr &to, const EvaluationValuePtr &value)
+{
+       throw EvaluationFailure{} << "unsupported operation, " << typeName() << " is not a wrte-able container";
+}
+
+class EvaluationValueEmptyImpl : public EvaluationValueBase
+{
+public:
+       std::string typeName() const override
+       {
+               return "Empty";
+       }
+       bool isEmpty() const override
+       {
+               return true;
+       }
+
+       void writeToStream(std::ostream &os) const override
+       {
+               os << "null";
+       }
+       size_t oper_hash() override
+       {
+               return 1;
+       }
+
+       bool oper_equal(const EvaluationValuePtr &other) override
+       {
+               return other->isEmpty();
+       }
+       bool oper_is_true() override
+       {
+               return false;
+       }
+};
+
+EvaluationValuePtr EvaluationValueBase::create()
+{
+       return std::make_shared<EvaluationValueEmptyImpl>();
+}
diff --git a/src/batch/EvaluationValueBase.hpp b/src/batch/EvaluationValueBase.hpp
new file mode 100644 (file)
index 0000000..b8f45f9
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2017  Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TEST_EVALUATION_VALUE_BASE
+#define TEST_EVALUATION_VALUE_BASE
+
+#include "EvaluationValue.hpp"
+
+// sanity check and for safety - comparing those pointers is an error anyway
+bool operator == (EvaluationValuePtr, EvaluationValuePtr) = delete;
+bool operator != (EvaluationValuePtr, EvaluationValuePtr) = delete;
+bool operator <= (EvaluationValuePtr, EvaluationValuePtr) = delete;
+bool operator >= (EvaluationValuePtr, EvaluationValuePtr) = delete;
+bool operator < (EvaluationValuePtr, EvaluationValuePtr) = delete;
+bool operator > (EvaluationValuePtr, EvaluationValuePtr) = delete;
+
+class EvaluationValueBase : public std::enable_shared_from_this<EvaluationValueBase>
+{
+protected:
+       EvaluationValueBase() = default;
+       virtual ~EvaluationValueBase() = default;
+
+       EvaluationValueBase(const EvaluationValueBase &) = delete;
+       EvaluationValueBase(EvaluationValueBase &&) = delete;
+
+       EvaluationValueBase &operator = (const EvaluationValueBase &) = delete;
+       EvaluationValueBase &operator = (EvaluationValueBase &&) = delete;
+
+       template <typename T> static int orderValues(T a, T b)
+       {
+               if (a == b) return 0;
+               return a < b ? -1 : 1;
+       }
+public:
+       enum class Cmp {
+               Equal, NotEqual
+       };
+       enum class Order {
+               Less, LessThan, More, MoreThan
+       };
+
+       bool oper_cmp(Cmp, const EvaluationValuePtr &);
+       bool oper_order(Order, const EvaluationValuePtr &);
+       virtual bool isEmpty() const
+       {
+               return false;
+       }
+
+       virtual std::string typeName() const = 0;
+       virtual bool oper_equal(const EvaluationValuePtr &) = 0;
+       virtual int oper_order(const EvaluationValuePtr &);
+       virtual size_t oper_hash();
+       virtual bool oper_contains(const EvaluationValuePtr &value);
+       virtual bool oper_is_true() = 0;
+       virtual EvaluationValuePtr oper_call(const std::vector<EvaluationValue_> &args);
+       virtual EvaluationValuePtr oper_attr_get(const std::string &name);
+       virtual EvaluationValuePtr oper_attr_set(const std::string &name, const EvaluationValuePtr &);
+       virtual EvaluationValuePtr oper_negate();
+       virtual EvaluationValuePtr oper_index_get(const EvaluationValuePtr &index);
+       virtual EvaluationValuePtr oper_index_get(const EvaluationValuePtr &from, const EvaluationValuePtr &to);
+       virtual EvaluationValuePtr oper_index_set(const EvaluationValuePtr &index, const EvaluationValuePtr &value);
+       virtual EvaluationValuePtr oper_index_set(const EvaluationValuePtr &from, const EvaluationValuePtr &to, const EvaluationValuePtr &value);
+
+       virtual void writeToStream(std::ostream &) const = 0;
+
+       static EvaluationValuePtr create();
+#define Q(type) \
+       static void as(EvaluationValue ## type &v, const EvaluationValuePtr &q); \
+       static void convertTo(EvaluationValue ## type &v, const EvaluationValuePtr &q); \
+       static EvaluationValuePtr create(EvaluationValue ## type); \
+       virtual EvaluationValuePtr convertTo ## type(); \
+       virtual const EvaluationValue ## type &as ## type(); \
+       virtual bool is ## type() const { return false; }
+
+       Q(String)
+       Q(Integer)
+       Q(Double)
+       Q(UIElement)
+       Q(Boolean)
+       Q(Point)
+       Q(Function)
+       Q(Vector)
+       Q(Set)
+       Q(Dict)
+#undef Q
+
+       size_t getSingleIndex(const EvaluationValuePtr &index, size_t size) const;
+       std::pair<size_t, size_t> getDoubleIndexes(const EvaluationValuePtr &from, const EvaluationValuePtr &to, size_t size) const;
+
+       static EvaluationContext &currentContext();
+public:
+       class ContextManager
+       {
+               EvaluationContext *prev = nullptr;
+       public:
+               ContextManager(EvaluationContext &);
+               ~ContextManager();
+
+               ContextManager(const ContextManager &) = delete;
+               ContextManager(ContextManager &&) = delete;
+
+               ContextManager &operator = (const ContextManager &) = delete;
+               ContextManager &operator = (ContextManager &&) = delete;
+       };
+};
+std::ostream &operator << (std::ostream &s, const EvaluationValuePtr &v);
+
+#endif
diff --git a/src/batch/EvaluationValueBoolean.cpp b/src/batch/EvaluationValueBoolean.cpp
new file mode 100644 (file)
index 0000000..6191647
--- /dev/null
@@ -0,0 +1,48 @@
+#include "EvaluationValueBase.hpp"
+
+class EvaluationValueBooleanImpl : public EvaluationValueBase
+{
+public:
+       EvaluationValueBooleanImpl(EvaluationValueBoolean v) : value(v) { }
+
+       std::string typeName() const override
+       {
+               return "Boolean";
+       }
+       bool isBoolean() const override
+       {
+               return true;
+       }
+       EvaluationValuePtr convertToBoolean() override
+       {
+               return shared_from_this();
+       }
+       const EvaluationValueBoolean &asBoolean() override
+       {
+               return value;
+       }
+
+       void writeToStream(std::ostream &os) const override
+       {
+               os << (value ? "true" : "false");
+       }
+       size_t oper_hash() override
+       {
+               return std::hash<EvaluationValueBoolean>()(value);
+       }
+       bool oper_equal(const EvaluationValuePtr &other) override
+       {
+               return other->isBoolean() && value == other->asBoolean();
+       }
+       bool oper_is_true() override
+       {
+               return value;
+       }
+private:
+       EvaluationValueBoolean value;
+};
+
+EvaluationValuePtr EvaluationValueBase::create(EvaluationValueBoolean v)
+{
+       return std::make_shared<EvaluationValueBooleanImpl>(v);
+}
diff --git a/src/batch/EvaluationValueDict.cpp b/src/batch/EvaluationValueDict.cpp
new file mode 100644 (file)
index 0000000..6f86763
--- /dev/null
@@ -0,0 +1,75 @@
+#include "EvaluationValueBase.hpp"
+
+class EvaluationValueDictImpl : public EvaluationValueBase
+{
+public:
+       EvaluationValueDictImpl(EvaluationValueDict v) : value(std::move(v)) { }
+
+       std::string typeName() const override
+       {
+               return "Dict";
+       }
+       bool isDict() const override
+       {
+               return true;
+       }
+       EvaluationValuePtr convertToBoolean() override
+       {
+               return create(!value.empty());
+       }
+       EvaluationValuePtr convertToDict() override
+       {
+               return shared_from_this();
+       }
+       const EvaluationValueDict &asDict() override
+       {
+               return value;
+       }
+
+       void writeToStream(std::ostream &os) const override
+       {
+               if (value.empty()) {
+                       os << "{:}";
+                       return;
+               }
+               os << "{ ";
+               bool first = true;
+               for (auto &v : value) {
+                       if (first) first = false;
+                       else os << ", ";
+                       os << v.first << ": " << v.second;
+               }
+               os << " }";
+       }
+       bool oper_equal(const EvaluationValuePtr &other) override
+       {
+               return other->isDict() && value == other->asDict();
+       }
+       bool oper_is_true() override
+       {
+               return !value.empty();
+       }
+       bool oper_contains(const EvaluationValuePtr &v) override
+       {
+               return value.find(v) != value.end();
+       }
+       EvaluationValuePtr oper_index_get(const EvaluationValuePtr &index) override
+       {
+               auto it = value.find(index);
+               if (it == value.end()) throw EvaluationFailure{} << "missing key '" << index << "'";
+               return it->second.getInternalValue();
+       }
+       EvaluationValuePtr oper_index_set(const EvaluationValuePtr &index, const EvaluationValuePtr &val) override
+       {
+               auto it = value.insert({ index, val });
+               it.first->second = val;
+               return val;
+       }
+private:
+       EvaluationValueDict value;
+};
+
+EvaluationValuePtr EvaluationValueBase::create(EvaluationValueDict v)
+{
+       return std::make_shared<EvaluationValueDictImpl>(std::move(v));
+}
diff --git a/src/batch/EvaluationValueDouble.cpp b/src/batch/EvaluationValueDouble.cpp
new file mode 100644 (file)
index 0000000..78c1db0
--- /dev/null
@@ -0,0 +1,74 @@
+#include "EvaluationValueBase.hpp"
+
+class EvaluationValueDoubleImpl : public EvaluationValueBase
+{
+public:
+       EvaluationValueDoubleImpl(EvaluationValueDouble v) : value(v) { }
+
+       std::string typeName() const override
+       {
+               return "Double";
+       }
+       bool isDouble() const override
+       {
+               return true;
+       }
+       EvaluationValuePtr convertToBoolean() override
+       {
+               return create(bool(value));
+       }
+       EvaluationValuePtr convertToDouble() override
+       {
+               return shared_from_this();
+       }
+       EvaluationValuePtr convertToString() override
+       {
+               return create(std::to_string(value));
+       }
+       EvaluationValuePtr convertToInteger() override
+       {
+               if (static_cast<EvaluationValueInteger>(value) != value)
+                       throw EvaluationFailure{} << "'" << value << "' doesn't fit into integer";
+               return create(static_cast<EvaluationValueInteger>(value));
+       }
+       const EvaluationValueDouble &asDouble() override
+       {
+               return value;
+       }
+
+       void writeToStream(std::ostream &os) const override
+       {
+               os << value;
+       }
+       size_t oper_hash() override
+       {
+               return std::hash<double>()(value);
+       }
+       bool oper_equal(const EvaluationValuePtr &other) override
+       {
+               if (other->isDouble()) return value == other->asDouble();
+               if (other->isInteger()) return value == static_cast<double>(other->asInteger());
+               return false;
+       }
+       int oper_order(const EvaluationValuePtr &other) override
+       {
+               if (other->isDouble()) return orderValues(value, other->asDouble());
+               if (other->isInteger()) return orderValues(value, static_cast<double>(other->asInteger()));
+               return EvaluationValueBase::oper_order(other);
+       }
+       bool oper_is_true() override
+       {
+               return value != 0;
+       }
+       EvaluationValuePtr oper_negate() override
+       {
+               return create(-value);
+       }
+private:
+       EvaluationValueDouble value;
+};
+
+EvaluationValuePtr EvaluationValueBase::create(EvaluationValueDouble v)
+{
+       return std::make_shared<EvaluationValueDoubleImpl>(v);
+}
diff --git a/src/batch/EvaluationValueFunction.cpp b/src/batch/EvaluationValueFunction.cpp
new file mode 100644 (file)
index 0000000..983952a
--- /dev/null
@@ -0,0 +1,57 @@
+#include "EvaluationValueBase.hpp"
+#include "EvaluationContext.hpp"
+
+class EvaluationValueFunctionImpl : public EvaluationValueBase
+{
+public:
+       EvaluationValueFunctionImpl(EvaluationValueFunction v) : value(std::move(v))
+       {
+               ASSERT(value);
+       }
+
+       std::string typeName() const override
+       {
+               return "Function";
+       }
+       bool isFunction() const override
+       {
+               return true;
+       }
+       EvaluationValuePtr convertToBoolean() override
+       {
+               assert(value);
+               return create(bool(value));
+       }
+       EvaluationValuePtr convertToFunction() override
+       {
+               return shared_from_this();
+       }
+       const EvaluationValueFunction &asFunction() override
+       {
+               return value;
+       }
+
+       void writeToStream(std::ostream &os) const override
+       {
+               os << "<functor>";
+       }
+       bool oper_equal(const EvaluationValuePtr &other) override
+       {
+               throw EvaluationFailure{} << "unsupported operation, can't compare values " << typeName() << " and " << other->typeName();
+       }
+       bool oper_is_true() override
+       {
+               return true;
+       }
+       EvaluationValuePtr oper_call(const std::vector<EvaluationValue_> &args) override
+       {
+               return value(args).getInternalValue();
+       }
+private:
+       EvaluationValueFunction value;
+};
+
+EvaluationValuePtr EvaluationValueBase::create(EvaluationValueFunction v)
+{
+       return std::make_shared<EvaluationValueFunctionImpl>(std::move(v));
+}
diff --git a/src/batch/EvaluationValueInteger.cpp b/src/batch/EvaluationValueInteger.cpp
new file mode 100644 (file)
index 0000000..21afd78
--- /dev/null
@@ -0,0 +1,72 @@
+#include "EvaluationValueBase.hpp"
+
+class EvaluationValueIntegerImpl : public EvaluationValueBase
+{
+public:
+       EvaluationValueIntegerImpl(EvaluationValueInteger v) : value(v) { }
+
+       std::string typeName() const override
+       {
+               return "Integer";
+       }
+       bool isInteger() const override
+       {
+               return true;
+       }
+       EvaluationValuePtr convertToBoolean() override
+       {
+               return create(bool(value));
+       }
+       EvaluationValuePtr convertToInteger() override
+       {
+               return shared_from_this();
+       }
+       EvaluationValuePtr convertToString() override
+       {
+               return create(std::to_string(value));
+       }
+       EvaluationValuePtr convertToDouble() override
+       {
+               return create(static_cast<double>(value));
+       }
+       const EvaluationValueInteger &asInteger() override
+       {
+               return value;
+       }
+
+       void writeToStream(std::ostream &os) const override
+       {
+               os << value;
+       }
+       size_t oper_hash() override
+       {
+               return std::hash<EvaluationValueInteger>()(value);
+       }
+       bool oper_equal(const EvaluationValuePtr &other) override
+       {
+               if (other->isInteger()) return value == other->asInteger();
+               if (other->isDouble()) return static_cast<double>(value) == other->asDouble();
+               return false;
+       }
+       int oper_order(const EvaluationValuePtr &other) override
+       {
+               if (other->isInteger()) return orderValues(value, other->asInteger());
+               if (other->isDouble()) return orderValues(static_cast<double>(value), other->asDouble());
+               return EvaluationValueBase::oper_order(other);
+       }
+       bool oper_is_true() override
+       {
+               return value != 0;
+       }
+       EvaluationValuePtr oper_negate() override
+       {
+               return create(-value);
+       }
+private:
+       EvaluationValueInteger value;
+};
+
+EvaluationValuePtr EvaluationValueBase::create(EvaluationValueInteger v)
+{
+       return std::make_shared<EvaluationValueIntegerImpl>(v);
+}
diff --git a/src/batch/EvaluationValuePoint.cpp b/src/batch/EvaluationValuePoint.cpp
new file mode 100644 (file)
index 0000000..ccdd026
--- /dev/null
@@ -0,0 +1,64 @@
+#include "EvaluationValueBase.hpp"
+#include "EvaluationContext.hpp"
+#include "../Geometry.hpp"
+
+class EvaluationValuePointImpl : public EvaluationValueBase
+{
+public:
+       EvaluationValuePointImpl(EvaluationValuePoint v) : value(v) { }
+
+       std::string typeName() const override
+       {
+               return "Point";
+       }
+       bool isPoint() const override
+       {
+               return true;
+       }
+       EvaluationValuePtr convertToBoolean() override
+       {
+               return create(true);
+       }
+       EvaluationValuePtr convertToPoint() override
+       {
+               return shared_from_this();
+       }
+       EvaluationValuePtr convertToUIElement() override
+       {
+               return create(EvaluationContext::getCurrentEvaluationContext().executionInterface().convertToUIElement(value));
+       }
+       const EvaluationValuePoint &asPoint() override
+       {
+               return value;
+       }
+
+       void writeToStream(std::ostream &os) const override
+       {
+               os << "<" << value.x << ", " << value.y << ">";
+       }
+       size_t oper_hash() override
+       {
+               return (std::hash<size_t>()(value.x) << 16) ^ std::hash<size_t>()(value.y);
+       }
+       bool oper_equal(const EvaluationValuePtr &other) override
+       {
+               return other->isPoint() && value == other->asPoint();
+       }
+       bool oper_is_true() override
+       {
+               return true;
+       }
+       EvaluationValuePtr oper_attr_get(const std::string &name) override
+       {
+               if (name == "x") return create(static_cast<EvaluationValueInteger>(value.x));
+               if (name == "y") return create(static_cast<EvaluationValueInteger>(value.y));
+               return EvaluationValueBase::oper_attr_get(name);
+       }
+private:
+       EvaluationValuePoint value;
+};
+
+EvaluationValuePtr EvaluationValueBase::create(EvaluationValuePoint v)
+{
+       return std::make_shared<EvaluationValuePointImpl>(v);
+}
diff --git a/src/batch/EvaluationValueSet.cpp b/src/batch/EvaluationValueSet.cpp
new file mode 100644 (file)
index 0000000..f65a434
--- /dev/null
@@ -0,0 +1,68 @@
+#include "EvaluationValueBase.hpp"
+
+class EvaluationValueSetImpl : public EvaluationValueBase
+{
+public:
+       EvaluationValueSetImpl(EvaluationValueSet v) : value(std::move(v)) { }
+
+       std::string typeName() const override
+       {
+               return "Set";
+       }
+       bool isSet() const override
+       {
+               return true;
+       }
+       EvaluationValuePtr convertToBoolean() override
+       {
+               return create(!value.empty());
+       }
+       EvaluationValuePtr convertToSet() override
+       {
+               return shared_from_this();
+       }
+       EvaluationValuePtr convertToVector() override
+       {
+               return create(EvaluationValueVector{ value.begin(), value.end() });
+       }
+       const EvaluationValueSet &asSet() override
+       {
+               return value;
+       }
+
+       void writeToStream(std::ostream &os) const override
+       {
+               if (value.empty()) {
+                       os << "{}";
+                       return;
+               }
+
+               os << "{ ";
+               bool first = true;
+               for (auto &v : value) {
+                       if (first) first = false;
+                       else os << ", ";
+                       os << v;
+               }
+               os << " }";
+       }
+       bool oper_equal(const EvaluationValuePtr &other) override
+       {
+               return other->isSet() && value == other->asSet();
+       }
+       bool oper_is_true() override
+       {
+               return !value.empty();
+       }
+       bool oper_contains(const EvaluationValuePtr &v) override
+       {
+               return value.find(v) != value.end();
+       }
+private:
+       EvaluationValueSet value;
+};
+
+EvaluationValuePtr EvaluationValueBase::create(EvaluationValueSet v)
+{
+       return std::make_shared<EvaluationValueSetImpl>(std::move(v));
+}
diff --git a/src/batch/EvaluationValueString.cpp b/src/batch/EvaluationValueString.cpp
new file mode 100644 (file)
index 0000000..53a8b1f
--- /dev/null
@@ -0,0 +1,73 @@
+#include "EvaluationValueBase.hpp"
+#include "EvaluationContext.hpp"
+#include "../Geometry.hpp"
+
+class EvaluationValueStringImpl : public EvaluationValueBase
+{
+public:
+       EvaluationValueStringImpl(EvaluationValueString v) : value(std::move(v)) { }
+
+       std::string typeName() const override
+       {
+               return "String";
+       }
+       bool isString() const override
+       {
+               return true;
+       }
+       EvaluationValuePtr convertToBoolean() override
+       {
+               return create(!value.empty());
+       }
+       EvaluationValuePtr convertToString() override
+       {
+               return shared_from_this();
+       }
+       EvaluationValuePtr convertToUIElement() override
+       {
+               return create(EvaluationContext::getCurrentEvaluationContext().executionInterface().convertToUIElement(value));
+       }
+       const EvaluationValueString &asString() override
+       {
+               return value;
+       }
+
+       void writeToStream(std::ostream &os) const override
+       {
+               os << "'" << value << "'";
+       }
+       size_t oper_hash() override
+       {
+               return std::hash<EvaluationValueString>()(value);
+       }
+       bool oper_equal(const EvaluationValuePtr &other) override
+       {
+               return other->isString() && value == other->asString();
+       }
+       bool oper_is_true() override
+       {
+               return !value.empty();
+       }
+       EvaluationValuePtr oper_attr_get(const std::string &name) override
+       {
+               if (name == "len") return create(static_cast<EvaluationValueInteger>(value.size()));
+               return EvaluationValueBase::oper_attr_get(name);
+       }
+       EvaluationValuePtr oper_index_get(const EvaluationValuePtr &index) override
+       {
+               auto i = getSingleIndex(index, value.size());
+               return create(value.substr(i, 1));
+       }
+       EvaluationValuePtr oper_index_get(const EvaluationValuePtr &from, const EvaluationValuePtr &to) override
+       {
+               auto indexes = getDoubleIndexes(from, to, value.size());
+               return create(value.substr(indexes.first, indexes.second - indexes.first));
+       }
+private:
+       EvaluationValueString value;
+};
+
+EvaluationValuePtr EvaluationValueBase::create(EvaluationValueString v)
+{
+       return std::make_shared<EvaluationValueStringImpl>(std::move(v));
+}
diff --git a/src/batch/EvaluationValueUIElement.cpp b/src/batch/EvaluationValueUIElement.cpp
new file mode 100644 (file)
index 0000000..25e7ac9
--- /dev/null
@@ -0,0 +1,71 @@
+#include "EvaluationValueBase.hpp"
+#include "EvaluationContext.hpp"
+#include "../UIElement.hpp"
+#include "../Atspi.hpp"
+
+class EvaluationValueUIElementImpl : public EvaluationValueBase
+{
+public:
+       EvaluationValueUIElementImpl(EvaluationValueUIElement v) : value(std::move(v)) { }
+
+       std::string typeName() const override
+       {
+               return "UIElement";
+       }
+       bool isUIElement() const override
+       {
+               return true;
+       }
+       EvaluationValuePtr convertToBoolean() override
+       {
+               return create(bool(value->getObject()));
+       }
+       EvaluationValuePtr convertToUIElement() override
+       {
+               return shared_from_this();
+       }
+       const EvaluationValueUIElement &asUIElement() override
+       {
+               return value;
+       }
+
+       void writeToStream(std::ostream &os) const override
+       {
+               os << "<" << 
+                       EvaluationContext::getCurrentEvaluationContext().executionInterface().getUIElementUniqueId(value) << 
+                       ">";
+       }
+       size_t oper_hash() override
+       {
+               auto id = EvaluationContext::getCurrentEvaluationContext().executionInterface().getUIElementUniqueId(value);
+               return std::hash<std::string>()(id);
+       }
+       bool oper_equal(const EvaluationValuePtr &other) override
+       {
+               if (!other->isUIElement()) return false;
+
+               auto selfId = EvaluationContext::getCurrentEvaluationContext().executionInterface().getUIElementUniqueId(value);
+               auto otherId = EvaluationContext::getCurrentEvaluationContext().executionInterface().getUIElementUniqueId(other->asUIElement());
+               return selfId == otherId;
+       }
+       bool oper_is_true() override
+       {
+               return true;
+       }
+       EvaluationValuePtr oper_attr_get(const std::string &name) override
+       {
+               if (name == "name")
+                       return create(EvaluationContext::getCurrentEvaluationContext().executionInterface().getUIElementName(value));
+               if (name == "middle_point")
+                       return create(value->getScanningCoordinates());
+               return EvaluationValueBase::oper_attr_get(name);
+       }
+private:
+       EvaluationValueUIElement value;
+};
+
+EvaluationValuePtr EvaluationValueBase::create(EvaluationValueUIElement v)
+{
+       ASSERT(v->getObject());
+       return std::make_shared<EvaluationValueUIElementImpl>(std::move(v));
+}
diff --git a/src/batch/EvaluationValueVector.cpp b/src/batch/EvaluationValueVector.cpp
new file mode 100644 (file)
index 0000000..c60a143
--- /dev/null
@@ -0,0 +1,117 @@
+#include "EvaluationValueBase.hpp"
+
+class EvaluationValueVectorImpl : public EvaluationValueBase
+{
+public:
+       EvaluationValueVectorImpl(EvaluationValueVector v) : value(std::move(v)) { }
+
+       std::string typeName() const override
+       {
+               return "Vector";
+       }
+       bool isVector() const override
+       {
+               return true;
+       }
+       EvaluationValuePtr convertToBoolean() override
+       {
+               return create(!value.empty());
+       }
+       EvaluationValuePtr convertToVector() override
+       {
+               return shared_from_this();
+       }
+       const EvaluationValueVector &asVector() override
+       {
+               return value;
+       }
+
+       void writeToStream(std::ostream &os) const override
+       {
+               if (value.empty()) {
+                       os << "[]";
+                       return;
+               }
+               os << "[ ";
+               bool first = true;
+               for (auto &v : value) {
+                       if (first) first = false;
+                       else os << ", ";
+                       os << v;
+               }
+               os << " ]";
+       }
+       bool oper_equal(const EvaluationValuePtr &other) override
+       {
+               return other->isVector() && value == other->asVector();
+       }
+       int oper_order(const EvaluationValuePtr &other) override
+       {
+               if (!other->isVector())
+                       return EvaluationValueBase::oper_order(other);
+
+               auto &o = other->asVector();
+               for (auto i = 0u; i < std::min(value.size(), o.size()); ++i) {
+                       if (value[i] == o[i]) continue;
+                       return value[i] < o[i] ? -1 : 1;
+               }
+               if (value.size() < o.size()) return -1;
+               if (value.size() > o.size()) return 1;
+               return 0;
+       }
+       bool oper_is_true() override
+       {
+               return !value.empty();
+       }
+       bool oper_contains(const EvaluationValuePtr &v) override
+       {
+               for (auto &a : value)
+                       if (a == v)
+                               return true;
+               return false;
+       }
+       EvaluationValuePtr oper_index_get(const EvaluationValuePtr &index) override
+       {
+               auto i = getSingleIndex(index, value.size());
+               return value[i].getInternalValue();
+       }
+       EvaluationValuePtr oper_index_get(const EvaluationValuePtr &from, const EvaluationValuePtr &to) override
+       {
+               auto indexes = getDoubleIndexes(from, to, value.size());
+               std::vector<EvaluationValue_> tmp;
+               tmp.reserve(indexes.second - indexes.first);
+               for (auto i = indexes.first; i < indexes.second; ++i)
+                       tmp.push_back(value[i]);
+               return create(std::move(tmp));
+       }
+       EvaluationValuePtr oper_index_set(const EvaluationValuePtr &index, const EvaluationValuePtr &val) override
+       {
+               auto i = getSingleIndex(index, value.size());
+               value[i] = val;
+               return val;
+       }
+       EvaluationValuePtr oper_index_set(const EvaluationValuePtr &from, const EvaluationValuePtr &to, const EvaluationValuePtr &val) override
+       {               
+               if (!val->isVector())
+                       return EvaluationValueBase::oper_index_set(from, to, val);
+
+               auto indexes = getDoubleIndexes(from, to, value.size());
+               std::vector<EvaluationValue_> tmp;
+               tmp.reserve(value.size() - (indexes.second - indexes.first) + val->asVector().size());
+               for (size_t i = 0; i < indexes.first; ++i)
+                       tmp.push_back(value[i]);
+               for (auto &q : val->asVector())
+                       tmp.push_back(q);
+               for (size_t i = indexes.second; i < value.size(); ++i)
+                       tmp.push_back(value[i]);
+               value = std::move(tmp);
+               return shared_from_this();
+       }
+private:
+       EvaluationValueVector value;
+};
+
+EvaluationValuePtr EvaluationValueBase::create(EvaluationValueVector v)
+{
+       return std::make_shared<EvaluationValueVectorImpl>(std::move(v));
+}
index 20a9b95..5eb0e93 100644 (file)
 #include <string>
 #include <iomanip>
 
-using detail::VectorType;
-using detail::SetType;
-using detail::FunctionType;
-using detail::DictType;
-
 std::ostringstream &Evaluator::printLocationAndIndent(std::ostringstream &os, const TokenLocation &loc, unsigned int depth) const
 {
        std::string indent(static_cast<size_t>(depth), ' ');
@@ -70,7 +65,7 @@ void DebugEvaluatorInterface::setCurrentInterface(std::unique_ptr<DebugEvaluator
        debugInterface = std::move(inf);
 }
 
-template <typename F> static auto evaluateHelper(std::string debugId, F && f) 
+template <typename F> static auto evaluateHelper(std::string debugId, TokenLocation loc, F &&f)
 {
        struct CallOnExit {
                std::function<void()> func;
@@ -78,12 +73,23 @@ template <typename F> static auto evaluateHelper(std::string debugId, F && f)
                ~CallOnExit() { func(); }
        };      
        EvaluationDepthCountManager countManager;
-       if (!debugInterface) return f();
+       if (!debugInterface) {
+               try {
+                       return f();
+               } catch(EvaluationFailure &ev) {
+                       ev.setLocationIfMissing(loc);
+                       throw;
+               }
+       }
        std::string indent(static_cast<size_t>(evaluationDepth * 2), ' ');
        try {
                CallOnExit call{ [&]() { debugInterface->write(indent + "leaving " + debugId); } };
                debugInterface->write(indent + "entering " + debugId);
                return f();
+       } catch(EvaluationFailure &ev) {
+               ev.setLocationIfMissing(loc);
+               debugInterface->write(indent + "exception " + debugId + " (" + ev.what() + "), leaving");
+               throw;
        } catch (std::exception &ex) {
                debugInterface->write(indent + "exception " + debugId + " (" + ex.what() + "), leaving");
                throw;
@@ -93,20 +99,20 @@ template <typename F> static auto evaluateHelper(std::string debugId, F && f)
        }
 }
 
-EvaluationValue ExpressionEvaluator::evaluate() const
+EvaluationValue_ ExpressionEvaluator::evaluate() const
 {
-       return evaluateHelper(std::to_string(getDebugId()), [&]() { return evaluateImpl(); } );
+       return evaluateHelper(std::to_string(getDebugId()), location(), [&]() { return evaluateImpl(); });
 }
 
 void StatementEvaluator::evaluate() const
 {
-       return evaluateHelper(std::to_string(getDebugId()), [&]() { return evaluateImpl(); } );
+       return evaluateHelper(std::to_string(getDebugId()), location(), [&]() { return evaluateImpl(); });
 }
 
 IdentifierEvaluator::IdentifierEvaluator(TokenLocation tokenLocation, std::string identifier) :
        ExpressionEvaluator(std::move(tokenLocation)), identifier(std::move(identifier)) { }
 
-EvaluationValue IdentifierEvaluator::evaluateImpl() const
+EvaluationValue_ IdentifierEvaluator::evaluateImpl() const
 {
        return EvaluationContext::getCurrentEvaluationContext().getVariable(location(), identifier);
 }
@@ -119,9 +125,9 @@ void IdentifierEvaluator::printSelfInfo(std::ostringstream &os, unsigned int dep
 AttributeEvaluator::AttributeEvaluator(TokenLocation tokenLocation, ExprPtr self, std::string identifier) :
        ExpressionEvaluator(std::move(tokenLocation)), self(std::move(self)), identifier(std::move(identifier)) { }
 
-EvaluationValue AttributeEvaluator::evaluateImpl() const
+EvaluationValue_ AttributeEvaluator::evaluateImpl() const
 {
-       return EvaluationContext::getCurrentEvaluationContext().getAttribute(location(), self->evaluate(), identifier);
+       return self->evaluate().attr_get(identifier);
 }
 
 void AttributeEvaluator::printSelfInfo(std::ostringstream &os, unsigned int depth) const
@@ -135,9 +141,10 @@ void AttributeEvaluator::printSelfInfo(std::ostringstream &os, unsigned int dept
 AttributeSetterEvaluator::AttributeSetterEvaluator(TokenLocation tokenLocation, ExprPtr self, std::string identifier, ExprPtr value) :
        ExpressionEvaluator(std::move(tokenLocation)), self(std::move(self)), value(std::move(value)), identifier(std::move(identifier)) { }
 
-EvaluationValue AttributeSetterEvaluator::evaluateImpl() const
+EvaluationValue_ AttributeSetterEvaluator::evaluateImpl() const
 {
-       return EvaluationContext::getCurrentEvaluationContext().setAttribute(location(), self->evaluate(), identifier, value->evaluate());
+       auto val = value->evaluate();
+       return self->evaluate().attr_set(identifier, std::move(val));
 }
 
 void AttributeSetterEvaluator::printSelfInfo(std::ostringstream &os, unsigned int depth) const
@@ -153,7 +160,7 @@ void AttributeSetterEvaluator::printSelfInfo(std::ostringstream &os, unsigned in
 SetterEvaluator::SetterEvaluator(TokenLocation tokenLocation, std::string identifier, ExprPtr value) :
        ExpressionEvaluator(std::move(tokenLocation)), value(std::move(value)), identifier(std::move(identifier)) { }
 
-EvaluationValue SetterEvaluator::evaluateImpl() const
+EvaluationValue_ SetterEvaluator::evaluateImpl() const
 {
        auto v = value->evaluate();
        EvaluationContext::getCurrentEvaluationContext().setVariable(identifier, v);
@@ -171,11 +178,11 @@ void SetterEvaluator::printSelfInfo(std::ostringstream &os, unsigned int depth)
 PointEvaluator::PointEvaluator(TokenLocation tokenLocation, ExprPtr x, ExprPtr y) :
        ExpressionEvaluator(std::move(tokenLocation)), x(std::move(x)), y(std::move(y)) { }
 
-EvaluationValue PointEvaluator::evaluateImpl() const
+EvaluationValue_ PointEvaluator::evaluateImpl() const
 {
-       auto xInt = detail::ConvertTo<int>::convert(x->evaluate());
-       auto yInt = detail::ConvertTo<int>::convert(y->evaluate());
-       return Point{ xInt, yInt };
+       auto xInt = x->evaluate().convertToInteger();
+       auto yInt = y->evaluate().convertToInteger();
+       return EvaluationValuePoint{ static_cast<int>(xInt), static_cast<int>(yInt) };
 }
 
 void PointEvaluator::printSelfInfo(std::ostringstream &os, unsigned int depth) const
@@ -188,10 +195,10 @@ void PointEvaluator::printSelfInfo(std::ostringstream &os, unsigned int depth) c
 }
 
 
-IntegerEvaluator::IntegerEvaluator(TokenLocation tokenLocation, int value) :
+IntegerEvaluator::IntegerEvaluator(TokenLocation tokenLocation, int64_t value) :
        ExpressionEvaluator(std::move(tokenLocation)), value(value) { }
 
-EvaluationValue IntegerEvaluator::evaluateImpl() const
+EvaluationValue_ IntegerEvaluator::evaluateImpl() const
 {
        return value;
 }
@@ -205,7 +212,7 @@ void IntegerEvaluator::printSelfInfo(std::ostringstream &os, unsigned int depth)
 DoubleEvaluator::DoubleEvaluator(TokenLocation tokenLocation, double value) :
        ExpressionEvaluator(std::move(tokenLocation)), value(value) { }
 
-EvaluationValue DoubleEvaluator::evaluateImpl() const
+EvaluationValue_ DoubleEvaluator::evaluateImpl() const
 {
        return value;
 }
@@ -219,9 +226,9 @@ void DoubleEvaluator::printSelfInfo(std::ostringstream &os, unsigned int depth)
 StringEvaluator::StringEvaluator(TokenLocation tokenLocation, std::string value) :
        ExpressionEvaluator(std::move(tokenLocation)), value(std::move(value)) { }
 
-EvaluationValue StringEvaluator::evaluateImpl() const
+EvaluationValue_ StringEvaluator::evaluateImpl() const
 {
-       return EvaluationValue{ value };
+       return value;
 }
 
 void StringEvaluator::printSelfInfo(std::ostringstream &os, unsigned int depth) const
@@ -233,17 +240,17 @@ void StringEvaluator::printSelfInfo(std::ostringstream &os, unsigned int depth)
 ArraySetDictEvaluator::ArraySetDictEvaluator(TokenLocation tokenLocation, ExprPtrs values, Kind kind) :
        ExpressionEvaluator(std::move(tokenLocation)), values(std::move(values)), kind(kind) { }
 
-EvaluationValue ArraySetDictEvaluator::evaluateImpl() const
+EvaluationValue_ ArraySetDictEvaluator::evaluateImpl() const
 {
-       std::vector<EvaluationValue> vals;
+       std::vector<EvaluationValue_> vals;
        for (auto &v : values)
                vals.push_back(v->evaluate());
 
        if (kind == Kind::VECTOR)
-               return { std::move(vals) };
+               return std::move(vals);
 
        if (kind == Kind::SET) {
-               SetType tmp;
+               EvaluationValueSet tmp;
                for (auto &v : vals) {
                        tmp.insert(std::move(v));
                }
@@ -251,7 +258,7 @@ EvaluationValue ArraySetDictEvaluator::evaluateImpl() const
        }
 
        ASSERT(kind == Kind::DICT);
-       DictType tmp;
+       EvaluationValueDict tmp;
        for (auto i = 0u; i < vals.size(); i += 2) {
                tmp.insert({ std::move(vals[i]), std::move(vals[i + 1]) });
        }
@@ -291,23 +298,27 @@ void ArraySetDictEvaluator::printSelfInfo(std::ostringstream &os, unsigned int d
 OperatorEvaluator::OperatorEvaluator(TokenLocation tokenLocation, ExprPtrs args, Kind kind) :
        ExpressionEvaluator(std::move(tokenLocation)), args(std::move(args)), kind(kind) { }
 
-EvaluationValue OperatorEvaluator::evaluateImpl() const
+EvaluationValue_ OperatorEvaluator::evaluateImpl() const
 {
-       std::vector<EvaluationValue> vals;
+       std::vector<EvaluationValue_> vals;
        for (auto &a : args)
                vals.push_back(a->evaluate());
 
        switch (kind) {
        case Kind::IN:
-               return EvaluationContext::getCurrentEvaluationContext().evaluateIn(location(), vals[1], vals[0]);
+               return vals[1].contains(vals[0]);
        case Kind::NOT:
-               return !bool(vals[0]);
+               return !vals[0];
        case Kind::MINUS:
-               return EvaluationContext::getCurrentEvaluationContext().evaluateMinus(location(), vals[0]);
+               return -vals[0];
        case Kind::GET:
-               return EvaluationContext::getCurrentEvaluationContext().evaluateAccessGet(location(), vals);
+               if (vals.size() == 2) return vals[0].index_get(vals[1]);
+               ASSERT(vals.size() == 3);
+               return vals[0].index_get(vals[1], vals[2]);
        case Kind::SET:
-               return EvaluationContext::getCurrentEvaluationContext().evaluateAccessSet(location(), std::move(vals));
+               if (vals.size() == 3) return vals[0].index_set(vals[1], vals[1]);
+               ASSERT(vals.size() == 4);
+               return vals[0].index_set(vals[1], vals[2], vals[3]);
        }
        ASSERT(0);
        throw EvaluationFailure{} << "unknown operator";
@@ -347,9 +358,9 @@ void OperatorEvaluator::printSelfInfo(std::ostringstream &os, unsigned int depth
 CompOperatorEvaluator::CompOperatorEvaluator(TokenLocation tokenLocation, ExprPtrs args, std::vector<Kind> kinds, std::vector<TokenLocation> locations) :
        ExpressionEvaluator(std::move(tokenLocation)), args(std::move(args)), kinds(kinds), locations(std::move(locations)) { }
 
-EvaluationValue CompOperatorEvaluator::evaluateImpl() const
+EvaluationValue_ CompOperatorEvaluator::evaluateImpl() const
 {
-       auto cmp = [](const EvaluationValue & l, const EvaluationValue & r, Kind kind) {
+       auto cmp = [](const EvaluationValue_ & l, const EvaluationValue_ & r, const TokenLocation & loc, Kind kind) {
                switch (kind) {
                case Kind::EQ:
                        return l == r;
@@ -369,7 +380,8 @@ EvaluationValue CompOperatorEvaluator::evaluateImpl() const
        auto l = args[0]->evaluate();
        for (auto i = 0u; i < kinds.size(); ++i) {
                auto r = args[i + 1]->evaluate();
-               if (!cmp(l, r, kinds[i])) return false;
+               if (!cmp(l, r, locations[i], kinds[i]))
+                       return false;
                l = std::move(r);
        }
        return true;
@@ -419,7 +431,7 @@ void CompOperatorEvaluator::printSelfInfo(std::ostringstream &os, unsigned int d
 BooleanEvaluator::BooleanEvaluator(TokenLocation tokenLocation, bool value) :
        ExpressionEvaluator(std::move(tokenLocation)), value(std::move(value)) { }
 
-EvaluationValue BooleanEvaluator::evaluateImpl() const
+EvaluationValue_ BooleanEvaluator::evaluateImpl() const
 {
        return value;
 }
@@ -433,20 +445,19 @@ void BooleanEvaluator::printSelfInfo(std::ostringstream &os, unsigned int depth)
 CallEvaluator::CallEvaluator(TokenLocation tokenLocation, ExprPtr function, ExprPtrs args) :
        ExpressionEvaluator(tokenLocation), function(std::move(function)), args(std::move(args)) { }
 
-EvaluationValue CallEvaluator::evaluateImpl() const
+EvaluationValue_ CallEvaluator::evaluateImpl() const
 {
-       std::vector<EvaluationValue> values;
+       std::vector<EvaluationValue_> values;
        values.reserve(args.size());
        for (auto &arg : args) {
                values.push_back(arg->evaluate());
        }
-       return EvaluationContext::getCurrentEvaluationContext().callFunction(location(), function->evaluate(), std::move(values));
+       return function->evaluate()(values);
 }
 
 void CallEvaluator::printSelfInfo(std::ostringstream &os, unsigned int depth) const
 {
-       printLocationAndIndent(os, location(), depth) << "call\n";
-       printLocationAndIndent(os, location(), depth) << "function set is\n";
+       printLocationAndIndent(os, location(), depth) << "function call\n";
        function->printSelfInfo(os, depth + 1);
        for (auto i = 0u; i < args.size(); ++i) {
                printLocationAndIndent(os, location(), depth) << "arg " << i << " is\n";
index 3c9a836..31fdff9 100644 (file)
 #include <unordered_map>
 #include <sstream>
 
-class EvaluationContext;
-class EvaluationValue;
-class TokenLocation;
-class Evaluator;
+class EvaluationValue_;
 
 /**
  * @brief Class for printing debug information, when evaluation batch
@@ -115,7 +112,7 @@ public:
         * Calling this function will evaluate given expression (by calling evaluateImpl).
         * It will also deal with debug printing (if any).
         */
-       EvaluationValue evaluate() const;
+       EvaluationValue_ evaluate() const;
 protected:
        /**
         * @brief Virtual evaluation function.
@@ -123,7 +120,7 @@ protected:
         * Calling this function will evaluate given expression, including it's all children,
         * and return produced value. Might raise an EvaluationFailure exception.
         */
-       virtual EvaluationValue evaluateImpl() const = 0;
+       virtual EvaluationValue_ evaluateImpl() const = 0;
 };
 
 /**
@@ -169,10 +166,11 @@ using StatPtrs = std::vector<StatPtr>;
 class IdentifierEvaluator : public ExpressionEvaluator
 {
        std::string identifier;
+protected:
+       EvaluationValue_ evaluateImpl() const override;
 public:
        IdentifierEvaluator(TokenLocation location_, std::string identifier);
 
-       EvaluationValue evaluateImpl() const override;
        void printSelfInfo(std::ostringstream &os, unsigned int depth) const override;
 };
 
@@ -187,10 +185,11 @@ class AttributeEvaluator : public ExpressionEvaluator
 {
        ExprPtr self;
        std::string identifier;
+protected:
+       EvaluationValue_ evaluateImpl() const override;
 public:
        AttributeEvaluator(TokenLocation location_, ExprPtr self, std::string identifier);
 
-       EvaluationValue evaluateImpl() const override;
        void printSelfInfo(std::ostringstream &os, unsigned int depth) const override;
 };
 
@@ -205,10 +204,11 @@ class AttributeSetterEvaluator : public ExpressionEvaluator
 {
        ExprPtr self, value;
        std::string identifier;
+protected:
+       EvaluationValue_ evaluateImpl() const override;
 public:
        AttributeSetterEvaluator(TokenLocation location_, ExprPtr self, std::string identifier, ExprPtr value);
 
-       EvaluationValue evaluateImpl() const override;
        void printSelfInfo(std::ostringstream &os, unsigned int depth) const override;
 };
 
@@ -222,10 +222,11 @@ class SetterEvaluator : public ExpressionEvaluator
 {
        ExprPtr value;
        std::string identifier;
+protected:
+       EvaluationValue_ evaluateImpl() const override;
 public:
        SetterEvaluator(TokenLocation location_, std::string identifier, ExprPtr value);
 
-       EvaluationValue evaluateImpl() const override;
        void printSelfInfo(std::ostringstream &os, unsigned int depth) const override;
 };
 
@@ -238,10 +239,11 @@ public:
 class PointEvaluator : public ExpressionEvaluator
 {
        ExprPtr x, y;
+protected:
+       EvaluationValue_ evaluateImpl() const override;
 public:
        PointEvaluator(TokenLocation location_, ExprPtr x, ExprPtr y);
 
-       EvaluationValue evaluateImpl() const override;
        void printSelfInfo(std::ostringstream &os, unsigned int depth) const override;
 };
 
@@ -250,11 +252,12 @@ public:
  */
 class IntegerEvaluator : public ExpressionEvaluator
 {
-       int value;
+       int64_t value;
+protected:
+       EvaluationValue_ evaluateImpl() const override;
 public:
-       IntegerEvaluator(TokenLocation location_, int value);
+       IntegerEvaluator(TokenLocation location_, int64_t value);
 
-       EvaluationValue evaluateImpl() const override;
        void printSelfInfo(std::ostringstream &os, unsigned int depth) const override;
 };
 
@@ -264,10 +267,11 @@ public:
 class DoubleEvaluator : public ExpressionEvaluator
 {
        double value;
+protected:
+       EvaluationValue_ evaluateImpl() const override;
 public:
        DoubleEvaluator(TokenLocation location_, double value);
 
-       EvaluationValue evaluateImpl() const override;
        void printSelfInfo(std::ostringstream &os, unsigned int depth) const override;
 };
 
@@ -277,10 +281,11 @@ public:
 class BooleanEvaluator : public ExpressionEvaluator
 {
        bool value;
+protected:
+       EvaluationValue_ evaluateImpl() const override;
 public:
        BooleanEvaluator(TokenLocation location_, bool value);
 
-       EvaluationValue evaluateImpl() const override;
        void printSelfInfo(std::ostringstream &os, unsigned int depth) const override;
 };
 
@@ -290,10 +295,11 @@ public:
 class StringEvaluator : public ExpressionEvaluator
 {
        std::string value;
+protected:
+       EvaluationValue_ evaluateImpl() const override;
 public:
        StringEvaluator(TokenLocation location_, std::string value);
 
-       EvaluationValue evaluateImpl() const override;
        void printSelfInfo(std::ostringstream &os, unsigned int depth) const override;
 };
 
@@ -306,13 +312,14 @@ public:
  */
 class ArraySetDictEvaluator : public ExpressionEvaluator
 {
+protected:
+       EvaluationValue_ evaluateImpl() const override;
 public:
        enum class Kind {
                SET, VECTOR, DICT
        };
        ArraySetDictEvaluator(TokenLocation location_, ExprPtrs values, Kind kind);
 
-       EvaluationValue evaluateImpl() const override;
        void printSelfInfo(std::ostringstream &os, unsigned int depth) const override;
 private:
        ExprPtrs values;
@@ -330,10 +337,11 @@ class CallEvaluator : public ExpressionEvaluator
 {
        ExprPtr function;
        ExprPtrs args;
+protected:
+       EvaluationValue_ evaluateImpl() const override;
 public:
        CallEvaluator(TokenLocation location_, ExprPtr function, ExprPtrs args);
 
-       EvaluationValue evaluateImpl() const override;
        void printSelfInfo(std::ostringstream &os, unsigned int depth) const override;
 };
 
@@ -346,13 +354,14 @@ public:
  */
 class OperatorEvaluator : public ExpressionEvaluator
 {
+protected:
+       EvaluationValue_ evaluateImpl() const override;
 public:
        enum class Kind {
                IN, GET, SET, MINUS, NOT
        };
        OperatorEvaluator(TokenLocation location_, ExprPtrs args, Kind kind);
 
-       EvaluationValue evaluateImpl() const override;
        void printSelfInfo(std::ostringstream &os, unsigned int depth) const override;
 private:
        ExprPtrs args;
@@ -370,13 +379,14 @@ private:
  */
 class CompOperatorEvaluator : public ExpressionEvaluator
 {
+protected:
+       EvaluationValue_ evaluateImpl() const override;
 public:
        enum class Kind {
                EQ, NE, LE, LT, GE, GT
        };
        CompOperatorEvaluator(TokenLocation location_, ExprPtrs args, std::vector<Kind> kinds, std::vector<TokenLocation> locations);
 
-       EvaluationValue evaluateImpl() const override;
        void printSelfInfo(std::ostringstream &os, unsigned int depth) const override;
 private:
        ExprPtrs args;
index c5d1283..77c385a 100644 (file)
@@ -21,8 +21,8 @@
 #include "batch/Evaluator.hpp"
 #include <sstream>
 
-using VarsType = std::unordered_map<std::string, EvaluationValue>;
-using ActsType = std::unordered_map<std::string, detail::FunctionType>;
+using VarsType = std::unordered_map<std::string, EvaluationValue_>;
+using ActsType = std::unordered_map<std::string, EvaluationValueFunction>;
 
 struct TestExecutor : ExecutorInterface {
        TestExecutor(VarsType variables = {}, ActsType activities = {},
@@ -31,7 +31,7 @@ struct TestExecutor : ExecutorInterface {
                variables(std::move(variables)), activities(std::move(activities)),
                pointToUI(std::move(pointToUI)), stringToUI(std::move(stringToUI)) { }
 
-       EvaluationValue getVariableByName(const std::string &name) override
+       EvaluationValue_ getVariableByName(const std::string &name) override
        {
                auto it = variables.find(name);
                if (it == variables.end()) throw EvaluationFailure{} << "no variable " << name;
@@ -120,22 +120,13 @@ TEST(TestExec, simpleParser)
        ASSERT_TRUE(result);
 
        std::string result2;
-       auto vars = VarsType {
-               {
-                       "foo", detail::UserFunctionType<int, std::string, std::string, bool>{
-                               [&](int v1, std::string v2, std::string v3, bool v4) -> EvaluationValue {
-                                       return std::to_string(v1) + "," + v2 + "," + v3 + "," + (v4 ? "true" : "false");
-                               }
-                       }
-               },
-               {
-                       "bar", detail::UserFunctionType<std::string>{
-                               [&](std::string value) -> EvaluationValue {
-                                       result2 = value;
-                                       return nullptr;
-                               }
-                       }
-               },
+       VarsType vars;
+       vars["foo"] = [&](int v1, std::string v2, std::string v3, bool v4) -> EvaluationValue_ {
+               return std::to_string(v1) + "," + v2 + "," + v3 + "," + (v4 ? "true" : "false");
+       };
+       vars["bar"] = [&](std::string value) -> EvaluationValue_ {
+               result2 = value;
+               return {};
        };
        TestExecutor exec(std::move(vars));
        EvaluationContext ec { exec };
@@ -194,18 +185,14 @@ protected:
                size_t callCount = 0;
                auto vars = VarsType { };
                std::ostringstream output;
-               vars["assert"] = detail::UserFunctionType<bool> {
-                       [&](bool val) -> EvaluationValue {
-                               if (!val) throw EvaluationFailure{} << "assertion failed2";
-                               ++callCount;
-                               return {};
-                       }
+               vars["assert"] = [&](bool val) -> EvaluationValue_ {
+                       if (!val) throw EvaluationFailure{} << "assertion failed";
+                       ++callCount;
+                       return {};
                };
-               vars["print"] = detail::UserFunctionType<EvaluationValue> {
-                       [&](EvaluationValue val) -> EvaluationValue {
-                               output << ">>> " << val << "\n";
-                               return {};
-                       }
+               vars["print"] = [&](EvaluationValue_ val) -> EvaluationValue_ {
+                       output << ">>> " << val << "\n";
+                       return {};
                };
                TestExecutor exec{ std::move(vars) };
                EvaluationContext ec{ exec };
@@ -248,7 +235,39 @@ TEST_F(ScriptTest, simpleComparisions)
                "assert(1 < 2 > 1)\n"
                "assert(1 < 2 < 3)\n"
                "assert(not (1 > 2))\n"
-               , 12);
+
+               "assert(1.0 == 1)\n"
+               "assert(1.0 != 2)\n"
+               "assert(1.0 < 2)\n"
+               "assert(1.0 > -1)\n"
+               "assert(1.0 <= 2)\n"
+               "assert(1.0 <= 1)\n"
+               "assert(1.0 >= -1)\n"
+               "assert(1.0 >= 1)\n"
+
+               "assert(1 == 1.0)\n"
+               "assert(1 != 2.0)\n"
+               "assert(1 < 2.0)\n"
+               "assert(1 > -1.0)\n"
+               "assert(1 <= 2.0)\n"
+               "assert(1 <= 1.0)\n"
+               "assert(1 >= -1.0)\n"
+               "assert(1 >= 1.0)\n"
+
+               "assert(1.0 == 1.0)\n"
+               "assert(1.0 != 2.0)\n"
+               "assert(1.0 < 2.0)\n"
+               "assert(1.0 > -1.0)\n"
+               "assert(1.0 <= 2.0)\n"
+               "assert(1.0 <= 1.0)\n"
+               "assert(1.0 >= -1.0)\n"
+               "assert(1.0 >= 1.0)\n"
+
+               "assert(true == true)\n"
+               "assert(false == false)\n"
+               "assert(true != false)\n"
+               "assert(false != true)\n"
+               , 12 + 8 + 8 + 8 + 4);
 }
 
 TEST_F(ScriptTest, vector)