diff options
author | Stefan Radomski <github@mintwerk.de> | 2017-05-14 10:13:53 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-05-14 10:13:53 (GMT) |
commit | 1c4f3c8ccf362429ad6c80a9291fc7534e0691ab (patch) | |
tree | 693d22f22ffb75eaa144500fc6db146a3e5c2d42 | |
parent | 43370419fb7a9f14d85f96f39ffff86a337756d4 (diff) | |
parent | 673701710475dd1b9b4d06b8d5db99fa656306e8 (diff) | |
download | uscxml-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.cpp | 44 | ||||
-rw-r--r-- | src/uscxml/interpreter/ContentExecutorImpl.h | 1 | ||||
-rw-r--r-- | src/uscxml/interpreter/InterpreterImpl.h | 4 | ||||
-rw-r--r-- | src/uscxml/messages/Event.h | 8 | ||||
-rw-r--r-- | src/uscxml/plugins/DataModel.cpp | 4 | ||||
-rw-r--r-- | src/uscxml/plugins/DataModel.h | 2 | ||||
-rw-r--r-- | src/uscxml/plugins/DataModelImpl.h | 6 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp | 128 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/lua/LuaDataModel.h | 1 | ||||
-rw-r--r-- | src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h | 1 | ||||
-rw-r--r-- | test/issues/test-issue116.scxml | 43 | ||||
-rw-r--r-- | test/w3c/lua/test562.scxml | 25 |
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("Hello from function") +end + </data> + <data id="varFunc2">function() + return 2 +end + </data> + <data expr="nil" id="varFunc3"/> + </datamodel> + <final id="Pass"> + <onentry> + <log expr=""Pass"" label="Outcome"/> + </onentry> + </final> + <final id="Fail"> + <onentry> + <log expr=""Fail"" 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("this is from Script!") + +print(string.format("varFunc3()==%d",varFunc3())) +print(string.format("varFunc2()==%d",varFunc2())) + +varFunc1() + +print(string.format("varFunc4()==%d",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 |