add several major batch mode functionalities 50/206250/8
authorRadoslaw Cybulski <r.cybulski@partner.samsung.com>
Wed, 15 May 2019 11:44:47 +0000 (13:44 +0200)
committerRadoslaw Cybulski <r.cybulski@partner.samsung.com>
Thu, 16 May 2019 14:23:18 +0000 (16:23 +0200)
Logical operators (and / or / not), bit operators (| & ^ ~),
string.join, iterator type support, multiple fingers tap.

Change-Id: I3825388db3107901533e48285f43bab6371b7a65

28 files changed:
CMakeLists.txt
src/batch/BatchRunner.cpp
src/batch/BatchRunner.hpp
src/batch/EvaluationContext.cpp
src/batch/EvaluationContext.hpp
src/batch/EvaluationValue.cpp
src/batch/EvaluationValue.hpp
src/batch/EvaluationValueBase.cpp
src/batch/EvaluationValueBase.hpp
src/batch/EvaluationValueBoolean.cpp
src/batch/EvaluationValueDict.cpp
src/batch/EvaluationValueDouble.cpp
src/batch/EvaluationValueFunction.cpp
src/batch/EvaluationValueInteger.cpp
src/batch/EvaluationValueIterator.cpp [new file with mode: 0644]
src/batch/EvaluationValuePoint.cpp
src/batch/EvaluationValueSet.cpp
src/batch/EvaluationValueString.cpp
src/batch/EvaluationValueUIElement.cpp
src/batch/EvaluationValueVector.cpp
src/batch/EvaluationValueWait.cpp
src/batch/Evaluator.cpp
src/batch/Evaluator.hpp
src/batch/Lexer.cpp
src/batch/Parser.cpp
src/batch/ReturnValue.hpp
src/utils.cpp
tests/no-ui-scenarios/BatchExecTests.cpp

index fbf4ba388234a8be69106ebeebabc48864d63ccd..dd6a6510fac8173bf43bb544637675f8defdd439 100644 (file)
@@ -39,7 +39,7 @@ pkg_check_modules(pkgs REQUIRED
 
 SET(COMMON_FLAGS "-fdiagnostics-color=always -fPIC")
 SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COMMON_FLAGS}")
-SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMMON_FLAGS} -std=c++14")
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMMON_FLAGS} -std=c++14 -g")
 
 # install desktop file & icon
 SET(RES_DIR "${CMAKE_INSTALL_PREFIX}/res")
index 6d1e2d20775904a6c1bbd62c17753701335dd13b..3b71d8fa8ad44f43b7f0a24d42701c4b283addca 100644 (file)
@@ -259,6 +259,41 @@ std::shared_ptr<UIElement> BatchExecutor::convertToUIElement(Point pt)
        });
 }
 
