summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Radomski <github@mintwerk.de>2017-05-14 10:13:53 (GMT)
committerGitHub <noreply@github.com>2017-05-14 10:13:53 (GMT)
commit1c4f3c8ccf362429ad6c80a9291fc7534e0691ab (patch)
tree693d22f22ffb75eaa144500fc6db146a3e5c2d42
parent43370419fb7a9f14d85f96f39ffff86a337756d4 (diff)
parent673701710475dd1b9b4d06b8d5db99fa656306e8 (diff)
downloaduscxml-1c4f3c8ccf362429ad6c80a9291fc7534e0691ab.zip
uscxml-1c4f3c8ccf362429ad6c80a9291fc7534e0691ab.tar.gz
uscxml-1c4f3c8ccf362429ad6c80a9291fc7534e0691ab.tar.bz2
Merge pull request #129 from alexzhornyak/Explicit-Eval
Implementation of eval function
-rw-r--r--src/uscxml/interpreter/BasicContentExecutor.cpp44
-rw-r--r--src/uscxml/interpreter/ContentExecutorImpl.h1
-rw-r--r--src/uscxml/interpreter/InterpreterImpl.h4
-rw-r--r--src/uscxml/messages/Event.h8
-rw-r--r--src/uscxml/plugins/DataModel.cpp4
-rw-r--r--src/uscxml/plugins/DataModel.h2
-rw-r--r--src/uscxml/plugins/DataModelImpl.h6
-rw-r--r--src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp128
-rw-r--r--src/uscxml/plugins/datamodel/lua/LuaDataModel.h1
-rw-r--r--src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h1
-rw-r--r--test/issues/test-issue116.scxml43
-rw-r--r--test/w3c/lua/test562.scxml25
12 files changed, 140 insertions, 127 deletions
diff --git a/src/uscxml/interpreter/BasicContentExecutor.cpp b/src/uscxml/interpreter/BasicContentExecutor.cpp
index 7ffda91..61277bd 100644
--- a/src/uscxml/interpreter/BasicContentExecutor.cpp
+++ b/src/uscxml/interpreter/BasicContentExecutor.cpp
@@ -67,7 +67,7 @@ void BasicContentExecutor::processSend(XERCESC_NS::DOMElement* element) {
sendEvent.name = ATTR(element, kXMLCharEvent);
}
} catch (Event e) {
- ERROR_EXECUTION_THROW2("Syntax error in send element eventexpr", element);
+ ERROR_EXECUTION_THROW3(e,"Syntax error in send element eventexpr", element);
}
try {
@@ -78,7 +78,7 @@ void BasicContentExecutor::processSend(XERCESC_NS::DOMElement* element) {
target = ATTR(element, kXMLCharTarget);
}
} catch (Event e) {
- ERROR_EXECUTION_THROW2("Syntax error in send element targetexpr", element);
+ ERROR_EXECUTION_THROW3(e,"Syntax error in send element targetexpr", element);
}
try {
@@ -89,7 +89,7 @@ void BasicContentExecutor::processSend(XERCESC_NS::DOMElement* element) {
type = ATTR(element, kXMLCharType);
}
} catch (Event e) {
- ERROR_EXECUTION_THROW2("Syntax error in send element typeexpr", element);
+ ERROR_EXECUTION_THROW3(e,"Syntax error in send element typeexpr", element);
}
try {
@@ -124,7 +124,7 @@ void BasicContentExecutor::processSend(XERCESC_NS::DOMElement* element) {
}
}
} catch (Event e) {
- ERROR_EXECUTION_THROW2("Syntax error in send element idlocation", element);
+ ERROR_EXECUTION_THROW3(e,"Syntax error in send element idlocation", element);
}
try {
@@ -148,14 +148,14 @@ void BasicContentExecutor::processSend(XERCESC_NS::DOMElement* element) {
}
}
} catch (Event e) {
- ERROR_EXECUTION_THROW2("Syntax error in send element delayexpr", element);
+ ERROR_EXECUTION_THROW3(e,"Syntax error in send element delayexpr", element);
}
try {
// namelist
processNameLists(sendEvent.namelist, element);
} catch (Event e) {
- ERROR_EXECUTION_THROW2("Syntax error in send element namelist", element);
+ ERROR_EXECUTION_THROW3(e,"Syntax error in send element namelist", element);
}
@@ -163,7 +163,7 @@ void BasicContentExecutor::processSend(XERCESC_NS::DOMElement* element) {
// params
processParams(sendEvent.params, element);
} catch (Event e) {
- ERROR_EXECUTION_THROW2("Syntax error in send element param expr", element);
+ ERROR_EXECUTION_THROW3(e,"Syntax error in send element param expr", element);
}
try {
@@ -173,7 +173,7 @@ void BasicContentExecutor::processSend(XERCESC_NS::DOMElement* element) {
sendEvent.data = elementAsData(contents.front());
}
} catch (Event e) {
- ERROR_EXECUTION_THROW2("Syntax error in send element content", element);
+ ERROR_EXECUTION_THROW3(e,"Syntax error in send element content", element);
}
// if (sendReq->dom) {
@@ -291,7 +291,7 @@ void BasicContentExecutor::processLog(XERCESC_NS::DOMElement* content) {
void BasicContentExecutor::processScript(XERCESC_NS::DOMElement* content) {
// download as necessary
std::string scriptContent(X(content->getTextContent()));
- _callbacks->evalAsData(scriptContent);
+ _callbacks->eval(scriptContent);
}
@@ -431,14 +431,14 @@ void BasicContentExecutor::invoke(XERCESC_NS::DOMElement* element) {
element->setUserData(kXMLCharInvokeId, (void*)invokeId, NULL);
} catch (Event e) {
- ERROR_EXECUTION_THROW2("Syntax error in invoke element idlocation", element);
+ ERROR_EXECUTION_THROW3(e,"Syntax error in invoke element idlocation", element);
}
try {
// namelist
processNameLists(invokeEvent.namelist, element);
} catch (Event e) {
- ERROR_EXECUTION_THROW2("Syntax error in send element namelist", element);
+ ERROR_EXECUTION_THROW3(e,"Syntax error in send element namelist", element);
}
@@ -446,7 +446,7 @@ void BasicContentExecutor::invoke(XERCESC_NS::DOMElement* element) {
// params
processParams(invokeEvent.params, element);
} catch (Event e) {
- ERROR_EXECUTION_THROW2("Syntax error in send element param expr", element);
+ ERROR_EXECUTION_THROW3(e,"Syntax error in send element param expr", element);
}
try {
@@ -467,7 +467,7 @@ void BasicContentExecutor::invoke(XERCESC_NS::DOMElement* element) {
#endif
}
} catch (Event e) {
- ERROR_EXECUTION_THROW2("Syntax error in invoke element content", element);
+ ERROR_EXECUTION_THROW3(e,"Syntax error in invoke element content", element);
}
// autoforward
@@ -513,7 +513,7 @@ void BasicContentExecutor::raiseDoneEvent(XERCESC_NS::DOMElement* state, XERCESC
// namelist
processNameLists(doneEvent.namelist, doneData);
} catch (Event e) {
- ERROR_EXECUTION_THROW2("Syntax error in donedata element namelist", doneData);
+ ERROR_EXECUTION_THROW3(e,"Syntax error in donedata element namelist", doneData);
}
@@ -521,7 +521,7 @@ void BasicContentExecutor::raiseDoneEvent(XERCESC_NS::DOMElement* state, XERCESC
// params
processParams(doneEvent.params, doneData);
} catch (Event e) {
- ERROR_EXECUTION_THROW2("Syntax error in donedata element param expr", doneData);
+ ERROR_EXECUTION_THROW3(e,"Syntax error in donedata element param expr", doneData);
}
try {
@@ -531,7 +531,7 @@ void BasicContentExecutor::raiseDoneEvent(XERCESC_NS::DOMElement* state, XERCESC
doneEvent.data = elementAsData(contents.front());
}
} catch (Event e) {
- ERROR_EXECUTION_THROW2("Syntax error in donedata element content", doneData);
+ ERROR_EXECUTION_THROW3(e,"Syntax error in donedata element content", doneData);
}
} catch (ErrorEvent exc) {
@@ -691,9 +691,19 @@ Data BasicContentExecutor::elementAsData(XERCESC_NS::DOMElement* element, bool a
contentSS << X((*textIter)->getNodeValue());
}
+ // this must be handled in getAsData
// test294, test562
if (LOCALNAME(element) == "content") {
- return Data(spaceNormalize(contentSS.str()), Data::VERBATIM);
+ // need first try getAsData because how to pass 179 ?
+ try {
+ // test153, we need to throw for test150 in promela
+ Data d = _callbacks->getAsData(contentSS.str());
+ if (!d.empty())
+ return d;
+ }
+ catch (ErrorEvent &) {
+ return Data(spaceNormalize(contentSS.str()), Data::VERBATIM);
+ }
}
if (asExpression) // not actually used, but likely expected
diff --git a/src/uscxml/interpreter/ContentExecutorImpl.h b/src/uscxml/interpreter/ContentExecutorImpl.h
index 5f0acfe..82acc1c 100644
--- a/src/uscxml/interpreter/ContentExecutorImpl.h
+++ b/src/uscxml/interpreter/ContentExecutorImpl.h
@@ -59,6 +59,7 @@ public:
uint32_t iteration) = 0;
virtual Data evalAsData(const std::string& expr) = 0;
+ virtual void eval(const std::string& expr) { evalAsData(expr); }
virtual Data getAsData(const std::string& expr) = 0;
virtual void assign(const std::string& location, const Data& data, const std::map<std::string, std::string>& attrs) = 0;
diff --git a/src/uscxml/interpreter/InterpreterImpl.h b/src/uscxml/interpreter/InterpreterImpl.h
index a68298b..fd6d393 100644
--- a/src/uscxml/interpreter/InterpreterImpl.h
+++ b/src/uscxml/interpreter/InterpreterImpl.h
@@ -187,6 +187,10 @@ public:
return _dataModel.evalAsData(expr);
}
+ virtual void eval(const std::string& content) {
+ _dataModel.eval(content);
+ }
+
virtual Data getAsData(const std::string& expr) {
return _dataModel.getAsData(expr);
}
diff --git a/src/uscxml/messages/Event.h b/src/uscxml/messages/Event.h
index b774f8a..fd9dd42 100644
--- a/src/uscxml/messages/Event.h
+++ b/src/uscxml/messages/Event.h
@@ -77,6 +77,14 @@
throw exc;\
}
+#define ERROR_EXECUTION_THROW3(evt,caption,node) \
+{\
+ auto it = evt.data.compound.find("cause"); \
+ ERROR_EXECUTION2(exc,it!=evt.data.compound.end() ? it->second.atom : "",node); \
+ exc.data.compound["caption"] = uscxml::Data(caption, uscxml::Data::VERBATIM); \
+ throw exc;\
+}
+
#define ERROR_COMMUNICATION_THROW(cause) \
{\
ERROR_COMMUNICATION(exc, cause); \
diff --git a/src/uscxml/plugins/DataModel.cpp b/src/uscxml/plugins/DataModel.cpp
index 07fd4b4..cf4dda2 100644
--- a/src/uscxml/plugins/DataModel.cpp
+++ b/src/uscxml/plugins/DataModel.cpp
@@ -42,6 +42,10 @@ Data DataModel::evalAsData(const std::string& content) {
return _impl->evalAsData(content);
}
+void DataModel::eval(const std::string& content) {
+ _impl->eval(content);
+}
+
bool DataModel::evalAsBool(const std::string& expr) {
return _impl->evalAsBool(expr);
}
diff --git a/src/uscxml/plugins/DataModel.h b/src/uscxml/plugins/DataModel.h
index 9185cc8..484f1cc 100644
--- a/src/uscxml/plugins/DataModel.h
+++ b/src/uscxml/plugins/DataModel.h
@@ -54,6 +54,8 @@ public:
virtual Data getAsData(const std::string& content);
/// @copydoc DataModelImpl::evalAsData()
virtual Data evalAsData(const std::string& content);
+ /// @copydoc DataModelImpl::eval()
+ virtual void eval(const std::string& content);
/// @copydoc DataModelImpl::evalAsBool()
virtual bool evalAsBool(const std::string& expr);
diff --git a/src/uscxml/plugins/DataModelImpl.h b/src/uscxml/plugins/DataModelImpl.h
index a804ea3..62453a8 100644
--- a/src/uscxml/plugins/DataModelImpl.h
+++ b/src/uscxml/plugins/DataModelImpl.h
@@ -173,6 +173,12 @@ public:
virtual Data evalAsData(const std::string& content) = 0;
/**
+ * evaluating script content without return
+ * @param mostly used in script content.
+ */
+ virtual void eval(const std::string& content) { evalAsData(content); }
+
+ /**
* Evaluate a given expression as a boolean.
* This function is a subset of evalAsData() but saves on creating and copying a Data object.
* @param expr An expression in the data-model's language.
diff --git a/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp b/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp
index 94d2467..8f50729 100644
--- a/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp
+++ b/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp
@@ -79,9 +79,12 @@ static int luaEval(lua_State* luaState, const std::string& expr) {
static Data getLuaAsData(lua_State* _luaState, const luabridge::LuaRef& lua) {
Data data;
if (lua.isFunction()) {
- // TODO: this might lead to a stack-overflow
- luabridge::LuaRef luaEvald = lua();
- return getLuaAsData(_luaState, luaEvald);
+ // we are creating __tmpFunc
+ // then it will be assigned to data variable
+ luabridge::setGlobal(_luaState, lua, "__tmpFunc");
+
+ data.atom = "__tmpFunc";
+ data.type = Data::INTERPRETED;
} else if(lua.isLightUserdata() || lua.isUserdata()) {
// not sure what to do
} else if(lua.isThread()) {
@@ -353,49 +356,23 @@ void LuaDataModel::setEvent(const Event& event) {
Data LuaDataModel::evalAsData(const std::string& content) {
Data data;
- ErrorEvent originalError;
std::string trimmedExpr = boost::trim_copy(content);
- try {
- int retVals = luaEval(_luaState, "return(" + trimmedExpr + ")");
- if (retVals == 1) {
- data = getLuaAsData(_luaState, luabridge::LuaRef::fromStack(_luaState, -1));
- }
- lua_pop(_luaState, retVals);
- return data;
- } catch (ErrorEvent e) {
- originalError = e;
- }
-
- int retVals = 0;
- try {
- // evaluate again without the return()
- retVals = luaEval(_luaState, trimmedExpr);
- } catch (ErrorEvent e) {
- throw originalError; // we will assume syntax error and throw
- }
-
-#if 1
- // Note: Empty result is not an error test302, but how to do test488?
- if (retVals == 0 && !isValidSyntax(trimmedExpr)) {
- throw originalError; // we will assume syntax error and throw
+ int retVals = luaEval(_luaState, "return(" + trimmedExpr + ")");
+ if (retVals == 1) {
+ data = getLuaAsData(_luaState, luabridge::LuaRef::fromStack(_luaState, -1));
}
-#endif
-
- try {
- if (retVals == 1) {
- data = getLuaAsData(_luaState, luabridge::LuaRef::fromStack(_luaState, -1));
- }
- lua_pop(_luaState, retVals);
- return data;
+ lua_pop(_luaState, retVals);
+ return data;
+}
- } catch (ErrorEvent e) {
- throw e; // we will assume syntax error and throw
- }
+void LuaDataModel::eval(const std::string& content) {
+ std::string trimmedExpr = boost::trim_copy(content);
+ int retVals = luaEval(_luaState, trimmedExpr);
- return data;
+ lua_pop(_luaState, retVals);
}
bool LuaDataModel::isValidSyntax(const std::string& expr) {
@@ -508,81 +485,12 @@ void LuaDataModel::assign(const std::string& location, const Data& data, const s
// JSObjectSetProperty(_ctx, JSContextGetGlobalObject(_ctx), JSStringCreateWithUTF8CString(location.c_str()), getNodeAsValue(data.node), 0, &exception);
} else {
- // trigger error.execution for undefined locations, test286 test311
- int retVals = luaEval(_luaState, location + " = " + location);
- lua_pop(_luaState, retVals);
-
- std::list<std::pair<std::string, bool> > idPath;
- size_t start = 0;
- for (size_t i = 0; i < location.size(); i++) {
- if (location[i] == '.' || location[i] == '[') {
- idPath.push_back(std::make_pair(location.substr(start, i - start), false));
- start = i + 1;
- } else if (location[i] == ']') {
- idPath.push_back(std::make_pair(location.substr(start, i - start), true));
- start = i + 1;
- }
- }
- if (start < location.size())
- idPath.push_back(std::make_pair(location.substr(start, location.size() - start), false));
-
- if (idPath.size() == 0)
- return;
luabridge::LuaRef lua = getDataAsLua(_luaState, data);
- if (idPath.size() == 1) {
- // trivial case where we reference a simple toplevel identifier
- luabridge::setGlobal(_luaState, lua, location.c_str());
-
- } else {
- auto globalId = idPath.front();
- idPath.pop_front();
-
- auto field = idPath.back();
- idPath.pop_back();
-
- luabridge::LuaRef topValue = luabridge::getGlobal(_luaState, globalId.first.c_str());
- luabridge::LuaRef value = topValue;
-
- for (auto ident : idPath) {
- if (!value.isTable())
- value = luabridge::newTable(_luaState);
+ luabridge::setGlobal(_luaState, lua, "__tmpAssign");
+ eval(location + "= __tmpAssign");
- if (ident.second) {
- luabridge::LuaRef tmp = value[strTo<long>(ident.first)];
- } else {
- luabridge::LuaRef tmp = value[ident];
- value = tmp;
- }
- }
- if (field.second) {
- if (field.first.length() == 0) {
- ERROR_EXECUTION_THROW("Subscript operator is empty");
- }
-
- if (!isNumeric(field.first.c_str(), 10) && field.first[0] != '"' && field.first[0] != '\'') {
- // evaluate subscript as variable
- Data subscript = evalAsData(field.first);
- if (subscript.atom.length() > 0) {
- field.first = subscript.atom;
- } else {
- ERROR_EXECUTION_THROW("Evaluated subscript operator '" + subscript.asJSON() + "' is invalid");
- }
- }
-
- if (isNumeric(field.first.c_str(), 10)) {
- // numeric array subscript
- value[strTo<long>(field.first)] = lua;
- } else {
- // string array subscript
- value[field.first] = lua;
- }
- } else {
- value[field.first] = lua;
- }
-
- }
// std::cout << Data::toJSON(evalAsData(location)) << std::endl;
}
diff --git a/src/uscxml/plugins/datamodel/lua/LuaDataModel.h b/src/uscxml/plugins/datamodel/lua/LuaDataModel.h
index a43b959..93379fc 100644
--- a/src/uscxml/plugins/datamodel/lua/LuaDataModel.h
+++ b/src/uscxml/plugins/datamodel/lua/LuaDataModel.h
@@ -74,6 +74,7 @@ public:
virtual bool evalAsBool(const std::string& expr);
virtual Data evalAsData(const std::string& expr);
+ virtual void eval(const std::string& content);
virtual Data getAsData(const std::string& content);
virtual bool isDeclared(const std::string& expr);
diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h
index 61931c6..b030d8b 100644
--- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h
+++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h
@@ -23,6 +23,7 @@
#include "uscxml/config.h"
#include "uscxml/interpreter/InterpreterImpl.h"
#include "uscxml/interpreter/BasicEventQueue.h"
+#include "uscxml/interpreter/LoggingImpl.h"
#include "uscxml/plugins/InvokerImpl.h"
diff --git a/test/issues/test-issue116.scxml b/test/issues/test-issue116.scxml
new file mode 100644
index 0000000..ca1cc56
--- /dev/null
+++ b/test/issues/test-issue116.scxml
@@ -0,0 +1,43 @@
+<scxml datamodel="lua" initial="StateShape1" name="ScxmlShape1" version="1.0" xmlns="http://www.w3.org/2005/07/scxml">
+ <datamodel>
+ <data id="varFunc1">function()
+ print(&quot;Hello from function&quot;)
+end
+ </data>
+ <data id="varFunc2">function()
+ return 2
+end
+ </data>
+ <data expr="nil" id="varFunc3"/>
+ </datamodel>
+ <final id="Pass">
+ <onentry>
+ <log expr="&quot;Pass&quot;" label="Outcome"/>
+ </onentry>
+ </final>
+ <final id="Fail">
+ <onentry>
+ <log expr="&quot;Fail&quot;" label="Outcome"/>
+ </onentry>
+ </final>
+ <state id="StateShape1">
+ <onentry>
+ <assign expr="varFunc2" location="varFunc3"/>
+ <assign expr="function()
+ return 4
+end" location="varFunc4"/>
+ <log expr="''" label="Test"/>
+ <script>print(&quot;this is from Script!&quot;)
+
+print(string.format(&quot;varFunc3()==%d&quot;,varFunc3()))
+print(string.format(&quot;varFunc2()==%d&quot;,varFunc2()))
+
+varFunc1()
+
+print(string.format(&quot;varFunc4()==%d&quot;,varFunc4()))
+ </script>
+ </onentry>
+ <transition cond="varFunc4()==4 and varFunc3()==2" target="Pass"/>
+ <transition target="Fail"/>
+ </state>
+</scxml> \ No newline at end of file
diff --git a/test/w3c/lua/test562.scxml b/test/w3c/lua/test562.scxml
new file mode 100644
index 0000000..fc73973
--- /dev/null
+++ b/test/w3c/lua/test562.scxml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scxml datamodel="lua" initial="s0" name="ScxmlShape1" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance">
+ <state id="s0">
+ <onentry>
+ <send event="foo">
+ <content>
+this is a
+string
+ </content>
+ </send>
+ </onentry>
+ <transition cond="_event.data == 'this is a string'" event="foo" target="pass"/>
+ <transition event="*" target="fail"/>
+ </state>
+ <final id="pass">
+ <onentry>
+ <log expr="'pass'" label="Outcome"/>
+ </onentry>
+ </final>
+ <final id="fail">
+ <onentry>
+ <log expr="'fail'" label="Outcome"/>
+ </onentry>
+ </final>
+</scxml> \ No newline at end of file