summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Radomski <sradomski@mintwerk.de>2016-01-15 13:42:06 (GMT)
committerStefan Radomski <sradomski@mintwerk.de>2016-01-15 13:42:06 (GMT)
commit38da34e8ba7956bed2e4703289ed70e3f6aade52 (patch)
treebaf0b424f395ae63fbf3f0d8123a3e59e1ef51d7
parent613cf9fb6fe4b24bc7852d5a31953f6ff419e43c (diff)
downloaduscxml-38da34e8ba7956bed2e4703289ed70e3f6aade52.zip
uscxml-38da34e8ba7956bed2e4703289ed70e3f6aade52.tar.gz
uscxml-38da34e8ba7956bed2e4703289ed70e3f6aade52.tar.bz2
Working on C transformation
-rwxr-xr-xcontrib/cmake/FileInformation.cmake187
-rwxr-xr-xcontrib/cmake/FileInformation.cmd20
-rwxr-xr-xcontrib/cmake/FileInformation.sh95
-rwxr-xr-xcontrib/cmake/FileInformation.vbs42
-rw-r--r--src/uscxml/Interpreter.cpp79
-rw-r--r--src/uscxml/Interpreter.h8
-rw-r--r--src/uscxml/plugins/datamodel/promela/PromelaDataModel.cpp2
-rw-r--r--src/uscxml/transform/ChartToC copy.cpp1617
-rw-r--r--src/uscxml/transform/ChartToC.cpp303
-rw-r--r--src/uscxml/transform/ChartToC.h1
-rw-r--r--test/CMakeLists.txt435
-rw-r--r--test/ctest/CTestCustom.ctest.in148
-rw-r--r--test/src/test-c-machine.cpp42
-rw-r--r--test/src/test-c-machine.machine.c350
-rw-r--r--test/src/test-lifecycle.cpp26
-rw-r--r--test/src/test-w3c.cpp146
-rwxr-xr-xtest/w3c/analyze_tests.pl38
-rw-r--r--test/w3c/run_generated_c_test.cmake51
-rw-r--r--test/w3c/run_generated_test.cmake87
19 files changed, 3032 insertions, 645 deletions
diff --git a/contrib/cmake/FileInformation.cmake b/contrib/cmake/FileInformation.cmake
new file mode 100755
index 0000000..d626b8b
--- /dev/null
+++ b/contrib/cmake/FileInformation.cmake
@@ -0,0 +1,187 @@
+# - CMake module for getting file information such as size and modification date
+#
+# This module overrides the built-in CMake command file to provide two additional sub-commands
+# SIZE and TIMESTAMP on all platforms. Under UNIX the sub-commands USER_NAME, GROUP_NAME and
+# PERMISSIONS are also provided.
+#
+# file (SIZE filename var)
+# SIZE will store the size of the file in bytes into the variable.
+#
+# file (TIMESTAMP filename var)
+# TIMESTAMP will store the modification date of the file into the variable as an ISO 8601
+# formatted string (e.g., "2011-07-02T13:00:22"). The chronological order of two timestamps
+# can be determined with a STRLESS, STRGREATER or STREQUAL expression.
+#
+# get_timestamp_component (var timestamp TIMESTAMP|DATE|TIME|YEAR|MONTH|DAY|HOUR|MINUTE|SECOND|TIMEZONE ...)
+# gets a specific component of a ISO 8601 formatted string. Multiple components can be
+# retrieved at the same time as a list.
+#
+# current_timestamp (var [ TIMESTAMP|DATE|TIME|YEAR|MONTH|DAY|HOUR|MINUTE|SECOND|TIMEZONE ... ])
+# will store the current date and time into the variable as an ISO 8601 formatted string.
+# Optionally components of the current date and time can be retrieved as a list instead.
+#
+# The following sub-commands are available on UNIX and Apple (Mac OS X) only:
+#
+# file (USER_NAME filename var)
+# USER_NAME will store the user name of the file owner into the variable.
+#
+# file (GROUP_NAME filename var)
+# GROUP_NAME will store the group name of the file owner into the variable.
+#
+# file (PERMISSIONS filename var)
+# PERMISSIONS will store the the permissions of the file into the variable as a list.
+# Valid permissions are OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ, GROUP_WRITE,
+# GROUP_EXECUTE, WORLD_READ, WORLD_WRITE, WORLD_EXECUTE, SETUID, and SETGID.
+#
+#=============================================================================
+# Copyright 2011-2013 Sascha Kratky
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#=============================================================================
+
+get_filename_component(FileInformation_CMAKE_MODULE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+set (FileInformation_CMAKE_MODULE_VERSION "1.2.0")
+find_program(BASH bash)
+
+# private function which invokes platform specific helper script
+function (_invoke_helper_script _command _filePath _outputVar _exitCodeVar)
+ if (CMAKE_HOST_UNIX)
+ set (_helperScript "${FileInformation_CMAKE_MODULE_DIR}/FileInformation.sh")
+ # make sure helper script is executable
+ execute_process(COMMAND chmod "-f" "+x" "${_helperScript}" TIMEOUT 5)
+ elseif (CMAKE_HOST_WIN32)
+ set (_helperScript "${FileInformation_CMAKE_MODULE_DIR}/FileInformation.cmd")
+ # Windows requires native paths
+ file (TO_NATIVE_PATH "${_helperScript}" _helperScript)
+ if (_filePath)
+ file (TO_NATIVE_PATH "${_filePath}" _filePath)
+ endif()
+ else()
+ message (FATAL_ERROR "Unsupported host platform ${CMAKE_HOST_SYSTEM_NAME}.")
+ endif()
+ string (TOLOWER "${_command}" _cmd)
+ execute_process(
+ COMMAND "${BASH}" "${_helperScript}" "--${_cmd}" "${_filePath}"
+ TIMEOUT 5
+ RESULT_VARIABLE _result
+ OUTPUT_VARIABLE _output
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ set (${_exitCodeVar} ${_result} PARENT_SCOPE)
+ set (${_outputVar} ${_output} PARENT_SCOPE)
+endfunction()
+
+if (NOT COMMAND get_timestamp_component)
+ # do not override get_timestamp_component if it already exists
+ function (get_timestamp_component _outputVar _timestamp)
+ if (${ARGC} LESS 3)
+ message (FATAL_ERROR "timestamp requires at least three arguments.")
+ endif()
+ string(STRIP "${_timestamp}" _timestamp)
+ if ("${_timestamp}" MATCHES "([0-9-]+)T([0-9:Z+-]+)")
+ set (_date "${CMAKE_MATCH_1}")
+ set (_time "${CMAKE_MATCH_2}")
+ if ("${_date}" MATCHES "([0-9][0-9][0-9][0-9])(-?([0-9][0-9])(-?([0-9][0-9]))?)?")
+ set (_year "${CMAKE_MATCH_1}")
+ set (_month "${CMAKE_MATCH_3}")
+ set (_day "${CMAKE_MATCH_5}")
+ else()
+ unset(_year)
+ unset(_month)
+ unset(_day)
+ endif()
+ if ("${_time}" MATCHES "([0-9][0-9])(:?([0-9][0-9])(:?([0-9][0-9]))?)?(Z|([+-][0-9:]+))?")
+ set (_hour "${CMAKE_MATCH_1}")
+ set (_minute "${CMAKE_MATCH_3}")
+ set (_second "${CMAKE_MATCH_5}")
+ set (_timezone "${CMAKE_MATCH_6}")
+ if (_timezone)
+ # if time is UTC, use +00:00
+ string (REPLACE "Z" "+0000" _timezone "${_timezone}")
+ # use canonical representation of time zone
+ string (REPLACE ":" "" _timezone "${_timezone}")
+ string (REGEX REPLACE "^[0-9][0-9]$" "\\000" _timezone "${_timezone}")
+ endif()
+ else()
+ unset(_hour)
+ unset(_minute)
+ unset(_second)
+ endif()
+ set (_result "")
+ foreach (_component ${ARGN})
+ string (TOLOWER "_${_component}" _componentVar)
+ if (DEFINED "${_componentVar}" AND
+ "${${_componentVar}}" MATCHES ".+")
+ set (_componentValue "${${_componentVar}}")
+ else()
+ message (WARNING
+ "get_timestamp_component cannot extract component ${_component}.")
+ set (_componentValue "${_component}-NOTFOUND")
+ endif()
+ list (APPEND _result ${_componentValue})
+ endforeach()
+ else()
+ message (SEND_ERROR
+ "get_timestamp_component ${_timeStamp} is not an ISO 8601 string.")
+ set (_result "TIMESTAMP-NOTFOUND")
+ endif()
+ set (${_outputVar} ${_result} PARENT_SCOPE)
+ endfunction()
+endif()
+
+if (NOT COMMAND current_timestamp)
+ # do not override current_timestamp if it already exists
+ function (current_timestamp _outputVar)
+ _invoke_helper_script("current_timestamp" "" _result _exitCode)
+ if (NOT ${_exitCode} EQUAL 0)
+ message (SEND_ERROR "current_timestamp failed.")
+ set (_result "TIMESTAMP-NOTFOUND")
+ elseif (${ARGC} GREATER 1)
+ get_timestamp_component (_result "${_result}" ${ARGN})
+ endif()
+ set (${_outputVar} ${_result} PARENT_SCOPE)
+ endfunction()
+endif()
+
+macro (file)
+ if ("${ARGV0}" MATCHES "SIZE|TIMESTAMP|PERMISSIONS|USER_NAME|GROUP_NAME")
+ if (NOT ${ARGC} EQUAL 3)
+ message (FATAL_ERROR "file sub-command ${ARGV0} requires two arguments.")
+ endif()
+ set (_filePath "${ARGV1}")
+ set (_varName "${ARGV2}")
+ get_filename_component(_filePath "${_filePath}" ABSOLUTE)
+ if (NOT EXISTS "${_filePath}")
+ message (FATAL_ERROR "file ${ARGV0} ${_filePath} does not exist.")
+ endif()
+ if ("${ARGV0}" STREQUAL "SIZE" AND IS_DIRECTORY "${_filePath}")
+ message (FATAL_ERROR "file ${ARGV0} ${_filePath} is a directory.")
+ endif()
+ _invoke_helper_script("${ARGV0}" "${_filePath}" ${_varName} _exitCode)
+ if (NOT ${_exitCode} EQUAL 0)
+ message (SEND_ERROR "file ${ARGV0} failed for ${_filePath}.")
+ set (${_varName} "${ARGV0}-NOTFOUND")
+ endif()
+ else()
+ # pass call to original file function
+ _file (${ARGV})
+ endif()
+endmacro()
diff --git a/contrib/cmake/FileInformation.cmd b/contrib/cmake/FileInformation.cmd
new file mode 100755
index 0000000..015d1f2
--- /dev/null
+++ b/contrib/cmake/FileInformation.cmd
@@ -0,0 +1,20 @@
+@echo off
+rem helper script for FileInformation CMake module
+
+setlocal enabledelayedexpansion
+
+set "INPUT_OPTION=%~1"
+
+if "!INPUT_OPTION!" == "--size" (
+ echo %~z2
+) else if "!INPUT_OPTION!" == "--timestamp" (
+ rem do not use %~t2, its format depends on regional settings
+ rem use Visual Basic to obtain ISO 8601 formatted time stamp
+ cscript //Nologo "%~dpn0.vbs" "%~1" "%~f2"
+) else if "!INPUT_OPTION!" == "--current_timestamp" (
+ rem do not use %DATE% and %TIME%, their format depends on regional settings
+ rem use Visual Basic to obtain ISO 8601 formatted time stamp
+ cscript //Nologo "%~dpn0.vbs" "%~1"
+) else (
+ exit 1
+)
diff --git a/contrib/cmake/FileInformation.sh b/contrib/cmake/FileInformation.sh
new file mode 100755
index 0000000..e9533b1
--- /dev/null
+++ b/contrib/cmake/FileInformation.sh
@@ -0,0 +1,95 @@
+#!/bin/bash
+# helper script for FileInformation CMake module
+
+#logger $# "$@"
+
+function to_cmake_permission() {
+ local symbolic_perm=$1
+ local owner_group_world=$2
+ local set_user_group=$3
+ case "${symbolic_perm}" in
+ "r" ) echo "${owner_group_world}_READ";;
+ "w" ) echo "${owner_group_world}_WRITE";;
+ "x" ) echo "${owner_group_world}_EXECUTE";;
+ "s" ) echo "${owner_group_world}_EXECUTE;${set_user_group}";;
+ "S" ) echo "${set_user_group}";;
+ "t" ) echo "${owner_group_world}_EXECUTE";;
+ * ) echo "";;
+ esac
+}
+
+function to_cmake_permissions() {
+ local symbolic_perms=$1
+ local -a cmake_perms_array
+ for i in 0 1 2
+ do
+ cmake_perms_array[((0+$i))]=$(to_cmake_permission ${symbolic_perms:((1+$i)):1} "OWNER" "SETUID")
+ cmake_perms_array[((3+$i))]=$(to_cmake_permission ${symbolic_perms:((4+$i)):1} "GROUP" "SETGID")
+ cmake_perms_array[((6+$i))]=$(to_cmake_permission ${symbolic_perms:((7+$i)):1} "WORLD")
+ done
+ local cmake_perms=""
+ for cmake_perm in ${cmake_perms_array[*]}
+ do
+ if [ -z $cmake_perms ]
+ then
+ cmake_perms=$cmake_perm
+ else
+ cmake_perms="$cmake_perms;$cmake_perm"
+ fi
+ done
+ echo $cmake_perms
+}
+
+INPUT_OPTION=$1
+
+# format timestamp according to ISO 8601
+TIMESTAMP_FORMAT=%Y-%m-%dT%H:%M:%S%z
+
+if [[ $OSTYPE == darwin* || $OSTYPE == freebsd* ]]
+then
+ # Mac OS X or FreeBSD
+ if [ "$INPUT_OPTION" = "--size" ]
+ then
+ stat -f "%z" "$2"
+ elif [ "$INPUT_OPTION" = "--timestamp" ]
+ then
+ date -r $(stat -f "%m" "$2") "+$TIMESTAMP_FORMAT"
+ elif [ "$INPUT_OPTION" = "--current_timestamp" ]
+ then
+ date "+$TIMESTAMP_FORMAT"
+ elif [ "$INPUT_OPTION" = "--user_name" ]
+ then
+ stat -f "%Su" "$2"
+ elif [ "$INPUT_OPTION" = "--group_name" ]
+ then
+ stat -f "%Sg" "$2"
+ elif [ "$INPUT_OPTION" = "--permissions" ]
+ then
+ to_cmake_permissions $(stat -f "%Sp" "$2")
+ else
+ exit 1
+ fi
+else
+ # other Unices
+ if [ "$INPUT_OPTION" = "--size" ]
+ then
+ stat -c "%s" "$2"
+ elif [ "$INPUT_OPTION" = "--timestamp" ]
+ then
+ date -r "$2" "+$TIMESTAMP_FORMAT"
+ elif [ "$INPUT_OPTION" = "--current_timestamp" ]
+ then
+ date "+$TIMESTAMP_FORMAT"
+ elif [ "$INPUT_OPTION" = "--user_name" ]
+ then
+ stat -c "%U" "$2"
+ elif [ "$INPUT_OPTION" = "--group_name" ]
+ then
+ stat -c "%G" "$2"
+ elif [ "$INPUT_OPTION" = "--permissions" ]
+ then
+ to_cmake_permissions $(stat -c "%A" "$2")
+ else
+ exit 1
+ fi
+fi
diff --git a/contrib/cmake/FileInformation.vbs b/contrib/cmake/FileInformation.vbs
new file mode 100755
index 0000000..c78cae0
--- /dev/null
+++ b/contrib/cmake/FileInformation.vbs
@@ -0,0 +1,42 @@
+' helper script for FileInformation CMake module
+
+Function ToISODateTime(ByVal dt)
+ ToISODateTime = CStr(Year(dt)) & "-" & _
+ Right("00" & Month(dt), 2) & "-" & _
+ Right("00" & Day(dt), 2) & "T" & _
+ Right("00" & Hour(dt), 2) & ":" & _
+ Right("00" & Minute(dt), 2) & ":" & _
+ Right("00" & Second(dt), 2)
+End Function
+
+If WScript.Arguments.Count < 1 Then
+ Wscript.Quit 1
+End If
+
+InputOption=WScript.Arguments.Item(0)
+
+If InputOption = "--current_timestamp" Then
+ Wscript.Echo ToISODateTime(Now)
+ Wscript.Quit 0
+End If
+
+If WScript.Arguments.Count < 2 Then
+ Wscript.Quit 1
+End If
+
+Set FSO=CreateObject("Scripting.FileSystemObject")
+if FSO.FolderExists(WScript.Arguments.Item(1)) Then
+ Set FSItem=FSO.GetFolder(WScript.Arguments.Item(1))
+Else
+ Set FSItem=FSO.GetFile(WScript.Arguments.Item(1))
+End If
+
+If InputOption = "--size" Then
+ Wscript.Echo CStr(FSItem.Size)
+ Wscript.Quit 0
+ElseIf InputOption = "--timestamp" Then
+ Wscript.Echo ToISODateTime(FSItem.DateLastModified)
+ Wscript.Quit 0
+End If
+
+Wscript.Quit 1
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
index 2a15924..0375f9b 100644
--- a/src/uscxml/Interpreter.cpp
+++ b/src/uscxml/Interpreter.cpp
@@ -61,7 +61,8 @@
/// valid interpreter state transitions
#define VALID_FROM_INSTANTIATED(newState) ( \
- newState == USCXML_MICROSTEPPED || \
+ newState == USCXML_MICROSTEPPED || \
+ newState == USCXML_INITIALIZED || \
newState == USCXML_DESTROYED\
)
@@ -384,6 +385,13 @@ void StateTransitionMonitor::beforeEnteringState(uscxml::Interpreter interpreter
}
+void StateTransitionMonitor::beforeMicroStep(uscxml::Interpreter interpreter) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+ std::cerr << "Config: {";
+ printNodeSet(interpreter.getConfiguration());
+ std::cerr << "}" << std::endl;
+}
+
void StateTransitionMonitor::printNodeSet(const Arabica::XPath::NodeSet<std::string>& config) {
std::string seperator;
for (int i = 0; i < config.size(); i++) {
@@ -593,21 +601,18 @@ InterpreterImpl::~InterpreterImpl() {
// make sure we are done with setting up with early abort
tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
stop(); // unset started bit
+
+ setInterpreterState(USCXML_DESTROYED);
+
+ // unblock event queue
+ Event event;
+ event.name = "unblock.and.die";
+ receive(event);
+
}
// std::cerr << "stopped " << this << std::endl;
// tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
if (_thread) {
- if (_thread->get_id() != tthread::this_thread::get_id()) {
-
- // unblock event queue
- Event event;
- event.name = "unblock.and.die";
- receive(event);
-
- } else {
- // this can happen with a shared_from_this at an interpretermonitor
- setInterpreterState(USCXML_DESTROYED);
- }
_thread->join();
delete(_thread);
}
@@ -784,6 +789,7 @@ InterpreterState InterpreterImpl::step(int waitForMS) {
// setup document and interpreter
if (!_isInitialized) {
init(); // will throw
+ return _state;
}
if (_configuration.size() == 0) {
@@ -954,23 +960,25 @@ EXIT_INTERPRETER:
exitInterpreter();
if (_sendQueue) {
+ _sendQueue->stop();
std::map<std::string, std::pair<InterpreterImpl*, SendRequest> >::iterator sendIter = _sendIds.begin();
while(sendIter != _sendIds.end()) {
_sendQueue->cancelEvent(sendIter->first);
sendIter++;
}
+ _sendQueue->start();
}
USCXML_MONITOR_CALLBACK(afterCompletion)
// assert(hasLegalConfiguration());
+ setInterpreterState(USCXML_FINISHED);
_mutex.unlock();
// remove datamodel
// if(!_userSuppliedDataModel)
// _dataModel = DataModel();
- setInterpreterState(USCXML_FINISHED);
return _state;
} catch (boost::bad_weak_ptr e) {
LOG(ERROR) << "Unclean shutdown " << std::endl << std::endl;
@@ -1284,6 +1292,11 @@ void InterpreterImpl::setInterpreterState(InterpreterState newState) {
break;
assert(false);
break;
+ case USCXML_INITIALIZED:
+ if (VALID_FROM_INITIALIZED(newState))
+ break;
+ assert(false);
+ break;
case USCXML_MICROSTEPPED:
if (VALID_FROM_MICROSTEPPED(newState))
break;
@@ -1304,11 +1317,8 @@ void InterpreterImpl::setInterpreterState(InterpreterState newState) {
break;
assert(false);
break;
- case USCXML_DESTROYED:
- assert(false);
- break;
-
default:
+ assert(false);
break;
}
@@ -1352,7 +1362,22 @@ bool InterpreterImpl::runOnMainThread(int fps, bool blocking) {
void InterpreterImpl::reset() {
tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
-
+
+ if (_sendQueue) {
+ _sendQueue->stop();
+ std::map<std::string, std::pair<InterpreterImpl*, SendRequest> >::iterator sendIter = _sendIds.begin();
+ while(sendIter != _sendIds.end()) {
+ _sendQueue->cancelEvent(sendIter->first);
+ sendIter = _sendIds.erase(sendIter);
+ }
+ _sendQueue->start();
+ }
+ std::map<std::string, Invoker>::iterator invokeIter = _invokers.begin();
+ while(invokeIter != _invokers.end()) {
+ invokeIter->second.uninvoke();
+ invokeIter = _invokers.erase(invokeIter);
+ }
+
_externalQueue.clear();
_internalQueue.clear();
_historyValue.clear();
@@ -1675,6 +1700,7 @@ void InterpreterImpl::init() {
_isInitialized = true;
_stable = false;
+ setInterpreterState(USCXML_INITIALIZED);
}
/**
@@ -2537,9 +2563,9 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Element<std::string>& c
}
}
} else if (iequals(TAGNAME(content), _nsInfo.xmlNSPrefix + "elseif")) {
- std::cerr << "Found single elsif to evaluate!" << std::endl;
+ LOG(ERROR) << "Found single elsif to evaluate!" << std::endl;
} else if (iequals(TAGNAME(content), _nsInfo.xmlNSPrefix + "else")) {
- std::cerr << "Found single else to evaluate!" << std::endl;
+ LOG(ERROR) << "Found single else to evaluate!" << std::endl;
} else if (iequals(TAGNAME(content), _nsInfo.xmlNSPrefix + "foreach")) {
// --- FOREACH --------------------------
if (HAS_ATTR(content, "array") && HAS_ATTR(content, "item")) {
@@ -2571,16 +2597,19 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Element<std::string>& c
} else if (iequals(TAGNAME(content), _nsInfo.xmlNSPrefix + "log")) {
// --- LOG --------------------------
Arabica::DOM::Element<std::string> logElem = (Arabica::DOM::Element<std::string>)content;
- if (logElem.hasAttribute("label"))
- std::cerr << logElem.getAttribute("label") << ": ";
+ if (logElem.hasAttribute("label")) {
+ std::cout << logElem.getAttribute("label") << ": ";
+ }
if (logElem.hasAttribute("expr")) {
try {
- std::cerr << _dataModel.evalAsString(logElem.getAttribute("expr")) << std::endl;
+ std::string msg = _dataModel.evalAsString(logElem.getAttribute("expr"));
+ std::cout << msg << std::endl;
}
CATCH_AND_DISTRIBUTE2("Syntax error in expr attribute of log element", content)
} else {
- if (logElem.hasAttribute("label"))
- std::cerr << std::endl;
+ if (logElem.hasAttribute("label")) {
+ std::cout << std::endl;
+ }
}
} else if (iequals(TAGNAME(content), _nsInfo.xmlNSPrefix + "assign")) {
// --- ASSIGN --------------------------
diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h
index fa02eca..a721ad3 100644
--- a/src/uscxml/Interpreter.h
+++ b/src/uscxml/Interpreter.h
@@ -164,8 +164,9 @@ enum InterpreterState {
USCXML_DESTROYED = -2, ///< destructor ran - users should never see this one
USCXML_FINISHED = -1, ///< machine reached a final configuration and is done
USCXML_IDLE = 0, ///< stable configuration and queues empty
- USCXML_INSTANTIATED = 1, ///< nothing really, just instantiated
- USCXML_MICROSTEPPED = 2, ///< processed one transition set
+ USCXML_INITIALIZED = 1, ///< DOM is setup and all external components instantiated
+ USCXML_INSTANTIATED = 2, ///< nothing really, just instantiated
+ USCXML_MICROSTEPPED = 3, ///< processed one transition set
USCXML_MACROSTEPPED = 4, ///< processed all transition sets and reached a stable configuration
};
USCXML_API std::ostream& operator<< (std::ostream& os, const InterpreterState& interpreterState);
@@ -890,7 +891,8 @@ public:
virtual void beforeProcessingEvent(uscxml::Interpreter interpreter, const uscxml::Event& event);
virtual void beforeExitingState(uscxml::Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing);
virtual void beforeEnteringState(uscxml::Interpreter interpreter, const Arabica::DOM::Element<std::string>& state, bool moreComing);
-
+ virtual void beforeMicroStep(uscxml::Interpreter interpreter);
+
protected:
static tthread::recursive_mutex _mutex;
void printNodeSet(const Arabica::XPath::NodeSet<std::string>& config);
diff --git a/src/uscxml/plugins/datamodel/promela/PromelaDataModel.cpp b/src/uscxml/plugins/datamodel/promela/PromelaDataModel.cpp
index cd6bef3..d9f50cf 100644
--- a/src/uscxml/plugins/datamodel/promela/PromelaDataModel.cpp
+++ b/src/uscxml/plugins/datamodel/promela/PromelaDataModel.cpp
@@ -215,7 +215,7 @@ bool PromelaDataModel::isValidSyntax(const std::string& expr) {
try {
PromelaParser parser(expr);
} catch (Event e) {
- std::cerr << e << std::endl;
+ LOG(ERROR) << e << std::endl;
return false;
}
return true;
diff --git a/src/uscxml/transform/ChartToC copy.cpp b/src/uscxml/transform/ChartToC copy.cpp
new file mode 100644
index 0000000..ce597ff
--- /dev/null
+++ b/src/uscxml/transform/ChartToC copy.cpp
@@ -0,0 +1,1617 @@
+/**
+ * @file
+ * @author 2012-2015 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @copyright Simplified BSD
+ *
+ * @cond
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the FreeBSD license as published by the FreeBSD
+ * project.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the FreeBSD license along with this
+ * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#include "uscxml/transform/ChartToFSM.h"
+#include "uscxml/transform/ChartToC.h"
+#include "uscxml/debug/Complexity.h"
+#include <DOM/io/Stream.hpp>
+#include <iostream>
+#include "uscxml/UUID.h"
+#include "uscxml/DOMUtils.h"
+#include <math.h>
+#include <boost/algorithm/string.hpp>
+#include <glog/logging.h>
+
+#include <algorithm>
+#include <iomanip>
+
+namespace uscxml {
+
+using namespace Arabica::DOM;
+using namespace Arabica::XPath;
+
+Transformer ChartToC::transform(const Interpreter& other) {
+ ChartToC* c2c = new ChartToC(other);
+
+ return boost::shared_ptr<TransformerImpl>(c2c);
+}
+
+ChartToC::ChartToC(const Interpreter& other) : TransformerImpl() {
+ cloneFrom(other.getImpl());
+}
+
+void ChartToC::writeTo(std::ostream& stream) {
+ _binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY);
+ _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : "");
+
+ std::set<std::string> elements;
+ elements.insert(_nsInfo.xmlNSPrefix + "scxml");
+ elements.insert(_nsInfo.xmlNSPrefix + "state");
+ elements.insert(_nsInfo.xmlNSPrefix + "final");
+ elements.insert(_nsInfo.xmlNSPrefix + "parallel");
+ elements.insert(_nsInfo.xmlNSPrefix + "history");
+ elements.insert(_nsInfo.xmlNSPrefix + "initial");
+ elements.insert(_nsInfo.xmlNSPrefix + "parallel");
+ _states = inDocumentOrder(elements, _scxml);
+
+ for (int i = 0; i < _states.size(); i++) {
+ Element<std::string> state(_states[i]);
+ state.setAttribute("documentOrder", toStr(i));
+ if (HAS_ATTR(state, "id")) {
+ _stateNames[ATTR(state, "id")] = state;
+ }
+ }
+
+ elements.clear();
+ elements.insert(_nsInfo.xmlNSPrefix + "transition");
+ _transitions = inPostFixOrder(elements, _scxml);
+
+ for (int i = 0; i < _transitions.size(); i++) {
+ Element<std::string> transition(_transitions[i]);
+ transition.setAttribute("postFixOrder", toStr(i));
+ }
+
+ // how many bits do we need to represent the state array?
+ std::string seperator;
+ _stateCharArraySize = ceil((float)_states.size() / (float)8);
+ _stateCharArrayInit = "{";
+ for (int i = 0; i < _stateCharArraySize; i++) {
+ _stateCharArrayInit += seperator + "0";
+ seperator = ", ";
+ }
+ _stateCharArrayInit += "}";
+
+ seperator = "";
+ _transCharArraySize = ceil((float)_transitions.size() / (float)8);
+ _transCharArrayInit = "{";
+ for (int i = 0; i < _transCharArraySize; i++) {
+ _transCharArrayInit += seperator + "0";
+ seperator = ", ";
+ }
+ _transCharArrayInit += "}";
+
+ writeIncludes(stream);
+ writeMacros(stream);
+ writeTypes(stream);
+ writeElementInfo(stream);
+ writeExecContent(stream);
+ writeStates(stream);
+ writeTransitions(stream);
+ writeHelpers(stream);
+ writeFSM(stream);
+
+ // http://stackoverflow.com/questions/2525310/how-to-define-and-work-with-an-array-of-bits-in-c
+
+}
+
+void ChartToC::writeIncludes(std::ostream& stream) {
+ stream << "#include <stdint.h> // explicit types" << std::endl;
+ stream << "#include <stddef.h> // NULL" << std::endl;
+ stream << std::endl;
+}
+
+void ChartToC::writeMacros(std::ostream& stream) {
+ stream << "#define IS_SET(idx, bitset) ((bitset[idx >> 3] & (1 << (idx & 7))) != 0)" << std::endl;
+ stream << "#define SET_BIT(idx, bitset) bitset[idx >> 3] |= (1 << (idx & 7));" << std::endl;
+ stream << "#define CLEARBIT(idx, bitset) bitset[idx >> 3] &= (1 << (idx & 7)) ^ 0xFF;" << std::endl;
+ stream << std::endl;
+
+ stream << "#ifdef __GNUC__" << std::endl;
+ stream << "#define likely(x) (__builtin_expect(!!(x), 1))" << std::endl;
+ stream << "#define unlikely(x) (__builtin_expect(!!(x), 0))" << std::endl;
+ stream << "#else" << std::endl;
+ stream << "#define likely(x) (x)" << std::endl;
+ stream << "#define unlikely(x) (x)" << std::endl;
+ stream << "#endif" << std::endl;
+ stream << std::endl;
+
+ stream << "// error return codes" << std::endl;
+ stream << "#define SCXML_ERR_OK 0" << std::endl;
+ stream << "#define SCXML_ERR_IDLE 1" << std::endl;
+ stream << "#define SCXML_ERR_DONE 2" << std::endl;
+ stream << "#define SCXML_ERR_MISSING_CALLBACK 3" << std::endl;
+ stream << "#define SCXML_ERR_FOREACH_DONE 4" << std::endl;
+ stream << "#define SCXML_ERR_EXEC_CONTENT 5" << std::endl;
+ stream << "#define SCXML_ERR_INVALID_TARGET 6" << std::endl;
+ stream << "#define SCXML_ERR_INVALID_TYPE 7" << std::endl;
+ stream << "#define SCXML_ERR_UNSUPPORTED 8" << std::endl;
+ stream << std::endl;
+
+ stream << "#define SCXML_MACHINE_NAME \"" << _name << "\"" << std::endl;
+ stream << "#define SCXML_NUMBER_STATES " << _states.size() << std::endl;
+ stream << "#define SCXML_NUMBER_TRANSITIONS " << _transitions.size() << std::endl;
+ stream << std::endl;
+
+ stream << "#define SCXML_TRANS_SPONTANEOUS 0x01" << std::endl;
+ stream << "#define SCXML_TRANS_TARGETLESS 0x02" << std::endl;
+ stream << "#define SCXML_TRANS_INTERNAL 0x04" << std::endl;
+ stream << "#define SCXML_TRANS_HISTORY 0x08" << std::endl;
+ stream << std::endl;
+
+ stream << "#define SCXML_STATE_ATOMIC 0x01" << std::endl;
+ stream << "#define SCXML_STATE_PARALLEL 0x02" << std::endl;
+ stream << "#define SCXML_STATE_COMPOUND 0x03" << std::endl;
+ stream << "#define SCXML_STATE_FINAL 0x04" << std::endl;
+ stream << "#define SCXML_STATE_HISTORY_DEEP 0x05" << std::endl;
+ stream << "#define SCXML_STATE_HISTORY_SHALLOW 0x06" << std::endl;
+ stream << "#define SCXML_STATE_INITIAL 0x07" << std::endl;
+
+ stream << "" << std::endl;
+ stream << "#define SCXML_CTX_PRISTINE 0x00" << std::endl;
+ stream << "#define SCXML_CTX_SPONTANEOUS 0x01" << std::endl;
+ stream << "#define SCXML_CTX_INITIALIZED 0x02" << std::endl;
+ stream << "#define SCXML_CTX_TOP_LEVEL_FINAL 0x04" << std::endl;
+ stream << "#define SCXML_CTX_TRANSITION_FOUND 0x08" << std::endl;
+ stream << std::endl;
+
+ stream << "#define ELEM_DATA_IS_SET(data) (data->id != NULL)" << std::endl;
+ stream << "#define ELEM_DONEDATA_IS_SET(donedata) (donedata->content != NULL || donedata->contentexpr != NULL || donedata->params != NULL)" << std::endl;
+ stream << "#define ELEM_PARAM_IS_SET(param) (param->name != NULL)" << std::endl;
+ stream << std::endl;
+}
+
+void ChartToC::writeTypes(std::ostream& stream) {
+
+ stream << std::endl;
+ stream << "typedef struct scxml_transition scxml_transition;" << std::endl;
+ stream << "typedef struct scxml_state scxml_state;" << std::endl;
+ stream << "typedef struct scxml_ctx scxml_ctx;" << std::endl;
+ stream << "typedef struct scxml_invoke scxml_invoke;" << std::endl;
+
+ stream << std::endl;
+
+ stream << "typedef struct scxml_elem_send scxml_elem_send;" << std::endl;
+ stream << "typedef struct scxml_elem_param scxml_elem_param;" << std::endl;
+ stream << "typedef struct scxml_elem_data scxml_elem_data;" << std::endl;
+ stream << "typedef struct scxml_elem_donedata scxml_elem_donedata;" << std::endl;
+ stream << "typedef struct scxml_elem_foreach scxml_elem_foreach;" << std::endl;
+ stream << std::endl;
+
+ stream << "typedef void* (*dequeue_internal_cb_t)(const scxml_ctx* ctx);" << std::endl;
+ stream << "typedef void* (*dequeue_external_cb_t)(const scxml_ctx* ctx);" << std::endl;
+ stream << "typedef int (*is_enabled_cb_t)(const scxml_ctx* ctx, const scxml_transition* transition, const void* event);" << std::endl;
+ stream << "typedef int (*is_true_cb_t)(const scxml_ctx* ctx, const char* expr);" << std::endl;
+ stream << "typedef int (*exec_content_t)(const scxml_ctx* ctx, const scxml_state* state, const void* event);" << std::endl;
+ stream << "typedef int (*raise_done_event_t)(const scxml_ctx* ctx, const scxml_state* state, const scxml_elem_donedata* donedata);" << std::endl;
+ stream << "typedef int (*invoke_t)(const scxml_ctx* ctx, const scxml_state* s, const scxml_invoke* x);" << std::endl;
+ stream << std::endl;
+
+ stream << "typedef int (*exec_content_log_t)(const scxml_ctx* ctx, const char* label, const char* expr);" << std::endl;
+ stream << "typedef int (*exec_content_raise_t)(const scxml_ctx* ctx, const char* event);" << std::endl;
+ stream << "typedef int (*exec_content_send_t)(const scxml_ctx* ctx, const scxml_elem_send* send);" << std::endl;
+ stream << "typedef int (*exec_content_foreach_init_t)(const scxml_ctx* ctx, const scxml_elem_foreach* foreach);" << std::endl;
+ stream << "typedef int (*exec_content_foreach_next_t)(const scxml_ctx* ctx, const scxml_elem_foreach* foreach);" << std::endl;
+ stream << "typedef int (*exec_content_foreach_done_t)(const scxml_ctx* ctx, const scxml_elem_foreach* foreach);" << std::endl;
+ stream << "typedef int (*exec_content_assign_t)(const scxml_ctx* ctx, const char* location, const char* expr);" << std::endl;
+ stream << "typedef int (*exec_content_init_t)(const scxml_ctx* ctx, const scxml_elem_data* data);" << std::endl;
+ stream << "typedef int (*exec_content_cancel_t)(const scxml_ctx* ctx, const char* sendid, const char* sendidexpr);" << std::endl;
+ stream << "typedef int (*exec_content_finalize_t)(const scxml_ctx* ctx, const scxml_invoke* invoker, const void* event);" << std::endl;
+ stream << "typedef int (*exec_content_script_t)(const scxml_ctx* ctx, const char* src, const char* content);" << std::endl;
+ stream << std::endl;
+
+ stream << "struct scxml_elem_data {" << std::endl;
+ stream << " const char* id;" << std::endl;
+ stream << " const char* src;" << std::endl;
+ stream << " const char* expr;" << std::endl;
+ stream << " const char* content;" << std::endl;
+ stream << "};" << std::endl;
+ stream << std::endl;
+
+ stream << "struct scxml_state {" << std::endl;
+ stream << " const char* name; // eventual name" << std::endl;
+ stream << " uint16_t parent; // parent" << std::endl;
+ stream << " exec_content_t on_entry; // on entry handlers" << std::endl;
+ stream << " exec_content_t on_exit; // on exit handlers" << std::endl;
+ stream << " invoke_t invoke; // invocations" << std::endl;
+ stream << " char children[" << _stateCharArraySize << "]; // all children" << std::endl;
+ stream << " char completion[" << _stateCharArraySize << "]; // default completion" << std::endl;
+ stream << " char ancestors[" << _stateCharArraySize << "]; // all ancestors" << std::endl;
+ stream << " const scxml_elem_data* data;" << std::endl;
+ stream << " uint8_t type; // atomic, parallel, compound, final, history" << std::endl;
+ stream << "};" << std::endl;
+ stream << std::endl;
+
+ stream << "struct scxml_transition {" << std::endl;
+ stream << " uint16_t source;" << std::endl;
+ stream << " char target[" << _stateCharArraySize << "];" << std::endl;
+ stream << " const char* event;" << std::endl;
+ stream << " const char* condition;" << std::endl;
+ stream << " exec_content_t on_transition;" << std::endl;
+ stream << " uint8_t type;" << std::endl;
+ stream << " char conflicts[" << _transCharArraySize << "];" << std::endl;
+ stream << " char exit_set[" << _stateCharArraySize << "];" << std::endl;
+ stream << "};" << std::endl;
+ stream << std::endl;
+
+ stream << "struct scxml_elem_foreach {" << std::endl;
+ stream << " const char* array;" << std::endl;
+ stream << " const char* item;" << std::endl;
+ stream << " const char* index;" << std::endl;
+ stream << "};" << std::endl;
+ stream << std::endl;
+
+ stream << "struct scxml_elem_param {" << std::endl;
+ stream << " const char* name;" << std::endl;
+ stream << " const char* expr;" << std::endl;
+ stream << " const char* location;" << std::endl;
+ stream << "};" << std::endl;
+ stream << std::endl;
+
+ stream << "struct scxml_elem_donedata {" << std::endl;
+ stream << " uint16_t source;" << std::endl;
+ stream << " const char* content;" << std::endl;
+ stream << " const char* contentexpr;" << std::endl;
+ stream << " const scxml_elem_param* params;" << std::endl;
+ stream << "};" << std::endl;
+ stream << std::endl;
+
+ stream << "struct scxml_elem_invoke {" << std::endl;
+ stream << " const char* type;" << std::endl;
+ stream << " const char* typeexpr;" << std::endl;
+ stream << " const char* src;" << std::endl;
+ stream << " const char* srcexpr;" << std::endl;
+ stream << " const char* id;" << std::endl;
+ stream << " const char* idlocation;" << std::endl;
+ stream << " const char* namelist;" << std::endl;
+ stream << " uint8_t autoforward;" << std::endl;
+ stream << " const scxml_elem_param* params;" << std::endl;
+ stream << " const exec_content_finalize_t* finalize;" << std::endl;
+ stream << " const char* content;" << std::endl;
+ stream << " const char* contentexpr;" << std::endl;
+ stream << " void* user_data;" << std::endl;
+ stream << "};" << std::endl;
+ stream << std::endl;
+
+ stream << "struct scxml_elem_send {" << std::endl;
+ stream << " const char* event;" << std::endl;
+ stream << " const char* eventexpr;" << std::endl;
+ stream << " const char* target;" << std::endl;
+ stream << " const char* targetexpr;" << std::endl;
+ stream << " const char* type;" << std::endl;
+ stream << " const char* typeexpr;" << std::endl;
+ stream << " const char* id;" << std::endl;
+ stream << " const char* idlocation;" << std::endl;
+ stream << " const char* delay;" << std::endl;
+ stream << " const char* delayexpr;" << std::endl;
+ stream << " const char* namelist;" << std::endl;
+ stream << " const char* content;" << std::endl;
+ stream << " const char* contentexpr;" << std::endl;
+ stream << " const scxml_elem_param* params;" << std::endl;
+ stream << " void* user_data;" << std::endl;
+ stream << "};" << std::endl;
+ stream << std::endl;
+
+ stream << "struct scxml_ctx {" << std::endl;
+ stream << " uint8_t flags;" << std::endl;
+ stream << std::endl;
+ stream << " char config[" << _stateCharArraySize << "];" << std::endl;
+ stream << " char history[" << _stateCharArraySize << "];" << std::endl;
+ stream << " char pending_invokes[" << _stateCharArraySize << "];" << std::endl;
+ stream << " char initialized_data[" << _stateCharArraySize << "];" << std::endl;
+ stream << std::endl;
+ stream << " void* user_data;" << std::endl;
+ stream << " void* event;" << std::endl;
+ stream << std::endl;
+ stream << " dequeue_internal_cb_t dequeue_internal;" << std::endl;
+ stream << " dequeue_external_cb_t dequeue_external;" << std::endl;
+ stream << " is_enabled_cb_t is_enabled;" << std::endl;
+ stream << " is_true_cb_t is_true;" << std::endl;
+ stream << " raise_done_event_t raise_done_event;" << std::endl;
+ stream << std::endl;
+ stream << " exec_content_log_t exec_content_log;" << std::endl;
+ stream << " exec_content_raise_t exec_content_raise;" << std::endl;
+ stream << " exec_content_send_t exec_content_send;" << std::endl;
+ stream << " exec_content_foreach_init_t exec_content_foreach_init;" << std::endl;
+ stream << " exec_content_foreach_next_t exec_content_foreach_next;" << std::endl;
+ stream << " exec_content_foreach_done_t exec_content_foreach_done;" << std::endl;
+ stream << " exec_content_assign_t exec_content_assign;" << std::endl;
+ stream << " exec_content_init_t exec_content_init;" << std::endl;
+ stream << " exec_content_cancel_t exec_content_cancel;" << std::endl;
+ stream << " exec_content_script_t exec_content_script;" << std::endl;
+ stream << " invoke_t invoke;" << std::endl;
+ stream << "};" << std::endl;
+ stream << std::endl;
+}
+
+void ChartToC::writeHelpers(std::ostream& stream) {
+ stream << "#ifdef SCXML_VERBOSE" << std::endl;
+ stream << "static void printStateNames(const char* a) {" << std::endl;
+ stream << " const char* seperator = \"\";" << std::endl;
+ stream << " for (int i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl;
+ stream << " if (IS_SET(i, a)) {" << std::endl;
+ stream << " printf(\"%s%s\", seperator, (scxml_states[i].name != NULL ? scxml_states[i].name : \"UNK\"));" << std::endl;
+ stream << " seperator = \", \";" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << " printf(\"\\n\");" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
+
+ stream << "static void printBitsetIndices(const char* a, size_t length) {" << std::endl;
+ stream << " const char* seperator = \"\";" << std::endl;
+ stream << " for (int i = 0; i < length; i++) {" << std::endl;
+ stream << " if (IS_SET(i, a)) {" << std::endl;
+ stream << " printf(\"%s%d\", seperator, i);" << std::endl;
+ stream << " seperator = \", \";" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << " printf(\"\\n\");" << std::endl;
+ stream << "}" << std::endl;
+
+ stream << "#endif" << std::endl;
+ stream << std::endl;
+
+ stream << "static void bit_or(char* dest, const char* mask, size_t i) {" << std::endl;
+ stream << " do {" << std::endl;
+ stream << " dest[i - 1] |= mask[i - 1];" << std::endl;
+ stream << " } while(--i);" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
+
+ stream << "static void bit_copy(char* dest, const char* source, size_t i) {" << std::endl;
+ stream << " do {" << std::endl;
+ stream << " dest[i - 1] = source[i - 1];" << std::endl;
+ stream << " } while(--i);" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
+
+ stream << "static int bit_has_and(const char* a, const char* b, size_t i) {" << std::endl;
+ stream << " do {" << std::endl;
+ stream << " if (a[i - 1] & b[i - 1])" << std::endl;
+ stream << " return true;" << std::endl;
+ stream << " } while(--i);" << std::endl;
+ stream << " return false;" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
+
+ stream << "static void bit_and_not(char* dest, const char* mask, size_t i) {" << std::endl;
+ stream << " do {" << std::endl;
+ stream << " dest[i - 1] &= ~mask[i - 1];" << std::endl;
+ stream << " } while(--i);" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
+
+ stream << "static void bit_and(char* dest, const char* mask, size_t i) {" << std::endl;
+ stream << " do {" << std::endl;
+ stream << " dest[i - 1] &= mask[i - 1];" << std::endl;
+ stream << " } while(--i);" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
+
+ stream << "static int bit_any_set(const char* a, size_t i) {" << std::endl;
+ stream << " do {" << std::endl;
+ stream << " if (a[i - 1] > 0)" << std::endl;
+ stream << " return true;" << std::endl;
+ stream << " } while(--i);" << std::endl;
+ stream << " return false;" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
+
+}
+
+void ChartToC::writeExecContent(std::ostream& stream) {
+ for (int i = 0; i < _states.size(); i++) {
+ Element<std::string> state(_states[i]);
+
+ if (i == 0) {
+ // root state - we need to perform some initialization here
+ NodeSet<std::string> globalScripts = filterChildElements(_nsInfo.xmlNSPrefix + "script", state);
+ for (int j = 0; j < globalScripts.size(); j++) {
+ stream << "static int global_script_" << toStr(j) << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
+ stream << " int err = SCXML_ERR_OK;" << std::endl;
+ writeExecContent(stream, globalScripts[j], 1);
+ stream << " return SCXML_ERR_OK;" << std::endl;
+ stream << "}" << std::endl;
+ }
+
+ stream << "static int global_script(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
+ for (int j = 0; j < globalScripts.size(); j++) {
+ stream << " global_script_" << toStr(j) << "(ctx, state, event);" << std::endl;
+ }
+ stream << " return SCXML_ERR_OK;" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
+ }
+
+ NodeSet<std::string> onexit = filterChildElements(_nsInfo.xmlNSPrefix + "onexit", state);
+ for (int j = 0; j < onexit.size(); j++) {
+ stream << "static int " << DOMUtils::idForNode(state) << "_on_exit_" << toStr(j) << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
+ stream << " int err = SCXML_ERR_OK;" << std::endl;
+ writeExecContent(stream, onexit[j], 1);
+ stream << " return SCXML_ERR_OK;" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
+ }
+
+ if (onexit.size() > 0) {
+ stream << "static int " << DOMUtils::idForNode(state) << "_on_exit(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
+ for (int j = 0; j < onexit.size(); j++) {
+ stream << " " << DOMUtils::idForNode(state) << "_on_exit_" << toStr(j) << "(ctx, state, event);" << std::endl;
+ }
+ stream << " return SCXML_ERR_OK;" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
+ }
+
+
+ NodeSet<std::string> onentry = filterChildElements(_nsInfo.xmlNSPrefix + "onentry", state);
+ for (int j = 0; j < onentry.size(); j++) {
+ stream << "static int " << DOMUtils::idForNode(state) << "_on_entry_" << toStr(j) << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
+ stream << " int err = SCXML_ERR_OK;" << std::endl;
+ writeExecContent(stream, onentry[j], 1);
+ stream << " return SCXML_ERR_OK;" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
+ }
+
+ bool hasInitialState = false;
+ NodeSet<std::string> initial = filterChildElements(_nsInfo.xmlNSPrefix + "initial", state);
+ if (initial.size() > 0) {
+ NodeSet<std::string> initialTransition = filterChildElements(_nsInfo.xmlNSPrefix + "transition", initial);
+ if (initialTransition.size() > 0) {
+ hasInitialState = true;
+ stream << "static int " << DOMUtils::idForNode(state) << "_initial" << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
+ stream << " int err = SCXML_ERR_OK;" << std::endl;
+ writeExecContent(stream, initialTransition[0], 1);
+ stream << " return SCXML_ERR_OK;" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
+ }
+ }
+
+
+ if (onentry.size() > 0) {
+ stream << "static int " << DOMUtils::idForNode(state) << "_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
+ for (int j = 0; j < onentry.size(); j++) {
+ stream << " " << DOMUtils::idForNode(state) << "_on_entry_" << toStr(j) << "(ctx, state, event);" << std::endl;
+ }
+ if (hasInitialState) {
+ stream << " " << DOMUtils::idForNode(state) << "_initial" << "(ctx, state, event);" << std::endl;
+ }
+
+ stream << " return SCXML_ERR_OK;" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
+ }
+
+
+ NodeSet<std::string> invoke = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", state);
+ if (invoke.size() > 0) {
+ stream << "static int " << DOMUtils::idForNode(state) << "_invoke(const scxml_ctx* ctx, const scxml_state* s, const scxml_invoke* x) {" << std::endl;
+ for (int j = 0; j < invoke.size(); j++) {
+ stream << " ctx->invoke(ctx, s, x);" << std::endl;
+ stream << " return SCXML_ERR_OK;" << std::endl;
+ stream << std::endl;
+ }
+ stream << "}" << std::endl;
+ }
+ }
+
+ for (int i = 0; i < _transitions.size(); i++) {
+ Element<std::string> transition(_transitions[i]);
+ if (iequals(TAGNAME_CAST(transition.getParentNode()), "initial"))
+ continue;
+
+ NodeSet<std::string> execContent = filterChildType(Node_base::ELEMENT_NODE, transition);
+
+ if (execContent.size() > 0) {
+ stream << "static int " << DOMUtils::idForNode(transition) << "_on_trans(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
+ stream << " int err = SCXML_ERR_OK;" << std::endl;
+ for (int j = 0; j < execContent.size(); j++) {
+ writeExecContent(stream, Element<std::string>(execContent[j]), 1);
+ }
+ stream << " return SCXML_ERR_OK;" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
+ }
+ }
+}
+
+void ChartToC::writeExecContent(std::ostream& stream, const Arabica::DOM::Node<std::string>& node, int indent) {
+ if (!node)
+ return;
+
+ if (node.getNodeType() == Node_base::TEXT_NODE) {
+ if (boost::trim_copy(node.getNodeValue()).length() > 0) {
+ std::string escaped = escape(node.getNodeValue());
+ stream << escaped;
+ }
+ return;
+ }
+
+ std::string padding;
+ for (int i = 0; i < indent; i++) {
+ padding += " ";
+ }
+
+
+ if (node.getNodeType() != Node_base::ELEMENT_NODE)
+ return; // skip anything not an element
+
+ Arabica::DOM::Element<std::string> elem = Arabica::DOM::Element<std::string>(node);
+
+ if (false) {
+ } else if(TAGNAME(elem) == "onentry" || TAGNAME(elem) == "onexit" || TAGNAME(elem) == "transition" || TAGNAME(elem) == "finalize") {
+ // descent into childs and write their contents
+ Arabica::DOM::Node<std::string> child = node.getFirstChild();
+ while(child) {
+ writeExecContent(stream, child, indent);
+ child = child.getNextSibling();
+ }
+ } else if(TAGNAME(elem) == "script") {
+ stream << padding;
+ stream << "if likely(ctx->exec_content_script != NULL) {" << std::endl;
+ stream << padding;
+ stream << " if unlikely((err = ctx->exec_content_script(ctx, ";
+ stream << (HAS_ATTR(elem, "src") ? "\"" + escape(ATTR(elem, "src")) + "\"" : "NULL") << ", ";
+
+ NodeSet<std::string> scriptTexts = filterChildType(Node_base::TEXT_NODE, elem);
+ if (scriptTexts.size() > 0) {
+ stream << "\"";
+ writeExecContent(stream, scriptTexts[0], 0);
+ stream << "\"";
+ } else {
+ stream << "NULL";
+ }
+
+ stream << ")) != SCXML_ERR_OK) return err;" << std::endl;
+ stream << padding << "} else {" << std::endl;
+ stream << padding << " return SCXML_ERR_MISSING_CALLBACK;" << std::endl;
+ stream << padding << "}" << std::endl;
+
+ } else if(TAGNAME(elem) == "log") {
+ stream << padding;
+ stream << "if likely(ctx->exec_content_log != NULL) {" << std::endl;
+ stream << padding;
+ stream << " if unlikely((ctx->exec_content_log(ctx, ";
+ stream << (HAS_ATTR(elem, "label") ? "\"" + escape(ATTR(elem, "label")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(elem, "expr") ? "\"" + escape(ATTR(elem, "expr")) + "\"" : "NULL");
+ stream << ")) != SCXML_ERR_OK) return err;" << std::endl;
+ stream << padding << "} else {" << std::endl;
+ stream << padding << " return SCXML_ERR_MISSING_CALLBACK;" << std::endl;
+ stream << padding << "}" << std::endl;
+
+ } else if(TAGNAME(elem) == "foreach") {
+ stream << padding << "if likely(ctx->exec_content_foreach_init != NULL &&" << std::endl;
+ stream << padding << " ctx->exec_content_foreach_next != NULL &&" << std::endl;
+ stream << padding << " ctx->exec_content_foreach_done != NULL) {" << std::endl;
+ stream << std::endl;
+
+ stream << padding << " if unlikely((ctx->exec_content_foreach_init(ctx, &scxml_elem_foreachs[" << ATTR(elem, "documentOrder") << "])) != SCXML_ERR_OK) return err;" << std::endl;
+ stream << padding << " while (ctx->exec_content_foreach_next(ctx, &scxml_elem_foreachs[" << ATTR(elem, "documentOrder") << "]) == SCXML_ERR_OK) {" << std::endl;
+ Arabica::DOM::Node<std::string> child = node.getFirstChild();
+ while(child) {
+ writeExecContent(stream, child, indent + 2);
+ child = child.getNextSibling();
+ }
+ stream << padding << " }" << std::endl;
+ stream << padding << " if ((ctx->exec_content_foreach_done(ctx, &scxml_elem_foreachs[" << ATTR(elem, "documentOrder") << "])) != SCXML_ERR_OK) return err;" << std::endl;
+ stream << padding << "} else {" << std::endl;
+ stream << padding << " return SCXML_ERR_MISSING_CALLBACK;" << std::endl;
+ stream << padding << "}" << std::endl;
+
+ } else if(TAGNAME(elem) == "if") {
+ stream << padding;
+ stream << "if likely(ctx->is_true != NULL) {" << std::endl;
+ stream << padding;
+ stream << " if (ctx->is_true(ctx, " << (HAS_ATTR(elem, "cond") ? "\"" + escape(ATTR(elem, "cond")) + "\"" : "NULL") << ")) {" << std::endl;
+ Arabica::DOM::Node<std::string> child = elem.getFirstChild();
+ while(child) {
+ if (child.getNodeType() == Node_base::ELEMENT_NODE && TAGNAME_CAST(child) == "elseif") {
+ stream << padding;
+ stream << " } else if (ctx->is_true(ctx, " << (HAS_ATTR_CAST(child, "cond") ? "\"" + escape(ATTR_CAST(child, "cond")) + "\"" : "NULL") << ")) {" << std::endl;
+ } else if (child.getNodeType() == Node_base::ELEMENT_NODE && TAGNAME_CAST(child) == "else") {
+ stream << padding;
+ stream << " } else {" << std::endl;
+ } else {
+ writeExecContent(stream, child, indent + 2);
+ }
+ child = child.getNextSibling();
+ }
+ stream << padding << " }" << std::endl;
+ stream << padding << "} else {" << std::endl;
+ stream << padding << " return SCXML_ERR_MISSING_CALLBACK;" << std::endl;
+ stream << padding << "}" << std::endl;
+
+ } else if(TAGNAME(elem) == "assign") {
+ stream << padding;
+ stream << "if likely(ctx->exec_content_assign != NULL) {" << std::endl;
+ stream << padding;
+ stream << " if ((ctx->exec_content_assign(ctx, ";
+ stream << (HAS_ATTR(elem, "location") ? "\"" + escape(ATTR(elem, "location")) + "\"" : "NULL") << ", ";
+ if (HAS_ATTR(elem, "expr")) {
+ stream << "\"" + escape(ATTR(elem, "expr")) + "\"";
+ } else {
+ NodeSet<std::string> assignTexts = filterChildType(Node_base::TEXT_NODE, elem);
+ if (assignTexts.size() > 0) {
+ stream << "\"";
+ writeExecContent(stream, assignTexts[0], 0);
+ stream << "\"";
+ } else {
+ stream << "NULL";
+ }
+ }
+ stream << ")) != SCXML_ERR_OK) return err;" << std::endl;
+ stream << padding << "} else {" << std::endl;
+ stream << padding << " return SCXML_ERR_MISSING_CALLBACK;" << std::endl;
+ stream << padding << "}" << std::endl;
+
+
+ } else if(TAGNAME(elem) == "raise") {
+ stream << padding;
+ stream << "if likely(ctx->exec_content_raise != NULL) {" << std::endl;
+ stream << padding;
+ stream << " if unlikely((ctx->exec_content_raise(ctx, ";
+ stream << (HAS_ATTR(elem, "event") ? "\"" + escape(ATTR(elem, "event")) + "\"" : "NULL");
+ stream << ")) != SCXML_ERR_OK) return err;" << std::endl;
+ stream << padding << "} else {" << std::endl;
+ stream << padding << " return SCXML_ERR_MISSING_CALLBACK;" << std::endl;
+ stream << padding << "}" << std::endl;
+
+ } else if(TAGNAME(elem) == "send") {
+ stream << padding;
+ stream << "if likely(ctx->exec_content_send != NULL) {" << std::endl;
+ stream << padding;
+ stream << " if ((ctx->exec_content_send(ctx, &scxml_elem_sends[" << ATTR(elem, "documentOrder") << "]";
+ stream << ")) != SCXML_ERR_OK) return err;" << std::endl;
+ stream << padding << "} else {" << std::endl;
+ stream << padding << " return SCXML_ERR_MISSING_CALLBACK;" << std::endl;
+ stream << padding << "}" << std::endl;
+
+ } else if(TAGNAME(elem) == "cancel") {
+ stream << padding;
+ stream << "if likely(ctx->exec_content_cancel != NULL) {" << std::endl;
+ stream << padding;
+ stream << " if ((ctx->exec_content_cancel(ctx, ";
+ stream << (HAS_ATTR(elem, "sendid") ? "\"" + escape(ATTR(elem, "sendid")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(elem, "sendidexpr") ? "\"" + escape(ATTR(elem, "sendidexpr")) + "\"" : "NULL");
+ stream << ")) != SCXML_ERR_OK) return err;" << std::endl;
+ stream << padding << "} else {" << std::endl;
+ stream << padding << " return SCXML_ERR_MISSING_CALLBACK;" << std::endl;
+ stream << padding << "}" << std::endl;
+
+ } else {
+ std::cerr << "'" << TAGNAME(elem) << "'" << std::endl << elem << std::endl;
+ assert(false);
+ }
+
+}
+
+void ChartToC::writeElementInfo(std::ostream& stream) {
+ NodeSet<std::string> foreachs = filterChildElements(_nsInfo.xmlNSPrefix + "foreach", _scxml, true);
+ if (foreachs.size() > 0) {
+ stream << "static scxml_elem_foreach scxml_elem_foreachs[" << foreachs.size() << "] = {" << std::endl;
+ for (int i = 0; i < foreachs.size(); i++) {
+ Element<std::string> foreach(foreachs[i]);
+ stream << " { ";
+ stream << (HAS_ATTR(foreach, "array") ? "\"" + escape(ATTR(foreach, "array")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(foreach, "item") ? "\"" + escape(ATTR(foreach, "item")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(foreach, "index") ? "\"" + escape(ATTR(foreach, "index")) + "\"" : "NULL");
+ stream << " }" << (i + 1 < foreachs.size() ? ",": "") << std::endl;
+ foreach.setAttribute("documentOrder", toStr(i));
+ }
+ stream << "};" << std::endl;
+ stream << std::endl;
+ }
+
+ NodeSet<std::string> datas = filterChildElements(_nsInfo.xmlNSPrefix + "data", _scxml, true);
+ if (datas.size() > 0) {
+ size_t dataIndexOffset = 0;
+ Node<std::string> parent;
+ size_t distinctParents = 0;
+
+ if (_binding == InterpreterImpl::EARLY) {
+ Element<std::string>(_states[0]).setAttribute("dataIndex", "0");
+ distinctParents = 1;
+ } else {
+ for (int i = 0; i < datas.size(); i++) {
+ Element<std::string> data(datas[i]);
+ if (data.getParentNode() != parent) {
+ distinctParents++;
+ }
+ }
+ }
+
+ parent = Node<std::string>();
+
+ stream << "static scxml_elem_data scxml_elem_datas[" << datas.size() + distinctParents << "] = {" << std::endl;
+ for (int i = 0; i < datas.size(); i++) {
+ Element<std::string> data(datas[i]);
+ if (data.getParentNode().getParentNode() != parent) {
+ if (_binding == InterpreterImpl::LATE) {
+ if (i > 0) {
+ stream << " { NULL, NULL, NULL, NULL }," << std::endl;
+ dataIndexOffset++;
+ }
+ Element<std::string>(data.getParentNode().getParentNode()).setAttribute("dataIndex", toStr(i + dataIndexOffset));
+ }
+ parent = data.getParentNode().getParentNode();
+ }
+ stream << " { ";
+ stream << (HAS_ATTR(data, "id") ? "\"" + escape(ATTR(data, "id")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(data, "src") ? "\"" + escape(ATTR(data, "src")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(data, "expr") ? "\"" + escape(ATTR(data, "expr")) + "\"" : "NULL") << ", ";
+
+ NodeSet<std::string> dataTexts = filterChildType(Node_base::TEXT_NODE, data);
+ if (dataTexts.size() > 0) {
+ if (boost::trim_copy(dataTexts[0].getNodeValue()).length() > 0) {
+ std::string escaped = escape(dataTexts[0].getNodeValue());
+ stream << "\"" << escaped << "\"" << std::endl;
+ }
+ } else {
+ stream << "NULL";
+ }
+ stream << " }," << std::endl;
+
+ }
+ stream << " { NULL, NULL, NULL, NULL }" << std::endl;
+ stream << "};" << std::endl;
+ stream << std::endl;
+ }
+
+ NodeSet<std::string> params = filterChildElements(_nsInfo.xmlNSPrefix + "param", _scxml, true);
+ if (params.size() > 0) {
+ Node<std::string> parent;
+ size_t distinctParents = 0;
+ for (int i = 0; i < params.size(); i++) {
+ Element<std::string> param(params[i]);
+ if (param.getParentNode() != parent) {
+ distinctParents++;
+ }
+ }
+ parent = Node<std::string>();
+
+ stream << "static scxml_elem_param scxml_elem_params[" << params.size() + distinctParents << "] = {" << std::endl;
+ for (int i = 0; i < params.size(); i++) {
+ Element<std::string> param(params[i]);
+ if (param.getParentNode() != parent) {
+ Element<std::string>(param.getParentNode()).setAttribute("paramIndex", toStr(i));
+ if (i > 0) {
+ stream << " { NULL, NULL, NULL }," << std::endl;
+ }
+ parent = param.getParentNode();
+ }
+ stream << " { ";
+ stream << (HAS_ATTR(param, "name") ? "\"" + escape(ATTR(param, "name")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(param, "expr") ? "\"" + escape(ATTR(param, "expr")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(param, "location") ? "\"" + escape(ATTR(param, "location")) + "\"" : "NULL");
+ stream << " }," << std::endl;
+
+ }
+ stream << " { NULL, NULL, NULL }" << std::endl;
+ stream << "};" << std::endl;
+ stream << std::endl;
+ }
+
+ NodeSet<std::string> sends = filterChildElements(_nsInfo.xmlNSPrefix + "send", _scxml, true);
+ if (sends.size() > 0) {
+ stream << "static scxml_elem_send scxml_elem_sends[" << sends.size() << "] = {" << std::endl;
+ for (int i = 0; i < sends.size(); i++) {
+ Element<std::string> send(sends[i]);
+ stream << " { ";
+ stream << (HAS_ATTR(send, "event") ? "\"" + escape(ATTR(send, "event")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(send, "eventexpr") ? "\"" + escape(ATTR(send, "eventexpr")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(send, "target") ? "\"" + escape(ATTR(send, "target")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(send, "targetexpr") ? "\"" + escape(ATTR(send, "targetexpr")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(send, "type") ? "\"" + escape(ATTR(send, "type")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(send, "typeexpr") ? "\"" + escape(ATTR(send, "typeexpr")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(send, "id") ? "\"" + escape(ATTR(send, "id")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(send, "idlocation") ? "\"" + escape(ATTR(send, "idlocation")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(send, "delay") ? "\"" + escape(ATTR(send, "delay")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(send, "delayexpr") ? "\"" + escape(ATTR(send, "delayexpr")) + "\"" : "NULL") << ", ";
+ stream << (HAS_ATTR(send, "namelist") ? "\"" + escape(ATTR(send, "namelist")) + "\"" : "NULL") << ", ";
+
+ NodeSet<std::string> contents = filterChildElements(_nsInfo.xmlNSPrefix + "content", send);
+ if (contents.size() > 0) {
+ std::stringstream ss;
+ NodeList<std::string> cChilds = contents[0].getChildNodes();
+ for (int j = 0; j < cChilds.getLength(); j++) {
+ ss << cChilds.item(j);
+ }
+ stream << (ss.str().size() > 0 ? "\"" + escape(ss.str()) + "\", " : "NULL, ");
+ stream << (HAS_ATTR_CAST(contents[0], "expr") ? "\"" + ATTR_CAST(contents[0], "expr") + "\", " : "NULL, ");
+ } else {
+ stream << "NULL, NULL, ";
+ }
+
+
+ if (HAS_ATTR(send, "paramIndex")) {
+ stream << "(const scxml_elem_param*)&scxml_elem_params[" << escape(ATTR(send, "paramIndex")) << "], ";
+ } else {
+ stream << "NULL, ";
+ }
+ stream << "NULL";
+
+ stream << " }" << (i + 1 < sends.size() ? ",": "") << std::endl;
+ send.setAttribute("documentOrder", toStr(i));
+ }
+ stream << "};" << std::endl;
+ stream << std::endl;
+ }
+
+ NodeSet<std::string> donedatas = filterChildElements(_nsInfo.xmlNSPrefix + "donedata", _scxml, true);
+ stream << "static scxml_elem_donedata scxml_elem_donedatas[" << donedatas.size() + 1 << "] = {" << std::endl;
+ for (int i = 0; i < donedatas.size(); i++) {
+ Element<std::string> donedata(donedatas[i]);
+ stream << " { ";
+
+ // parent
+ stream << ATTR_CAST(donedata.getParentNode(), "documentOrder") << ", ";
+
+ NodeSet<std::string> contents = filterChildElements(_nsInfo.xmlNSPrefix + "content", donedata);
+ if (contents.size() > 0) {
+ std::stringstream ss;
+ NodeList<std::string> cChilds = contents[0].getChildNodes();
+ for (int j = 0; j < cChilds.getLength(); j++) {
+ ss << cChilds.item(j);
+ }
+ stream << (ss.str().size() > 0 ? "\"" + escape(ss.str()) + "\", " : "NULL, ");
+ stream << (HAS_ATTR_CAST(contents[0], "expr") ? "\"" + ATTR_CAST(contents[0], "expr") + "\", " : "NULL, ");
+ } else {
+ stream << "NULL, NULL, ";
+ }
+
+ if (HAS_ATTR(donedata, "paramIndex")) {
+ stream << "(const scxml_elem_param*)&scxml_elem_params[" << escape(ATTR(donedata, "paramIndex")) << "]";
+ } else {
+ stream << "NULL";
+ }
+
+ stream << " }," << std::endl;
+ donedata.setAttribute("documentOrder", toStr(i));
+ }
+ stream << " { 0, NULL, NULL }" << std::endl;
+ stream << "};" << std::endl;
+ stream << std::endl;
+
+}
+
+void ChartToC::writeStates(std::ostream& stream) {
+ stream << "static scxml_state scxml_states[" << toStr(_states.size()) << "] = {" << std::endl;
+ for (int i = 0; i < _states.size(); i++) {
+ Element<std::string> state(_states[i]);
+ stream << " { ";
+
+ // name
+ stream << (HAS_ATTR(state, "id") ? "\"" + escape(ATTR(state, "id")) + "\"" : "NULL") << ", ";
+
+ // parent
+ stream << (i == 0 ? "0" : ATTR_CAST(state.getParentNode(), "documentOrder")) << ", ";
+
+ // onentry
+ stream << (filterChildElements(_nsInfo.xmlNSPrefix + "onentry", state).size() > 0 ? DOMUtils::idForNode(state) + "_on_entry" : "NULL") << ", ";
+
+ // onexit
+ stream << (filterChildElements(_nsInfo.xmlNSPrefix + "onexit", state).size() > 0 ? DOMUtils::idForNode(state) + "_on_exit" : "NULL") << ", ";
+
+ // invokers
+ stream << (filterChildElements(_nsInfo.xmlNSPrefix + "invoke", state).size() > 0 ? DOMUtils::idForNode(state) + "_invoke" : "NULL") << ", ";
+
+ // children
+ std::string childBools;
+ std::string childBoolsIdx;
+ for (int j = 0; j < _states.size(); j++) {
+ if (_states[j].getParentNode() == state) {
+ childBools += "1";
+ childBoolsIdx += " " + toStr(j);
+ } else {
+ childBools += "0";
+ }
+ }
+ stream << "{ ";
+ writeCharArrayInitList(stream, childBools);
+ stream << " /* " << childBools << "," << childBoolsIdx << " */";
+ stream << " }, ";
+
+ // default completion
+ NodeSet<std::string> completion;
+ if (isHistory(state)) {
+ bool deep = (HAS_ATTR(state, "type") && iequals(ATTR(state, "type"), "deep"));
+ for (int j = 0; j < _states.size(); j++) {
+ if (deep) {
+ if (isDescendant(_states[j], state.getParentNode()) && !isHistory(Element<std::string>(_states[j]))) {
+ completion.push_back(_states[j]);
+ }
+ } else {
+ if (_states[j].getParentNode() == state.getParentNode() && !isHistory(Element<std::string>(_states[j]))) {
+ completion.push_back(_states[j]);
+ }
+ }
+ }
+ }
+ if (isParallel(state)) {
+ completion = getChildStates(state);
+ } else if (state.hasAttribute("initial")) {
+ completion = getStates(tokenizeIdRefs(state.getAttribute("initial")));
+ } else {
+ NodeSet<std::string> initElems = filterChildElements(_nsInfo.xmlNSPrefix + "initial", state);
+ if(initElems.size() > 0 && !iequals(ATTR_CAST(initElems[0], "generated"), "true")) {
+ // initial element is first child
+ completion.push_back(initElems[0]);
+ } else {
+ // first child state
+ Arabica::XPath::NodeSet<std::string> initStates;
+ NodeList<std::string> childs = state.getChildNodes();
+ for (int i = 0; i < childs.getLength(); i++) {
+ if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ if (isState(Element<std::string>(childs.item(i)))) {
+ completion.push_back(childs.item(i));
+ break;
+ }
+ }
+ }
+ }
+
+ std::string descBools;
+ std::string descBoolsIdx;
+ for (int j = 0; j < _states.size(); j++) {
+ if (isMember(_states[j], completion)) {
+ descBools += "1";
+ descBoolsIdx += " " + toStr(j);
+ } else {
+ descBools += "0";
+ }
+ }
+ stream << "{ ";
+ writeCharArrayInitList(stream, descBools);
+ stream << " /* " << descBools << "," << descBoolsIdx << " */";
+ stream << " }, ";
+
+ // ancestors
+ std::string ancBools;
+ std::string ancBoolsIdx;
+ for (int j = 0; j < _states.size(); j++) {
+ if (isDescendant(state, _states[j])) {
+ ancBools += "1";
+ ancBoolsIdx += " " + toStr(j);
+ } else {
+ ancBools += "0";
+ }
+ }
+ stream << "{ ";
+ writeCharArrayInitList(stream, ancBools);
+ stream << " /* " << ancBools << "," << ancBoolsIdx << " */";
+ stream << " }, ";
+
+ if (HAS_ATTR(state, "dataIndex")) {
+ stream << "(const scxml_elem_data*)&scxml_elem_datas[" << escape(ATTR(state, "dataIndex")) << "], ";
+ } else {
+ stream << "NULL, ";
+ }
+
+ if (false) {
+ } else if (iequals(TAGNAME(state), "initial")) {
+ stream << "SCXML_STATE_INITIAL";
+ } else if (isFinal(state)) {
+ stream << "SCXML_STATE_FINAL";
+ } else if (isHistory(state)) {
+ if (HAS_ATTR(state, "type") && iequals(ATTR(state, "type"), "deep")) {
+ stream << "SCXML_STATE_HISTORY_DEEP";
+ } else {
+ stream << "SCXML_STATE_HISTORY_SHALLOW";
+ }
+ } else if (isAtomic(state)) {
+ stream << "SCXML_STATE_ATOMIC";
+ } else if (isParallel(state)) {
+ stream << "SCXML_STATE_PARALLEL";
+ } else if (isCompound(state)) {
+ stream << "SCXML_STATE_COMPOUND";
+ } else { // <scxml>
+ stream << "SCXML_STATE_COMPOUND";
+ }
+
+ stream << " }" << (i + 1 < _states.size() ? ",": "") << std::endl;
+ }
+ stream << "};" << std::endl;
+ stream << std::endl;
+}
+
+
+void ChartToC::writeTransitions(std::ostream& stream) {
+
+ stream << "static scxml_transition scxml_transitions[" << toStr(_transitions.size()) << "] = {" << std::endl;
+ for (int i = 0; i < _transitions.size(); i++) {
+ Element<std::string> transition(_transitions[i]);
+ stream << " { ";
+
+ /**
+ uint16_t source;
+ target[SCXML_NUMBER_STATES / 8 + 1];
+ const char* event;
+ const char* condition;
+ exec_content_t on_transition;
+ uint8_t type;
+ char conflicts[SCXML_NUMBER_STATES / 8 + 1];
+ char exit_set[SCXML_NUMBER_STATES / 8 + 1];
+ */
+
+ // source
+ stream << ATTR_CAST(transition.getParentNode(), "documentOrder") << ", ";
+
+ // targets
+ if (HAS_ATTR(transition, "target")) {
+ std::list<std::string> targets = tokenize(ATTR(transition, "target"));
+
+ std::string targetBools;
+ for (int j = 0; j < _states.size(); j++) {
+ Element<std::string> state(_states[j]);
+
+ if (HAS_ATTR(state, "id") &&
+ std::find(targets.begin(), targets.end(), escape(ATTR(state, "id"))) != targets.end()) {
+ targetBools += "1";
+ } else {
+ targetBools += "0";
+ }
+ }
+
+ stream << "{ ";
+ writeCharArrayInitList(stream, targetBools);
+ stream << " /* " << targetBools << " */";
+ stream << " }, ";
+
+ } else {
+ stream << "{ NULL }, ";
+ }
+
+ // event
+ stream << (HAS_ATTR(transition, "event") ? "\"" + escape(ATTR(transition, "event")) + "\"" : "NULL") << ", ";
+
+ // condition
+ stream << (HAS_ATTR(transition, "cond") ? "\"" + escape(ATTR(transition, "cond")) + "\"" : "NULL") << ", ";
+
+ // on transition handlers
+ if (filterChildType(Arabica::DOM::Node_base::ELEMENT_NODE, transition).size() > 0 &&
+ !iequals(TAGNAME_CAST(transition.getParentNode()), "initial")) {
+ stream << DOMUtils::idForNode(transition) + "_on_trans, ";
+ } else {
+ stream << "NULL, ";
+ }
+
+ // type
+ std::string seperator = "";
+ if (!HAS_ATTR(transition, "target")) {
+ stream << seperator << "SCXML_TRANS_TARGETLESS";
+ seperator = " | ";
+ }
+
+ if (HAS_ATTR(transition, "type") && iequals(ATTR(transition, "type"), "internal")) {
+ stream << seperator << "SCXML_TRANS_INTERNAL";
+ seperator = " | ";
+ }
+
+ if (!HAS_ATTR(transition, "event")) {
+ stream << seperator << "SCXML_TRANS_SPONTANEOUS";
+ seperator = " | ";
+ }
+
+ if (iequals(TAGNAME_CAST(transition.getParentNode()), "history")) {
+ stream << seperator << "SCXML_TRANS_HISTORY";
+ seperator = " | ";
+ }
+
+ if (seperator.size() == 0) {
+ stream << "0";
+ }
+ stream << ", ";
+
+ // conflicts
+ std::string conflictBools;
+ for (unsigned int j = 0; j < _transitions.size(); j++) {
+ Element<std::string> t2(_transitions[j]);
+ if (hasIntersection(computeExitSet(transition), computeExitSet(t2)) ||
+ (getSourceState(transition) == getSourceState(t2)) ||
+ (isDescendant(getSourceState(transition), getSourceState(t2))) ||
+ (isDescendant(getSourceState(t2), getSourceState(transition)))) {
+ conflictBools += "1";
+ } else {
+ conflictBools += "0";
+ }
+ }
+ stream << "{ ";
+ writeCharArrayInitList(stream, conflictBools);
+ stream << " /* " << conflictBools << " */";
+ stream << " }, ";
+
+ // exit set
+ std::string exitSetBools;
+ NodeSet<std::string> exitSet = computeExitSet(transition);
+ for (unsigned int j = 0; j < _states.size(); j++) {
+ Element<std::string> state(_states[j]);
+ if (isMember(state, exitSet)) {
+ exitSetBools += "1";
+ } else {
+ exitSetBools += "0";
+ }
+ }
+ stream << "{ ";
+ writeCharArrayInitList(stream, exitSetBools);
+ stream << " /* " << exitSetBools << " */";
+ stream << " }";
+
+ stream << " }" << (i + 1 < _transitions.size() ? ",": "") << std::endl;
+ }
+ stream << "};" << std::endl;
+ stream << std::endl;
+}
+
+Arabica::XPath::NodeSet<std::string> ChartToC::computeExitSet(const Arabica::DOM::Element<std::string>& transition) {
+
+ NodeSet<std::string> statesToExit;
+ if (!isTargetless(transition)) {
+ Arabica::DOM::Node<std::string> domain = getTransitionDomain(transition);
+ if (!domain)
+ return statesToExit;
+ for (unsigned int j = 0; j < _states.size(); j++) {
+ const Node<std::string>& s = _states[j];
+ if (isDescendant(s, domain)) {
+ statesToExit.push_back(s);
+ }
+ }
+ }
+
+ return statesToExit;
+}
+
+void ChartToC::writeCharArrayInitList(std::ostream& stream, const std::string& boolString) {
+ /**
+ * 0111 -> 0x08
+ * 1111 -> 0x0f
+ * 1111 1111 -> 0xff
+ * 1111 1111 1110 -> 0x0f, 0xfd
+ *
+ * 76543210 fedcba98 ...
+ */
+
+ std::string charArray;
+ size_t index = 0;
+ char currChar = 0;
+
+ for (std::string::const_iterator bIter = boolString.begin(); bIter != boolString.end(); bIter++) {
+
+ if (*bIter == '1') {
+ currChar |= 1 << index;
+ }
+
+ index++;
+ if (index == 8) {
+ charArray += currChar;
+ currChar = 0;
+ index = 0;
+ }
+ }
+
+ if (index != 0) {
+ charArray += currChar;
+ }
+
+ std::string seperator = "";
+ for (std::string::const_iterator cIter = charArray.begin(); cIter != charArray.end(); cIter++) {
+ stream << seperator << "0x" << std::setw(2) << std::setfill('0') << std::hex << int(*cIter & 0xFF);
+ seperator = ", ";
+ }
+}
+
+void ChartToC::writeFSM(std::ostream& stream) {
+ stream << "int scxml_step(scxml_ctx* ctx) {" << std::endl;
+ stream << std::endl;
+
+ stream << "#ifdef SCXML_VERBOSE" << std::endl;
+ stream << " printf(\"Config: \");" << std::endl;
+ stream << " printStateNames(ctx->config);" << std::endl;
+ stream << "#endif" << std::endl;
+ stream << std::endl;
+
+ stream << "MACRO_STEP:" << std::endl;
+ stream << " ctx->flags &= ~SCXML_CTX_TRANSITION_FOUND;" << std::endl;
+ stream << std::endl;
+
+ stream << " if (ctx->flags & SCXML_CTX_TOP_LEVEL_FINAL) " << std::endl;
+ stream << " return SCXML_ERR_DONE; " << std::endl;
+ stream << std::endl;
+
+ stream << " int err = SCXML_ERR_OK;" << std::endl;
+ stream << " char conflicts[" << _transCharArraySize << "] = " << _transCharArrayInit << ";" << std::endl;
+ stream << " char target_set[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl;
+ stream << " char exit_set[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl;
+ stream << " char trans_set[" << _transCharArraySize << "] = " << _transCharArrayInit << ";" << std::endl;
+ stream << " char entry_set[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl;
+ stream << std::endl;
+
+ stream << " if unlikely(ctx->flags == SCXML_CTX_PRISTINE) {" << std::endl;
+ stream << " global_script(ctx, &scxml_states[0], NULL);" << std::endl;
+ stream << " bit_or(target_set, scxml_states[0].completion, " << _stateCharArraySize << ");" << std::endl;
+ stream << " ctx->flags |= SCXML_CTX_SPONTANEOUS | SCXML_CTX_INITIALIZED;" << std::endl;
+ stream << " goto COMPLETE_CONFIG;" << std::endl;
+ stream << " }" << std::endl;
+ stream << std::endl;
+
+ stream << " if (ctx->flags & SCXML_CTX_SPONTANEOUS) {" << std::endl;
+ stream << " ctx->event = NULL;" << std::endl;
+ stream << " goto SELECT_TRANSITIONS;" << std::endl;
+ stream << " }" << std::endl;
+ stream << " if ((ctx->event = ctx->dequeue_internal(ctx)) != NULL) {" << std::endl;
+ stream << " goto SELECT_TRANSITIONS;" << std::endl;
+ stream << " }" << std::endl;
+ stream << " if ((ctx->event = ctx->dequeue_external(ctx)) != NULL) {" << std::endl;
+ stream << " goto SELECT_TRANSITIONS;" << std::endl;
+ stream << " }" << std::endl;
+ stream << std::endl;
+
+// HISTORY TRANSITION IS SELECTED BY ACCIDENT!
+
+ stream << "SELECT_TRANSITIONS:" << std::endl;
+ stream << " for (int i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {" << std::endl;
+ stream << " // never select history or initial transitions automatically" << std::endl;
+ stream << " if unlikely(scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_HISTORY))" << std::endl;
+ stream << " continue;" << std::endl;
+ stream << std::endl;
+ stream << " // is the transition active?" << std::endl;
+ stream << " if (IS_SET(scxml_transitions[i].source, ctx->config)) {" << std::endl;
+ stream << " // is it non-conflicting?" << std::endl;
+ stream << " if (!IS_SET(i, conflicts)) {" << std::endl;
+ stream << " // is it enabled?" << std::endl;
+ stream << " if (ctx->is_enabled(ctx, &scxml_transitions[i], ctx->event) > 0) {" << std::endl;
+ stream << " // remember that we found a transition" << std::endl;
+ stream << " ctx->flags |= SCXML_CTX_TRANSITION_FOUND;" << std::endl;
+ stream << std::endl;
+
+ stream << " // transitions that are pre-empted" << std::endl;
+ stream << " bit_or(conflicts, scxml_transitions[i].conflicts, " << _transCharArraySize << ");" << std::endl;
+ stream << std::endl;
+ stream << " // states that are directly targeted (resolve as entry-set later)" << std::endl;
+ stream << " bit_or(target_set, scxml_transitions[i].target, " << _stateCharArraySize << ");" << std::endl;
+ stream << std::endl;
+ stream << " // states that will be left" << std::endl;
+ stream << " bit_or(exit_set, scxml_transitions[i].exit_set, " << _stateCharArraySize << ");" << std::endl;
+ stream << std::endl;
+ stream << " SET_BIT(i, trans_set);" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << " bit_and(exit_set, ctx->config, " << _stateCharArraySize << ");" << std::endl;
+ stream << std::endl;
+
+ stream << " if (ctx->flags & SCXML_CTX_TRANSITION_FOUND) {" << std::endl;
+ stream << " ctx->flags |= SCXML_CTX_SPONTANEOUS;" << std::endl;
+ stream << " } else {" << std::endl;
+ stream << " ctx->flags &= ~SCXML_CTX_SPONTANEOUS;" << std::endl;
+ stream << " goto MACRO_STEP;" << std::endl;
+// stream << " return SCXML_ERR_OK;" << std::endl;
+ stream << " }" << std::endl;
+ stream << std::endl;
+
+ stream << "#ifdef SCXML_VERBOSE" << std::endl;
+ stream << " printf(\"Targets: \");" << std::endl;
+ stream << " printStateNames(target_set);" << std::endl;
+ stream << "#endif" << std::endl;
+ stream << std::endl;
+
+ stream << "#ifdef SCXML_VERBOSE" << std::endl;
+ stream << " printf(\"Exiting: \");" << std::endl;
+ stream << " printStateNames(exit_set);" << std::endl;
+ stream << "#endif" << std::endl;
+ stream << std::endl;
+
+ stream << "#ifdef SCXML_VERBOSE" << std::endl;
+ stream << " printf(\"History: \");" << std::endl;
+ stream << " printStateNames(ctx->history);" << std::endl;
+ stream << "#endif" << std::endl;
+ stream << std::endl;
+
+ stream << "COMPLETE_CONFIG:" << std::endl;
+ stream << " // calculate new entry set" << std::endl;
+ stream << " bit_copy(entry_set, target_set, " << _stateCharArraySize << ");" << std::endl;
+ stream << std::endl;
+ stream << " // iterate for ancestors" << std::endl;
+ stream << " for (int i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl;
+ stream << " if (IS_SET(i, entry_set)) {" << std::endl;
+ stream << " bit_or(entry_set, scxml_states[i].ancestors, " << _stateCharArraySize << ");" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << std::endl;
+
+ stream << "// ADD_DESCENDANTS:" << std::endl;
+ stream << " // iterate for descendants" << std::endl;
+ stream << " for (int i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl;
+ stream << " if (IS_SET(i, entry_set)) {" << std::endl;
+ stream << " switch (scxml_states[i].type) {" << std::endl;
+ stream << " case SCXML_STATE_PARALLEL: {" << std::endl;
+ stream << " bit_or(entry_set, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl;
+ stream << " break;" << std::endl;
+ stream << " }" << std::endl;
+ stream << " case SCXML_STATE_HISTORY_SHALLOW:" << std::endl;
+ stream << " case SCXML_STATE_HISTORY_DEEP: {" << std::endl;
+ stream << " char history_targets[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl;
+ stream << " if (!bit_has_and(scxml_states[i].completion, ctx->history, " << _stateCharArraySize << ")) {" << std::endl;
+ stream << " // nothing set for history, look for a default transition or enter parents completion" << std::endl;
+ stream << " for (int j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {" << std::endl;
+ stream << " if unlikely(scxml_transitions[j].source == i) {" << std::endl;
+ stream << " bit_or(entry_set, scxml_transitions[j].target, " << _stateCharArraySize << ");" << std::endl;
+ stream << " SET_BIT(j, trans_set);" << std::endl;
+ stream << " break;" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << " // TODO: enter parents default completion here" << std::endl;
+ stream << " } else {" << std::endl;
+ stream << " bit_copy(history_targets, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl;
+ stream << " bit_and(history_targets, ctx->history, " << _stateCharArraySize << ");" << std::endl;
+ stream << " bit_or(entry_set, history_targets, " << _stateCharArraySize << ");" << std::endl;
+ stream << " }" << std::endl;
+ stream << " break;" << std::endl;
+ stream << " }" << std::endl;
+ stream << " case SCXML_STATE_INITIAL: {" << std::endl;
+ stream << " for (int j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {" << std::endl;
+ stream << " if (scxml_transitions[j].source == i) {" << std::endl;
+ stream << " SET_BIT(j, trans_set);" << std::endl;
+ stream << " CLEARBIT(i, entry_set);" << std::endl;
+ stream << " bit_or(entry_set, scxml_transitions[j].target, " << _stateCharArraySize << ");" << std::endl;
+ stream << " // one target may have been above, reestablish completion" << std::endl;
+ stream << " // goto ADD_DESCENDANTS; // initial will have to be first!" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << " break;" << std::endl;
+ stream << " }" << std::endl;
+ stream << " case SCXML_STATE_COMPOUND: { // we need to check whether one child is already in entry_set" << std::endl;
+ stream << " if (!bit_has_and(entry_set, scxml_states[i].children, " << _stateCharArraySize << ") &&" << std::endl;
+ stream << " !bit_has_and(ctx->config, scxml_states[i].children, " << _stateCharArraySize << "))" << std::endl;
+ stream << " {" << std::endl;
+ stream << " bit_or(entry_set, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl;
+ stream << " }" << std::endl;
+ stream << " break;" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << std::endl;
+
+ stream << "#ifdef SCXML_VERBOSE" << std::endl;
+ stream << " printf(\"Transitions: \");" << std::endl;
+ stream << " printBitsetIndices(trans_set, sizeof(char) * 8 * " << _transCharArraySize << ");" << std::endl;
+ stream << "#endif" << std::endl;
+ stream << std::endl;
+
+ stream << "// REMEMBER_HISTORY:" << std::endl;
+ stream << " for (int i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl;
+ stream << " if unlikely(scxml_states[i].type == SCXML_STATE_HISTORY_SHALLOW || scxml_states[i].type == SCXML_STATE_HISTORY_DEEP) {" << std::endl;
+ stream << " // a history state whose parent is about to be exited" << std::endl;
+ stream << " if unlikely(IS_SET(scxml_states[i].parent, exit_set)) {" << std::endl;
+ stream << " char history[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl;
+ stream << " bit_copy(history, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl;
+ stream << std::endl;
+ stream << " // set those states who were enabled" << std::endl;
+ stream << " bit_and(history, ctx->config, " << _stateCharArraySize << ");" << std::endl;
+ stream << std::endl;
+ stream << " // clear current history with completion mask" << std::endl;
+ stream << " bit_and_not(ctx->history, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl;
+ stream << std::endl;
+ stream << " // set history" << std::endl;
+ stream << " bit_or(ctx->history, history, " << _stateCharArraySize << ");" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+
+ stream << "// EXIT_STATES:" << std::endl;
+ stream << " for (int i = SCXML_NUMBER_STATES - 1; i >= 0; i--) {" << std::endl;
+ stream << " if (IS_SET(i, exit_set) && IS_SET(i, ctx->config)) {" << std::endl;
+ stream << " // call all on exit handlers" << std::endl;
+ stream << " if (scxml_states[i].on_exit != NULL) {" << std::endl;
+ stream << " if unlikely((err = scxml_states[i].on_exit(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK)" << std::endl;
+ stream << " return err;" << std::endl;
+ stream << " }" << std::endl;
+ stream << " CLEARBIT(i, ctx->config);" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << std::endl;
+
+ stream << "// TAKE_TRANSITIONS:" << std::endl;
+ stream << " for (int i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {" << std::endl;
+ stream << " if (IS_SET(i, trans_set) && (scxml_transitions[i].type & SCXML_TRANS_HISTORY) == 0) {" << std::endl;
+ stream << " // call executable content in transition" << std::endl;
+ stream << " if (scxml_transitions[i].on_transition != NULL) {" << std::endl;
+ stream << " if unlikely((err = scxml_transitions[i].on_transition(ctx," << std::endl;
+ stream << " &scxml_states[scxml_transitions[i].source]," << std::endl;
+ stream << " ctx->event)) != SCXML_ERR_OK)" << std::endl;
+ stream << " return err;" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << std::endl;
+
+ stream << "#ifdef SCXML_VERBOSE" << std::endl;
+ stream << " printf(\"Entering: \");" << std::endl;
+ stream << " printStateNames(entry_set);" << std::endl;
+ stream << "#endif" << std::endl;
+ stream << std::endl;
+
+ stream << "// ENTER_STATES:" << std::endl;
+ stream << " for (int i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl;
+ stream << " if (IS_SET(i, entry_set) && !IS_SET(i, ctx->config)) {" << std::endl;
+ stream << " // these are no proper states" << std::endl;
+ stream << " if unlikely(scxml_states[i].type == SCXML_STATE_HISTORY_DEEP ||" << std::endl;
+ stream << " scxml_states[i].type == SCXML_STATE_HISTORY_SHALLOW ||" << std::endl;
+ stream << " scxml_states[i].type == SCXML_STATE_INITIAL)" << std::endl;
+ stream << " continue;" << std::endl;
+ stream << std::endl;
+
+ stream << " SET_BIT(i, ctx->config);" << std::endl;
+ stream << std::endl;
+
+ stream << " // initialize data" << std::endl;
+ stream << " if (!IS_SET(i, ctx->initialized_data)) {" << std::endl;
+ stream << " if unlikely(scxml_states[i].data != NULL && ctx->exec_content_init != NULL) {" << std::endl;
+ stream << " ctx->exec_content_init(ctx, scxml_states[i].data);" << std::endl;
+ stream << " }" << std::endl;
+ stream << " SET_BIT(i, ctx->initialized_data);" << std::endl;
+ stream << " }" << std::endl;
+ stream << std::endl;
+
+ stream << " if (scxml_states[i].on_entry != NULL) {" << std::endl;
+ stream << " if unlikely((err = scxml_states[i].on_entry(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK)" << std::endl;
+ stream << " return err;" << std::endl;
+ stream << " }" << std::endl;
+ stream << std::endl;
+
+ stream << " // take history transitions" << std::endl;
+ stream << " for (int j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {" << std::endl;
+ stream << " if unlikely(IS_SET(j, trans_set) &&" << std::endl;
+ stream << " (scxml_transitions[j].type & SCXML_TRANS_HISTORY) &&" << std::endl;
+ stream << " scxml_states[scxml_transitions[j].source].parent == i) {" << std::endl;
+ stream << " // call executable content in transition" << std::endl;
+ stream << " if (scxml_transitions[j].on_transition != NULL) {" << std::endl;
+ stream << " if unlikely((err = scxml_transitions[j].on_transition(ctx," << std::endl;
+ stream << " &scxml_states[i]," << std::endl;
+ stream << " ctx->event)) != SCXML_ERR_OK)" << std::endl;
+ stream << " return err;" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << std::endl;
+
+ stream << " // handle final states" << std::endl;
+ stream << " if unlikely(scxml_states[i].type == SCXML_STATE_FINAL) {" << std::endl;
+ stream << " if unlikely(scxml_states[i].ancestors[0] == 0x01) {" << std::endl;
+ stream << " ctx->flags |= SCXML_CTX_TOP_LEVEL_FINAL;" << std::endl;
+ stream << " } else {" << std::endl;
+ stream << " // raise done event" << std::endl;
+ stream << " scxml_elem_donedata* donedata = &scxml_elem_donedatas[0];" << std::endl;
+ stream << " while(ELEM_DONEDATA_IS_SET(donedata)) {" << std::endl;
+ stream << " if unlikely(donedata->source == i)" << std::endl;
+ stream << " break;" << std::endl;
+ stream << " donedata++;" << std::endl;
+ stream << " }" << std::endl;
+ stream << " ctx->raise_done_event(ctx, &scxml_states[scxml_states[i].parent], (ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL));" << std::endl;
+ stream << " }" << std::endl;
+ stream << std::endl;
+
+ stream << " /**" << std::endl;
+ stream << " * are we the last final state to leave a parallel state?:" << std::endl;
+ stream << " * 1. Gather all parallel states in our ancestor chain" << std::endl;
+ stream << " * 2. Find all states for which these parallels are ancestors" << std::endl;
+ stream << " * 3. Iterate all active final states and remove their ancestors" << std::endl;
+ stream << " * 4. If a state remains, not all children of a parallel are final" << std::endl;
+ stream << " */" << std::endl;
+ stream << " for (int j = 0; j < SCXML_NUMBER_STATES; j++) {" << std::endl;
+ stream << " if unlikely(scxml_states[j].type == SCXML_STATE_PARALLEL) {" << std::endl;
+ stream << " char parallel_children[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl;
+ stream << " size_t parallel = j;" << std::endl;
+ stream << " for (int k = 0; k < SCXML_NUMBER_STATES; k++) {" << std::endl;
+ stream << " if unlikely(IS_SET(parallel, scxml_states[k].ancestors) && IS_SET(k, ctx->config)) {" << std::endl;
+ stream << " if (scxml_states[k].type == SCXML_STATE_FINAL) {" << std::endl;
+ stream << " bit_and_not(parallel_children, scxml_states[k].ancestors, " << _stateCharArraySize << ");" << std::endl;
+ stream << " } else {" << std::endl;
+ stream << " SET_BIT(k, parallel_children);" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << " if unlikely(!bit_any_set(parallel_children, " << _stateCharArraySize << ")) {" << std::endl;
+ stream << " ctx->raise_done_event(ctx, &scxml_states[parallel], NULL);" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << std::endl;
+
+ stream << " }" << std::endl;
+ stream << std::endl;
+
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << std::endl;
+
+// stream << "// HISTORY_TRANSITIONS:" << std::endl;
+// stream << " for (int i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {" << std::endl;
+// stream << " if unlikely(IS_SET(i, trans_set) && (scxml_transitions[i].type & SCXML_TRANS_HISTORY)) {" << std::endl;
+// stream << " // call executable content in transition" << std::endl;
+// stream << " if (scxml_transitions[i].on_transition != NULL) {" << std::endl;
+// stream << " if unlikely((err = scxml_transitions[i].on_transition(ctx," << std::endl;
+// stream << " &scxml_states[scxml_transitions[i].source]," << std::endl;
+// stream << " ctx->event)) != SCXML_ERR_OK)" << std::endl;
+// stream << " return err;" << std::endl;
+// stream << " }" << std::endl;
+// stream << " }" << std::endl;
+// stream << " }" << std::endl;
+// stream << std::endl;
+
+
+ stream << " return SCXML_ERR_OK;" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
+}
+
+NodeSet<std::string> ChartToC::inPostFixOrder(const std::set<std::string>& elements, const Element<std::string>& root) {
+ NodeSet<std::string> nodes;
+ inPostFixOrder(elements, root, nodes);
+ return nodes;
+}
+
+void ChartToC::inPostFixOrder(const std::set<std::string>& elements, const Element<std::string>& root, NodeSet<std::string>& nodes) {
+ NodeList<std::string> children = root.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ Arabica::DOM::Element<std::string> childElem(children.item(i));
+ inPostFixOrder(elements, childElem, nodes);
+
+ }
+ for (int i = 0; i < children.getLength(); i++) {
+ if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ Arabica::DOM::Element<std::string> childElem(children.item(i));
+
+ if (elements.find(TAGNAME(childElem)) != elements.end()) {
+ nodes.push_back(childElem);
+ }
+ }
+}
+
+NodeSet<std::string> ChartToC::inDocumentOrder(const std::set<std::string>& elements, const Element<std::string>& root) {
+ NodeSet<std::string> nodes;
+ inDocumentOrder(elements, root, nodes);
+ return nodes;
+}
+
+void ChartToC::inDocumentOrder(const std::set<std::string>& elements, const Element<std::string>& root, NodeSet<std::string>& nodes) {
+ if (elements.find(TAGNAME(root)) != elements.end()) {
+ nodes.push_back(root);
+ }
+
+ NodeList<std::string> children = root.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ Arabica::DOM::Element<std::string> childElem(children.item(i));
+ inDocumentOrder(elements, childElem, nodes);
+ }
+}
+
+ChartToC::~ChartToC() {
+}
+
+} \ No newline at end of file
diff --git a/src/uscxml/transform/ChartToC.cpp b/src/uscxml/transform/ChartToC.cpp
index 2d3f6ba..8fe6ac7 100644
--- a/src/uscxml/transform/ChartToC.cpp
+++ b/src/uscxml/transform/ChartToC.cpp
@@ -123,8 +123,8 @@ void ChartToC::writeMacros(std::ostream& stream) {
stream << std::endl;
stream << "#ifdef __GNUC__" << std::endl;
- stream << "#define likely(x) __builtin_expect(!!(x), 1)" << std::endl;
- stream << "#define unlikely(x) __builtin_expect(!!(x), 0)" << std::endl;
+ stream << "#define likely(x) (__builtin_expect(!!(x), 1))" << std::endl;
+ stream << "#define unlikely(x) (__builtin_expect(!!(x), 0))" << std::endl;
stream << "#else" << std::endl;
stream << "#define likely(x) (x)" << std::endl;
stream << "#define unlikely(x) (x)" << std::endl;
@@ -151,7 +151,8 @@ void ChartToC::writeMacros(std::ostream& stream) {
stream << "#define SCXML_TRANS_SPONTANEOUS 0x01" << std::endl;
stream << "#define SCXML_TRANS_TARGETLESS 0x02" << std::endl;
stream << "#define SCXML_TRANS_INTERNAL 0x04" << std::endl;
- stream << "#define SCXML_TRANS_HISTORY 0x08" << std::endl;
+ stream << "#define SCXML_TRANS_HISTORY 0x08" << std::endl;
+ stream << "#define SCXML_TRANS_INITIAL 0x10" << std::endl;
stream << std::endl;
stream << "#define SCXML_STATE_ATOMIC 0x01" << std::endl;
@@ -225,7 +226,7 @@ void ChartToC::writeTypes(std::ostream& stream) {
stream << "struct scxml_state {" << std::endl;
stream << " const char* name; // eventual name" << std::endl;
- stream << " uint16_t source; // parent" << std::endl;
+ stream << " uint16_t parent; // parent" << std::endl;
stream << " exec_content_t on_entry; // on entry handlers" << std::endl;
stream << " exec_content_t on_exit; // on exit handlers" << std::endl;
stream << " invoke_t invoke; // invocations" << std::endl;
@@ -315,7 +316,8 @@ void ChartToC::writeTypes(std::ostream& stream) {
stream << " char pending_invokes[" << _stateCharArraySize << "];" << std::endl;
stream << " char initialized_data[" << _stateCharArraySize << "];" << std::endl;
stream << std::endl;
- stream << " void* user_data;" << std::endl;
+ stream << " void* user_data;" << std::endl;
+ stream << " void* event;" << std::endl;
stream << std::endl;
stream << " dequeue_internal_cb_t dequeue_internal;" << std::endl;
stream << " dequeue_external_cb_t dequeue_external;" << std::endl;
@@ -421,26 +423,21 @@ void ChartToC::writeExecContent(std::ostream& stream) {
if (i == 0) {
// root state - we need to perform some initialization here
NodeSet<std::string> globalScripts = filterChildElements(_nsInfo.xmlNSPrefix + "script", state);
- if (globalScripts.size() > 0) {
- _hasGlobalScripts = true;
- for (int j = 0; j < globalScripts.size(); j++) {
- stream << "static int global_script_" << toStr(j) << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
- stream << " int err = SCXML_ERR_OK;" << std::endl;
- writeExecContent(stream, globalScripts[j], 1);
- stream << " return SCXML_ERR_OK;" << std::endl;
- stream << "}" << std::endl;
- }
-
- stream << "static int global_script(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
- for (int j = 0; j < globalScripts.size(); j++) {
- stream << " global_script_" << toStr(j) << "(ctx, state, event);" << std::endl;
- }
- stream << " return SCXML_ERR_OK;" << std::endl;
- stream << "}" << std::endl;
- stream << std::endl;
- } else {
- _hasGlobalScripts = false;
- }
+ for (int j = 0; j < globalScripts.size(); j++) {
+ stream << "static int global_script_" << toStr(j) << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
+ stream << " int err = SCXML_ERR_OK;" << std::endl;
+ writeExecContent(stream, globalScripts[j], 1);
+ stream << " return SCXML_ERR_OK;" << std::endl;
+ stream << "}" << std::endl;
+ }
+
+ stream << "static int global_script(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl;
+ for (int j = 0; j < globalScripts.size(); j++) {
+ stream << " global_script_" << toStr(j) << "(ctx, state, event);" << std::endl;
+ }
+ stream << " return SCXML_ERR_OK;" << std::endl;
+ stream << "}" << std::endl;
+ stream << std::endl;
}
NodeSet<std::string> onexit = filterChildElements(_nsInfo.xmlNSPrefix + "onexit", state);
@@ -860,44 +857,39 @@ void ChartToC::writeElementInfo(std::ostream& stream) {
}
NodeSet<std::string> donedatas = filterChildElements(_nsInfo.xmlNSPrefix + "donedata", _scxml, true);
- if (donedatas.size() > 0) {
- _hasDoneData = true;
- stream << "static scxml_elem_donedata scxml_elem_donedatas[" << donedatas.size() + 1 << "] = {" << std::endl;
- for (int i = 0; i < donedatas.size(); i++) {
- Element<std::string> donedata(donedatas[i]);
- stream << " { ";
-
- // parent
- stream << ATTR_CAST(donedata.getParentNode(), "documentOrder") << ", ";
-
- NodeSet<std::string> contents = filterChildElements(_nsInfo.xmlNSPrefix + "content", donedata);
- if (contents.size() > 0) {
- std::stringstream ss;
- NodeList<std::string> cChilds = contents[0].getChildNodes();
- for (int j = 0; j < cChilds.getLength(); j++) {
- ss << cChilds.item(j);
- }
- stream << (ss.str().size() > 0 ? "\"" + escape(ss.str()) + "\", " : "NULL, ");
- stream << (HAS_ATTR_CAST(contents[0], "expr") ? "\"" + ATTR_CAST(contents[0], "expr") + "\", " : "NULL, ");
- } else {
- stream << "NULL, NULL, ";
- }
-
- if (HAS_ATTR(donedata, "paramIndex")) {
- stream << "(const scxml_elem_param*)&scxml_elem_params[" << escape(ATTR(donedata, "paramIndex")) << "]";
- } else {
- stream << "NULL";
- }
-
- stream << " }," << std::endl;
- donedata.setAttribute("documentOrder", toStr(i));
- }
- stream << " { 0, NULL, NULL }" << std::endl;
- stream << "};" << std::endl;
- stream << std::endl;
- } else {
- _hasDoneData = false;
- }
+ stream << "static scxml_elem_donedata scxml_elem_donedatas[" << donedatas.size() + 1 << "] = {" << std::endl;
+ for (int i = 0; i < donedatas.size(); i++) {
+ Element<std::string> donedata(donedatas[i]);
+ stream << " { ";
+
+ // parent
+ stream << ATTR_CAST(donedata.getParentNode(), "documentOrder") << ", ";
+
+ NodeSet<std::string> contents = filterChildElements(_nsInfo.xmlNSPrefix + "content", donedata);
+ if (contents.size() > 0) {
+ std::stringstream ss;
+ NodeList<std::string> cChilds = contents[0].getChildNodes();
+ for (int j = 0; j < cChilds.getLength(); j++) {
+ ss << cChilds.item(j);
+ }
+ stream << (ss.str().size() > 0 ? "\"" + escape(ss.str()) + "\", " : "NULL, ");
+ stream << (HAS_ATTR_CAST(contents[0], "expr") ? "\"" + ATTR_CAST(contents[0], "expr") + "\", " : "NULL, ");
+ } else {
+ stream << "NULL, NULL, ";
+ }
+
+ if (HAS_ATTR(donedata, "paramIndex")) {
+ stream << "(const scxml_elem_param*)&scxml_elem_params[" << escape(ATTR(donedata, "paramIndex")) << "]";
+ } else {
+ stream << "NULL";
+ }
+
+ stream << " }," << std::endl;
+ donedata.setAttribute("documentOrder", toStr(i));
+ }
+ stream << " { 0, NULL, NULL }" << std::endl;
+ stream << "};" << std::endl;
+ stream << std::endl;
}
@@ -1125,6 +1117,11 @@ void ChartToC::writeTransitions(std::ostream& stream) {
seperator = " | ";
}
+ if (iequals(TAGNAME_CAST(transition.getParentNode()), "initial")) {
+ stream << seperator << "SCXML_TRANS_INITIAL";
+ seperator = " | ";
+ }
+
if (seperator.size() == 0) {
stream << "0";
}
@@ -1228,7 +1225,7 @@ void ChartToC::writeCharArrayInitList(std::ostream& stream, const std::string& b
}
void ChartToC::writeFSM(std::ostream& stream) {
- stream << "static int scxml_step(scxml_ctx* ctx) {" << std::endl;
+ stream << "int scxml_step(scxml_ctx* ctx) {" << std::endl;
stream << std::endl;
stream << "#ifdef SCXML_VERBOSE" << std::endl;
@@ -1237,7 +1234,7 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << "#endif" << std::endl;
stream << std::endl;
- stream << "// MACRO_STEP:" << std::endl;
+ stream << "MACRO_STEP:" << std::endl;
stream << " ctx->flags &= ~SCXML_CTX_TRANSITION_FOUND;" << std::endl;
stream << std::endl;
@@ -1253,36 +1250,30 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " char entry_set[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl;
stream << std::endl;
- stream << " void* event;" << std::endl;
stream << " if unlikely(ctx->flags == SCXML_CTX_PRISTINE) {" << std::endl;
- if (_hasGlobalScripts) {
- stream << " global_script(ctx, &scxml_states[0], NULL);" << std::endl;
- }
+ stream << " global_script(ctx, &scxml_states[0], NULL);" << std::endl;
stream << " bit_or(target_set, scxml_states[0].completion, " << _stateCharArraySize << ");" << std::endl;
stream << " ctx->flags |= SCXML_CTX_SPONTANEOUS | SCXML_CTX_INITIALIZED;" << std::endl;
- stream << " goto COMPLETE_CONFIG;" << std::endl;
+ stream << " goto ESTABLISH_ENTRY_SET;" << std::endl;
stream << " }" << std::endl;
stream << std::endl;
stream << " if (ctx->flags & SCXML_CTX_SPONTANEOUS) {" << std::endl;
- stream << " event = NULL;" << std::endl;
+ stream << " ctx->event = NULL;" << std::endl;
stream << " goto SELECT_TRANSITIONS;" << std::endl;
stream << " }" << std::endl;
- stream << " if ((event = ctx->dequeue_internal(ctx)) != NULL) {" << std::endl;
+ stream << " if ((ctx->event = ctx->dequeue_internal(ctx)) != NULL) {" << std::endl;
stream << " goto SELECT_TRANSITIONS;" << std::endl;
stream << " }" << std::endl;
- stream << " if ((event = ctx->dequeue_external(ctx)) != NULL) {" << std::endl;
-
+ stream << " if ((ctx->event = ctx->dequeue_external(ctx)) != NULL) {" << std::endl;
stream << " goto SELECT_TRANSITIONS;" << std::endl;
stream << " }" << std::endl;
stream << std::endl;
-// HISTORY TRANSITION IS SELECTED BY ACCIDENT!
-
stream << "SELECT_TRANSITIONS:" << std::endl;
stream << " for (int i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {" << std::endl;
stream << " // never select history or initial transitions automatically" << std::endl;
- stream << " if unlikely(scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_HISTORY))" << std::endl;
+ stream << " if unlikely(scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL))" << std::endl;
stream << " continue;" << std::endl;
stream << std::endl;
stream << " // is the transition active?" << std::endl;
@@ -1290,7 +1281,7 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " // is it non-conflicting?" << std::endl;
stream << " if (!IS_SET(i, conflicts)) {" << std::endl;
stream << " // is it enabled?" << std::endl;
- stream << " if (ctx->is_enabled(ctx, &scxml_transitions[i], event) > 0) {" << std::endl;
+ stream << " if (ctx->is_enabled(ctx, &scxml_transitions[i], ctx->event) > 0) {" << std::endl;
stream << " // remember that we found a transition" << std::endl;
stream << " ctx->flags |= SCXML_CTX_TRANSITION_FOUND;" << std::endl;
stream << std::endl;
@@ -1316,8 +1307,7 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " ctx->flags |= SCXML_CTX_SPONTANEOUS;" << std::endl;
stream << " } else {" << std::endl;
stream << " ctx->flags &= ~SCXML_CTX_SPONTANEOUS;" << std::endl;
- stream << " // goto MACRO_STEP;" << std::endl;
- stream << " return SCXML_ERR_OK;" << std::endl;
+// stream << " return SCXML_ERR_OK;" << std::endl;
stream << " }" << std::endl;
stream << std::endl;
@@ -1327,26 +1317,6 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << "#endif" << std::endl;
stream << std::endl;
- stream << "// REMEMBER_HISTORY:" << std::endl;
- stream << " for (int i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl;
- stream << " if unlikely(scxml_states[i].type == SCXML_STATE_HISTORY_SHALLOW || scxml_states[i].type == SCXML_STATE_HISTORY_DEEP) {" << std::endl;
- stream << " // a history state whose parent is about to be exited" << std::endl;
- stream << " if unlikely(IS_SET(scxml_states[i].source, exit_set)) {" << std::endl;
- stream << " char history[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl;
- stream << " bit_copy(history, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl;
- stream << std::endl;
- stream << " // set those states who were enabled" << std::endl;
- stream << " bit_and(history, ctx->config, " << _stateCharArraySize << ");" << std::endl;
- stream << std::endl;
- stream << " // clear current history with completion mask" << std::endl;
- stream << " bit_and_not(ctx->history, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl;
- stream << std::endl;
- stream << " // set history" << std::endl;
- stream << " bit_or(ctx->history, history, " << _stateCharArraySize << ");" << std::endl;
- stream << " }" << std::endl;
- stream << " }" << std::endl;
- stream << " }" << std::endl;
-
stream << "#ifdef SCXML_VERBOSE" << std::endl;
stream << " printf(\"Exiting: \");" << std::endl;
stream << " printStateNames(exit_set);" << std::endl;
@@ -1358,21 +1328,29 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " printStateNames(ctx->history);" << std::endl;
stream << "#endif" << std::endl;
stream << std::endl;
-
- stream << "// EXIT_STATES:" << std::endl;
- stream << " for (int i = SCXML_NUMBER_STATES - 1; i >= 0; i--) {" << std::endl;
- stream << " if (IS_SET(i, exit_set) && IS_SET(i, ctx->config)) {" << std::endl;
- stream << " // call all on exit handlers" << std::endl;
- stream << " if (scxml_states[i].on_exit != NULL) {" << std::endl;
- stream << " if unlikely((err = scxml_states[i].on_exit(ctx, &scxml_states[i], event)) != SCXML_ERR_OK)" << std::endl;
- stream << " return err;" << std::endl;
- stream << " }" << std::endl;
- stream << " CLEARBIT(i, ctx->config);" << std::endl;
- stream << " }" << std::endl;
- stream << " }" << std::endl;
- stream << std::endl;
-
- stream << "COMPLETE_CONFIG:" << std::endl;
+
+ stream << "// REMEMBER_HISTORY:" << std::endl;
+ stream << " for (int i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl;
+ stream << " if unlikely(scxml_states[i].type == SCXML_STATE_HISTORY_SHALLOW || scxml_states[i].type == SCXML_STATE_HISTORY_DEEP) {" << std::endl;
+ stream << " // a history state whose parent is about to be exited" << std::endl;
+ stream << " if unlikely(IS_SET(scxml_states[i].parent, exit_set)) {" << std::endl;
+ stream << " char history[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl;
+ stream << " bit_copy(history, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl;
+ stream << std::endl;
+ stream << " // set those states who were enabled" << std::endl;
+ stream << " bit_and(history, ctx->config, " << _stateCharArraySize << ");" << std::endl;
+ stream << std::endl;
+ stream << " // clear current history with completion mask - TODO: errornously clears nested history" << std::endl;
+ stream << " bit_and_not(ctx->history, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl;
+ stream << std::endl;
+ stream << " // set history" << std::endl;
+ stream << " bit_or(ctx->history, history, " << _stateCharArraySize << ");" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << std::endl;
+
+ stream << "ESTABLISH_ENTRY_SET:" << std::endl;
stream << " // calculate new entry set" << std::endl;
stream << " bit_copy(entry_set, target_set, " << _stateCharArraySize << ");" << std::endl;
stream << std::endl;
@@ -1384,7 +1362,6 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " }" << std::endl;
stream << std::endl;
- stream << "// ADD_DESCENDANTS:" << std::endl;
stream << " // iterate for descendants" << std::endl;
stream << " for (int i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl;
stream << " if (IS_SET(i, entry_set)) {" << std::endl;
@@ -1396,7 +1373,8 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " case SCXML_STATE_HISTORY_SHALLOW:" << std::endl;
stream << " case SCXML_STATE_HISTORY_DEEP: {" << std::endl;
stream << " char history_targets[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl;
- stream << " if (!bit_has_and(scxml_states[i].completion, ctx->history, " << _stateCharArraySize << ")) {" << std::endl;
+ stream << " if (!bit_has_and(scxml_states[i].completion, ctx->history, " << _stateCharArraySize << ") &&" << std::endl;
+ stream << " !IS_SET(scxml_states[i].parent, ctx->config)) {" << std::endl;
stream << " // nothing set for history, look for a default transition or enter parents completion" << std::endl;
stream << " for (int j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {" << std::endl;
stream << " if unlikely(scxml_transitions[j].source == i) {" << std::endl;
@@ -1426,8 +1404,9 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " break;" << std::endl;
stream << " }" << std::endl;
stream << " case SCXML_STATE_COMPOUND: { // we need to check whether one child is already in entry_set" << std::endl;
- stream << " if (!bit_has_and(entry_set, scxml_states[i].children, " << _stateCharArraySize << ") &&" << std::endl;
- stream << " !bit_has_and(ctx->config, scxml_states[i].children, " << _stateCharArraySize << "))" << std::endl;
+ stream << " if (!bit_has_and(entry_set, scxml_states[i].children, " << _stateCharArraySize << ") &&" << std::endl;
+ stream << " (!bit_has_and(ctx->config, scxml_states[i].children, " << _stateCharArraySize << ") ||" << std::endl;
+ stream << " bit_has_and(exit_set, scxml_states[i].children, " << _stateCharArraySize << ")))" << std::endl;
stream << " {" << std::endl;
stream << " bit_or(entry_set, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl;
stream << " }" << std::endl;
@@ -1444,6 +1423,19 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << "#endif" << std::endl;
stream << std::endl;
+ stream << "// EXIT_STATES:" << std::endl;
+ stream << " for (int i = SCXML_NUMBER_STATES - 1; i >= 0; i--) {" << std::endl;
+ stream << " if (IS_SET(i, exit_set) && IS_SET(i, ctx->config)) {" << std::endl;
+ stream << " // call all on exit handlers" << std::endl;
+ stream << " if (scxml_states[i].on_exit != NULL) {" << std::endl;
+ stream << " if unlikely((err = scxml_states[i].on_exit(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK)" << std::endl;
+ stream << " return err;" << std::endl;
+ stream << " }" << std::endl;
+ stream << " CLEARBIT(i, ctx->config);" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << std::endl;
+
stream << "// TAKE_TRANSITIONS:" << std::endl;
stream << " for (int i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {" << std::endl;
stream << " if (IS_SET(i, trans_set) && (scxml_transitions[i].type & SCXML_TRANS_HISTORY) == 0) {" << std::endl;
@@ -1451,7 +1443,7 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " if (scxml_transitions[i].on_transition != NULL) {" << std::endl;
stream << " if unlikely((err = scxml_transitions[i].on_transition(ctx," << std::endl;
stream << " &scxml_states[scxml_transitions[i].source]," << std::endl;
- stream << " event)) != SCXML_ERR_OK)" << std::endl;
+ stream << " ctx->event)) != SCXML_ERR_OK)" << std::endl;
stream << " return err;" << std::endl;
stream << " }" << std::endl;
stream << " }" << std::endl;
@@ -1487,37 +1479,40 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << std::endl;
stream << " if (scxml_states[i].on_entry != NULL) {" << std::endl;
- stream << " if unlikely((err = scxml_states[i].on_entry(ctx, &scxml_states[i], event)) != SCXML_ERR_OK)" << std::endl;
+ stream << " if unlikely((err = scxml_states[i].on_entry(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK)" << std::endl;
stream << " return err;" << std::endl;
stream << " }" << std::endl;
stream << std::endl;
+ stream << " // take history transitions" << std::endl;
+ stream << " for (int j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {" << std::endl;
+ stream << " if unlikely(IS_SET(j, trans_set) &&" << std::endl;
+ stream << " (scxml_transitions[j].type & SCXML_TRANS_HISTORY) &&" << std::endl;
+ stream << " scxml_states[scxml_transitions[j].source].parent == i) {" << std::endl;
+ stream << " // call executable content in transition" << std::endl;
+ stream << " if (scxml_transitions[j].on_transition != NULL) {" << std::endl;
+ stream << " if unlikely((err = scxml_transitions[j].on_transition(ctx," << std::endl;
+ stream << " &scxml_states[i]," << std::endl;
+ stream << " ctx->event)) != SCXML_ERR_OK)" << std::endl;
+ stream << " return err;" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << " }" << std::endl;
+ stream << std::endl;
+
stream << " // handle final states" << std::endl;
stream << " if unlikely(scxml_states[i].type == SCXML_STATE_FINAL) {" << std::endl;
stream << " if unlikely(scxml_states[i].ancestors[0] == 0x01) {" << std::endl;
stream << " ctx->flags |= SCXML_CTX_TOP_LEVEL_FINAL;" << std::endl;
stream << " } else {" << std::endl;
stream << " // raise done event" << std::endl;
- stream << " size_t parent = 0;" << std::endl;
- stream << " for (int j = SCXML_NUMBER_STATES - 1; j >= 0; j--) {" << std::endl;
- stream << " // we could trade runtime for memory here by saving the parent index" << std::endl;
- stream << " if unlikely(IS_SET(j, scxml_states[i].ancestors)) {" << std::endl;
- stream << " parent = j;" << std::endl;
- stream << " break;" << std::endl;
- stream << " }" << std::endl;
- stream << " }" << std::endl;
- stream << " // is this raised for toplevel final as well?" << std::endl;
- if (_hasDoneData) {
- stream << " scxml_elem_donedata* donedata = &scxml_elem_donedatas[0];" << std::endl;
- stream << " while(ELEM_DONEDATA_IS_SET(donedata)) {" << std::endl;
- stream << " if unlikely(donedata->source == i)" << std::endl;
- stream << " break;" << std::endl;
- stream << " donedata++;" << std::endl;
- stream << " }" << std::endl;
- stream << " ctx->raise_done_event(ctx, &scxml_states[parent], (ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL));" << std::endl;
- } else {
- stream << " ctx->raise_done_event(ctx, &scxml_states[parent], NULL);" << std::endl;
- }
+ stream << " scxml_elem_donedata* donedata = &scxml_elem_donedatas[0];" << std::endl;
+ stream << " while(ELEM_DONEDATA_IS_SET(donedata)) {" << std::endl;
+ stream << " if unlikely(donedata->source == i)" << std::endl;
+ stream << " break;" << std::endl;
+ stream << " donedata++;" << std::endl;
+ stream << " }" << std::endl;
+ stream << " ctx->raise_done_event(ctx, &scxml_states[scxml_states[i].parent], (ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL));" << std::endl;
stream << " }" << std::endl;
stream << std::endl;
@@ -1555,19 +1550,19 @@ void ChartToC::writeFSM(std::ostream& stream) {
stream << " }" << std::endl;
stream << std::endl;
- stream << "// HISTORY_TRANSITIONS:" << std::endl;
- stream << " for (int i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {" << std::endl;
- stream << " if unlikely(IS_SET(i, trans_set) && (scxml_transitions[i].type & SCXML_TRANS_HISTORY)) {" << std::endl;
- stream << " // call executable content in transition" << std::endl;
- stream << " if (scxml_transitions[i].on_transition != NULL) {" << std::endl;
- stream << " if unlikely((err = scxml_transitions[i].on_transition(ctx," << std::endl;
- stream << " &scxml_states[scxml_transitions[i].source]," << std::endl;
- stream << " event)) != SCXML_ERR_OK)" << std::endl;
- stream << " return err;" << std::endl;
- stream << " }" << std::endl;
- stream << " }" << std::endl;
- stream << " }" << std::endl;
- stream << std::endl;
+// stream << "// HISTORY_TRANSITIONS:" << std::endl;
+// stream << " for (int i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {" << std::endl;
+// stream << " if unlikely(IS_SET(i, trans_set) && (scxml_transitions[i].type & SCXML_TRANS_HISTORY)) {" << std::endl;
+// stream << " // call executable content in transition" << std::endl;
+// stream << " if (scxml_transitions[i].on_transition != NULL) {" << std::endl;
+// stream << " if unlikely((err = scxml_transitions[i].on_transition(ctx," << std::endl;
+// stream << " &scxml_states[scxml_transitions[i].source]," << std::endl;
+// stream << " ctx->event)) != SCXML_ERR_OK)" << std::endl;
+// stream << " return err;" << std::endl;
+// stream << " }" << std::endl;
+// stream << " }" << std::endl;
+// stream << " }" << std::endl;
+// stream << std::endl;
stream << " return SCXML_ERR_OK;" << std::endl;
diff --git a/src/uscxml/transform/ChartToC.h b/src/uscxml/transform/ChartToC.h
index 6e6bac0..e600241 100644
--- a/src/uscxml/transform/ChartToC.h
+++ b/src/uscxml/transform/ChartToC.h
@@ -78,7 +78,6 @@ protected:
Arabica::XPath::NodeSet<std::string> _transitions;
bool _hasGlobalScripts;
- bool _hasDoneData;
size_t _transCharArraySize;
std::string _transCharArrayInit;
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 5af6a4a..cf7c182 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,4 +1,5 @@
-set(TEST_TIMEOUT 10)
+set(TEST_TIMEOUT 15)
+set(TEST_BENCHMARK_ITERATIONS 1000)
function(USCXML_TEST_COMPILE)
set(options BUILD_ONLY)
@@ -77,6 +78,8 @@ add_test(test-execution ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/uscxml-browser ${CMAKE
add_test(test-communication ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/uscxml-browser -t5493 ${CMAKE_SOURCE_DIR}/test/uscxml/test-communication.scxml)
add_test(test-done-data ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/uscxml-browser ${CMAKE_SOURCE_DIR}/test/uscxml/test-donedata.scxml)
+# declare W#C tests
+
find_program(SPIN spin)
find_program(GCC gcc)
find_program(GPP g++)
@@ -94,177 +97,295 @@ if (NOT BUILD_MINIMAL)
w3c/*sub*.scxml
)
+ set(TEST_CLASSES
+ # standard tests generated per datamodel
+ "ecma"
+ "xpath"
+ "null"
+ "lua"
+ "promela"
+
+ # generated c source
+ "gen/c/ecma"
+ "gen/c/xpath"
+ "gen/c/lua"
+ "gen/c/promela"
+
+ # state-machine interpreters
+ "fsm/ecma"
+ "fsm/xpath"
+ "fsm/lua"
+ "fsm/promela"
+
+ # minimized interpreters
+ "min/ecma"
+ "min/xpath"
+ "min/lua"
+ "min/promela"
+
+ # performance tests
+ "perf/gen/c/ecma"
+ "perf/ecma")
+
+ # prepare directories for test classes and copy resources over
foreach(W3C_RESOURCE ${W3C_RESOURCES} )
- # we abuse this as head and tail
- get_filename_component(W3C_RESOURCE_PATH ${W3C_RESOURCE} PATH)
- get_filename_component(W3C_TEST_TYPE ${W3C_RESOURCE_PATH} NAME)
-
- if (BUILD_TESTS_W3C_ECMA AND W3C_TEST_TYPE STREQUAL "ecma")
- file(COPY ${W3C_RESOURCE} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/ecma)
- elseif (BUILD_TESTS_W3C_XPATH AND W3C_TEST_TYPE STREQUAL "xpath")
- file(COPY ${W3C_RESOURCE} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/xpath)
- elseif (BUILD_TESTS_W3C_LUA AND W3C_TEST_TYPE STREQUAL "lua")
- file(COPY ${W3C_RESOURCE} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/lua)
- elseif (BUILD_TESTS_W3C_PROMELA AND W3C_TEST_TYPE STREQUAL "promela")
- file(COPY ${W3C_RESOURCE} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/lua)
- endif()
+ get_filename_component(TEST_DATAMODEL ${W3C_RESOURCE} NAME)
+ foreach(TEST_CLASS ${TEST_CLASSES})
+ # datamodel has to be the suffix of the test class
+ if (TEST_CLASS MATCHES ".*/${TEST_DATAMODEL}$")
+ file(COPY ${W3C_RESOURCE} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/${TEST_CLASS})
+ endif()
+ endforeach()
endforeach()
- # prepare tests
- file(GLOB_RECURSE W3C_TESTS
- w3c/*.scxml
- )
-
- foreach( W3C_TEST ${W3C_TESTS} )
- string(REGEX MATCH "[^//]+/[^//]+.scxml" TEST_NAME ${W3C_TEST})
- # message("TEST_NAME: ${TEST_NAME}")
- if (NOT TEST_NAME MATCHES ".*sub.*")
- if (TEST_NAME MATCHES "^null\\/.*")
- add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST})
- set_property(TEST ${TEST_NAME} PROPERTY LABELS ${TEST_NAME})
- set_tests_properties(${TEST_NAME} PROPERTIES TIMEOUT ${TEST_TIMEOUT})
- endif()
+ # establish actual tests
+ foreach(TEST_CLASS ${TEST_CLASSES})
+ get_filename_component(TEST_DATAMODEL ${TEST_CLASS} NAME)
+ get_filename_component(TEST_TYPE ${TEST_CLASS} PATH)
- if (BUILD_TESTS_W3C_ECMA AND TEST_NAME MATCHES "^ecma\\/.*")
- add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST})
- set_property(TEST ${TEST_NAME} PROPERTY LABELS ${TEST_NAME})
- set_tests_properties(${TEST_NAME} PROPERTIES TIMEOUT ${TEST_TIMEOUT})
+ # get all respective scxml files into W3C_TESTS
+ file(GLOB_RECURSE W3C_TESTS w3c/${TEST_DATAMODEL}/*.scxml)
- # set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "TEST FAILED")
-
- if (TEST_NAME STREQUAL "ecma/test250.scxml")
- set_tests_properties(${TEST_NAME} PROPERTIES
- FAIL_REGULAR_EXPRESSION "entering final state, invocation was not cancelled")
- elseif (TEST_NAME STREQUAL "ecma/test307.scxml")
- set_tests_properties(${TEST_NAME} PROPERTIES
- FAIL_REGULAR_EXPRESSION "error in state")
- endif()
- endif()
+ SET(IS_PERFORMANCE_TEST OFF)
+ if (TEST_CLASS MATCHES "^perf/.*")
+ SET(IS_PERFORMANCE_TEST ON)
+ endif()
- if (BUILD_TESTS_GENERATED_C AND TEST_NAME MATCHES "^ecma\\/.*")
- add_test(NAME "gen_c/${TEST_NAME}"
- COMMAND ${CMAKE_COMMAND}
- -DOUTDIR:FILEPATH=${CMAKE_CURRENT_BINARY_DIR}/gen_c
- -DTESTFILE:FILEPATH=${W3C_TEST}
- -DJSC_LIBRARY:FILEPATH=${JSC_LIBRARY}
- -DUSCXML_TRANSFORM_BIN:FILEPATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/uscxml-transform
- -DGCC_BIN:FILEPATH=${GCC}
- -DGPP_BIN:FILEPATH=${GPP}
- -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}
- -DUSCXML_PLATFORM_ID=${USCXML_PLATFORM_ID}
- -DCMAKE_BINARY_DIR=${CMAKE_BINARY_DIR}
- -DPROJECT_BINARY_DIR=${PROJECT_BINARY_DIR}
- -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
- -DSCAFFOLDING_FOR_GENERATED_C:FILEPATH=${CMAKE_CURRENT_SOURCE_DIR}/src/test-c-machine.cpp
- -P ${CMAKE_CURRENT_SOURCE_DIR}/w3c/run_generated_c_test.cmake)
- set_property(TEST "gen_c/${TEST_NAME}" PROPERTY LABELS "gen_c/${TEST_NAME}")
- set_tests_properties("gen_c/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
- set_tests_properties("gen_c/${TEST_NAME}" PROPERTIES DEPENDS uscxml-transform)
-
- endif()
-
- if (BUILD_TESTS_FSM AND BUILD_TESTS_FSM_ECMA AND TEST_NAME MATCHES "^ecma\\/.*")
- add_test("fsm/${TEST_NAME}" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c -f ${W3C_TEST})
- set_property(TEST "fsm/${TEST_NAME}" PROPERTY LABELS "fsm/${TEST_NAME}")
- set_tests_properties("fsm/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
-
- add_test(NAME "minimized/${TEST_NAME}"
- COMMAND ${CMAKE_COMMAND}
- -DOUTDIR:FILEPATH=${CMAKE_CURRENT_BINARY_DIR}/ecma
- -DTESTFILE:FILEPATH=${W3C_TEST}
- -DUSCXML_TRANSFORM_BIN:FILEPATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/uscxml-transform
- -DUSCXML_W3C_TEST_BIN:FILEPATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c
- -P ${CMAKE_CURRENT_SOURCE_DIR}/w3c/run_minimized_test.cmake)
- set_property(TEST "minimized/${TEST_NAME}" PROPERTY LABELS "minimized/${TEST_NAME}")
- set_tests_properties("minimized/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
-
- set_tests_properties(${TEST_NAME} PROPERTIES DEPENDS uscxml-transform)
- set_tests_properties(${TEST_NAME} PROPERTIES DEPENDS test-w3c)
-
- # add_test(NAME "fsm/minimized/${TEST_NAME}"
- # COMMAND ${CMAKE_COMMAND}
- # -DOUTDIR:FILEPATH=${CMAKE_CURRENT_BINARY_DIR}/ecma
- # -DTESTFILE:FILEPATH=${W3C_TEST}
- # -DUSCXML_TRANSFORM_BIN:FILEPATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/uscxml-transform
- # -DUSCXML_W3C_TEST_BIN:FILEPATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c
- # -P ${CMAKE_CURRENT_SOURCE_DIR}/w3c/run_minimized_flat_test.cmake)
- # set_property(TEST "fsm/minimized/${TEST_NAME}" PROPERTY LABELS "fsm/minimized/${TEST_NAME}")
- # set_tests_properties("fsm/minimized/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
-
- # set_tests_properties(${TEST_NAME} PROPERTIES DEPENDS uscxml-transform)
- # set_tests_properties(${TEST_NAME} PROPERTIES DEPENDS test-w3c)
-
- endif()
+ if (IS_PERFORMANCE_TEST)
+ string(REGEX REPLACE "^perf/?" "" TEST_TYPE ${TEST_TYPE})
+ endif()
- if (BUILD_TESTS_W3C_XPATH AND TEST_NAME MATCHES "^xpath\\/.*")
- add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST})
- set_property(TEST ${TEST_NAME} PROPERTY LABELS ${TEST_NAME})
- set_tests_properties(${TEST_NAME} PROPERTIES TIMEOUT ${TEST_TIMEOUT})
- # set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "TEST FAILED")
- if (BUILD_TESTS_FSM AND BUILD_TESTS_FSM_XPATH)
- add_test("fsm/${TEST_NAME}" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c -f ${W3C_TEST})
- set_property(TEST "fsm/${TEST_NAME}" PROPERTY LABELS "fsm/${TEST_NAME}")
- set_tests_properties("fsm/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
- endif()
+ SET(IS_STANDARD_TEST OFF)
+ if ("${TEST_TYPE}" STREQUAL "")
+ if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/w3c/${TEST_DATAMODEL}")
+ SET(IS_STANDARD_TEST ON)
endif()
+ endif()
- if (BUILD_DM_LUA AND LUA_FOUND AND BUILD_TESTS_W3C_LUA AND TEST_NAME MATCHES "^lua\\/.*")
- add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST})
- set_property(TEST ${TEST_NAME} PROPERTY LABELS ${TEST_NAME})
- set_tests_properties(${TEST_NAME} PROPERTIES TIMEOUT ${TEST_TIMEOUT})
- # set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "TEST FAILED")
- if (BUILD_TESTS_FSM AND BUILD_TESTS_FSM_LUA)
- add_test("fsm/${TEST_NAME}" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c -f ${W3C_TEST})
- set_property(TEST "fsm/${TEST_NAME}" PROPERTY LABELS "fsm/${TEST_NAME}")
- set_tests_properties("fsm/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
- endif()
-
- endif()
+ # normal IRP tests - get all scxml files within
+ foreach(W3C_TEST ${W3C_TESTS} )
+ get_filename_component(TEST_FILE ${W3C_TEST} NAME)
+ set(TEST_NAME "${TEST_CLASS}/${TEST_FILE}")
- if (BUILD_DM_PROLOG AND SWI_FOUND AND BUILD_TESTS_W3C_PROLOG AND TEST_NAME MATCHES "^prolog\\/.*")
- add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST})
- set_property(TEST ${TEST_NAME} PROPERTY LABELS ${TEST_NAME})
- set_tests_properties(${TEST_NAME} PROPERTIES TIMEOUT ${TEST_TIMEOUT})
- # set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "TEST FAILED")
- if (BUILD_TESTS_FSM AND BUILD_TESTS_FSM_PROLOG)
- add_test("fsm/${TEST_NAME}" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c -f ${W3C_TEST})
- set_property(TEST "fsm/${TEST_NAME}" PROPERTY LABELS "fsm/${TEST_NAME}")
- set_tests_properties("fsm/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
- endif()
- endif()
+ if (NOT TEST_NAME MATCHES ".*sub.*")
+ if (IS_STANDARD_TEST)
+
+ add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST})
+
+ if (TEST_NAME MATCHES ".*/test250.scxml")
+ set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "entering final state, invocation was not cancelled")
+ elseif (TEST_NAME MATCHES ".*/test307.scxml")
+ set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "error in state")
+ endif()
+
+ # more properties for standard tests
- if (BUILD_DM_PROMELA AND BUILD_TESTS_W3C_PROMELA AND TEST_NAME MATCHES "^promela\\/.*")
- add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST})
+ else()
+
+ if (TEST_TYPE MATCHES "^gen.*")
+ get_filename_component(TEST_TARGET ${TEST_TYPE} NAME)
+ if (TEST_TYPE MATCHES "^gen/${TEST_TARGET}")
+
+ # generate native interpreters
+ add_test(NAME "${TEST_NAME}"
+ COMMAND ${CMAKE_COMMAND}
+ -DOUTDIR:FILEPATH=${CMAKE_CURRENT_BINARY_DIR}/${TEST_CLASS}
+ -DTESTFILE:FILEPATH=${W3C_TEST}
+ -DTARGETLANG=${TEST_TARGET}
+ -DJSC_LIBRARY:FILEPATH=${JSC_LIBRARY}
+ -DUSCXML_TRANSFORM_BIN:FILEPATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/uscxml-transform
+ -DGCC_BIN:FILEPATH=${GCC}
+ -DGPP_BIN:FILEPATH=${GPP}
+ -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}
+ -DUSCXML_PLATFORM_ID=${USCXML_PLATFORM_ID}
+ -DCMAKE_BINARY_DIR=${CMAKE_BINARY_DIR}
+ -DPROJECT_BINARY_DIR=${PROJECT_BINARY_DIR}
+ -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
+ -DSCAFFOLDING_FOR_GENERATED_C:FILEPATH=${CMAKE_CURRENT_SOURCE_DIR}/src/test-c-machine.cpp
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/w3c/run_generated_test.cmake)
+ set_tests_properties("${TEST_NAME}" PROPERTIES DEPENDS uscxml-transform)
+
+ endif()
+
+ elseif (TEST_TYPE MATCHES "^min.*")
+
+ add_test(NAME "${TEST_NAME}"
+ COMMAND ${CMAKE_COMMAND}
+ -DOUTDIR:FILEPATH=${CMAKE_CURRENT_BINARY_DIR}/ecma
+ -DTESTFILE:FILEPATH=${W3C_TEST}
+ -DUSCXML_TRANSFORM_BIN:FILEPATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/uscxml-transform
+ -DUSCXML_W3C_TEST_BIN:FILEPATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/w3c/run_minimized_test.cmake)
+
+
+ elseif (TEST_TYPE MATCHES "^fsm.*")
+
+ add_test("${TEST_NAME}" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c -f ${W3C_TEST})
+
+ endif()
+ endif()
+
set_property(TEST ${TEST_NAME} PROPERTY LABELS ${TEST_NAME})
set_tests_properties(${TEST_NAME} PROPERTIES TIMEOUT ${TEST_TIMEOUT})
- # set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "TEST FAILED")
- if (BUILD_TESTS_FSM AND BUILD_TESTS_FSM_PROMELA)
- add_test("fsm/${TEST_NAME}" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c -f ${W3C_TEST})
- set_property(TEST "fsm/${TEST_NAME}" PROPERTY LABELS "fsm/${TEST_NAME}")
- set_tests_properties("fsm/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
+ if (IS_PERFORMANCE_TEST)
+ set_tests_properties("${TEST_NAME}" PROPERTIES ENVIRONMENT USCXML_BENCHMARK_ITERATIONS=${TEST_BENCHMARK_ITERATIONS})
endif()
+
endif()
-
- if (GCC AND SPIN AND BUILD_DM_PROMELA AND BUILD_TESTS_W3C_PROMELA AND TEST_NAME MATCHES "^promela\\/.*")
-
- add_test(NAME "spin/${TEST_NAME}"
- COMMAND ${CMAKE_COMMAND}
- -DOUTDIR:FILEPATH=${CMAKE_CURRENT_BINARY_DIR}/promela
- -DTESTFILE:FILEPATH=${W3C_TEST}
- -DUSCXML_TRANSFORM_BIN:FILEPATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/uscxml-transform
- -DSPIN_BIN:FILEPATH=${SPIN}
- -DGCC_BIN:FILEPATH=${GCC}
- -P ${CMAKE_CURRENT_SOURCE_DIR}/w3c/run_promela_test.cmake)
- set_property(TEST "spin/${TEST_NAME}" PROPERTY LABELS "spin/${TEST_NAME}")
- set_tests_properties("spin/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
- set_tests_properties("spin/${TEST_NAME}" PROPERTIES PASS_REGULAR_EXPRESSION "depth reached [0-9]+, errors: 0")
- set_tests_properties("spin/${TEST_NAME}" PROPERTIES FAIL_REGULAR_EXPRESSION "depth reached [0-9]+, errors: [1-9]+")
-
- set_tests_properties(${TEST_NAME} PROPERTIES DEPENDS uscxml-transform)
- # set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "TEST FAILED")
- endif()
-
- endif()
+ endforeach()
endforeach()
+
+ # # iterate all SCXML files in test directory
+ # foreach( W3C_TEST ${W3C_TESTS} )
+ # string(REGEX MATCH "[^//]+/[^//]+.scxml" TEST_NAME ${W3C_TEST})
+ # message("TEST_NAME: ${TEST_NAME}")
+ # if (NOT TEST_NAME MATCHES ".*sub.*")
+ #
+ # # add new test
+ # add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST})
+ # set_property(TEST ${TEST_NAME} PROPERTY LABELS ${TEST_NAME})
+ # set_tests_properties(${TEST_NAME} PROPERTIES TIMEOUT ${TEST_TIMEOUT})
+ #
+ # if (BUILD_TESTS_W3C_ECMA AND TEST_NAME MATCHES "^ecma\\/.*")
+ # add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST})
+ # set_property(TEST ${TEST_NAME} PROPERTY LABELS ${TEST_NAME})
+ # set_tests_properties(${TEST_NAME} PROPERTIES TIMEOUT ${TEST_TIMEOUT})
+ #
+ # # set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "TEST FAILED")
+ #
+ # if (TEST_NAME STREQUAL "ecma/test250.scxml")
+ # set_tests_properties(${TEST_NAME} PROPERTIES
+ # FAIL_REGULAR_EXPRESSION "entering final state, invocation was not cancelled")
+ # elseif (TEST_NAME STREQUAL "ecma/test307.scxml")
+ # set_tests_properties(${TEST_NAME} PROPERTIES
+ # FAIL_REGULAR_EXPRESSION "error in state")
+ # endif()
+ # endif()
+ #
+ # if (BUILD_TESTS_GENERATED_C AND TEST_NAME MATCHES "^ecma\\/.*")
+ # add_test(NAME "gen_c/${TEST_NAME}"
+ # COMMAND ${CMAKE_COMMAND}
+ # -DOUTDIR:FILEPATH=${CMAKE_CURRENT_BINARY_DIR}/gen_c
+ # -DTESTFILE:FILEPATH=${W3C_TEST}
+ # -DJSC_LIBRARY:FILEPATH=${JSC_LIBRARY}
+ # -DUSCXML_TRANSFORM_BIN:FILEPATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/uscxml-transform
+ # -DGCC_BIN:FILEPATH=${GCC}
+ # -DGPP_BIN:FILEPATH=${GPP}
+ # -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}
+ # -DUSCXML_PLATFORM_ID=${USCXML_PLATFORM_ID}
+ # -DCMAKE_BINARY_DIR=${CMAKE_BINARY_DIR}
+ # -DPROJECT_BINARY_DIR=${PROJECT_BINARY_DIR}
+ # -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
+ # -DSCAFFOLDING_FOR_GENERATED_C:FILEPATH=${CMAKE_CURRENT_SOURCE_DIR}/src/test-c-machine.cpp
+ # -P ${CMAKE_CURRENT_SOURCE_DIR}/w3c/run_generated_c_test.cmake)
+ # set_property(TEST "gen_c/${TEST_NAME}" PROPERTY LABELS "gen_c/${TEST_NAME}")
+ # set_tests_properties("gen_c/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
+ # set_tests_properties("gen_c/${TEST_NAME}" PROPERTIES DEPENDS uscxml-transform)
+ #
+ # endif()
+ #
+ # if (BUILD_TESTS_FSM AND BUILD_TESTS_FSM_ECMA AND TEST_NAME MATCHES "^ecma\\/.*")
+ # add_test("fsm/${TEST_NAME}" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c -f ${W3C_TEST})
+ # set_property(TEST "fsm/${TEST_NAME}" PROPERTY LABELS "fsm/${TEST_NAME}")
+ # set_tests_properties("fsm/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
+ #
+ # add_test(NAME "minimized/${TEST_NAME}"
+ # COMMAND ${CMAKE_COMMAND}
+ # -DOUTDIR:FILEPATH=${CMAKE_CURRENT_BINARY_DIR}/ecma
+ # -DTESTFILE:FILEPATH=${W3C_TEST}
+ # -DUSCXML_TRANSFORM_BIN:FILEPATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/uscxml-transform
+ # -DUSCXML_W3C_TEST_BIN:FILEPATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c
+ # -P ${CMAKE_CURRENT_SOURCE_DIR}/w3c/run_minimized_test.cmake)
+ # set_property(TEST "minimized/${TEST_NAME}" PROPERTY LABELS "minimized/${TEST_NAME}")
+ # set_tests_properties("minimized/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
+ #
+ # set_tests_properties(${TEST_NAME} PROPERTIES DEPENDS uscxml-transform)
+ # set_tests_properties(${TEST_NAME} PROPERTIES DEPENDS test-w3c)
+ #
+ # # add_test(NAME "fsm/minimized/${TEST_NAME}"
+ # # COMMAND ${CMAKE_COMMAND}
+ # # -DOUTDIR:FILEPATH=${CMAKE_CURRENT_BINARY_DIR}/ecma
+ # # -DTESTFILE:FILEPATH=${W3C_TEST}
+ # # -DUSCXML_TRANSFORM_BIN:FILEPATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/uscxml-transform
+ # # -DUSCXML_W3C_TEST_BIN:FILEPATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c
+ # # -P ${CMAKE_CURRENT_SOURCE_DIR}/w3c/run_minimized_flat_test.cmake)
+ # # set_property(TEST "fsm/minimized/${TEST_NAME}" PROPERTY LABELS "fsm/minimized/${TEST_NAME}")
+ # # set_tests_properties("fsm/minimized/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
+ #
+ # # set_tests_properties(${TEST_NAME} PROPERTIES DEPENDS uscxml-transform)
+ # # set_tests_properties(${TEST_NAME} PROPERTIES DEPENDS test-w3c)
+ #
+ # endif()
+ #
+ # if (BUILD_TESTS_W3C_XPATH AND TEST_NAME MATCHES "^xpath\\/.*")
+ # add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST})
+ # set_property(TEST ${TEST_NAME} PROPERTY LABELS ${TEST_NAME})
+ # set_tests_properties(${TEST_NAME} PROPERTIES TIMEOUT ${TEST_TIMEOUT})
+ # # set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "TEST FAILED")
+ # if (BUILD_TESTS_FSM AND BUILD_TESTS_FSM_XPATH)
+ # add_test("fsm/${TEST_NAME}" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c -f ${W3C_TEST})
+ # set_property(TEST "fsm/${TEST_NAME}" PROPERTY LABELS "fsm/${TEST_NAME}")
+ # set_tests_properties("fsm/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
+ # endif()
+ # endif()
+ #
+ # if (BUILD_DM_LUA AND LUA_FOUND AND BUILD_TESTS_W3C_LUA AND TEST_NAME MATCHES "^lua\\/.*")
+ # add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST})
+ # set_property(TEST ${TEST_NAME} PROPERTY LABELS ${TEST_NAME})
+ # set_tests_properties(${TEST_NAME} PROPERTIES TIMEOUT ${TEST_TIMEOUT})
+ # # set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "TEST FAILED")
+ # if (BUILD_TESTS_FSM AND BUILD_TESTS_FSM_LUA)
+ # add_test("fsm/${TEST_NAME}" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c -f ${W3C_TEST})
+ # set_property(TEST "fsm/${TEST_NAME}" PROPERTY LABELS "fsm/${TEST_NAME}")
+ # set_tests_properties("fsm/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
+ # endif()
+ #
+ # endif()
+ #
+ # if (BUILD_DM_PROLOG AND SWI_FOUND AND BUILD_TESTS_W3C_PROLOG AND TEST_NAME MATCHES "^prolog\\/.*")
+ # add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST})
+ # set_property(TEST ${TEST_NAME} PROPERTY LABELS ${TEST_NAME})
+ # set_tests_properties(${TEST_NAME} PROPERTIES TIMEOUT ${TEST_TIMEOUT})
+ # # set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "TEST FAILED")
+ # if (BUILD_TESTS_FSM AND BUILD_TESTS_FSM_PROLOG)
+ # add_test("fsm/${TEST_NAME}" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c -f ${W3C_TEST})
+ # set_property(TEST "fsm/${TEST_NAME}" PROPERTY LABELS "fsm/${TEST_NAME}")
+ # set_tests_properties("fsm/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
+ # endif()
+ # endif()
+ #
+ # if (BUILD_DM_PROMELA AND BUILD_TESTS_W3C_PROMELA AND TEST_NAME MATCHES "^promela\\/.*")
+ # add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST})
+ # set_property(TEST ${TEST_NAME} PROPERTY LABELS ${TEST_NAME})
+ # set_tests_properties(${TEST_NAME} PROPERTIES TIMEOUT ${TEST_TIMEOUT})
+ # # set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "TEST FAILED")
+ # if (BUILD_TESTS_FSM AND BUILD_TESTS_FSM_PROMELA)
+ # add_test("fsm/${TEST_NAME}" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c -f ${W3C_TEST})
+ # set_property(TEST "fsm/${TEST_NAME}" PROPERTY LABELS "fsm/${TEST_NAME}")
+ # set_tests_properties("fsm/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
+ # endif()
+ # endif()
+ #
+ # if (GCC AND SPIN AND BUILD_DM_PROMELA AND BUILD_TESTS_W3C_PROMELA AND TEST_NAME MATCHES "^promela\\/.*")
+ #
+ # add_test(NAME "spin/${TEST_NAME}"
+ # COMMAND ${CMAKE_COMMAND}
+ # -DOUTDIR:FILEPATH=${CMAKE_CURRENT_BINARY_DIR}/promela
+ # -DTESTFILE:FILEPATH=${W3C_TEST}
+ # -DUSCXML_TRANSFORM_BIN:FILEPATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/uscxml-transform
+ # -DSPIN_BIN:FILEPATH=${SPIN}
+ # -DGCC_BIN:FILEPATH=${GCC}
+ # -P ${CMAKE_CURRENT_SOURCE_DIR}/w3c/run_promela_test.cmake)
+ # set_property(TEST "spin/${TEST_NAME}" PROPERTY LABELS "spin/${TEST_NAME}")
+ # set_tests_properties("spin/${TEST_NAME}" PROPERTIES TIMEOUT ${TEST_TIMEOUT})
+ # set_tests_properties("spin/${TEST_NAME}" PROPERTIES PASS_REGULAR_EXPRESSION "depth reached [0-9]+, errors: 0")
+ # set_tests_properties("spin/${TEST_NAME}" PROPERTIES FAIL_REGULAR_EXPRESSION "depth reached [0-9]+, errors: [1-9]+")
+ #
+ # set_tests_properties(${TEST_NAME} PROPERTIES DEPENDS uscxml-transform)
+ # # set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "TEST FAILED")
+ # endif()
+ #
+ # endif()
+ # endforeach()
endif() \ No newline at end of file
diff --git a/test/ctest/CTestCustom.ctest.in b/test/ctest/CTestCustom.ctest.in
index 6a66839..6ba6eb1 100644
--- a/test/ctest/CTestCustom.ctest.in
+++ b/test/ctest/CTestCustom.ctest.in
@@ -198,79 +198,103 @@ set(CTEST_CUSTOM_TESTS_IGNORE
### Ignore for generated C sources
# we do not support invokers yet
- "gen_c/ecma/test187.scxml"
- "gen_c/ecma/test191.scxml"
- "gen_c/ecma/test192.scxml"
- "gen_c/ecma/test207.scxml"
- "gen_c/ecma/test215.scxml"
- "gen_c/ecma/test216.scxml"
- "gen_c/ecma/test220.scxml"
- "gen_c/ecma/test223.scxml"
- "gen_c/ecma/test224.scxml"
- "gen_c/ecma/test225.scxml"
- "gen_c/ecma/test226.scxml"
- "gen_c/ecma/test228.scxml"
- "gen_c/ecma/test229.scxml"
- "gen_c/ecma/test230.scxml"
- "gen_c/ecma/test232.scxml"
- "gen_c/ecma/test233.scxml"
- "gen_c/ecma/test234.scxml"
- "gen_c/ecma/test235.scxml"
- "gen_c/ecma/test236.scxml"
- "gen_c/ecma/test237.scxml"
- "gen_c/ecma/test239.scxml"
- "gen_c/ecma/test240.scxml"
- "gen_c/ecma/test241.scxml"
- "gen_c/ecma/test242.scxml"
- "gen_c/ecma/test243.scxml"
- "gen_c/ecma/test244.scxml"
- "gen_c/ecma/test245.scxml"
- "gen_c/ecma/test247.scxml"
- "gen_c/ecma/test250.scxml"
- "gen_c/ecma/test252.scxml"
- "gen_c/ecma/test253.scxml"
- "gen_c/ecma/test276.scxml"
- "gen_c/ecma/test338.scxml"
- "gen_c/ecma/test347.scxml"
- "gen_c/ecma/test422.scxml"
- "gen_c/ecma/test530.scxml"
- "gen_c/ecma/test554.scxml"
+ "gen/c/ecma/test187.scxml"
+ "gen/c/ecma/test191.scxml"
+ "gen/c/ecma/test192.scxml"
+ "gen/c/ecma/test207.scxml"
+ "gen/c/ecma/test215.scxml"
+ "gen/c/ecma/test216.scxml"
+ "gen/c/ecma/test220.scxml"
+ "gen/c/ecma/test223.scxml"
+ "gen/c/ecma/test224.scxml"
+ "gen/c/ecma/test225.scxml"
+ "gen/c/ecma/test226.scxml"
+ "gen/c/ecma/test228.scxml"
+ "gen/c/ecma/test229.scxml"
+ "gen/c/ecma/test230.scxml"
+ "gen/c/ecma/test232.scxml"
+ "gen/c/ecma/test233.scxml"
+ "gen/c/ecma/test234.scxml"
+ "gen/c/ecma/test235.scxml"
+ "gen/c/ecma/test236.scxml"
+ "gen/c/ecma/test237.scxml"
+ "gen/c/ecma/test239.scxml"
+ "gen/c/ecma/test240.scxml"
+ "gen/c/ecma/test241.scxml"
+ "gen/c/ecma/test242.scxml"
+ "gen/c/ecma/test243.scxml"
+ "gen/c/ecma/test244.scxml"
+ "gen/c/ecma/test245.scxml"
+ "gen/c/ecma/test247.scxml"
+ "gen/c/ecma/test250.scxml"
+ "gen/c/ecma/test252.scxml"
+ "gen/c/ecma/test253.scxml"
+ "gen/c/ecma/test276.scxml"
+ "gen/c/ecma/test338.scxml"
+ "gen/c/ecma/test347.scxml"
+ "gen/c/ecma/test422.scxml"
+ "gen/c/ecma/test530.scxml"
+ "gen/c/ecma/test554.scxml"
# we do not support io processors yet
- "gen_c/ecma/test201.scxml"
- "gen_c/ecma/test496.scxml"
- "gen_c/ecma/test500.scxml"
- "gen_c/ecma/test501.scxml"
- "gen_c/ecma/test509.scxml"
- "gen_c/ecma/test510.scxml"
- "gen_c/ecma/test518.scxml"
- "gen_c/ecma/test519.scxml"
- "gen_c/ecma/test520.scxml"
- "gen_c/ecma/test521.scxml"
- "gen_c/ecma/test522.scxml"
- "gen_c/ecma/test531.scxml"
- "gen_c/ecma/test532.scxml"
- "gen_c/ecma/test534.scxml"
- "gen_c/ecma/test567.scxml"
- "gen_c/ecma/test569.scxml"
- "gen_c/ecma/test577.scxml"
+ "gen/c/ecma/test201.scxml"
+ "gen/c/ecma/test496.scxml"
+ "gen/c/ecma/test500.scxml"
+ "gen/c/ecma/test501.scxml"
+ "gen/c/ecma/test509.scxml"
+ "gen/c/ecma/test510.scxml"
+ "gen/c/ecma/test518.scxml"
+ "gen/c/ecma/test519.scxml"
+ "gen/c/ecma/test520.scxml"
+ "gen/c/ecma/test521.scxml"
+ "gen/c/ecma/test522.scxml"
+ "gen/c/ecma/test531.scxml"
+ "gen/c/ecma/test532.scxml"
+ "gen/c/ecma/test534.scxml"
+ "gen/c/ecma/test567.scxml"
+ "gen/c/ecma/test569.scxml"
+ "gen/c/ecma/test577.scxml"
# failing is succeeding
- "gen_c/ecma/test301.scxml"
+ "gen/c/ecma/test301.scxml"
# manual test
- "gen_c/ecma/test307.scxml"
+ "gen/c/ecma/test307.scxml"
# data from file
- "gen_c/ecma/test446.scxml"
- "gen_c/ecma/test552.scxml"
- "gen_c/ecma/test557.scxml"
- "gen_c/ecma/test558.scxml"
+ "gen/c/ecma/test446.scxml"
+ "gen/c/ecma/test552.scxml"
+ "gen/c/ecma/test557.scxml"
+ "gen/c/ecma/test558.scxml"
# XML DOM in data
- "gen_c/ecma/test561.scxml"
+ "gen/c/ecma/test561.scxml"
+
+
+ ### Ignore for delay with performance
+
+ # timeouts with benchmarking due to delayed events
+ "perf/gen/c/ecma/test175.scxml"
+ "perf/gen/c/ecma/test185.scxml"
+ "perf/gen/c/ecma/test186.scxml"
+ "perf/gen/c/ecma/test208.scxml"
+ "perf/gen/c/ecma/test210.scxml"
+ "perf/gen/c/ecma/test409.scxml"
+ "perf/gen/c/ecma/test423.scxml"
+ "perf/gen/c/ecma/test553.scxml"
+ "perf/gen/c/ecma/test579.scxml"
+
+ "perf/ecma/test175.scxml"
+ "perf/ecma/test185.scxml"
+ "perf/ecma/test186.scxml"
+ "perf/ecma/test208.scxml"
+ "perf/ecma/test210.scxml"
+ "perf/ecma/test409.scxml"
+ "perf/ecma/test423.scxml"
+ "perf/ecma/test553.scxml"
+ "perf/ecma/test579.scxml"
)
-
+# unset(CTEST_CUSTOM_TESTS_IGNORE)
diff --git a/test/src/test-c-machine.cpp b/test/src/test-c-machine.cpp
index 390ca0a..c8848ac 100644
--- a/test/src/test-c-machine.cpp
+++ b/test/src/test-c-machine.cpp
@@ -6,7 +6,7 @@
#include <deque> // deque
#include <boost/algorithm/string.hpp> // trim
-//#define SCXML_VERBOSE
+#define SCXML_VERBOSE
#include "uscxml/config.h"
@@ -492,16 +492,20 @@ int exec_content_foreach_done(const scxml_ctx* ctx, const scxml_elem_foreach* fo
int exec_content_log(const scxml_ctx* ctx, const char* label, const char* expr) {
try {
- if (label != 0) {
-// printf("%s: %s\n", label, USER_DATA(ctx)->datamodel.evalAsString(expr).c_str());
- } else {
-// printf("%s\n", USER_DATA(ctx)->datamodel.evalAsString(expr).c_str());
- }
+ if (label != NULL) {
+ printf("%s%s", label, (expr != NULL ? ": " : ""));
+ }
+ if (expr != NULL) {
+ std::string msg = USER_DATA(ctx)->datamodel.evalAsString(expr);
+ printf("%s", msg.c_str());
+ }
+ if (label != NULL || expr != NULL) {
+ printf("\n");
+ }
} catch (Event e) {
exec_content_raise(ctx, e.name.c_str());
return SCXML_ERR_EXEC_CONTENT;
}
-
return SCXML_ERR_OK;
}
@@ -570,7 +574,7 @@ int main(int argc, char** argv) {
const char* envBenchmarkRuns = getenv("USCXML_BENCHMARK_ITERATIONS");
if (envBenchmarkRuns != NULL) {
benchmarkRuns = strTo<size_t>(envBenchmarkRuns);
- }
+ }
size_t remainingRuns = benchmarkRuns;
@@ -590,6 +594,8 @@ int main(int argc, char** argv) {
double avgDm = 0;
#endif
+ Timer tTotal;
+ tTotal.start();
while(remainingRuns-- > 0) {
memset(&ctx, 0, sizeof(scxml_ctx));
@@ -622,8 +628,15 @@ int main(int argc, char** argv) {
microSteps = 0;
while((err = scxml_step(&ctx)) == SCXML_ERR_OK) {
- microSteps++;
+ t.stop();
+ microSteps++;
+ if (ctx.event != NULL) {
+ delete ((Event*)(ctx.event));
+ }
+ t.start();
}
+ microSteps++;
+
assert(ctx.flags & SCXML_CTX_TOP_LEVEL_FINAL);
t.stop();
@@ -645,11 +658,12 @@ int main(int argc, char** argv) {
interpreterInfo.eq.clear();
interpreterInfo.iq.clear();
}
-
- // 14.25311111 us per microstep
- // 1.923466667 us
- std::cout << (avg * 1000.0) / (double)benchmarkRuns << " ms on average" << std::endl;
- std::cout << microSteps << " microsteps per iteration (" << (avg * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep)" << std::endl;
+ tTotal.stop();
+ std::cout << benchmarkRuns << " iterations" << std::endl;
+ std::cout << tTotal.elapsed * 1000.0 << " ms in total" << std::endl;
+ std::cout << (avg * 1000.0) / (double)benchmarkRuns << " ms per execution" << std::endl;
+ std::cout << microSteps << " microsteps per iteration" << std::endl;
+ std::cout << (avg * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep" << std::endl;
#ifdef BUILD_PROFILING
std::cout << (avgDm * 1000.0) / (double)benchmarkRuns << " ms in datamodel" << std::endl;
std::cout << ((avg - avgDm) * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep \\wo datamodel" << std::endl;
diff --git a/test/src/test-c-machine.machine.c b/test/src/test-c-machine.machine.c
index be14d3e..efc4c22 100644
--- a/test/src/test-c-machine.machine.c
+++ b/test/src/test-c-machine.machine.c
@@ -5,8 +5,13 @@
#define SET_BIT(idx, bitset) bitset[idx >> 3] |= (1 << (idx & 7));
#define CLEARBIT(idx, bitset) bitset[idx >> 3] &= (1 << (idx & 7)) ^ 0xFF;
-#define likely(x) (x)
-#define unlikely(x) (x)
+#ifdef __GNUC__
+#define likely(x) (__builtin_expect(!!(x), 1))
+#define unlikely(x) (__builtin_expect(!!(x), 0))
+#else
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
// error return codes
#define SCXML_ERR_OK 0
@@ -20,13 +25,14 @@
#define SCXML_ERR_UNSUPPORTED 8
#define SCXML_MACHINE_NAME ""
-#define SCXML_NUMBER_STATES 5
-#define SCXML_NUMBER_TRANSITIONS 4
+#define SCXML_NUMBER_STATES 11
+#define SCXML_NUMBER_TRANSITIONS 13
#define SCXML_TRANS_SPONTANEOUS 0x01
#define SCXML_TRANS_TARGETLESS 0x02
#define SCXML_TRANS_INTERNAL 0x04
#define SCXML_TRANS_HISTORY 0x08
+#define SCXML_TRANS_INITIAL 0x10
#define SCXML_STATE_ATOMIC 0x01
#define SCXML_STATE_PARALLEL 0x02
@@ -87,26 +93,26 @@ struct scxml_elem_data {
struct scxml_state {
const char* name; // eventual name
- uint16_t source; // parent
+ uint16_t parent; // parent
exec_content_t on_entry; // on entry handlers
exec_content_t on_exit; // on exit handlers
invoke_t invoke; // invocations
- char children[1]; // all children
- char completion[1]; // default completion
- char ancestors[1]; // all ancestors
+ char children[2]; // all children
+ char completion[2]; // default completion
+ char ancestors[2]; // all ancestors
const scxml_elem_data* data;
uint8_t type; // atomic, parallel, compound, final, history
};
struct scxml_transition {
uint16_t source;
- char target[1];
+ char target[2];
const char* event;
const char* condition;
exec_content_t on_transition;
uint8_t type;
- char conflicts[1];
- char exit_set[1];
+ char conflicts[2];
+ char exit_set[2];
};
struct scxml_elem_foreach {
@@ -165,12 +171,13 @@ struct scxml_elem_send {
struct scxml_ctx {
uint8_t flags;
- char config[1];
- char history[1];
- char pending_invokes[1];
- char initialized_data[1];
+ char config[2];
+ char history[2];
+ char pending_invokes[2];
+ char initialized_data[2];
void* user_data;
+ void* event;
dequeue_internal_cb_t dequeue_internal;
dequeue_external_cb_t dequeue_external;
@@ -191,15 +198,67 @@ struct scxml_ctx {
invoke_t invoke;
};
+static scxml_elem_data scxml_elem_datas[2] = {
+ { "Var1", NULL, "0", NULL },
+ { NULL, NULL, NULL, NULL }
+};
+
+static scxml_elem_send scxml_elem_sends[1] = {
+ { "timeout", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "'1s'", NULL, NULL, NULL, NULL, NULL }
+};
+
+static scxml_elem_donedata scxml_elem_donedatas[1] = {
+ { 0, NULL, NULL }
+};
+
+static int global_script(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ return SCXML_ERR_OK;
+}
+
+static int s0_on_exit_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ int err = SCXML_ERR_OK;
+ if likely(ctx->exec_content_assign != NULL) {
+ if ((ctx->exec_content_assign(ctx, "Var1", "Var1 + 1")) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ if likely(ctx->exec_content_log != NULL) {
+ if unlikely((ctx->exec_content_log(ctx, "Var1 is", "Var1")) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ return SCXML_ERR_OK;
+}
+
+static int s0_on_exit(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ s0_on_exit_0(ctx, state, event);
+ return SCXML_ERR_OK;
+}
+
static int s0_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
int err = SCXML_ERR_OK;
+ if likely(ctx->exec_content_send != NULL) {
+ if ((ctx->exec_content_send(ctx, &scxml_elem_sends[0])) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
if likely(ctx->exec_content_raise != NULL) {
- if ((ctx->exec_content_raise(ctx, "foo")) != SCXML_ERR_OK) return err;
+ if unlikely((ctx->exec_content_raise(ctx, "event1")) != SCXML_ERR_OK) return err;
} else {
return SCXML_ERR_MISSING_CALLBACK;
}
+ return SCXML_ERR_OK;
+}
+
+static int s0_initial(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ int err = SCXML_ERR_OK;
if likely(ctx->exec_content_raise != NULL) {
- if ((ctx->exec_content_raise(ctx, "bar")) != SCXML_ERR_OK) return err;
+ if unlikely((ctx->exec_content_raise(ctx, "event2")) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ if likely(ctx->exec_content_log != NULL) {
+ if unlikely((ctx->exec_content_log(ctx, "initial transition in s0", NULL)) != SCXML_ERR_OK) return err;
} else {
return SCXML_ERR_MISSING_CALLBACK;
}
@@ -208,6 +267,22 @@ static int s0_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const v
static int s0_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
s0_on_entry_0(ctx, state, event);
+ s0_initial(ctx, state, event);
+ return SCXML_ERR_OK;
+}
+
+static int s03_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ int err = SCXML_ERR_OK;
+ if likely(ctx->exec_content_log != NULL) {
+ if unlikely((ctx->exec_content_log(ctx, "Var1 when entering s03", "Var1")) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ return SCXML_ERR_OK;
+}
+
+static int s03_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ s03_on_entry_0(ctx, state, event);
return SCXML_ERR_OK;
}
@@ -241,19 +316,49 @@ static int fail_on_entry(const scxml_ctx* ctx, const scxml_state* state, const v
return SCXML_ERR_OK;
}
-static scxml_state scxml_states[5] = {
- { NULL, 0, NULL, NULL, NULL, { 0x1e /* 01111, 1 2 3 4 */ }, { 0x02 /* 01000, 1 */ }, { 0x00 /* 00000, */ }, NULL, SCXML_STATE_COMPOUND },
- { "s0", 0, s0_on_entry, NULL, NULL, { 0x00 /* 00000, */ }, { 0x00 /* 00000, */ }, { 0x01 /* 10000, 0 */ }, NULL, SCXML_STATE_ATOMIC },
- { "s1", 0, NULL, NULL, NULL, { 0x00 /* 00000, */ }, { 0x00 /* 00000, */ }, { 0x01 /* 10000, 0 */ }, NULL, SCXML_STATE_ATOMIC },
- { "pass", 0, pass_on_entry, NULL, NULL, { 0x00 /* 00000, */ }, { 0x00 /* 00000, */ }, { 0x01 /* 10000, 0 */ }, NULL, SCXML_STATE_FINAL },
- { "fail", 0, fail_on_entry, NULL, NULL, { 0x00 /* 00000, */ }, { 0x00 /* 00000, */ }, { 0x01 /* 10000, 0 */ }, NULL, SCXML_STATE_FINAL }
+static int sh1_transition0_on_trans(const scxml_ctx* ctx, const scxml_state* state, const void* event) {
+ int err = SCXML_ERR_OK;
+ if likely(ctx->exec_content_raise != NULL) {
+ if unlikely((ctx->exec_content_raise(ctx, "event3")) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ if likely(ctx->exec_content_log != NULL) {
+ if unlikely((ctx->exec_content_log(ctx, "history transition in sh1", NULL)) != SCXML_ERR_OK) return err;
+ } else {
+ return SCXML_ERR_MISSING_CALLBACK;
+ }
+ return SCXML_ERR_OK;
+}
+
+static scxml_state scxml_states[11] = {
+ { NULL, 0, NULL, NULL, NULL, { 0x82, 0x07 /* 01000001111, 1 7 8 9 10 */ }, { 0x02, 0x00 /* 01000000000, 1 */ }, { 0x00, 0x00 /* 00000000000, */ }, (const scxml_elem_data*)&scxml_elem_datas[0], SCXML_STATE_COMPOUND },
+ { "s0", 0, s0_on_entry, s0_on_exit, NULL, { 0x7c, 0x00 /* 00111110000, 2 3 4 5 6 */ }, { 0x04, 0x00 /* 00100000000, 2 */ }, { 0x01, 0x00 /* 10000000000, 0 */ }, NULL, SCXML_STATE_COMPOUND },
+ { NULL, 1, NULL, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x00, 0x00 /* 00000000000, */ }, { 0x03, 0x00 /* 11000000000, 0 1 */ }, NULL, SCXML_STATE_INITIAL },
+ { "sh1", 1, NULL, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x74, 0x00 /* 00101110000, 2 4 5 6 */ }, { 0x03, 0x00 /* 11000000000, 0 1 */ }, NULL, SCXML_STATE_HISTORY_SHALLOW },
+ { "s01", 1, NULL, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x00, 0x00 /* 00000000000, */ }, { 0x03, 0x00 /* 11000000000, 0 1 */ }, NULL, SCXML_STATE_ATOMIC },
+ { "s02", 1, NULL, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x00, 0x00 /* 00000000000, */ }, { 0x03, 0x00 /* 11000000000, 0 1 */ }, NULL, SCXML_STATE_ATOMIC },
+ { "s03", 1, s03_on_entry, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x00, 0x00 /* 00000000000, */ }, { 0x03, 0x00 /* 11000000000, 0 1 */ }, NULL, SCXML_STATE_ATOMIC },
+ { "s2", 0, NULL, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x00, 0x00 /* 00000000000, */ }, { 0x01, 0x00 /* 10000000000, 0 */ }, NULL, SCXML_STATE_ATOMIC },
+ { "s3", 0, NULL, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x00, 0x00 /* 00000000000, */ }, { 0x01, 0x00 /* 10000000000, 0 */ }, NULL, SCXML_STATE_ATOMIC },
+ { "pass", 0, pass_on_entry, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x00, 0x00 /* 00000000000, */ }, { 0x01, 0x00 /* 10000000000, 0 */ }, NULL, SCXML_STATE_FINAL },
+ { "fail", 0, fail_on_entry, NULL, NULL, { 0x00, 0x00 /* 00000000000, */ }, { 0x00, 0x00 /* 00000000000, */ }, { 0x01, 0x00 /* 10000000000, 0 */ }, NULL, SCXML_STATE_FINAL }
};
-static scxml_transition scxml_transitions[4] = {
- { 1, { 0x04 /* 00100 */ }, "foo", NULL, NULL, 0, { 0x0f /* 1111 */ }, { 0x1e /* 01111 */ } },
- { 1, { 0x10 /* 00001 */ }, "*", NULL, NULL, 0, { 0x0f /* 1111 */ }, { 0x1e /* 01111 */ } },
- { 2, { 0x08 /* 00010 */ }, "bar", NULL, NULL, 0, { 0x0f /* 1111 */ }, { 0x1e /* 01111 */ } },
- { 2, { 0x10 /* 00001 */ }, "*", NULL, NULL, 0, { 0x0f /* 1111 */ }, { 0x1e /* 01111 */ } }
+static scxml_transition scxml_transitions[13] = {
+ { 2, { 0x08, 0x00 /* 00010000000 */ }, NULL, NULL, NULL, SCXML_TRANS_SPONTANEOUS | SCXML_TRANS_INITIAL, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 3, { 0x10, 0x00 /* 00001000000 */ }, NULL, NULL, sh1_transition0_on_trans, SCXML_TRANS_SPONTANEOUS | SCXML_TRANS_HISTORY, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 4, { 0x20, 0x00 /* 00000100000 */ }, "event1", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0x7c, 0x00 /* 00111110000 */ } },
+ { 4, { 0x00, 0x04 /* 00000000001 */ }, "*", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 5, { 0x40, 0x00 /* 00000010000 */ }, "event2", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0x7c, 0x00 /* 00111110000 */ } },
+ { 5, { 0x00, 0x04 /* 00000000001 */ }, "*", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 6, { 0x02, 0x00 /* 01000000000 */ }, "event3", "Var1==0", NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 6, { 0x80, 0x00 /* 00000001000 */ }, "event1", "Var1==1", NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 6, { 0x00, 0x04 /* 00000000001 */ }, "*", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 7, { 0x00, 0x01 /* 00000000100 */ }, "event2", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 7, { 0x00, 0x04 /* 00000000001 */ }, "*", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 8, { 0x00, 0x04 /* 00000000001 */ }, "event3", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } },
+ { 8, { 0x00, 0x02 /* 00000000010 */ }, "timeout", NULL, NULL, 0, { 0xff, 0x1f /* 1111111111111 */ }, { 0xfe, 0x07 /* 01111111111 */ } }
};
#ifdef SCXML_VERBOSE
@@ -320,7 +425,7 @@ static int bit_any_set(const char* a, size_t i) {
return false;
}
-static int scxml_step(scxml_ctx* ctx) {
+int scxml_step(scxml_ctx* ctx) {
#ifdef SCXML_VERBOSE
printf("Config: ");
@@ -334,34 +439,34 @@ MACRO_STEP:
return SCXML_ERR_DONE;
int err = SCXML_ERR_OK;
- char conflicts[1] = {0};
- char target_set[1] = {0};
- char exit_set[1] = {0};
- char trans_set[1] = {0};
- char entry_set[1] = {0};
+ char conflicts[2] = {0, 0};
+ char target_set[2] = {0, 0};
+ char exit_set[2] = {0, 0};
+ char trans_set[2] = {0, 0};
+ char entry_set[2] = {0, 0};
- void* event;
if unlikely(ctx->flags == SCXML_CTX_PRISTINE) {
- bit_or(target_set, scxml_states[0].completion, 1);
+ global_script(ctx, &scxml_states[0], NULL);
+ bit_or(target_set, scxml_states[0].completion, 2);
ctx->flags |= SCXML_CTX_SPONTANEOUS | SCXML_CTX_INITIALIZED;
- goto COMPLETE_CONFIG;
+ goto ESTABLISH_ENTRY_SET;
}
if (ctx->flags & SCXML_CTX_SPONTANEOUS) {
- event = NULL;
+ ctx->event = NULL;
goto SELECT_TRANSITIONS;
}
- if ((event = ctx->dequeue_internal(ctx)) != NULL) {
+ if ((ctx->event = ctx->dequeue_internal(ctx)) != NULL) {
goto SELECT_TRANSITIONS;
}
- if ((event = ctx->dequeue_external(ctx)) != NULL) {
+ if ((ctx->event = ctx->dequeue_external(ctx)) != NULL) {
goto SELECT_TRANSITIONS;
}
SELECT_TRANSITIONS:
for (int i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {
// never select history or initial transitions automatically
- if unlikely(scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_HISTORY))
+ if unlikely(scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL))
continue;
// is the transition active?
@@ -369,32 +474,30 @@ SELECT_TRANSITIONS:
// is it non-conflicting?
if (!IS_SET(i, conflicts)) {
// is it enabled?
- if (ctx->is_enabled(ctx, &scxml_transitions[i], event) > 0) {
+ if (ctx->is_enabled(ctx, &scxml_transitions[i], ctx->event) > 0) {
// remember that we found a transition
ctx->flags |= SCXML_CTX_TRANSITION_FOUND;
// transitions that are pre-empted
- bit_or(conflicts, scxml_transitions[i].conflicts, 1);
+ bit_or(conflicts, scxml_transitions[i].conflicts, 2);
// states that are directly targeted (resolve as entry-set later)
- bit_or(target_set, scxml_transitions[i].target, 1);
+ bit_or(target_set, scxml_transitions[i].target, 2);
// states that will be left
- bit_or(exit_set, scxml_transitions[i].exit_set, 1);
+ bit_or(exit_set, scxml_transitions[i].exit_set, 2);
SET_BIT(i, trans_set);
}
}
}
}
- bit_and(exit_set, ctx->config, 1);
+ bit_and(exit_set, ctx->config, 2);
if (ctx->flags & SCXML_CTX_TRANSITION_FOUND) {
ctx->flags |= SCXML_CTX_SPONTANEOUS;
} else {
ctx->flags &= ~SCXML_CTX_SPONTANEOUS;
- // goto MACRO_STEP;
- return SCXML_ERR_OK;
}
#ifdef SCXML_VERBOSE
@@ -402,25 +505,6 @@ SELECT_TRANSITIONS:
printStateNames(target_set);
#endif
-REMEMBER_HISTORY:
- for (int i = 0; i < SCXML_NUMBER_STATES; i++) {
- if unlikely(scxml_states[i].type == SCXML_STATE_HISTORY_SHALLOW || scxml_states[i].type == SCXML_STATE_HISTORY_DEEP) {
- // a history state whose parent is about to be exited
- if unlikely(IS_SET(scxml_states[i].source, exit_set)) {
- char history[1] = {0};
- bit_copy(history, scxml_states[i].completion, 1);
-
- // set those states who were enabled
- bit_and(history, ctx->config, 1);
-
- // clear current history with completion mask
- bit_and_not(ctx->history, scxml_states[i].completion, 1);
-
- // set history
- bit_or(ctx->history, history, 1);
- }
- }
- }
#ifdef SCXML_VERBOSE
printf("Exiting: ");
printStateNames(exit_set);
@@ -431,55 +515,68 @@ REMEMBER_HISTORY:
printStateNames(ctx->history);
#endif
-EXIT_STATES:
- for (int i = SCXML_NUMBER_STATES - 1; i >= 0; i--) {
- if (IS_SET(i, exit_set) && IS_SET(i, ctx->config)) {
- // call all on exit handlers
- if (scxml_states[i].on_exit != NULL) {
- if unlikely((err = scxml_states[i].on_exit(ctx, &scxml_states[i], event)) != SCXML_ERR_OK)
- return err;
+
+ // REMEMBER_HISTORY:
+ for (int i = 0; i < SCXML_NUMBER_STATES; i++) {
+ if unlikely(scxml_states[i].type == SCXML_STATE_HISTORY_SHALLOW || scxml_states[i].type == SCXML_STATE_HISTORY_DEEP) {
+ // a history state whose parent is about to be exited
+ if unlikely(IS_SET(scxml_states[i].parent, exit_set)) {
+ char history[2] = {0, 0};
+ bit_copy(history, scxml_states[i].completion, 2);
+
+ // set those states who were enabled
+ bit_and(history, ctx->config, 2);
+
+ // clear current history with completion mask - TODO: errornously clears nested history
+ bit_and_not(ctx->history, scxml_states[i].completion, 2);
+
+ // set history
+ bit_or(ctx->history, history, 2);
}
- CLEARBIT(i, ctx->config);
}
}
+#ifdef SCXML_VERBOSE
+ printf("Transitions: ");
+ printBitsetIndices(trans_set, sizeof(char) * 8 * 2);
+#endif
-COMPLETE_CONFIG:
+ESTABLISH_ENTRY_SET:
// calculate new entry set
- bit_copy(entry_set, target_set, 1);
+ bit_copy(entry_set, target_set, 2);
// iterate for ancestors
for (int i = 0; i < SCXML_NUMBER_STATES; i++) {
if (IS_SET(i, entry_set)) {
- bit_or(entry_set, scxml_states[i].ancestors, 1);
+ bit_or(entry_set, scxml_states[i].ancestors, 2);
}
}
-ADD_DESCENDANTS:
// iterate for descendants
for (int i = 0; i < SCXML_NUMBER_STATES; i++) {
if (IS_SET(i, entry_set)) {
switch (scxml_states[i].type) {
case SCXML_STATE_PARALLEL: {
- bit_or(entry_set, scxml_states[i].completion, 1);
+ bit_or(entry_set, scxml_states[i].completion, 2);
break;
}
case SCXML_STATE_HISTORY_SHALLOW:
case SCXML_STATE_HISTORY_DEEP: {
- char history_targets[1] = {0};
- if (!bit_has_and(scxml_states[i].completion, ctx->history, 1)) {
+ char history_targets[2] = {0, 0};
+ if (!bit_has_and(scxml_states[i].completion, ctx->history, 2) &&
+ !IS_SET(scxml_states[i].parent, ctx->config)) {
// nothing set for history, look for a default transition or enter parents completion
for (int j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {
if unlikely(scxml_transitions[j].source == i) {
- bit_or(entry_set, scxml_transitions[j].target, 1);
+ bit_or(entry_set, scxml_transitions[j].target, 2);
SET_BIT(j, trans_set);
break;
}
}
// TODO: enter parents default completion here
} else {
- bit_copy(history_targets, scxml_states[i].completion, 1);
- bit_and(history_targets, ctx->history, 1);
- bit_or(entry_set, history_targets, 1);
+ bit_copy(history_targets, scxml_states[i].completion, 2);
+ bit_and(history_targets, ctx->history, 2);
+ bit_or(entry_set, history_targets, 2);
}
break;
}
@@ -488,7 +585,7 @@ ADD_DESCENDANTS:
if (scxml_transitions[j].source == i) {
SET_BIT(j, trans_set);
CLEARBIT(i, entry_set);
- bit_or(entry_set, scxml_transitions[j].target, 1);
+ bit_or(entry_set, scxml_transitions[j].target, 2);
// one target may have been above, reestablish completion
// goto ADD_DESCENDANTS; // initial will have to be first!
}
@@ -496,10 +593,11 @@ ADD_DESCENDANTS:
break;
}
case SCXML_STATE_COMPOUND: { // we need to check whether one child is already in entry_set
- if (!bit_has_and(entry_set, scxml_states[i].children, 1) &&
- !bit_has_and(ctx->config, scxml_states[i].children, 1))
+ if (!bit_has_and(entry_set, scxml_states[i].children, 2) &&
+ (!bit_has_and(ctx->config, scxml_states[i].children, 2) ||
+ bit_has_and(exit_set, scxml_states[i].children, 2)))
{
- bit_or(entry_set, scxml_states[i].completion, 1);
+ bit_or(entry_set, scxml_states[i].completion, 2);
}
break;
}
@@ -507,19 +605,26 @@ ADD_DESCENDANTS:
}
}
-#ifdef SCXML_VERBOSE
- printf("Transitions: ");
- printBitsetIndices(trans_set, sizeof(char) * 8 * 1);
-#endif
+// EXIT_STATES:
+ for (int i = SCXML_NUMBER_STATES - 1; i >= 0; i--) {
+ if (IS_SET(i, exit_set) && IS_SET(i, ctx->config)) {
+ // call all on exit handlers
+ if (scxml_states[i].on_exit != NULL) {
+ if unlikely((err = scxml_states[i].on_exit(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK)
+ return err;
+ }
+ CLEARBIT(i, ctx->config);
+ }
+ }
-TAKE_TRANSITIONS:
+// TAKE_TRANSITIONS:
for (int i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {
if (IS_SET(i, trans_set) && (scxml_transitions[i].type & SCXML_TRANS_HISTORY) == 0) {
// call executable content in transition
if (scxml_transitions[i].on_transition != NULL) {
if unlikely((err = scxml_transitions[i].on_transition(ctx,
&scxml_states[scxml_transitions[i].source],
- event)) != SCXML_ERR_OK)
+ ctx->event)) != SCXML_ERR_OK)
return err;
}
}
@@ -530,7 +635,7 @@ TAKE_TRANSITIONS:
printStateNames(entry_set);
#endif
-ENTER_STATES:
+// ENTER_STATES:
for (int i = 0; i < SCXML_NUMBER_STATES; i++) {
if (IS_SET(i, entry_set) && !IS_SET(i, ctx->config)) {
// these are no proper states
@@ -550,26 +655,38 @@ ENTER_STATES:
}
if (scxml_states[i].on_entry != NULL) {
- if unlikely((err = scxml_states[i].on_entry(ctx, &scxml_states[i], event)) != SCXML_ERR_OK)
+ if unlikely((err = scxml_states[i].on_entry(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK)
return err;
}
+ // take history transitions
+ for (int j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {
+ if unlikely(IS_SET(j, trans_set) &&
+ (scxml_transitions[j].type & SCXML_TRANS_HISTORY) &&
+ scxml_states[scxml_transitions[j].source].parent == i) {
+ // call executable content in transition
+ if (scxml_transitions[j].on_transition != NULL) {
+ if unlikely((err = scxml_transitions[j].on_transition(ctx,
+ &scxml_states[i],
+ ctx->event)) != SCXML_ERR_OK)
+ return err;
+ }
+ }
+ }
+
// handle final states
if unlikely(scxml_states[i].type == SCXML_STATE_FINAL) {
if unlikely(scxml_states[i].ancestors[0] == 0x01) {
ctx->flags |= SCXML_CTX_TOP_LEVEL_FINAL;
} else {
// raise done event
- size_t parent = 0;
- for (int j = SCXML_NUMBER_STATES - 1; j >= 0; j--) {
- // we could trade runtime for memory here by saving the parent index
- if unlikely(IS_SET(j, scxml_states[i].ancestors)) {
- parent = j;
- break;
- }
+ scxml_elem_donedata* donedata = &scxml_elem_donedatas[0];
+ while(ELEM_DONEDATA_IS_SET(donedata)) {
+ if unlikely(donedata->source == i)
+ break;
+ donedata++;
}
- // is this raised for toplevel final as well?
- ctx->raise_done_event(ctx, &scxml_states[parent], NULL);
+ ctx->raise_done_event(ctx, &scxml_states[scxml_states[i].parent], (ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL));
}
/**
@@ -581,18 +698,18 @@ ENTER_STATES:
*/
for (int j = 0; j < SCXML_NUMBER_STATES; j++) {
if unlikely(scxml_states[j].type == SCXML_STATE_PARALLEL) {
- char parallel_children[1] = {0};
+ char parallel_children[2] = {0, 0};
size_t parallel = j;
for (int k = 0; k < SCXML_NUMBER_STATES; k++) {
if unlikely(IS_SET(parallel, scxml_states[k].ancestors) && IS_SET(k, ctx->config)) {
if (scxml_states[k].type == SCXML_STATE_FINAL) {
- bit_and_not(parallel_children, scxml_states[k].ancestors, 1);
+ bit_and_not(parallel_children, scxml_states[k].ancestors, 2);
} else {
SET_BIT(k, parallel_children);
}
}
}
- if unlikely(!bit_any_set(parallel_children, 1)) {
+ if unlikely(!bit_any_set(parallel_children, 2)) {
ctx->raise_done_event(ctx, &scxml_states[parallel], NULL);
}
}
@@ -603,19 +720,6 @@ ENTER_STATES:
}
}
-HISTORY_TRANSITIONS:
- for (int i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {
- if unlikely(IS_SET(i, trans_set) && (scxml_transitions[i].type & SCXML_TRANS_HISTORY)) {
- // call executable content in transition
- if (scxml_transitions[i].on_transition != NULL) {
- if unlikely((err = scxml_transitions[i].on_transition(ctx,
- &scxml_states[scxml_transitions[i].source],
- event)) != SCXML_ERR_OK)
- return err;
- }
- }
- }
-
return SCXML_ERR_OK;
}
diff --git a/test/src/test-lifecycle.cpp b/test/src/test-lifecycle.cpp
index 84ffbb5..7ac40fa 100644
--- a/test/src/test-lifecycle.cpp
+++ b/test/src/test-lifecycle.cpp
@@ -275,7 +275,9 @@ int main(int argc, char** argv) {
Interpreter interpreter = Interpreter::fromXML(xml, "");
interpreter.addMonitor(mon);
- callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE);
+ callBackSeq.push_back(USCXML_BEFORETAKINGTRANSITION);
+ callBackSeq.push_back(USCXML_AFTERTAKINGTRANSITION);
+ callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE);
callBackSeq.push_back(USCXML_AFTERENTERINGSTATE);
callBackSeq.push_back(USCXML_BEFOREMICROSTEP);
@@ -299,9 +301,10 @@ int main(int argc, char** argv) {
callBackSeq.push_back(USCXML_BEFORECOMPLETION);
callBackSeq.push_back(USCXML_AFTERCOMPLETION);
- assert(interpreter.getState() == USCXML_INSTANTIATED);
- assert(interpreter.step() == USCXML_MICROSTEPPED);
+ assert(interpreter.getState() == USCXML_INSTANTIATED);
+ assert(interpreter.step() == USCXML_INITIALIZED);
assert(interpreter.step() == USCXML_MICROSTEPPED);
+ assert(interpreter.step() == USCXML_MICROSTEPPED);
assert(interpreter.step() == USCXML_FINISHED);
assert(callBackSeq.empty());
}
@@ -319,6 +322,8 @@ int main(int argc, char** argv) {
Interpreter interpreter = Interpreter::fromXML(xml, "");
interpreter.addMonitor(mon);
+ callBackSeq.push_back(USCXML_BEFORETAKINGTRANSITION);
+ callBackSeq.push_back(USCXML_AFTERTAKINGTRANSITION);
callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE);
callBackSeq.push_back(USCXML_AFTERENTERINGSTATE);
@@ -335,10 +340,13 @@ int main(int argc, char** argv) {
callBackSeq.push_back(USCXML_AFTERCOMPLETION);
assert(interpreter.getState() == USCXML_INSTANTIATED);
- assert(interpreter.step() == USCXML_MICROSTEPPED);
+ assert(interpreter.step() == USCXML_INITIALIZED);
+ assert(interpreter.step() == USCXML_MICROSTEPPED);
assert(interpreter.step() == USCXML_FINISHED);
interpreter.reset();
+ callBackSeq.push_back(USCXML_BEFORETAKINGTRANSITION);
+ callBackSeq.push_back(USCXML_AFTERTAKINGTRANSITION);
callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE);
callBackSeq.push_back(USCXML_AFTERENTERINGSTATE);
@@ -355,7 +363,8 @@ int main(int argc, char** argv) {
callBackSeq.push_back(USCXML_AFTERCOMPLETION);
assert(interpreter.getState() == USCXML_INSTANTIATED);
- assert(interpreter.step() == USCXML_MICROSTEPPED);
+ assert(interpreter.step() == USCXML_INITIALIZED);
+ assert(interpreter.step() == USCXML_MICROSTEPPED);
assert(interpreter.step() == USCXML_FINISHED);
}
@@ -378,6 +387,8 @@ int main(int argc, char** argv) {
Interpreter interpreter = Interpreter::fromXML(xml, "");
interpreter.addMonitor(mon);
+ callBackSeq.push_back(USCXML_BEFORETAKINGTRANSITION);
+ callBackSeq.push_back(USCXML_AFTERTAKINGTRANSITION);
callBackSeq.push_back(USCXML_BEFOREENTERINGSTATE);
callBackSeq.push_back(USCXML_BEFOREEXECUTINGCONTENT);
callBackSeq.push_back(USCXML_AFTEREXECUTINGCONTENT);
@@ -406,10 +417,11 @@ int main(int argc, char** argv) {
callBackSeq.push_back(USCXML_BEFORECOMPLETION);
callBackSeq.push_back(USCXML_AFTERCOMPLETION);
- assert(interpreter.getState() == USCXML_INSTANTIATED);
+ assert(interpreter.getState() == USCXML_INSTANTIATED);
+ assert(interpreter.step() == USCXML_INITIALIZED);
assert(interpreter.step() == USCXML_IDLE);
assert(interpreter.step(true) == USCXML_MACROSTEPPED);
- assert(interpreter.step() == USCXML_MICROSTEPPED);
+ assert(interpreter.step() == USCXML_MICROSTEPPED);
assert(interpreter.step() == USCXML_FINISHED);
}
}
diff --git a/test/src/test-w3c.cpp b/test/src/test-w3c.cpp
index 3de8e4d..aa2bff5 100644
--- a/test/src/test-w3c.cpp
+++ b/test/src/test-w3c.cpp
@@ -2,10 +2,27 @@
// #define protected public
#include "uscxml/config.h"
+
+#ifdef APPLE
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <pthread.h>
+#endif
+
#include "uscxml/Common.h"
#include "uscxml/Convenience.h"
+
+#ifdef BUILD_PROFILING
+// get access to the datamodel - this causes strange issues with MSVC depending on include order
+// may be better to ifndef all protected: and private: stanzas for profiling?
+#define protected public
#include "uscxml/Interpreter.h"
+#undef protected
+# endif
+
+
#include "uscxml/DOMUtils.h"
+#include "uscxml/concurrency/Timer.h"
#include "uscxml/Factory.h"
#include "uscxml/server/HTTPServer.h"
@@ -29,7 +46,7 @@
static bool withFlattening = false;
static double delayFactor = 1;
-static size_t benchmarkRuns = 0;
+static size_t benchmarkRuns = 1;
static std::string documentURI;
int retCode = EXIT_FAILURE;
@@ -63,17 +80,45 @@ class W3CStatusMonitor : public uscxml::InterpreterMonitor {
void beforeCompletion(uscxml::Interpreter tmp) {
if (interpreter.getConfiguration().size() == 1 && interpreter.isInState("pass")) {
- std::cout << "TEST SUCCEEDED" << std::endl;
+#ifndef BUILD_PROFILING
+ std::cout << "TEST SUCCEEDED" << std::endl;
+#endif
retCode = EXIT_SUCCESS;
return;
}
+#ifndef BUILD_PROFILING
std::cout << "TEST FAILED" << std::endl;
- }
+#endif
+ retCode = EXIT_FAILURE;
+ }
};
int main(int argc, char** argv) {
using namespace uscxml;
+#ifdef APPLE
+ mach_timebase_info_data_t timebase_info;
+ mach_timebase_info(&timebase_info);
+
+ const uint64_t NANOS_PER_MSEC = 1000000ULL;
+ double clock2abs = ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC;
+
+ thread_time_constraint_policy_data_t policy;
+ policy.period = 0;
+ policy.computation = (uint32_t)(5 * clock2abs); // 5 ms of work
+ policy.constraint = (uint32_t)(10 * clock2abs);
+ policy.preemptible = FALSE;
+
+ int kr = thread_policy_set(pthread_mach_thread_np(pthread_self()),
+ THREAD_TIME_CONSTRAINT_POLICY,
+ (thread_policy_t)&policy,
+ THREAD_TIME_CONSTRAINT_POLICY_COUNT);
+ if (kr != KERN_SUCCESS) {
+ mach_error("thread_policy_set:", kr);
+ exit(1);
+ }
+#endif
+
try {
#if defined(HAS_SIGNAL_H) && !defined(WIN32)
@@ -85,7 +130,6 @@ int main(int argc, char** argv) {
}
google::InitGoogleLogging(argv[0]);
- google::LogToStderr();
HTTPServer::getInstance(32954, 32955, NULL); // bind to some random tcp sockets for ioprocessor tests
@@ -94,6 +138,14 @@ int main(int argc, char** argv) {
delayFactor = strTo<double>(dfEnv);
}
+ const char* envBenchmarkRuns = getenv("USCXML_BENCHMARK_ITERATIONS");
+ if (envBenchmarkRuns != NULL) {
+ benchmarkRuns = strTo<size_t>(envBenchmarkRuns);
+ google::SetStderrLogging(3);
+ } else {
+ google::LogToStderr();
+ }
+
int option;
while ((option = getopt(argc, argv, "fd:b:")) != -1) {
switch(option) {
@@ -111,11 +163,6 @@ int main(int argc, char** argv) {
}
}
- const char* envBenchmarkRuns = getenv("USCXML_BENCHMARK_ITERATIONS");
- if (envBenchmarkRuns != NULL) {
- benchmarkRuns = strTo<size_t>(envBenchmarkRuns);
- }
-
documentURI = argv[optind];
LOG(INFO) << "Processing " << documentURI << (withFlattening ? " FSM converted" : "") << (delayFactor ? "" : " with delays *= " + toStr(delayFactor)) << (benchmarkRuns > 0 ? " for " + toStr(benchmarkRuns) + " benchmarks" : "");
@@ -162,50 +209,59 @@ int main(int argc, char** argv) {
W3CStatusMonitor* vm = new W3CStatusMonitor();
interpreter.addMonitor(vm);
- if (benchmarkRuns > 0) {
- LOG(INFO) << "Benchmarking " << documentURI << (withFlattening ? " FSM converted" : "") << (delayFactor ? "" : " with delays *= " + toStr(delayFactor));
+ LOG(INFO) << "Benchmarking " << documentURI << (withFlattening ? " FSM converted" : "") << (delayFactor ? "" : " with delays *= " + toStr(delayFactor));
+
+ size_t remainingRuns = benchmarkRuns;
+ size_t microSteps = 0;
- InterpreterState state = interpreter.getState();
+ Timer tTotal;
+ tTotal.start();
- double avg = 0;
+ double avg = 0;
#ifdef BUILD_PROFILING
- double avgDm = 0;
- double avgStep = 0;
+ double avgDm = 0;
+ double avgStep = 0;
#endif
- size_t remainingRuns = benchmarkRuns;
- uint64_t start = tthread::chrono::system_clock::now();
-
- while(remainingRuns-- > 0) {
- Timer t;
- t.start();
- for(;;) {
- state = interpreter.step(true);
- if (state == USCXML_FINISHED) {
+
+ while(remainingRuns-- > 0) {
+ Timer t;
+ microSteps = 0;
+
+ InterpreterState state = interpreter.getState();
+
+ for(;;) {
+ state = interpreter.step(true);
+ microSteps++;
+ if (state == USCXML_INITIALIZED) {
+ t.start();
+ } else if (state == USCXML_FINISHED) {
#ifdef BUILD_PROFILING
- avgDm += interpreter.getDataModel().timer.elapsed;
- interpreter.getDataModel().timer.reset();
- avgStep += interpreter.timer.elapsed;
+ avgDm += interpreter._impl->_dataModel.timer.elapsed;
+ interpreter._impl->_dataModel.timer.reset();
+ avgStep += interpreter.timer.elapsed;
#endif
- }
- if (state < 0)
- break;
- }
- t.stop();
- avg += t.elapsed;
- interpreter.reset();
- }
- uint64_t totalDuration = tthread::chrono::system_clock::now() - start;
- std::cout << benchmarkRuns << " iterations in " << totalDuration << " ms" << std::endl;
- std::cout << (avg * 1000.0) / (double)benchmarkRuns << " ms on average" << std::endl;
+ }
+ if (state < 0)
+ break;
+ }
+ assert(retCode == EXIT_SUCCESS);
+ t.stop();
+ avg += t.elapsed;
+ interpreter.reset();
+ std::cout << "." << std::flush;
+ }
+
+ tTotal.stop();
+
+ std::cout << benchmarkRuns << " iterations" << std::endl;
+ std::cout << tTotal.elapsed * 1000.0 << " ms in total" << std::endl;
+ std::cout << (avg * 1000.0) / (double)benchmarkRuns << " ms per execution" << std::endl;
+ std::cout << microSteps << " microsteps per iteration" << std::endl;
+ std::cout << (avg * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep" << std::endl;
#ifdef BUILD_PROFILING
- std::cout << (avgDm * 1000.0) / (double)benchmarkRuns << " ms in datamodel" << std::endl;
- std::cout << (avgStep * 1000.0) / (double)benchmarkRuns << " ms in microsteps" << std::endl;
+ std::cout << (avgDm * 1000.0) / (double)benchmarkRuns << " ms in datamodel" << std::endl;
+ std::cout << ((avg - avgDm) * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep \\wo datamodel" << std::endl;
#endif
-
- } else {
- interpreter.start();
- while(interpreter.runOnMainThread(25));
- }
}
} catch(Event e) {
std::cout << e << std::endl;
diff --git a/test/w3c/analyze_tests.pl b/test/w3c/analyze_tests.pl
index b891066..7a6ed08 100755
--- a/test/w3c/analyze_tests.pl
+++ b/test/w3c/analyze_tests.pl
@@ -68,7 +68,7 @@ while ($block = <FILE>) {
# Test Epilog ========
if ($block =~
/
- Test\s(\S+)\sReason:\n
+ Test\s(\S+)\.\n
/x ) {
$test->{$currTest}->{'status'} = lc($1);
next;
@@ -85,6 +85,38 @@ while ($block = <FILE>) {
# next; - no next as this is part of the actual test output we need to scan below
}
+ # Performance ========
+ if ($block =~
+ /
+ (\d+)\siterations\n
+ ([\d\.]+)\sms\sin\stotal\n
+ ([\d\.]+)\sms\sper\sexecution\n
+ (\d+)\smicrosteps\sper\siteration\n
+ ([\d\.]+)\sms\sper\smicrostep\n
+ ([\d\.]+)\sms\sin\sdatamodel\n
+ ([\d\.]+)\sms\sper\smicrostep\s\\wo\sdatamodel\n
+ /x ) {
+ $test->{$currTest}->{'benchmark'}->{'iterations'} = $1;
+ $test->{$currTest}->{'benchmark'}->{'total'} = $2;
+ $test->{$currTest}->{'benchmark'}->{'perExecution'} = $3;
+ $test->{$currTest}->{'benchmark'}->{'mirosteps'} = $4;
+ $test->{$currTest}->{'benchmark'}->{'perMicrostep'} = $5;
+ $test->{$currTest}->{'benchmark'}->{'inDataModel'} = $6;
+ $test->{$currTest}->{'benchmark'}->{'inMicrostep'} = $7;
+ }
+
+ if ($block =~ /Size\sof\scompiled\sunit:\s(\d+)/x ) {
+ $test->{$currTest}->{'benchmark'}->{'size'} = $1;
+ }
+
+ if ($block =~ /Size\sof\scompiled\sunit\soptimized\sfor\sspeed:\s(\d+)/x ) {
+ $test->{$currTest}->{'benchmark'}->{'sizeFast'} = $1;
+ }
+
+ if ($block =~ /Size\sof\scompiled\sunit\soptimized\sfor\ssize:\s(\d+)/x ) {
+ $test->{$currTest}->{'benchmark'}->{'sizeSmall'} = $1;
+ }
+
# Minimization ========
# print $block;
@@ -240,7 +272,9 @@ if (@dataQuery > 0) {
if (defined($currVal->{$dataKey})) {
$currVal = $currVal->{$dataKey};
} else {
- die("no key $dataKey in structure:\n" . Dumper($currVal));
+ print STDERR "no key $dataKey in structure:\n" . Dumper($currVal);
+ $currVal = "N/A";
+ last;
}
}
print $seperator . $currVal;
diff --git a/test/w3c/run_generated_c_test.cmake b/test/w3c/run_generated_c_test.cmake
deleted file mode 100644
index 2c35762..0000000
--- a/test/w3c/run_generated_c_test.cmake
+++ /dev/null
@@ -1,51 +0,0 @@
-# convert given file to promela and run spin
-
-get_filename_component(TEST_FILE_NAME ${TESTFILE} NAME)
-execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTDIR})
-
-message(STATUS "${USCXML_TRANSFORM_BIN} -tc -i ${TESTFILE} -o ${OUTDIR}/${TEST_FILE_NAME}.machine.c")
-execute_process(COMMAND time -p ${USCXML_TRANSFORM_BIN} -tc -i ${TESTFILE} -o ${OUTDIR}/${TEST_FILE_NAME}.machine.c RESULT_VARIABLE CMD_RESULT)
-if(CMD_RESULT)
- message(FATAL_ERROR "Error running ${USCXML_TRANSFORM_BIN}: ${CMD_RESULT}")
-endif()
-message(STATUS "time for transforming to c machine")
-
-# message(FATAL_ERROR "PROJECT_BINARY_DIR: ${PROJECT_BINARY_DIR}")
-
-set(COMPILE_CMD
-"-o" "${OUTDIR}/${TEST_FILE_NAME}"
-"-Ofast"
-"-L${CMAKE_LIBRARY_OUTPUT_DIRECTORY}"
-"-luscxml64"
-"-include" "${OUTDIR}/${TEST_FILE_NAME}.machine.c"
-"-I${PROJECT_SOURCE_DIR}/contrib/prebuilt/${USCXML_PLATFORM_ID}/include"
-"-I${PROJECT_SOURCE_DIR}/contrib/prebuilt/${USCXML_PLATFORM_ID}/include/arabica"
-"-I${PROJECT_SOURCE_DIR}/contrib/prebuilt/include"
-"-I${CMAKE_BINARY_DIR}"
-"-I${PROJECT_BINARY_DIR}"
-"-I${PROJECT_SOURCE_DIR}/src"
-"-Wl,-rpath,${CMAKE_LIBRARY_OUTPUT_DIRECTORY}"
-"-DAUTOINCLUDE_TEST=ON"
-"${SCAFFOLDING_FOR_GENERATED_C}")
-
-message(STATUS "${GPP_BIN} ${COMPILE_CMD}")
-execute_process(
- COMMAND time -p ${GPP_BIN} ${COMPILE_CMD}
- WORKING_DIRECTORY ${OUTDIR} RESULT_VARIABLE CMD_RESULT)
-if(CMD_RESULT)
- message(FATAL_ERROR "Error running g++ ${GPP_BIN}: ${CMD_RESULT}")
-endif()
-message(STATUS "time for transforming to binary")
-
-message(STATUS "${OUTDIR}/${TEST_FILE_NAME}")
-execute_process(
- COMMAND time -p ${OUTDIR}/${TEST_FILE_NAME}
- WORKING_DIRECTORY ${OUTDIR}
- RESULT_VARIABLE CMD_RESULT)
-if(CMD_RESULT)
- message(FATAL_ERROR "Error running generated c test: ${CMD_RESULT}")
-endif()
-message(STATUS "time for execution")
-
-# message(STATUS "${TEST_OUT}")
-# file(WRITE ${OUTDIR}/${TEST_FILE_NAME}.pml.out ${TEST_OUT}) \ No newline at end of file
diff --git a/test/w3c/run_generated_test.cmake b/test/w3c/run_generated_test.cmake
new file mode 100644
index 0000000..cf13fd9
--- /dev/null
+++ b/test/w3c/run_generated_test.cmake
@@ -0,0 +1,87 @@
+# convert given file to promela and run spin
+
+set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/contrib/cmake)
+include("${CMAKE_MODULE_PATH}/FileInformation.cmake")
+
+get_filename_component(TEST_FILE_NAME ${TESTFILE} NAME)
+execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTDIR})
+
+message(STATUS "${USCXML_TRANSFORM_BIN} -t${TARGETLANG} -i ${TESTFILE} -o ${OUTDIR}/${TEST_FILE_NAME}.machine.c")
+execute_process(COMMAND time -p ${USCXML_TRANSFORM_BIN} -t${TARGETLANG} -i ${TESTFILE} -o ${OUTDIR}/${TEST_FILE_NAME}.machine.c RESULT_VARIABLE CMD_RESULT)
+if(CMD_RESULT)
+ message(FATAL_ERROR "Error running ${USCXML_TRANSFORM_BIN}: ${CMD_RESULT}")
+endif()
+message(STATUS "time for transforming to c machine")
+
+# message(FATAL_ERROR "PROJECT_BINARY_DIR: ${PROJECT_BINARY_DIR}")
+
+if (${TARGETLANG} STREQUAL "c")
+
+ # set(COMPILE_CMD_OBJ
+ # "-c" "${OUTDIR}/${TEST_FILE_NAME}.machine.c"
+ # "-o" "${OUTDIR}/${TEST_FILE_NAME}.machine.c.o"
+ # "-Ofast")
+ #
+ # message(STATUS "${GPP_BIN} ${COMPILE_CMD_OBJ}")
+ # execute_process(
+ # COMMAND time -p ${GPP_BIN} ${COMPILE_CMD_OBJ}
+ # WORKING_DIRECTORY ${OUTDIR} RESULT_VARIABLE CMD_RESULT)
+ # if(CMD_RESULT)
+ # message(FATAL_ERROR "Error running g++ ${GPP_BIN}: ${CMD_RESULT}")
+ # endif()
+ # file (SIZE "${OUTDIR}/${TEST_FILE_NAME}.machine.c.o" BINARY_SIZE)
+ # message("Size of compiled unit optimized for speed: ${BINARY_SIZE}")
+ #
+ # set(COMPILE_CMD_OBJ
+ # "-c" "${OUTDIR}/${TEST_FILE_NAME}.machine.c"
+ # "-o" "${OUTDIR}/${TEST_FILE_NAME}.machine.c.o"
+ # "-Os")
+ #
+ # message(STATUS "${GPP_BIN} ${COMPILE_CMD_OBJ}")
+ # execute_process(
+ # COMMAND time -p ${GPP_BIN} ${COMPILE_CMD_OBJ}
+ # WORKING_DIRECTORY ${OUTDIR} RESULT_VARIABLE CMD_RESULT)
+ # if(CMD_RESULT)
+ # message(FATAL_ERROR "Error running g++ ${GPP_BIN}: ${CMD_RESULT}")
+ # endif()
+ # file (SIZE "${OUTDIR}/${TEST_FILE_NAME}.machine.c.o" BINARY_SIZE)
+ # message("Size of compiled unit optimized for size: ${BINARY_SIZE}")
+
+ set(COMPILE_CMD_BIN
+ "-o" "${OUTDIR}/${TEST_FILE_NAME}"
+ "-Ofast"
+ "-L${CMAKE_LIBRARY_OUTPUT_DIRECTORY}"
+ "-luscxml64"
+ "-include" "${OUTDIR}/${TEST_FILE_NAME}.machine.c"
+ "-I${PROJECT_SOURCE_DIR}/contrib/prebuilt/${USCXML_PLATFORM_ID}/include"
+ "-I${PROJECT_SOURCE_DIR}/contrib/prebuilt/${USCXML_PLATFORM_ID}/include/arabica"
+ "-I${PROJECT_SOURCE_DIR}/contrib/prebuilt/include"
+ "-I${CMAKE_BINARY_DIR}"
+ "-I${PROJECT_BINARY_DIR}"
+ "-I${PROJECT_SOURCE_DIR}/src"
+ "-Wl,-rpath,${CMAKE_LIBRARY_OUTPUT_DIRECTORY}"
+ "-DAUTOINCLUDE_TEST=ON"
+ "${SCAFFOLDING_FOR_GENERATED_C}")
+
+ message(STATUS "${GPP_BIN} ${COMPILE_CMD_BIN}")
+ execute_process(
+ COMMAND time -p ${GPP_BIN} ${COMPILE_CMD_BIN}
+ WORKING_DIRECTORY ${OUTDIR} RESULT_VARIABLE CMD_RESULT)
+ if(CMD_RESULT)
+ message(FATAL_ERROR "Error running g++ ${GPP_BIN}: ${CMD_RESULT}")
+ endif()
+ message(STATUS "time for transforming to binary")
+
+ message(STATUS "${OUTDIR}/${TEST_FILE_NAME}")
+ execute_process(
+ COMMAND time -p ${OUTDIR}/${TEST_FILE_NAME}
+ WORKING_DIRECTORY ${OUTDIR}
+ RESULT_VARIABLE CMD_RESULT)
+ if(CMD_RESULT)
+ message(FATAL_ERROR "Error running generated c test: ${CMD_RESULT}")
+ endif()
+ message(STATUS "time for execution")
+endif()
+
+# message(STATUS "${TEST_OUT}")
+# file(WRITE ${OUTDIR}/${TEST_FILE_NAME}.pml.out ${TEST_OUT}) \ No newline at end of file