+std::unordered_map<std::string, std::string> BatchExecutor::getUIElementAttributes(const std::shared_ptr<UIElement> &uiElem)
+{
+       return executeOnMainThread([&]() {
+               auto atspi = Singleton<UniversalSwitch>::instance().getAtspi();
+               auto found = atspi->getAttributes(uiElem->getObject());
+               std::unordered_map<std::string, std::string> res;
+               for (auto &it : found)
+                       res.insert(std::move(it));
+               return std::move(res);
+       });
+}
+
+unsigned int BatchExecutor::getUIElementRole(const std::shared_ptr<UIElement> &uiElem)
+{
+       return executeOnMainThread([&]() {
+               auto atspi = Singleton<UniversalSwitch>::instance().getAtspi();
+               auto found = atspi->getRole(uiElem->getObject());
+               if (found)
+                       return static_cast<unsigned int>(*found);
+               throw EvaluationFailure{} << "failed to get at-spi object's role (use dlogutil to get at-spi error message)";
+       });
+}
+
+Atspi::StateSet BatchExecutor::getUIElementStates(const std::shared_ptr<UIElement> &uiElem)
+{
+       return executeOnMainThread([&]() {
+               auto atspi = Singleton<UniversalSwitch>::instance().getAtspi();
+               auto states = atspi->getStateSet(uiElem->getObject());
+               if (states) {
+                       return std::move(*states);
+               }
+               throw EvaluationFailure{} << "failed to get at-spi state set (use dlogutil to get at-spi error message)";
+       });
+}
+
 std::string BatchExecutor::getUIElementName(const std::shared_ptr<UIElement> &uiElem)
 {
        return executeOnMainThread([&]() {
@@ -432,133 +467,130 @@ std::string BatchExecutor::getFileContent(const std::string &filename)
        return std::string(bufor.data(), (size_t)total);
 }
 
-namespace
+//TODO: when switching to c++17 we should use std::filename::path
+std::string getPathRelativeToFile(const std::string &relativePath, const std::string &file)
 {
-       //TODO: when switching to c++17 we should use std::filename::path
-       std::string getPathRelativeToFile(const std::string &relativePath, const std::string &file)
-       {
-               if (!relativePath.empty() && relativePath[0] == '/') {
-                       //not a relative path
-                       return relativePath;
-               }
-               auto pos = file.rfind('/');
-               if (pos == std::string::npos) {
-                       return relativePath;
-               }
-               return file.substr(0, pos + 1) + relativePath;
+       if (!relativePath.empty() && relativePath[0] == '/') {
+               //not a relative path
+               return relativePath;
        }
+       auto pos = file.rfind('/');
+       if (pos == std::string::npos) {
+               return relativePath;
+       }
+       return file.substr(0, pos + 1) + relativePath;
+}
 
-       std::string errorToStr(int err)
-       {
-               std::ostringstream tmp;
-               bool first = true;
+std::string errorToStr(int err)
+{
+       std::ostringstream tmp;
+       bool first = true;
 #define Q(a) \
        if (a == err) { \
                if (first) first = false; \
                else tmp << ", "; \
                tmp << #a; \
        }
-               Q(TIZEN_ERROR_NONE)
-               Q(TIZEN_ERROR_NOT_PERMITTED)
-               Q(TIZEN_ERROR_NO_SUCH_FILE)
-               Q(TIZEN_ERROR_NO_SUCH_PROCESS)
-               Q(TIZEN_ERROR_INTERRUPTED_SYS_CALL)
-               Q(TIZEN_ERROR_IO_ERROR)
-               Q(TIZEN_ERROR_NO_SUCH_DEVICE)
-               Q(TIZEN_ERROR_ARGUMENT_LIST_TOO_LONG)
-               Q(TIZEN_ERROR_EXEC_FORMAT_ERROR)
-               Q(TIZEN_ERROR_BAD_FILE_NUMBER)
-               Q(TIZEN_ERROR_TRY_AGAIN)
-               Q(TIZEN_ERROR_OUT_OF_MEMORY)
-               Q(TIZEN_ERROR_PERMISSION_DENIED)
-               Q(TIZEN_ERROR_BAD_ADDRESS)
-               Q(TIZEN_ERROR_BLOCK_DEVICE_REQUIRED)
-               Q(TIZEN_ERROR_RESOURCE_BUSY)
-               Q(TIZEN_ERROR_FILE_EXISTS)
-               Q(TIZEN_ERROR_CROSS_DEVICE_LINK)
-               Q(TIZEN_ERROR_NOT_A_DIRECTORY)
-               Q(TIZEN_ERROR_IS_A_DIRECTORY)
-               Q(TIZEN_ERROR_INVALID_PARAMETER)
-               Q(TIZEN_ERROR_FILE_TABLE_OVERFLOW)
-               Q(TIZEN_ERROR_TOO_MANY_OPEN_FILES)
-               Q(TIZEN_ERROR_TOO_NOT_A_TERMINAL)
-               Q(TIZEN_ERROR_TOO_TEXT_FILE_BUSY)
-               Q(TIZEN_ERROR_FILE_TOO_LARGE)
-               Q(TIZEN_ERROR_FILE_NO_SPACE_ON_DEVICE)
-               Q(TIZEN_ERROR_ILLEGAL_SEEK)
-               Q(TIZEN_ERROR_READ_ONLY_FILESYSTEM)
-               Q(TIZEN_ERROR_NO_DATA)
-               Q(TIZEN_ERROR_TOO_MANY_LINKS)
-               Q(TIZEN_ERROR_BROKEN_PIPE)
-               Q(TIZEN_ERROR_ARGUMENT_OUT_OF_DOMAIN)
-               Q(TIZEN_ERROR_RESULT_OUT_OF_RANGE)
-               Q(TIZEN_ERROR_WOULD_CAUSE_DEADLOCK)
-               Q(TIZEN_ERROR_FILE_NAME_TOO_LONG)
-               Q(TIZEN_ERROR_FILE_NO_LOCKS_AVAILABLE)
-               Q(TIZEN_ERROR_INVALID_OPERATION)
-               Q(TIZEN_ERROR_DIR_NOT_EMPTY)
-               Q(TIZEN_ERROR_TOO_MANY_SYMBOLIC_LINKS)
-               Q(TIZEN_ERROR_WOULD_BLOCK)
-               Q(TIZEN_ERROR_CORRUPTED_SHARED_LIB)
-               Q(TIZEN_ERROR_LIB_SECTION_CORRUPTED)
-               Q(TIZEN_ERROR_LINK_TOO_MANY_SHARED_LIB)
-               Q(TIZEN_ERROR_SHARED_LIB_EXEC)
-               Q(TIZEN_ERROR_ILLEGAL_BYTE_SEQ)
-               Q(TIZEN_ERROR_SYSTEM_CALL_RESTART)
-               Q(TIZEN_ERROR_STREAMS_PIPE)
-               Q(TIZEN_ERROR_TOO_MANY_USERS)
-               Q(TIZEN_ERROR_NON_SOCKET)
-               Q(TIZEN_ERROR_NO_DEST_ADDRESS)
-               Q(TIZEN_ERROR_MSG_TOO_LONG)
-               Q(TIZEN_ERROR_PROTOCOL_WRONG_TYPE)
-               Q(TIZEN_ERROR_PROTOCOL_NOT_AVALIABLE)
-               Q(TIZEN_ERROR_PROTOCOL_NOT_SUPPORTED)
-               Q(TIZEN_ERROR_SOCKET_TYPE_NOT_SUPPORTED)
-               Q(TIZEN_ERROR_ENDPOINT_OPERATIN_NOT_SUPPORTED)
-               Q(TIZEN_ERROR_PROTOCOL_FAMILY_NOT_SUPPORTED)
-               Q(TIZEN_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED)
-               Q(TIZEN_ERROR_ADDRES_IN_USE)
-               Q(TIZEN_ERROR_CANNOT_ASSIGN_ADDRESS)
-               Q(TIZEN_ERROR_NETWORK_DOWN)
-               Q(TIZEN_ERROR_NETWORK_UNREACHABLE)
-               Q(TIZEN_ERROR_NETWORK_RESET)
-               Q(TIZEN_ERROR_CONNECTION_ABORTED)
-               Q(TIZEN_ERROR_CONNECTION_RESET_BY_PEER)
-               Q(TIZEN_ERROR_BUFFER_SPACE)
-               Q(TIZEN_ERROR_ENDPOINT_CONNECTED)
-               Q(TIZEN_ERROR_ENDPOINT_NOT_CONNECTED)
-               Q(TIZEN_ERROR_ENDPOINT_SHUTDOWN)
-               Q(TIZEN_ERROR_TOO_MANY_REFERENCES)
-               Q(TIZEN_ERROR_CONNECTION_TIME_OUT)
-               Q(TIZEN_ERROR_CONNECTION_REFUSED)
-               Q(TIZEN_ERROR_HOST_DOWN)
-               Q(TIZEN_ERROR_NO_ROUTE_TO_HOST)
-               Q(TIZEN_ERROR_ALREADY_IN_PROGRESS)
-               Q(TIZEN_ERROR_NOW_IN_PROGRESS)
-               Q(TIZEN_ERROR_STALE_NFS_FILE_HANDLE)
-               Q(TIZEN_ERROR_STRUCTURE_UNCLEAN)
-               Q(TIZEN_ERROR_NOT_XENIX_NAMED_TYPE_FILE)
-               Q(TIZEN_ERROR_NO_XENIX_SEMAPHORES_AVAILABLE)
-               Q(TIZEN_ERROR_IS_NAMED_TYPE_FILE)
-               Q(TIZEN_ERROR_REMOTE_IO)
-               Q(TIZEN_ERROR_QUOTA_EXCEEDED)
-               Q(TIZEN_ERROR_NO_MEDIUM)
-               Q(TIZEN_ERROR_WRONG_MEDIUM_TYPE)
-               Q(TIZEN_ERROR_CANCELED)
-               Q(TIZEN_ERROR_KEY_NOT_AVAILABLE)
-               Q(TIZEN_ERROR_KEY_EXPIRED)
-               Q(TIZEN_ERROR_KEY_REVOKED)
-               Q(TIZEN_ERROR_KEY_REJECTED)
-               Q(TIZEN_ERROR_OWNER_DEAD)
-               Q(TIZEN_ERROR_UNKNOWN)
-               Q(TIZEN_ERROR_TIMED_OUT)
-               Q(TIZEN_ERROR_NOT_SUPPORTED)
-               Q(TIZEN_ERROR_USER_NOT_CONSENTED)
-               Q(TIZEN_ERROR_DEVICE_POLICY_RESTRICTION)
-               Q(TIZEN_ERROR_END_OF_COLLECTION)
+       Q(TIZEN_ERROR_NONE)
+       Q(TIZEN_ERROR_NOT_PERMITTED)
+       Q(TIZEN_ERROR_NO_SUCH_FILE)
+       Q(TIZEN_ERROR_NO_SUCH_PROCESS)
+       Q(TIZEN_ERROR_INTERRUPTED_SYS_CALL)
+       Q(TIZEN_ERROR_IO_ERROR)
+       Q(TIZEN_ERROR_NO_SUCH_DEVICE)
+       Q(TIZEN_ERROR_ARGUMENT_LIST_TOO_LONG)
+       Q(TIZEN_ERROR_EXEC_FORMAT_ERROR)
+       Q(TIZEN_ERROR_BAD_FILE_NUMBER)
+       Q(TIZEN_ERROR_TRY_AGAIN)
+       Q(TIZEN_ERROR_OUT_OF_MEMORY)
+       Q(TIZEN_ERROR_PERMISSION_DENIED)
+       Q(TIZEN_ERROR_BAD_ADDRESS)
+       Q(TIZEN_ERROR_BLOCK_DEVICE_REQUIRED)
+       Q(TIZEN_ERROR_RESOURCE_BUSY)
+       Q(TIZEN_ERROR_FILE_EXISTS)
+       Q(TIZEN_ERROR_CROSS_DEVICE_LINK)
+       Q(TIZEN_ERROR_NOT_A_DIRECTORY)
+       Q(TIZEN_ERROR_IS_A_DIRECTORY)
+       Q(TIZEN_ERROR_INVALID_PARAMETER)
+       Q(TIZEN_ERROR_FILE_TABLE_OVERFLOW)
+       Q(TIZEN_ERROR_TOO_MANY_OPEN_FILES)
+       Q(TIZEN_ERROR_TOO_NOT_A_TERMINAL)
+       Q(TIZEN_ERROR_TOO_TEXT_FILE_BUSY)
+       Q(TIZEN_ERROR_FILE_TOO_LARGE)
+       Q(TIZEN_ERROR_FILE_NO_SPACE_ON_DEVICE)
+       Q(TIZEN_ERROR_ILLEGAL_SEEK)
+       Q(TIZEN_ERROR_READ_ONLY_FILESYSTEM)
+       Q(TIZEN_ERROR_NO_DATA)
+       Q(TIZEN_ERROR_TOO_MANY_LINKS)
+       Q(TIZEN_ERROR_BROKEN_PIPE)
+       Q(TIZEN_ERROR_ARGUMENT_OUT_OF_DOMAIN)
+       Q(TIZEN_ERROR_RESULT_OUT_OF_RANGE)
+       Q(TIZEN_ERROR_WOULD_CAUSE_DEADLOCK)
+       Q(TIZEN_ERROR_FILE_NAME_TOO_LONG)
+       Q(TIZEN_ERROR_FILE_NO_LOCKS_AVAILABLE)
+       Q(TIZEN_ERROR_INVALID_OPERATION)
+       Q(TIZEN_ERROR_DIR_NOT_EMPTY)
+       Q(TIZEN_ERROR_TOO_MANY_SYMBOLIC_LINKS)
+       Q(TIZEN_ERROR_WOULD_BLOCK)
+       Q(TIZEN_ERROR_CORRUPTED_SHARED_LIB)
+       Q(TIZEN_ERROR_LIB_SECTION_CORRUPTED)
+       Q(TIZEN_ERROR_LINK_TOO_MANY_SHARED_LIB)
+       Q(TIZEN_ERROR_SHARED_LIB_EXEC)
+       Q(TIZEN_ERROR_ILLEGAL_BYTE_SEQ)
+       Q(TIZEN_ERROR_SYSTEM_CALL_RESTART)
+       Q(TIZEN_ERROR_STREAMS_PIPE)
+       Q(TIZEN_ERROR_TOO_MANY_USERS)
+       Q(TIZEN_ERROR_NON_SOCKET)
+       Q(TIZEN_ERROR_NO_DEST_ADDRESS)
+       Q(TIZEN_ERROR_MSG_TOO_LONG)
+       Q(TIZEN_ERROR_PROTOCOL_WRONG_TYPE)
+       Q(TIZEN_ERROR_PROTOCOL_NOT_AVALIABLE)
+       Q(TIZEN_ERROR_PROTOCOL_NOT_SUPPORTED)
+       Q(TIZEN_ERROR_SOCKET_TYPE_NOT_SUPPORTED)
+       Q(TIZEN_ERROR_ENDPOINT_OPERATIN_NOT_SUPPORTED)
+       Q(TIZEN_ERROR_PROTOCOL_FAMILY_NOT_SUPPORTED)
+       Q(TIZEN_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED)
+       Q(TIZEN_ERROR_ADDRES_IN_USE)
+       Q(TIZEN_ERROR_CANNOT_ASSIGN_ADDRESS)
+       Q(TIZEN_ERROR_NETWORK_DOWN)
+       Q(TIZEN_ERROR_NETWORK_UNREACHABLE)
+       Q(TIZEN_ERROR_NETWORK_RESET)
+       Q(TIZEN_ERROR_CONNECTION_ABORTED)
+       Q(TIZEN_ERROR_CONNECTION_RESET_BY_PEER)
+       Q(TIZEN_ERROR_BUFFER_SPACE)
+       Q(TIZEN_ERROR_ENDPOINT_CONNECTED)
+       Q(TIZEN_ERROR_ENDPOINT_NOT_CONNECTED)
+       Q(TIZEN_ERROR_ENDPOINT_SHUTDOWN)
+       Q(TIZEN_ERROR_TOO_MANY_REFERENCES)
+       Q(TIZEN_ERROR_CONNECTION_TIME_OUT)
+       Q(TIZEN_ERROR_CONNECTION_REFUSED)
+       Q(TIZEN_ERROR_HOST_DOWN)
+       Q(TIZEN_ERROR_NO_ROUTE_TO_HOST)
+       Q(TIZEN_ERROR_ALREADY_IN_PROGRESS)
+       Q(TIZEN_ERROR_NOW_IN_PROGRESS)
+       Q(TIZEN_ERROR_STALE_NFS_FILE_HANDLE)
+       Q(TIZEN_ERROR_STRUCTURE_UNCLEAN)
+       Q(TIZEN_ERROR_NOT_XENIX_NAMED_TYPE_FILE)
+       Q(TIZEN_ERROR_NO_XENIX_SEMAPHORES_AVAILABLE)
+       Q(TIZEN_ERROR_IS_NAMED_TYPE_FILE)
+       Q(TIZEN_ERROR_REMOTE_IO)
+       Q(TIZEN_ERROR_QUOTA_EXCEEDED)
+       Q(TIZEN_ERROR_NO_MEDIUM)
+       Q(TIZEN_ERROR_WRONG_MEDIUM_TYPE)
+       Q(TIZEN_ERROR_CANCELED)
+       Q(TIZEN_ERROR_KEY_NOT_AVAILABLE)
+       Q(TIZEN_ERROR_KEY_EXPIRED)
+       Q(TIZEN_ERROR_KEY_REVOKED)
+       Q(TIZEN_ERROR_KEY_REJECTED)
+       Q(TIZEN_ERROR_OWNER_DEAD)
+       Q(TIZEN_ERROR_UNKNOWN)
+       Q(TIZEN_ERROR_TIMED_OUT)
+       Q(TIZEN_ERROR_NOT_SUPPORTED)
+       Q(TIZEN_ERROR_USER_NOT_CONSENTED)
+       Q(TIZEN_ERROR_DEVICE_POLICY_RESTRICTION)
+       Q(TIZEN_ERROR_END_OF_COLLECTION)
 #undef Q
-               return tmp.str();
-       }
+       return tmp.str();
 }
 
 void BatchExecutor::killApplication(const std::pair<std::string, std::string> &appInstance)
@@ -770,6 +802,12 @@ void BatchExecutor::insertMethods()
                        return {};
                },  { {"text"} } };
 
+       variables["str"] = EvaluationValueFunction{ [&](EvaluationValue e) -> EvaluationValue {
+                       std::ostringstream tmp;
+                       tmp << e;
+                       return tmp.str();
+               },  { {"value"} } };
+
        variables["len"] = EvaluationValueFunction{ [&](EvaluationValue e) -> EvaluationValue {
                        if (e.isString()) return static_cast<int>(e.asString().size());
                        if (e.isVector()) return static_cast<int>(e.asVector().size());
@@ -851,7 +889,7 @@ void BatchExecutor::insertMethods()
                Optional<EvaluationValue> defValue;
                if (tapCount > 1)
                        defValue = EvaluationValuePoint{ 300, 300 };
-               return EvaluationValueFunction{ [ &, tapCount](EvaluationValue target) -> EvaluationValue {
+               return EvaluationValueFunction{ [ &, tapCount](EvaluationValue target, EvaluationValue fingers) -> EvaluationValue {
                                auto root = getVisibleRoot();
                                if (!root) throw EvaluationFailure{} << "no visible root (context changed didn't happen)";
                                ASSERT(root->getObject());
@@ -860,13 +898,16 @@ void BatchExecutor::insertMethods()
                                        target = this->convertToUIElement(target.convertToString());
                                }
                                auto dest = target.convertToUIElement();
+                               auto fingerCount = fingers.convertToInteger();
+                               if (fingerCount <= 0 || fingerCount > 3)
+                                       throw EvaluationFailure{} << "invalid finger count (must be between 1 and 3)";
 
                                auto sleep_until = std::chrono::high_resolution_clock::now() + std::chrono::milliseconds{ 400 };
                                for (auto i = 0u; i < tapCount; ++i)
                                {
                                        executeOnMainThread([&]() {
                                                auto coord = dest->getScanningCoordinates();
-                                               auto res = utils::generateTapGesture(coord.x, coord.y, 0.0f);
+                                               auto res = utils::generateTapGesture(coord.x, coord.y, 0.0f, fingerCount);
                                                if (!res)
                                                        throw EvaluationFailure{} << "failed to execute " << tapCount << " tap gesture, " << res.getError().message;
                                        });
@@ -874,7 +915,7 @@ void BatchExecutor::insertMethods()
                                std::this_thread::sleep_until(sleep_until);
 
                                return EvaluationValue{};
-                       }, { { "target" } } };
+                       }, { { "target", defValue }, { "fingers", 1 } } };
        };
        variables["TAP"] = generateTapFunction(1);
        variables["DOUBLE_TAP"] = generateTapFunction(2);
@@ -1377,6 +1418,10 @@ static void threadFunc(StatPtr result, std::unique_ptr<BatchExecutor> exec, std:
                        exec->outputStream() << "evaluation successed\n";
                } catch (ReturnValue &r) {
                        exec->outputStream() << "script returned: " << r.getResult();
+               } catch (ContinueValue) {
+                       exec->outputStream() << "unhandled continue statement";
+               } catch (BreakValue &r) {
+                       exec->outputStream() << "unhandled break statement";
                } catch (EvaluationFailure &e) {
                        if (e.hasLocation())
                                exec->outputStream() << e.location().toString() << ": ";
index 43d76a25fb8aff15bd460e6188b824cb0463559e..6d18fc4a76f7cd5eceac8cd2217957c0a5baf40e 100644 (file)
@@ -93,6 +93,9 @@ public:
        std::shared_ptr<UIElement> getVisibleRoot() override;
        std::shared_ptr<UIElement> convertToUIElement(Point pt) override;
        std::string getUIElementName(const std::shared_ptr<UIElement> &uiElem) override;
+       Atspi::StateSet getUIElementStates(const std::shared_ptr<UIElement> &o) override;
+       unsigned int getUIElementRole(const std::shared_ptr<UIElement> &o) override;
+       std::unordered_map<std::string, std::string> getUIElementAttributes(const std::shared_ptr<UIElement> &o) override;
        std::string getUIElementUniqueId(const std::shared_ptr<UIElement> &uiElem) override;
        std::shared_ptr<UIElement> convertToUIElement(const std::string &requestedName) override;
 
index 94fd7aa3201f72946acbc0332a83a21d8304a0eb..5e2c75b21b10e1eb2beba7ed64dc6b5e5cb6813b 100644 (file)
@@ -93,6 +93,18 @@ const std::string &EvaluationContext::topBatchPath()
        return *batchPathStack.back();
 }
 
+Atspi::StateSet ExecutorInterface::getUIElementStates(const std::shared_ptr<UIElement> &o)
+{
+       throw EvaluationFailure{} << "getUIElementStates not implemeneted";
+}
+unsigned int ExecutorInterface::getUIElementRole(const std::shared_ptr<UIElement> &o)
+{
+       throw EvaluationFailure{} << "getUIElementRole not implemeneted";
+}
+std::unordered_map<std::string, std::string> ExecutorInterface::getUIElementAttributes(const std::shared_ptr<UIElement> &o)
+{
+       throw EvaluationFailure{} << "getUIElementAttributes not implemeneted";
+}
 
 std::string ExecutorInterface::getUIElementName(const std::shared_ptr<UIElement> &elem)
 {
index 9d5b2a6a7d237909e642fe6d49fbadb52b3a22b5..4d007d852da46c6cf155d5a807ff7ec418229ea5 100644 (file)
@@ -77,6 +77,10 @@ struct ExecutorInterface {
         */
        virtual std::string getUIElementName(const std::shared_ptr<UIElement> &);
 
+       virtual Atspi::StateSet getUIElementStates(const std::shared_ptr<UIElement> &);
+       virtual unsigned int getUIElementRole(const std::shared_ptr<UIElement> &);
+       virtual std::unordered_map<std::string, std::string> getUIElementAttributes(const std::shared_ptr<UIElement> &);
+
        /**
         * @brief Returns string uniquely identifying given at-spi object
         */
index 0ae50acfa4ae97c2099f5c9e30d417062cd5baa1..4881976097a42a2cd43365a0f26c50ff770be023 100644 (file)
@@ -95,6 +95,7 @@ Q(Vector)
 Q(Set)
 Q(Dict)
 Q(Wait)
+Q(Iterator)
 #undef Q
 
 std::string EvaluationValue::typeName() const
@@ -167,6 +168,51 @@ EvaluationValue EvaluationValue::operator - () const
        return value->oper_negate();
 }
 
+EvaluationValue EvaluationValue::operator + (const EvaluationValue &o) const
+{
+       return value->oper_add(o.value);
+}
+EvaluationValue EvaluationValue::operator - (const EvaluationValue &o) const
+{
+       return value->oper_sub(o.value);
+}
+EvaluationValue EvaluationValue::operator / (const EvaluationValue &o) const
+{
+       return value->oper_div(o.value);
+}
+EvaluationValue EvaluationValue::operator * (const EvaluationValue &o) const
+{
+       return value->oper_mul(o.value);
+}
+EvaluationValue EvaluationValue::operator % (const EvaluationValue &o) const
+{
+       return value->oper_mod(o.value);
+}
+EvaluationValue EvaluationValue::operator & (const EvaluationValue &o) const
+{
+       return value->oper_bit_and(o.value);
+}
+EvaluationValue EvaluationValue::operator | (const EvaluationValue &o) const
+{
+       return value->oper_bit_or(o.value);
+}
+EvaluationValue EvaluationValue::operator ^ (const EvaluationValue &o) const
+{
+       return value->oper_bit_xor(o.value);
+}
+EvaluationValue EvaluationValue::operator << (const EvaluationValue &o) const
+{
+       return value->oper_lshift(o.value);
+}
+EvaluationValue EvaluationValue::operator >> (const EvaluationValue &o) const
+{
+       return value->oper_rshift(o.value);
+}
+EvaluationValue EvaluationValue::operator ~() const
+{
+       return value->oper_bit_neg();
+}
+
 EvaluationValue EvaluationValue::attr_get(const std::string &name) const
 {
        return value->oper_attr_get(name);
@@ -176,6 +222,32 @@ EvaluationValue EvaluationValue::attr_set(const std::string &name, const Evaluat
        return value->oper_attr_set(name, val.value);
 }
 
+EvaluationValue EvaluationValue::iterate() const
+{
+       return value->convertToIterator();
+}
+
+EvaluationValue EvaluationValue::iterator_get_current() const
+{
+       return value->iterator_get();
+}
+
+void EvaluationValue::iterator_next() const
+{
+       value->iterator_next();
+}
+
+Optional<EvaluationValue> EvaluationValueIteratorCopyImpl::get() const
+{
+       if (index >= values.size()) return {};
+       return values[index];
+}
+
+void EvaluationValueIteratorCopyImpl::next()
+{
+       if (index < values.size()) ++index;
+}
+
 std::ostream &operator << (std::ostream &s, const EvaluationValue &v)
 {
        return s << v.value;
index ba20b00fa1c000fe3b0d9709721539f5e2f53706..b16799edc27f5d34215e7d99ab2b5eb7ec3d4ff6 100644 (file)
@@ -62,6 +62,12 @@ private:
        mutable std::string cachedText;
 };
 
+class EvaluationFailureIteratorExhaused : public EvaluationFailure
+{
+public:
+       using EvaluationFailure::EvaluationFailure;
+};
+
 class EvaluationValue;
 
 namespace std
@@ -71,6 +77,8 @@ namespace std
        };
 }
 
+struct EvaluationValueIteratorInterface;
+
 class EvaluationValueWaitInterface;
 class EvaluationContext;
 class EvaluationValueBase;
@@ -87,6 +95,14 @@ class EvaluationValueFunction;
 using EvaluationValueVector = std::vector<EvaluationValue>;
 using EvaluationValueSet = std::unordered_set<EvaluationValue>;
 using EvaluationValueDict = std::unordered_map<EvaluationValue, EvaluationValue>;
+using EvaluationValueIterator = std::shared_ptr<EvaluationValueIteratorInterface>;
+
+struct EvaluationValueIteratorInterface {
+       virtual ~EvaluationValueIteratorInterface() = default;
+
+       virtual Optional<EvaluationValue> get() const = 0;
+       virtual void next() = 0;
+};
 
 class EvaluationValueWaitInterface
 {
@@ -196,6 +212,7 @@ public:
        Q(Set)
        Q(Dict)
        Q(Wait)
+       Q(Iterator)
 #undef Q
 
        std::string typeName() const;
@@ -217,10 +234,25 @@ public:
        EvaluationValue index_set(const EvaluationValue &, const EvaluationValue &, const EvaluationValue &value);
 
        EvaluationValue operator - () const;
+       EvaluationValue operator + (const EvaluationValue &o) const;
+       EvaluationValue operator - (const EvaluationValue &o) const;
+       EvaluationValue operator /(const EvaluationValue &o) const;
+       EvaluationValue operator * (const EvaluationValue &o) const;
+       EvaluationValue operator % (const EvaluationValue &o) const;
+       EvaluationValue operator & (const EvaluationValue &o) const;
+       EvaluationValue operator | (const EvaluationValue &o) const;
+       EvaluationValue operator ^ (const EvaluationValue &o) const;
+       EvaluationValue operator << (const EvaluationValue &o) const;
+       EvaluationValue operator >> (const EvaluationValue &o) const;
+       EvaluationValue operator ~() const;
 
        EvaluationValue attr_get(const std::string &name) const;
        EvaluationValue attr_set(const std::string &name, const EvaluationValue &value);
 
+       EvaluationValue iterate() const;
+       EvaluationValue iterator_get_current() const;
+       void iterator_next() const;
+
        const auto &getInternalValue() const
        {
                return value;
@@ -256,6 +288,18 @@ private:
        }
 };
 
+class EvaluationValueIteratorCopyImpl : public EvaluationValueIteratorInterface
+{
+public:
+       Optional<EvaluationValue> get() const override;
+       void next() override;
+
+       EvaluationValueIteratorCopyImpl(std::vector<EvaluationValue> values) : values(std::move(values)) { }
+private:
+       std::vector<EvaluationValue> values;
+       size_t index = 0;
+};
+
 namespace detail
 {
        template<int ...> struct sequence {};
index e238715d6b2d4909fe664e979eb04b8f3f3f1fa8..15c12cfe5dee26a34ea2df25bb8d40677a52ce3d 100644 (file)
@@ -29,9 +29,9 @@ namespace std
 #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{} << \
+       const EvaluationValue ## type &EvaluationValueBase::as ## type() const { throw EvaluationFailure{} << \
                                "unsupported operation, type " << typeName() << " can't be represented as " #type; } \
-       EvaluationValuePtr EvaluationValueBase::convertTo ## type() { throw EvaluationFailure{} << \
+       EvaluationValuePtr EvaluationValueBase::convertTo ## type() const { throw EvaluationFailure{} << \
                                "unsupported operation, can't convert " << typeName() << " to " #type; }
 
 Q(String)
@@ -45,6 +45,7 @@ Q(Vector)
 Q(Set)
 Q(Dict)
 Q(Wait)
+Q(Iterator)
 #undef Q
 
 std::ostream &operator << (std::ostream &s, const EvaluationValuePtr &v)
@@ -146,6 +147,71 @@ EvaluationValuePtr EvaluationValueBase::oper_attr_set(const std::string &name, c
        throw EvaluationFailure{} << "unsupported operation, " << typeName() << " doesn't have a " << name << " attribute";
 }
 
+EvaluationValuePtr EvaluationValueBase::iterator_get() const
+{
+       throw EvaluationFailure{} << "unsupported operation: get iterator's current value (" << typeName() << " is not an iterator)";
+}
+
+void EvaluationValueBase::iterator_next()
+{
+       throw EvaluationFailure{} << "unsupported operation: pust iterator to next element (" << typeName() << " is not an iterator)";
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_bit_neg() const
+{
+       throw EvaluationFailure{} << "unsupported operation, " << typeName() << " is not a number";
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_add(const EvaluationValuePtr &o) const
+{
+       throw EvaluationFailure{} << "unsupported operation " << typeName() << " + " << o->typeName();
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_sub(const EvaluationValuePtr &o) const
+{
+       throw EvaluationFailure{} << "unsupported operation " << typeName() << " - " << o->typeName();
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_div(const EvaluationValuePtr &o) const
+{
+       throw EvaluationFailure{} << "unsupported operation " << typeName() << " / " << o->typeName();
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_mul(const EvaluationValuePtr &o) const
+{
+       throw EvaluationFailure{} << "unsupported operation " << typeName() << " * " << o->typeName();
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_mod(const EvaluationValuePtr &o) const
+{
+       throw EvaluationFailure{} << "unsupported operation " << typeName() << " % " << o->typeName();
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_bit_and(const EvaluationValuePtr &o) const
+{
+       throw EvaluationFailure{} << "unsupported operation " << typeName() << " & " << o->typeName();
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_bit_or(const EvaluationValuePtr &o) const
+{
+       throw EvaluationFailure{} << "unsupported operation " << typeName() << " | " << o->typeName();
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_bit_xor(const EvaluationValuePtr &o) const
+{
+       throw EvaluationFailure{} << "unsupported operation " << typeName() << " ^ " << o->typeName();
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_lshift(const EvaluationValuePtr &o) const
+{
+       throw EvaluationFailure{} << "unsupported operation " << typeName() << " << " << o->typeName();
+}
+
+EvaluationValuePtr EvaluationValueBase::oper_rshift(const EvaluationValuePtr &o) const
+{
+       throw EvaluationFailure{} << "unsupported operation " << typeName() << " >> " << o->typeName();
+}
+
 EvaluationValuePtr EvaluationValueBase::oper_negate()
 {
        throw EvaluationFailure{} << "unsupported operation, " << typeName() << " is not a number";
@@ -171,6 +237,11 @@ EvaluationValuePtr EvaluationValueBase::oper_index_set(const EvaluationValuePtr
        throw EvaluationFailure{} << "unsupported operation, " << typeName() << " is not a wrte-able container";
 }
 
+std::shared_ptr<EvaluationValueBase> EvaluationValueBase::shared_from_this() const
+{
+       return const_cast<EvaluationValueBase *>(this)->std::enable_shared_from_this<EvaluationValueBase>::shared_from_this();
+}
+
 class EvaluationValueEmptyImpl : public EvaluationValueBase
 {
 public:
index d90f2c37cf5d9840775dd81edca9e8cae1a735a2..9188843945ea0ed56110a1b3a50a0544ad033b30 100644 (file)
@@ -73,6 +73,20 @@ public:
        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 EvaluationValuePtr oper_bit_neg() const;
+       virtual EvaluationValuePtr oper_add(const EvaluationValuePtr &o) const;
+       virtual EvaluationValuePtr oper_sub(const EvaluationValuePtr &o) const;
+       virtual EvaluationValuePtr oper_div(const EvaluationValuePtr &o) const;
+       virtual EvaluationValuePtr oper_mul(const EvaluationValuePtr &o) const;
+       virtual EvaluationValuePtr oper_mod(const EvaluationValuePtr &o) const;
+       virtual EvaluationValuePtr oper_bit_and(const EvaluationValuePtr &o) const;
+       virtual EvaluationValuePtr oper_bit_or(const EvaluationValuePtr &o) const;
+       virtual EvaluationValuePtr oper_bit_xor(const EvaluationValuePtr &o) const;
+       virtual EvaluationValuePtr oper_lshift(const EvaluationValuePtr &o) const;
+       virtual EvaluationValuePtr oper_rshift(const EvaluationValuePtr &o) const;
+
+       virtual EvaluationValuePtr iterator_get() const;
+       virtual void iterator_next();
 
        virtual void writeToStream(std::ostream &) const = 0;
 
@@ -81,8 +95,8 @@ public:
        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 EvaluationValuePtr convertTo ## type() const; \
+       virtual const EvaluationValue ## type &as ## type() const; \
        virtual bool is ## type() const { return false; }
 
        Q(String)
@@ -96,8 +110,21 @@ public:
        Q(Set)
        Q(Dict)
        Q(Wait)
+       Q(Iterator)
 #undef Q
 
+       static EvaluationValuePtr create(std::uint64_t v)
+       {
+               return create(static_cast<std::int64_t>(v));
+       }
+       static EvaluationValuePtr create(int v)
+       {
+               return create(static_cast<std::int64_t>(v));
+       }
+       static EvaluationValuePtr create(unsigned int v)
+       {
+               return create(static_cast<std::int64_t>(v));
+       }
        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;
 
@@ -116,6 +143,8 @@ public:
                ContextManager &operator = (const ContextManager &) = delete;
                ContextManager &operator = (ContextManager &&) = delete;
        };
+protected:
+       std::shared_ptr<EvaluationValueBase> shared_from_this() const;
 };
 std::ostream &operator << (std::ostream &s, const EvaluationValuePtr &v);
 
index 61d7305a91699e11a4a7b55292bfe82b3a4c0840..79f964027bdf101e092bb45c51553e70d9f6c676 100644 (file)
@@ -29,11 +29,11 @@ public:
        {
                return true;
        }
-       EvaluationValuePtr convertToBoolean() override
+       EvaluationValuePtr convertToBoolean() const override
        {
                return shared_from_this();
        }
-       const EvaluationValueBoolean &asBoolean() override
+       const EvaluationValueBoolean &asBoolean() const override
        {
                return value;
        }
index db0f083982914305b24f5542604bc8545ec8fd2a..74c468a22b33aebe8faa32c9655a04c6ac000b78 100644 (file)
@@ -29,15 +29,15 @@ public:
        {
                return true;
        }
-       EvaluationValuePtr convertToBoolean() override
+       EvaluationValuePtr convertToBoolean() const override
        {
                return create(!value.empty());
        }
-       EvaluationValuePtr convertToDict() override
+       EvaluationValuePtr convertToDict() const override
        {
                return shared_from_this();
        }
-       const EvaluationValueDict &asDict() override
+       const EvaluationValueDict &asDict() const override
        {
                return value;
        }
@@ -69,6 +69,44 @@ public:
        {
                return value.find(v) != value.end();
        }
+       EvaluationValuePtr oper_bit_and(const EvaluationValuePtr &o) const override
+       {
+               auto &r = o->asDict();
+               EvaluationValueDict res;
+               for (auto &q : value) {
+                       if (r.find(q.first) != r.end()) {
+                               res.insert(q);
+                       }
+               }
+               return create(std::move(res));
+       }
+       EvaluationValuePtr oper_bit_or(const EvaluationValuePtr &o) const override
+       {
+               auto res = value;
+               res.insert(o->asDict().begin(), o->asDict().end());
+               return create(std::move(res));
+       }
+       EvaluationValuePtr oper_bit_xor(const EvaluationValuePtr &o) const override
+       {
+               auto &r = o->asDict();
+               EvaluationValueDict res;
+               for (auto &q : value) {
+                       if (r.find(q.first) == r.end()) {
+                               res.insert(q);
+                       }
+               }
+               for (auto &q : r) {
+                       if (value.find(q.first) == value.end()) {
+                               res.insert(q);
+                       }
+               }
+               return create(std::move(res));
+       }
+       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 it = value.find(index);
@@ -81,6 +119,15 @@ public:
                it.first->second = val;
                return val;
        }
+       EvaluationValuePtr convertToIterator() const override
+       {
+               std::vector<EvaluationValue> tmp;
+               tmp.reserve(value.size());
+               for (auto &it : value) {
+                       tmp.push_back(it.first);
+               }
+               return create(std::make_shared<EvaluationValueIteratorCopyImpl>(tmp));
+       }
 private:
        EvaluationValueDict value;
 };
index d1f868e4deab22221d8a310335e3b7a638590f43..5ea0f4f0195c2eb52271de3a4ff56237346a3ee2 100644 (file)
@@ -29,25 +29,25 @@ public:
        {
                return true;
        }
-       EvaluationValuePtr convertToBoolean() override
+       EvaluationValuePtr convertToBoolean() const override
        {
                return create(bool(value));
        }
-       EvaluationValuePtr convertToDouble() override
+       EvaluationValuePtr convertToDouble() const override
        {
                return shared_from_this();
        }
-       EvaluationValuePtr convertToString() override
+       EvaluationValuePtr convertToString() const override
        {
                return create(std::to_string(value));
        }
-       EvaluationValuePtr convertToInteger() override
+       EvaluationValuePtr convertToInteger() const 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
+       const EvaluationValueDouble &asDouble() const override
        {
                return value;
        }
@@ -80,6 +80,63 @@ public:
        {
                return create(-value);
        }
+
+#define I(q) ((q)->convertToInteger()->asInteger())
+#define D(q) ((q)->convertToDouble()->asDouble())
+#define U(q) static_cast<uint64_t>(I(q))
+
+       EvaluationValuePtr oper_bit_neg() const override
+       {
+               return create(~U(this));
+       }
+       EvaluationValuePtr oper_bit_and(const EvaluationValuePtr &o) const override
+       {
+               return create(U(this) & U(o));
+       }
+       EvaluationValuePtr oper_bit_or(const EvaluationValuePtr &o) const override
+       {
+               return create(U(this) | U(o));
+       }
+       EvaluationValuePtr oper_bit_xor(const EvaluationValuePtr &o) const override
+       {
+               return create(U(this) ^ U(o));
+       }
+       EvaluationValuePtr oper_lshift(const EvaluationValuePtr &o) const override
+       {
+               return create(U(this) << U(o));
+       }
+       EvaluationValuePtr oper_rshift(const EvaluationValuePtr &o) const override
+       {
+               return create(U(this) >> U(o));
+       }
+       EvaluationValuePtr oper_mod(const EvaluationValuePtr &o) const override
+       {
+               return create(U(this) % U(o));
+       }
+#define Q(op) \
+       if (isInteger() && o->isInteger()) return create(I(this) op I(o)); \
+       return create(D(this) op D(o));
+       EvaluationValuePtr oper_add(const EvaluationValuePtr &o) const override
+       {
+               Q(+)
+       }
+       EvaluationValuePtr oper_sub(const EvaluationValuePtr &o) const override
+       {
+               Q(-)
+       }
+       EvaluationValuePtr oper_div(const EvaluationValuePtr &o) const override
+       {
+               return create(D(this) / D(o));
+       }
+       EvaluationValuePtr oper_mul(const EvaluationValuePtr &o) const override
+       {
+               Q(*)
+       }
+#undef Q
+#undef I
+#undef U
+#undef D
+
 private:
        EvaluationValueDouble value;
 };
index 12f4f029a3c522bedf3d28208cbf3960ce1220fd..8187903d2b8d2a5e000fc6c029a37b1991094694 100644 (file)
@@ -33,16 +33,16 @@ public:
        {
                return true;
        }
-       EvaluationValuePtr convertToBoolean() override
+       EvaluationValuePtr convertToBoolean() const override
        {
                assert(value);
                return create(bool(value));
        }
-       EvaluationValuePtr convertToFunction() override
+       EvaluationValuePtr convertToFunction() const override
        {
                return shared_from_this();
        }
-       const EvaluationValueFunction &asFunction() override
+       const EvaluationValueFunction &asFunction() const override
        {
                return value;
        }
index 9ed8581635cdd14a5f8b336314d9fa04cd58cb61..c38abce2b765347bcceb0ebeacacec3216be13d6 100644 (file)
@@ -29,23 +29,23 @@ public:
        {
                return true;
        }
-       EvaluationValuePtr convertToBoolean() override
+       EvaluationValuePtr convertToBoolean() const override
        {
                return create(bool(value));
        }
-       EvaluationValuePtr convertToInteger() override
+       EvaluationValuePtr convertToInteger() const override
        {
                return shared_from_this();
        }
-       EvaluationValuePtr convertToString() override
+       EvaluationValuePtr convertToString() const override
        {
                return create(std::to_string(value));
        }
-       EvaluationValuePtr convertToDouble() override
+       EvaluationValuePtr convertToDouble() const override
        {
                return create(static_cast<double>(value));
        }
-       const EvaluationValueInteger &asInteger() override
+       const EvaluationValueInteger &asInteger() const override
        {
                return value;
        }
@@ -78,6 +78,63 @@ public:
        {
                return create(-value);
        }
+
+#define I(q) ((q)->convertToInteger()->asInteger())
+#define D(q) ((q)->convertToDouble()->asDouble())
+#define U(q) static_cast<uint64_t>(I(q))
+
+       EvaluationValuePtr oper_bit_neg() const override
+       {
+               return create(~U(this));
+       }
+       EvaluationValuePtr oper_bit_and(const EvaluationValuePtr &o) const override
+       {
+               return create(U(this) & U(o));
+       }
+       EvaluationValuePtr oper_bit_or(const EvaluationValuePtr &o) const override
+       {
+               return create(U(this) | U(o));
+       }
+       EvaluationValuePtr oper_bit_xor(const EvaluationValuePtr &o) const override
+       {
+               return create(U(this) ^ U(o));
+       }
+       EvaluationValuePtr oper_lshift(const EvaluationValuePtr &o) const override
+       {
+               return create(U(this) << U(o));
+       }
+       EvaluationValuePtr oper_rshift(const EvaluationValuePtr &o) const override
+       {
+               return create(U(this) >> U(o));
+       }
+       EvaluationValuePtr oper_mod(const EvaluationValuePtr &o) const override
+       {
+               return create(U(this) % U(o));
+       }
+#define Q(op) \
+       if (isInteger() && o->isInteger()) return create(I(this) op I(o)); \
+       return create(D(this) op D(o));
+       EvaluationValuePtr oper_add(const EvaluationValuePtr &o) const override
+       {
+               Q(+)
+       }
+       EvaluationValuePtr oper_sub(const EvaluationValuePtr &o) const override
+       {
+               Q(-)
+       }
+       EvaluationValuePtr oper_div(const EvaluationValuePtr &o) const override
+       {
+               return create(D(this) / D(o));
+       }
+       EvaluationValuePtr oper_mul(const EvaluationValuePtr &o) const override
+       {
+               Q(*)
+       }
+#undef Q
+#undef I
+#undef U
+#undef D
+
 private:
        EvaluationValueInteger value;
 };
diff --git a/src/batch/EvaluationValueIterator.cpp b/src/batch/EvaluationValueIterator.cpp
new file mode 100644 (file)
index 0000000..4b66130
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018  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.
+ */
+
+#include "EvaluationValueBase.hpp"
+
+class EvaluationValueIteratorImpl : public EvaluationValueBase
+{
+public:
+       EvaluationValueIteratorImpl(EvaluationValueIterator v) : value(v) { }
+
+       std::string typeName() const override
+       {
+               return "Boolean";
+       }
+       bool isIterator() const override
+       {
+               return true;
+       }
+       EvaluationValuePtr convertToIterator() const override
+       {
+               return shared_from_this();
+       }
+       const EvaluationValueIterator &asIterator() const override
+       {
+               return value;
+       }
+
+       void writeToStream(std::ostream &os) const override
+       {
+               os << "iterator";
+       }
+       bool oper_equal(const EvaluationValuePtr &other) override
+       {
+               return other->isIterator() && value == other->asIterator();
+       }
+       bool oper_is_true() override
+       {
+               return bool(value->get());
+       }
+       EvaluationValuePtr iterator_get() const override
+       {
+               auto v = value->get();
+               if (!v) throw EvaluationFailureIteratorExhaused{} << "iterator exhaused";
+               return v->getInternalValue();
+       }
+       void iterator_next() override
+       {
+               value->next();
+       }
+       EvaluationValuePtr oper_attr_get(const std::string &name) override
+       {
+               if (name == "next") return create([self = shared_from_this()]() -> EvaluationValue {
+                       self->iterator_next();
+                       return {};
+               });
+               if (name == "get") return create([self = shared_from_this()]() -> EvaluationValue {
+                       return self->iterator_get();
+               });
+               return EvaluationValueBase::oper_attr_get(name);
+       }
+private:
+       EvaluationValueIterator value;
+};
+
+EvaluationValuePtr EvaluationValueBase::create(EvaluationValueIterator v)
+{
+       return std::make_shared<EvaluationValueIteratorImpl>(v);
+}
index 5856f2f7bf465300f856f2fef399f561f1837d85..5731130030ed6e1e46bbd6520dd9d030ad14e220 100644 (file)
@@ -31,19 +31,19 @@ public:
        {
                return true;
        }
-       EvaluationValuePtr convertToBoolean() override
+       EvaluationValuePtr convertToBoolean() const override
        {
                return create(true);
        }
-       EvaluationValuePtr convertToPoint() override
+       EvaluationValuePtr convertToPoint() const override
        {
                return shared_from_this();
        }
-       EvaluationValuePtr convertToUIElement() override
+       EvaluationValuePtr convertToUIElement() const override
        {
                return create(EvaluationContext::getCurrentEvaluationContext().executionInterface().convertToUIElement(value));
        }
-       const EvaluationValuePoint &asPoint() override
+       const EvaluationValuePoint &asPoint() const override
        {
                return value;
        }
index ece6358ff1b8502656b6468a782c55ad9daa872c..3bde2076350b05b3d5782f7a7e514954c8b82042 100644 (file)
@@ -29,19 +29,19 @@ public:
        {
                return true;
        }
-       EvaluationValuePtr convertToBoolean() override
+       EvaluationValuePtr convertToBoolean() const override
        {
                return create(!value.empty());
        }
-       EvaluationValuePtr convertToSet() override
+       EvaluationValuePtr convertToSet() const override
        {
                return shared_from_this();
        }
-       EvaluationValuePtr convertToVector() override
+       EvaluationValuePtr convertToVector() const override
        {
                return create(EvaluationValueVector{ value.begin(), value.end() });
        }
-       const EvaluationValueSet &asSet() override
+       const EvaluationValueSet &asSet() const override
        {
                return value;
        }
@@ -62,6 +62,44 @@ public:
                }
                os << " }";
        }
+       EvaluationValuePtr oper_bit_and(const EvaluationValuePtr &o) const override
+       {
+               auto &r = o->asSet();
+               EvaluationValueSet res;
+               for (auto &q : value) {
+                       if (r.find(q) != r.end()) {
+                               res.insert(q);
+                       }
+               }
+               return create(std::move(res));
+       }
+       EvaluationValuePtr oper_bit_or(const EvaluationValuePtr &o) const override
+       {
+               EvaluationValueSet res = value;
+               res.insert(o->asSet().begin(), o->asSet().end());
+               return create(std::move(res));
+       }
+       EvaluationValuePtr oper_bit_xor(const EvaluationValuePtr &o) const override
+       {
+               auto &r = o->asSet();
+               EvaluationValueSet res;
+               for (auto &q : value) {
+                       if (r.find(q) == r.end()) {
+                               res.insert(q);
+                       }
+               }
+               for (auto &q : r) {
+                       if (value.find(q) == value.end()) {
+                               res.insert(q);
+                       }
+               }
+               return create(std::move(res));
+       }
+       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);
+       }
        bool oper_equal(const EvaluationValuePtr &other) override
        {
                return other->isSet() && value == other->asSet();
@@ -74,6 +112,11 @@ public:
        {
                return value.find(v) != value.end();
        }
+       EvaluationValuePtr convertToIterator() const override
+       {
+               std::vector<EvaluationValue> tmp{ value.begin(), value.end() };
+               return create(std::make_shared<EvaluationValueIteratorCopyImpl>(tmp));
+       }
 private:
        EvaluationValueSet value;
 };
index a40a34e06c673dde2dbc7140559bdd05ea3eccd4..c14e970060efcee7f8f2154b719e894b77e71457 100644 (file)
@@ -31,19 +31,19 @@ public:
        {
                return true;
        }
-       EvaluationValuePtr convertToBoolean() override
+       EvaluationValuePtr convertToBoolean() const override
        {
                return create(!value.empty());
        }
-       EvaluationValuePtr convertToString() override
+       EvaluationValuePtr convertToString() const override
        {
                return shared_from_this();
        }
-       EvaluationValuePtr convertToUIElement() override
+       EvaluationValuePtr convertToUIElement() const override
        {
                return create(EvaluationContext::getCurrentEvaluationContext().executionInterface().convertToUIElement(value));
        }
-       const EvaluationValueString &asString() override
+       const EvaluationValueString &asString() const override
        {
                return value;
        }
@@ -67,8 +67,35 @@ public:
        EvaluationValuePtr oper_attr_get(const std::string &name) override
        {
                if (name == "len") return create(static_cast<EvaluationValueInteger>(value.size()));
+               if (name == "join") {
+                       return create(EvaluationValueFunction{
+                               [self = std::static_pointer_cast<EvaluationValueStringImpl>(shared_from_this())](EvaluationValue data) -> EvaluationValue {
+                                       auto join = [](const std::string & mid, auto beg, auto end)
+                                       {
+                                               std::ostringstream tmp;
+                                               bool first = true;
+                                               while (beg != end) {
+                                                       if (first) first = false;
+                                                       else tmp << mid;
+                                                       tmp << (*beg).convertToString();
+                                                       ++beg;
+                                               }
+                                               return tmp.str();
+                                       };
+                                       if (data.isVector())
+                                               return create(join(self->value, data.asVector().begin(), data.asVector().end()));
+                                       if (data.isSet())
+                                               return create(join(self->value, data.asSet().begin(), data.asSet().end()));
+                                       throw EvaluationFailure{} << "can't join " << data.typeName();
+                               }, { { "data" } } });
+               }
+
                return EvaluationValueBase::oper_attr_get(name);
        }
+       EvaluationValuePtr oper_add(const EvaluationValuePtr &o) const override
+       {
+               return create(value + o->asString());
+       }
        EvaluationValuePtr oper_index_get(const EvaluationValuePtr &index) override
        {
                auto i = getSingleIndex(index, value.size());
@@ -79,6 +106,15 @@ public:
                auto indexes = getDoubleIndexes(from, to, value.size());
                return create(value.substr(indexes.first, indexes.second - indexes.first));
        }
+       EvaluationValuePtr convertToIterator() const override
+       {
+               std::vector<EvaluationValue> tmp;
+               tmp.reserve(value.size());
+               for (auto q : value)
+                       tmp.push_back(create(std::string{ &q, 1 }));
+               return create(std::make_shared<EvaluationValueIteratorCopyImpl>(tmp));
+       }
+
 private:
        EvaluationValueString value;
 };
index 9507a3d9c7319b8fb1c907bccf3fea53da356598..e4b69c8912da8c6bcef43e9496bd8c9dde9c88a7 100644 (file)
@@ -32,15 +32,15 @@ public:
        {
                return true;
        }
-       EvaluationValuePtr convertToBoolean() override
+       EvaluationValuePtr convertToBoolean() const override
        {
                return create(bool(value->getObject()));
        }
-       EvaluationValuePtr convertToUIElement() override
+       EvaluationValuePtr convertToUIElement() const override
        {
                return shared_from_this();
        }
-       const EvaluationValueUIElement &asUIElement() override
+       const EvaluationValueUIElement &asUIElement() const override
        {
                return value;
        }
@@ -72,8 +72,27 @@ public:
        {
                if (name == "name")
                        return create(EvaluationContext::getCurrentEvaluationContext().executionInterface().getUIElementName(value));
-               if (name == "middle_point")
+               if (name == "center")
                        return create(value->getScanningCoordinates());
+               if (name == "role")
+                       return create(EvaluationContext::getCurrentEvaluationContext().executionInterface().getUIElementRole(value));
+               if (name == "states") {
+                       auto tmp = EvaluationContext::getCurrentEvaluationContext().executionInterface().getUIElementStates(value);
+                       EvaluationValueSet v;
+                       for (auto i = 0u; i < tmp.size(); ++i) {
+                               if (tmp[i])
+                                       v.insert(i);
+                       }
+                       return create(std::move(v));
+               }
+               if (name == "attributes") {
+                       auto tmp = EvaluationContext::getCurrentEvaluationContext().executionInterface().getUIElementAttributes(value);
+                       EvaluationValueDict d;
+                       for (auto &it : d) {
+                               d.insert({ std::move(it.first), std::move(it.second) });
+                       }
+                       return create(std::move(d));
+               }
                return EvaluationValueBase::oper_attr_get(name);
        }
 private:
index d6ccce81faf5958a39c554daaf306c47eb670ef4..a0cbab6bd5603e6512645508137372ef774efa71 100644 (file)
@@ -29,15 +29,19 @@ public:
        {
                return true;
        }
-       EvaluationValuePtr convertToBoolean() override
+       EvaluationValuePtr convertToBoolean() const override
        {
                return create(!value.empty());
        }
-       EvaluationValuePtr convertToVector() override
+       EvaluationValuePtr convertToVector() const override
        {
                return shared_from_this();
        }
-       const EvaluationValueVector &asVector() override
+       EvaluationValuePtr convertToIterator() const override
+       {
+               return create(std::make_shared<EvaluationValueIteratorCopyImpl>(value));
+       }
+       const EvaluationValueVector &asVector() const override
        {
                return value;
        }
@@ -86,6 +90,53 @@ public:
                                return true;
                return false;
        }
+       EvaluationValuePtr oper_attr_get(const std::string &name) override
+       {
+               if (name == "len") return create(static_cast<EvaluationValueInteger>(value.size()));
+               if (name == "append") return create([self = std::static_pointer_cast<EvaluationValueVectorImpl>(shared_from_this())](EvaluationValue o) -> EvaluationValue {
+                       self->value.push_back(std::move(o));
+                       return {};
+               });
+               if (name == "insert") return create([self = std::static_pointer_cast<EvaluationValueVectorImpl>(shared_from_this())]
+                       (EvaluationValue index, EvaluationValue o) -> EvaluationValue {
+                       auto i = self->getSingleIndex(index.getInternalValue(), self->value.size());
+                       self->value.insert(self->value.begin() + i, std::move(o));
+                       return {};
+               });
+               if (name == "filter") {
+                       return create(EvaluationValueFunction{
+                               [self = std::static_pointer_cast<EvaluationValueVectorImpl>(shared_from_this())](EvaluationValue filter) -> EvaluationValue {
+                                       auto &f = filter.asFunction();
+                                       auto v = EvaluationValueVector{};
+                                       for (auto &q : self->value)
+                                       {
+                                               if (f({ { q } })) {
+                                                       v.push_back(q);
+                                               }
+                                       }
+                                       return create(std::move(v));
+                               }, { {"predicate" } } });
+               }
+               if (name == "pop") {
+                       return create(EvaluationValueFunction{
+                               [self = std::static_pointer_cast<EvaluationValueVectorImpl>(shared_from_this())](EvaluationValue index) -> EvaluationValue {
+                                       auto i = self->getSingleIndex(index.getInternalValue(), self->value.size());
+                                       auto v = std::move(self->value[i]);
+                                       self->value.erase(self->value.begin() + i);
+                                       return v;
+                               }, { {"index", -1 } } });
+               }
+               return EvaluationValueBase::oper_attr_get(name);
+       }
+       EvaluationValuePtr oper_add(const EvaluationValuePtr &o) const override
+       {
+               auto &v = o->asVector();
+               auto r = EvaluationValueVector{};
+               r.reserve(value.size() + v.size());
+               for (auto &q : value) r.push_back(q);
+               for (auto &q : v) r.push_back(q);
+               return create(std::move(r));
+       }
        EvaluationValuePtr oper_index_get(const EvaluationValuePtr &index) override
        {
                auto i = getSingleIndex(index, value.size());
@@ -124,7 +175,7 @@ public:
                return shared_from_this();
        }
 private:
-       EvaluationValueVector value;
+       mutable EvaluationValueVector value;
 };
 
 EvaluationValuePtr EvaluationValueBase::create(EvaluationValueVector v)
index c450db11254ca6dab7511b6957c85ee7071603ed..bd821177737a886fe1f866f47706476958b5a61c 100644 (file)
@@ -32,11 +32,11 @@ public:
        {
                return true;
        }
-       EvaluationValuePtr convertToWait() override
+       EvaluationValuePtr convertToWait() const override
        {
                return shared_from_this();
        }
-       const EvaluationValueWait &asWait() override
+       const EvaluationValueWait &asWait() const override
        {
                return value;
        }
index ab67e4371eb4727a1e798085ffcd289535a63d9b..05e22290327d07c42702bbd07b741d6d1f684fe0 100644 (file)
@@ -151,7 +151,7 @@ EvaluationValue IdentifierEvaluator::evaluateImpl() const
 
 void IdentifierEvaluator::printSelfInfo(unsigned int depth) const
 {
-       printLocationAndIndent(location(), depth) << "identifier " << identifier << "\n";
+       printLocationAndIndent(location(), depth) << "identifier " << identifier;
 }
 
 AttributeEvaluator::AttributeEvaluator(TokenLocation tokenLocation, ExprPtr self, std::string identifier) :
@@ -164,8 +164,8 @@ EvaluationValue AttributeEvaluator::evaluateImpl() const
 
 void AttributeEvaluator::printSelfInfo(unsigned int depth) const
 {
-       printLocationAndIndent(location(), depth) << "attribute " << identifier << "\n";
-       printLocationAndIndent(location(), depth) << "self is\n";
+       printLocationAndIndent(location(), depth) << "attribute " << identifier;
+       printLocationAndIndent(location(), depth) << "self is";
        self->printSelfInfo(depth + 1);
 }
 
@@ -180,10 +180,10 @@ EvaluationValue AttributeSetterEvaluator::evaluateImpl() const
 
 void AttributeSetterEvaluator::printSelfInfo(unsigned int depth) const
 {
-       printLocationAndIndent(location(), depth) << "attribute setter " << identifier << "\n";
-       printLocationAndIndent(location(), depth) << "self is\n";
+       printLocationAndIndent(location(), depth) << "attribute setter " << identifier;
+       printLocationAndIndent(location(), depth) << "self is";
        self->printSelfInfo(depth + 1);
-       printLocationAndIndent(location(), depth) << "value to set is\n";
+       printLocationAndIndent(location(), depth) << "value to set is";
        value->printSelfInfo(depth + 1);
 }
 
@@ -201,8 +201,8 @@ EvaluationValue SetterEvaluator::evaluateImpl() const
 
 void SetterEvaluator::printSelfInfo(unsigned int depth) const
 {
-       printLocationAndIndent(location(), depth) << "setter " << identifier << "\n";
-       printLocationAndIndent(location(), depth) << "value to set is\n";
+       printLocationAndIndent(location(), depth) << "setter " << identifier;
+       printLocationAndIndent(location(), depth) << "value to set is";
        value->printSelfInfo(depth + 1);
 }
 
@@ -220,10 +220,10 @@ EvaluationValue PointEvaluator::evaluateImpl() const
 
 void PointEvaluator::printSelfInfo(unsigned int depth) const
 {
-       printLocationAndIndent(location(), depth) << "point\n";
-       printLocationAndIndent(location(), depth) << "x is\n";
+       printLocationAndIndent(location(), depth) << "point";
+       printLocationAndIndent(location(), depth) << "x is";
        x->printSelfInfo(depth + 1);
-       printLocationAndIndent(location(), depth) << "y is\n";
+       printLocationAndIndent(location(), depth) << "y is";
        y->printSelfInfo(depth + 1);
 }
 
@@ -239,7 +239,7 @@ EvaluationValue IntegerEvaluator::evaluateImpl() const
 
 void IntegerEvaluator::printSelfInfo(unsigned int depth) const
 {
-       printLocationAndIndent(location(), depth) << "integer " << value << "\n";
+       printLocationAndIndent(location(), depth) << "integer " << value;
 }
 
 
@@ -254,7 +254,7 @@ EvaluationValue DoubleEvaluator::evaluateImpl() const
 
 void DoubleEvaluator::printSelfInfo(unsigned int depth) const
 {
-       printLocationAndIndent(location(), depth) << "double " << value << "\n";
+       printLocationAndIndent(location(), depth) << "double " << value;
 }
 
 
@@ -269,7 +269,7 @@ EvaluationValue StringEvaluator::evaluateImpl() const
 
 void StringEvaluator::printSelfInfo(unsigned int depth) const
 {
-       printLocationAndIndent(location(), depth) << "string '" << value << "'\n";
+       printLocationAndIndent(location(), depth) << "string '" << value << "'";
 }
 
 
@@ -307,26 +307,26 @@ void ArraySetDictEvaluator::printSelfInfo(unsigned int depth) const
                auto os = printLocationAndIndent(location(), depth);
                switch (kind) {
                case Kind::SET:
-                       os << "set\n";
+                       os << "set";
                        break;
                case Kind::VECTOR:
-                       os << "vector\n";
+                       os << "vector";
                        break;
                case Kind::DICT:
-                       os << "dict\n";
+                       os << "dict";
                        break;
                }
        }
        if (kind == Kind::SET || kind == Kind::VECTOR) {
                for (auto i = 0u; i < values.size(); ++i) {
-                       printLocationAndIndent(location(), depth) << "element " << (i + 1) << "\n";
+                       printLocationAndIndent(location(), depth) << "element " << (i + 1);
                        values[i]->printSelfInfo(depth + 1);
                }
        } else {
                for (auto i = 0u; i < values.size(); i += 2) {
-                       printLocationAndIndent(location(), depth) << "element " << (i / 2 + 1) << " key\n";
+                       printLocationAndIndent(location(), depth) << "element " << (i / 2 + 1) << " key";
                        values[i]->printSelfInfo(depth + 1);
-                       printLocationAndIndent(location(), depth) << "element " << (i / 2 + 1) << " value\n";
+                       printLocationAndIndent(location(), depth) << "element " << (i / 2 + 1) << " value";
                        values[i + 1]->printSelfInfo(depth + 1);
                }
        }
@@ -358,6 +358,32 @@ EvaluationValue OperatorEvaluator::evaluateImpl() const
                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]);
