diff options
author | Stefan Radomski <sradomski@mintwerk.de> | 2016-02-11 09:40:02 (GMT) |
---|---|---|
committer | Stefan Radomski <sradomski@mintwerk.de> | 2016-02-11 09:40:02 (GMT) |
commit | 7b428e5435f83a7e7db37094a9197afa2dd09bf5 (patch) | |
tree | 8e23dcc47322ddd79ada2bdbb5f0315266b1e1b4 | |
parent | 179fe8cd5cf53893ad1783ff0ff41cf94e24a59b (diff) | |
download | uscxml-7b428e5435f83a7e7db37094a9197afa2dd09bf5.zip uscxml-7b428e5435f83a7e7db37094a9197afa2dd09bf5.tar.gz uscxml-7b428e5435f83a7e7db37094a9197afa2dd09bf5.tar.bz2 |
Some tidying up of ANSI-C transformation
-rw-r--r-- | README.md | 21 | ||||
-rw-r--r-- | apps/uscxml-transform.cpp | 39 | ||||
-rw-r--r-- | docs/COMPARISON.md | 89 | ||||
-rw-r--r-- | docs/GETTING_STARTED.md (renamed from docs/untitled.txt) | 0 | ||||
-rw-r--r-- | docs/NATIVE_CODE.md | 142 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToC.cpp | 203 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToC.h | 2 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToVHDL.cpp | 112 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToVHDL.h | 6 | ||||
-rw-r--r-- | test/CMakeLists.txt | 25 | ||||
-rw-r--r-- | test/src/test-c-inline.c | 40 | ||||
-rw-r--r-- | test/src/test-c-inline.c.scxml.c | 951 | ||||
-rw-r--r-- | test/src/test-c-machine.cpp | 42 | ||||
-rw-r--r-- | test/src/test-c-machine.scxml.c (renamed from test/src/test-c-machine.machine.c) | 228 |
14 files changed, 1727 insertions, 173 deletions
@@ -55,7 +55,7 @@ frontend. It implements the following features: * C# bindings * PHP module for apache and cli interpreter (discontinued) * <b>Interactive Debugger</b> - * Accessible via a [web-frontend](http://htmlpreview.github.io/?https://github.com/tklab-tud/uscxml/blob/master/apps/uscxml-debugger.html) + * Accessible via a [web-frontend](http://htmlpreview.github.io/?apps/uscxml-debugger.html) * Complete with user-defined breakpoints, data model inspection and stepping ### Transformer @@ -65,21 +65,24 @@ made available via the <tt>uscxml-transform</tt> binary. It is a general tool for SCXML documents and currently implements the following features: * Transformations onto - * [Flattened SCXML documents](https://github.com/tklab-tud/uscxml/blob/master/src/uscxml/transform/ChartToFlatSCXML.cpp) in which only a single state is ever active + * [Flattened SCXML documents](src/uscxml/transform/ChartToFlatSCXML.cpp) in which only a single state is ever active * Resulting documents require slight adaptations to a compliant interpreter for donedata, the <tt>In</tt> predicate and invokers. * Semantic equivalence is shown via IRP tests. - * [ANSI C native code](https://github.com/tklab-tud/uscxml/blob/master/src/uscxml/transform/ChartToC.cpp) for easy embedding of SCXML state-charts in C and C++ programs + * [ANSI C native code](src/uscxml/transform/ChartToC.cpp) for easy embedding of SCXML state-charts in C and C++ programs * No custom I/O processors implemented in scaffolding just yet. - * [PROMELA programs](https://github.com/tklab-tud/uscxml/blob/master/src/uscxml/transform/ChartToPromela.cpp) for model-checking via linear temporal logic with the SPIN model-checker. + * To get started with transforming and embedding ANSI C code, read the [inline SCXML document](docs/NATIVE_CODE.md). + * [PROMELA programs](src/uscxml/transform/ChartToPromela.cpp) for model-checking via linear temporal logic with the SPIN model-checker. * Only defined for the <tt>promela</tt> and <tt>null</tt> datamodel. - * [Minimized SCXML documents](https://github.com/tklab-tud/uscxml/blob/master/src/uscxml/transform/ChartToMinimalSCXML.cpp) with dead states and executable content removed + * [Minimized SCXML documents](src/uscxml/transform/ChartToMinimalSCXML.cpp) with dead states and executable content removed * Minimization is performed dynamically by marking elements as visited and removing unvisited elements. * Annotations of the transitions exit set entry set, priority, conflicts, domain +Currently, we support a transformation from SCXML onto ANSI C. + ### Test Reports * We continuously run the [W3C IRP tests](http://www.w3.org/Voice/2013/scxml-irp/) for SCXML. -* Some tests are [excluded](https://github.com/tklab-tud/uscxml/blob/master/test/ctest/CTestCustom.ctest.in). +* Some tests are [excluded](test/ctest/CTestCustom.ctest.in). To run the tests yourself, you need to generate the build environment and pass <tt>-DBUILD_TESTS=ON</tt> via CMake: @@ -100,14 +103,14 @@ so maybe restrict yourself to some subset. uSCXML itself is distributed under the Simplified BSD license as in, do not sue us and do not misrepresent authorship. Please have a look at the licenses of the [libraries we depend -upon](https://github.com/tklab-tud/uscxml/blob/master/docs/BUILDING.md#build-dependencies) as well. +upon](docs/BUILDING.md#build-dependencies) as well. ## Performance We did some performance measurements in the scope of the C transformation. As you can see in the figure below, for most IRP tests we average to a duration of 5-20us per microstep on an early 2015 MacBook Pro 13" with 3.1GHz in the case -of [generated/compiled C](https://github.com/tklab-tud/uscxml/blob/master/test/src/test-c-machine.machine.c). For interpretation at runtime, we average at around 70-130us per +of [generated/compiled C](test/src/test-c-machine.machine.c). For interpretation at runtime, we average at around 70-130us per microstep. The generated C is rather optimized while the focus of the interpreter is more on correctness, feature completeness and extensibility. However, there are some lessons learned that are yet to be applied for the @@ -116,7 +119,7 @@ interpreter. <img src="https://raw.github.com/tklab-tud/uscxml/master/docs/Performance_Microstep.png" width="500px" /> For the tests, we took the -[highest precision timer](https://github.com/tklab-tud/uscxml/blob/master/src/uscxml/concurrency/Timer.cpp) +[highest precision timer](src/uscxml/concurrency/Timer.cpp) we could attain and measured how long the execution of a given SCXML IRP test took while subtracting initialization, tear-down and the time spent in the data-model's routines. Time is averaged over 1.000 iterations. diff --git a/apps/uscxml-transform.cpp b/apps/uscxml-transform.cpp index 857a160..a5aa9ec 100644 --- a/apps/uscxml-transform.cpp +++ b/apps/uscxml-transform.cpp @@ -275,11 +275,44 @@ int main(int argc, char** argv) { } else { interpreter = Interpreter::fromURL(inputFile); } - if (!interpreter) { - LOG(ERROR) << "Cannot create interpreter from " << inputFile; - exit(EXIT_FAILURE); + } catch (Event e) { + // we will reattempt below, not yet a fatal error + } catch (const std::exception &e) { + std::cout << e.what() << std::endl; + } + + if (!interpreter) { + URL tmp(inputFile); + tmp.toAbsoluteCwd(); + std::stringstream contentSS; + contentSS << tmp; + + std::string inlineBeginMarker = "INLINE SCXML BEGIN\n"; + std::string inlineEndMarker = "\nINLINE SCXML END"; + + size_t inlineSCXMLBegin = contentSS.str().find(inlineBeginMarker); + if (inlineSCXMLBegin != std::string::npos) { + inlineSCXMLBegin += inlineBeginMarker.size(); + size_t inlineSCXMLEnd = contentSS.str().find(inlineEndMarker); + std::string inlineSCXMLContent = contentSS.str().substr(inlineSCXMLBegin, inlineSCXMLEnd - inlineSCXMLBegin); + try { + interpreter = Interpreter::fromXML(inlineSCXMLContent, tmp); + } catch (Event e) { + std::cout << e << std::endl; + } catch (const std::exception &e) { + std::cout << e.what() << std::endl; + } } + } + + if (!interpreter) { + LOG(ERROR) << "Cannot create interpreter from " << inputFile; + exit(EXIT_FAILURE); + + } + + try { if (verbose) { std::list<InterpreterIssue> issues = interpreter.validate(); for (std::list<InterpreterIssue>::iterator issueIter = issues.begin(); issueIter != issues.end(); issueIter++) { diff --git a/docs/COMPARISON.md b/docs/COMPARISON.md new file mode 100644 index 0000000..94e8d3b --- /dev/null +++ b/docs/COMPARISON.md @@ -0,0 +1,89 @@ +# Comparison of SCXML Interpreters + +In this document, I will make an attempt to compare and measure the performance +of the various, freely available SCXML interpreters. If you are the author of +one of these interpreters and feel that I misrepresented your work, please do +not hesitate to contact me and I will reevaluate / correct any factual errors. + +This selection is based on the list of available implementations on the [SCXML +wiki](https://en.wikipedia.org/wiki/SCXML) page, plus a few interpreters I know +from the [W3C mailing list](https://lists.w3.org/Archives/Public/www-voice/) +and the [SCXML workshops](http://scxmlworkshop.de). I will list all +interpreters known to me, but only benchmark those that pass the W3C IRP tests +as is required for an actual SCXML interpreter. + +# Methodology + +The benchmarks were performed with a [huge +SCXML](https://github.com/tklab-tud/uscxml/tree/master/test/w3c/compound) file +containing all of the automatic W3C IRP tests that do not rely on timeouts to +pass. + +## scxmlcc + +| Platforms | Tested on | Tested | Website | +|---------------|---------------------|------------------|---------------| +| Linux only | Debian Jessie 64Bit | **No**: Subset of SCXML implemented is insufficient for SCXML IRP tests. | [http://scxmlcc.org](http://scxmlcc.org) | + +### How to build + + $ sudo apt-get install build-essential libboost-all-dev autorevision + $ git clone https://github.com/jp-embedded/scxmlcc.git + $ cd scxmlcc/src + $ make + +### Evaluation + + $ ./scxmlcc -i ./test-ecma-all.scxml |sort |uniq + warning: event asteriks not currently supported + warning: event tokens not currently supported + warning: parallel support is not fully implemented/tested + warning: unknown action type 'script' + warning: unknown item 'assign' in <onentry> or <onexit> + warning: unknown item 'assign' in <transition> + warning: unknown item 'cancel' in <transition> + warning: unknown item 'datamodel' in <state> + warning: unknown item 'donedata' in <state> + warning: unknown item 'foreach' in <onentry> or <onexit> + warning: unknown item 'if' in <onentry> or <onexit> + warning: unknown item 'invoke' in <state> + warning: unknown item 'send' in <onentry> or <onexit> + warning: unknown item 'send' in <transition> + +The subset of SCXML implemented in <tt>scxmlcc</tt> is insufficient to run the +performance / compliance benchmarks. + +## SCXML Lab + +| Platforms | Tested on | Tested | Website | +|---------------|---------------------|-----------|---------------| +| HTML5 | Safari 9.0.3 | **No**: Subset of SCXML implemented is insufficient for SCXML IRP tests. | [http://www.ling.gu.se/~lager/Labs/SCXML-Lab/](http://www.ling.gu.se/~lager/Labs/SCXML-Lab/) | + +I pasted the file above into their web-frontend and got a <tt>validation-error</tt> + + Unexpected attribute 'datamodel' in <scxml>. Hint: + Valid attributes are: 'id', 'initialstate', 'version', 'xmlns'. + +The <tt>datamodel</tt> is indeed not required for a compliant interpreter, but +we will not be able to pass any meaningful subset of the SCXML IRP tests +without support for a datamodel. + +## Legian + +| Platforms | Tested on | Tested | Website | +|---------------|---------------------|-----------|---------------| +| Java | Java(TM) SE (build 1.8.0_45-b14) | **No**: Subset of SCXML implemented is insufficient for SCXML IRP tests. | [https://github.com/pelatimtt/Legian](https://github.com/pelatimtt/Legian/) | + +Does not claim W3C compliance and will, therefore, not pass the compound IRP tests. + +## Qt SCXML Engine + +| Platforms | Tested on | Tested | Website | +|---------------|---------------------|-----------|---------------| +| Any | Mac OSX 10.11.3 with Macports 2.3.4 | **No**: Subset of SCXML implemented is insufficient for SCXML IRP tests. | [https://qt.gitorious.org/qt-labs/scxml](https://qt.gitorious.org/qt-labs/scxml/) | + +[No +support](https://qt.gitorious.org/qt-labs/scxml?p=qt-labs:scxml.git;a=blob_plain;f=doc/scxml.qdoc;hb=HEAD) +for <tt><donedata></tt>, <tt><finalize></tt>. Furthermore the +<tt>profile</tt> (now <tt>datamodel</tt> with finalized SCXML recommendation) +attribute is ignored. diff --git a/docs/untitled.txt b/docs/GETTING_STARTED.md index 8c585bf..8c585bf 100644 --- a/docs/untitled.txt +++ b/docs/GETTING_STARTED.md diff --git a/docs/NATIVE_CODE.md b/docs/NATIVE_CODE.md new file mode 100644 index 0000000..91af599 --- /dev/null +++ b/docs/NATIVE_CODE.md @@ -0,0 +1,142 @@ +# Generating Native Code + +You can use the <tt>uscxml-transform</tt> tool to create native code from an +SCXML document. In this case, you will not use an instance of the +<tt>uscxml::Interpreter</tt> class, but instantiate an SCXML context from a +native description of the state-chart. + +## Embedding ANSI C + +To embed the control flow described within an SCXML document in most variances +of the C language, we provide a transformation onto ANSI C (C89) as a proper +subset of virtually any more modern C/C++ dialect. There are two general +approaches to achieve this. In any case, you need to transform your SCXML +state-chart onto ANSI C by invoking <tt>uscxml-transform</tt>: + + $ uscxml-transform -tc -i INPUT_FILE -o OUTPUT_FILE + +This transformation will create a single file that you can compile and link or +include directly. I advice to include the file into another compilation unit +and not to compile it directly, as it allows for more convenience and is +generally a more flexible approach. The file will contain: + +1. A set of pre-processor **macros** for convenience and definitions, all starting +with an <tt>USCXML_</tt> prefix. Of special note are the following macros that +allow you to influence important characteristics of you state-machine. + + * <tt>**USCXML_NR_STATES_TYPE** / **USCXML_NR_TRANS_TYPE**</tt>: + + The type for unsigned integers that is of sufficient size to contain + the number of states / transitions of your largest state machine. The + transformation will automatically choose one of the <tt>uint*_t</tt> + types, though a popular extension, they are only available in C99 + (<tt>stdint.h</tt>). Also, if you like to reuse parts of the file (e.g. + the types below) in another compilation unit, you might need to + predefine them explicitly to a sufficient size. + + * <tt>**USCXML_MAX_NR_STATES_BYTES** / **USCXML_MAX_NR_TRANS_BYTES**</tt>: + + The minimial size for the bit-arrays as <tt>char[N]</tt> containing the + states and transitions in the various types and on the stack during a + microstep. It has to be larger or equal to the smallest positive + integer that, when multiplied by 8 is larger or equal to the number of + states and transitions repsectively. + + In other words, make sure that + <tt>states[USCXML_MAX_NR_STATES_BYTES]</tt> has room for one bit per + state and <tt>transitions[USCXML_MAX_NR_TRANS_BYTES]</tt> for one bit + per transition. + + * There are some other macros defined, but they are rather for + micro-optimizations. Have a look at a generated file. + +2. All compound data **types** (<tt>struct</tt>) to encode an SCXML state-machine. +These will refer to the macros above to require memory for a state-chart's +states and transitions, so make sure that the macros are set if you +conditionally include parts of the generated file and double-check that the +type definitions are the same in every compilation unit if you want to access +state-machines from other units (i.e. same value for macros above!). + +3. The actual **symbols** for one or many state-machines from the input SCXML +file. Their identifiers are all prefixed by an identifier derived from the +content of a given SCXML document. As such, if you transform any given SCXML +document twice, you might end up with duplicate symbols, yet again, the +state-chart's will be functionally identical as they contained the same content. + + In order for not having to guess the prefix when referring to any machine + in application code, the tranformation will define three additional macros: + + #ifndef USCXML_MACHINE + # define USCXML_MACHINE _uscxml_BC220711_machine + #endif + #define USCXML_MACHINE_0 _uscxml_BC220711_machine + #define USCXML_MACHINE_NAME_HERE _uscxml_BC220711_machine + + The first macro is useful if you only transformed a single SCXML + state-chart as it will always refer to the very first state-chart + encountered. If there is more than one SCXML state-chart within a document + (i.e. an invocation of nested machines) you can also refer to them by index + or their eventual name. + +4. Some **helper functions**, most notably bit operations for arbitrary length +bit arrays. + +5. The **micro-step function** <tt>uscxml_step</tt>, which will perform a +micro-step on a given context and delegate control flow accordingly. + +These elements are always contained and you can, selectively, disable their +inclusion by pre-defining respective macros (have a look at a generated source +file). + +Now in order to actually use an SCXML document to manage the control flow among +a set of functions, there are two general approaches. Both use the generated +ANSI C source code above, but require more or less resources at runtime as +detailled below. + +### Fully Compliant + +An SCXML interpreter does more than to perform a series of microsteps for event +over a set of states and transitions and there are quite a few responsibilities +not implemented in the generated ANSI C code: + +1. **Event Queues**: + + A compliant interpreter is required to maintain two event queues, an + internal and an external one. With the generated ANSI C source, these are + integrated via four callbacks and will need to be implemented in + user-supplied code: + + 1. <tt>**uscxml_ctx.dequeue_internal**</tt>: This callback is invoked + whenever the interpreter needs an event from the internal event queue. It + is passed an instance of a <tt>uscxml_ctx</tt> structure and is supposed to + return an opaque pointer to an event. If the internal queue is empty, + <tt>NULL</tt> is to be returned. + + 2. <tt>**uscxml_ctx.dequeue_external**</tt>: This callback is functionally + equivalent to <tt>uscxml_ctx.dequeue_internal</tt> but invoked, when an + external event is to be dequeued. + + 3. <tt>**uscxml_ctx.exec_content_send**</tt>: Whenever there is an + <tt><send></tt> element encountered in executable content, the generated + ANSI C code will invoke this callback with a context and an + <tt>uscxml_elem_send</tt> instance and the user code registered at the + callback is expected to handle the send request as per recommendation. + + 4. <tt>**uscxml_ctx.exec_content_raise**</tt>: This callback is invoked for + any <tt><raise></tt> element processed as part of executable content and + is expected to deliver an event to the internal event queue. + +2. **Transition Matching / Enabling** + + An event will match and enable a set of transitions. The generated ANSI C + source will already make sure that only valid sets of transitions can be + selected to constitute the optimal transition set for a microstep, but + user-supplied code will have to decide whether a transition is matched and + enabled. This is done via the <tt>**uscxml_ctx.is_enabled**</tt> callback. + It receives a context, a <tt>uscxml_transition</tt> structure and the + opaque event pointer and will have to return <tt>0</tt> for when the + transition is not matched and enabled by the given event and <tt>1</tt> if + it is. + + +### Light-Weight diff --git a/src/uscxml/transform/ChartToC.cpp b/src/uscxml/transform/ChartToC.cpp index f9eba98..c6be393 100644 --- a/src/uscxml/transform/ChartToC.cpp +++ b/src/uscxml/transform/ChartToC.cpp @@ -56,6 +56,15 @@ ChartToC::ChartToC(const Interpreter& other) : TransformerImpl(), _topMostMachin prepare(); findNestedMachines(); + if (_extensions.find("prefix") != _extensions.end()) { + _prefixes = new std::list<std::string>(); + std::pair<std::multimap<std::string, std::string>::iterator, + std::multimap<std::string, std::string>::iterator> keyRange = _extensions.equal_range("prefix"); + for (std::multimap<std::string, std::string>::iterator iter = keyRange.first; iter != keyRange.second; ++iter) { + _prefixes->push_back(iter->second); + } + } + } void ChartToC::setHistoryCompletion() { @@ -423,8 +432,8 @@ void ChartToC::writeTo(std::ostream& stream) { (*machIter)->writeExecContent(stream); (*machIter)->writeStates(stream); (*machIter)->writeTransitions(stream); + (*machIter)->writeMachineInfo(stream); } - writeMachineInfo(stream); writeHelpers(stream); writeFSM(stream); @@ -434,7 +443,9 @@ void ChartToC::writeTo(std::ostream& stream) { void ChartToC::writeForwardDeclarations(std::ostream& stream) { stream << "/* forward declare machines to allow references */" << std::endl; - stream << "extern const uscxml_machine uscxml_machines[" << toStr(_allMachines.size() + 1) << "];" << std::endl; + for (std::list<ChartToC*>::iterator machIter = _allMachines.begin(); machIter != _allMachines.end(); machIter++) { + stream << "extern const uscxml_machine " << (*machIter)->_prefix << "_machine;" << std::endl; + } stream << std::endl; } @@ -488,13 +499,15 @@ void ChartToC::findNestedMachines() { } void ChartToC::writeIncludes(std::ostream& stream) { - stream << "#include <stdint.h> /* explicit types */" << std::endl; + stream << "#ifndef USCXML_NO_STDTYPES_H" << std::endl; + stream << "# include <stdint.h> /* explicit types */" << std::endl; + stream << "#endif" << std::endl; stream << "#include <stddef.h> /* NULL */" << std::endl; stream << std::endl; } void ChartToC::writeMacros(std::ostream& stream) { - stream << "#ifndef USCXML_GEN_C_MACROS" << std::endl; + stream << "#ifndef USCXML_NO_GEN_C_MACROS" << std::endl; stream << std::endl; stream << "/**" << std::endl; stream << " * All macros used for the scxml types and functions" << std::endl; @@ -651,7 +664,7 @@ void ChartToC::writeMacros(std::ostream& stream) { stream << "#define USCXML_ELEM_PARAM_IS_SET(param) (param->name != NULL)" << std::endl; stream << "#define USCXML_MACHINE_IS_SET(machine) (machine->nr_states > 0)" << std::endl; stream << std::endl; - stream << "#define USCXML_GEN_C_MACROS" << std::endl; + stream << "#define USCXML_NO_GEN_C_MACROS" << std::endl; stream << "#endif" << std::endl; stream << std::endl; } @@ -659,11 +672,11 @@ void ChartToC::writeMacros(std::ostream& stream) { void ChartToC::writeTypes(std::ostream& stream) { stream << std::endl; - stream << "#ifndef USCXML_GEN_C_TYPES" << std::endl; + stream << "#ifndef USCXML_NO_GEN_C_TYPES" << std::endl; stream << std::endl; stream << "/**" << std::endl; stream << " * All types required to represent an SCXML state chart." << std::endl; - stream << " * Just predefine the USCXML_GEN_C_TYPES macro if you do not need them." << std::endl; + stream << " * Just predefine the USCXML_NO_GEN_C_TYPES macro if you do not need them." << std::endl; stream << " */" << std::endl; stream << std::endl; @@ -876,7 +889,7 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << " invoke_t invoke;" << std::endl; stream << "};" << std::endl; stream << std::endl; - stream << "#define USCXML_GEN_C_TYPES" << std::endl; + stream << "#define USCXML_NO_GEN_C_TYPES" << std::endl; stream << "#endif" << std::endl; stream << std::endl; } @@ -917,7 +930,7 @@ void ChartToC::writeHelpers(std::ostream& stream) { stream << "#endif" << std::endl; stream << std::endl; - stream << "#ifndef USCXML_BIT_OPERATIONS" << std::endl; + stream << "#ifndef USCXML_NO_BIT_OPERATIONS" << std::endl; stream << "/**" << std::endl; stream << " * Return true if there is a common bit in a and b." << std::endl; stream << " */" << std::endl; @@ -993,15 +1006,22 @@ void ChartToC::writeHelpers(std::ostream& stream) { stream << " };" << std::endl; stream << "}" << std::endl; stream << std::endl; - stream << "#define USCXML_BIT_OPERATIONS" << std::endl; + stream << "#define USCXML_NO_BIT_OPERATIONS" << std::endl; stream << "#endif" << std::endl; stream << std::endl; } void ChartToC::writeExecContentFinalize(std::ostream& stream) { + // needs to be written prior to invocation elem info NodeSet<std::string> finalizes = DOMUtils::inDocumentOrder(_nsInfo.xmlNSPrefix + "finalize", _scxml); + + if (finalizes.size() > 0) { + stream << "#ifndef USCXML_NO_EXEC_CONTENT" << std::endl; + stream << std::endl; + } + for (size_t i = 0; i < finalizes.size(); i++) { Element<std::string> finalize(finalizes[i]); NodeSet<std::string> execContent = filterChildType(Node_base::ELEMENT_NODE, finalize); @@ -1018,9 +1038,16 @@ void ChartToC::writeExecContentFinalize(std::ostream& stream) { } } + if (finalizes.size() > 0) { + stream << "#endif" << std::endl; + stream << std::endl; + } } void ChartToC::writeExecContent(std::ostream& stream) { + stream << "#ifndef USCXML_NO_EXEC_CONTENT" << std::endl; + stream << std::endl; + for (size_t i = 0; i < _states.size(); i++) { Element<std::string> state(_states[i]); @@ -1118,6 +1145,9 @@ void ChartToC::writeExecContent(std::ostream& stream) { } } + stream << "#endif" << std::endl; + stream << std::endl; + } void ChartToC::writeExecContent(std::ostream& stream, const Arabica::DOM::Node<std::string>& node, int indent) { @@ -1126,8 +1156,12 @@ void ChartToC::writeExecContent(std::ostream& stream, const Arabica::DOM::Node<s if (node.getNodeType() == Node_base::TEXT_NODE) { if (boost::trim_copy(node.getNodeValue()).length() > 0) { - std::string escaped = escape(node.getNodeValue()); - stream << escaped; + if (HAS_ATTR(_scxml, "datamodel") && ATTR(_scxml, "datamodel") == "native") { + stream << node.getNodeValue(); + } else { + std::string escaped = escape(node.getNodeValue()); + stream << escaped; + } } return; } @@ -1291,6 +1325,10 @@ void ChartToC::writeExecContent(std::ostream& stream, const Arabica::DOM::Node<s } void ChartToC::writeElementInfoInvocation(std::ostream& stream) { + + stream << "#ifndef USCXML_NO_ELEM_INFO" << std::endl; + stream << std::endl; + NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _scxml, true); if (invokes.size() > 0) { _hasElement.insert("invoke"); @@ -1321,6 +1359,15 @@ void ChartToC::writeElementInfoInvocation(std::ostream& stream) { stream << " /* machine */ "; if (HAS_ATTR(invoke, "md5sum")) { +#if 1 + size_t machIdx = 0; + for (std::list<ChartToC*>::iterator machIter = _allMachines.begin(); machIter != _allMachines.end(); machIter++, machIdx++) { + if ((*machIter)->_md5 == ATTR(invoke, "md5sum")) { + stream << "&" << (*machIter)->_prefix << "_machine"; + break; + } + } +#else size_t machIdx = 0; for (std::list<ChartToC*>::iterator machIter = _allMachines.begin(); machIter != _allMachines.end(); machIter++, machIdx++) { if ((*machIter)->_md5 == ATTR(invoke, "md5sum")) { @@ -1328,6 +1375,7 @@ void ChartToC::writeElementInfoInvocation(std::ostream& stream) { break; } } +#endif } else { stream << "NULL"; } @@ -1410,9 +1458,15 @@ void ChartToC::writeElementInfoInvocation(std::ostream& stream) { stream << std::endl; } + stream << "#endif" << std::endl; + stream << std::endl; + } void ChartToC::writeElementInfo(std::ostream& stream) { + stream << "#ifndef USCXML_NO_ELEM_INFO" << std::endl; + stream << std::endl; + NodeSet<std::string> foreachs = DOMUtils::inDocumentOrder(_nsInfo.xmlNSPrefix + "foreach", _scxml); if (foreachs.size() > 0) { _hasElement.insert("foreach"); @@ -1624,9 +1678,76 @@ void ChartToC::writeElementInfo(std::ostream& stream) { stream << "};" << std::endl; stream << std::endl; + stream << "#endif" << std::endl; + stream << std::endl; + } void ChartToC::writeMachineInfo(std::ostream& stream) { + + stream << "#ifndef USCXML_NO_ELEM_INFO" << std::endl; + stream << std::endl; + +#if 1 + size_t currIndex = 0; + char* currIndexStr = getenv("USCXML_CURRENT_MACHINE_INDEX"); + if (currIndexStr != NULL) { + currIndex = strTo<size_t>(currIndexStr); + } + + stream << "#ifndef USCXML_MACHINE" << std::endl; + stream << "# define USCXML_MACHINE " << _prefix << "_machine" << std::endl; + stream << "#endif" << std::endl; + + stream << "#define USCXML_MACHINE_" << toStr(currIndex) << " " << _prefix << "_machine" << std::endl; + + if (_name.size() > 0) { + std::string macroName = boost::to_upper_copy(escape(_name)); + boost::replace_all(macroName, "-", "_"); + stream << "#define USCXML_MACHINE_" << macroName << " " << _prefix << "_machine" << std::endl; + } + stream << std::endl; + + currIndex++; + setenv("USCXML_CURRENT_MACHINE_INDEX", toStr(currIndex).c_str(), 1); + + stream << "const uscxml_machine " << _prefix << "_machine = {" << std::endl; + stream << " /* flags */ 0," << std::endl; + stream << " /* nr_states */ " << _states.size() << "," << std::endl; + stream << " /* nr_transitions */ " << _transitions.size() << "," << std::endl; + stream << " /* name */ \"" << escape(_name) << "\"," << std::endl; + stream << " /* datamodel */ \"" << (HAS_ATTR(_scxml, "datamodel") ? ATTR(_scxml, "datamodel") : "null") << "\"," << std::endl; + stream << " /* uuid */ \"" << _md5 << "\"," << std::endl; + stream << " /* states */ " << "&" << _prefix << "_states[0], " << std::endl; + stream << " /* transitions */ " << "&" << _prefix << "_transitions[0], " << std::endl; + stream << " /* parent */ "; + if (_parentMachine != NULL) { + size_t parentIndex = 0; + for (std::list<ChartToC*>::iterator parentIter = _topMostMachine->_allMachines.begin(); + parentIter != _topMostMachine->_allMachines.end(); + parentIter++, parentIndex++) { + if (*parentIter == _parentMachine) { + stream << "&" << (*parentIter)->_prefix << "_machine"; + } + } + } else { + stream << "NULL"; + } + stream << "," << std::endl; + + stream << " /* donedata */ " << "&" << _prefix << "_elem_donedatas[0], " << std::endl; + stream << " /* script */ "; + if (filterChildElements(_nsInfo.xmlNSPrefix + "script", _scxml).size() > 0) { + stream << _prefix << "_global_script" << std::endl; + } else { + stream << "NULL"; + } + stream << std::endl; + + stream << "};" << std::endl; + stream << std::endl; + +#else if (_topMostMachine != NULL) return; @@ -1670,9 +1791,17 @@ void ChartToC::writeMachineInfo(std::ostream& stream) { stream << " {0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }" << std::endl; stream << "};" << std::endl; stream << std::endl; +#endif + + stream << "#endif" << std::endl; + stream << std::endl; + } void ChartToC::writeStates(std::ostream& stream) { + stream << "#ifndef USCXML_NO_ELEM_INFO" << std::endl; + stream << std::endl; + stream << "static const uscxml_state " << _prefix << "_states[" << toStr(_states.size()) << "] = {" << std::endl; for (size_t i = 0; i < _states.size(); i++) { Element<std::string> state(_states[i]); @@ -1754,11 +1883,18 @@ void ChartToC::writeStates(std::ostream& stream) { } stream << "};" << std::endl; stream << std::endl; + + stream << "#endif" << std::endl; + stream << std::endl; + } void ChartToC::writeTransitions(std::ostream& stream) { + stream << "#ifndef USCXML_NO_ELEM_INFO" << std::endl; + stream << std::endl; + // cross reference transition by document order - is this really needed?! std::set<std::string> elements; elements.insert(_nsInfo.xmlNSPrefix + "transition"); @@ -1853,6 +1989,10 @@ void ChartToC::writeTransitions(std::ostream& stream) { } stream << "};" << std::endl; stream << std::endl; + + stream << "#endif" << std::endl; + stream << std::endl; + } Arabica::XPath::NodeSet<std::string> ChartToC::computeExitSet(const Arabica::DOM::Element<std::string>& transition) { @@ -1916,7 +2056,7 @@ void ChartToC::writeCharArrayInitList(std::ostream& stream, const std::string& b } void ChartToC::writeFSM(std::ostream& stream) { - stream << "#ifndef USCXML_STEP_FUNCTION" << std::endl; + stream << "#ifndef USCXML_NO_STEP_FUNCTION" << std::endl; stream << "int uscxml_step(uscxml_ctx* ctx) {" << std::endl; stream << std::endl; @@ -1981,7 +2121,7 @@ void ChartToC::writeFSM(std::ostream& stream) { 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 << " if (ctx->dequeue_internal != NULL && (ctx->event = ctx->dequeue_internal(ctx)) != NULL) {" << std::endl; stream << " goto SELECT_TRANSITIONS;" << std::endl; stream << " }" << std::endl; stream << std::endl; @@ -2003,10 +2143,15 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << " }" << std::endl; stream << std::endl; - stream << " if ((ctx->event = ctx->dequeue_external(ctx)) != NULL) {" << std::endl; + stream << " if (ctx->dequeue_external != NULL && (ctx->event = ctx->dequeue_external(ctx)) != NULL) {" << std::endl; stream << " goto SELECT_TRANSITIONS;" << std::endl; stream << " }" << std::endl; stream << std::endl; + stream << " if (ctx->dequeue_external == NULL) {" << std::endl; + stream << " return USCXML_ERR_DONE;" << std::endl; + stream << " }" << std::endl; + stream << " return USCXML_ERR_IDLE;" << std::endl; + stream << std::endl; stream << "SELECT_TRANSITIONS:" << std::endl; stream << " bit_clear_all(conflicts, nr_trans_bytes);" << std::endl; @@ -2020,22 +2165,26 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << " if (BIT_HAS(USCXML_GET_TRANS(i).source, ctx->config)) {" << std::endl; stream << " /* is it non-conflicting? */" << std::endl; stream << " if (!BIT_HAS(i, conflicts)) {" << std::endl; - stream << " /* is it enabled? */" << std::endl; - stream << " if (ctx->is_enabled(ctx, &USCXML_GET_TRANS(i), ctx->event) > 0) {" << std::endl; - stream << " /* remember that we found a transition */" << std::endl; - stream << " ctx->flags |= USCXML_CTX_TRANSITION_FOUND;" << std::endl; + stream << " /* is it spontaneous with an event or vice versa? */" << std::endl; + stream << " if ((USCXML_GET_TRANS(i).event == NULL && ctx->event == NULL) || " << std::endl; + stream << " (USCXML_GET_TRANS(i).event != NULL && ctx->event != NULL)) {" << std::endl; + stream << " /* is it enabled? */" << std::endl; + stream << " if (ctx->is_enabled(ctx, &USCXML_GET_TRANS(i), ctx->event) > 0) {" << std::endl; + stream << " /* remember that we found a transition */" << std::endl; + stream << " ctx->flags |= USCXML_CTX_TRANSITION_FOUND;" << std::endl; stream << std::endl; - stream << " /* transitions that are pre-empted */" << std::endl; - stream << " bit_or(conflicts, USCXML_GET_TRANS(i).conflicts, nr_trans_bytes);" << std::endl; + stream << " /* transitions that are pre-empted */" << std::endl; + stream << " bit_or(conflicts, USCXML_GET_TRANS(i).conflicts, nr_trans_bytes);" << std::endl; stream << std::endl; - stream << " /* states that are directly targeted (resolve as entry-set later) */" << std::endl; - stream << " bit_or(target_set, USCXML_GET_TRANS(i).target, nr_states_bytes);" << std::endl; + stream << " /* states that are directly targeted (resolve as entry-set later) */" << std::endl; + stream << " bit_or(target_set, USCXML_GET_TRANS(i).target, nr_states_bytes);" << std::endl; stream << std::endl; - stream << " /* states that will be left */" << std::endl; - stream << " bit_or(exit_set, USCXML_GET_TRANS(i).exit_set, nr_states_bytes);" << std::endl; + stream << " /* states that will be left */" << std::endl; + stream << " bit_or(exit_set, USCXML_GET_TRANS(i).exit_set, nr_states_bytes);" << std::endl; stream << std::endl; - stream << " BIT_SET_AT(i, trans_set);" << std::endl; + stream << " BIT_SET_AT(i, trans_set);" << std::endl; + stream << " }" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; @@ -2334,7 +2483,7 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << "}" << std::endl; stream << std::endl; - stream << "#define USCXML_STEP_FUNCTION" << std::endl; + stream << "#define USCXML_NO_STEP_FUNCTION" << std::endl; stream << "#endif" << std::endl; stream << std::endl; } diff --git a/src/uscxml/transform/ChartToC.h b/src/uscxml/transform/ChartToC.h index 4e1d14a..bb17102 100644 --- a/src/uscxml/transform/ChartToC.h +++ b/src/uscxml/transform/ChartToC.h @@ -93,6 +93,8 @@ protected: ChartToC* _parentMachine; std::list<ChartToC*> _nestedMachines; std::list<ChartToC*> _allMachines; + + std::list<std::string>* _prefixes; }; } diff --git a/src/uscxml/transform/ChartToVHDL.cpp b/src/uscxml/transform/ChartToVHDL.cpp index 8e7f43f..f37ad7e 100644 --- a/src/uscxml/transform/ChartToVHDL.cpp +++ b/src/uscxml/transform/ChartToVHDL.cpp @@ -125,28 +125,14 @@ void ChartToVHDL::writeTo(std::ostream& stream) { // _eventTrie.dump(); - writeOptimalTransitionSetSelection(stream); writeTypes(stream); writeFiFo(stream); - writeTransitionSet(stream); + writeOptimalTransitionSetSelection(stream); writeExitSet(stream); writeEntrySet(stream); writeFSM(stream); } -void ChartToVHDL::writeTransitionSet(std::ostream & stream) { - for (size_t i = 0; i < _transitions.size(); i++) { - Element<std::string> transition(_transitions[i]); - std::string name = DOMUtils::idForNode(transition); - - } -} - -void ChartToVHDL::writeExitSet(std::ostream & stream) { -} - -void ChartToVHDL::writeEntrySet(std::ostream & stream) { -} void ChartToVHDL::writeFSM(std::ostream & stream) { @@ -475,14 +461,14 @@ std::string ChartToVHDL::eventNameEscape(const std::string& eventName) { } void ChartToVHDL::writeOptimalTransitionSetSelection(std::ostream & stream) { - stream << "-- write optimal transition set selection" << std::endl; + stream << "-- optimal transition set selection" << std::endl; for (size_t i = 0; i < _transitions.size(); i++) { Element<std::string> transition(_transitions[i]); std::string conflicts = ATTR(transition, "conflictBools"); stream << "in_optimal_transition_set_" << ATTR(transition, "postFixOrder") << "_sig " << "<= " << (HAS_ATTR(transition, "event") ? "(not spontaneous_sig)" : "spontaneous_sig") << " and " << std::endl - << " state_active_" << ATTR(transition, "source") << "_sig and not ( 0 " << std::endl; + << " state_active_" << ATTR(transition, "source") << "_sig and not ( '0' " << std::endl; for (size_t j = 0; j < i; j++) { if (conflicts[j] == '1') { stream << " or in_optimal_transition_set_" << toStr(j) << "_sig" << std::endl; @@ -490,7 +476,7 @@ void ChartToVHDL::writeOptimalTransitionSetSelection(std::ostream & stream) { } stream << " )"; if (HAS_ATTR(transition, "event")) { - stream << " and ( 0 " << std::endl;; + stream << " and ( '0' " << std::endl;; // find all matching event literals std::list<std::string> eventDescs = tokenizeIdRefs(ATTR(transition, "event")); @@ -508,6 +494,96 @@ void ChartToVHDL::writeOptimalTransitionSetSelection(std::ostream & stream) { } +void ChartToVHDL::writeExitSet(std::ostream & stream) { + stream << "-- exit set selection" << std::endl; + + for (size_t i = 0; i < _states.size(); i++) { + Element<std::string> state(_states[i]); + std::string completion = ATTR(state, "completionBools"); + std::string ancestors = ATTR(state, "ancBools"); + std::string children = ATTR(state, "childBools"); + std::string parent = ATTR(state, "parent"); + + stream << "in_exit_set_" << toStr(i) << "_sig " + << "<= state_active_ " << toStr(i) << "_sig and ('0'" << std::endl; + for (size_t j = 0; j < _transitions.size(); j++) { + Element<std::string> transition(_transitions[j]); + std::string exitSet = ATTR(transition, "exitSetBools"); + if (exitSet[i] == '1') { + stream << " or in_optimal_transition_set_" << toStr(j) << "_sig " << std::endl; + } + } + + stream << ")"; + stream << ";" << std::endl; + + } +} + +void ChartToVHDL::writeEntrySet(std::ostream & stream) { + stream << "-- entry set selection" << std::endl; + + for (size_t i = 0; i < _states.size(); i++) { + Element<std::string> state(_states[i]); + std::string completion = ATTR(state, "completionBools"); + std::string ancestors = ATTR(state, "ancBools"); + std::string children = ATTR(state, "childBools"); + std::string parent = ATTR(state, "parent"); + + stream << "in_complete_entry_set_up_" << toStr(i) << "_sig <= ('0'" << std::endl; + + for (size_t j = 0; j < _transitions.size(); j++) { + Element<std::string> transition(_transitions[j]); +// std::cout << transition; + std::string targetSet = ATTR(transition, "targetBools"); + if (targetSet[i] == '1') { + stream << " or in_optimal_transition_set_" << toStr(j) << std::endl; + } + } + if (isCompound(state)) { + for (size_t j = 0; j < _states.size(); j++) { + if (children[j] != '1') + continue; + + stream << " or in_complete_entry_set_up_" << toStr(j) << "_sig" << std::endl; + } + + } + stream << ");" << std::endl; + + } + + for (size_t i = 0; i < _states.size(); i++) { + Element<std::string> state(_states[i]); + std::string completion = ATTR(state, "completionBools"); + std::string ancestors = ATTR(state, "ancBools"); + std::string children = ATTR(state, "childBools"); + std::string parent = ATTR(state, "parent"); + + if (parent.size() == 0) { + continue; // TODO: FixMe <scxml> + } + + stream << "in_complete_entry_set_" << toStr(i) << "_sig <= (in_complete_entry_set_up_" << toStr(i) << "_sig or (" << std::endl; + + if (isParallel(Element<std::string>(_states[strTo<size_t>(parent)]))) { + stream << " in_complete_entry_set_" << toStr(parent) << "_sig" << std::endl; + } else if (isCompound(Element<std::string>(_states[strTo<size_t>(parent)]))) { + stream << " default_completion_" << toStr(parent) << "_sig" << std::endl; + + for (size_t j = 0; j < _states.size(); j++) { + if (children[j] != '1') + continue; + stream << " and not (is_active" << toStr(j) << "_sig and not in_exit_set_" << toStr(j) << "_sig)" << std::endl; + + } + } + + stream << ");" << std::endl; + + } +} + //TODO write event generator // wie die letzten beiden states erkennen // process bauen der bei fail 0 ausgibt und bei accept 1 diff --git a/src/uscxml/transform/ChartToVHDL.h b/src/uscxml/transform/ChartToVHDL.h index 64cf444..abcb477 100644 --- a/src/uscxml/transform/ChartToVHDL.h +++ b/src/uscxml/transform/ChartToVHDL.h @@ -51,7 +51,11 @@ protected: void writeTopDown(std::ostream& stream); void writeTypes(std::ostream& stream); + void writeOptimalTransitionSetSelection(std::ostream& stream); + void writeExitSet(std::ostream & stream); + void writeEntrySet(std::ostream & stream); + void writeNextStateLogic(std::ostream& stream); void writeOutputLogic(std::ostream& stream); void writeSignals(std::ostream& stream); @@ -61,8 +65,6 @@ protected: void writeFSM(std::ostream& stream); void writeTransitionSet(std::ostream & stream); - void writeExitSet(std::ostream & stream); - void writeEntrySet(std::ostream & stream); Trie _eventTrie; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d61abf7..1c1223e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -82,7 +82,30 @@ 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 +# tests for inline SCXML with generated C + +add_executable(test-c-inline src/test-c-inline.c) +set_target_properties(test-c-inline PROPERTIES FOLDER "Tests") + +add_test(NAME "gen/c/inline" + COMMAND ${CMAKE_COMMAND} + -DOUTDIR:FILEPATH=${CMAKE_CURRENT_BINARY_DIR}/gen/c + -DTESTFILE:FILEPATH=${CMAKE_CURRENT_SOURCE_DIR}/src/test-c-inline.c + -DTARGETLANG=c + -DUSCXML_TRANSFORM_BIN:FILEPATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/uscxml-transform + -DCC_BIN:FILEPATH=${CC} + -DCXX_BIN:FILEPATH=${CXX} + -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} + -P ${CMAKE_CURRENT_SOURCE_DIR}/w3c/run_generated_inline_test.cmake) +set_tests_properties("gen/c/inline" PROPERTIES DEPENDS uscxml-transform) +set_property(TEST "gen/c/inline" PROPERTY LABELS "gen/c/inline") + + +# declare W3C tests find_program(SPIN spin) find_program(CC gcc) diff --git a/test/src/test-c-inline.c b/test/src/test-c-inline.c new file mode 100644 index 0000000..c12ac73 --- /dev/null +++ b/test/src/test-c-inline.c @@ -0,0 +1,40 @@ +#include <stdlib.h> // EXIT_SUCCESS +#include <stdio.h> // printf +#include <string.h> // memset + +/** + * Preprocess: + * uscxml-transform -tc -i ./test-c-inline.c -o ./test-c-inline.c.scxml.c + */ + +/** INLINE SCXML BEGIN +<scxml name="test-inline" datamodel="native"> + <state id="foo"> + <onentry> + enteredFoo(); + </onentry> + </state> +</scxml> +INLINE SCXML END */ + +/** + * These function can be called from within executable content + */ +void enteredFoo() { + printf("Entered Foo!\n"); +} + +#include "test-c-inline.c.scxml.c" + +int main(int argc, char** argv) { + uscxml_ctx ctx; + memset(&ctx, 0, sizeof(uscxml_ctx)); + ctx.machine = &USCXML_MACHINE_TEST_INLINE; + + int err = USCXML_ERR_OK; + while(err != USCXML_ERR_DONE) { + err = uscxml_step(&ctx); + } + + return EXIT_SUCCESS; +}
\ No newline at end of file diff --git a/test/src/test-c-inline.c.scxml.c b/test/src/test-c-inline.c.scxml.c new file mode 100644 index 0000000..d586bb3 --- /dev/null +++ b/test/src/test-c-inline.c.scxml.c @@ -0,0 +1,951 @@ +/** + Generated from source: + file:///Users/sradomski/Documents/TK/Code/uscxml/test/src/test-c-inline.c +*/ + +#ifndef USCXML_NO_STDTYPES_H +# include <stdint.h> /* explicit types */ +#endif +#include <stddef.h> /* NULL */ + +#ifndef USCXML_NO_GEN_C_MACROS + +/** + * All macros used for the scxml types and functions + * + * ** IMPORTANT: Make sure to set the following macros prior to including. ** + * They are used to represent the machine in the types to follow + * and to allocate stack memory during a micro-step function. + * When in doubt, overprovide. + * + * USCXML_NR_STATES_TYPE + * as the smallest type for positive integers that can contain the + * largest number of states from an individual state machine. E.g.: + * < 2^8 states => uint8_t + * < 2^16 states => uint16_t + * < 2^32 states => uint32_t + */ + +#ifndef USCXML_NR_STATES_TYPE +# define USCXML_NR_STATES_TYPE uint8_t +#endif + +/** + * USCXML_NR_TRANS_TYPE + * the same as above but for the number of transitions. + */ + +#ifndef USCXML_NR_TRANS_TYPE +# define USCXML_NR_TRANS_TYPE uint8_t +#endif + +/** + * USCXML_MAX_NR_STATES_BYTES + * the smallest multiple of 8 that, if multiplied by 8, + * is larger than USCXML_NR_STATES_TYPE, e.g: + * 1-8 states => 1 + * 9-16 states => 2 + * 17-24 states => 3 + * 25-32 states => 4 + * ... + */ + +#ifndef USCXML_MAX_NR_STATES_BYTES +# define USCXML_MAX_NR_STATES_BYTES 1 +#endif + +/** + * USCXML_MAX_NR_TRANS_BYTES + * same as above but for transitions. + */ + +#ifndef USCXML_MAX_NR_TRANS_BYTES +# define USCXML_MAX_NR_TRANS_BYTES 0 +#endif + +/** + * USCXML_NUMBER_STATES / USCXML_NUMBER_TRANS + * Per default the number of states / transitions is retrieved from the machine + * info in the uscxml_ctx struct, but you can also hard-code it per macro. + */ + +#ifndef USCXML_NUMBER_STATES +# define USCXML_NUMBER_STATES (ctx->machine->nr_states) +#endif + +#ifndef USCXML_NUMBER_TRANS +# define USCXML_NUMBER_TRANS (ctx->machine->nr_transitions) +#endif + +/** + * USCXML_GET_STATE / USCXML_GET_TRANS + * Per default an individual state or transitions is retrieved from the machine + * info in the uscxml_ctx struct, but you can also hard-code it per macro. + */ + +#ifndef USCXML_GET_STATE +# define USCXML_GET_STATE(i) (ctx->machine->states[i]) +#endif + +#ifndef USCXML_GET_TRANS +# define USCXML_GET_TRANS(i) (ctx->machine->transitions[i]) +#endif + + +/* Common macros below */ + +#define BIT_HAS(idx, bitset) ((bitset[idx >> 3] & (1 << (idx & 7))) != 0) +#define BIT_SET_AT(idx, bitset) bitset[idx >> 3] |= (1 << (idx & 7)); +#define BIT_CLEAR(idx, bitset) bitset[idx >> 3] &= (1 << (idx & 7)) ^ 0xFF; + +#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 USCXML_ERR_OK 0 +#define USCXML_ERR_IDLE 1 +#define USCXML_ERR_DONE 2 +#define USCXML_ERR_MISSING_CALLBACK 3 +#define USCXML_ERR_FOREACH_DONE 4 +#define USCXML_ERR_EXEC_CONTENT 5 +#define USCXML_ERR_INVALID_TARGET 6 +#define USCXML_ERR_INVALID_TYPE 7 +#define USCXML_ERR_UNSUPPORTED 8 + +#define USCXML_TRANS_SPONTANEOUS 0x01 +#define USCXML_TRANS_TARGETLESS 0x02 +#define USCXML_TRANS_INTERNAL 0x04 +#define USCXML_TRANS_HISTORY 0x08 +#define USCXML_TRANS_INITIAL 0x10 + +#define USCXML_STATE_ATOMIC 0x01 +#define USCXML_STATE_PARALLEL 0x02 +#define USCXML_STATE_COMPOUND 0x03 +#define USCXML_STATE_FINAL 0x04 +#define USCXML_STATE_HISTORY_DEEP 0x05 +#define USCXML_STATE_HISTORY_SHALLOW 0x06 +#define USCXML_STATE_INITIAL 0x07 +#define USCXML_STATE_HAS_HISTORY 0x80 /* highest bit */ +#define USCXML_STATE_MASK(t) (t & 0x7F) /* mask highest bit */ + +#define USCXML_CTX_PRISTINE 0x00 +#define USCXML_CTX_SPONTANEOUS 0x01 +#define USCXML_CTX_INITIALIZED 0x02 +#define USCXML_CTX_TOP_LEVEL_FINAL 0x04 +#define USCXML_CTX_TRANSITION_FOUND 0x08 +#define USCXML_CTX_FINISHED 0x10 + +#define USCXML_ELEM_DATA_IS_SET(data) (data->id != NULL) +#define USCXML_ELEM_DONEDATA_IS_SET(donedata) (donedata->content != NULL || donedata->contentexpr != NULL || donedata->params != NULL) +#define USCXML_ELEM_PARAM_IS_SET(param) (param->name != NULL) +#define USCXML_MACHINE_IS_SET(machine) (machine->nr_states > 0) + +#define USCXML_NO_GEN_C_MACROS +#endif + + +#ifndef USCXML_NO_GEN_C_TYPES + +/** + * All types required to represent an SCXML state chart. + * Just predefine the USCXML_NO_GEN_C_TYPES macro if you do not need them. + */ + +typedef struct uscxml_machine uscxml_machine; +typedef struct uscxml_transition uscxml_transition; +typedef struct uscxml_state uscxml_state; +typedef struct uscxml_ctx uscxml_ctx; +typedef struct uscxml_elem_invoke uscxml_elem_invoke; + +typedef struct uscxml_elem_send uscxml_elem_send; +typedef struct uscxml_elem_param uscxml_elem_param; +typedef struct uscxml_elem_data uscxml_elem_data; +typedef struct uscxml_elem_donedata uscxml_elem_donedata; +typedef struct uscxml_elem_foreach uscxml_elem_foreach; + +typedef void* (*dequeue_internal_t)(const uscxml_ctx* ctx); +typedef void* (*dequeue_external_t)(const uscxml_ctx* ctx); +typedef int (*is_enabled_t)(const uscxml_ctx* ctx, const uscxml_transition* transition, const void* event); +typedef int (*is_true_t)(const uscxml_ctx* ctx, const char* expr); +typedef int (*exec_content_t)(const uscxml_ctx* ctx, const uscxml_state* state, const void* event); +typedef int (*raise_done_event_t)(const uscxml_ctx* ctx, const uscxml_state* state, const uscxml_elem_donedata* donedata); +typedef int (*invoke_t)(const uscxml_ctx* ctx, const uscxml_state* s, const uscxml_elem_invoke* invocation, unsigned char uninvoke); + +typedef int (*exec_content_log_t)(const uscxml_ctx* ctx, const char* label, const char* expr); +typedef int (*exec_content_raise_t)(const uscxml_ctx* ctx, const char* event); +typedef int (*exec_content_send_t)(const uscxml_ctx* ctx, const uscxml_elem_send* send); +typedef int (*exec_content_foreach_init_t)(const uscxml_ctx* ctx, const uscxml_elem_foreach* foreach); +typedef int (*exec_content_foreach_next_t)(const uscxml_ctx* ctx, const uscxml_elem_foreach* foreach); +typedef int (*exec_content_foreach_done_t)(const uscxml_ctx* ctx, const uscxml_elem_foreach* foreach); +typedef int (*exec_content_assign_t)(const uscxml_ctx* ctx, const char* location, const char* expr); +typedef int (*exec_content_init_t)(const uscxml_ctx* ctx, const uscxml_elem_data* data); +typedef int (*exec_content_cancel_t)(const uscxml_ctx* ctx, const char* sendid, const char* sendidexpr); +typedef int (*exec_content_finalize_t)(const uscxml_ctx* ctx, const uscxml_elem_invoke* invoker, const void* event); +typedef int (*exec_content_script_t)(const uscxml_ctx* ctx, const char* src, const char* content); + +/** + * A single SCXML state-machine. + */ +struct uscxml_machine { + unsigned char flags; /* Unused */ + USCXML_NR_STATES_TYPE nr_states; /* Make sure to set type per macro! */ + USCXML_NR_TRANS_TYPE nr_transitions; /* Make sure to set type per macro! */ + const char* name; + const char* datamodel; + const char* uuid; /* currently MD5 sum */ + const uscxml_state* states; + const uscxml_transition* transitions; + const uscxml_machine* parent; + const uscxml_elem_donedata* donedata; + const exec_content_t script; /* Global script elements */ +}; + +/** + * All information pertaining to a <data> element. + * With late data binding, blocks of data elements are separated by NULL + * use USCXML_ELEM_DATA_IS_SET to test for end of a block. + */ +struct uscxml_elem_data { + const char* id; + const char* src; + const char* expr; + const char* content; +}; + +/** + * All information pertaining to any state element. + */ +struct uscxml_state { + const char* name; /* eventual name */ + const USCXML_NR_STATES_TYPE parent; /* parent */ + const exec_content_t on_entry; /* on entry handlers */ + const exec_content_t on_exit; /* on exit handlers */ + const invoke_t invoke; /* invocations */ + const char children[USCXML_MAX_NR_STATES_BYTES]; /* all children */ + const char completion[USCXML_MAX_NR_STATES_BYTES]; /* default completion */ + const char ancestors[USCXML_MAX_NR_STATES_BYTES]; /* all ancestors */ + const uscxml_elem_data* data; /* data with late binding */ + const unsigned char type; /* One of USCXML_STATE_* */ +}; + +/** + * All information pertaining to a <transitions> element. + */ +struct uscxml_transition { + const USCXML_NR_STATES_TYPE source; + const char target[USCXML_MAX_NR_STATES_BYTES]; + const char* event; + const char* condition; + const exec_content_t on_transition; + const unsigned char type; + const char conflicts[USCXML_MAX_NR_TRANS_BYTES]; + const char exit_set[USCXML_MAX_NR_STATES_BYTES]; +}; + +/** + * All information pertaining to a <foreach> element. + */ +struct uscxml_elem_foreach { + const char* array; + const char* item; + const char* index; +}; + +/** + * All information pertaining to a <param> element. + * Blocks of params are separated by NULL params, use + * USCXML_ELEM_PARAM_IS_SET to test for end of a block. + */ +struct uscxml_elem_param { + const char* name; + const char* expr; + const char* location; +}; + +/** + * All information pertaining to a <donedata> element. + */ +struct uscxml_elem_donedata { + const USCXML_NR_STATES_TYPE source; + const char* content; + const char* contentexpr; + const uscxml_elem_param* params; +}; + +/** + * All information pertaining to an <invoke> element. + */ +struct uscxml_elem_invoke { + const uscxml_machine* machine; + const char* type; + const char* typeexpr; + const char* src; + const char* srcexpr; + const char* id; + const char* idlocation; + const char* sourcename; + const char* namelist; + const unsigned char autoforward; + const uscxml_elem_param* params; + exec_content_finalize_t finalize; + const char* content; + const char* contentexpr; +}; + +/** + * All information pertaining to a <send> element. + */ +struct uscxml_elem_send { + const char* event; + const char* eventexpr; + const char* target; + const char* targetexpr; + const char* type; + const char* typeexpr; + const char* id; + const char* idlocation; + const char* delay; + const char* delayexpr; + const char* namelist; /* not space-separated, still as in attribute value */ + const char* content; + const char* contentexpr; + const uscxml_elem_param* params; +}; + +/** + * Represents an instance of a state-chart at runtime/ + */ +struct uscxml_ctx { + unsigned char flags; + const uscxml_machine* machine; + + char config[USCXML_MAX_NR_STATES_BYTES]; /* Make sure these macros specify a sufficient size */ + char history[USCXML_MAX_NR_STATES_BYTES]; + char invocations[USCXML_MAX_NR_STATES_BYTES]; + char initialized_data[USCXML_MAX_NR_STATES_BYTES]; + + void* user_data; + void* event; + + dequeue_internal_t dequeue_internal; + dequeue_external_t dequeue_external; + is_enabled_t is_enabled; + is_true_t is_true; + raise_done_event_t raise_done_event; + + exec_content_log_t exec_content_log; + exec_content_raise_t exec_content_raise; + exec_content_send_t exec_content_send; + exec_content_foreach_init_t exec_content_foreach_init; + exec_content_foreach_next_t exec_content_foreach_next; + exec_content_foreach_done_t exec_content_foreach_done; + exec_content_assign_t exec_content_assign; + exec_content_init_t exec_content_init; + exec_content_cancel_t exec_content_cancel; + exec_content_script_t exec_content_script; + + invoke_t invoke; +}; + +#define USCXML_NO_GEN_C_TYPES +#endif + +/* forward declare machines to allow references */ +extern const uscxml_machine _uscxml_9FAC9BE9_machine; + +#ifndef USCXML_NO_ELEM_INFO + +static const uscxml_elem_donedata _uscxml_9FAC9BE9_elem_donedatas[1] = { + /* source, content, contentexpr, params */ + { 0, NULL, NULL, NULL } +}; + +#endif + +#ifndef USCXML_NO_ELEM_INFO + +#endif + +#ifndef USCXML_NO_EXEC_CONTENT + +static int _uscxml_9FAC9BE9_foo_on_entry_0(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { + int err = USCXML_ERR_OK; + + enteredFoo(); + return USCXML_ERR_OK; +} + +static int _uscxml_9FAC9BE9_foo_on_entry(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { + _uscxml_9FAC9BE9_foo_on_entry_0(ctx, state, event); + return USCXML_ERR_OK; +} + +#endif + +#ifndef USCXML_NO_ELEM_INFO + +static const uscxml_state _uscxml_9FAC9BE9_states[2] = { + { /* state number 0 */ + /* name */ NULL, + /* parent */ 0, + /* onentry */ NULL, + /* onexit */ NULL, + /* invoke */ NULL, + /* children */ { 0x02 /* 01 */ }, + /* completion */ { 0x02 /* 01 */ }, + /* ancestors */ { 0x00 /* 00 */ }, + /* data */ NULL, + /* type */ USCXML_STATE_COMPOUND, + }, + { /* state number 1 */ + /* name */ "foo", + /* parent */ 0, + /* onentry */ _uscxml_9FAC9BE9_foo_on_entry, + /* onexit */ NULL, + /* invoke */ NULL, + /* children */ { 0x00 /* 00 */ }, + /* completion */ { 0x00 /* 00 */ }, + /* ancestors */ { 0x01 /* 10 */ }, + /* data */ NULL, + /* type */ USCXML_STATE_ATOMIC, + } +}; + +#endif + +#ifndef USCXML_NO_ELEM_INFO + +static const uscxml_transition _uscxml_9FAC9BE9_transitions[0] = { +}; + +#endif + +#ifndef USCXML_NO_ELEM_INFO + +#ifndef USCXML_MACHINE +# define USCXML_MACHINE _uscxml_9FAC9BE9_machine +#endif +#define USCXML_MACHINE_0 _uscxml_9FAC9BE9_machine +#define USCXML_MACHINE_TEST_INLINE _uscxml_9FAC9BE9_machine + +const uscxml_machine _uscxml_9FAC9BE9_machine = { + /* flags */ 0, + /* nr_states */ 2, + /* nr_transitions */ 0, + /* name */ "test-inline", + /* datamodel */ "native", + /* uuid */ "9FAC9BE9A82F66AFD36A205557064B27", + /* states */ &_uscxml_9FAC9BE9_states[0], + /* transitions */ &_uscxml_9FAC9BE9_transitions[0], + /* parent */ NULL, + /* donedata */ &_uscxml_9FAC9BE9_elem_donedatas[0], + /* script */ NULL +}; + +#endif + +#ifdef USCXML_VERBOSE +/** + * Print name of states contained in a (debugging). + */ +static void printStateNames(const uscxml_ctx* ctx, const char* a, size_t length) { + size_t i; + const char* seperator = ""; + for (i = 0; i < length; i++) { + if (BIT_HAS(i, a)) { + printf("%s%s", seperator, (USCXML_GET_STATE(i).name != NULL ? USCXML_GET_STATE(i).name : "UNK")); + seperator = ", "; + } + } + printf("\n"); +} + +/** + * Print bits set in a in a binary representation (debugging). + */ +static void printBitsetIndices(const char* a, size_t length) { + size_t i; + const char* seperator = ""; + for (i = 0; i < length; i++) { + if (BIT_HAS(i, a)) { + printf("%s%lu", seperator, i); + seperator = ", "; + } + } + printf("\n"); +} +#endif + +#ifndef USCXML_NO_BIT_OPERATIONS +/** + * Return true if there is a common bit in a and b. + */ +static int bit_has_and(const char* a, const char* b, size_t i) { + while(i--) { + if (a[i] & b[i]) + return 1; + } + return 0; +} + +/** + * Set all bits to 0, this corresponds to memset(a, 0, i), + * but does not require string.h or cstring. + */ +static void bit_clear_all(char* a, size_t i) { + while(i--) { + a[i] = 0; + } +} + +/** + * Return true if there is any bit set in a. + */ +static int bit_has_any(const char* a, size_t i) { + while(i--) { + if (a[i] > 0) + return 1; + } + return 0; +} + +/** + * Set all bits from given mask in dest, this is |= for bit arrays. + */ +static void bit_or(char* dest, const char* mask, size_t i) { + while(i--) { + dest[i] |= mask[i]; + } +} + +/** + * Copy all bits from source to dest, this corresponds to memcpy(a, b, i), + * but does not require string.h or cstring. + */ +static void bit_copy(char* dest, const char* source, size_t i) { + while(i--) { + dest[i] = source[i]; + } +} + +/** + * Unset bits from mask in dest. + */ +static void bit_and_not(char* dest, const char* mask, size_t i) { + while(i--) { + dest[i] &= ~mask[i]; + } +} + +/** + * Set bits from mask in dest. + */ +static void bit_and(char* dest, const char* mask, size_t i) { + while(i--) { + dest[i] &= mask[i]; + }; +} + +#define USCXML_NO_BIT_OPERATIONS +#endif + +#ifndef USCXML_NO_STEP_FUNCTION +int uscxml_step(uscxml_ctx* ctx) { + + USCXML_NR_STATES_TYPE i, j, k; + USCXML_NR_STATES_TYPE nr_states_bytes = ((USCXML_NUMBER_STATES + 7) & ~7) >> 3; + USCXML_NR_TRANS_TYPE nr_trans_bytes = ((USCXML_NUMBER_TRANS + 7) & ~7) >> 3; + int err = USCXML_ERR_OK; + char conflicts [USCXML_MAX_NR_TRANS_BYTES]; + char trans_set [USCXML_MAX_NR_TRANS_BYTES]; + char target_set [USCXML_MAX_NR_STATES_BYTES]; + char exit_set [USCXML_MAX_NR_STATES_BYTES]; + char entry_set [USCXML_MAX_NR_STATES_BYTES]; + char tmp_states [USCXML_MAX_NR_STATES_BYTES]; + +#ifdef USCXML_VERBOSE + printf("Config: "); + printStateNames(ctx, ctx->config, USCXML_NUMBER_STATES); +#endif + + if (ctx->flags & USCXML_CTX_FINISHED) + return USCXML_ERR_DONE; + + if (ctx->flags & USCXML_CTX_TOP_LEVEL_FINAL) { + /* exit all remaining states */ + i = USCXML_NUMBER_STATES; + while(i-- > 0) { + if (BIT_HAS(i, ctx->config)) { + /* call all on exit handlers */ + if (USCXML_GET_STATE(i).on_exit != NULL) { + if unlikely((err = USCXML_GET_STATE(i).on_exit(ctx, &USCXML_GET_STATE(i), ctx->event)) != USCXML_ERR_OK) + return err; + } + } + if (BIT_HAS(i, ctx->invocations)) { + if (USCXML_GET_STATE(i).invoke != NULL) + USCXML_GET_STATE(i).invoke(ctx, &USCXML_GET_STATE(i), NULL, 1); + BIT_CLEAR(i, ctx->invocations); + } + } + ctx->flags |= USCXML_CTX_FINISHED; + return USCXML_ERR_DONE; + } + + bit_clear_all(target_set, nr_states_bytes); + bit_clear_all(trans_set, nr_trans_bytes); + if unlikely(ctx->flags == USCXML_CTX_PRISTINE) { + if (ctx->machine->script != NULL) + ctx->machine->script(ctx, &ctx->machine->states[0], NULL); + bit_or(target_set, ctx->machine->states[0].completion, nr_states_bytes); + ctx->flags |= USCXML_CTX_SPONTANEOUS | USCXML_CTX_INITIALIZED; + goto ESTABLISH_ENTRY_SET; + } + + if (ctx->flags & USCXML_CTX_SPONTANEOUS) { + ctx->event = NULL; + goto SELECT_TRANSITIONS; + } + if (ctx->dequeue_internal != NULL && (ctx->event = ctx->dequeue_internal(ctx)) != NULL) { + goto SELECT_TRANSITIONS; + } + + /* manage invocations */ + for (i = 0; i < USCXML_NUMBER_STATES; i++) { + /* uninvoke */ + if (!BIT_HAS(i, ctx->config) && BIT_HAS(i, ctx->invocations)) { + if (USCXML_GET_STATE(i).invoke != NULL) + USCXML_GET_STATE(i).invoke(ctx, &USCXML_GET_STATE(i), NULL, 1); + BIT_CLEAR(i, ctx->invocations) + } + /* invoke */ + if (BIT_HAS(i, ctx->config) && !BIT_HAS(i, ctx->invocations)) { + if (USCXML_GET_STATE(i).invoke != NULL) + USCXML_GET_STATE(i).invoke(ctx, &USCXML_GET_STATE(i), NULL, 0); + BIT_SET_AT(i, ctx->invocations) + } + } + + if (ctx->dequeue_external != NULL && (ctx->event = ctx->dequeue_external(ctx)) != NULL) { + goto SELECT_TRANSITIONS; + } + + if (ctx->dequeue_external == NULL) { + return USCXML_ERR_DONE; + } + return USCXML_ERR_IDLE; + +SELECT_TRANSITIONS: + bit_clear_all(conflicts, nr_trans_bytes); + bit_clear_all(exit_set, nr_states_bytes); + for (i = 0; i < USCXML_NUMBER_TRANS; i++) { + /* never select history or initial transitions automatically */ + if unlikely(USCXML_GET_TRANS(i).type & (USCXML_TRANS_HISTORY | USCXML_TRANS_INITIAL)) + continue; + + /* is the transition active? */ + if (BIT_HAS(USCXML_GET_TRANS(i).source, ctx->config)) { + /* is it non-conflicting? */ + if (!BIT_HAS(i, conflicts)) { + /* is it spontaneous with an event or vice versa? */ + if ((USCXML_GET_TRANS(i).event == NULL && ctx->event == NULL) || + (USCXML_GET_TRANS(i).event != NULL && ctx->event != NULL)) { + /* is it enabled? */ + if (ctx->is_enabled(ctx, &USCXML_GET_TRANS(i), ctx->event) > 0) { + /* remember that we found a transition */ + ctx->flags |= USCXML_CTX_TRANSITION_FOUND; + + /* transitions that are pre-empted */ + bit_or(conflicts, USCXML_GET_TRANS(i).conflicts, nr_trans_bytes); + + /* states that are directly targeted (resolve as entry-set later) */ + bit_or(target_set, USCXML_GET_TRANS(i).target, nr_states_bytes); + + /* states that will be left */ + bit_or(exit_set, USCXML_GET_TRANS(i).exit_set, nr_states_bytes); + + BIT_SET_AT(i, trans_set); + } + } + } + } + } + bit_and(exit_set, ctx->config, nr_states_bytes); + + if (ctx->flags & USCXML_CTX_TRANSITION_FOUND) { + ctx->flags |= USCXML_CTX_SPONTANEOUS; + ctx->flags &= ~USCXML_CTX_TRANSITION_FOUND; + } else { + ctx->flags &= ~USCXML_CTX_SPONTANEOUS; + } + +#ifdef USCXML_VERBOSE + printf("Targets: "); + printStateNames(ctx, target_set, USCXML_NUMBER_STATES); +#endif + +#ifdef USCXML_VERBOSE + printf("Exiting: "); + printStateNames(ctx, exit_set, USCXML_NUMBER_STATES); +#endif + +#ifdef USCXML_VERBOSE + printf("History: "); + printStateNames(ctx, ctx->history, USCXML_NUMBER_STATES); +#endif + +/* REMEMBER_HISTORY: */ + for (i = 0; i < USCXML_NUMBER_STATES; i++) { + if unlikely(USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_SHALLOW || + USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_DEEP) { + /* a history state whose parent is about to be exited */ + if unlikely(BIT_HAS(USCXML_GET_STATE(i).parent, exit_set)) { + bit_copy(tmp_states, USCXML_GET_STATE(i).completion, nr_states_bytes); + + /* set those states who were enabled */ + bit_and(tmp_states, ctx->config, nr_states_bytes); + + /* clear current history with completion mask */ + bit_and_not(ctx->history, USCXML_GET_STATE(i).completion, nr_states_bytes); + + /* set history */ + bit_or(ctx->history, tmp_states, nr_states_bytes); + } + } + } + +ESTABLISH_ENTRY_SET: + /* calculate new entry set */ + bit_copy(entry_set, target_set, nr_states_bytes); + + /* iterate for ancestors */ + for (i = 0; i < USCXML_NUMBER_STATES; i++) { + if (BIT_HAS(i, entry_set)) { + bit_or(entry_set, USCXML_GET_STATE(i).ancestors, nr_states_bytes); + } + } + + /* iterate for descendants */ + for (i = 0; i < USCXML_NUMBER_STATES; i++) { + if (BIT_HAS(i, entry_set)) { + switch (USCXML_STATE_MASK(USCXML_GET_STATE(i).type)) { + case USCXML_STATE_PARALLEL: { + bit_or(entry_set, USCXML_GET_STATE(i).completion, nr_states_bytes); + break; + } + case USCXML_STATE_HISTORY_SHALLOW: + case USCXML_STATE_HISTORY_DEEP: { + if (!bit_has_and(USCXML_GET_STATE(i).completion, ctx->history, nr_states_bytes) && + !BIT_HAS(USCXML_GET_STATE(i).parent, ctx->config)) { + /* nothing set for history, look for a default transition */ + for (j = 0; j < USCXML_NUMBER_TRANS; j++) { + if unlikely(ctx->machine->transitions[j].source == i) { + bit_or(entry_set, ctx->machine->transitions[j].target, nr_states_bytes); + if(USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_DEEP && + !bit_has_and(ctx->machine->transitions[j].target, USCXML_GET_STATE(i).children, nr_states_bytes)) { + for (k = i + 1; k < USCXML_NUMBER_STATES; k++) { + if (BIT_HAS(k, ctx->machine->transitions[j].target)) { + bit_or(entry_set, ctx->machine->states[k].ancestors, nr_states_bytes); + break; + } + } + } + BIT_SET_AT(j, trans_set); + break; + } + /* Note: SCXML mandates every history to have a transition! */ + } + } else { + bit_copy(tmp_states, USCXML_GET_STATE(i).completion, nr_states_bytes); + bit_and(tmp_states, ctx->history, nr_states_bytes); + bit_or(entry_set, tmp_states, nr_states_bytes); + if (USCXML_GET_STATE(i).type == (USCXML_STATE_HAS_HISTORY | USCXML_STATE_HISTORY_DEEP)) { + /* a deep history state with nested histories -> more completion */ + for (j = i + 1; j < USCXML_NUMBER_STATES; j++) { + if (BIT_HAS(j, USCXML_GET_STATE(i).completion) && + BIT_HAS(j, entry_set) && + (ctx->machine->states[j].type & USCXML_STATE_HAS_HISTORY)) { + for (k = j + 1; k < USCXML_NUMBER_STATES; k++) { + /* add nested history to entry_set */ + if ((USCXML_STATE_MASK(ctx->machine->states[k].type) == USCXML_STATE_HISTORY_DEEP || + USCXML_STATE_MASK(ctx->machine->states[k].type) == USCXML_STATE_HISTORY_SHALLOW) && + BIT_HAS(k, ctx->machine->states[j].children)) { + /* a nested history state */ + BIT_SET_AT(k, entry_set); + } + } + } + } + } + } + break; + } + case USCXML_STATE_INITIAL: { + for (j = 0; j < USCXML_NUMBER_TRANS; j++) { + if (ctx->machine->transitions[j].source == i) { + BIT_SET_AT(j, trans_set); + BIT_CLEAR(i, entry_set); + bit_or(entry_set, ctx->machine->transitions[j].target, nr_states_bytes); + for (k = i + 1; k < USCXML_NUMBER_STATES; k++) { + if (BIT_HAS(k, ctx->machine->transitions[j].target)) { + bit_or(entry_set, ctx->machine->states[k].ancestors, nr_states_bytes); + } + } + } + } + break; + } + case USCXML_STATE_COMPOUND: { /* we need to check whether one child is already in entry_set */ + if (!bit_has_and(entry_set, USCXML_GET_STATE(i).children, nr_states_bytes) && + (!bit_has_and(ctx->config, USCXML_GET_STATE(i).children, nr_states_bytes) || + bit_has_and(exit_set, USCXML_GET_STATE(i).children, nr_states_bytes))) + { + bit_or(entry_set, USCXML_GET_STATE(i).completion, nr_states_bytes); + if (!bit_has_and(USCXML_GET_STATE(i).completion, USCXML_GET_STATE(i).children, nr_states_bytes)) { + /* deep completion */ + for (j = i + 1; j < USCXML_NUMBER_STATES; j++) { + if (BIT_HAS(j, USCXML_GET_STATE(i).completion)) { + bit_or(entry_set, ctx->machine->states[j].ancestors, nr_states_bytes); + break; /* completion of compound is single state */ + } + } + } + } + break; + } + } + } + } + +#ifdef USCXML_VERBOSE + printf("Transitions: "); + printBitsetIndices(trans_set, sizeof(char) * 8 * nr_trans_bytes); +#endif + +/* EXIT_STATES: */ + i = USCXML_NUMBER_STATES; + while(i-- > 0) { + if (BIT_HAS(i, exit_set) && BIT_HAS(i, ctx->config)) { + /* call all on exit handlers */ + if (USCXML_GET_STATE(i).on_exit != NULL) { + if unlikely((err = USCXML_GET_STATE(i).on_exit(ctx, &USCXML_GET_STATE(i), ctx->event)) != USCXML_ERR_OK) + return err; + } + BIT_CLEAR(i, ctx->config); + } + } + +/* TAKE_TRANSITIONS: */ + for (i = 0; i < USCXML_NUMBER_TRANS; i++) { + if (BIT_HAS(i, trans_set) && (USCXML_GET_TRANS(i).type & (USCXML_TRANS_HISTORY | USCXML_TRANS_INITIAL)) == 0) { + /* call executable content in transition */ + if (USCXML_GET_TRANS(i).on_transition != NULL) { + if unlikely((err = USCXML_GET_TRANS(i).on_transition(ctx, + &ctx->machine->states[USCXML_GET_TRANS(i).source], + ctx->event)) != USCXML_ERR_OK) + return err; + } + } + } + +#ifdef USCXML_VERBOSE + printf("Entering: "); + printStateNames(ctx, entry_set, USCXML_NUMBER_STATES); +#endif + +/* ENTER_STATES: */ + for (i = 0; i < USCXML_NUMBER_STATES; i++) { + if (BIT_HAS(i, entry_set) && !BIT_HAS(i, ctx->config)) { + /* these are no proper states */ + if unlikely(USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_DEEP || + USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_SHALLOW || + USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_INITIAL) + continue; + + BIT_SET_AT(i, ctx->config); + + /* initialize data */ + if (!BIT_HAS(i, ctx->initialized_data)) { + if unlikely(USCXML_GET_STATE(i).data != NULL && ctx->exec_content_init != NULL) { + ctx->exec_content_init(ctx, USCXML_GET_STATE(i).data); + } + BIT_SET_AT(i, ctx->initialized_data); + } + + if (USCXML_GET_STATE(i).on_entry != NULL) { + if unlikely((err = USCXML_GET_STATE(i).on_entry(ctx, &USCXML_GET_STATE(i), ctx->event)) != USCXML_ERR_OK) + return err; + } + + /* take history and initial transitions */ + for (j = 0; j < USCXML_NUMBER_TRANS; j++) { + if unlikely(BIT_HAS(j, trans_set) && + (ctx->machine->transitions[j].type & (USCXML_TRANS_HISTORY | USCXML_TRANS_INITIAL)) && + ctx->machine->states[ctx->machine->transitions[j].source].parent == i) { + /* call executable content in transition */ + if (ctx->machine->transitions[j].on_transition != NULL) { + if unlikely((err = ctx->machine->transitions[j].on_transition(ctx, + &USCXML_GET_STATE(i), + ctx->event)) != USCXML_ERR_OK) + return err; + } + } + } + + /* handle final states */ + if unlikely(USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_FINAL) { + if unlikely(USCXML_GET_STATE(i).ancestors[0] == 0x01) { + ctx->flags |= USCXML_CTX_TOP_LEVEL_FINAL; + } else { + /* raise done event */ + const uscxml_elem_donedata* donedata = &ctx->machine->donedata[0]; + while(USCXML_ELEM_DONEDATA_IS_SET(donedata)) { + if unlikely(donedata->source == i) + break; + donedata++; + } + ctx->raise_done_event(ctx, &ctx->machine->states[USCXML_GET_STATE(i).parent], (USCXML_ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL)); + } + + /** + * are we the last final state to leave a parallel state?: + * 1. Gather all parallel states in our ancestor chain + * 2. Find all states for which these parallels are ancestors + * 3. Iterate all active final states and remove their ancestors + * 4. If a state remains, not all children of a parallel are final + */ + for (j = 0; j < USCXML_NUMBER_STATES; j++) { + if unlikely(USCXML_STATE_MASK(ctx->machine->states[j].type) == USCXML_STATE_PARALLEL && + BIT_HAS(j, USCXML_GET_STATE(i).ancestors)) { + bit_clear_all(tmp_states, nr_states_bytes); + for (k = 0; k < USCXML_NUMBER_STATES; k++) { + if unlikely(BIT_HAS(j, ctx->machine->states[k].ancestors) && BIT_HAS(k, ctx->config)) { + if (USCXML_STATE_MASK(ctx->machine->states[k].type) == USCXML_STATE_FINAL) { + bit_and_not(tmp_states, ctx->machine->states[k].ancestors, nr_states_bytes); + } else { + BIT_SET_AT(k, tmp_states); + } + } + } + if unlikely(!bit_has_any(tmp_states, nr_states_bytes)) { + ctx->raise_done_event(ctx, &ctx->machine->states[j], NULL); + } + } + } + + } + + } + } + + return USCXML_ERR_OK; +} + +#define USCXML_NO_STEP_FUNCTION +#endif + diff --git a/test/src/test-c-machine.cpp b/test/src/test-c-machine.cpp index 3bd92aa..2879ef9 100644 --- a/test/src/test-c-machine.cpp +++ b/test/src/test-c-machine.cpp @@ -17,7 +17,7 @@ #endif #ifndef AUTOINCLUDE_TEST -#include "test-c-machine.machine.c" +#include "test-c-machine.scxml.c" #endif #include "uscxml/Convenience.h" @@ -637,27 +637,27 @@ public: Data d; std::stringstream content; - if (data->expr != NULL) { - d = USER_DATA(ctx)->dataModel.getStringAsData(data->expr); -// d = Data(data->expr, Data::INTERPRETED); - } else if (data->content != NULL) { - content << data->content; - d = USER_DATA(ctx)->dataModel.getStringAsData(content.str()); -// d = Data(content.str(), Data::INTERPRETED); - } else if (data->src != NULL) { - URL sourceURL(data->src); - if (USER_DATA(ctx)->baseURL.size() > 0) { - sourceURL.toAbsolute(USER_DATA(ctx)->baseURL); + try { + if (data->expr != NULL) { +// d = USER_DATA(ctx)->dataModel.getStringAsData(data->expr); + d = Data(data->expr, Data::INTERPRETED); + } else if (data->content != NULL) { + content << data->content; + d = USER_DATA(ctx)->dataModel.getStringAsData(content.str()); + // d = Data(content.str(), Data::INTERPRETED); + } else if (data->src != NULL) { + URL sourceURL(data->src); + if (USER_DATA(ctx)->baseURL.size() > 0) { + sourceURL.toAbsolute(USER_DATA(ctx)->baseURL); + } else { + sourceURL.toAbsoluteCwd(); + } + content << sourceURL; + // d = Data(content.str(), Data::INTERPRETED); + d = USER_DATA(ctx)->dataModel.getStringAsData(content.str()); } else { - sourceURL.toAbsoluteCwd(); + d = Data("undefined", Data::INTERPRETED); } - content << sourceURL; -// d = Data(content.str(), Data::INTERPRETED); - d = USER_DATA(ctx)->dataModel.getStringAsData(content.str()); - } else { - d = Data("undefined", Data::INTERPRETED); - } - try { // this might fail with an unquoted string literal in content USER_DATA(ctx)->dataModel.init(data->id, d); } catch (Event e) { @@ -930,7 +930,7 @@ int main(int argc, char** argv) { double avgDm = 0; #endif - StateMachine rootMachine(&uscxml_machines[0]); + StateMachine rootMachine(&USCXML_MACHINE); Timer tTotal; tTotal.start(); diff --git a/test/src/test-c-machine.machine.c b/test/src/test-c-machine.scxml.c index 5ac3994..cbbfbfe 100644 --- a/test/src/test-c-machine.machine.c +++ b/test/src/test-c-machine.scxml.c @@ -1,12 +1,14 @@ /** Generated from source: - file:///Users/sradomski/Documents/TK/Code/uscxml/test/w3c/lua/test150.scxml + file:///Users/sradomski/Documents/TK/Code/uscxml/test/w3c/ecma/test326.scxml */ -#include <stdint.h> /* explicit types */ +#ifndef USCXML_NO_STDTYPES_H +# include <stdint.h> /* explicit types */ +#endif #include <stddef.h> /* NULL */ -#ifndef USCXML_GEN_C_MACROS +#ifndef USCXML_NO_GEN_C_MACROS /** * All macros used for the scxml types and functions @@ -143,15 +145,15 @@ #define USCXML_ELEM_PARAM_IS_SET(param) (param->name != NULL) #define USCXML_MACHINE_IS_SET(machine) (machine->nr_states > 0) -#define USCXML_GEN_C_MACROS +#define USCXML_NO_GEN_C_MACROS #endif -#ifndef USCXML_GEN_C_TYPES +#ifndef USCXML_NO_GEN_C_TYPES /** * All types required to represent an SCXML state chart. - * Just predefine the USCXML_GEN_C_TYPES macro if you do not need them. + * Just predefine the USCXML_NO_GEN_C_TYPES macro if you do not need them. */ typedef struct uscxml_machine uscxml_machine; @@ -350,41 +352,38 @@ struct uscxml_ctx { invoke_t invoke; }; -#define USCXML_GEN_C_TYPES +#define USCXML_NO_GEN_C_TYPES #endif /* forward declare machines to allow references */ -extern const uscxml_machine uscxml_machines[2]; +extern const uscxml_machine _uscxml_EC83C2A5_machine; -static const uscxml_elem_foreach _uscxml_9FEEFF45_elem_foreachs[2] = { - /* array, item, index */ - { "testvar3", "testvar1", "testvar2" }, - { "testvar3", "testvar4", "testvar5" } -}; +#ifndef USCXML_NO_ELEM_INFO -static const uscxml_elem_data _uscxml_9FEEFF45_elem_datas[4] = { +static const uscxml_elem_data _uscxml_EC83C2A5_elem_datas[3] = { /* id, src, expr, content */ - { "testvar1", NULL, NULL, NULL }, - { "testvar2", NULL, NULL, NULL }, - { "testvar3", NULL, NULL, "{1,2,3}" }, + { "Var1", NULL, "_ioprocessors", NULL }, + { "Var2", NULL, NULL, NULL }, { NULL, NULL, NULL, NULL } }; -static const uscxml_elem_donedata _uscxml_9FEEFF45_elem_donedatas[1] = { +static const uscxml_elem_donedata _uscxml_EC83C2A5_elem_donedatas[1] = { /* source, content, contentexpr, params */ { 0, NULL, NULL, NULL } }; -static int _uscxml_9FEEFF45_s0_on_entry_0(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { - int err = USCXML_ERR_OK; - if likely(ctx->exec_content_foreach_init != NULL && - ctx->exec_content_foreach_next != NULL && - ctx->exec_content_foreach_done != NULL) { +#endif - if unlikely((ctx->exec_content_foreach_init(ctx, &_uscxml_9FEEFF45_elem_foreachs[0])) != USCXML_ERR_OK) return err; - while (ctx->exec_content_foreach_next(ctx, &_uscxml_9FEEFF45_elem_foreachs[0]) == USCXML_ERR_OK) { - } - if ((ctx->exec_content_foreach_done(ctx, &_uscxml_9FEEFF45_elem_foreachs[0])) != USCXML_ERR_OK) return err; +#ifndef USCXML_NO_ELEM_INFO + +#endif + +#ifndef USCXML_NO_EXEC_CONTENT + +static int _uscxml_EC83C2A5_s1_on_entry_0(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { + int err = USCXML_ERR_OK; + if likely(ctx->exec_content_assign != NULL) { + if ((ctx->exec_content_assign(ctx, "_ioprocessors", "'otherName'")) != USCXML_ERR_OK) return err; } else { return USCXML_ERR_MISSING_CALLBACK; } @@ -396,38 +395,61 @@ static int _uscxml_9FEEFF45_s0_on_entry_0(const uscxml_ctx* ctx, const uscxml_st return USCXML_ERR_OK; } -static int _uscxml_9FEEFF45_s0_on_entry(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { - _uscxml_9FEEFF45_s0_on_entry_0(ctx, state, event); +static int _uscxml_EC83C2A5_s1_on_entry(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { + _uscxml_EC83C2A5_s1_on_entry_0(ctx, state, event); return USCXML_ERR_OK; } -static int _uscxml_9FEEFF45_s1_on_entry_0(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { +static int _uscxml_EC83C2A5_s2_on_entry_0(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { int err = USCXML_ERR_OK; - if likely(ctx->exec_content_foreach_init != NULL && - ctx->exec_content_foreach_next != NULL && - ctx->exec_content_foreach_done != NULL) { + if likely(ctx->exec_content_assign != NULL) { + if ((ctx->exec_content_assign(ctx, "Var2", "_ioprocessors")) != USCXML_ERR_OK) return err; + } else { + return USCXML_ERR_MISSING_CALLBACK; + } + return USCXML_ERR_OK; +} - if unlikely((ctx->exec_content_foreach_init(ctx, &_uscxml_9FEEFF45_elem_foreachs[1])) != USCXML_ERR_OK) return err; - while (ctx->exec_content_foreach_next(ctx, &_uscxml_9FEEFF45_elem_foreachs[1]) == USCXML_ERR_OK) { - } - if ((ctx->exec_content_foreach_done(ctx, &_uscxml_9FEEFF45_elem_foreachs[1])) != USCXML_ERR_OK) return err; +static int _uscxml_EC83C2A5_s2_on_entry(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { + _uscxml_EC83C2A5_s2_on_entry_0(ctx, state, event); + return USCXML_ERR_OK; +} + +static int _uscxml_EC83C2A5_pass_on_entry_0(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { + int err = USCXML_ERR_OK; + if likely(ctx->exec_content_log != NULL) { + if unlikely((ctx->exec_content_log(ctx, "Outcome", "'pass'")) != USCXML_ERR_OK) return err; } else { return USCXML_ERR_MISSING_CALLBACK; } - if likely(ctx->exec_content_raise != NULL) { - if unlikely((ctx->exec_content_raise(ctx, "bar")) != USCXML_ERR_OK) return err; + return USCXML_ERR_OK; +} + +static int _uscxml_EC83C2A5_pass_on_entry(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { + _uscxml_EC83C2A5_pass_on_entry_0(ctx, state, event); + return USCXML_ERR_OK; +} + +static int _uscxml_EC83C2A5_fail_on_entry_0(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { + int err = USCXML_ERR_OK; + if likely(ctx->exec_content_log != NULL) { + if unlikely((ctx->exec_content_log(ctx, "Outcome", "'fail'")) != USCXML_ERR_OK) return err; } else { return USCXML_ERR_MISSING_CALLBACK; } return USCXML_ERR_OK; } -static int _uscxml_9FEEFF45_s1_on_entry(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { - _uscxml_9FEEFF45_s1_on_entry_0(ctx, state, event); +static int _uscxml_EC83C2A5_fail_on_entry(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { + _uscxml_EC83C2A5_fail_on_entry_0(ctx, state, event); return USCXML_ERR_OK; } -static const uscxml_state _uscxml_9FEEFF45_states[6] = { +#endif + +#ifndef USCXML_NO_ELEM_INFO + +static const uscxml_state _uscxml_EC83C2A5_states[6] = { { /* state number 0 */ /* name */ NULL, /* parent */ 0, @@ -437,13 +459,13 @@ static const uscxml_state _uscxml_9FEEFF45_states[6] = { /* children */ { 0x3e /* 011111 */ }, /* completion */ { 0x02 /* 010000 */ }, /* ancestors */ { 0x00 /* 000000 */ }, - /* data */ &_uscxml_9FEEFF45_elem_datas[0], + /* data */ &_uscxml_EC83C2A5_elem_datas[0], /* type */ USCXML_STATE_COMPOUND, }, { /* state number 1 */ /* name */ "s0", /* parent */ 0, - /* onentry */ _uscxml_9FEEFF45_s0_on_entry, + /* onentry */ NULL, /* onexit */ NULL, /* invoke */ NULL, /* children */ { 0x00 /* 000000 */ }, @@ -455,7 +477,7 @@ static const uscxml_state _uscxml_9FEEFF45_states[6] = { { /* state number 2 */ /* name */ "s1", /* parent */ 0, - /* onentry */ _uscxml_9FEEFF45_s1_on_entry, + /* onentry */ _uscxml_EC83C2A5_s1_on_entry, /* onexit */ NULL, /* invoke */ NULL, /* children */ { 0x00 /* 000000 */ }, @@ -467,7 +489,7 @@ static const uscxml_state _uscxml_9FEEFF45_states[6] = { { /* state number 3 */ /* name */ "s2", /* parent */ 0, - /* onentry */ NULL, + /* onentry */ _uscxml_EC83C2A5_s2_on_entry, /* onexit */ NULL, /* invoke */ NULL, /* children */ { 0x00 /* 000000 */ }, @@ -479,7 +501,7 @@ static const uscxml_state _uscxml_9FEEFF45_states[6] = { { /* state number 4 */ /* name */ "pass", /* parent */ 0, - /* onentry */ NULL, + /* onentry */ _uscxml_EC83C2A5_pass_on_entry, /* onexit */ NULL, /* invoke */ NULL, /* children */ { 0x00 /* 000000 */ }, @@ -491,7 +513,7 @@ static const uscxml_state _uscxml_9FEEFF45_states[6] = { { /* state number 5 */ /* name */ "fail", /* parent */ 0, - /* onentry */ NULL, + /* onentry */ _uscxml_EC83C2A5_fail_on_entry, /* onexit */ NULL, /* invoke */ NULL, /* children */ { 0x00 /* 000000 */ }, @@ -502,37 +524,41 @@ static const uscxml_state _uscxml_9FEEFF45_states[6] = { } }; -static const uscxml_transition _uscxml_9FEEFF45_transitions[6] = { +#endif + +#ifndef USCXML_NO_ELEM_INFO + +static const uscxml_transition _uscxml_EC83C2A5_transitions[6] = { { /* transition number 0 with priority 0 - target: fail + target: s1 */ /* source */ 1, - /* target */ { 0x20 /* 000001 */ }, - /* event */ "error", - /* condition */ NULL, + /* target */ { 0x04 /* 001000 */ }, + /* event */ NULL, + /* condition */ "Var1", /* ontrans */ NULL, - /* type */ 0, + /* type */ USCXML_TRANS_SPONTANEOUS, /* conflicts */ { 0x3f /* 111111 */ }, /* exit set */ { 0x3e /* 011111 */ } }, { /* transition number 1 with priority 1 - target: s1 + target: fail */ /* source */ 1, - /* target */ { 0x04 /* 001000 */ }, - /* event */ "*", - /* condition */ NULL, + /* target */ { 0x20 /* 000001 */ }, + /* event */ NULL, + /* condition */ "true", /* ontrans */ NULL, - /* type */ 0, + /* type */ USCXML_TRANS_SPONTANEOUS, /* conflicts */ { 0x3f /* 111111 */ }, /* exit set */ { 0x3e /* 011111 */ } }, { /* transition number 2 with priority 2 - target: fail + target: s2 */ /* source */ 2, - /* target */ { 0x20 /* 000001 */ }, - /* event */ "error", + /* target */ { 0x08 /* 000100 */ }, + /* event */ "error.execution", /* condition */ NULL, /* ontrans */ NULL, /* type */ 0, @@ -540,10 +566,10 @@ static const uscxml_transition _uscxml_9FEEFF45_transitions[6] = { /* exit set */ { 0x3e /* 011111 */ } }, { /* transition number 3 with priority 3 - target: s2 + target: fail */ /* source */ 2, - /* target */ { 0x08 /* 000100 */ }, + /* target */ { 0x20 /* 000001 */ }, /* event */ "*", /* condition */ NULL, /* ontrans */ NULL, @@ -557,7 +583,7 @@ static const uscxml_transition _uscxml_9FEEFF45_transitions[6] = { /* source */ 3, /* target */ { 0x10 /* 000010 */ }, /* event */ NULL, - /* condition */ "testvar4 ~= nil", + /* condition */ "Var1==Var2", /* ontrans */ NULL, /* type */ USCXML_TRANS_SPONTANEOUS, /* conflicts */ { 0x3f /* 111111 */ }, @@ -577,23 +603,32 @@ static const uscxml_transition _uscxml_9FEEFF45_transitions[6] = { } }; -const uscxml_machine uscxml_machines[2] = { - { +#endif + +#ifndef USCXML_NO_ELEM_INFO + +#ifndef USCXML_MACHINE +# define USCXML_MACHINE _uscxml_EC83C2A5_machine +#endif +#define USCXML_MACHINE_0 _uscxml_EC83C2A5_machine +#define USCXML_MACHINE_MACHINENAME _uscxml_EC83C2A5_machine + +const uscxml_machine _uscxml_EC83C2A5_machine = { /* flags */ 0, /* nr_states */ 6, /* nr_transitions */ 6, - /* name */ "", - /* datamodel */ "lua", - /* uuid */ "9FEEFF45D10C557438897A21612B7382", - /* states */ &_uscxml_9FEEFF45_states[0], - /* transitions */ &_uscxml_9FEEFF45_transitions[0], + /* name */ "machineName", + /* datamodel */ "ecmascript", + /* uuid */ "EC83C2A5BDF05B11A1F7E2C35039F65D", + /* states */ &_uscxml_EC83C2A5_states[0], + /* transitions */ &_uscxml_EC83C2A5_transitions[0], /* parent */ NULL, - /* donedata */ &_uscxml_9FEEFF45_elem_donedatas[0], + /* donedata */ &_uscxml_EC83C2A5_elem_donedatas[0], /* script */ NULL - }, - {0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; +#endif + #ifdef USCXML_VERBOSE /** * Print name of states contained in a (debugging). @@ -626,7 +661,7 @@ static void printBitsetIndices(const char* a, size_t length) { } #endif -#ifndef USCXML_BIT_OPERATIONS +#ifndef USCXML_NO_BIT_OPERATIONS /** * Return true if there is a common bit in a and b. */ @@ -696,10 +731,10 @@ static void bit_and(char* dest, const char* mask, size_t i) { }; } -#define USCXML_BIT_OPERATIONS +#define USCXML_NO_BIT_OPERATIONS #endif -#ifndef USCXML_STEP_FUNCTION +#ifndef USCXML_NO_STEP_FUNCTION int uscxml_step(uscxml_ctx* ctx) { USCXML_NR_TRANS_TYPE i, j, k; @@ -756,7 +791,7 @@ int uscxml_step(uscxml_ctx* ctx) { ctx->event = NULL; goto SELECT_TRANSITIONS; } - if ((ctx->event = ctx->dequeue_internal(ctx)) != NULL) { + if (ctx->dequeue_internal != NULL && (ctx->event = ctx->dequeue_internal(ctx)) != NULL) { goto SELECT_TRANSITIONS; } @@ -776,10 +811,15 @@ int uscxml_step(uscxml_ctx* ctx) { } } - if ((ctx->event = ctx->dequeue_external(ctx)) != NULL) { + if (ctx->dequeue_external != NULL && (ctx->event = ctx->dequeue_external(ctx)) != NULL) { goto SELECT_TRANSITIONS; } + if (ctx->dequeue_external == NULL) { + return USCXML_ERR_DONE; + } + return USCXML_ERR_IDLE; + SELECT_TRANSITIONS: bit_clear_all(conflicts, nr_trans_bytes); bit_clear_all(exit_set, nr_states_bytes); @@ -792,21 +832,25 @@ SELECT_TRANSITIONS: if (BIT_HAS(USCXML_GET_TRANS(i).source, ctx->config)) { /* is it non-conflicting? */ if (!BIT_HAS(i, conflicts)) { - /* is it enabled? */ - if (ctx->is_enabled(ctx, &USCXML_GET_TRANS(i), ctx->event) > 0) { - /* remember that we found a transition */ - ctx->flags |= USCXML_CTX_TRANSITION_FOUND; + /* is it spontaneous with an event or vice versa? */ + if ((USCXML_GET_TRANS(i).event == NULL && ctx->event == NULL) || + (USCXML_GET_TRANS(i).event != NULL && ctx->event != NULL)) { + /* is it enabled? */ + if (ctx->is_enabled(ctx, &USCXML_GET_TRANS(i), ctx->event) > 0) { + /* remember that we found a transition */ + ctx->flags |= USCXML_CTX_TRANSITION_FOUND; - /* transitions that are pre-empted */ - bit_or(conflicts, USCXML_GET_TRANS(i).conflicts, nr_trans_bytes); + /* transitions that are pre-empted */ + bit_or(conflicts, USCXML_GET_TRANS(i).conflicts, nr_trans_bytes); - /* states that are directly targeted (resolve as entry-set later) */ - bit_or(target_set, USCXML_GET_TRANS(i).target, nr_states_bytes); + /* states that are directly targeted (resolve as entry-set later) */ + bit_or(target_set, USCXML_GET_TRANS(i).target, nr_states_bytes); - /* states that will be left */ - bit_or(exit_set, USCXML_GET_TRANS(i).exit_set, nr_states_bytes); + /* states that will be left */ + bit_or(exit_set, USCXML_GET_TRANS(i).exit_set, nr_states_bytes); - BIT_SET_AT(i, trans_set); + BIT_SET_AT(i, trans_set); + } } } } @@ -1082,6 +1126,6 @@ ESTABLISH_ENTRY_SET: return USCXML_ERR_OK; } -#define USCXML_STEP_FUNCTION +#define USCXML_NO_STEP_FUNCTION #endif |