summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2014-07-30 20:41:50 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2014-07-30 20:41:50 (GMT)
commitb7a2d38bdcee3bf85a32dea7ac74b144d5ef40fa (patch)
treebade629bcca6b6a1417cb45be4349a3c27ea0feb
parentafbd0c4463c6f28ec1cd6ea45a68fdbcfcfeae6c (diff)
downloaduscxml-b7a2d38bdcee3bf85a32dea7ac74b144d5ef40fa.zip
uscxml-b7a2d38bdcee3bf85a32dea7ac74b144d5ef40fa.tar.gz
uscxml-b7a2d38bdcee3bf85a32dea7ac74b144d5ef40fa.tar.bz2
See detailled log
- Forcing Data.Type for Data(String) constructor now, default used to be INTERPRETED. - setDataModel and addIOProcessor on interpreter now - fixed a bug with Data(bool) constructor - various smaller fixes
-rw-r--r--apps/samples/vrml/viewer.html2
-rw-r--r--apps/uscxml-dot.cpp49
-rw-r--r--apps/uscxml-transform.cpp9
-rw-r--r--embedding/java/src/org/uscxml/tests/ioprocessor/console/ConsoleFrame.java74
-rw-r--r--embedding/java/src/org/uscxml/tests/ioprocessor/console/ConsoleIOProc.java93
-rw-r--r--src/bindings/swig/java/uscxml.i20
-rw-r--r--src/uscxml/Interpreter.cpp307
-rw-r--r--src/uscxml/Interpreter.h52
-rw-r--r--src/uscxml/URL.cpp2
-rw-r--r--src/uscxml/debug/SCXMLDotWriter.cpp172
-rw-r--r--src/uscxml/debug/SCXMLDotWriter.h10
-rw-r--r--src/uscxml/interpreter/InterpreterDraft6.cpp26
-rw-r--r--src/uscxml/interpreter/InterpreterDraft6.h1
-rw-r--r--src/uscxml/messages/Data.h8
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp5
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp6
-rw-r--r--src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp147
-rw-r--r--src/uscxml/plugins/datamodel/lua/LuaDataModel.h2
-rw-r--r--src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp2
-rw-r--r--src/uscxml/plugins/element/file/FileElement.cpp8
-rw-r--r--src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp2
-rw-r--r--src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp16
-rw-r--r--src/uscxml/plugins/invoker/graphics/openscenegraph/converter/OSGConverter.cpp2
-rw-r--r--src/uscxml/plugins/invoker/miles/MilesSessionInvoker.cpp28
-rw-r--r--src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp12
-rw-r--r--src/uscxml/transform/ChartToFSM.cpp147
-rw-r--r--src/uscxml/transform/ChartToFSM.h32
-rw-r--r--src/uscxml/transform/FSMToCPP.cpp545
-rw-r--r--src/uscxml/transform/FSMToCPP.h72
-rw-r--r--src/uscxml/transform/FlatStateIdentifier.h155
-rw-r--r--test/src/test-w3c.cpp2
-rw-r--r--test/w3c/lua/test201.scxml2
-rw-r--r--test/w3c/lua/test496.scxml2
-rw-r--r--test/w3c/lua/test500.scxml2
-rw-r--r--test/w3c/lua/test501.scxml2
-rw-r--r--test/w3c/lua/test509.scxml4
-rw-r--r--test/w3c/lua/test510.scxml2
-rw-r--r--test/w3c/lua/test518.scxml2
-rw-r--r--test/w3c/lua/test519.scxml2
-rw-r--r--test/w3c/lua/test520.scxml6
-rw-r--r--test/w3c/lua/test521.scxml2
-rw-r--r--test/w3c/lua/test522.scxml2
-rw-r--r--test/w3c/lua/test531.scxml2
-rw-r--r--test/w3c/lua/test532.scxml2
-rw-r--r--test/w3c/lua/test534.scxml2
-rw-r--r--test/w3c/lua/test553.scxml2
-rw-r--r--test/w3c/lua/test554.scxml2
-rw-r--r--test/w3c/lua/test567.scxml2
48 files changed, 1647 insertions, 401 deletions
diff --git a/apps/samples/vrml/viewer.html b/apps/samples/vrml/viewer.html
index 467681e..c585aaa 100644
--- a/apps/samples/vrml/viewer.html
+++ b/apps/samples/vrml/viewer.html
@@ -87,7 +87,7 @@
// serverURL: "http://femkit.smartvortex.eu:8086/vrml/",
// });
- var vrmlViewer = new VRMLViewer("scene1", {
+ var vrmlViewer = new eu_smartvorex_femkit_ui_modelviewer.VRMLViewer("scene1", {
resRoot: "/img/tridi/",
enableMovies: false,
enableDND: false,
diff --git a/apps/uscxml-dot.cpp b/apps/uscxml-dot.cpp
index 2b230b4..11e2994 100644
--- a/apps/uscxml-dot.cpp
+++ b/apps/uscxml-dot.cpp
@@ -39,29 +39,6 @@ void printUsageAndExit(const char* progName) {
int currOpt = 1;
-int32_t consumeNumericOption(int argc, char** argv, const std::string& name, int32_t defaultVal) {
- std::string test = argv[currOpt];
- if (boost::starts_with(test, std::string("-") + name)) {
- int value = 0;
- if (test.size() > 2) {
- // no space before value
- value = strTo<int>(test.substr(2, test.size() - 2));
- } else {
- // space before value
- if (argc > currOpt) {
- std::string tmp = argv[++currOpt];
- value = strTo<int>(tmp);
- } else {
- printUsageAndExit(argv[0]);
- }
- }
- currOpt++;
- return value;
- }
-
- return defaultVal;
-}
-
int main(int argc, char** argv) {
// setup logging
@@ -73,25 +50,26 @@ int main(int argc, char** argv) {
printUsageAndExit(argv[0]);
std::list<SCXMLDotWriter::StateAnchor> stateAnchors;
+ SCXMLDotWriter::StateAnchor rootAnchor;
SCXMLDotWriter::StateAnchor currAnchor;
int option;
- while ((option = getopt(argc, argv, "d:t:")) != -1) {
+ while ((option = getopt(argc, argv, "d:t:e:")) != -1) {
switch(option) {
case 'd':
- currAnchor.childDepth = strTo<int32_t>(optarg);
+ rootAnchor.childDepth = strTo<int32_t>(optarg);
break;
case 't':
- currAnchor.transDepth = strTo<int32_t>(optarg);
+ rootAnchor.transDepth = strTo<int32_t>(optarg);
break;
case 'e': {
std::string edgeType(optarg);
if (edgeType == "target") {
- currAnchor.type = SCXMLDotWriter::PORT_TARGET;
+ rootAnchor.type = SCXMLDotWriter::PORT_TARGET;
} else if (edgeType == "event") {
- currAnchor.type = SCXMLDotWriter::PORT_EVENT;
+ rootAnchor.type = SCXMLDotWriter::PORT_EVENT;
} else if (edgeType == "transition") {
- currAnchor.type = SCXMLDotWriter::PORT_TRANSITION;
+ rootAnchor.type = SCXMLDotWriter::PORT_TRANSITION;
} else {
printUsageAndExit(argv[0]);
}
@@ -102,8 +80,8 @@ int main(int argc, char** argv) {
}
}
- if (currAnchor)
- stateAnchors.push_back(currAnchor);
+ if (rootAnchor)
+ stateAnchors.push_back(rootAnchor);
try {
// current option has to be the interpreter's name
@@ -133,13 +111,20 @@ int main(int argc, char** argv) {
}
if (currAnchor) {
+ currAnchor.type = rootAnchor.type;
stateAnchors.push_back(currAnchor);
}
currAnchor = SCXMLDotWriter::StateAnchor();
}
- std::string outName = inputFile.file() + ".dot";
+ std::string outName;
+ if (boost::starts_with("file", inputFile.scheme())) {
+ outName = inputFile.path() + ".dot";
+ } else {
+ outName = inputFile.file() + ".dot";
+ }
+
SCXMLDotWriter::toDot(outName, interpreter, stateAnchors);
} catch(Event e) {
diff --git a/apps/uscxml-transform.cpp b/apps/uscxml-transform.cpp
index 245a89c..fc33617 100644
--- a/apps/uscxml-transform.cpp
+++ b/apps/uscxml-transform.cpp
@@ -193,7 +193,14 @@ int main(int argc, char** argv) {
}
if (toFlat) {
- std::cout << ChartToFSM::flatten(interpreter).getDocument();
+ if (outputFile.size() == 0 || outputFile == "-") {
+ std::cout << ChartToFSM::flatten(interpreter).getDocument();
+ } else {
+ std::ofstream outStream;
+ outStream.open(outputFile.c_str());
+ outStream << ChartToFSM::flatten(interpreter).getDocument();
+ outStream.close();
+ }
exit(EXIT_SUCCESS);
}
} catch (Event e) {
diff --git a/embedding/java/src/org/uscxml/tests/ioprocessor/console/ConsoleFrame.java b/embedding/java/src/org/uscxml/tests/ioprocessor/console/ConsoleFrame.java
new file mode 100644
index 0000000..b44c05e
--- /dev/null
+++ b/embedding/java/src/org/uscxml/tests/ioprocessor/console/ConsoleFrame.java
@@ -0,0 +1,74 @@
+package org.uscxml.tests.ioprocessor.console;
+
+import java.awt.Frame;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import org.uscxml.Factory;
+import org.uscxml.Interpreter;
+import org.uscxml.InterpreterException;
+
+public class ConsoleFrame extends Frame {
+
+ private static final long serialVersionUID = 3682378173372160680L;
+ public static Map<Interpreter, Frame> perInterpreter = new HashMap<Interpreter, Frame>();
+
+ public ConsoleFrame() throws InterpreterException {
+ super("Input Frame");
+ JPanel p = new JPanel();
+ JLabel label = new JLabel("Key Listener!");
+ p.add(label);
+ add(p);
+ setSize(200, 100);
+
+ final Interpreter interpreter = Interpreter.fromXML(
+ "<scxml datamodel=\"ecmascript\">"
+ + " <script src=\"http://uscxml.tk.informatik.tu-darmstadt.de/scripts/dump.js\" />"
+ + " <script>var charSeq = \"\";</script>"
+ + " <state id=\"idle\">"
+ + " <transition event=\"key.released\" cond=\"_event.data.keyChar == 10\">"
+ + " <log expr=\"charSeq\" />"
+ + " <script>"
+ + " charSeq = \"\";"
+ + " </script>"
+ + " </transition>"
+ + " <transition event=\"*\">"
+ + " <log label=\"event\" expr=\"dump(_event.data)\" />"
+ + " <script>charSeq += String.fromCharCode(_event.data.keyChar);</script>"
+ + " </transition>"
+ + " </state>"
+ + "</scxml>");
+
+
+ perInterpreter.put(interpreter, this);
+
+ Thread intrerpreterThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ interpreter.interpret();
+ } catch (InterpreterException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ intrerpreterThread.start();
+
+ setVisible(true);
+ }
+
+ public static void main(String[] args) throws InterpreterException {
+ System.load("/Users/sradomski/Documents/TK/Code/uscxml/build/cli/lib/libuscxmlNativeJava64.jnilib");
+
+ ConsoleIOProc ioProc = new ConsoleIOProc();
+ Factory.getInstance().registerIOProcessor(ioProc);
+
+ ConsoleFrame frame = new ConsoleFrame();
+
+ }
+
+}
+
diff --git a/embedding/java/src/org/uscxml/tests/ioprocessor/console/ConsoleIOProc.java b/embedding/java/src/org/uscxml/tests/ioprocessor/console/ConsoleIOProc.java
new file mode 100644
index 0000000..f0ad491
--- /dev/null
+++ b/embedding/java/src/org/uscxml/tests/ioprocessor/console/ConsoleIOProc.java
@@ -0,0 +1,93 @@
+package org.uscxml.tests.ioprocessor.console;
+
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+import org.uscxml.Data;
+import org.uscxml.Event;
+import org.uscxml.IOProcessor;
+import org.uscxml.Interpreter;
+import org.uscxml.SendRequest;
+import org.uscxml.StringList;
+
+public class ConsoleIOProc extends IOProcessor implements KeyListener {
+
+ /** IOProcessor */
+ @Override
+ public IOProcessor create(Interpreter interpreter) {
+ ConsoleIOProc ioProc = new ConsoleIOProc();
+ ioProc.swigReleaseOwnership();
+
+ if (ConsoleFrame.perInterpreter.containsKey(interpreter)) {
+ ConsoleFrame.perInterpreter.get(interpreter).addKeyListener(ioProc);
+ } else {
+ System.err.println("No data for interpreter specific instances");
+ }
+ return ioProc;
+ }
+
+ /** IOProcessor */
+ @Override
+ public StringList getNames() {
+ StringList ss = new StringList();
+ ss.add("console");
+ return ss;
+ }
+
+ /** IOProcessor */
+ @Override
+ public Data getDataModelVariables() {
+ // return anything for _ioprocessor['console']
+ Data data = Data.fromJSON("{ foo: \"bar\", test: [1,2,3,4,5,6] }");
+ return data;
+ }
+
+ /** IOProcessor */
+ @Override
+ public void send(SendRequest req) {
+ // interpreter wants to send something, just print on console
+ System.out.println(req);
+ }
+
+ /** KeyListener */
+ @Override
+ public void keyPressed(KeyEvent e) {
+ Event evt = new Event("key.pressed");
+ evt.setData(keyEventToData(e));
+ returnEvent(evt, true);
+ }
+
+ /** KeyListener */
+ @Override
+ public void keyReleased(KeyEvent e) {
+ Event evt = new Event("key.released");
+ evt.setData(keyEventToData(e));
+ returnEvent(evt, true);
+ }
+
+ /** KeyListener */
+ @Override
+ public void keyTyped(KeyEvent e) {
+ Event evt = new Event("key.typed");
+ evt.setData(keyEventToData(e));
+ returnEvent(evt, true);
+ }
+
+ static Data keyEventToData(KeyEvent e) {
+ Data data = new Data();
+ data.put("id", new Data(e.getID()));
+ data.put("keyChar", new Data(e.getKeyChar()));
+ data.put("keyLocation", new Data(e.getKeyLocation()));
+ data.put("modifiers", new Data(e.getModifiers()));
+ data.put("modifiersEx", new Data(e.getModifiersEx()));
+ data.put("when", new Data(e.getWhen()));
+ data.put("actionKey", new Data(e.isActionKey()));
+ data.put("altDown", new Data(e.isAltDown()));
+ data.put("altGraphDown", new Data(e.isAltGraphDown()));
+ data.put("ctrlDown", new Data(e.isControlDown()));
+ data.put("metaDown", new Data(e.isMetaDown()));
+ data.put("shiftDown", new Data(e.isShiftDown()));
+
+ return data;
+ }
+} \ No newline at end of file
diff --git a/src/bindings/swig/java/uscxml.i b/src/bindings/swig/java/uscxml.i
index 688ca6e..036b244 100644
--- a/src/bindings/swig/java/uscxml.i
+++ b/src/bindings/swig/java/uscxml.i
@@ -42,7 +42,7 @@ typedef uscxml::ExecutableContentImpl ExecutableContentImpl;
%javaconst(1);
-%rename(equals) operator==;
+%rename(equals) operator==; // signature is wrong, still useful
%rename(isValid) operator bool;
//**************************************************
@@ -98,6 +98,15 @@ WRAP_THROW_EXCEPTION(uscxml::Interpreter::step);
WRAP_THROW_EXCEPTION(uscxml::Interpreter::interpret);
+%define WRAP_HASHCODE( CLASSNAME )
+%extend CLASSNAME {
+ virtual int hashCode() {
+/* std::cout << "Calc hashcode as " << (int)(size_t)self->getImpl().get() << std::endl << std::flush;*/
+ return (int)(size_t)self->getImpl().get();
+ }
+};
+%enddef
+
%define WRAP_TO_STRING( CLASSNAME )
%extend CLASSNAME {
virtual std::string toString() {
@@ -113,6 +122,8 @@ WRAP_TO_STRING(uscxml::Data);
WRAP_TO_STRING(uscxml::SendRequest);
WRAP_TO_STRING(uscxml::InvokeRequest);
+WRAP_HASHCODE(uscxml::Interpreter);
+
%include "../uscxml_ignores.i"
#if 0
@@ -240,6 +251,13 @@ import java.net.URL;
return invokers;
}
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof Interpreter) {
+ return equals((Interpreter)other);
+ }
+ return hashCode() == other.hashCode();
+ }
%}
%rename(getCompoundNative) uscxml::Data::getCompound();
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
index 8767242..438aec3 100644
--- a/src/uscxml/Interpreter.cpp
+++ b/src/uscxml/Interpreter.cpp
@@ -353,6 +353,7 @@ InterpreterImpl::InterpreterImpl() {
_topLevelFinalReached = false;
_stable = false;
_isInitialized = false;
+ _userSuppliedDataModel = false;
_domIsSetup = false;
_httpServlet = NULL;
_factory = NULL;
@@ -723,6 +724,7 @@ void InterpreterImpl::setupDOM() {
// normalize document
// TODO: Resolve XML includes
+#if 0
// make sure every state has an id
Arabica::XPath::NodeSet<std::string> states;
states.push_back(_xpath.evaluate("//" + _nsInfo.xpathPrefix + "state", _scxml).asNodeSet());
@@ -734,6 +736,7 @@ void InterpreterImpl::setupDOM() {
stateElem.setAttribute("id", UUID::getUUID());
}
}
+#endif
// make sure every invoke has an idlocation or id
Arabica::XPath::NodeSet<std::string> invokes = _xpath.evaluate("//" + _nsInfo.xpathPrefix + "invoke", _scxml).asNodeSet();
@@ -744,10 +747,12 @@ void InterpreterImpl::setupDOM() {
}
}
+#if 0
// add an id to the scxml element
if (!_scxml.hasAttribute("id")) {
_scxml.setAttribute("id", UUID::getUUID());
}
+#endif
// register for dom events to manage cached states
Arabica::DOM::Events::EventTarget<std::string> eventTarget(_scxml);
@@ -779,12 +784,14 @@ void InterpreterImpl::init() {
// start io processoes
setupIOProcessors();
- // instantiate datamodel
- if (HAS_ATTR(_scxml, "datamodel")) {
- // might throw
- _dataModel = _factory->createDataModel(ATTR(_scxml, "datamodel"), this);
- } else {
- _dataModel = _factory->createDataModel("null", this);
+ // instantiate datamodel if not explicitly set
+ if (!_dataModel) {
+ if (HAS_ATTR(_scxml, "datamodel")) {
+ // might throw
+ _dataModel = _factory->createDataModel(ATTR(_scxml, "datamodel"), this);
+ } else {
+ _dataModel = _factory->createDataModel("null", this);
+ }
}
_dataModel.assign("_x.args", _cmdLineOptions);
@@ -820,9 +827,7 @@ void InterpreterImpl::init() {
// executeGlobalScriptElements
NodeSet<std::string> globalScriptElems = filterChildElements(_nsInfo.xmlNSPrefix + "script", _scxml);
for (unsigned int i = 0; i < globalScriptElems.size(); i++) {
- if (_dataModel) {
- executeContent(Element<std::string>(globalScriptElems[i]));
- }
+ executeContent(Element<std::string>(globalScriptElems[i]));
}
_isInitialized = true;
@@ -833,10 +838,6 @@ void InterpreterImpl::init() {
* Called with a single data element from the topmost datamodel element.
*/
void InterpreterImpl::initializeData(const Element<std::string>& data) {
- if (!_dataModel) {
- LOG(ERROR) << "Cannot initialize data when no datamodel is given!";
- return;
- }
/// test 226/240 - initialize from invoke request
if (_invokeReq.params.find(ATTR(data, "id")) != _invokeReq.params.end()) {
@@ -893,7 +894,9 @@ void InterpreterImpl::internalDoneSend(const Arabica::DOM::Element<std::string>&
if (!isState(state))
return;
- Arabica::DOM::Element<std::string> parent = (Arabica::DOM::Element<std::string>)state.getParentNode();
+ if (parentIsScxmlState(state))
+ return;
+
Event event;
Arabica::XPath::NodeSet<std::string> doneDatas = filterChildElements(_nsInfo.xmlNSPrefix + "donedata", state);
@@ -907,7 +910,7 @@ void InterpreterImpl::internalDoneSend(const Arabica::DOM::Element<std::string>&
if (contents.size() > 0) {
std::string expr;
processContentElement(contents[0], event.dom, event.content, expr);
- if (expr.length() > 0 && _dataModel) {
+ if (expr.length() > 0) {
try {
event.content =_dataModel.evalAsString(expr);
} catch (Event e) {
@@ -942,7 +945,7 @@ void InterpreterImpl::processDOMorText(const Arabica::DOM::Node<std::string>& el
std::string& text) {
// do we need to download?
if (HAS_ATTR(element, "src") ||
- (HAS_ATTR(element, "srcexpr") && _dataModel)) {
+ (HAS_ATTR(element, "srcexpr"))) {
std::stringstream srcContent;
URL sourceURL(HAS_ATTR(element, "srcexpr") ? _dataModel.evalAsString(ATTR(element, "srcexpr")) : ATTR(element, "src"));
if (!sourceURL.toAbsolute(_baseURI)) {
@@ -1042,9 +1045,9 @@ void InterpreterImpl::processParamChilds(const Arabica::DOM::Node<std::string>&
continue;
}
Data paramValue;
- if (HAS_ATTR(paramElems[i], "expr") && _dataModel) {
+ if (HAS_ATTR(paramElems[i], "expr")) {
paramValue = _dataModel.getStringAsData(ATTR(paramElems[i], "expr"));
- } else if(HAS_ATTR(paramElems[i], "location") && _dataModel) {
+ } else if(HAS_ATTR(paramElems[i], "location")) {
paramValue = _dataModel.getStringAsData(ATTR(paramElems[i], "location"));
} else {
LOG(ERROR) << "param element is missing expr or location or no datamodel is specified";
@@ -1072,7 +1075,7 @@ void InterpreterImpl::send(const Arabica::DOM::Node<std::string>& element) {
sendReq.Event::eventType = Event::EXTERNAL;
try {
// event
- if (HAS_ATTR(element, "eventexpr") && _dataModel) {
+ if (HAS_ATTR(element, "eventexpr")) {
sendReq.name = _dataModel.evalAsString(ATTR(element, "eventexpr"));
} else if (HAS_ATTR(element, "event")) {
sendReq.name = ATTR(element, "event");
@@ -1083,7 +1086,7 @@ void InterpreterImpl::send(const Arabica::DOM::Node<std::string>& element) {
}
try {
// target
- if (HAS_ATTR(element, "targetexpr") && _dataModel) {
+ if (HAS_ATTR(element, "targetexpr")) {
sendReq.target = _dataModel.evalAsString(ATTR(element, "targetexpr"));
} else if (HAS_ATTR(element, "target")) {
sendReq.target = ATTR(element, "target");
@@ -1094,7 +1097,7 @@ void InterpreterImpl::send(const Arabica::DOM::Node<std::string>& element) {
}
try {
// type
- if (HAS_ATTR(element, "typeexpr") && _dataModel) {
+ if (HAS_ATTR(element, "typeexpr")) {
sendReq.type = _dataModel.evalAsString(ATTR(element, "typeexpr"));
} else if (HAS_ATTR(element, "type")) {
sendReq.type = ATTR(element, "type");
@@ -1128,8 +1131,8 @@ void InterpreterImpl::send(const Arabica::DOM::Node<std::string>& element) {
*
*/
sendReq.sendid = ATTR(getParentState(element), "id") + "." + UUID::getUUID();
- if (HAS_ATTR(element, "idlocation") && _dataModel) {
- _dataModel.assign(ATTR(element, "idlocation"), "'" + sendReq.sendid + "'");
+ if (HAS_ATTR(element, "idlocation")) {
+ _dataModel.assign(ATTR(element, "idlocation"), Data("'" + sendReq.sendid + "'", Data::INTERPRETED));
} else {
sendReq.hideSendId = true;
}
@@ -1143,7 +1146,7 @@ void InterpreterImpl::send(const Arabica::DOM::Node<std::string>& element) {
// delay
std::string delay;
sendReq.delayMs = 0;
- if (HAS_ATTR(element, "delayexpr") && _dataModel) {
+ if (HAS_ATTR(element, "delayexpr")) {
delay = _dataModel.evalAsString(ATTR(element, "delayexpr"));
} else if (HAS_ATTR(element, "delay")) {
delay = ATTR(element, "delay");
@@ -1202,7 +1205,7 @@ void InterpreterImpl::send(const Arabica::DOM::Node<std::string>& element) {
if (contents.size() > 0) {
std::string expr;
processContentElement(contents[0], sendReq.dom, sendReq.content, expr);
- if (expr.length() > 0 && _dataModel) {
+ if (expr.length() > 0) {
try {
sendReq.data = _dataModel.getStringAsData(expr);
} catch (Event e) {
@@ -1279,7 +1282,7 @@ void InterpreterImpl::invoke(const Arabica::DOM::Node<std::string>& element) {
invokeReq.Event::eventType = Event::EXTERNAL;
try {
// type
- if (HAS_ATTR(element, "typeexpr") && _dataModel) {
+ if (HAS_ATTR(element, "typeexpr")) {
invokeReq.type = _dataModel.evalAsString(ATTR(element, "typeexpr"));
} else if (HAS_ATTR(element, "type")) {
invokeReq.type = ATTR(element, "type");
@@ -1287,7 +1290,7 @@ void InterpreterImpl::invoke(const Arabica::DOM::Node<std::string>& element) {
// src
std::string source;
- if (HAS_ATTR(element, "srcexpr") && _dataModel) {
+ if (HAS_ATTR(element, "srcexpr")) {
source = _dataModel.evalAsString(ATTR(element, "srcexpr"));
} else if (HAS_ATTR(element, "src")) {
source = ATTR(element, "src");
@@ -1307,8 +1310,8 @@ void InterpreterImpl::invoke(const Arabica::DOM::Node<std::string>& element) {
invokeReq.invokeid = ATTR(element, "id");
} else {
invokeReq.invokeid = ATTR(getParentState(element), "id") + "." + UUID::getUUID();
- if (HAS_ATTR(element, "idlocation") && _dataModel) {
- _dataModel.assign(ATTR(element, "idlocation"), "'" + invokeReq.invokeid + "'");
+ if (HAS_ATTR(element, "idlocation")) {
+ _dataModel.assign(ATTR(element, "idlocation"), Data("'" + invokeReq.invokeid + "'", Data::INTERPRETED));
}
}
} catch (Event e) {
@@ -1352,7 +1355,7 @@ void InterpreterImpl::invoke(const Arabica::DOM::Node<std::string>& element) {
if (contents.size() > 0) {
std::string expr;
processContentElement(contents[0], invokeReq.dom, invokeReq.content, expr);
- if (expr.length() > 0 && _dataModel) {
+ if (expr.length() > 0) {
try {
invokeReq.data =_dataModel.getStringAsData(expr);
} catch (Event e) {
@@ -1414,12 +1417,10 @@ void InterpreterImpl::invoke(const Arabica::DOM::Node<std::string>& element) {
} catch(...) {
LOG(ERROR) << "Unknown exception caught while sending invoke request to invoker " << invokeReq.invokeid;
}
- if (_dataModel) {
- try {
+ try {
// _dataModel.assign("_invokers['" + invokeReq.invokeid + "']", invoker.getDataModelVariables());
- } catch(...) {
- LOG(ERROR) << "Exception caught while assigning datamodel variables from invoker " << invokeReq.invokeid;
- }
+ } catch(...) {
+ LOG(ERROR) << "Exception caught while assigning datamodel variables from invoker " << invokeReq.invokeid;
}
} catch (...) {
LOG(ERROR) << "Invoker " << invokeReq.type << " threw an exception";
@@ -1435,7 +1436,7 @@ void InterpreterImpl::invoke(const Arabica::DOM::Node<std::string>& element) {
void InterpreterImpl::cancelInvoke(const Arabica::DOM::Node<std::string>& element) {
std::string invokeId;
- if (HAS_ATTR(element, "idlocation") && _dataModel) {
+ if (HAS_ATTR(element, "idlocation")) {
invokeId = _dataModel.evalAsString(ATTR(element, "idlocation"));
} else if (HAS_ATTR(element, "id")) {
invokeId = ATTR(element, "id");
@@ -1444,12 +1445,10 @@ void InterpreterImpl::cancelInvoke(const Arabica::DOM::Node<std::string>& elemen
}
if (_invokers.find(invokeId) != _invokers.end()) {
LOG(INFO) << "Removed invoker at " << invokeId;
- if (_dataModel) {
- try {
- _dataModel.assign("_invokers['" + invokeId + "']", std::string("''"));
- } catch (Event e) {
- LOG(ERROR) << "Syntax when removing invoker:" << std::endl << e << std::endl;
- }
+ try {
+ _dataModel.assign("_invokers['" + invokeId + "']", Data(std::string("''"), Data::INTERPRETED));
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax when removing invoker:" << std::endl << e << std::endl;
}
USCXML_MONITOR_CALLBACK3(beforeUninvoking, Element<std::string>(element), invokeId)
@@ -1464,8 +1463,62 @@ void InterpreterImpl::cancelInvoke(const Arabica::DOM::Node<std::string>& elemen
//receiveInternal(Event("done.invoke." + invokeId, Event::PLATFORM));
}
+#if 1
// see: http://www.w3.org/TR/scxml/#EventDescriptors
+bool InterpreterImpl::nameMatch(const std::string& eventDescs, const std::string& eventName) {
+ if(eventDescs.length() == 0 || eventName.length() == 0)
+ return false;
+
+ // naive case of single descriptor and exact match
+ if (iequals(eventDescs, eventName))
+ return true;
+
+ size_t start = 0;
+ std::string eventDesc;
+ for (int i = 0; i < eventDescs.size(); i++) {
+ if (isspace(eventDescs[i])) {
+ if (i > 0 && start < i - 1) {
+ eventDesc = eventDescs.substr(start, i - start);
+ }
+ while(isspace(eventDescs[++i])); // skip whitespaces
+ start = i;
+ } else if (i + 1 == eventDescs.size()) {
+ eventDesc = eventDescs.substr(start, i + 1 - start);
+ }
+
+ if (eventDesc.size() > 0) {
+ // remove optional trailing .* for CCXML compatibility
+ if (eventDesc.find("*", eventDesc.size() - 1) != std::string::npos)
+ eventDesc = eventDesc.substr(0, eventDesc.size() - 1);
+ if (eventDesc.find(".", eventDesc.size() - 1) != std::string::npos)
+ eventDesc = eventDesc.substr(0, eventDesc.size() - 1);
+
+ // was eventDesc the * wildcard
+ if (eventDesc.size() == 0)
+ return true;
+
+ // eventDesc has to be a real prefix of event now and therefore shorter
+ if (eventDesc.size() >= eventName.size())
+ goto NEXT_DESC;
+
+ // are they already equal?
+ if (iequals(eventDesc, eventName))
+ return true;
+
+ if (eventName.find(eventDesc) == 0) {
+ if (eventName.find(".", eventDesc.size()) == eventDesc.size())
+ return true;
+ }
+NEXT_DESC:
+ eventDesc = "";
+ }
+ }
+ return false;
+}
+
+#else
+// see: http://www.w3.org/TR/scxml/#EventDescriptors
bool InterpreterImpl::nameMatch(const std::string& transitionEvent, const std::string& event) {
if(transitionEvent.length() == 0 || event.length() == 0)
return false;
@@ -1507,7 +1560,7 @@ bool InterpreterImpl::nameMatch(const std::string& transitionEvent, const std::s
}
return false;
}
-
+#endif
bool InterpreterImpl::hasConditionMatch(const Arabica::DOM::Element<std::string>& conditional) {
if (HAS_ATTR(conditional, "cond") && ATTR(conditional, "cond").length() > 0) {
@@ -1588,7 +1641,7 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Element<std::string>& c
if (contents.size() > 0) {
std::string expr;
processContentElement(contents[0], raised.dom, raised.content, expr);
- if (expr.length() > 0 && _dataModel) {
+ if (expr.length() > 0) {
try {
raised.data = _dataModel.getStringAsData(expr);
} catch (Event e) {
@@ -1657,33 +1710,31 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Element<std::string>& c
std::cerr << "Found single else to evaluate!" << std::endl;
} else if (iequals(TAGNAME(content), _nsInfo.xmlNSPrefix + "foreach")) {
// --- FOREACH --------------------------
- if (_dataModel) {
- if (HAS_ATTR(content, "array") && HAS_ATTR(content, "item")) {
- std::string array = ATTR(content, "array");
- std::string item = ATTR(content, "item");
- std::string index = (HAS_ATTR(content, "index") ? ATTR(content, "index") : "");
- uint32_t iterations = 0;
- try {
- iterations = _dataModel.getLength(array);
- }
- CATCH_AND_DISTRIBUTE2("Syntax error in array attribute of foreach element", content)
- try {
- _dataModel.pushContext(); // copy old and enter new context
+ if (HAS_ATTR(content, "array") && HAS_ATTR(content, "item")) {
+ std::string array = ATTR(content, "array");
+ std::string item = ATTR(content, "item");
+ std::string index = (HAS_ATTR(content, "index") ? ATTR(content, "index") : "");
+ uint32_t iterations = 0;
+ try {
+ iterations = _dataModel.getLength(array);
+ }
+ CATCH_AND_DISTRIBUTE2("Syntax error in array attribute of foreach element", content)
+ try {
+ _dataModel.pushContext(); // copy old and enter new context
// if (!_dataModel.isDeclared(item)) {
// _dataModel.init(item, Data());
// }
- for (uint32_t iteration = 0; iteration < iterations; iteration++) {
- _dataModel.setForeach(item, array, index, iteration);
- if (content.hasChildNodes())
- // execute content and have exception rethrown to break foreach
- executeContent(content.getChildNodes(), rethrow);
- }
- _dataModel.popContext(); // leave stacked context
+ for (uint32_t iteration = 0; iteration < iterations; iteration++) {
+ _dataModel.setForeach(item, array, index, iteration);
+ if (content.hasChildNodes())
+ // execute content and have exception rethrown to break foreach
+ executeContent(content.getChildNodes(), rethrow);
}
- CATCH_AND_DISTRIBUTE2("Syntax error in foreach element", content)
- } else {
- LOG(ERROR) << "Expected array and item attributes with foreach element!" << std::endl;
+ _dataModel.popContext(); // leave stacked context
}
+ CATCH_AND_DISTRIBUTE2("Syntax error in foreach element", content)
+ } else {
+ LOG(ERROR) << "Expected array and item attributes with foreach element!" << std::endl;
}
} else if (iequals(TAGNAME(content), _nsInfo.xmlNSPrefix + "log")) {
// --- LOG --------------------------
@@ -1701,7 +1752,7 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Element<std::string>& c
}
} else if (iequals(TAGNAME(content), _nsInfo.xmlNSPrefix + "assign")) {
// --- ASSIGN --------------------------
- if (_dataModel && HAS_ATTR(content, "location")) {
+ if (HAS_ATTR(content, "location")) {
try {
if (!_dataModel.isDeclared(ATTR(content, "location"))) {
// test 286, 331
@@ -1717,64 +1768,60 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Element<std::string>& c
}
} else if (iequals(TAGNAME(content), _nsInfo.xmlNSPrefix + "validate")) {
// --- VALIDATE --------------------------
- if (_dataModel) {
- std::string location = (HAS_ATTR(content, "location") ? ATTR(content, "location") : "");
- std::string schema = (HAS_ATTR(content, "schema") ? ATTR(content, "schema") : "");
- _dataModel.validate(location, schema);
- }
+ std::string location = (HAS_ATTR(content, "location") ? ATTR(content, "location") : "");
+ std::string schema = (HAS_ATTR(content, "schema") ? ATTR(content, "schema") : "");
+ _dataModel.validate(location, schema);
} else if (iequals(TAGNAME(content), _nsInfo.xmlNSPrefix + "script")) {
// --- SCRIPT --------------------------
- if (_dataModel) {
- if (HAS_ATTR(content, "src")) {
- URL scriptUrl(ATTR(content, "src"));
- if (!scriptUrl.isAbsolute() && !_baseURI) {
- LOG(ERROR) << "script element has relative URI " << ATTR(content, "src") << " with no base URI set for interpreter";
- return;
- }
+ if (HAS_ATTR(content, "src")) {
+ URL scriptUrl(ATTR(content, "src"));
+ if (!scriptUrl.isAbsolute() && !_baseURI) {
+ LOG(ERROR) << "script element has relative URI " << ATTR(content, "src") << " with no base URI set for interpreter";
+ return;
+ }
- if (!scriptUrl.toAbsolute(_baseURI)) {
- LOG(ERROR) << "Failed to convert relative script URI " << ATTR(content, "src") << " to absolute with base URI " << _baseURI.asString();
- return;
- }
+ if (!scriptUrl.toAbsolute(_baseURI)) {
+ LOG(ERROR) << "Failed to convert relative script URI " << ATTR(content, "src") << " to absolute with base URI " << _baseURI.asString();
+ return;
+ }
- std::stringstream srcContent;
- try {
- if (_cachedURLs.find(scriptUrl.asString()) != _cachedURLs.end() && false) {
- srcContent << _cachedURLs[scriptUrl.asString()];
- } else {
- srcContent << scriptUrl;
- if (scriptUrl.downloadFailed()) {
- LOG(ERROR) << "script element source cannot be downloaded";
- }
- _cachedURLs[scriptUrl.asString()] = scriptUrl;
- }
- } catch (Event exception) {
- // script failed to download
- if (exception.name == "error.communication") {
- throw exception; // terminate test329, test301
+ std::stringstream srcContent;
+ try {
+ if (_cachedURLs.find(scriptUrl.asString()) != _cachedURLs.end() && false) {
+ srcContent << _cachedURLs[scriptUrl.asString()];
+ } else {
+ srcContent << scriptUrl;
+ if (scriptUrl.downloadFailed()) {
+ LOG(ERROR) << "script element source cannot be downloaded";
}
- receive(exception);
- return;
+ _cachedURLs[scriptUrl.asString()] = scriptUrl;
+ }
+ } catch (Event exception) {
+ // script failed to download
+ if (exception.name == "error.communication") {
+ throw exception; // terminate test329, test301
}
+ receive(exception);
+ return;
+ }
- try {
- _dataModel.eval((Element<std::string>)content, srcContent.str());
+ try {
+ _dataModel.eval((Element<std::string>)content, srcContent.str());
+ }
+ CATCH_AND_DISTRIBUTE("Syntax error while executing script element from '" + ATTR(content, "src") + "':")
+ } else {
+ if (content.hasChildNodes()) {
+ // search for the text node with the actual script
+ std::string scriptContent;
+ for (Node<std::string> child = content.getFirstChild(); child; child = child.getNextSibling()) {
+ if (child.getNodeType() == Node_base::TEXT_NODE || child.getNodeType() == Node_base::CDATA_SECTION_NODE)
+ scriptContent += child.getNodeValue();
}
- CATCH_AND_DISTRIBUTE("Syntax error while executing script element from '" + ATTR(content, "src") + "':")
- } else {
- if (content.hasChildNodes()) {
- // search for the text node with the actual script
- std::string scriptContent;
- for (Node<std::string> child = content.getFirstChild(); child; child = child.getNextSibling()) {
- if (child.getNodeType() == Node_base::TEXT_NODE || child.getNodeType() == Node_base::CDATA_SECTION_NODE)
- scriptContent += child.getNodeValue();
- }
- if (scriptContent.size() > 0) {
- try {
- _dataModel.eval((Element<std::string>)content, scriptContent);
- }
- CATCH_AND_DISTRIBUTE2("Syntax error while executing script element", content)
+ if (scriptContent.size() > 0) {
+ try {
+ _dataModel.eval((Element<std::string>)content, scriptContent);
}
+ CATCH_AND_DISTRIBUTE2("Syntax error while executing script element", content)
}
}
}
@@ -2281,9 +2328,8 @@ bool InterpreterImpl::isDescendant(const Arabica::DOM::Node<std::string>& s1,
}
bool InterpreterImpl::isTargetless(const Arabica::DOM::Element<std::string>& transition) {
- if (transition.hasAttributes()) {
- if (((Arabica::DOM::Element<std::string>)transition).hasAttribute("target"))
- return false;
+ if (transition.hasAttribute("target")) {
+ return false;
}
return true;
}
@@ -2428,6 +2474,12 @@ void InterpreterImpl::setupIOProcessors() {
continue;
}
+ // do not override if already set
+ if (_ioProcessors.find(ioProcIter->first) != _ioProcessors.end()) {
+ ioProcIter++;
+ continue;
+ }
+
// this might throw error.execution
_ioProcessors[ioProcIter->first] = _factory->createIOProcessor(ioProcIter->first, this);
_ioProcessors[ioProcIter->first].setType(ioProcIter->first);
@@ -2447,19 +2499,16 @@ void InterpreterImpl::setupIOProcessors() {
std::list<std::string> names = _ioProcessors[ioProcIter->first].getNames();
std::list<std::string>::iterator nameIter = names.begin();
while(nameIter != names.end()) {
- if (!boost::equal(*nameIter, ioProcIter->first))
+ // do not override
+ if (!boost::equal(*nameIter, ioProcIter->first) && _ioProcessors.find(*nameIter) != _ioProcessors.end())
_ioProcessors[*nameIter] = _ioProcessors[ioProcIter->first];
nameIter++;
}
#if 0
- if (_dataModel) {
- try {
- _dataModel.registerIOProcessor(ioProcIter->first, _ioProcessors[ioProcIter->first]);
- } catch (Event e) {
- LOG(ERROR) << "Syntax error when setting _ioprocessors:" << std::endl << e << std::endl;
- }
- } else {
- LOG(INFO) << "Not registering " << ioProcIter->first << " at _ioprocessors in datamodel, no datamodel specified";
+ try {
+ _dataModel.registerIOProcessor(ioProcIter->first, _ioProcessors[ioProcIter->first]);
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error when setting _ioprocessors:" << std::endl << e << std::endl;
}
#endif
ioProcIter++;
@@ -2550,7 +2599,7 @@ bool InterpreterImpl::isLegalConfiguration(const NodeSet<std::string>& config) {
for (int i = 0; i < config.size(); i++) {
if (isAtomic(Element<std::string>(config[i]))) {
Node<std::string> parent = config[i];
- while((parent = parent.getParentNode())) {
+ while(((parent = parent.getParentNode()) && parent.getNodeType() == Node_base::ELEMENT_NODE)) {
if (isState(Element<std::string>(parent)) &&
(iequals(LOCALNAME(parent), "state") ||
iequals(LOCALNAME(parent), "parallel"))) {
diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h
index 4659b13..8a2b282 100644
--- a/src/uscxml/Interpreter.h
+++ b/src/uscxml/Interpreter.h
@@ -277,10 +277,6 @@ public:
return _httpServlet;
}
- DataModel getDataModel() {
- return _dataModel;
- }
-
void setParentQueue(uscxml::concurrency::BlockingQueue<SendRequest>* parentQueue) {
_parentQueue = parentQueue;
}
@@ -356,10 +352,31 @@ public:
return _sendQueue;
}
+ void addIOProcessor(IOProcessor ioProc) {
+ std::list<std::string> names = ioProc.getNames();
+
+ std::list<std::string>::iterator nameIter = names.begin();
+ while(nameIter != names.end()) {
+ _ioProcessors[*nameIter] = ioProc;
+ _ioProcessors[*nameIter].setType(names.front());
+ _ioProcessors[*nameIter].setInterpreter(this);
+
+ nameIter++;
+ }
+ }
+
const std::map<std::string, IOProcessor>& getIOProcessors() {
return _ioProcessors;
}
+ void setDataModel(const DataModel& dataModel) {
+ _userSuppliedDataModel = true;
+ _dataModel = dataModel;
+ }
+ DataModel getDataModel() {
+ return _dataModel;
+ }
+
const std::map<std::string, Invoker>& getInvokers() {
return _invokers;
}
@@ -407,7 +424,7 @@ public:
static std::list<std::string> tokenizeIdRefs(const std::string& idRefs);
static std::string spaceNormalize(const std::string& text);
- static bool nameMatch(const std::string& transitionEvent, const std::string& event);
+ static bool nameMatch(const std::string& eventDescs, const std::string& event);
Arabica::DOM::Node<std::string> findLCCA(const Arabica::XPath::NodeSet<std::string>& states);
virtual Arabica::XPath::NodeSet<std::string> getProperAncestors(const Arabica::DOM::Node<std::string>& s1, const Arabica::DOM::Node<std::string>& s2);
@@ -448,6 +465,7 @@ protected:
bool _topLevelFinalReached;
bool _isInitialized;
bool _domIsSetup;
+ bool _userSuppliedDataModel;
bool _isStarted;
bool _isRunning;
@@ -625,9 +643,25 @@ public:
return _impl->getHTTPServlet();
}
+ void setDataModel(const DataModel& dataModel) {
+ _impl->setDataModel(dataModel);
+ }
DataModel getDataModel() {
return _impl->getDataModel();
}
+
+ void addIOProcessor(IOProcessor ioProc) {
+ _impl->addIOProcessor(ioProc);
+ }
+ const std::map<std::string, IOProcessor>& getIOProcessors() {
+ return _impl->getIOProcessors();
+ }
+
+ const std::map<std::string, Invoker>& getInvokers() {
+ return _impl->getInvokers();
+ }
+
+
void setParentQueue(uscxml::concurrency::BlockingQueue<SendRequest>* parentQueue) {
return _impl->setParentQueue(parentQueue);
}
@@ -700,14 +734,6 @@ public:
return _impl->getDelayQueue();
}
- const std::map<std::string, IOProcessor>& getIOProcessors() {
- return _impl->getIOProcessors();
- }
-
- const std::map<std::string, Invoker>& getInvokers() {
- return _impl->getInvokers();
- }
-
bool runOnMainThread(int fps, bool blocking = true) {
return _impl->runOnMainThread(fps, blocking);
}
diff --git a/src/uscxml/URL.cpp b/src/uscxml/URL.cpp
index 79a3f65..4e97faa 100644
--- a/src/uscxml/URL.cpp
+++ b/src/uscxml/URL.cpp
@@ -179,7 +179,7 @@ URLImpl::operator Data() const {
data.compound["host"] = Data(_uri.host(), Data::VERBATIM);
data.compound["scheme"] = Data(_uri.scheme(), Data::VERBATIM);
data.compound["path"] = Data(_uri.path(), Data::VERBATIM);
- data.compound["port"] = Data(_uri.port());
+ data.compound["port"] = Data(_uri.port(), Data::INTERPRETED);
data.compound["isAbsolute"] = Data(_uri.is_absolute());
if (_statusCode.length() > 0)
data.compound["statusCode"] = Data(_statusCode, Data::VERBATIM);
diff --git a/src/uscxml/debug/SCXMLDotWriter.cpp b/src/uscxml/debug/SCXMLDotWriter.cpp
index 16269a9..e833a10 100644
--- a/src/uscxml/debug/SCXMLDotWriter.cpp
+++ b/src/uscxml/debug/SCXMLDotWriter.cpp
@@ -20,6 +20,7 @@
#include "uscxml/Common.h"
#include "uscxml/UUID.h"
#include "SCXMLDotWriter.h"
+#include "../transform/FlatStateIdentifier.h"
#include "uscxml/DOMUtils.h"
#include <boost/algorithm/string.hpp> // replace_all
#include <iomanip>
@@ -44,6 +45,7 @@ SCXMLDotWriter::SCXMLDotWriter(Interpreter interpreter,
NodeList<std::string > scxmlElems = interpreter.getDocument().getElementsByTagName("scxml");
_scxml = (Element<std::string>)scxmlElems.item(0);
+ _isFlat = HAS_ATTR(_scxml, "flat") && DOMUtils::attributeIsTrue(ATTR(_scxml, "flat"));
if (_anchors.size() == 0) {
StateAnchor anchor;
@@ -275,7 +277,7 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const Element<std::stri
os << getPrefix() << "subgraph \"cluster_" << stateId << "\" {" << std::endl;
_indentation++;
os << getPrefix() << "fontsize=14" << std::endl;
- os << getPrefix() << "label=<<b>" << nameForNode(stateElem) << "</b>>" << std::endl;
+ os << getPrefix() << "label=<" << nameForNode(stateElem) << ">" << std::endl;
// os << getPrefix() << "rank=\"same\"" << std::endl;
os << getPrefix() << "labeljust=l" << std::endl;
@@ -312,7 +314,7 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const Element<std::stri
os << getPrefix() << "shape=doublecircle," << std::endl;
os << getPrefix() << "color=black," << std::endl;
os << getPrefix() << "penwidth=2," << std::endl;
- os << getPrefix() << "label=<" << nameForNode(stateElem) << ">" << std::endl;
+ os << getPrefix() << "label=< <table cellborder=\"0\" border=\"0\"><tr><td balign=\"left\">" << nameForNode(stateElem) << "</td></tr></table>>" << std::endl;
_indentation--;
os << getPrefix() << "];" << std::endl;
@@ -325,27 +327,30 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const Element<std::stri
// os << getPrefix() << "style=filled, fillcolor=lightgrey, " << std::endl;
DotState::mmap_s_e_t::const_iterator destIterF, destIterB;
- std::list<std::string> outPorts; // count unique keys
+ //std::list<std::string> outPorts; // count unique keys
+
+ int nrOutPorts = 0;
switch (dotState.portType) {
case PORT_TARGET: // outports are per target
for(DotState::mmap_s_e_t::const_iterator it = dotState.targets.begin(), end = dotState.targets.end();
it != end;
it = dotState.targets.upper_bound(it->first)) {
- outPorts.push_back(it->first);
+ nrOutPorts++;
}
break;
case PORT_EVENT: // outports are per event
for(DotState::mmap_s_e_t::const_iterator it = dotState.events.begin(), end = dotState.events.end();
it != end;
it = dotState.events.upper_bound(it->first)) {
- outPorts.push_back(it->first);
+ nrOutPorts++;
}
break;
case PORT_TRANSITION:
- for (int i = 0; i < dotState.transitions.size(); i++) {
- outPorts.push_back(idForNode(dotState.transitions[i]));
- }
+ nrOutPorts = dotState.transitions.size();
+// for (int i = 0; i < dotState.transitions.size(); i++) {
+// outPorts.push_back(idForNode(dotState.transitions[i]));
+// }
break;
}
@@ -361,26 +366,34 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const Element<std::stri
*/
std::string details = getDetailedLabel(stateElem);
+ std::string stateLabel = nameForNode(stateElem);
+ int stateLines = 0;
- os << "<table " << (isInitial ? "bgcolor=\"orange\" " : "") << "cellborder=\"1\" border=\"0\" cellspacing=\"0\" cellpadding=\"2\" >" << std::endl;
- os << " <tr><td port=\"__name\" rowspan=\"" << outPorts.size() + 1 << "\"><b>" << nameForNode(stateElem) << "</b></td></tr>" << std::endl;
+ std::string::size_type start = 0;
+ while ((start = stateLabel.find("<br", start)) != std::string::npos) {
+ ++stateLines;
+ start += 3;
+ }
+
+ os << "<table " << (isInitial ? "bgcolor=\"orange\" " : "") << "valign=\"top\" align=\"left\" cellborder=\"1\" border=\"0\" cellspacing=\"0\" cellpadding=\"5\" >" << std::endl;
+ os << " <tr><td port=\"__name\" balign=\"left\" valign=\"top\" align=\"left\" rowspan=\"" << nrOutPorts + 1 << "\">" << stateLabel << "</td></tr>" << std::endl;
switch (dotState.portType) {
case PORT_TARGET: // outports are per target
- writePerTargetPorts(os, outPorts, dotState);
+ writePerTargetPorts(os, dotState, stateLines);
break;
case PORT_EVENT: // outports are per event
- writePerEventPorts(os, outPorts, dotState);
+ writePerEventPorts(os, dotState, stateLines);
break;
case PORT_TRANSITION:
- writePerTransitionPorts(os, outPorts, dotState);
+ writePerTransitionPorts(os, dotState, stateLines);
break;
}
// write details of the state
if (details.size() > 0) {
- os << " <tr><td colspan=\"" << (outPorts.size() == 0 ? 1 : 2) << "\">" << std::endl;
+ os << " <tr><td balign=\"left\" colspan=\"" << (nrOutPorts == 0 ? 1 : 2) << "\">" << std::endl;
os << details << std::endl;
os << " </td></tr>" << std::endl;
}
@@ -388,7 +401,7 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const Element<std::stri
// write history states
NodeSet<std::string> histories = InterpreterImpl::filterChildElements(_xmlNSPrefix + "history", stateElem);
for (int i = 0; i < histories.size(); i++) {
- os << " <tr><td port=\"" << ATTR(histories[i], "id") << "\" colspan=\"" << (outPorts.size() == 0 ? 1 : 2) << "\"><b>history: </b>" << ATTR(histories[i], "id") << "</td></tr>" << std::endl;
+ os << " <tr><td port=\"" << ATTR(histories[i], "id") << "\" balign=\"left\" colspan=\"" << (nrOutPorts == 0 ? 1 : 2) << "\"><b>history: </b>" << ATTR(histories[i], "id") << "</td></tr>" << std::endl;
}
@@ -423,76 +436,92 @@ void SCXMLDotWriter::writeStateElement(std::ostream& os, const Element<std::stri
}
}
-void SCXMLDotWriter::writePerTransitionPorts(std::ostream& os, const std::list<std::string>& outPorts, const DotState& dotState) {
+void SCXMLDotWriter::writePerTransitionPorts(std::ostream& os, const DotState& dotState, int stateLines) {
// TODO: Not implemented
}
-void SCXMLDotWriter::writePerEventPorts(std::ostream& os, const std::list<std::string>& outPorts, const DotState& dotState) {
- // TODO: Not implemented
+void SCXMLDotWriter::writePerEventPorts(std::ostream& os, const DotState& dotState, int stateLines) {
+ // std::multimap<std::string, Arabica::DOM::Element<std::string> > events; // key is event name, value is transitions that react
- // outports contain event names
std::string stateId = idForNode(dotState.node);
DotState::mmap_s_e_t::const_iterator destIterF, destIterB;
- for(std::list<std::string>::const_iterator nameIter = outPorts.begin(); nameIter != outPorts.end(); nameIter++) {
- os << " <tr><td port=\"" << portEscape(*nameIter) << "\" align=\"right\">" << *nameIter << "</td></tr>" << std::endl;
+ for(DotState::mmap_s_e_t::const_iterator it = dotState.events.begin(), end = dotState.events.end();
+ it != end;
+ it = dotState.events.upper_bound(it->first)) {
+ os << " <tr><td port=\"" << portEscape(it->first) << "\" align=\"right\">" << it->first << "</td></tr>" << std::endl;
}
+
}
-void SCXMLDotWriter::writePerTargetPorts(std::ostream& os, const std::list<std::string>& outPorts, const DotState& dotState) {
- // outports contain remote node ids
+void SCXMLDotWriter::writePerTargetPorts(std::ostream& os, const DotState& dotState, int stateLines) {
+ // std::multimap<std::string, Arabica::DOM::Element<std::string> > targets; // key is remote node, transition is element
+
+ int nrOutports = 0;
std::string stateId = idForNode(dotState.node);
- DotState::mmap_s_e_t::const_iterator destIterF, destIterB;
- for(std::list<std::string>::const_iterator nameIter = outPorts.begin(); nameIter != outPorts.end(); nameIter++) {
+ typedef DotState::mmap_s_e_t iter_t;
+
+ // we need to count outports first for vertical padding
+ for(iter_t::const_iterator targetIter = dotState.targets.begin(), end = dotState.targets.end();
+ targetIter != end;
+ targetIter = dotState.targets.upper_bound(targetIter->first)) {
+ nrOutports++;
+ }
+
+ for(iter_t::const_iterator targetIter = dotState.targets.begin(), end = dotState.targets.end();
+ targetIter != end;
+ targetIter = dotState.targets.upper_bound(targetIter->first)) {
// gather all events that activate the transition
- std::string portName = *nameIter;
- DotEdge edge(stateId, portName);
- edge.fromPort = portName;
-
- std::multimap<std::string, std::string> eventConds; // event to condition
- std::pair <DotState::mmap_s_e_t::const_iterator, DotState::mmap_s_e_t::const_iterator> targetKeyRange = dotState.targets.equal_range(portName);
- for (destIterB = targetKeyRange.first; destIterB != targetKeyRange.second; ++destIterB) {
- const Element<std::string>& transElem = destIterB->second;
- std::list<std::string> eventNames = InterpreterImpl::tokenizeIdRefs(ATTR(transElem, "event"));
- for (std::list<std::string>::iterator eventIter = eventNames.begin(); eventIter != eventNames.end(); eventIter++) {
- eventConds.insert(std::make_pair(*eventIter, ATTR(transElem, "cond")));
- }
- if (eventNames.size() == 0) {
+ std::string targetId = targetIter->first;
+
+ std::set<std::string> eventNames;
+
+ DotEdge edge(stateId, targetId);
+ edge.fromPort = targetId;
+
+ std::pair <iter_t::const_iterator, iter_t::const_iterator> targetKeyRange = dotState.targets.equal_range(targetId);
+ for (iter_t::const_iterator transIter = targetKeyRange.first; transIter != targetKeyRange.second; ++transIter) {
+ const Element<std::string>& transElem = transIter->second;
+
+ std::list<std::string> events = InterpreterImpl::tokenizeIdRefs(ATTR(transElem, "event"));
+ eventNames.insert(events.begin(), events.end());
+
+ if (events.size() == 0) {
// spontaneous transition
- eventConds.insert(std::make_pair("&#35;", ATTR(transElem, "cond")));
+ eventNames.insert("&#35;");
edge.type = EDGE_SPONTANEOUS;
}
}
- if (_graph.find(portName) != _graph.end())
+
+ if (_graph.find(targetId) != _graph.end())
_edges.insert(edge);
- typedef std::multimap<std::string, std::string>::iterator condIter_t;
std::stringstream outPortSS;
- outPortSS << "<b>" << portName << "</b><br align=\"right\" />";
+ outPortSS << (_isFlat ? FlatStateIdentifier::toHTMLLabel(targetId) : "<b>" + targetId + "</b>" );
- std::string opener = "{";
- std::string closer;
- std::string seperator;
- condIter_t iterA, iterB;
- for(iterA = eventConds.begin(); iterA != eventConds.end(); iterA = iterB) {
- std::string eventName = iterA->first;
- bool hasCondition = false;
-
- std::pair <condIter_t, condIter_t> condRange = eventConds.equal_range(eventName);
- for (iterB = condRange.first; iterB != condRange.second; ++iterB) {
- hasCondition = true;
- }
+ if (_isFlat) {
+ outPortSS << "<br /><b>events: </b>{";
+ } else {
+ outPortSS << "<br />{";
+ }
- outPortSS << opener << seperator << eventName << (hasCondition ? "" : "");
+ std::string seperator;
+ for (std::set<std::string>::const_iterator eventIter = eventNames.begin(); eventIter != eventNames.end(); eventIter++) {
+ outPortSS << seperator << *eventIter << std::endl;
seperator = ", ";
- opener = "";
- closer = "}";
}
- outPortSS << closer;
+ outPortSS << "}";
- os << " <tr><td port=\"" << portEscape(portName) << "\" align=\"right\">" << outPortSS.str() << "</td></tr>" << std::endl;
+ if (nrOutports == 1) {
+ int missing = stateLines - nrOutports;
+ while (_isFlat && missing-- >= 1) {
+ outPortSS << "<br /> ";
+ }
+ }
+
+ os << " <tr><td port=\"" << portEscape(targetId) << "\" balign=\"left\" align=\"left\">" << outPortSS.str() << "</td></tr>" << std::endl;
}
}
@@ -689,7 +718,6 @@ std::string SCXMLDotWriter::getDetailedLabel(const Element<std::string>& elem, i
std::string SCXMLDotWriter::portEscape(const std::string& text) {
std::string escaped(text);
boost::replace_all(escaped, ".", "-");
-
return text;
}
@@ -719,7 +747,16 @@ std::string SCXMLDotWriter::nameForNode(const Node<std::string>& node) {
if (node.getNodeType() == Node_base::ELEMENT_NODE) {
Element<std::string> elem = (Element<std::string>)node;
- if (false) {
+ if (InterpreterImpl::isFinal(elem) && _isFlat) {
+ // ignore visited and history with final elements
+ FlatStateIdentifier flatId(elem.getAttribute("id"));
+ return "<b>" + flatId.active.front() + "</b>";
+ }
+
+ if (elem.hasAttribute("id") && _isFlat) {
+ elemName = FlatStateIdentifier::toHTMLLabel(elem.getAttribute("id"));
+ if (elemName.size() > 0)
+ return elemName;
} else if (elem.getTagName() == "scxml") {
if (elem.hasAttribute("name") && !UUID::isUUID(elem.getAttribute("name"))) {
elemName += elem.getAttribute("name");
@@ -734,10 +771,11 @@ std::string SCXMLDotWriter::nameForNode(const Node<std::string>& node) {
elemName += elem.getAttribute("id");
}
}
+
if (elemName.size() == 0)
elemName = boost::lexical_cast<std::string>(node.getLocalName());
- return elemName;
+ return "<b>" + elemName + "</b>";
}
@@ -747,6 +785,13 @@ std::string SCXMLDotWriter::idForNode(const Node<std::string>& node) {
// try to get the id as the name or id attribute
if (node.getNodeType() == Node_base::ELEMENT_NODE) {
Element<std::string> elem = (Element<std::string>)node;
+
+ if (InterpreterImpl::isFinal(elem) && _isFlat) {
+ // ignore visited and history with final elements
+ FlatStateIdentifier flatId(elem.getAttribute("id"));
+ return flatId.activeId();
+ }
+
if (elem.hasAttribute("name")) {
elemId = elem.getAttribute("name");
} else if (elem.hasAttribute("id")) {
@@ -774,9 +819,6 @@ std::string SCXMLDotWriter::idForNode(const Node<std::string>& node) {
} while ((tmpParent = tmpParent.getParentNode()));
// elemId = ssElemId.str();
}
-
- std::replace(elemId.begin(), elemId.end(), '-', '_');
-
return elemId;
}
diff --git a/src/uscxml/debug/SCXMLDotWriter.h b/src/uscxml/debug/SCXMLDotWriter.h
index 3ac697f..61fbfad 100644
--- a/src/uscxml/debug/SCXMLDotWriter.h
+++ b/src/uscxml/debug/SCXMLDotWriter.h
@@ -64,7 +64,7 @@ public:
};
struct StateAnchor {
- StateAnchor() : childDepth(-1), transDepth(-1), type(PORT_TARGET) {}
+ StateAnchor() : childDepth(std::numeric_limits<int32_t>::max()), transDepth(std::numeric_limits<int32_t>::max()), type(PORT_TARGET) {}
Arabica::DOM::Element<std::string> element;
int32_t childDepth;
int32_t transDepth;
@@ -166,9 +166,9 @@ protected:
int32_t transDepth = std::numeric_limits<int32_t>::max());
void writeStateElement(std::ostream& os, const Arabica::DOM::Element<std::string>& state);
- void writePerTransitionPorts(std::ostream& os, const std::list<std::string>& outPorts, const DotState& dotState);
- void writePerEventPorts(std::ostream& os, const std::list<std::string>& outPorts, const DotState& dotState);
- void writePerTargetPorts(std::ostream& os, const std::list<std::string>& outPorts, const DotState& dotState);
+ void writePerTransitionPorts(std::ostream& os, const DotState& dotState, int stateLines = 0);
+ void writePerEventPorts(std::ostream& os, const DotState& dotState, int stateLines = 0);
+ void writePerTargetPorts(std::ostream& os, const DotState& dotState, int stateLines = 0);
void writeUnknownNode(std::ostream& os, const std::string& targetId);
@@ -184,6 +184,8 @@ protected:
Arabica::DOM::Element<std::string> _transition;
Arabica::DOM::Element<std::string> _scxml;
Interpreter _interpreter;
+ bool _isFlat;
+
std::string _xmlNSPrefix;
std::list<StateAnchor> _anchors;
std::map<std::string, DotEdge> _histories;
diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp
index 7569fdb..554cd28 100644
--- a/src/uscxml/interpreter/InterpreterDraft6.cpp
+++ b/src/uscxml/interpreter/InterpreterDraft6.cpp
@@ -138,6 +138,15 @@ InterpreterState InterpreterDraft6::step(int waitForMS = 0) {
setInterpreterState(USCXML_MICROSTEPPED);
}
+ if (!isLegalConfiguration(_configuration)) {
+ std:: cout << "Illegal configuration: {";
+ for (int i = 0; i < _configuration.size(); i++) {
+ std::cout << ATTR(_configuration[i], "id") << ", " << std::endl;
+ }
+ std:: cout << "}" << std::endl;
+ }
+ assert(isLegalConfiguration(_configuration));
+
// are there spontaneous transitions?
if (!_stable) {
enabledTransitions = selectEventlessTransitions();
@@ -164,8 +173,7 @@ InterpreterState InterpreterDraft6::step(int waitForMS = 0) {
USCXML_MONITOR_CALLBACK2(beforeProcessingEvent, _currEvent)
- if (_dataModel)
- _dataModel.setEvent(_currEvent);
+ _dataModel.setEvent(_currEvent);
enabledTransitions = selectTransitions(_currEvent.name);
if (!enabledTransitions.empty()) {
@@ -281,7 +289,7 @@ EXIT_INTERPRETER:
_mutex.unlock();
// remove datamodel
- if(_dataModel)
+ if(!_userSuppliedDataModel)
_dataModel = DataModel();
setInterpreterState(USCXML_FINISHED);
@@ -375,16 +383,14 @@ Arabica::XPath::NodeSet<std::string> InterpreterDraft6::selectTransitions(const
unsigned int index = 0;
while(states.size() > index) {
- bool foundTransition = false;
NodeSet<std::string> transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", states[index]);
for (unsigned int k = 0; k < transitions.size(); k++) {
if (isEnabledTransition(Element<std::string>(transitions[k]), event)) {
enabledTransitions.push_back(transitions[k]);
- foundTransition = true;
goto LOOP;
}
}
- if (!foundTransition) {
+ {
Node<std::string> parent = states[index].getParentNode();
if (parent) {
states.push_back(parent);
@@ -549,6 +555,9 @@ bool InterpreterDraft6::isWithinParallel(const Element<std::string>& transition)
if (isTargetless(transition))
return false;
+ if (_transWithinParallel.find(transition) != _transWithinParallel.end())
+ return _transWithinParallel[transition];
+
Node<std::string> source;
if (HAS_ATTR(transition, "type") && iequals(ATTR(transition, "type"), "internal")) {
source = getSourceState(transition);
@@ -559,7 +568,10 @@ bool InterpreterDraft6::isWithinParallel(const Element<std::string>& transition)
targets.push_back(source);
Node<std::string> lcpa = findLCPA(targets);
- return lcpa;
+ _transWithinParallel[transition] = lcpa;
+
+ return _transWithinParallel[transition];
+
}
Node<std::string> InterpreterDraft6::findLCPA(const Arabica::XPath::NodeSet<std::string>& states) {
diff --git a/src/uscxml/interpreter/InterpreterDraft6.h b/src/uscxml/interpreter/InterpreterDraft6.h
index 297434f..062d79a 100644
--- a/src/uscxml/interpreter/InterpreterDraft6.h
+++ b/src/uscxml/interpreter/InterpreterDraft6.h
@@ -55,6 +55,7 @@ protected:
bool isWithinParallel(const Arabica::DOM::Element<std::string>& transition);
Arabica::DOM::Node<std::string> findLCPA(const Arabica::XPath::NodeSet<std::string>& states);
+ std::map<Arabica::DOM::Element<std::string>, bool> _transWithinParallel; // this is costly to calculate
};
}
diff --git a/src/uscxml/messages/Data.h b/src/uscxml/messages/Data.h
index 584bf09..0d27548 100644
--- a/src/uscxml/messages/Data.h
+++ b/src/uscxml/messages/Data.h
@@ -44,7 +44,7 @@ public:
Data() : type(INTERPRETED) {}
// TODO: default INTERPRETED is unfortunate
- Data(const std::string& atom, Type type = INTERPRETED) : atom(atom), type(type) {}
+ Data(const std::string& atom, Type type) : atom(atom), type(type) {}
Data(const char* data, size_t size, const std::string& mimeType, bool adopt = false);
// convenience constructors
@@ -57,9 +57,9 @@ public:
Data(double atom) : atom(toStr(atom)), type(INTERPRETED) {}
Data(bool atom) : type(INTERPRETED) {
if (atom) {
- atom = "true";
+ this->atom = "true";
} else {
- atom = "false";
+ this->atom = "false";
}
}
@@ -67,7 +67,7 @@ public:
#if 0
// constructor for arbitrary types, skip if type is subclass though (C++11)
- // we will have to drop this constructor as it interferes with operator Data() and entails C++11
+ // we will have to drop this constructor as it interferes with operator Data() and requires C++11
template <typename T>
Data(T value, typename std::enable_if<! std::is_base_of<Data, T>::value>::type* = nullptr)
: atom(toStr(value)), type(INTERPRETED) {}
diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp
index 64b61af..6d15f72 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp
+++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp
@@ -474,16 +474,17 @@ void JSCDataModel::setForeach(const std::string& item,
// assign array element to item
std::stringstream ss;
ss << array << "[" << iteration << "]";
- assign(item, ss.str());
+ assign(item, Data(ss.str(), Data::INTERPRETED));
if (index.length() > 0) {
// assign iteration element to index
std::stringstream ss;
ss << iteration;
- assign(index, ss.str());
+ assign(index, Data(ss.str(), Data::INTERPRETED));
}
}
bool JSCDataModel::isLocation(const std::string& expr) {
+ // location needs to be RHS and ++ is only valid for RHS
JSStringRef scriptJS = JSStringCreateWithUTF8CString((expr + "++").c_str());
JSValueRef exception = NULL;
bool valid = JSCheckScriptSyntax(_ctx, scriptJS, NULL, 0, &exception);
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
index f4bfabd..cd27126 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
@@ -499,12 +499,12 @@ void V8DataModel::setForeach(const std::string& item,
// assign array element to item
std::stringstream ss;
ss << array << "[" << iteration << "]";
- assign(item, ss.str());
+ assign(item, Data(ss.str(), Data::INTERPRETED));
if (index.length() > 0) {
// assign iteration element to index
std::stringstream ss;
ss << iteration;
- assign(index, ss.str());
+ assign(index, Data(ss.str(), Data::INTERPRETED));
}
}
@@ -753,7 +753,7 @@ void V8DataModel::throwExceptionEvent(const v8::TryCatch& tryCatch) {
std::stringstream ssLineNumber;
int lineNumber = message->GetLineNumber();
ssLineNumber << lineNumber;
- exceptionEvent.data.compound["linenumber"] = Data(ssLineNumber.str());
+ exceptionEvent.data.compound["linenumber"] = Data(ssLineNumber.str(), Data::INTERPRETED);
int startColumn = message->GetStartColumn();
int endColumn = message->GetEndColumn();
diff --git a/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp b/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp
index 018a8c4..bf8b538 100644
--- a/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp
+++ b/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp
@@ -44,14 +44,65 @@ bool pluginConnect(pluma::Host& host) {
}
#endif
-LuaDataModel::LuaDataModel() {
- _luaState = NULL;
-}
-
static int luaInspect(lua_State * l) {
return 0;
}
+static luabridge::LuaRef getDataAsLua(lua_State* _luaState, const Data& data) {
+ luabridge::LuaRef luaData (_luaState);
+
+ if (data.node) {
+ ERROR_EXECUTION_THROW("No DOM support in Lua datamodel");
+ }
+ if (data.compound.size() > 0) {
+ luaData = luabridge::newTable(_luaState);
+ std::map<std::string, Data>::const_iterator compoundIter = data.compound.begin();
+ while(compoundIter != data.compound.end()) {
+ luaData[compoundIter->first] = getDataAsLua(_luaState, compoundIter->second);
+ compoundIter++;
+ }
+ luaData["inspect"] = luaInspect;
+ return luaData;
+ }
+ if (data.array.size() > 0) {
+ luaData = luabridge::newTable(_luaState);
+ std::list<Data>::const_iterator arrayIter = data.array.begin();
+ uint32_t index = 0;
+ while(arrayIter != data.array.end()) {
+ luaData[index++] = getDataAsLua(_luaState, *arrayIter);
+ arrayIter++;
+ }
+ luaData["inspect"] = luaInspect;
+ return luaData;
+ }
+ if (data.atom.size() > 0) {
+ switch (data.type) {
+ case Data::VERBATIM: {
+// luaData = "\"" + data.atom + "\"";
+ luaData = data.atom;
+ break;
+ }
+ case Data::INTERPRETED: {
+ if (isNumeric(data.atom.c_str(), 10)) {
+ if (data.atom.find(".") != std::string::npos) {
+ luaData = strTo<double>(data.atom);
+ } else {
+ luaData = strTo<long>(data.atom);
+ }
+ } else {
+ luaData = data.atom;
+ }
+ }
+ }
+ return luaData;
+ }
+ return luaData;
+}
+
+LuaDataModel::LuaDataModel() {
+ _luaState = NULL;
+}
+
static int luaInFunction(lua_State * l) {
luabridge::LuaRef ref = luabridge::getGlobal(l, "__interpreter");
InterpreterImpl* interpreter = ref.cast<InterpreterImpl*>();
@@ -78,23 +129,22 @@ boost::shared_ptr<DataModelImpl> LuaDataModel::create(InterpreterImpl* interpret
luaL_openlibs(dm->_luaState);
luabridge::getGlobalNamespace(dm->_luaState).beginClass<InterpreterImpl>("Interpreter").endClass();
+ luabridge::setGlobal(dm->_luaState, dm->_interpreter, "__interpreter");
+
luabridge::getGlobalNamespace(dm->_luaState).addCFunction("In", luaInFunction);
-// luabridge::getGlobalNamespace(dm->_luaState)
-// .beginClass <uscxml::Event> ("Event")
-// .addProperty("name", &uscxml::Event::getName)
-// .addProperty("raw", &uscxml::Event::getRaw)
-// .addProperty("data", &uscxml::Event::getData)
-// .addProperty("xml", &uscxml::Event::getXML)
-// .addProperty("eventType", &uscxml::Event::getEventType)
-// .addProperty("origin", &uscxml::Event::getOrigin)
-// .addProperty("originType", &uscxml::Event::getOriginType)
-// .addProperty("content", &uscxml::Event::getContent)
-// .addProperty("invokeId", &uscxml::Event::getInvokeId)
-// .addProperty("sendId", &uscxml::Event::getSendId)
-// .endClass ();
+ luabridge::LuaRef ioProcTable = luabridge::newTable(dm->_luaState);
- luabridge::setGlobal(dm->_luaState, dm->_interpreter, "__interpreter");
+ std::map<std::string, IOProcessor>::const_iterator ioProcIter = dm->_interpreter->getIOProcessors().begin();
+ while(ioProcIter != dm->_interpreter->getIOProcessors().end()) {
+ Data ioProcData = ioProcIter->second.getDataModelVariables();
+ ioProcTable[ioProcIter->first] = getDataAsLua(dm->_luaState, ioProcData);
+ ioProcIter++;
+ }
+ luabridge::setGlobal(dm->_luaState, ioProcTable, "_ioprocessors");
+
+ luabridge::setGlobal(dm->_luaState, dm->_interpreter->getName(), "_name");
+ luabridge::setGlobal(dm->_luaState, dm->_interpreter->getSessionId(), "_sessionid");
return dm;
}
@@ -142,56 +192,6 @@ static Data getLuaAsData(const luabridge::LuaRef& lua) {
return data;
}
-static luabridge::LuaRef getDataAsLua(lua_State* _luaState, const Data& data) {
- luabridge::LuaRef luaData (_luaState);
-
- if (data.node) {
- ERROR_EXECUTION_THROW("No DOM support in Lua datamodel");
- }
- if (data.compound.size() > 0) {
- luaData = luabridge::newTable(_luaState);
- std::map<std::string, Data>::const_iterator compoundIter = data.compound.begin();
- while(compoundIter != data.compound.end()) {
- luaData[compoundIter->first] = getDataAsLua(_luaState, compoundIter->second);
- compoundIter++;
- }
- luaData["inspect"] = luaInspect;
- return luaData;
- }
- if (data.array.size() > 0) {
- luaData = luabridge::newTable(_luaState);
- std::list<Data>::const_iterator arrayIter = data.array.begin();
- uint32_t index = 0;
- while(arrayIter != data.array.end()) {
- luaData[index++] = getDataAsLua(_luaState, *arrayIter);
- arrayIter++;
- }
- luaData["inspect"] = luaInspect;
- return luaData;
- }
- if (data.atom.size() > 0) {
- switch (data.type) {
- case Data::VERBATIM: {
- luaData = "\"" + data.atom + "\"";
- break;
- }
- case Data::INTERPRETED: {
- if (isNumeric(data.atom.c_str(), 10)) {
- if (data.atom.find(".") != std::string::npos) {
- luaData = strTo<double>(data.atom);
- } else {
- luaData = strTo<long>(data.atom);
- }
- } else {
- luaData = data.atom;
- }
- }
- }
- return luaData;
- }
- return luaData;
-}
-
void LuaDataModel::setEvent(const Event& event) {
luabridge::LuaRef luaEvent(_luaState);
luaEvent = luabridge::newTable(_luaState);
@@ -471,5 +471,16 @@ std::string LuaDataModel::evalAsString(const std::string& expr) {
return "";
}
+std::string LuaDataModel::andExpressions(std::list<std::string> exprs) {
+ std::stringstream exprSS;
+ std::list<std::string>::const_iterator listIter;
+ std::string andExpr;
+ for (listIter = exprs.begin(); listIter != exprs.end(); listIter++) {
+ exprSS << andExpr << *listIter;
+ andExpr = " && ";
+ }
+ return exprSS.str();
+}
+
} \ No newline at end of file
diff --git a/src/uscxml/plugins/datamodel/lua/LuaDataModel.h b/src/uscxml/plugins/datamodel/lua/LuaDataModel.h
index 828db0e..86e7e17 100644
--- a/src/uscxml/plugins/datamodel/lua/LuaDataModel.h
+++ b/src/uscxml/plugins/datamodel/lua/LuaDataModel.h
@@ -85,6 +85,8 @@ public:
virtual std::string evalAsString(const std::string& expr);
virtual bool evalAsBool(const Arabica::DOM::Node<std::string>& node, const std::string& expr);
+ virtual std::string andExpressions(std::list<std::string>);
+
protected:
virtual int luaEval(const Arabica::DOM::Element<std::string>& scriptElem,
diff --git a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp
index c38842b..41e015e 100644
--- a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp
+++ b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp
@@ -269,7 +269,7 @@ Data XPathDataModel::getStringAsData(const std::string& content) {
std::string idx = ss.str();
ss.str("");
ss << ns[i];
- data.compound[idx] = Data(ss.str());
+ data.compound[idx] = Data(ss.str(), Data::INTERPRETED);
}
data.type = Data::INTERPRETED;
return data;
diff --git a/src/uscxml/plugins/element/file/FileElement.cpp b/src/uscxml/plugins/element/file/FileElement.cpp
index d5908ec..247c3c8 100644
--- a/src/uscxml/plugins/element/file/FileElement.cpp
+++ b/src/uscxml/plugins/element/file/FileElement.cpp
@@ -184,10 +184,10 @@ void FileElement::enterElement(const Arabica::DOM::Node<std::string>& node) {
event.data.compound["file"].compound["name"] = Data(filename, Data::VERBATIM);
event.data.compound["file"].compound["path"] = Data(_filepath, Data::VERBATIM);
- event.data.compound["file"].compound["mtime"] = toStr(fileStat.st_mtime);
- event.data.compound["file"].compound["ctime"] = toStr(fileStat.st_ctime);
- event.data.compound["file"].compound["atime"] = toStr(fileStat.st_atime);
- event.data.compound["file"].compound["size"] = toStr(fileStat.st_size);
+ event.data.compound["file"].compound["mtime"] = Data(toStr(fileStat.st_mtime), Data::INTERPRETED);
+ event.data.compound["file"].compound["ctime"] = Data(toStr(fileStat.st_ctime), Data::INTERPRETED);
+ event.data.compound["file"].compound["atime"] = Data(toStr(fileStat.st_atime), Data::INTERPRETED);
+ event.data.compound["file"].compound["size"] = Data(toStr(fileStat.st_size), Data::INTERPRETED);
FILE *fp;
diff --git a/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp b/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp
index eda4ce8..5e2d8eb 100644
--- a/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp
+++ b/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp
@@ -225,7 +225,7 @@ void FFMPEGInvoker::finish(EncodingContext* ctx, const SendRequest& req) {
Event event;
event.name = "render.done";
- event.data.compound["context"] = context;
+ event.data.compound["context"] = Data(context, Data::INTERPRETED);
event.data.compound["movie"] = Data(movieBuffer, length, "video/mpeg", true);
event.data.compound["filename"] = Data(std::string("movie.") + ctx->extension, Data::VERBATIM);
diff --git a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp
index 902b825..c808192 100644
--- a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp
+++ b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp
@@ -84,10 +84,10 @@ Data DirMonInvoker::getDataModelVariables() {
std::map<std::string, struct stat> entries = _watcher->getAllEntries();
std::map<std::string, struct stat>::iterator entryIter = entries.begin();
while(entryIter != entries.end()) {
- data.compound["file"].compound[entryIter->first].compound["mtime"] = toStr(entryIter->second.st_mtime);
- data.compound["file"].compound[entryIter->first].compound["ctime"] = toStr(entryIter->second.st_mtime);
- data.compound["file"].compound[entryIter->first].compound["atime"] = toStr(entryIter->second.st_mtime);
- data.compound["file"].compound[entryIter->first].compound["size"] = toStr(entryIter->second.st_mtime);
+ data.compound["file"].compound[entryIter->first].compound["mtime"] = Data(toStr(entryIter->second.st_mtime), Data::INTERPRETED);
+ data.compound["file"].compound[entryIter->first].compound["ctime"] = Data(toStr(entryIter->second.st_mtime), Data::INTERPRETED);
+ data.compound["file"].compound[entryIter->first].compound["atime"] = Data(toStr(entryIter->second.st_mtime), Data::INTERPRETED);
+ data.compound["file"].compound[entryIter->first].compound["size"] = Data(toStr(entryIter->second.st_mtime), Data::INTERPRETED);
entryIter++;
}
@@ -252,10 +252,10 @@ void DirMonInvoker::handleChanges(DirectoryWatch::Action action, const std::stri
}
if (action != DirectoryWatch::DELETED) {
- event.data.compound["file"].compound["mtime"] = toStr(fileStat.st_mtime);
- event.data.compound["file"].compound["ctime"] = toStr(fileStat.st_ctime);
- event.data.compound["file"].compound["atime"] = toStr(fileStat.st_atime);
- event.data.compound["file"].compound["size"] = toStr(fileStat.st_size);
+ event.data.compound["file"].compound["mtime"] = Data(toStr(fileStat.st_mtime), Data::INTERPRETED);
+ event.data.compound["file"].compound["ctime"] = Data(toStr(fileStat.st_ctime), Data::INTERPRETED);
+ event.data.compound["file"].compound["atime"] = Data(toStr(fileStat.st_atime), Data::INTERPRETED);
+ event.data.compound["file"].compound["size"] = Data(toStr(fileStat.st_size), Data::INTERPRETED);
}
event.data.compound["file"].compound["name"] = Data(basename, Data::VERBATIM);
diff --git a/src/uscxml/plugins/invoker/graphics/openscenegraph/converter/OSGConverter.cpp b/src/uscxml/plugins/invoker/graphics/openscenegraph/converter/OSGConverter.cpp
index 0ebf9b8..2a68be7 100644
--- a/src/uscxml/plugins/invoker/graphics/openscenegraph/converter/OSGConverter.cpp
+++ b/src/uscxml/plugins/invoker/graphics/openscenegraph/converter/OSGConverter.cpp
@@ -42,7 +42,7 @@
#define EVAL_PARAM_EXPR(param, expr, key) \
if (param.find(key) == param.end() && param.find(expr) != param.end() && _interpreter->getDataModel()) \
- param.insert(std::make_pair(key, _interpreter->getDataModel().evalAsString(param.find(expr)->second.atom)));
+ param.insert(std::make_pair(key, Data(_interpreter->getDataModel().evalAsString(param.find(expr)->second.atom), Data::INTERPRETED)));
#define CAST_PARAM(param, var, key, type) \
if (param.find(key) != param.end()) { \
diff --git a/src/uscxml/plugins/invoker/miles/MilesSessionInvoker.cpp b/src/uscxml/plugins/invoker/miles/MilesSessionInvoker.cpp
index 9dfe94f..7b45f2c 100644
--- a/src/uscxml/plugins/invoker/miles/MilesSessionInvoker.cpp
+++ b/src/uscxml/plugins/invoker/miles/MilesSessionInvoker.cpp
@@ -282,7 +282,7 @@ void MilesSessionInvoker::send(const SendRequest& req) {
void MilesSessionInvoker::processEventStart(const std::string& origin, const std::string& userid, const std::string& reflector, const std::string& session) {
Event ev;
- ev.data.compound["origin"] = origin;
+ ev.data.compound["origin"] = Data(origin, Data::INTERPRETED);
//std::cout << req;
if(num_connected>0) {
num_connected++;
@@ -383,7 +383,7 @@ void MilesSessionInvoker::processEventStart(const std::string& origin, const std
void MilesSessionInvoker::processEventStop(const std::string& origin) {
Event ev;
- ev.data.compound["origin"] = origin;
+ ev.data.compound["origin"] = Data(origin, Data::INTERPRETED);
if(num_connected==0) {
LOG(ERROR) << "not connected";
@@ -419,7 +419,7 @@ void MilesSessionInvoker::processEventStop(const std::string& origin) {
void MilesSessionInvoker::processEventParticipants(const std::string& origin) {
Event ev;
- ev.data.compound["origin"] = origin;
+ ev.data.compound["origin"] = Data(origin, Data::INTERPRETED);
if(num_connected==0) {
LOG(ERROR) << "not connected";
ev.name = "participants.error";
@@ -440,7 +440,7 @@ void MilesSessionInvoker::processEventParticipants(const std::string& origin) {
void MilesSessionInvoker::processEventThumbnail(const std::string& origin, const std::string& userid) {
Event ev;
- ev.data.compound["origin"] = origin;
+ ev.data.compound["origin"] = Data(origin, Data::INTERPRETED);
if(num_connected==0) {
LOG(ERROR) << "not connected";
ev.name = "thumbnail.error";
@@ -496,52 +496,52 @@ void MilesSessionInvoker::processEventThumbnail(const std::string& origin, const
void MilesSessionInvoker::processEventVideoOn(const std::string& origin, const std::string& userid) {
Event ev;
ev.name = "videoon.reply";
- ev.data.compound["origin"] = origin;
+ ev.data.compound["origin"] = Data(origin, Data::INTERPRETED);
returnEvent(ev);
}
void MilesSessionInvoker::processEventVideoOff(const std::string& origin, const std::string& userid) {
Event ev;
ev.name = "videooff.reply";
- ev.data.compound["origin"] = origin;
+ ev.data.compound["origin"] = Data(origin, Data::INTERPRETED);
returnEvent(ev);
}
void MilesSessionInvoker::processEventAudioOn(const std::string& origin, const std::string& userid) {
Event ev;
ev.name = "audioon.reply";
- ev.data.compound["origin"] = origin;
+ ev.data.compound["origin"] = Data(origin, Data::INTERPRETED);
returnEvent(ev);
}
void MilesSessionInvoker::processEventAudioOff(const std::string& origin, const std::string& userid) {
Event ev;
ev.name = "audiooff.reply";
- ev.data.compound["origin"] = origin;
+ ev.data.compound["origin"] = Data(origin, Data::INTERPRETED);
returnEvent(ev);
}
void MilesSessionInvoker::processEventSendVideo(const std::string& origin, size_t width, size_t height, size_t framerate, const std::string& compression) {
Event ev;
ev.name = "sendvideo.reply";
- ev.data.compound["origin"] = origin;
+ ev.data.compound["origin"] = Data(origin, Data::INTERPRETED);
sendvideo_enabled = 1;
returnEvent(ev);
}
void MilesSessionInvoker::processEventSendVideoOff(const std::string& origin) {
Event ev;
ev.name = "sendvideooff.reply";
- ev.data.compound["origin"] = origin;
+ ev.data.compound["origin"] = Data(origin, Data::INTERPRETED);
returnEvent(ev);
sendvideo_enabled = 0;
}
void MilesSessionInvoker::processEventSendAudio(const std::string& origin, const std::string& encoding) {
Event ev;
ev.name = "sendaudio.reply";
- ev.data.compound["origin"] = origin;
+ ev.data.compound["origin"] = Data(origin, Data::INTERPRETED);
returnEvent(ev);
sendaudio_enabled = 1;
}
void MilesSessionInvoker::processEventSendAudioOff(const std::string& origin) {
Event ev;
ev.name = "sendaudiooff.reply";
- ev.data.compound["origin"] = origin;
+ ev.data.compound["origin"] = Data(origin, Data::INTERPRETED);
returnEvent(ev);
sendaudio_enabled = 0;
}
@@ -552,7 +552,7 @@ void MilesSessionInvoker::processEventPostText(const std::string& origin, const
int n, length;
Event ev;
- ev.data.compound["origin"] = origin;
+ ev.data.compound["origin"] = Data(origin, Data::INTERPRETED);
if(num_connected==0) {
LOG(ERROR) << "not connected";
ev.name = "posttext.error";
@@ -574,7 +574,7 @@ void MilesSessionInvoker::processEventPostText(const std::string& origin, const
void MilesSessionInvoker::processEventGetText(const std::string& origin) {
Event ev;
- ev.data.compound["origin"] = origin;
+ ev.data.compound["origin"] = Data(origin, Data::INTERPRETED);
if(num_connected==0) {
LOG(ERROR) << "not connected";
ev.name = "gettext.error";
diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp
index 6ef1bd4..61008ff 100644
--- a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp
+++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp
@@ -402,7 +402,7 @@ bool UmundoInvoker::protobufToData(Data& data, const google::protobuf::Message&
case google::protobuf::FieldDescriptor::TYPE_DOUBLE:
if (fieldDesc->is_repeated()) {
for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
- data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedDouble(msg, fieldDesc, j))));
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedDouble(msg, fieldDesc, j)), Data::INTERPRETED));
}
} else {
data.compound[key].atom = toStr(reflect->GetDouble(msg, fieldDesc));
@@ -423,7 +423,7 @@ bool UmundoInvoker::protobufToData(Data& data, const google::protobuf::Message&
case google::protobuf::FieldDescriptor::TYPE_UINT32:
if (fieldDesc->is_repeated()) {
for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
- data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedUInt32(msg, fieldDesc, j))));
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedUInt32(msg, fieldDesc, j)), Data::INTERPRETED));
}
} else {
data.compound[key].atom = toStr(reflect->GetUInt32(msg, fieldDesc));
@@ -433,7 +433,7 @@ bool UmundoInvoker::protobufToData(Data& data, const google::protobuf::Message&
case google::protobuf::FieldDescriptor::TYPE_UINT64:
if (fieldDesc->is_repeated()) {
for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
- data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedUInt64(msg, fieldDesc, j))));
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedUInt64(msg, fieldDesc, j)), Data::INTERPRETED));
}
} else {
data.compound[key].atom = toStr(reflect->GetUInt64(msg, fieldDesc));
@@ -442,7 +442,7 @@ bool UmundoInvoker::protobufToData(Data& data, const google::protobuf::Message&
case google::protobuf::FieldDescriptor::TYPE_FLOAT:
if (fieldDesc->is_repeated()) {
for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
- data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedFloat(msg, fieldDesc, j))));
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedFloat(msg, fieldDesc, j)), Data::INTERPRETED));
}
} else {
data.compound[key].atom = toStr(reflect->GetFloat(msg, fieldDesc));
@@ -456,7 +456,7 @@ bool UmundoInvoker::protobufToData(Data& data, const google::protobuf::Message&
case google::protobuf::FieldDescriptor::TYPE_SFIXED32:
if (fieldDesc->is_repeated()) {
for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
- data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedInt32(msg, fieldDesc, j))));
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedInt32(msg, fieldDesc, j)), Data::INTERPRETED));
}
} else {
data.compound[key].atom = toStr(reflect->GetInt32(msg, fieldDesc));
@@ -467,7 +467,7 @@ bool UmundoInvoker::protobufToData(Data& data, const google::protobuf::Message&
case google::protobuf::FieldDescriptor::TYPE_SFIXED64:
if (fieldDesc->is_repeated()) {
for (int j = 0; j < reflect->FieldSize(msg, fieldDesc); j++) {
- data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedInt64(msg, fieldDesc, j))));
+ data.compound[key].array.push_back(Data(toStr(reflect->GetRepeatedInt64(msg, fieldDesc, j)), Data::INTERPRETED));
}
} else {
data.compound[key].atom = toStr(reflect->GetInt64(msg, fieldDesc));
diff --git a/src/uscxml/transform/ChartToFSM.cpp b/src/uscxml/transform/ChartToFSM.cpp
index cc94434..820e3bc 100644
--- a/src/uscxml/transform/ChartToFSM.cpp
+++ b/src/uscxml/transform/ChartToFSM.cpp
@@ -62,9 +62,72 @@ Interpreter ChartToFSM::flatten(const Interpreter& other) {
return flat;
}
+uint64_t ChartToFSM::stateMachineComplexity(const Arabica::DOM::Element<std::string>& root) {
+ Complexity complexity = calculateStateMachineComplexity(root);
+ uint64_t value = complexity.value;
+ for (std::list<uint64_t>::const_iterator histIter = complexity.history.begin(); histIter != complexity.history.end(); histIter++) {
+ value *= *histIter;
+ }
+
+ return value;
+}
+
+ChartToFSM::Complexity ChartToFSM::calculateStateMachineComplexity(const Arabica::DOM::Element<std::string>& root) {
+ Complexity complexity;
+
+ bool hasFlatHistory = false;
+ bool hasDeepHistory = false;
+
+ Arabica::DOM::NodeList<std::string> childElems = root.getChildNodes();
+ for (int i = 0; i < childElems.getLength(); i++) {
+ if (childElems.item(i).getNodeType() != Node_base::ELEMENT_NODE)
+ continue;
+ Element<std::string> childElem = Element<std::string>(childElems.item(i));
+ if (InterpreterImpl::isHistory(childElem)) {
+ if (HAS_ATTR(childElem, "type") && ATTR(childElem, "type") == "deep") {
+ hasDeepHistory = true;
+ } else {
+ hasFlatHistory = true;
+ }
+ }
+ }
+
+ if (InterpreterImpl::isCompound(root) || TAGNAME(root) == "scxml") {
+ // compounds can be in any of the child state -> add
+ NodeSet<std::string> childs = InterpreterImpl::getChildStates(root);
+ for (int i = 0; i < childs.size(); i++) {
+ complexity += calculateStateMachineComplexity(Element<std::string>(childs[i]));
+ }
+ if (hasFlatHistory) {
+ complexity.history.push_back(childs.size());
+ }
+ if (hasDeepHistory) {
+ complexity.history.push_back(complexity.value);
+ }
+ } else if (InterpreterImpl::isParallel(root)) {
+ // parallels are in all states -> multiply
+ NodeSet<std::string> childs = InterpreterImpl::getChildStates(root);
+ complexity.value = 1;
+ for (int i = 0; i < childs.size(); i++) {
+ complexity *= calculateStateMachineComplexity(Element<std::string>(childs[i]));
+ }
+ if (hasDeepHistory) {
+ complexity.history.push_back(complexity.value);
+ }
+
+ } else if (InterpreterImpl::isAtomic(root)) {
+ return 1;
+ }
+
+ return complexity;
+}
+
FlatteningInterpreter::FlatteningInterpreter(const Document<std::string>& doc) {
+ _perfProcessed = 0;
+ _perfTotal = 0;
+ _lastTimeStamp = tthread::chrono::system_clock::now();
_currGlobalTransition = NULL;
// just copy given doc into _document an create _flatDoc for the FSM
@@ -108,6 +171,9 @@ InterpreterState FlatteningInterpreter::interpret() {
init();
setupIOProcessors();
+ uint64_t complexity = ChartToFSM::stateMachineComplexity(_scxml) + 1;
+ std::cout << "Approximate Complexity: " << complexity << std::endl;
+
// initialize the datamodel
std::string datamodelName;
if (datamodelName.length() == 0 && HAS_ATTR(_scxml, "datamodel"))
@@ -179,11 +245,23 @@ InterpreterState FlatteningInterpreter::interpret() {
#endif
createDocument();
+
+ NodeSet<std::string> elements = InterpreterImpl::filterChildType(Node_base::ELEMENT_NODE, _scxml, true);
+ uint64_t nrStates = 0;
+ for (int i = 0; i < elements.size(); i++) {
+ Element<std::string> stateElem = Element<std::string>(elements[i]);
+ if (isState(stateElem) && !HAS_ATTR(stateElem, "transient"))
+ nrStates++;
+ }
+
+ std::cout << "Actual Complexity: " << nrStates << std::endl;
return _state;
}
void FlatteningInterpreter::executeContent(const Arabica::DOM::Element<std::string>& content, bool rethrow) {
// std::cout << content << std::endl;
+// std::cout << TAGNAME(content) << std::endl;
+
GlobalTransition::Action action;
if (false) {
@@ -193,8 +271,8 @@ void FlatteningInterpreter::executeContent(const Arabica::DOM::Element<std::stri
action.onExit = content;
} else if (TAGNAME(content) == "onentry") {
action.onExit = content;
- } else {
- assert(false);
+ } else { // e.g. global script elements
+ return;
}
_currGlobalTransition->actions.push_back(action);
}
@@ -216,9 +294,8 @@ void FlatteningInterpreter::cancelInvoke(const Arabica::DOM::Node<std::string>&
void FlatteningInterpreter::internalDoneSend(const Arabica::DOM::Element<std::string>& state) {
Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state;
-
-// if (parentIsScxmlState(state))
-// return;
+ if (parentIsScxmlState(state))
+ return;
// std::cout << "internalDoneSend: " << state << std::endl;
@@ -269,7 +346,26 @@ static bool isSuperset(const GlobalTransition* t1, const GlobalTransition* t2) {
return isSuperset;
}
-static NodeSet<std::string> filterChildEnabled(const NodeSet<std::string>& transitions) {
+static bool filterSameState(const NodeSet<std::string>& transitions) {
+ NodeSet<std::string> filteredTransitions;
+ for (unsigned int i = 0; i < transitions.size(); i++) {
+ Node<std::string> t1 = transitions[i];
+ Node<std::string> p1 = InterpreterImpl::getParentState(t1);
+
+ for (unsigned int j = 0; j < transitions.size(); j++) {
+ if (i == j)
+ continue;
+ Node<std::string> t2 = transitions[j];
+ Node<std::string> p2 = InterpreterImpl::getParentState(t2);
+
+ if (p1 == p2)
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool filterChildEnabled(const NodeSet<std::string>& transitions) {
// drop any transition that is already enabled by a child
NodeSet<std::string> filteredTransitions;
for (unsigned int i = 0; i < transitions.size(); i++) {
@@ -280,24 +376,22 @@ static NodeSet<std::string> filterChildEnabled(const NodeSet<std::string>& trans
continue;
Node<std::string> t2 = transitions[j];
Node<std::string> p2 = InterpreterImpl::getParentState(t2);
-// p2 = p2.getParentNode();
+ p2 = p2.getParentNode(); // TODO: think about again!
while(p2) {
if (p1 == p2) {
std::string eventDesc1 = ATTR(t1, "event");
std::string eventDesc2 = ATTR(t2, "event");
if (InterpreterImpl::nameMatch(eventDesc1, eventDesc2)) {
-// std::cout << "Dropping " << t1 << std::endl << "for " << t2 << std::endl;
- goto SKIP_TRANSITION;
+ return false;
}
}
p2 = p2.getParentNode();
}
}
filteredTransitions.push_back(t1);
-SKIP_TRANSITION:
;
}
- return filteredTransitions;
+ return true;
}
static std::list<GlobalTransition*> sortTransitions(std::list<GlobalTransition*> list) {
@@ -372,6 +466,8 @@ void FlatteningInterpreter::explode() {
}
_globalConf[globalState->stateId] = globalState;
+ assert(isLegalConfiguration(configuration));
+
// get all transition elements from states in the current configuration
NodeSet<std::string> allTransitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", configuration);
@@ -448,12 +544,30 @@ void FlatteningInterpreter::explode() {
break;
NodeSet<std::string> transitions;
+// std::cout << globalState->stateId << " [" << nrElements << "]: " << std::endl;
for (int i = 1; i <= k; i++) {
+// std::cout << stack[i] - 1 << ", ";
transitions.push_back(allTransitions[stack[i] - 1]);
}
+// std::cout << std::endl;
+
+ _perfTotal++;
+ _perfProcessed++;
+
+ if (tthread::chrono::system_clock::now() - _lastTimeStamp > 1000) {
+ _lastTimeStamp = tthread::chrono::system_clock::now();
+// std::cout << globalState->stateId << " [" << nrElements << "]: " << std::endl;
+ std::cout << _perfTotal << " [" << _perfProcessed << "/sec]" << std::endl;
+ _perfProcessed = 0;
+ }
+
+ // remove transitions in the same state
+ if(!filterSameState(transitions))
+ continue;
// remove those transitions with a child transition
- transitions = filterChildEnabled(transitions);
+ if(!filterChildEnabled(transitions))
+ continue;
// reduce to conflict-free subset
transitions = filterPreempted(transitions);
@@ -541,6 +655,13 @@ NEXT_DEPTH:
_currGlobalTransition = *transListIter;
microstep((*transListIter)->transitions);
+ if (!isLegalConfiguration(_configuration)) {
+ std::cout << "invalid configuration from " << globalState->stateId << std::endl;
+ for (int i = 0; i < (*transListIter)->transitions.size(); i++) {
+ std::cout << (*transListIter)->transitions[i] << std::endl;
+ }
+ assert(false);
+ }
explode();
// reset state for next transition set
@@ -906,7 +1027,7 @@ GlobalState::GlobalState(const Arabica::XPath::NodeSet<std::string>& activeState
histIter != historyStates.end();
histIter++) {
const Arabica::XPath::NodeSet<std::string>& histStates = histIter->second;
- idSS << "history-";
+ idSS << "history--";
idSS << histIter->first << "-";
for (int i = 0; i < histStates.size(); i++) {
idSS << ATTR(histStates[i], "id") << "-";
diff --git a/src/uscxml/transform/ChartToFSM.h b/src/uscxml/transform/ChartToFSM.h
index dba8d4d..0808a40 100644
--- a/src/uscxml/transform/ChartToFSM.h
+++ b/src/uscxml/transform/ChartToFSM.h
@@ -26,7 +26,7 @@
#include <DOM/Node.hpp>
#include <XPath/XPath.hpp>
#include <ostream>
-
+#include <list>
namespace uscxml {
class GlobalState;
@@ -137,6 +137,10 @@ protected:
GlobalState* _start;
GlobalTransition* _currGlobalTransition;
+ uint64_t _perfProcessed;
+ uint64_t _perfTotal;
+ uint64_t _lastTimeStamp;
+
int maxDepth;
int maxOrder;
@@ -147,6 +151,32 @@ protected:
class USCXML_API ChartToFSM {
public:
static Interpreter flatten(const Interpreter& other);
+ static uint64_t stateMachineComplexity(const Arabica::DOM::Element<std::string>& root);
+
+protected:
+ class USCXML_API Complexity {
+ public:
+ Complexity() : value(0) {}
+ Complexity(uint64_t value) : value(value) {}
+
+ Complexity& operator+=(const Complexity& rhs) {
+ value += rhs.value;
+ history.insert(history.end(), rhs.history.begin(), rhs.history.end());
+ return *this;
+ }
+
+ Complexity& operator*=(const Complexity& rhs) {
+ value *= rhs.value;
+ history.insert(history.end(), rhs.history.begin(), rhs.history.end());
+ return *this;
+ }
+
+ uint64_t value;
+ std::list<uint64_t> history;
+ };
+
+ static Complexity calculateStateMachineComplexity(const Arabica::DOM::Element<std::string>& root);
+
};
}
diff --git a/src/uscxml/transform/FSMToCPP.cpp b/src/uscxml/transform/FSMToCPP.cpp
new file mode 100644
index 0000000..6bf4535
--- /dev/null
+++ b/src/uscxml/transform/FSMToCPP.cpp
@@ -0,0 +1,545 @@
+/**
+ * @file
+ * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @copyright Simplified BSD
+ *
+ * @cond
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the FreeBSD license as published by the FreeBSD
+ * project.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the FreeBSD license along with this
+ * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#include "uscxml/transform/ChartToFSM.h"
+#include "uscxml/transform/FSMToCPP.h"
+#include <DOM/io/Stream.hpp>
+#include <iostream>
+#include "uscxml/UUID.h"
+#include <math.h>
+#include <boost/algorithm/string.hpp>
+#include <glog/logging.h>
+
+namespace uscxml {
+
+using namespace Arabica::DOM;
+using namespace Arabica::XPath;
+
+void FSMToCPP::writeProgram(std::ostream& stream,
+ const Interpreter& interpreter) {
+ FSMToCPP promelaWriter;
+ interpreter.getImpl()->copyTo(&promelaWriter);
+ promelaWriter.writeProgram(stream);
+}
+
+FSMToCPP::FSMToCPP() : _eventTrie(".") {
+}
+
+void FSMToCPP::writeEvents(std::ostream& stream) {
+ std::list<TrieNode*> eventNames = _eventTrie.getWordsWithPrefix("");
+ std::list<TrieNode*>::iterator eventIter = eventNames.begin();
+ stream << "// event name identifiers" << std::endl;
+ while(eventIter != eventNames.end()) {
+ stream << "#define " << "e" << (*eventIter)->identifier << " " << (*eventIter)->identifier;
+ stream << " // from \"" << (*eventIter)->value << "\"" << std::endl;
+ eventIter++;
+ }
+}
+
+void FSMToCPP::writeStates(std::ostream& stream) {
+ stream << "// state name identifiers" << std::endl;
+ for (int i = 0; i < _globalStates.size(); i++) {
+ stream << "#define " << "s" << i << " " << i;
+ stream << " // from \"" << ATTR(_globalStates[i], "id") << "\"" << std::endl;
+ }
+
+}
+
+Arabica::XPath::NodeSet<std::string> FSMToCPP::getTransientContent(const Arabica::DOM::Node<std::string>& state) {
+ Arabica::XPath::NodeSet<std::string> content;
+ Arabica::DOM::Node<std::string> currState = state;
+ for (;;) {
+ if (!HAS_ATTR(currState, "transient") || !DOMUtils::attributeIsTrue(ATTR(currState, "transient")))
+ break;
+ content.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "invoke", currState));
+ content.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "onentry", currState));
+ content.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "onexit", currState));
+ NodeSet<std::string> transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", currState);
+ currState = _states[ATTR(transitions[0], "target")];
+ }
+
+ return content;
+}
+
+Node<std::string> FSMToCPP::getUltimateTarget(const Arabica::DOM::Node<std::string>& transition) {
+ Arabica::DOM::Node<std::string> currState = _states[ATTR(transition, "target")];
+
+ for (;;) {
+ if (!HAS_ATTR(currState, "transient") || !DOMUtils::attributeIsTrue(ATTR(currState, "transient")))
+ return currState;
+ NodeSet<std::string> transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", currState);
+ currState = _states[ATTR(transitions[0], "target")];
+ }
+}
+
+void FSMToCPP::writeInlineComment(std::ostream& stream, const Arabica::DOM::Node<std::string>& node) {
+ if (node.getNodeType() != Node_base::COMMENT_NODE)
+ return;
+
+ std::string comment = node.getNodeValue();
+ boost::trim(comment);
+ if (!boost::starts_with(comment, "promela-inline:"))
+ return;
+
+ std::stringstream ssLine(comment);
+ std::string line;
+ std::getline(ssLine, line); // consume first line
+ while(std::getline(ssLine, line)) {
+ if (line.length() == 0)
+ continue;
+ stream << line;
+ }
+}
+
+void FSMToCPP::writeExecutableContent(std::ostream& stream, const Arabica::DOM::Node<std::string>& node, int indent) {
+
+ std::string padding;
+ for (int i = 0; i < indent; i++) {
+ padding += " ";
+ }
+
+ if (node.getNodeType() == Node_base::COMMENT_NODE) {
+ std::string comment = node.getNodeValue();
+ boost::trim(comment);
+ std::stringstream inlinePromela;
+ if (!boost::starts_with(comment, "promela-inline:"))
+ return;
+ std::stringstream ssLine(comment);
+ std::string line;
+ std::getline(ssLine, line); // consume first line
+ while(std::getline(ssLine, line)) {
+ if (line.length() == 0)
+ continue;
+ inlinePromela << line << std::endl;
+ }
+ stream << padding << "skip;" << std::endl;
+ stream << beautifyIndentation(inlinePromela.str(), indent) << std::endl;
+ }
+
+ if (node.getNodeType() != Node_base::ELEMENT_NODE)
+ return;
+
+ if (false) {
+ } else if(TAGNAME(node) == "state") {
+ if (HAS_ATTR(node, "transient") && DOMUtils::attributeIsTrue(ATTR(node, "transient"))) {
+ Arabica::XPath::NodeSet<std::string> execContent = getTransientContent(node);
+ for (int i = 0; i < execContent.size(); i++) {
+ writeExecutableContent(stream, execContent[i], indent);
+ }
+ } else {
+ Arabica::DOM::Node<std::string> child = node.getFirstChild();
+ while(child) {
+ writeExecutableContent(stream, child, indent);
+ child = child.getNextSibling();
+ }
+ }
+ } else if(TAGNAME(node) == "transition") {
+ stream << "t" << _transitions[node] << ":" << std::endl;
+
+ stream << padding << "atomic {" << std::endl;
+ writeExecutableContent(stream, _states[ATTR(node, "target")], indent+1);
+ stream << padding << " skip;" << std::endl;
+
+ Node<std::string> newState = getUltimateTarget(node);
+ for (int i = 0; i < _globalStates.size(); i++) {
+ if (newState != _globalStates[i])
+ continue;
+ stream << padding << " s = s" << i << ";" << std::endl;
+ }
+
+ stream << padding << "}" << std::endl;
+ if (isFinal(Element<std::string>(newState))) {
+ stream << padding << "goto terminate;" << std::endl;
+ } else {
+ stream << padding << "goto nextStep;" << std::endl;
+ }
+
+ } else if(TAGNAME(node) == "onentry" || TAGNAME(node) == "onexit") {
+ Arabica::DOM::Node<std::string> child = node.getFirstChild();
+ while(child) {
+ writeExecutableContent(stream, child, indent);
+ child = child.getNextSibling();
+ }
+
+ } else if(TAGNAME(node) == "script") {
+ NodeSet<std::string> scriptText = filterChildType(Node_base::TEXT_NODE, node, true);
+ for (int i = 0; i < scriptText.size(); i++) {
+ stream << beautifyIndentation(scriptText[i].getNodeValue(), indent) << std::endl;
+ }
+
+ } else if(TAGNAME(node) == "log") {
+ // ignore
+
+ } else if(TAGNAME(node) == "foreach") {
+ if (HAS_ATTR(node, "index"))
+ stream << padding << ATTR(node, "index") << " = 0;" << std::endl;
+ stream << padding << "for (" << ATTR(node, "item") << " in " << ATTR(node, "array") << ") {" << std::endl;
+ Arabica::DOM::Node<std::string> child = node.getFirstChild();
+ while(child) {
+ writeExecutableContent(stream, child, indent + 1);
+ child = child.getNextSibling();
+ }
+ if (HAS_ATTR(node, "index"))
+ stream << padding << " " << ATTR(node, "index") << "++;" << std::endl;
+ stream << padding << "}" << std::endl;
+
+ } else if(TAGNAME(node) == "if") {
+ NodeSet<std::string> condChain;
+ condChain.push_back(node);
+ condChain.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "elseif", node));
+ condChain.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "else", node));
+
+ writeIfBlock(stream, condChain, indent);
+
+ } else if(TAGNAME(node) == "raise") {
+ TrieNode* trieNode = _eventTrie.getNodeWithPrefix(ATTR(node, "event"));
+ stream << padding << "iQ!e" << trieNode->identifier << ";" << std::endl;
+ } else if(TAGNAME(node) == "send") {
+ if (!HAS_ATTR(node, "target")) {
+ // this is for our external queue
+ TrieNode* trieNode = _eventTrie.getNodeWithPrefix(ATTR(node, "event"));
+ stream << padding << "tmpQ!e" << trieNode->identifier << ";" << std::endl;
+ }
+ } else if(TAGNAME(node) == "invoke") {
+ } else if(TAGNAME(node) == "uninvoke") {
+ stream << padding << ATTR(node, "invokeid") << "EventSourceDone" << "= 1;" << std::endl;
+ } else {
+
+ std::cerr << "'" << TAGNAME(node) << "'" << std::endl << node << std::endl;
+ assert(false);
+ }
+
+}
+
+void FSMToCPP::writeIfBlock(std::ostream& stream, const Arabica::XPath::NodeSet<std::string>& condChain, int indent) {
+ if (condChain.size() == 0)
+ return;
+
+ std::string padding;
+ for (int i = 0; i < indent; i++) {
+ padding += " ";
+ }
+
+ bool noNext = condChain.size() == 1;
+ bool nextIsElse = false;
+ if (condChain.size() > 1) {
+ if (TAGNAME(condChain[1]) == "else") {
+ nextIsElse = true;
+ }
+ }
+
+ Node<std::string> ifNode = condChain[0];
+
+ stream << padding << "if" << std::endl;
+ // we need to nest the elseifs to resolve promela if semantics
+ stream << padding << ":: (" << ATTR(ifNode, "cond") << ") -> {" << std::endl;
+
+ Arabica::DOM::Node<std::string> child;
+ if (TAGNAME(ifNode) == "if") {
+ child = ifNode.getFirstChild();
+ } else {
+ child = ifNode.getNextSibling();
+ }
+ while(child) {
+ if (child.getNodeType() == Node_base::ELEMENT_NODE) {
+ if (TAGNAME(child) == "elseif" || TAGNAME(child) == "else")
+ break;
+ }
+ writeExecutableContent(stream, child, indent + 1);
+ child = child.getNextSibling();
+ }
+ stream << padding << "}" << std::endl;
+ stream << padding << ":: else -> ";
+
+ if (nextIsElse) {
+ child = condChain[1].getNextSibling();
+ stream << "{" << std::endl;
+ while(child) {
+ writeExecutableContent(stream, child, indent + 1);
+ child = child.getNextSibling();
+ }
+ stream << padding << "}" << std::endl;
+
+ } else if (noNext) {
+ stream << "skip;" << std::endl;
+ } else {
+ stream << "{" << std::endl;
+
+ Arabica::XPath::NodeSet<std::string> cdrCondChain;
+ for (int i = 1; i < condChain.size(); i++) {
+ cdrCondChain.push_back(condChain[i]);
+ }
+ writeIfBlock(stream, cdrCondChain, indent + 1);
+ stream << padding << "}" << std::endl;
+
+ }
+
+ stream << padding << "fi;" << std::endl;
+
+}
+
+std::string FSMToCPP::beautifyIndentation(const std::string& code, int indent) {
+
+ std::string padding;
+ for (int i = 0; i < indent; i++) {
+ padding += " ";
+ }
+
+ // remove topmost indentation from every line and reindent
+ std::stringstream beautifiedSS;
+
+ std::string initialIndent;
+ bool gotIndent = false;
+ bool isFirstLine = true;
+ std::stringstream ssLine(code);
+ std::string line;
+
+ while(std::getline(ssLine, line)) {
+ size_t firstChar = line.find_first_not_of(" \t\r\n");
+ if (firstChar != std::string::npos) {
+ if (!gotIndent) {
+ initialIndent = line.substr(0, firstChar);
+ gotIndent = true;
+ }
+ beautifiedSS << (isFirstLine ? "" : "\n") << padding << boost::replace_first_copy(line, initialIndent, "");
+ isFirstLine = false;
+ }
+ }
+
+ return beautifiedSS.str();
+}
+
+void FSMToCPP::writeDeclarations(std::ostream& stream) {
+
+ // get all data elements
+ NodeSet<std::string> datas = _xpath.evaluate("//" + _nsInfo.xpathPrefix + "data", _scxml).asNodeSet();
+ NodeSet<std::string> dataText = filterChildType(Node_base::TEXT_NODE, datas, true);
+
+ // write their text content
+ stream << "// datamodel variables" << std::endl;
+ for (int i = 0; i < dataText.size(); i++) {
+ Node<std::string> data = dataText[i];
+ stream << beautifyIndentation(data.getNodeValue()) << std::endl;
+ }
+
+ stream << std::endl;
+ stream << "// global variables" << std::endl;
+ stream << "int e; /* current event */" << std::endl;
+ stream << "int s; /* current state */" << std::endl;
+ stream << "chan iQ = [100] of {int} /* internal queue */" << std::endl;
+ stream << "chan eQ = [100] of {int} /* external queue */" << std::endl;
+ stream << "chan tmpQ = [100] of {int} /* temporary queue for external events in transitions */" << std::endl;
+ stream << "int tmpQItem;" << std::endl;
+
+ stream << std::endl;
+ stream << "// event sources" << std::endl;
+
+}
+
+void FSMToCPP::writeFSM(std::ostream& stream) {
+ NodeSet<std::string> transitions;
+
+ stream << "proctype step() {" << std::endl;
+ // write initial transition
+ transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", _startState);
+ assert(transitions.size() == 1);
+ stream << " // transition's executable content" << std::endl;
+ writeExecutableContent(stream, transitions[0], 1);
+
+ for (int i = 0; i < _globalStates.size(); i++) {
+ if (_globalStates[i] == _startState)
+ continue;
+ NodeSet<std::string> transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", _globalStates[i]);
+ for (int j = 0; j < transitions.size(); j++) {
+ writeExecutableContent(stream, transitions[j], 1);
+ }
+ }
+
+ stream << std::endl;
+ stream << "nextStep:" << std::endl;
+ stream << " // push send events to external queue" << std::endl;
+ stream << " if" << std::endl;
+ stream << " :: len(tmpQ) != 0 -> { tmpQ?e; eQ!e }" << std::endl;
+ stream << " :: else -> skip;" << std::endl;
+ stream << " fi;" << std::endl << std::endl;
+
+ stream << " /* pop an event */" << std::endl;
+ stream << " if" << std::endl;
+ stream << " :: len(iQ) != 0 -> iQ ? e /* from internal queue */" << std::endl;
+ stream << " :: else -> eQ ? e /* from external queue */" << std::endl;
+ stream << " fi;" << std::endl;
+ stream << " /* event dispatching per state */" << std::endl;
+ stream << " if" << std::endl;
+
+ writeEventDispatching(stream);
+
+ stream << " :: else -> goto nextStep;" << std::endl;
+ stream << " fi;" << std::endl;
+ stream << "terminate: skip;" << std::endl;
+
+
+ stream << "}" << std::endl;
+}
+
+void FSMToCPP::writeEventDispatching(std::ostream& stream) {
+ for (int i = 0; i < _globalStates.size(); i++) {
+ if (_globalStates[i] == _startState)
+ continue;
+
+ stream << " :: (s == s" << i << ") -> {" << std::endl;
+
+ NodeSet<std::string> transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", _globalStates[i]);
+ writeDispatchingBlock(stream, transitions, 2);
+ stream << " goto nextStep;" << std::endl;
+ stream << " }" << std::endl;
+ }
+}
+
+void FSMToCPP::writeDispatchingBlock(std::ostream& stream, const Arabica::XPath::NodeSet<std::string>& transChain, int indent) {
+ if (transChain.size() == 0)
+ return;
+
+ std::string padding;
+ for (int i = 0; i < indent; i++) {
+ padding += " ";
+ }
+
+ stream << padding << "if" << std::endl;
+ stream << padding << ":: ((0";
+
+ Node<std::string> currTrans = transChain[0];
+ std::string eventDesc = ATTR(currTrans, "event");
+ if (boost::ends_with(eventDesc, "*"))
+ eventDesc = eventDesc.substr(0, eventDesc.size() - 1);
+ if (boost::ends_with(eventDesc, "."))
+ eventDesc = eventDesc.substr(0, eventDesc.size() - 1);
+
+ if (eventDesc.size() == 0) {
+ stream << " || 1";
+ } else {
+ std::list<TrieNode*> trieNodes = _eventTrie.getWordsWithPrefix(eventDesc);
+
+ std::list<TrieNode*>::iterator trieIter = trieNodes.begin();
+ while(trieIter != trieNodes.end()) {
+ stream << " || e == e" << (*trieIter)->identifier;
+ trieIter++;
+ }
+ }
+
+ stream << ") && ";
+ stream << (HAS_ATTR(currTrans, "cond") ? ATTR(currTrans, "cond") : "1");
+ stream << ") -> goto t" << _transitions[currTrans] << ";" << std::endl;
+ ;
+
+ stream << padding << ":: else {" << std::endl;
+
+ Arabica::XPath::NodeSet<std::string> cdrTransChain;
+ for (int i = 1; i < transChain.size(); i++) {
+ cdrTransChain.push_back(transChain[i]);
+ }
+ writeDispatchingBlock(stream, cdrTransChain, indent + 1);
+
+ stream << padding << " goto nextStep;" << std::endl;
+ stream << padding << "}" << std::endl;
+ stream << padding << "fi;" << std::endl;
+}
+
+
+void FSMToCPP::writeMain(std::ostream& stream) {
+ stream << std::endl;
+ stream << "init {" << std::endl;
+ stream << " run step();" << std::endl;
+ stream << "}" << std::endl;
+
+}
+
+void FSMToCPP::initNodes() {
+ // get all states
+ NodeSet<std::string> states = filterChildElements(_nsInfo.xmlNSPrefix + "state", _scxml);
+ for (int i = 0; i < states.size(); i++) {
+ _states[ATTR(states[i], "id")] = states[i];
+ if (HAS_ATTR(states[i], "transient") && DOMUtils::attributeIsTrue(ATTR(states[i], "transient")))
+ continue;
+ _globalStates.push_back(states[i]);
+ }
+ _startState = _states[ATTR(_scxml, "initial")];
+
+ // initialize event trie with all events that might occur
+ NodeSet<std::string> internalEventNames;
+ internalEventNames.push_back(_xpath.evaluate("//" + _nsInfo.xpathPrefix + "transition", _scxml).asNodeSet());
+ internalEventNames.push_back(_xpath.evaluate("//" + _nsInfo.xpathPrefix + "raise", _scxml).asNodeSet());
+ internalEventNames.push_back(_xpath.evaluate("//" + _nsInfo.xpathPrefix + "send", _scxml).asNodeSet());
+
+ for (int i = 0; i < internalEventNames.size(); i++) {
+ if (HAS_ATTR(internalEventNames[i], "event")) {
+ std::string eventNames = ATTR(internalEventNames[i], "event");
+ std::list<std::string> events = tokenizeIdRefs(eventNames);
+ for (std::list<std::string>::iterator eventIter = events.begin();
+ eventIter != events.end(); eventIter++) {
+ std::string eventName = *eventIter;
+ if (boost::ends_with(eventName, "*"))
+ eventName = eventName.substr(0, eventName.size() - 1);
+ if (boost::ends_with(eventName, "."))
+ eventName = eventName.substr(0, eventName.size() - 1);
+ _eventTrie.addWord(eventName);
+ }
+ }
+ }
+
+ // enumerate transitions
+ NodeSet<std::string> transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", _scxml, true);
+ int index = 0;
+ for (int i = 0; i < transitions.size(); i++) {
+ _transitions[transitions[i]] = index++;
+ }
+}
+
+void FSMToCPP::writeProgram(std::ostream& stream) {
+
+ if (!HAS_ATTR(_scxml, "flat") || !DOMUtils::attributeIsTrue(ATTR(_scxml, "flat"))) {
+ LOG(ERROR) << "Given SCXML document was not flattened";
+ return;
+ }
+
+ if (!HAS_ATTR(_scxml, "datamodel") || ATTR(_scxml, "datamodel") != "promela") {
+ LOG(ERROR) << "Can only convert SCXML documents with \"promela\" datamodel";
+ return;
+ }
+
+ if (HAS_ATTR(_scxml, "binding") && ATTR(_scxml, "binding") != "early") {
+ LOG(ERROR) << "Can only convert for early data bindings";
+ return;
+ }
+
+ initNodes();
+
+ writeEvents(stream);
+ stream << std::endl;
+ writeStates(stream);
+ stream << std::endl;
+ writeDeclarations(stream);
+ stream << std::endl;
+ writeFSM(stream);
+ stream << std::endl;
+ writeMain(stream);
+ stream << std::endl;
+
+}
+
+} \ No newline at end of file
diff --git a/src/uscxml/transform/FSMToCPP.h b/src/uscxml/transform/FSMToCPP.h
new file mode 100644
index 0000000..59231b0
--- /dev/null
+++ b/src/uscxml/transform/FSMToCPP.h
@@ -0,0 +1,72 @@
+/**
+ * @file
+ * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @copyright Simplified BSD
+ *
+ * @cond
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the FreeBSD license as published by the FreeBSD
+ * project.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the FreeBSD license along with this
+ * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#ifndef FSMTOCPP_H_201672B0
+#define FSMTOCPP_H_201672B0
+
+#include "uscxml/interpreter/InterpreterDraft6.h"
+#include "uscxml/DOMUtils.h"
+#include "uscxml/util/Trie.h"
+
+#include <DOM/Document.hpp>
+#include <DOM/Node.hpp>
+#include <XPath/XPath.hpp>
+#include <ostream>
+
+namespace uscxml {
+
+class USCXML_API FSMToCPP : public InterpreterDraft6 {
+public:
+ static void writeProgram(std::ostream& stream,
+ const Interpreter& interpreter);
+
+ static std::string beautifyIndentation(const std::string& code, int indent = 0);
+
+protected:
+ FSMToCPP();
+ void writeProgram(std::ostream& stream);
+
+ void initNodes();
+
+ void writeEvents(std::ostream& stream);
+ void writeStates(std::ostream& stream);
+ void writeDeclarations(std::ostream& stream);
+ void writeExecutableContent(std::ostream& stream, const Arabica::DOM::Node<std::string>& node, int indent = 0);
+ void writeInlineComment(std::ostream& stream, const Arabica::DOM::Node<std::string>& node);
+ void writeFSM(std::ostream& stream);
+ void writeEventDispatching(std::ostream& stream);
+ void writeMain(std::ostream& stream);
+
+ void writeIfBlock(std::ostream& stream, const Arabica::XPath::NodeSet<std::string>& condChain, int indent = 0);
+ void writeDispatchingBlock(std::ostream& stream, const Arabica::XPath::NodeSet<std::string>& transChain, int indent = 0);
+
+ Arabica::XPath::NodeSet<std::string> getTransientContent(const Arabica::DOM::Node<std::string>& state);
+ Arabica::DOM::Node<std::string> getUltimateTarget(const Arabica::DOM::Node<std::string>& transition);
+
+ Trie _eventTrie;
+ Arabica::XPath::NodeSet<std::string> _globalStates;
+ Arabica::DOM::Node<std::string> _startState;
+ std::map<std::string, Arabica::DOM::Node<std::string> > _states;
+ std::map<Arabica::DOM::Node<std::string>, int> _transitions;
+
+};
+
+}
+
+#endif /* end of include guard: FSMTOCPP_H_201672B0 */
diff --git a/src/uscxml/transform/FlatStateIdentifier.h b/src/uscxml/transform/FlatStateIdentifier.h
new file mode 100644
index 0000000..2ee0443
--- /dev/null
+++ b/src/uscxml/transform/FlatStateIdentifier.h
@@ -0,0 +1,155 @@
+/**
+ * @file
+ * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @copyright Simplified BSD
+ *
+ * @cond
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the FreeBSD license as published by the FreeBSD
+ * project.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the FreeBSD license along with this
+ * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#ifndef FLATSTATEIDENTIFIER_H_E9534AF9
+#define FLATSTATEIDENTIFIER_H_E9534AF9
+
+
+#include <sstream>
+#include <string>
+#include <list>
+#include <map>
+
+namespace uscxml {
+
+class USCXML_API FlatStateIdentifier {
+public:
+ FlatStateIdentifier(const std::string& identifier) {
+ std::string parsedName;
+ // parse unique state identifier
+ std::stringstream elemNameSS(identifier);
+ std::string section;
+ while(std::getline(elemNameSS, section, ';')) {
+ if (boost::starts_with(section, "active-")) {
+ std::stringstream stateSS(section.substr(7));
+ std::string state;
+ while(std::getline(stateSS, state, '-')) {
+ if (state.length() > 0) {
+ active.push_back(state);
+ }
+ }
+ } else if (boost::starts_with(section, "entered-")) {
+ std::stringstream stateSS(section.substr(8));
+ std::string state;
+ while(std::getline(stateSS, state, '-')) {
+ if (state.length() > 0) {
+ visited.push_back(state);
+ }
+ }
+ } else if (boost::starts_with(section, "history-")) {
+ std::stringstream stateSS(section.substr(8));
+ std::string state;
+ std::string history;
+ while(std::getline(stateSS, state, '-')) {
+ if (state.length() > 0) {
+ if (history.size() == 0) {
+ history = state;
+ } else {
+ histories[history].push_back(state);
+ }
+ } else {
+ history = "";
+ }
+ }
+ }
+ }
+ }
+
+ std::string activeId() {
+ std::stringstream activeSS;
+ activeSS << "active-";
+ for (std::list<std::string>::const_iterator activeIter = active.begin(); activeIter != active.end(); activeIter++) {
+ activeSS << *activeIter << "-";
+ }
+ return activeSS.str();
+ }
+
+ std::list<std::string> active;
+ std::list<std::string> visited;
+ std::map<std::string, std::list<std::string> > histories;
+
+ static std::string toHTMLLabel(const std::string& identifier, int minRows = 0) {
+ FlatStateIdentifier flatId(identifier);
+
+ std::list<std::string>::const_iterator listIter;
+ std::stringstream labelSS;
+ std::string seperator;
+
+// labelSS << "<table valign=\"top\" align=\"left\" cellborder=\"0\" border=\"0\" cellspacing=\"0\" cellpadding=\"2\">";
+// labelSS << "<tr>";
+// labelSS << "<td balign=\"left\" align=\"left\" valign=\"top\">";
+
+ labelSS << "<b>active: </b>";
+ labelSS << "{";
+ for (listIter = flatId.active.begin(); listIter != flatId.active.end(); listIter++) {
+ labelSS << seperator << *listIter;
+ seperator = ", ";
+ }
+ labelSS << "}";
+
+ if (flatId.visited.size() > 0) {
+ minRows--;
+
+ labelSS << "<br /><b>init: </b>";
+
+ labelSS << "{";
+ seperator = "";
+ for (listIter = flatId.visited.begin(); listIter != flatId.visited.end(); listIter++) {
+ labelSS << seperator << *listIter;
+ seperator = ", ";
+ }
+ labelSS << "}";
+ }
+
+#if 1
+ if (flatId.histories.size() > 0) {
+ minRows--;
+
+ seperator = "";
+ std::string histSeperator = "<br /> ";
+
+ labelSS << "<br /><b>history: </b>";
+
+ std::map<std::string, std::list<std::string> >::const_iterator histIter;
+ for (histIter = flatId.histories.begin(); histIter != flatId.histories.end(); histIter++) {
+ labelSS << histSeperator << histIter->first << ": {";
+
+ for (listIter = histIter->second.begin(); listIter != histIter->second.end(); listIter++) {
+ labelSS << seperator << *listIter;
+ seperator = ", ";
+ }
+ labelSS << "}";
+ seperator = "";
+ }
+ }
+#endif
+// while(minRows-- > 0)
+// labelSS << "<tr><td valign=\"top\"></td></tr>"; // eat up rest of space
+//
+// labelSS << "</td>";
+// labelSS << "</tr>";
+// labelSS << "</table>";
+ return labelSS.str();
+ }
+
+};
+
+}
+
+#endif /* end of include guard: FLATSTATEIDENTIFIER_H_E9534AF9 */
diff --git a/test/src/test-w3c.cpp b/test/src/test-w3c.cpp
index 4060ef0..65b56dd 100644
--- a/test/src/test-w3c.cpp
+++ b/test/src/test-w3c.cpp
@@ -196,7 +196,7 @@ int main(int argc, char** argv) {
if (withFlattening) {
Interpreter flatInterpreter = Interpreter::fromURI(documentURI);
interpreter = Interpreter::fromDOM(ChartToFSM::flatten(flatInterpreter).getDocument(), flatInterpreter.getNameSpaceInfo());
- interpreter.setNameSpaceInfo(interpreter.getNameSpaceInfo());
+ interpreter.setSourceURI(flatInterpreter.getSourceURI());
} else {
interpreter = Interpreter::fromURI(documentURI);
}
diff --git a/test/w3c/lua/test201.scxml b/test/w3c/lua/test201.scxml
index f5f30f6..e1d6fe7 100644
--- a/test/w3c/lua/test201.scxml
+++ b/test/w3c/lua/test201.scxml
@@ -4,7 +4,7 @@ test since platforms are not required to support basic http event i/o -->
<scxml xmlns="http://www.w3.org/2005/07/scxml" initial="s0" version="1.0" datamodel="lua">
<state id="s0">
<onentry>
- <send type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" event="event1" targetexpr="FIXME"/>
+ <send type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" event="event1" targetexpr="_ioprocessors.basichttp.location"/>
<send event="timeout"/>
</onentry>
<transition event="event1" target="pass"/>
diff --git a/test/w3c/lua/test496.scxml b/test/w3c/lua/test496.scxml
index ab5a2c0..855788b 100644
--- a/test/w3c/lua/test496.scxml
+++ b/test/w3c/lua/test496.scxml
@@ -2,7 +2,7 @@
<scxml xmlns="http://www.w3.org/2005/07/scxml" initial="s0" version="1.0" datamodel="lua">
<state id="s0">
<onentry>
- <send type="http://www.w3.org/TR/scxml/#SCXMLEventProcessor" event="event" target="FIXME"/>
+ <send type="http://www.w3.org/TR/scxml/#SCXMLEventProcessor" event="event" target="#_scxml_foo"/>
<raise event="foo"/>
</onentry>
<transition event="error.communication" target="pass"/>
diff --git a/test/w3c/lua/test500.scxml b/test/w3c/lua/test500.scxml
index 527d36d..5139001 100644
--- a/test/w3c/lua/test500.scxml
+++ b/test/w3c/lua/test500.scxml
@@ -2,7 +2,7 @@
<!-- test that location field is found inside entry for SCXML Event I/O processor -->
<scxml xmlns="http://www.w3.org/2005/07/scxml" initial="s0" version="1.0" datamodel="lua">
<datamodel>
- <data expr="FIXME" id="testvar1"/>
+ <data expr="_ioprocessors['http://www.w3.org/TR/scxml/#SCXMLEventProcessor'].location" id="testvar1"/>
</datamodel>
<state id="s0">
<transition cond="testvar1 ~= nil" target="pass"/>
diff --git a/test/w3c/lua/test501.scxml b/test/w3c/lua/test501.scxml
index d54f700..e83faca 100644
--- a/test/w3c/lua/test501.scxml
+++ b/test/w3c/lua/test501.scxml
@@ -2,7 +2,7 @@
<!-- test that the location entry for the SCXML Event I/O processor can be used as the target for an event -->
<scxml xmlns="http://www.w3.org/2005/07/scxml" initial="s0" version="1.0" datamodel="lua">
<datamodel>
- <data expr="FIXME" id="testvar1"/>
+ <data expr="_ioprocessors['http://www.w3.org/TR/scxml/#SCXMLEventProcessor'].location" id="testvar1"/>
</datamodel>
<state id="s0">
<onentry>
diff --git a/test/w3c/lua/test509.scxml b/test/w3c/lua/test509.scxml
index 8dd27c5..f2cce85 100644
--- a/test/w3c/lua/test509.scxml
+++ b/test/w3c/lua/test509.scxml
@@ -5,10 +5,10 @@ at the accessURI -->
<state id="s0">
<onentry>
<send event="timeout" delay="30s"/>
- <send event="test" type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="FIXME"/>
+ <send event="test" type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="_ioprocessors.basichttp.location"/>
</onentry>
<!-- if the event was send by http and we get it, we succeed -->
- <transition event="test" cond="_event.httpmethod=='POST'" target="pass"/>
+ <transition event="test" cond="_event.name=='http.post'" target="pass"/>
<transition event="*" target="fail"/>
</state>
<final id="pass"/>
diff --git a/test/w3c/lua/test510.scxml b/test/w3c/lua/test510.scxml
index 2ccd802..f00b8a4 100644
--- a/test/w3c/lua/test510.scxml
+++ b/test/w3c/lua/test510.scxml
@@ -4,7 +4,7 @@
<state id="s0">
<onentry>
<send event="timeout" delay="30s"/>
- <send event="test" type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="FIXME"/>
+ <send event="test" type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="_ioprocessors.basichttp.location"/>
<!-- this creates an internal event -->
<raise event="internal"/>
</onentry>
diff --git a/test/w3c/lua/test518.scxml b/test/w3c/lua/test518.scxml
index 35b0db6..14576ed 100644
--- a/test/w3c/lua/test518.scxml
+++ b/test/w3c/lua/test518.scxml
@@ -7,7 +7,7 @@
<state id="s0">
<onentry>
<send event="timeout" delay="30s"/>
- <send event="test" type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" namelist="testvar1" targetexpr="FIXME"/>
+ <send event="test" type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" namelist="testvar1" targetexpr="_ioprocessors.basichttp.location"/>
</onentry>
<transition event="test" cond="_event.data.testvar1==2" target="pass"/>
<transition event="*" target="fail"/>
diff --git a/test/w3c/lua/test519.scxml b/test/w3c/lua/test519.scxml
index 0287f8a..1f4c71a 100644
--- a/test/w3c/lua/test519.scxml
+++ b/test/w3c/lua/test519.scxml
@@ -4,7 +4,7 @@
<state id="s0">
<onentry>
<send event="timeout" delay="30s"/>
- <send event="test" type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="FIXME">
+ <send event="test" type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="_ioprocessors.basichttp.location">
<param name="param1" expr="1"/>
</send>
</onentry>
diff --git a/test/w3c/lua/test520.scxml b/test/w3c/lua/test520.scxml
index 2e2e356..6e8cf7c 100644
--- a/test/w3c/lua/test520.scxml
+++ b/test/w3c/lua/test520.scxml
@@ -4,14 +4,14 @@
<state id="s0">
<onentry>
<send event="timeout" delay="30s"/>
- <send type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="FIXME">
+ <send type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="_ioprocessors.basichttp.location">
<content>this is some content</content>
</send>
</onentry>
<!-- if other end sends us back this event, we succeed. Test for two common
ways of encoding -->
- <transition event="HTTP.POST" cond="_event.httpresponse=='this+is+some+content'" target="pass"/>
- <transition event="HTTP.POST" cond="_event.httpresponse=='this%20is%20some%20content'" target="pass"/>
+ <transition event="HTTP.POST" cond="_event.raw=='this+is+some+content'" target="pass"/>
+ <transition event="HTTP.POST" cond="_event.raw=='this%20is%20some%20content'" target="pass"/>
<transition event="*" target="fail"/>
</state>
<final id="pass"/>
diff --git a/test/w3c/lua/test521.scxml b/test/w3c/lua/test521.scxml
index 5c79990..db23444 100644
--- a/test/w3c/lua/test521.scxml
+++ b/test/w3c/lua/test521.scxml
@@ -6,7 +6,7 @@ the error event, we succeed. Otherwise we eventually timeout and fail. -->
<state id="s0">
<onentry>
<!-- should cause an error -->
- <send event="event2" target="FIXME"/>
+ <send event="event2" targetexpr="#_scxml_foo"/>
<!-- this will get added to the external event queue after the error has been raised -->
<send event="timeout"/>
</onentry>
diff --git a/test/w3c/lua/test522.scxml b/test/w3c/lua/test522.scxml
index 18db5f0..152c945 100644
--- a/test/w3c/lua/test522.scxml
+++ b/test/w3c/lua/test522.scxml
@@ -5,7 +5,7 @@ to send a message to the processor -->
<state id="s0">
<onentry>
<send event="timeout" delay="30s"/>
- <send event="test" type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="FIXME"/>
+ <send event="test" type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="_ioprocessors.basichttp.location"/>
</onentry>
<!-- the event we receive should be called 'test', but that's not actually
required for this test. Only that the send deliver some event to us. So if
diff --git a/test/w3c/lua/test531.scxml b/test/w3c/lua/test531.scxml
index 36d8301..c2a98ff 100644
--- a/test/w3c/lua/test531.scxml
+++ b/test/w3c/lua/test531.scxml
@@ -5,7 +5,7 @@ of the raised event. -->
<state id="s0">
<onentry>
<send event="timeout" delay="3s"/>
- <send type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="FIXME">
+ <send type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="_ioprocessors.basichttp.location">
<param name="_scxmleventname" expr="'test'"/>
</send>
</onentry>
diff --git a/test/w3c/lua/test532.scxml b/test/w3c/lua/test532.scxml
index e9514a4..ca83985 100644
--- a/test/w3c/lua/test532.scxml
+++ b/test/w3c/lua/test532.scxml
@@ -5,7 +5,7 @@ as the name of the resulting event. -->
<state id="s0">
<onentry>
<send event="timeout" delay="3s"/>
- <send type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="FIXME">
+ <send type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="_ioprocessors.basichttp.location">
<!-- this content will be ignored, but it's here to make sure we have a message body -->
<content>some content</content>
</send>
diff --git a/test/w3c/lua/test534.scxml b/test/w3c/lua/test534.scxml
index c206bc0..42f5f2f 100644
--- a/test/w3c/lua/test534.scxml
+++ b/test/w3c/lua/test534.scxml
@@ -4,7 +4,7 @@
<state id="s0">
<onentry>
<send event="timeout" delay="30s"/>
- <send event="test" type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="FIXME">
+ <send event="test" type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="_ioprocessors.basichttp.location">
</send>
</onentry>
<!-- if other end sends us back this event, we succeed -->
diff --git a/test/w3c/lua/test553.scxml b/test/w3c/lua/test553.scxml
index cf926e7..5175945 100644
--- a/test/w3c/lua/test553.scxml
+++ b/test/w3c/lua/test553.scxml
@@ -7,7 +7,7 @@ of <send>'s args causes an error.. -->
<!-- timeout event -->
<send event="timeout" delay="100ms"/>
<!-- generate an invalid namelist -->
- <send event="event1" namelist=""/>
+ <send event="event1" namelist="!no"/>
</onentry>
<!-- if we get the timeout before event1, we assume that event1 hasn't been sent
We ignore the error event here because this assertion doesn't mention it -->
diff --git a/test/w3c/lua/test554.scxml b/test/w3c/lua/test554.scxml
index 5c46992..ed8b3b2 100644
--- a/test/w3c/lua/test554.scxml
+++ b/test/w3c/lua/test554.scxml
@@ -8,7 +8,7 @@ before the timer goes off. -->
<send event="timer" delay="100ms"/>
</onentry>
<!-- reference an invalid namelist -->
- <invoke type="http://www.w3.org/TR/scxml/" namelist="">
+ <invoke type="http://www.w3.org/TR/scxml/" namelist="!no">
<content>
<scxml initial="subFinal" version="1.0" datamodel="lua">
<final id="subFinal"/>
diff --git a/test/w3c/lua/test567.scxml b/test/w3c/lua/test567.scxml
index 0e9b4ca..509cf69 100644
--- a/test/w3c/lua/test567.scxml
+++ b/test/w3c/lua/test567.scxml
@@ -10,7 +10,7 @@ _event.data. -->
<send event="timeout" delay="3s"/>
<!-- in this case, 'test' will be placed in _scxmleventname. The <param> should
be used to populate _event.data -->
- <send event="test" type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="FIXME">
+ <send event="test" type="http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor" targetexpr="_ioprocessors.basichttp.location">
<param name="param1" expr="2"/>
</send>
</onentry>