+       case Kind::ADD:
+               return vals[0] + vals[1];
+       case Kind::SUB:
+               return vals[0] - vals[1];
+       case Kind::MUL:
+               return vals[0] * vals[1];
+       case Kind::DIV:
+               return vals[0] / vals[1];
+       case Kind::MOD:
+               return vals[0] % vals[1];
+       case Kind::LSHIFT:
+               return vals[0] << vals[1];
+       case Kind::RSHIFT:
+               return vals[0] >> vals[1];
+       case Kind::BIT_OR:
+               return vals[0] | vals[1];
+       case Kind::BIT_NOT:
+               return ~vals[0];
+       case Kind::BIT_AND:
+               return vals[0] & vals[1];
+       case Kind::BIT_XOR:
+               return vals[0] ^ vals[1];
+       case Kind::LOG_AND:
+               return bool(vals[0]) && bool(vals[1]);
+       case Kind::LOG_OR:
+               return bool(vals[0]) || bool(vals[1]);
        }
        ASSERT(0);
        throw EvaluationFailure{} << "unknown operator";
@@ -385,12 +411,51 @@ void OperatorEvaluator::printSelfInfo(unsigned int depth) const
                case Kind::SET:
                        desc = "[]=";
                        break;
+               case Kind::ADD:
+                       desc = "+";
+                       break;
+               case Kind::SUB:
+                       desc = "-";
+                       break;
+               case Kind::MUL:
+                       desc = "*";
+                       break;
+               case Kind::DIV:
+                       desc = "/";
+                       break;
+               case Kind::MOD:
+                       desc = "%";
+                       break;
+               case Kind::LSHIFT:
+                       desc = "<<";
+                       break;
+               case Kind::RSHIFT:
+                       desc = ">>";
+                       break;
+               case Kind::BIT_OR:
+                       desc = "|";
+                       break;
+               case Kind::BIT_NOT:
+                       desc = "~";
+                       break;
+               case Kind::BIT_AND:
+                       desc = "&";
+                       break;
+               case Kind::BIT_XOR:
+                       desc = "^";
+                       break;
+               case Kind::LOG_AND:
+                       desc = "and";
+                       break;
+               case Kind::LOG_OR:
+                       desc = "or";
+                       break;
                }
 
