diff options
author | Stefan Radomski <github@mintwerk.de> | 2017-07-13 20:29:09 (GMT) |
---|---|---|
committer | Stefan Radomski <github@mintwerk.de> | 2017-07-13 20:29:09 (GMT) |
commit | 04b04aa6624caf73ffe4fc33f918e7f48b27da37 (patch) | |
tree | 40a8f92a0abd081f59a8aacc4b726dabf3c8f2f5 | |
parent | e0d6ac8097bfd148a9956128a48b7d1addf81e68 (diff) | |
download | uscxml-04b04aa6624caf73ffe4fc33f918e7f48b27da37.zip uscxml-04b04aa6624caf73ffe4fc33f918e7f48b27da37.tar.gz uscxml-04b04aa6624caf73ffe4fc33f918e7f48b27da37.tar.bz2 |
LambdaMonitors and prepared use-case examples
23 files changed, 533 insertions, 55 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a4ff9e..4c2e3dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -527,13 +527,13 @@ if (NOT CMAKE_CROSSCOMPILING) add_subdirectory(test) endif() -add_executable(uscxml-browser apps/uscxml-browser.cpp ${GETOPT_FILES}) +add_executable(uscxml-browser src/apps/uscxml-browser.cpp ${GETOPT_FILES}) set_property(TARGET uscxml-browser PROPERTY CXX_STANDARD 11) set_property(TARGET uscxml-browser PROPERTY CXX_STANDARD_REQUIRED ON) install_executable(TARGETS uscxml-browser COMPONENT tools) target_link_libraries(uscxml-browser uscxml) -add_executable(uscxml-transform apps/uscxml-transform.cpp ${GETOPT_FILES}) +add_executable(uscxml-transform src/apps/uscxml-transform.cpp ${GETOPT_FILES}) set_property(TARGET uscxml-transform PROPERTY CXX_STANDARD 11) set_property(TARGET uscxml-transform PROPERTY CXX_STANDARD_REQUIRED ON) install_executable(TARGETS uscxml-transform COMPONENT tools) @@ -8,11 +8,11 @@ - [Changes](docs/CHANGES.md) - [Tests passed](test/w3c/TESTS.md) - [Publications](docs/PUBLICATIONS.md) +- [Benchmarks](docs/BENCHMARKS.md) ## What is it? -uSCXML is a platform to work with state-charts given as -[SCXML](http://www.w3.org/TR/scxml/) files. It consists of three principal components: +uSCXML is a platform to work with state-charts given as [SCXML](http://www.w3.org/TR/scxml/) files. It features the [fastest microstep](docs/BENCHMARKS.md) implementation available and consists of three principal components: 1. `libuscxml`: [C++ library](#embedded-as-a-library) containing an interpreter and accompanying functionality. @@ -20,9 +20,7 @@ uSCXML is a platform to work with state-charts given as 3. `uscxml-transform`: A collection of [transformation](#for-transformations) implementations to transpile SCXML, e.g. onto ANSI-C and VHDL. -The status of the various datamodels, bindings and generators with regard to the [W3C IRP -tests](https://www.w3.org/Voice/2013/scxml-irp/) can be checked in the [test -table](test/w3c/TESTS.md). +The status of the various datamodels, bindings and generators with regard to the [W3C IRPtests](https://www.w3.org/Voice/2013/scxml-irp/) can be checked in the [test table](test/w3c/TESTS.md). ## Installation @@ -58,15 +56,13 @@ For more detailled information, refer to the [documentation](http://tklab-tud.gi **Examples:** -* [uscxml-browser.cpp](https://github.com/tklab-tud/uscxml/blob/master/apps/uscxml-browser.cpp) (**C++**) +* [uscxml-browser.cpp](https://github.com/tklab-tud/uscxml/blob/master/src/apps/uscxml-browser.cpp) (**C++**) * [test-state-pass.cpp](https://github.com/tklab-tud/uscxml/blob/master/test/src/test-state-pass.cpp) (**C++**) * [TestStatePass.cs](https://github.com/tklab-tud/uscxml/blob/master/contrib/csharp/bindings/TestStatePass.cs) (**C#**) * [test-state-pass.py](https://github.com/tklab-tud/uscxml/blob/master/contrib/python/bindings/test-state-pass.py) (**Python**) * [JexlDataModelTest.java](https://github.com/tklab-tud/uscxml/blob/master/contrib/java/bindings/org/uscxml/tests/JexlDataModelTest.java) (**Java**) - - ### On the Command-line # interpret state-chart from url $ uscxml-browser https://raw.githubusercontent.com/tklab-tud/uscxml/master/test/w3c/null/test436.scxml @@ -78,34 +74,8 @@ For more detailled information, refer to the [documentation](http://tklab-tud.gi **Examples:** * [test-gen-c.cpp](https://github.com/tklab-tud/uscxml/blob/master/test/src/test-gen-c.cpp) (**C++**) -* [WaterPump.cxx](https://github.com/tklab-tud/uscxml/blob/master/apps/arduino/WaterPump.cxx) (**C++ on Arduino**) - -## Benchmarks - -We did conceive a [series of benchmark](https://github.com/tklab-tud/uscxml/tree/master/test/benchmarks) SCXML documents to evaluate the performance of the various SCXML implementations. The state-charts in the benchmarks are completely artificial and bear no resemblance to real-world state-charts. However, they may provide a general guidance to get an impression about the performance of the different implementations. - -The state-charts each stress a specific feature of any SCXML `microstep(T)` implementation. Each contains a state `mark` that is continuously entered and exited as part of a sequence of spontaneous microsteps and measures the entries per second. For every implementation, the [benchmark is run](https://github.com/tklab-tud/uscxml/blob/master/contrib/benchmarks/run.sh) for a number of seconds and the iterations per seconds are averaged. The benchmarks exist in increasing complexity from very simple with, e.g., 4 states nested in a depth of 4 compounds up until 512 for state-charts with > 250.000 states. - -**Note:** If you are the author / maintainer of one of the SCXML implementations being benchmarked below and feel that I misrepresent your implementation's performance, post an issue and I will set things straight. - -**Note:** There are two `microstep(T)` implementations in uSCXML, namely `fast` and `large` with the former being the default for transpilation and the latter for interpretation. Both are being employed on an interpreted state-chart here. For the `fast` microstep implementation we measured the case with pre-calculated predicates. - -**Note:** The numbers for scxmlcc are necessarily for the compiled case and N/A if we could not compile the state-chart within the time limit. - -### Transitions - -The Transitions benchmark measures transition selection with many conflicting transitions enabled as part of a microstep. - -![Transition Benchmark](https://user-images.githubusercontent.com/980655/27858834-004c9c78-6177-11e7-8519-2f73f0ff9fb4.png) - -### LCCA -When exiting a state via a transition, the least-common compound ancestor (LCCA) of the transition's targets and source state has to be identified. This is a common operation and its runtime is proportional to the nesting depth if implemented respectively. - -![LCCA Benchmark](https://user-images.githubusercontent.com/980655/27858835-00527ecc-6177-11e7-85d2-46c83ad5ed71.png) - -### Conclusion +* [WaterPump.cxx](https://github.com/tklab-tud/uscxml/blob/master/src/apps/arduino/WaterPump.cxx) (**C++ on Arduino**) -uSCXML with either microstep implementation is consistently the fastest with the exception of the Transitions benchmark, where the compiled `scxmlcc` is degenerating slower for more complex state-charts. This may be due to compiler optimizations (or an incomplete implementation) and it would be interesting to compare `scxmlcc` against the transpiled ANSI-C code from `uscxml-transform`. However, the limiting factor here becomes the time required to transpile the state-chart or to compile the generated source file into an executable binary respectively. With regard to huge state-charts, the large microstep implementation of `uSCXML` performs best and retains acceptable performance throughout the range of benchmarks, only surpassed by the fast implementation for smaller complexities. ## Changes diff --git a/contrib/cmake/CPackUSCXML.cmake b/contrib/cmake/CPackUSCXML.cmake index 2a6f88b..e9bc5ec 100644 --- a/contrib/cmake/CPackUSCXML.cmake +++ b/contrib/cmake/CPackUSCXML.cmake @@ -146,6 +146,11 @@ set(CPACK_DEBIAN_PACKAGE_NAME "uscxml") set(CPACK_RPM_PACKAGE_NAME "uscxml") set(CPACK_RPM_PACKAGE_LICENSE "Simplified BSD") +######################################## +# CMake Modules for clients +######################################## + +install(FILES ${PROJECT_SOURCE_DIR}/contrib/cmake/FindUSCXML.cmake DESTINATION share/uscxml/cmake COMPONENT library) ######################################## # Describe layout of package diff --git a/contrib/cmake/FindUSCXML.cmake b/contrib/cmake/FindUSCXML.cmake new file mode 100644 index 0000000..bf3605d --- /dev/null +++ b/contrib/cmake/FindUSCXML.cmake @@ -0,0 +1,84 @@ +# - Find USCXML +# This module checks if uSCXML is installed and determines where the +# include files and libraries are. This code sets the following +# variables: +# +# USCXML_INCLUDE_DIR = The full path to the uscxml headers +# USCXML_LIBRARIES = All uscxml libraries for release and debug builds +# +# Example: +# find_package(USCXML REQUIRED) +# include_directories(${USCXML_INCLUDE_DIR}) +# + +################################################### +# where to search for uscxml headers and libraries +################################################### +set(_USCXML_LIB_SEARCHPATH + ${USCXML_LIBRARY_ROOT} + "/usr/local" + "/opt/local" + "C:/Program Files (x86)/uSCXML" + "C:/Program Files/uSCXML" +) + +################################################### +# find the uSCXML header files +################################################### +FIND_PATH(USCXML_INCLUDE_DIR uscxml/uscxml.h + PATH_SUFFIXES include + PATHS ${_USCXML_LIB_SEARCHPATH} ${USCXML_HEADER_ROOT} + ENV USCXML_INCLUDE_DIR +) + + +set(USCXML_LIBRARIES) +# prefer MinSizeRel libraries +FIND_LIBRARY(USCXML_LIBRARY_RELEASE + PATH_SUFFIXES lib + NAMES uscxml_s + PATHS ${_USCXML_LIB_SEARCHPATH} + ENV USCXML_LIB_DIR +) +if (USCXML_LIBRARY_RELEASE) + list(APPEND USCXML_LIBRARIES optimized ${USCXML_LIBRARY_RELEASE}) +else() + # if no minsize libraries were found try normal release + FIND_LIBRARY(USCXML_LIBRARY_RELEASE + PATH_SUFFIXES lib + NAMES uscxml + PATHS ${_USCXML_LIB_SEARCHPATH} + ENV USCXML_LIB_DIR + ) + if (USCXML_LIBRARY_RELEASE) + list(APPEND USCXML_LIBRARIES optimized USCXML_LIBRARY_RELEASE) + endif() +endif() + +# prefer release with debug libraries +FIND_LIBRARY(USCXML_LIBRARY_DEBUG + PATH_SUFFIXES lib + NAMES uscxml_rd + PATHS ${_USCXML_LIB_SEARCHPATH} + ENV USCXML_LIB_DIR +) +if ("${USCXML_LIBRARY_DEBUG}") + list(APPEND USCXML_LIBRARIES debug ${USCXML_LIBRARY_DEBUG}) +else() + # go for normal debug libraries insteaf + FIND_LIBRARY(USCXML_LIBRARY_DEBUG + PATH_SUFFIXES lib + NAMES uscxml_d + PATHS ${_USCXML_LIB_SEARCHPATH} + ENV USCXML_LIB_DIR + ) + if ("${USCXML_LIBRARY_DEBUG}") + list(APPEND USCXML_LIBRARIES debug USCXML_LIBRARY_DEBUG) + endif() +endif() + + + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(USCXML DEFAULT_MSG USCXML_LIBRARIES USCXML_INCLUDE_DIR) +MARK_AS_ADVANCED(USCXML_INCLUDE_DIR USCXML_LIBRARIES) diff --git a/docs/BENCHMARKS.md b/docs/BENCHMARKS.md new file mode 100644 index 0000000..685c287 --- /dev/null +++ b/docs/BENCHMARKS.md @@ -0,0 +1,26 @@ +# Benchmarks + +We did conceive a [series of benchmark](https://github.com/tklab-tud/uscxml/tree/master/test/benchmarks) SCXML documents to evaluate the performance of the various SCXML implementations. The state-charts in the benchmarks are completely artificial and bear no resemblance to real-world state-charts. However, they may provide a general guidance to get an impression about the performance of the different implementations. + +The state-charts each stress a specific feature of any SCXML `microstep(T)` implementation. Each contains a state `mark` that is continuously entered and exited as part of a sequence of spontaneous microsteps and measures the entries per second. For every implementation, the [benchmark is run](https://github.com/tklab-tud/uscxml/blob/master/contrib/benchmarks/run.sh) for a number of seconds and the iterations per seconds are averaged. The benchmarks exist in increasing complexity from very simple with, e.g., 4 states nested in a depth of 4 compounds up until 512 for state-charts with > 250.000 states. + +**Note:** If you are the author / maintainer of one of the SCXML implementations being benchmarked below and feel that I misrepresent your implementation's performance, post an issue and I will set things straight. + +**Note:** There are two `microstep(T)` implementations in uSCXML, namely `fast` and `large` with the former being the default for transpilation and the latter for interpretation. Both are being employed on an interpreted state-chart here. For the `fast` microstep implementation we measured the case with pre-calculated predicates. + +**Note:** The numbers for scxmlcc are necessarily for the compiled case and N/A if we could not compile the state-chart within the time limit. + +## Transitions + +The Transitions benchmark measures transition selection with many conflicting transitions enabled as part of a microstep. + +![Transition Benchmark](https://user-images.githubusercontent.com/980655/27858834-004c9c78-6177-11e7-8519-2f73f0ff9fb4.png) + +## LCCA +When exiting a state via a transition, the least-common compound ancestor (LCCA) of the transition's targets and source state has to be identified. This is a common operation and its runtime is proportional to the nesting depth if implemented respectively. + +![LCCA Benchmark](https://user-images.githubusercontent.com/980655/27858835-00527ecc-6177-11e7-85d2-46c83ad5ed71.png) + +## Conclusion + +uSCXML with either microstep implementation is consistently the fastest with the exception of the Transitions benchmark, where the compiled `scxmlcc` is degenerating slower for more complex state-charts. This may be due to compiler optimizations (or an incomplete implementation) and it would be interesting to compare `scxmlcc` against the transpiled ANSI-C code from `uscxml-transform`. However, the limiting factor here becomes the time required to transpile the state-chart or to compile the generated source file into an executable binary respectively. With regard to huge state-charts, the large microstep implementation of `uSCXML` performs best and retains acceptable performance throughout the range of benchmarks, only surpassed by the fast implementation for smaller complexities. diff --git a/examples/cpp/library/lambdas/CMakeLists.txt b/examples/cpp/library/lambdas/CMakeLists.txt new file mode 100644 index 0000000..c062e64 --- /dev/null +++ b/examples/cpp/library/lambdas/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 2.8.6) +project(simple-scxml) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "/usr/local/share/uscxml/cmake/") +find_package(USCXML REQUIRED) + + +include_directories(${USCXML_INCLUDE_DIR}) +add_executable(simple main.cpp) +target_link_libraries(simple ${USCXML_LIBRARIES})
\ No newline at end of file diff --git a/examples/cpp/library/lambdas/main.cpp b/examples/cpp/library/lambdas/main.cpp new file mode 100644 index 0000000..316576b --- /dev/null +++ b/examples/cpp/library/lambdas/main.cpp @@ -0,0 +1,17 @@ +#include <iostream> +#include "uscxml/uscxml.h" + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + std::cerr << "Expected URL with SCXML document as first argument" << std::endl; + return -1; + } + + uscxml::Interpreter sc = uscxml::Interpreter::fromURL(argv[1]); + uscxml::InterpreterState state; + while ((state = sc.step()) != uscxml::USCXML_FINISHED) { + } + + return 0; +} diff --git a/examples/cpp/library/simple/CMakeLists.txt b/examples/cpp/library/simple/CMakeLists.txt new file mode 100644 index 0000000..c062e64 --- /dev/null +++ b/examples/cpp/library/simple/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 2.8.6) +project(simple-scxml) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "/usr/local/share/uscxml/cmake/") +find_package(USCXML REQUIRED) + + +include_directories(${USCXML_INCLUDE_DIR}) +add_executable(simple main.cpp) +target_link_libraries(simple ${USCXML_LIBRARIES})
\ No newline at end of file diff --git a/examples/cpp/library/simple/main.cpp b/examples/cpp/library/simple/main.cpp new file mode 100644 index 0000000..316576b --- /dev/null +++ b/examples/cpp/library/simple/main.cpp @@ -0,0 +1,17 @@ +#include <iostream> +#include "uscxml/uscxml.h" + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + std::cerr << "Expected URL with SCXML document as first argument" << std::endl; + return -1; + } + + uscxml::Interpreter sc = uscxml::Interpreter::fromURL(argv[1]); + uscxml::InterpreterState state; + while ((state = sc.step()) != uscxml::USCXML_FINISHED) { + } + + return 0; +} diff --git a/apps/arduino/WaterPump.cxx b/examples/cpp/transpiled/arduino/WaterPump.cxx index 01f4cfa..01f4cfa 100644 --- a/apps/arduino/WaterPump.cxx +++ b/examples/cpp/transpiled/arduino/WaterPump.cxx diff --git a/apps/arduino/WaterPump.scxml b/examples/cpp/transpiled/arduino/WaterPump.scxml index a7d8bad..a7d8bad 100644 --- a/apps/arduino/WaterPump.scxml +++ b/examples/cpp/transpiled/arduino/WaterPump.scxml diff --git a/apps/arduino/stateMachine.c b/examples/cpp/transpiled/arduino/stateMachine.c index a74535b..a74535b 100644 --- a/apps/arduino/stateMachine.c +++ b/examples/cpp/transpiled/arduino/stateMachine.c diff --git a/apps/uscxml-browser.cpp b/src/apps/uscxml-browser.cpp index dd0633b..dd0633b 100644 --- a/apps/uscxml-browser.cpp +++ b/src/apps/uscxml-browser.cpp diff --git a/apps/uscxml-browser.vbs b/src/apps/uscxml-browser.vbs index fc8ea9a..fc8ea9a 100644 --- a/apps/uscxml-browser.vbs +++ b/src/apps/uscxml-browser.vbs diff --git a/apps/uscxml-debugger.html b/src/apps/uscxml-debugger.html index fa49554..fa49554 100644 --- a/apps/uscxml-debugger.html +++ b/src/apps/uscxml-debugger.html diff --git a/apps/uscxml-transform.cpp b/src/apps/uscxml-transform.cpp index e99ed68..e99ed68 100644 --- a/apps/uscxml-transform.cpp +++ b/src/apps/uscxml-transform.cpp diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index c4025ba..f3aedee 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -271,6 +271,10 @@ std::list<InterpreterIssue> Interpreter::validate() { return InterpreterIssue::forInterpreter(_impl.get()); } +LambdaMonitor& Interpreter::on() { + return _impl->on(); +} + #if 1 static void printNodeSet(Logger& logger, const std::list<XERCESC_NS::DOMElement*> nodes) { std::string seperator; diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index 3c44400..aff77a2 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -34,6 +34,7 @@ #include "uscxml/interpreter/ContentExecutor.h" #include "uscxml/interpreter/EventQueue.h" #include "uscxml/interpreter/InterpreterState.h" +#include "uscxml/interpreter/InterpreterMonitor.h" #ifdef max #error define NOMINMAX or undefine the max macro please (https://support.microsoft.com/en-us/kb/143208) @@ -42,6 +43,7 @@ namespace uscxml { class InterpreterMonitor; +class LambdaMonitor; class InterpreterImpl; class InterpreterIssue; @@ -234,6 +236,9 @@ public: std::shared_ptr<InterpreterImpl> getImpl() const { return _impl; } + + LambdaMonitor& on(); + #if 0 // "Ambiguous user-defined-conversion" with operator bool() on MSVC from Visual Studio 12 explicit operator MicroStepCallbacks*() { diff --git a/src/uscxml/interpreter/InterpreterImpl.cpp b/src/uscxml/interpreter/InterpreterImpl.cpp index 414dba2..1caa3f0 100644 --- a/src/uscxml/interpreter/InterpreterImpl.cpp +++ b/src/uscxml/interpreter/InterpreterImpl.cpp @@ -103,6 +103,9 @@ InterpreterImpl::~InterpreterImpl() { if (_document) delete _document; + if (_lambdaMonitor) + delete _lambdaMonitor; + { std::lock_guard<std::recursive_mutex> lock(_instanceMutex); _instances.erase(getSessionId()); @@ -139,7 +142,7 @@ void InterpreterImpl::reset() { if (_microStepper) _microStepper.reset(); - _isInitialized = false; +// _isInitialized = false; _state = USCXML_INSTANTIATED; // _dataModel.reset(); if (_delayQueue) @@ -622,4 +625,12 @@ void InterpreterImpl::enqueueAtParent(const Event& event) { } +LambdaMonitor& InterpreterImpl::on() { + if (_lambdaMonitor == NULL) { + _lambdaMonitor = new LambdaMonitor(); + addMonitor(_lambdaMonitor); + } + return *_lambdaMonitor; +} + } diff --git a/src/uscxml/interpreter/InterpreterImpl.h b/src/uscxml/interpreter/InterpreterImpl.h index 42d61f2..2f5fb07 100644 --- a/src/uscxml/interpreter/InterpreterImpl.h +++ b/src/uscxml/interpreter/InterpreterImpl.h @@ -269,9 +269,13 @@ public: return _document; } + LambdaMonitor& on(); + protected: static void addInstance(std::shared_ptr<InterpreterImpl> instance); - + + LambdaMonitor* _lambdaMonitor = NULL; + Binding _binding; ActionLanguage _al; diff --git a/src/uscxml/interpreter/InterpreterMonitor.h b/src/uscxml/interpreter/InterpreterMonitor.h index 43b7f53..ed62675 100644 --- a/src/uscxml/interpreter/InterpreterMonitor.h +++ b/src/uscxml/interpreter/InterpreterMonitor.h @@ -65,26 +65,47 @@ public: InterpreterMonitor(Logger logger) : _copyToInvokers(false), _logger(logger) {} virtual ~InterpreterMonitor() {} - virtual void beforeProcessingEvent(const std::string& sessionId, const Event& event) {} + virtual void beforeProcessingEvent(const std::string& sessionId, + const Event& event) {} virtual void beforeMicroStep(const std::string& sessionId) {} - virtual void beforeExitingState(const std::string& sessionId, const std::string& stateName, const XERCESC_NS::DOMElement* state) {} - virtual void afterExitingState(const std::string& sessionId, const std::string& stateName, const XERCESC_NS::DOMElement* state) {} + virtual void beforeExitingState(const std::string& sessionId, + const std::string& stateName, + const XERCESC_NS::DOMElement* state) {} + virtual void afterExitingState(const std::string& sessionId, + const std::string& stateName, + const XERCESC_NS::DOMElement* state) {} - virtual void beforeExecutingContent(const std::string& sessionId, const XERCESC_NS::DOMElement* execContent) {} - virtual void afterExecutingContent(const std::string& sessionId, const XERCESC_NS::DOMElement* execContent) {} + virtual void beforeExecutingContent(const std::string& sessionId, + const XERCESC_NS::DOMElement* execContent) {} + virtual void afterExecutingContent(const std::string& sessionId, + const XERCESC_NS::DOMElement* execContent) {} - virtual void beforeUninvoking(const std::string& sessionId, const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid) {} - virtual void afterUninvoking(const std::string& sessionId, const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid) {} + virtual void beforeUninvoking(const std::string& sessionId, + const XERCESC_NS::DOMElement* invokeElem, + const std::string& invokeid) {} + virtual void afterUninvoking(const std::string& sessionId, + const XERCESC_NS::DOMElement* invokeElem, + const std::string& invokeid) {} - virtual void beforeTakingTransition(const std::string& sessionId, const XERCESC_NS::DOMElement* transition) {} - virtual void afterTakingTransition(const std::string& sessionId, const XERCESC_NS::DOMElement* transition) {} + virtual void beforeTakingTransition(const std::string& sessionId, + const XERCESC_NS::DOMElement* transition) {} + virtual void afterTakingTransition(const std::string& sessionId, + const XERCESC_NS::DOMElement* transition) {} - virtual void beforeEnteringState(const std::string& sessionId, const std::string& stateName, const XERCESC_NS::DOMElement* state) {} - virtual void afterEnteringState(const std::string& sessionId, const std::string& stateName, const XERCESC_NS::DOMElement* state) {} + virtual void beforeEnteringState(const std::string& sessionId, + const std::string& stateName, + const XERCESC_NS::DOMElement* state) {} + virtual void afterEnteringState(const std::string& sessionId, + const std::string& stateName, + const XERCESC_NS::DOMElement* state) {} - virtual void beforeInvoking(const std::string& sessionId, const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid) {} - virtual void afterInvoking(const std::string& sessionId, const XERCESC_NS::DOMElement* invokeElem, const std::string& invokeid) {} + virtual void beforeInvoking(const std::string& sessionId, + const XERCESC_NS::DOMElement* invokeElem, + const std::string& invokeid) {} + virtual void afterInvoking(const std::string& sessionId, + const XERCESC_NS::DOMElement* invokeElem, + const std::string& invokeid) {} virtual void afterMicroStep(const std::string& sessionId) {} virtual void onStableConfiguration(const std::string& sessionId) {} @@ -92,7 +113,8 @@ public: virtual void beforeCompletion(const std::string& sessionId) {} virtual void afterCompletion(const std::string& sessionId) {} - virtual void reportIssue(const std::string& sessionId, const InterpreterIssue& issue) {} + virtual void reportIssue(const std::string& sessionId, + const InterpreterIssue& issue) {} void copyToInvokers(bool copy) { _copyToInvokers = copy; @@ -125,6 +147,277 @@ protected: std::string _logPrefix; }; +class USCXML_API LambdaMonitor : public InterpreterMonitor { +public: + void processEvent(std::function<void (const std::string& sessionId, + const Event& event)> callback) { + _beforeProcessingEvent = callback; + } + + + void microStep(std::function<void (const std::string& sessionId)> callback, + bool after = false) { + if (after) { + _afterMicroStep = callback; + } else { + _beforeMicroStep = callback; + } + + } + + void exitState(std::function<void (const std::string& sessionId, + const std::string& stateName, + const XERCESC_NS::DOMElement* state)> callback, + bool after = false) { + if (after) { + _afterExitingState = callback; + } else { + _beforeExitingState = callback; + } + } + + void executeContent(std::function<void (const std::string& sessionId, + const XERCESC_NS::DOMElement* execContent)> callback, + bool after = false) { + if (after) { + _afterExecutingContent = callback; + } else { + _beforeExecutingContent = callback; + } + } + + void uninvoke(std::function<void (const std::string& sessionId, + const XERCESC_NS::DOMElement* invokeElem, + const std::string& invokeid)> callback, + bool after = false) { + if (after) { + _afterUninvoking = callback; + } else { + _beforeUninvoking = callback; + } + } + + void transition(std::function<void (const std::string& sessionId, + const XERCESC_NS::DOMElement* transition)> callback, + bool after = false) { + if (after) { + _afterTakingTransition = callback; + } else { + _beforeTakingTransition = callback; + } + } + + void enterState(std::function<void (const std::string& sessionId, + const std::string& stateName, + const XERCESC_NS::DOMElement* state)> callback, + bool after = false) { + _beforeEnteringState = callback; + if (after) { + _afterEnteringState = callback; + } else { + _beforeEnteringState = callback; + } + + } + + void invoke(std::function<void (const std::string& sessionId, + const XERCESC_NS::DOMElement* invokeElem, + const std::string& invokeid)> callback, + bool after = false) { + if (after) { + _afterInvoking = callback; + } else { + _beforeInvoking = callback; + } + } + + void stableConfiguration(std::function<void (const std::string& sessionId)> callback) { + _onStableConfiguration = callback; + } + + void completion(std::function<void (const std::string& sessionId)> callback, + bool after = false) { + if (after) { + _afterCompletion = callback; + } else { + _beforeCompletion = callback; + } + + } + + void reportIssue(std::function<void (const std::string& sessionId, + const InterpreterIssue& issue)> callback) { + _reportIssue = callback; + } + +protected: + + std::function<void (const std::string& sessionId, + const Event& event)> _beforeProcessingEvent; + + std::function<void (const std::string& sessionId)> _beforeMicroStep; + + std::function<void (const std::string& sessionId, + const std::string& stateName, + const XERCESC_NS::DOMElement* state)> _beforeExitingState; + + std::function<void (const std::string& sessionId, + const std::string& stateName, + const XERCESC_NS::DOMElement* state)> _afterExitingState; + + std::function<void (const std::string& sessionId, + const XERCESC_NS::DOMElement* execContent)> _beforeExecutingContent; + std::function<void (const std::string& sessionId, + const XERCESC_NS::DOMElement* execContent)> _afterExecutingContent; + + std::function<void (const std::string& sessionId, + const XERCESC_NS::DOMElement* invokeElem, + const std::string& invokeid)> _beforeUninvoking; + std::function<void (const std::string& sessionId, + const XERCESC_NS::DOMElement* invokeElem, + const std::string& invokeid)> _afterUninvoking; + + std::function<void (const std::string& sessionId, + const XERCESC_NS::DOMElement* transition)> _beforeTakingTransition; + std::function<void (const std::string& sessionId, + const XERCESC_NS::DOMElement* transition)> _afterTakingTransition; + + std::function<void (const std::string& sessionId, + const std::string& stateName, + const XERCESC_NS::DOMElement* state)> _beforeEnteringState; + std::function<void (const std::string& sessionId, + const std::string& stateName, + const XERCESC_NS::DOMElement* state)> _afterEnteringState; + + std::function<void (const std::string& sessionId, + const XERCESC_NS::DOMElement* invokeElem, + const std::string& invokeid)> _beforeInvoking; + std::function<void (const std::string& sessionId, + const XERCESC_NS::DOMElement* invokeElem, + const std::string& invokeid)> _afterInvoking; + + std::function<void (const std::string& sessionId)> _afterMicroStep; + std::function<void (const std::string& sessionId)> _onStableConfiguration; + + std::function<void (const std::string& sessionId)> _beforeCompletion; + std::function<void (const std::string& sessionId)> _afterCompletion; + + std::function<void (const std::string& sessionId, + const InterpreterIssue& issue)> _reportIssue; + + + + void beforeProcessingEvent(const std::string& sessionId, + const Event& event) { + if (_beforeProcessingEvent) + _beforeProcessingEvent(sessionId, event); + } + void beforeMicroStep(const std::string& sessionId) { + if (_beforeMicroStep) + _beforeMicroStep(sessionId); + } + + void beforeExitingState(const std::string& sessionId, + const std::string& stateName, + const XERCESC_NS::DOMElement* state) { + if (_beforeExitingState) + _beforeExitingState(sessionId, stateName, state); + } + + void afterExitingState(const std::string& sessionId, + const std::string& stateName, + const XERCESC_NS::DOMElement* state) { + if (_afterExitingState) + _afterExitingState(sessionId, stateName, state); + } + + void beforeExecutingContent(const std::string& sessionId, + const XERCESC_NS::DOMElement* execContent) { + if (_beforeExecutingContent) + _beforeExecutingContent(sessionId, execContent); + } + void afterExecutingContent(const std::string& sessionId, + const XERCESC_NS::DOMElement* execContent) { + if (_afterExecutingContent) + _afterExecutingContent(sessionId, execContent); + + } + + void beforeUninvoking(const std::string& sessionId, + const XERCESC_NS::DOMElement* invokeElem, + const std::string& invokeid) { + if (_beforeUninvoking) + _beforeUninvoking(sessionId, invokeElem, invokeid); + } + void afterUninvoking(const std::string& sessionId, + const XERCESC_NS::DOMElement* invokeElem, + const std::string& invokeid) { + if (_afterUninvoking) + _afterUninvoking(sessionId, invokeElem, invokeid); + } + + void beforeTakingTransition(const std::string& sessionId, + const XERCESC_NS::DOMElement* transition) { + if (_beforeTakingTransition) + _beforeTakingTransition(sessionId, transition); + } + void afterTakingTransition(const std::string& sessionId, + const XERCESC_NS::DOMElement* transition) { + if (_afterTakingTransition) + _afterTakingTransition(sessionId, transition); + } + + void beforeEnteringState(const std::string& sessionId, + const std::string& stateName, + const XERCESC_NS::DOMElement* state) { + if (_beforeEnteringState) + _beforeEnteringState(sessionId, stateName, state); + } + void afterEnteringState(const std::string& sessionId, + const std::string& stateName, + const XERCESC_NS::DOMElement* state) { + if (_afterEnteringState) + _afterEnteringState(sessionId, stateName, state); + } + + void beforeInvoking(const std::string& sessionId, + const XERCESC_NS::DOMElement* invokeElem, + const std::string& invokeid) { + if (_beforeInvoking) + _beforeInvoking(sessionId, invokeElem, invokeid); + } + void afterInvoking(const std::string& sessionId, + const XERCESC_NS::DOMElement* invokeElem, + const std::string& invokeid) { + if (_afterInvoking) + _afterInvoking(sessionId, invokeElem, invokeid); + } + + void afterMicroStep(const std::string& sessionId) { + if (_afterMicroStep) + _afterMicroStep(sessionId); + } + void onStableConfiguration(const std::string& sessionId) { + if (_onStableConfiguration) + _onStableConfiguration(sessionId); + } + + void beforeCompletion(const std::string& sessionId) { + if (_beforeCompletion) + _beforeCompletion(sessionId); + } + void afterCompletion(const std::string& sessionId) { + if (_afterCompletion) + _afterCompletion(sessionId); + } + + void reportIssue(const std::string& sessionId, + const InterpreterIssue& issue) { + if (_reportIssue) + _reportIssue(sessionId, issue); + } +}; + } #endif /* end of include guard: INTERPRETERMONITOR_H_D3F21429 */ diff --git a/src/uscxml/util/Predicates.cpp b/src/uscxml/util/Predicates.cpp index 6649907..1f95a52 100644 --- a/src/uscxml/util/Predicates.cpp +++ b/src/uscxml/util/Predicates.cpp @@ -328,7 +328,6 @@ DOMElement* getState(const std::string& stateId, const DOMElement* root) { } // no state with such an id in document! - assert(false); return NULL; } diff --git a/test/src/test-snippets.cpp b/test/src/test-snippets.cpp index f26b730..5eb680f 100644 --- a/test/src/test-snippets.cpp +++ b/test/src/test-snippets.cpp @@ -9,6 +9,8 @@ #include "uscxml/Interpreter.h" #include "uscxml/interpreter/LoggingImpl.h" +#include <iostream> + using namespace uscxml; void microstep_snippet() { @@ -31,9 +33,30 @@ void microstep_snippet() { } +void lambda_snippet() { + InterpreterState state = uscxml::USCXML_UNDEF; + Interpreter scxml = Interpreter::fromURL("https://raw.githubusercontent.com/tklab-tud/uscxml/master/test/w3c/null/test436.scxml"); + + scxml.on().enterState([](const std::string& sessionId, + const std::string& stateName, + const xercesc_3_1::DOMElement* state) { + std::cout << "Entered " << stateName << std::endl; + }); + + scxml.on().exitState([](const std::string& sessionId, + const std::string& stateName, + const xercesc_3_1::DOMElement* state) { + std::cout << "Exited " << stateName << std::endl; + }); + + + while((state = scxml.step()) != uscxml::USCXML_FINISHED) {} + +} + int main(int argc, char** argv) { try { - Logger::getDefault().log(USCXML_FATAL) << "Foo!" << " BAR?" << std::endl; + lambda_snippet(); microstep_snippet(); } catch (...) { exit(EXIT_FAILURE); |