From 38da34e8ba7956bed2e4703289ed70e3f6aade52 Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Fri, 15 Jan 2016 14:42:06 +0100 Subject: Working on C transformation --- contrib/cmake/FileInformation.cmake | 187 +++ contrib/cmake/FileInformation.cmd | 20 + contrib/cmake/FileInformation.sh | 95 ++ contrib/cmake/FileInformation.vbs | 42 + src/uscxml/Interpreter.cpp | 79 +- src/uscxml/Interpreter.h | 8 +- .../plugins/datamodel/promela/PromelaDataModel.cpp | 2 +- src/uscxml/transform/ChartToC copy.cpp | 1617 ++++++++++++++++++++ src/uscxml/transform/ChartToC.cpp | 303 ++-- src/uscxml/transform/ChartToC.h | 1 - test/CMakeLists.txt | 435 ++++-- test/ctest/CTestCustom.ctest.in | 148 +- test/src/test-c-machine.cpp | 42 +- test/src/test-c-machine.machine.c | 350 +++-- test/src/test-lifecycle.cpp | 26 +- test/src/test-w3c.cpp | 146 +- test/w3c/analyze_tests.pl | 38 +- test/w3c/run_generated_c_test.cmake | 51 - test/w3c/run_generated_test.cmake | 87 ++ 19 files changed, 3032 insertions(+), 645 deletions(-) create mode 100755 contrib/cmake/FileInformation.cmake create mode 100755 contrib/cmake/FileInformation.cmd create mode 100755 contrib/cmake/FileInformation.sh create mode 100755 contrib/cmake/FileInformation.vbs create mode 100644 src/uscxml/transform/ChartToC copy.cpp delete mode 100644 test/w3c/run_generated_c_test.cmake create mode 100644 test/w3c/run_generated_test.cmake 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 lock(_mutex); + std::cerr << "Config: {"; + printNodeSet(interpreter.getConfiguration()); + std::cerr << "}" << std::endl; +} + void StateTransitionMonitor::printNodeSet(const Arabica::XPath::NodeSet& 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 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 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 >::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 lock(_mutex); - + + if (_sendQueue) { + _sendQueue->stop(); + std::map >::iterator sendIter = _sendIds.begin(); + while(sendIter != _sendIds.end()) { + _sendQueue->cancelEvent(sendIter->first); + sendIter = _sendIds.erase(sendIter); + } + _sendQueue->start(); + } + std::map::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& 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& c } else if (iequals(TAGNAME(content), _nsInfo.xmlNSPrefix + "log")) { // --- LOG -------------------------- Arabica::DOM::Element logElem = (Arabica::DOM::Element)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& state, bool moreComing); virtual void beforeEnteringState(uscxml::Interpreter interpreter, const Arabica::DOM::Element& state, bool moreComing); - + virtual void beforeMicroStep(uscxml::Interpreter interpreter); + protected: static tthread::recursive_mutex _mutex; void printNodeSet(const Arabica::XPath::NodeSet& 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 . + * @endcond + */ + +#include "uscxml/transform/ChartToFSM.h" +#include "uscxml/transform/ChartToC.h" +#include "uscxml/debug/Complexity.h" +#include +#include +#include "uscxml/UUID.h" +#include "uscxml/DOMUtils.h" +#include +#include +#include + +#include +#include + +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(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 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 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 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 // explicit types" << std::endl; + stream << "#include // 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 state(_states[i]); + + if (i == 0) { + // root state - we need to perform some initialization here + NodeSet 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 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 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 initial = filterChildElements(_nsInfo.xmlNSPrefix + "initial", state); + if (initial.size() > 0) { + NodeSet 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 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 transition(_transitions[i]); + if (iequals(TAGNAME_CAST(transition.getParentNode()), "initial")) + continue; + + NodeSet 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(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& 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 elem = Arabica::DOM::Element(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 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 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 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 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 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 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 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 datas = filterChildElements(_nsInfo.xmlNSPrefix + "data", _scxml, true); + if (datas.size() > 0) { + size_t dataIndexOffset = 0; + Node parent; + size_t distinctParents = 0; + + if (_binding == InterpreterImpl::EARLY) { + Element(_states[0]).setAttribute("dataIndex", "0"); + distinctParents = 1; + } else { + for (int i = 0; i < datas.size(); i++) { + Element data(datas[i]); + if (data.getParentNode() != parent) { + distinctParents++; + } + } + } + + parent = Node(); + + stream << "static scxml_elem_data scxml_elem_datas[" << datas.size() + distinctParents << "] = {" << std::endl; + for (int i = 0; i < datas.size(); i++) { + Element data(datas[i]); + if (data.getParentNode().getParentNode() != parent) { + if (_binding == InterpreterImpl::LATE) { + if (i > 0) { + stream << " { NULL, NULL, NULL, NULL }," << std::endl; + dataIndexOffset++; + } + Element(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 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 params = filterChildElements(_nsInfo.xmlNSPrefix + "param", _scxml, true); + if (params.size() > 0) { + Node parent; + size_t distinctParents = 0; + for (int i = 0; i < params.size(); i++) { + Element param(params[i]); + if (param.getParentNode() != parent) { + distinctParents++; + } + } + parent = Node(); + + stream << "static scxml_elem_param scxml_elem_params[" << params.size() + distinctParents << "] = {" << std::endl; + for (int i = 0; i < params.size(); i++) { + Element param(params[i]); + if (param.getParentNode() != parent) { + Element(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 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 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 contents = filterChildElements(_nsInfo.xmlNSPrefix + "content", send); + if (contents.size() > 0) { + std::stringstream ss; + NodeList 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 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 donedata(donedatas[i]); + stream << " { "; + + // parent + stream << ATTR_CAST(donedata.getParentNode(), "documentOrder") << ", "; + + NodeSet contents = filterChildElements(_nsInfo.xmlNSPrefix + "content", donedata); + if (contents.size() > 0) { + std::stringstream ss; + NodeList 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 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 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(_states[j]))) { + completion.push_back(_states[j]); + } + } else { + if (_states[j].getParentNode() == state.getParentNode() && !isHistory(Element(_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 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 initStates; + NodeList childs = state.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE) + continue; + if (isState(Element(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 { // + 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 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 targets = tokenize(ATTR(transition, "target")); + + std::string targetBools; + for (int j = 0; j < _states.size(); j++) { + Element 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 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 exitSet = computeExitSet(transition); + for (unsigned int j = 0; j < _states.size(); j++) { + Element 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 ChartToC::computeExitSet(const Arabica::DOM::Element& transition) { + + NodeSet statesToExit; + if (!isTargetless(transition)) { + Arabica::DOM::Node domain = getTransitionDomain(transition); + if (!domain) + return statesToExit; + for (unsigned int j = 0; j < _states.size(); j++) { + const Node& 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 ChartToC::inPostFixOrder(const std::set& elements, const Element& root) { + NodeSet nodes; + inPostFixOrder(elements, root, nodes); + return nodes; +} + +void ChartToC::inPostFixOrder(const std::set& elements, const Element& root, NodeSet& nodes) { + NodeList children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE) + continue; + Arabica::DOM::Element 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 childElem(children.item(i)); + + if (elements.find(TAGNAME(childElem)) != elements.end()) { + nodes.push_back(childElem); + } + } +} + +NodeSet ChartToC::inDocumentOrder(const std::set& elements, const Element& root) { + NodeSet nodes; + inDocumentOrder(elements, root, nodes); + return nodes; +} + +void ChartToC::inDocumentOrder(const std::set& elements, const Element& root, NodeSet& nodes) { + if (elements.find(TAGNAME(root)) != elements.end()) { + nodes.push_back(root); + } + + NodeList children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE) + continue; + Arabica::DOM::Element 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 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 onexit = filterChildElements(_nsInfo.xmlNSPrefix + "onexit", state); @@ -860,44 +857,39 @@ void ChartToC::writeElementInfo(std::ostream& stream) { } NodeSet 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 donedata(donedatas[i]); - stream << " { "; - - // parent - stream << ATTR_CAST(donedata.getParentNode(), "documentOrder") << ", "; - - NodeSet contents = filterChildElements(_nsInfo.xmlNSPrefix + "content", donedata); - if (contents.size() > 0) { - std::stringstream ss; - NodeList 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 donedata(donedatas[i]); + stream << " { "; + + // parent + stream << ATTR_CAST(donedata.getParentNode(), "documentOrder") << ", "; + + NodeSet contents = filterChildElements(_nsInfo.xmlNSPrefix + "content", donedata); + if (contents.size() > 0) { + std::stringstream ss; + NodeList 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 _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 #include // 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(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 +#include +#include +#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(dfEnv); } + const char* envBenchmarkRuns = getenv("USCXML_BENCHMARK_ITERATIONS"); + if (envBenchmarkRuns != NULL) { + benchmarkRuns = strTo(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(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 = ) { # 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 = ) { # 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 -- cgit v0.12