-               os << desc << "\n";
+               os << desc;
        }
        for (auto i = 0u; i < args.size(); ++i) {
-               printLocationAndIndent(location(), depth) << "element " << (i + 1) << " key\n";
+               printLocationAndIndent(location(), depth) << "element " << (i + 1);
                args[i]->printSelfInfo(depth + 1);
        }
 }
@@ -461,7 +526,7 @@ void CompOperatorEvaluator::printSelfInfo(unsigned int depth) const
        }
 
        for (auto i = 0u; i < args.size(); ++i) {
-               printLocationAndIndent(location(), depth) << "argument " << (i + 1) << " key\n";
+               printLocationAndIndent(location(), depth) << "argument " << (i + 1) << " key";
                args[i]->printSelfInfo(depth + 1);
        }
 }
@@ -478,7 +543,7 @@ EvaluationValue BooleanEvaluator::evaluateImpl() const
 
 void BooleanEvaluator::printSelfInfo(unsigned int depth) const
 {
-       printLocationAndIndent(location(), depth) << "boolean " << (value ? "true" : "false") << "\n";
+       printLocationAndIndent(location(), depth) << "boolean " << (value ? "true" : "false");
 }
 
 
@@ -505,25 +570,58 @@ EvaluationValue CallEvaluator::evaluateImpl() const
 
 void CallEvaluator::printSelfInfo(unsigned int depth) const
 {
-       printLocationAndIndent(location(), depth) << "function call\n";
+       printLocationAndIndent(location(), depth) << "function call";
        function->printSelfInfo(depth + 1);
        for (auto i = 0u; i < args.size(); ++i) {
-               printLocationAndIndent(location(), depth) << "arg " << i << " is\n";
+               printLocationAndIndent(location(), depth) << "arg " << i << " is";
                args[i]->printSelfInfo(depth + 1);
        }
 }
 
+LambdaEvaluator::LambdaEvaluator(TokenLocation tokenLocation, std::vector<std::string> argNames, StatPtr codeBlock) :
+       ExpressionEvaluator(std::move(tokenLocation)), argNames(std::move(argNames)), codeBlock(std::move(codeBlock)) { }
+
+EvaluationValue LambdaEvaluator::evaluateImpl() const
+{
+       EvaluationValue tmp;
+       tmp = EvaluationValueFunction {[ = ](EvaluationValueFunction::Args args) -> EvaluationValue {
+                       if (this->argNames.size() != args.size())
+                               throw EvaluationFailure{} << "invalid number of arguments";
+                       EvaluationContext ctx;
+                       for (auto i = 0u; i < args.size(); ++i)
+                       {
+                               ctx.setVariable(argNames[i], args[i]);
+                       }
+                       try
+                       {
+                               DebugEvaluator{} << getDebugId() << ": function is called, evaluating";
+                               codeBlock->evaluate();
+                       } catch (ReturnValue &r)
+                       {
+                               DebugEvaluator{} << getDebugId() << ": got return value " << r.getResult();
+                               return r.getResult();
+                       }
+                       return {};
+               }
+       };
+       return tmp;
+}
+
+void LambdaEvaluator::printSelfInfo(unsigned int depth) const
+{
+       printLocationAndIndent(location(), depth) << "lambda definition";
+       for (auto i = 0u; i < argNames.size(); ++i) {
+               printLocationAndIndent(location(), depth) << "arg " << i << " is " << argNames[i];
+       }
+       printLocationAndIndent(location(), depth) << "body";
+       codeBlock->printSelfInfo(depth + 1);
+}
+
 FunctionEvaluator::FunctionEvaluator(TokenLocation location_, std::string functionName, std::vector<std::string> argNames, StatPtr codeBlock):
        StatementEvaluator(location_), functionName(std::move(functionName)), argNames(std::move(argNames)), codeBlock(std::move(codeBlock))  {}
 
 void FunctionEvaluator::evaluateImpl() const
 {
-       /*      TODO: add named parameters
-           std::vector<EvaluationValueFunction::Arg> tmp;
-               for (auto &arg: argNames) {
-                       tmp.push_back(arg);
-               }
-               */
        EvaluationContext::getCurrentEvaluationContext().setVariable(functionName,
        EvaluationValueFunction {[ = ](EvaluationValueFunction::Args args) -> EvaluationValue {
                        if (this->argNames.size() != args.size())
@@ -548,14 +646,15 @@ void FunctionEvaluator::evaluateImpl() const
 
 void FunctionEvaluator::printSelfInfo(unsigned int depth) const
 {
-       printLocationAndIndent(location(), depth) << "function definition " << functionName << "\n";
+       printLocationAndIndent(location(), depth) << "function definition " << functionName;
        for (auto i = 0u; i < argNames.size(); ++i) {
-               printLocationAndIndent(location(), depth) << "arg " << i << " is " << argNames[i] << "\n";
+               printLocationAndIndent(location(), depth) << "arg " << i << " is " << argNames[i];
        }
-       printLocationAndIndent(location(), depth) << "body\n";
+       printLocationAndIndent(location(), depth) << "body";
        codeBlock->printSelfInfo(depth + 1);
 }
 
+
 ReturnEvaluator::ReturnEvaluator(TokenLocation location_, ExprPtr result):
        StatementEvaluator(location_), result(std::move(result))  {}
 
@@ -568,8 +667,8 @@ void ReturnEvaluator::evaluateImpl() const
 
 void ReturnEvaluator::printSelfInfo(unsigned int depth) const
 {
-       printLocationAndIndent(location(), depth) << "return ";
-       result->printSelfInfo(depth + 1);
+       printLocationAndIndent(location(), depth) << "return";
+       if (result) result->printSelfInfo(depth + 1);
 }
 
 
@@ -601,7 +700,7 @@ void BlockEvaluator::evaluateImpl() const
 
 void BlockEvaluator::printSelfInfo(unsigned int depth) const
 {
-       printLocationAndIndent(location(), depth) << "block\n";
+       printLocationAndIndent(location(), depth) << "block";
        for (auto &e : evals)
                e->printSelfInfo(depth + 1);
 }
@@ -632,10 +731,132 @@ void WaitEvaluator::evaluateImpl() const
 
 void WaitEvaluator::printSelfInfo(unsigned int depth) const
 {
-       printLocationAndIndent(location(), depth) << "wait\n";
+       printLocationAndIndent(location(), depth) << "wait";
        exec->printSelfInfo(depth + 1);
        for (auto &w : waits) {
-               printLocationAndIndent(location(), depth) << "for\n";
+               printLocationAndIndent(location(), depth) << "for";
                w->printSelfInfo(depth + 1);
        }
 }
+
+
+ForEvaluator::ForEvaluator(TokenLocation location_, std::string ident, ExprPtr iterator, StatPtr body, StatPtr else_)
+       : StatementEvaluator(location_), ident(std::move(ident)), iterator(std::move(iterator)), body(std::move(body)), else_(std::move(else_)) {}
+
+void ForEvaluator::evaluateImpl() const
+{
+       auto iter_ = iterator->evaluate();
+       auto iter = iter_.convertToIterator();
+       bool broken = false;
+
+       while (1) {
+               auto v = iter->get();
+               if (!v) break;
+               EvaluationContext::getCurrentEvaluationContext().setVariable(ident, std::move(*v));
+               try {
+                       body->evaluate();
+               } catch (ContinueValue) {
+
+               } catch (BreakValue) {
+                       broken = true;
+                       break;
+               }
+               iter->next();
+       }
+       if (!broken && else_) else_->evaluate();
+}
+
+void ForEvaluator::printSelfInfo(unsigned int depth) const
+{
+       printLocationAndIndent(location(), depth) << "for " << ident << " in";
+       iterator->printSelfInfo(depth + 1);
+       printLocationAndIndent(location(), depth) << "body";
+       body->printSelfInfo(depth + 1);
+       if (else_) {
+               printLocationAndIndent(location(), depth) << "else";
+               else_->printSelfInfo(depth + 1);
+       }
+}
+
+WhileEvaluator::WhileEvaluator(TokenLocation location_, ExprPtr condition, StatPtr body, StatPtr else_)
+       : StatementEvaluator(location_), condition(std::move(condition)), body(std::move(body)), else_(std::move(else_)) {}
+
+void WhileEvaluator::evaluateImpl() const
+{
+       bool broken = false;
+
+       while (1) {
+               auto val = condition->evaluate();
+               if (!val.convertToBoolean()) break;
+               try {
+                       body->evaluate();
+               } catch (ContinueValue) {
+               } catch (BreakValue) {
+                       broken = true;
+                       break;
+               }
+       }
+       if (!broken && else_) else_->evaluate();
+}
+
+void WhileEvaluator::printSelfInfo(unsigned int depth) const
+{
+       printLocationAndIndent(location(), depth) << "while";
+       condition->printSelfInfo(depth + 1);
+       printLocationAndIndent(location(), depth) << "body";
+       body->printSelfInfo(depth + 1);
+       if (else_) {
+               printLocationAndIndent(location(), depth) << "else";
+               else_->printSelfInfo(depth + 1);
+       }
+}
+
+IfEvaluator::IfEvaluator(TokenLocation location_, ExprPtr condition, StatPtr body, StatPtr else_)
+       : StatementEvaluator(location_), condition(std::move(condition)), body(std::move(body)), else_(std::move(else_)) {}
+
+void IfEvaluator::evaluateImpl() const
+{
+       auto v = condition->evaluate();
+       auto v2 = v.convertToBoolean();
+       if (v2) {
+               body->evaluate();
+       } else if (else_) {
+               else_->evaluate();
+       }
+}
+
+void IfEvaluator::printSelfInfo(unsigned int depth) const
+{
+       printLocationAndIndent(location(), depth) << "if";
+       condition->printSelfInfo(depth + 1);
+       printLocationAndIndent(location(), depth) << "body";
+       body->printSelfInfo(depth + 1);
+       if (else_) {
+               printLocationAndIndent(location(), depth) << "else";
+               else_->printSelfInfo(depth + 1);
+       }
+}
+
+BreakEvaluator::BreakEvaluator(TokenLocation location_) : StatementEvaluator(location_) {}
+
+void BreakEvaluator::evaluateImpl() const
+{
+       throw BreakValue{};
+}
+
+void BreakEvaluator::printSelfInfo(unsigned int depth) const
+{
+       printLocationAndIndent(location(), depth) << "break";
+}
+
+ContinueEvaluator::ContinueEvaluator(TokenLocation location_) : StatementEvaluator(location_) {}
+
+void ContinueEvaluator::evaluateImpl() const
+{
+       throw ContinueValue{};
+}
+
+void ContinueEvaluator::printSelfInfo(unsigned int depth) const
+{
+       printLocationAndIndent(location(), depth) << "continue";
+}
index ef0e47d060858209375b3e06b766b900d6b86c2e..3cce13edc99a628fdb99c138d73dc8aa9d42a91a 100644 (file)
@@ -382,7 +382,7 @@ protected:
        EvaluationValue evaluateImpl() const override;
 public:
        enum class Kind {
-               IN, GET, SET, MINUS, NOT
+               IN, GET, SET, MINUS, NOT, LOG_OR, LOG_AND, ADD, SUB, MUL, DIV, MOD, LSHIFT, RSHIFT, BIT_OR, BIT_NOT, BIT_AND, BIT_XOR
        };
        OperatorEvaluator(TokenLocation location_, ExprPtrs args, Kind kind);
 
@@ -491,4 +491,70 @@ protected:
        void printSelfInfo(unsigned int depth) const override;
 };
 
+class LambdaEvaluator : public ExpressionEvaluator
+{
+       std::vector<std::string> argNames;
+       StatPtr codeBlock;
+public:
+       LambdaEvaluator(TokenLocation location_, std::vector<std::string> argNames, StatPtr codeBlock);
+protected:
+       EvaluationValue evaluateImpl() const override;
+public:
+       void printSelfInfo(unsigned int depth) const override;
+};
+
+class WhileEvaluator : public StatementEvaluator
+{
+       ExprPtr condition;
+       StatPtr body, else_;
+public:
+       WhileEvaluator(TokenLocation location_, ExprPtr condition, StatPtr body, StatPtr else_);
+protected:
+       void evaluateImpl() const override;
+       void printSelfInfo(unsigned int depth) const override;
+};
+
+class ForEvaluator : public StatementEvaluator
+{
+       std::string ident;
+       ExprPtr iterator;
+       StatPtr body, else_;
+public:
+       ForEvaluator(TokenLocation location_, std::string ident, ExprPtr iterator, StatPtr body, StatPtr else_);
+protected:
+       void evaluateImpl() const override;
+       void printSelfInfo(unsigned int depth) const override;
+};
+
+class IfEvaluator : public StatementEvaluator
+{
+       ExprPtr condition;
+       StatPtr body, else_;
+public:
+       IfEvaluator(TokenLocation location_, ExprPtr condition, StatPtr body, StatPtr else_);
+protected:
+       void evaluateImpl() const override;
+       void printSelfInfo(unsigned int depth) const override;
+};
+
+class BreakEvaluator : public StatementEvaluator
+{
+public:
+       BreakEvaluator(TokenLocation location_);
+protected:
+       void evaluateImpl() const override;
+       void printSelfInfo(unsigned int depth) const override;
+};
+
+class ContinueEvaluator : public StatementEvaluator
+{
+public:
+       ContinueEvaluator(TokenLocation location_);
+protected:
+       void evaluateImpl() const override;
+       void printSelfInfo(unsigned int depth) const override;
+};
+
+
+
 #endif
index f30c3ac7bba2ce3e477f958bef4cdafac2580731..e77f7a05b741c1ef71771eede4c40d0c0bb88be1 100644 (file)
@@ -78,7 +78,7 @@ std::string toString(TokenType t)
  * If found, resulting token will be KEYWORD rather than IDENTIFIER.
  */
 static std::unordered_set<std::string> keywords {
-       "true", "false", "def", "return"
+       "true", "false", "def", "return", "if", "else", "elif", "for", "in", "break", "continue", "while"
 };
 
 /**
@@ -88,11 +88,11 @@ static std::unordered_set<std::string> keywords {
  * Note, that when adding new operator, you must put it in collection with correct size (first element of the pair).
  */
 static std::vector<std::pair<unsigned int, std::unordered_set<std::string>>> operatorsbyLength {
-       { 2, { "==", "!=", "<=", ">=", "->" } },
+       { 2, { "==", "!=", "<=", ">=", "->", "<<", ">>" } },
        {
                1, {
                        "<", ">", "(", ")", ",", "=", "[", "]", "+", "-", ".", "*", "/", "{", "}",
-                       "!", "-", ":",
+                       "!", "-", ":", "%", "<<", ">>", "&", "|", "^", "~"
                }
        },
 };
@@ -208,6 +208,9 @@ class Lexer
                auto nextLineIndex = lineStart;
                for (; nextLineIndex < source.size() && source[nextLineIndex] != '\n'; ++nextLineIndex);
                auto lineContent = source.substr(lineStart, nextLineIndex - lineStart);
+               for (auto &q : lineContent) {
+                       if (q < ' ') q = ' ';
+               }
                lineInfo = std::make_shared<TokenLocation::LineInfo>(TokenLocation::LineInfo{
                        lineContent, fileNamePtr, line
                });
index 7a28f7d923ef58d314b0b3d634f491a3815862f5..2834aef940f10390c4e0a1bb12e37d0e0cc16285 100644 (file)
@@ -151,6 +151,18 @@ class Parser
                }
                return true;
        }
+       bool checkTokenText(const std::string &text1, const std::string &text2)
+       {
+               if (index >= tokens.size()) {
+                       error("unexpected end of file");
+                       return false;
+               }
+               if (tokens[index].text() != text1 && tokens[index].text() != text2) {
+                       error("expected '" + text1 + "' or '" + text2 + "', got '" + tokens[index].text() + "'");
+                       return false;
+               }
+               return true;
+       }
        /**
         * @brief Tries to consume token with type t
         *
@@ -201,6 +213,13 @@ class Parser
                return true;
        }
 
+       bool consume(const std::string &t1, const std::string &t2)
+       {
+               if (!checkTokenText(t1, t2)) return false;
+               ++index;
+               return true;
+       }
+
        /**
         * @brief Tries to parse arguments (as in function call), returns true if successful.
         *
@@ -253,13 +272,21 @@ class Parser
         */
        ExprPtr parseInteger(const Token &t)
        {
-               size_t pos = 0;
-               auto val = std::stoi(t.text(), &pos);
-               if (pos != t.text().size()) {
-                       error("'" + t.text() + "' is not a valid integer");
-                       return {};
+               std::uint64_t val = 0;
+               for (auto q : t.text()) {
+                       if (q >= '0' && q <= '9') {
+                               auto val2 = val * 10 + q - '0';
+                               if (val2 < val) {
+                                       error("'" + t.text() + "' is not a valid integer");
+                                       return {};
+                               }
+                               val = val2;
+                       } else {
+                               error("'" + t.text() + "' is not a valid integer");
+                               return {};
+                       }
                }
-               return std::make_shared<IntegerEvaluator>(t.location(), val);
+               return std::make_shared<IntegerEvaluator>(t.location(), static_cast<std::int64_t>(val));
        }
        /**
         * @brief Tries to parse token as double
@@ -296,6 +323,7 @@ class Parser
                case TokenType::KEYWORD:
                        if (t.text() == "true") return std::make_shared<BooleanEvaluator>(t.location(), true);
                        if (t.text() == "false") return std::make_shared<BooleanEvaluator>(t.location(), false);
+                       if (t.text() == "def" && index < tokens.size() && tokens[index].text() == "(") return parseLambda();
                        break;
                case TokenType::IDENTIFIER:
                        if (index < tokens.size() && tokens[index].text() == "=") {
@@ -377,7 +405,7 @@ class Parser
        {
                static std::unordered_map<std::string, OperatorEvaluator::Kind> opers {
                        { "-", OperatorEvaluator::Kind::MINUS },
-                       { "not", OperatorEvaluator::Kind::NOT },
+                       { "~", OperatorEvaluator::Kind::BIT_NOT },
                };
                if (index < tokens.size()) {
                        auto it = opers.find(tokens[index].text());
@@ -451,6 +479,93 @@ class Parser
                return std::move(e);
        }
 
+       ExprPtr parseExprOper1()
+       {
+               auto v = parsePostfixExpr();
+               while (index < tokens.size()) {
+                       OperatorEvaluator::Kind kind;
+                       if (tokens[index].text() == "*") kind = OperatorEvaluator::Kind::MUL;
+                       else if (tokens[index].text() == "/") kind = OperatorEvaluator::Kind::DIV;
+                       else if (tokens[index].text() == "%") kind = OperatorEvaluator::Kind::MOD;
+                       else break;
+                       ++index;
+                       auto v2 = parsePostfixExpr();
+                       v = std::make_shared<OperatorEvaluator>(tokens[index].location(), std::vector<ExprPtr> { std::move(v), std::move(v2) }, kind);
+               }
+               return v;
+       }
+
+       ExprPtr parseExprOper2()
+       {
+               auto v = parseExprOper1();
+               while (index < tokens.size()) {
+                       OperatorEvaluator::Kind kind;
+                       if (tokens[index].text() == "+") kind = OperatorEvaluator::Kind::ADD;
+                       else if (tokens[index].text() == "-") kind = OperatorEvaluator::Kind::SUB;
+                       else break;
+                       ++index;
+                       auto v2 = parseExprOper1();
+                       v = std::make_shared<OperatorEvaluator>(tokens[index].location(), std::vector<ExprPtr> { std::move(v), std::move(v2) }, kind);
+               }
+               return v;
+       }
+
+       ExprPtr parseExprOper3()
+       {
+               auto v = parseExprOper2();
+               while (index < tokens.size()) {
+                       OperatorEvaluator::Kind kind;
+                       if (tokens[index].text() == "<<") kind = OperatorEvaluator::Kind::LSHIFT;
+                       else if (tokens[index].text() == ">>") kind = OperatorEvaluator::Kind::RSHIFT;
+                       else break;
+                       ++index;
+                       auto v2 = parseExprOper2();
+                       v = std::make_shared<OperatorEvaluator>(tokens[index].location(), std::vector<ExprPtr> { std::move(v), std::move(v2) }, kind);
+               }
+               return v;
+       }
+
+       ExprPtr parseExprOper4()
+       {
+               auto v = parseExprOper3();
+               while (index < tokens.size()) {
+                       OperatorEvaluator::Kind kind;
+                       if (tokens[index].text() == "&") kind = OperatorEvaluator::Kind::BIT_AND;
+                       else break;
+                       ++index;
+                       auto v2 = parseExprOper3();
+                       v = std::make_shared<OperatorEvaluator>(tokens[index].location(), std::vector<ExprPtr> { std::move(v), std::move(v2) }, kind);
+               }
+               return v;
+       }
+
+       ExprPtr parseExprOper5()
+       {
+               auto v = parseExprOper4();
+               while (index < tokens.size()) {
+                       OperatorEvaluator::Kind kind;
+                       if (tokens[index].text() == "^") kind = OperatorEvaluator::Kind::BIT_XOR;
+                       else break;
+                       ++index;
+                       auto v2 = parseExprOper4();
+                       v = std::make_shared<OperatorEvaluator>(tokens[index].location(), std::vector<ExprPtr> { std::move(v), std::move(v2) }, kind);
+               }
+               return v;
+       }
+
+       ExprPtr parseExprOper6()
+       {
+               auto v = parseExprOper5();
+               while (index < tokens.size()) {
+                       OperatorEvaluator::Kind kind;
+                       if (tokens[index].text() == "|") kind = OperatorEvaluator::Kind::BIT_OR;
+                       else break;
+                       ++index;
+                       auto v2 = parseExprOper5();
+                       v = std::make_shared<OperatorEvaluator>(tokens[index].location(), std::vector<ExprPtr> { std::move(v), std::move(v2) }, kind);
+               }
+               return v;
+       }
        /**
         * @brief Proxy function to parse expressions, which doesn't contain comparision operators
         *
@@ -461,7 +576,7 @@ class Parser
         */
        ExprPtr parseExprAboveComparisions()
        {
-               return parsePostfixExpr();
+               return parseExprOper6();
        }
 
        /**
@@ -518,12 +633,48 @@ class Parser
                }
                return e;
        }
+
+       ExprPtr parseBooleanExp3()
+       {
+               if (index < tokens.size() && tokens[index].text() == "not") {
+                       auto location = tokens[index].location();
+                       ++index;
+                       auto v = parseComparisionsExpr();
+                       return std::make_shared<OperatorEvaluator>(location, ExprPtrs{ std::move(v) }, OperatorEvaluator::Kind::NOT);
+               }
+               return parseComparisionsExpr();
+       }
+
+       ExprPtr parseBooleanExp2()
+       {
+               auto v = parseBooleanExp3();
+               while (index < tokens.size() && tokens[index].text() == "or") {
+                       auto location = tokens[index].location();
+                       ++index;
+                       auto v2 = parseBooleanExp3();
+                       v = std::make_shared<OperatorEvaluator>(location, ExprPtrs{ std::move(v), std::move(v2) }, OperatorEvaluator::Kind::LOG_OR);
+               }
+               return std::move(v);
+       }
+
+       ExprPtr parseBooleanExp1()
+       {
+               auto v = parseBooleanExp2();
+               while (index < tokens.size() && tokens[index].text() == "and") {
+                       auto location = tokens[index].location();
+                       ++index;
+                       auto v2 = parseBooleanExp2();
+                       v = std::make_shared<OperatorEvaluator>(location, ExprPtrs{ std::move(v), std::move(v2) }, OperatorEvaluator::Kind::LOG_AND);
+               }
+               return std::move(v);
+       }
+
        /**
         * @brief Tries to parse expression - root of expression parsing
         */
        ExprPtr parseExpr()
        {
-               return parseComparisionsExpr();
+               return parseBooleanExp1();
        }
 
        /**
@@ -535,18 +686,19 @@ class Parser
        {
                StatPtrs statements;
                auto loc = tokens[index].location();
-               while (index < tokens.size()) {
-                       if (tokens[index].type() == TokenType::END_OF_LINE) {
-                               ++index;
-                               continue;
-                       }
-                       if (canConsume("}")) break;
-                       auto e = parseLine();
-                       if (e) {
-                               statements.push_back(std::move(e));
-                       } else {
-                               while (index < tokens.size() && tokens[index].type() != TokenType::END_OF_LINE) ++index;
-                               ++index;
+               if (index < tokens.size() && !canConsume("}")) {
+                       while (index < tokens.size() && !canConsume("}")) {
+                               if (tokens[index].type() == TokenType::END_OF_LINE) {
+                                       ++index;
+                                       continue;
+                               }
+                               auto e = parseLine();
+                               if (e) {
+                                       statements.push_back(std::move(e));
+                               } else {
+                                       while (index < tokens.size() && tokens[index].type() != TokenType::END_OF_LINE) ++index;
+                                       ++index;
+                               }
                        }
                }
                return std::make_shared<BlockEvaluator>(std::move(loc), std::move(statements));
@@ -581,6 +733,17 @@ class Parser
                return line;
        }
 
+       ExprPtr parseLambda()
+       {
+               auto location = tokens[index].location();
+               auto args = consumeArguments();
+               if (!args)
+                       return {};
+               auto block = parseBlock();
+               if (!block)
+                       return {};
+               return std::make_shared<LambdaEvaluator>(std::move(location), std::move(*args), std::move(block));
+       }
        /**
         * @brief Tries to parse single function
         */
@@ -601,6 +764,71 @@ class Parser
                return std::make_shared<FunctionEvaluator>(std::move(location), std::move(functionName), std::move(*args), std::move(block));
        }
 
+       StatPtr parseIf()
+       {
+               auto location = tokens[index].location();
+               if (!consume("if", "elif")) return {};
+               if (!consume("(")) return {};
+               auto v = parseExpr();
+               if (!consume(")")) return {};
+               auto block = parseLine();
+               StatPtr else_;
+               if (canConsume("else")) {
+                       consume("else");
+                       else_ = parseLine();
+               } else if (canConsume("elif")) {
+                       else_ = parseIf();
+               }
+               return std::make_shared<IfEvaluator>(std::move(location), std::move(v), std::move(block), std::move(else_));
+       }
+
+       StatPtr parseWhile()
+       {
+               auto location = tokens[index].location();
+               if (!consume("while")) return {};
+               if (!consume("(")) return {};
+               auto expr = parseExpr();
+               if (!consume(")")) return {};
+               auto block = parseLine();
+               StatPtr else_;
+               if (canConsume("else")) {
+                       consume("else");
+                       else_ = parseLine();
+               }
+               return std::make_shared<WhileEvaluator>(std::move(location), std::move(expr), std::move(block), std::move(else_));
+       }
+
+       StatPtr parseFor()
+       {
+               auto location = tokens[index].location();
+               if (!consume("for")) return {};
+               if (!consume("(")) return {};
+               auto ident = consumeIdentifier();
+               if (!consume("in")) return {};
+               auto expr = parseExpr();
+               if (!consume(")")) return {};
+               auto block = parseLine();
+               StatPtr else_;
+               if (canConsume("else")) {
+                       consume("else");
+                       else_ = parseLine();
+               }
+               return std::make_shared<ForEvaluator>(std::move(location), std::move(ident), std::move(expr), std::move(block), std::move(else_));
+       }
+
+       StatPtr parseBreak()
+       {
+               auto location = tokens[index].location();
+               if (!consume("break")) return {};
+               return std::make_shared<BreakEvaluator>(std::move(location));
+       }
+
+       StatPtr parseContinue()
+       {
+               auto location = tokens[index].location();
+               if (!consume("continue")) return {};
+               return std::make_shared<ContinueEvaluator>(std::move(location));
+       }
        /**
         * @brief Tries to parse return statement
         */
@@ -610,7 +838,7 @@ class Parser
                if (!consume("return"))
                        return {};
                ExprPtr expression;
-               if (!canConsume(TokenType::END_OF_LINE)) {
+               if (!canConsume(TokenType::END_OF_LINE) && !canConsume("}")) {
                        expression = parseExpr();
                        if (!expression)
                                return {};
@@ -632,13 +860,23 @@ class Parser
                        line = parseBlock();
                } else if (tokens[index].text() == "def") {
                        line = parseFunction();
+               } else if (tokens[index].text() == "break") {
+                       line = parseBreak();
+               } else if (tokens[index].text() == "continue") {
+                       line = parseContinue();
+               } else if (tokens[index].text() == "while") {
+                       line = parseWhile();
+               } else if (tokens[index].text() == "if") {
+                       line = parseIf();
+               } else if (tokens[index].text() == "for") {
+                       line = parseFor();
                } else if (tokens[index].text() == "return") {
                        line = parseReturn();
                } else {
                        auto expr = parseExpr();
                        if (!expr) return {};
                        if (!canConsume("->")) {
-                               if (!consume(TokenType::END_OF_LINE)) return {};
+                               if (!canConsume("}") && !canConsume(TokenType::END_OF_LINE)) return {};
                                tryWait = false;
                        }
                        auto loc = expr->location();
@@ -653,9 +891,10 @@ class Parser
                                if (!r) return {};
                                waits.push_back(std::move(r));
                        }
-                       if (!consume(TokenType::END_OF_LINE)) return {};
+                       if (!canConsume(TokenType::END_OF_LINE)) return {};
                        line = std::make_shared<WaitEvaluator>(loc, std::move(line), std::move(waits));
                }
+               if (canConsume(TokenType::END_OF_LINE)) consume(TokenType::END_OF_LINE);
                return std::move(line);
        }
 public:
index 6d5357d0861c27596d3e434db648f6350d8bac3b..d5482e0ccce402c024452ccf96b0e59c191a332d 100644 (file)
@@ -38,5 +38,12 @@ private:
        EvaluationValue result;
 };
 
+class ContinueValue
+{
+};
+
+class BreakValue
+{
+};
 
 #endif //RETURN_VALUE_HPP
index e2d0613a2448a4a0744bc07017c2810c4a77a0eb..0bc335732de33575fa88c2a1aaedabdb69af9f85 100644 (file)
@@ -19,6 +19,7 @@
 #include "UniversalSwitchLog.hpp"
 #include "DoneCallback.hpp"
 #include "dbusLocators.hpp"
+#include "batch/Monitor.hpp"
 
 #include <efl_util.h>
 #include <bundle_internal.h>
index a203b73064ad78999a2eb7a2d23a954df31d225d..c4d064d0b0884745a7bc6b7909679f7f7a31c50c 100644 (file)
@@ -173,6 +173,11 @@ protected:
                        output << ">>> " << val << "\n";
                        return {};
                };
+               vars["str"] = EvaluationValueFunction{ [](EvaluationValue e) -> EvaluationValue {
+                               std::ostringstream tmp;
+                               tmp << e;
+                               return tmp.str();
+                       },  { { "value" } } };
        }
 
        void SetUp(void) override
@@ -202,11 +207,11 @@ protected:
                std::vector<std::string> errors;
                auto result = parseTokens(errors, tokens);
 
-               if (!errors.empty()) {
+               if (!errors.empty() || !result) {
                        if (printException) {
                                std::ostringstream tmp;
                                DebugEvaluatorInterface::setCurrentInterface(std::make_unique<StreamDebugEvaluatorInterface>(std::cout));
-                               result->printSelfInfo(0);
+                               if (result) result->printSelfInfo(0);
                                DebugEvaluatorInterface::setCurrentInterface(nullptr);
                                for (auto &e : errors) {
                                        std::cout << e << "\n";
@@ -214,6 +219,10 @@ protected:
                        }
                        throw ParseFailure{};
                }
+               if (result) {
+                       //DebugEvaluatorInterface::setCurrentInterface(std::make_unique<StreamDebugEvaluatorInterface>(std::cout));
+                       //result->printSelfInfo(0);
+               }
                return result;
        }
 
@@ -230,7 +239,10 @@ protected:
                                while (i < txt.size()) {
                                        auto n = txt.find('\n', i);
                                        if (n == std::string::npos) n = txt.size();
-                                       output << std::setw(2) << c << ": " << txt.substr(i, n - i) << "\n";
+                                       auto m = txt.substr(i, n - i);
+                                       for (auto &q : m)
+                                               if (q < ' ') q = ' ';
+                                       output << std::setw(2) << c << ": " << m << "\n";
                                        if (e.hasLocation() && c == e.location().lineNum()) {
                                                for (auto i = 1u; i < e.location().offsetNum(); ++i)
                                                        output << " ";
@@ -261,6 +273,7 @@ protected:
        }
        void executeCountAsserts(std::string txt, size_t count = 1)
        {
+
                try {
                        execute(std::move(txt), true);
                } catch (EvaluationFailure &e) {
@@ -320,63 +333,111 @@ TEST_F(ScriptTest, simpleComparisions)
                , 12 + 8 + 8 + 8 + 4);
 }
 
+TEST_F(ScriptTest, simpleOperators)
+{
+       executeCountAsserts(
+               R"__(
+               assert(3 + 5 == 8)
+               assert(3 - 5 == -2)
+               assert(3 * 5 == 15)
+               assert(3 / 6 == 0.5)
+               assert(7 % 3 == 1)
+               assert(3 | 5 == 7)
+               assert(3 & 5 == 1)
+               assert(3 ^ 5 == 6)
+               assert(~3 == 18446744073709551612)
+               assert(~(-4) == 3)
+               )__"
+               , 10);
+}
+
 TEST_F(ScriptTest, vector)
 {
        executeCountAsserts(
-               "v = [1, 2, 3]\n"
-               "assert(v[0] == 1)\n"
-               "assert(v[1] == 2)\n"
-               "assert(v[2] == 3)\n"
-               "assert(v[-1] == 3)\n"
-               "assert(v[-2] == 2)\n"
-               "assert(v[-3] == 1)\n"
-               "assert(v[1:2] == [2])\n"
-               "assert(v[-2:-1] == [2])\n"
-               "v[1:2] = [4, 5, 6]\n"
-               "print(v)\n"
-               "assert(v == [1, 4, 5, 6, 3])\n"
-               "assert([1] != [2])\n"
-               "assert([1] == [1])\n"
-               "assert([1] != [])\n"
-               "assert([] == [])\n"
-               "assert([1, 2, 3] != [1, 2, 3, 4])\n"
-               "assert([1, 2, 3] < [1, 2, 3, 4])\n"
-               "assert([1, 2, 3] <= [1, 2, 3, 4])\n"
-               "assert([1, 2, 3, 5 ] > [1, 2, 3, 4])\n"
-               "assert([1, 2, 3, 5 ] >= [1, 2, 3, 4])\n"
-               "assert(1 in [1,2,3])\n"
-               "assert(1 not in [2,3])\n"
-               "assert(not (1 in [2,3]))\n"
-               , 21);
+               R"__(
+               v = [1, 2, 3]
+               assert(v[0] == 1)
+               assert(v[1] == 2)
+               assert(v[2] == 3)
+               assert(v[-1] == 3)
+               assert(v[-2] == 2)
+               assert(v[-3] == 1)
+               assert(v[1:2] == [2])
+               assert(v[-2:-1] == [2])
+               v[1:2] = [4, 5, 6]
+               assert(v == [1, 4, 5, 6, 3])
+               assert([1] != [2])
+               assert([1] == [1])
+               assert([1] != [])
+               assert([] == [])
+               assert([1, 2, 3] != [1, 2, 3, 4])
+               assert([1, 2, 3] < [1, 2, 3, 4])
+               assert([1, 2, 3] <= [1, 2, 3, 4])
+               assert([1, 2, 3, 5 ] > [1, 2, 3, 4])
+               assert([1, 2, 3, 5 ] >= [1, 2, 3, 4])
+               assert(1 in [1,2,3])
+               assert(1 not in [2,3])
+               assert(not (1 in [2,3]))
+               v = []
+               v.append(1)
+               v.append(2)
+               v.insert(1, 3)
+               assert(v == [1, 3, 2])
+               assert(v.pop() == 2)
+               assert(v == [1, 3])
+               v.append(4)
+               assert(v == [1, 3, 4])
+               assert(v.pop(1) == 3)
+               assert(v == [1, 4])
+               v = [1, 2, 3, 4, 5]
+               print(v.filter(def(v){ return true }))
+               v = v.filter(def(v) { return (v & 1) })
+               print(v)
+               assert(v == [1, 3, 5])
+               assert([1, 2, 3] + [4, 5] == [1, 2, 3, 4, 5])
+               )__"
+               , 29);
 }
 
 TEST_F(ScriptTest, set)
 {
        executeCountAsserts(
-               "v = {1, 2, 3, '1', '2', '3'}\n"
-               "assert(1 in v)\n"
-               "assert(2 in v)\n"
-               "assert(3 in v)\n"
-               "assert('1' in v)\n"
-               "assert('2' in v)\n"
-               "assert('3' in v)\n"
-               "assert('4' not in v)\n"
-               "assert(not ('4' in v))\n"
-               , 8);
+               R"__(
+               v = {1, 2, 3, '1', '2', '3'}
+               assert(1 in v)
+               assert(2 in v)
+               assert(3 in v)
+               assert('1' in v)
+               assert('2' in v)
+               assert('3' in v)
+               assert('4' not in v)
+               assert(not ('4' in v))
+               assert({ 1, 2, 3 } | { 3, 4, 5 } == { 1, 2, 3, 4, 5})
+               assert({ 1, 2, 3 } & { 3, 4, 5 } == { 3})
+               assert({ 1, 2, 3 } ^ { 3, 4, 5 } == { 1, 2, 4, 5})
+               )__"
+               , 11);
 }
 
 TEST_F(ScriptTest, map)
 {
        executeCountAsserts(
-               "v = {1: 1, 2: 2, '1': 3}\n"
-               "assert(1 in v)\n"
-               "assert(2 in v)\n"
-               "assert(3 not in v)\n"
-               "assert('1' in v)\n"
-               "assert('2' not in v)\n"
-               "assert(v[1] == 1)\n"
-               "assert(v['1'] == 3)\n"
-               , 7);
+               R"__(
+               v = {1: 1, 2: 2, '1': 3}
+               assert(1 in v)
+               assert(2 in v)
+               assert(3 not in v)
+               assert('1' in v)
+               assert('2' not in v)
+               assert(v[1] == 1)
+               assert(v['1'] == 3)
+               v1 = { 1:11, 2:22, 3:33 }
+               v2 = { 3:33, 4:44, 5:55 }
+               assert(v1 | v2 == { 1:11, 2:22, 3:33, 4:44, 5:55 })
+               assert(v1 & v2 == { 3:33 })
+               assert(v1 ^ v2 == { 1:11, 2:22, 4:44, 5:55 })
+               )__"
+               , 10);
 }
 
 TEST_F(ScriptTest, point)
@@ -397,6 +458,104 @@ TEST_F(ScriptTest, comments)
                , 1);
 }
 
+TEST_F(ScriptTest, whileStatement)
+{
+       executeCountAsserts(
+               R"__(
+               def f(q) {
+                       v = []
+                       a = 0
+                       while(a < 2) {
+                               a = a + 1
+                               if (q == 1) break
+                               if (q == 2) {
+                                       q = -1
+                                       continue
+                               }
+                               v.append(str(a))
+                       }
+                       else {
+                               if (q != 3) v.append('3')
+                       }
+                       v = '.'.join(v)
+                       return v
+               }
+               assert(f(0) == '1.2.3')
+               assert(f(1) == '')
+               assert(f(2) == '2.3')
+               assert(f(3) == '1.2')
+               )__"
+               , 4);
+}
+
+TEST_F(ScriptTest, forStatement)
+{
+       executeCountAsserts(
+               R"__(
+               v = []
+               for(a in [1, 2, 3, 4]) {
+                       if (a & 1) {
+                               v.append(a * 2)
+                               print('1')
+                       }
+               }
+               print(v)
+               assert(v == [2, 6])
+               )__"
+               , 1);
+}
+
+TEST_F(ScriptTest, forStatement2)
+{
+       executeCountAsserts(
+               R"__(
+               def f(q) {
+                       v = []
+                       for(a in [1, 2]) {
+                               if (q == 1) break
+                               if (q == 2) {
+                                       q = -1
+                                       continue
+                               }
+                               v.append(str(a))
+                       }
+                       else {
+                               if (q != 3) v.append('3')
+                       }
+                       v = '.'.join(v)
+                       return v
+               }
+               assert(f(0) == '1.2.3')
+               assert(f(1) == '')
+               assert(f(2) == '2.3')
+               assert(f(3) == '1.2')
+               )__"
+               , 4);
+}
+
+TEST_F(ScriptTest, ifStatement)
+{
+       executeCountAsserts(
+               R"__(
+               def f(q) {
+                       if (q == 1) return 11
+                       elif (q == 2) return 22
+                       else if (q == 3) return 33
+                       else {
+                               if (q == 4) return 44
+                               return 55
+                       }
+               }
+               assert(f(1) == 11)
+               assert(f(2) == 22)
+               assert(f(3) == 33)
+               assert(f(4) == 44)
+               assert(f(5) == 55)
+               assert(f(6) == 55)
+               )__"
+               , 6);
+}
+
 TEST_F(ScriptTest, defaultArguments)
 {
        std::tuple<int, int, int, int> val, expected;