diff options
author | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2015-04-02 11:44:48 (GMT) |
---|---|---|
committer | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2015-04-02 11:44:48 (GMT) |
commit | 81aa1c79dd158aa7bc76876552e4b1d05ecea656 (patch) | |
tree | 4b590410d4042c156cfd3d4e874f3a329390a72b /src/uscxml | |
parent | ff86d690dc02d7dd495000331d378e7d8eb688ac (diff) | |
download | uscxml-81aa1c79dd158aa7bc76876552e4b1d05ecea656.zip uscxml-81aa1c79dd158aa7bc76876552e4b1d05ecea656.tar.gz uscxml-81aa1c79dd158aa7bc76876552e4b1d05ecea656.tar.bz2 |
Reactivated PHP bindings and some work on PROMELA
Diffstat (limited to 'src/uscxml')
-rw-r--r-- | src/uscxml/DOMUtils.cpp | 6 | ||||
-rw-r--r-- | src/uscxml/DOMUtils.h | 1 | ||||
-rw-r--r-- | src/uscxml/Interpreter.cpp | 10 | ||||
-rw-r--r-- | src/uscxml/Interpreter.h | 4 | ||||
-rw-r--r-- | src/uscxml/messages/Data.h | 4 | ||||
-rw-r--r-- | src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp | 6 | ||||
-rw-r--r-- | src/uscxml/plugins/invoker/umundo/UmundoInvoker.h | 2 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToPromela.cpp | 816 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToPromela.h | 130 |
9 files changed, 437 insertions, 542 deletions
diff --git a/src/uscxml/DOMUtils.cpp b/src/uscxml/DOMUtils.cpp index 2d3c3ea..5d72d5f 100644 --- a/src/uscxml/DOMUtils.cpp +++ b/src/uscxml/DOMUtils.cpp @@ -122,6 +122,12 @@ std::list<Arabica::DOM::Node<std::string> > DOMUtils::getElementsByType(const Ar return result; } +NameSpacingParser NameSpacingParser::fromFile(const std::string& file) { + Arabica::SAX::InputSource<std::string> inputSource; + inputSource.setSystemId(file); + return fromInputSource(inputSource); +} + NameSpacingParser NameSpacingParser::fromXML(const std::string& xml) { std::stringstream* ss = new std::stringstream(); (*ss) << xml; diff --git a/src/uscxml/DOMUtils.h b/src/uscxml/DOMUtils.h index 2264e64..0691952 100644 --- a/src/uscxml/DOMUtils.h +++ b/src/uscxml/DOMUtils.h @@ -84,6 +84,7 @@ class USCXML_API NameSpacingParser : public Arabica::SAX2DOM::Parser<std::string public: NameSpacingParser(); NameSpacingParser(const NameSpacingParser& other) {} + static NameSpacingParser fromFile(const std::string& file); static NameSpacingParser fromXML(const std::string& xml); static NameSpacingParser fromInputSource(Arabica::SAX::InputSource<std::string>& source); diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index 060a397..1b2ca15 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -2260,7 +2260,7 @@ bool InterpreterImpl::nameMatch(const std::string& eventDescs, const std::string return true; // eventDesc has to be a real prefix of event now and therefore shorter - if (eventDesc.size() >= eventName.size()) + if (eventDesc.size() > eventName.size()) goto NEXT_DESC; // are they already equal? @@ -2910,17 +2910,19 @@ NodeSet<std::string> InterpreterImpl::getTargetStates(const Arabica::XPath::Node return targets; } -std::list<std::string> InterpreterImpl::tokenize(const std::string& line, const char sep) { +#define ISWHITESPACE(char) (isspace(char)) + +std::list<std::string> InterpreterImpl::tokenize(const std::string& line, const char sep, bool trimWhiteSpace) { std::list<std::string> tokens; // appr. 3x faster than stringstream size_t start = 0; for (int i = 0; i < line.size(); i++) { - if (line[i] == sep) { + if (line[i] == sep || (trimWhiteSpace && ISWHITESPACE(line[i]))) { if (i > 0 && start < i) { tokens.push_back(line.substr(start, i - start)); } - while(line[++i] == sep); // skip multiple occurences of seperator + while(line[i] == sep || (trimWhiteSpace && ISWHITESPACE(line[i]))) { i++; } // skip multiple occurences of seperator and whitespaces start = i; } else if (i + 1 == line.size()) { tokens.push_back(line.substr(start, i + 1 - start)); diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index 7019eb9..bef4c88 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -448,9 +448,9 @@ public: static Arabica::XPath::NodeSet<std::string> filterChildType(const Arabica::DOM::Node_base::Type type, const Arabica::XPath::NodeSet<std::string>& nodeSet, bool recurse = false); static std::list<std::string> tokenizeIdRefs(const std::string& idRefs) { - return tokenize(idRefs); + return tokenize(idRefs, ' ', true); } - static std::list<std::string> tokenize(const std::string& line, const char seperator = ' '); + static std::list<std::string> tokenize(const std::string& line, const char seperator = ' ', bool trimWhiteSpace = false); static std::string spaceNormalize(const std::string& text); static bool nameMatch(const std::string& eventDescs, const std::string& event); diff --git a/src/uscxml/messages/Data.h b/src/uscxml/messages/Data.h index 818b26e..f4d220f 100644 --- a/src/uscxml/messages/Data.h +++ b/src/uscxml/messages/Data.h @@ -132,8 +132,8 @@ public: } const Data item(const size_t index) const { - if (array.size() < index) { - std::list<Data>::const_iterator arrayIter; + if (array.size() > index) { + std::list<Data>::const_iterator arrayIter = array.begin(); for (int i = 0; i < index; i++, arrayIter++) {} return *arrayIter; } diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp index 5fd325d..0302d87 100644 --- a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp +++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp @@ -176,8 +176,8 @@ void UmundoInvoker::invoke(const InvokeRequest& req) { } _node = new umundo::Node(); - umundo::MDNSDiscoveryOptions discOpts; - _discovery = new umundo::Discovery(umundo::Discovery::MDNS, &discOpts); + umundo::DiscoveryConfigMDNS discOpts; + _discovery = new umundo::Discovery(&discOpts); _discovery->add(*_node); @@ -335,7 +335,7 @@ void UmundoInvoker::removed(umundo::ServiceDescription desc) { returnEvent(addedEvent); } -void UmundoInvoker::changed(umundo::ServiceDescription desc) { +void UmundoInvoker::changed(umundo::ServiceDescription desc, uint64_t what) { } bool UmundoInvoker::jsonbufToData(Data& data, const JSONProto& json) { diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h index 1c5c9a3..4c0e988 100644 --- a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h +++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.h @@ -60,7 +60,7 @@ public: virtual void added(umundo::ServiceDescription); virtual void removed(umundo::ServiceDescription); - virtual void changed(umundo::ServiceDescription); + virtual void changed(umundo::ServiceDescription, uint64_t what); virtual void welcome(umundo::TypedPublisher atPub, const umundo::SubscriberStub& sub); virtual void farewell(umundo::TypedPublisher fromPub, const umundo::SubscriberStub& sub); diff --git a/src/uscxml/transform/ChartToPromela.cpp b/src/uscxml/transform/ChartToPromela.cpp index b750409..59f1d75 100644 --- a/src/uscxml/transform/ChartToPromela.cpp +++ b/src/uscxml/transform/ChartToPromela.cpp @@ -130,200 +130,6 @@ void ChartToPromela::writeTo(std::ostream& stream) { writeProgram(stream); } -void PromelaEventSource::writeStart(std::ostream& stream, int indent) { - std::string padding; - for (int i = 0; i < indent; i++) { - padding += " "; - } - stream << padding << "run " << name << "EventSource() priority 10;" << std::endl; -} - -void PromelaEventSource::writeStop(std::ostream& stream, int indent) { - std::string padding; - for (int i = 0; i < indent; i++) { - padding += " "; - } - - stream << padding << name << "EventSourceDone = 1;" << std::endl; -} - -void PromelaEventSource::writeDeclarations(std::ostream& stream, int indent) { - std::string padding; - for (int i = 0; i < indent; i++) { - padding += " "; - } - stream << "bool " << name << "EventSourceDone = 0;" << std::endl; - -} - -void PromelaEventSource::writeBody(std::ostream& stream) { - - stream << "proctype " << name << "EventSource() {" << std::endl; - stream << " " << name << "EventSourceDone = 0;" << std::endl; - if (analyzer->usesComplexEventStruct()) { - stream << " _event_t tmpE;" << std::endl; - } - stream << " " << name << "NewEvent:" << std::endl; - stream << " " << "if" << std::endl; - stream << " " << ":: " << name << "EventSourceDone -> goto " << name << "Done;" << std::endl; - stream << " " << ":: " << "len(eQ) >= " << externalQueueLength - longestSequence << " -> skip;" << std::endl; - stream << " " << ":: else { " << std::endl; - - Trie& trie = analyzer->getTrie(); - if (source.type == PromelaInline::PROMELA_EVENT_SOURCE_CUSTOM) { - // custom event source - std::string content = source.content; - - boost::replace_all(content, "#REDO#", name + "NewEvent"); - boost::replace_all(content, "#DONE#", name + "Done"); - - std::list<TrieNode*> eventNames = trie.getChildsWithWords(trie.getNodeWithPrefix("")); - std::list<TrieNode*>::iterator eventNameIter = eventNames.begin(); - while(eventNameIter != eventNames.end()) { - boost::replace_all(content, "#" + (*eventNameIter)->value + "#", (*eventNameIter)->identifier); - eventNameIter++; - } - - stream << ChartToPromela::beautifyIndentation(content, 2) << std::endl; - } else { - // standard event source - stream << " " << " if" << std::endl; -// stream << " " << " :: 1 -> " << "goto " << sourceName << "NewEvent;" << std::endl; - - std::list<std::list<std::string> >::const_iterator seqIter = sequences.begin(); - while(seqIter != sequences.end()) { - stream << " " << ":: skip -> { "; - std::list<std::string>::const_iterator evIter = seqIter->begin(); - while(evIter != seqIter->end()) { - TrieNode* node = trie.getNodeWithPrefix(*evIter); - if (!node) { - std::cerr << "Event " << *evIter << " defined in event source but never used in transitions" << std::endl; - evIter++; - continue; - } - if (analyzer->usesComplexEventStruct()) { - stream << "tmpE.name = " << analyzer->macroForLiteral(node->value) << "; eQ!tmpE; "; - } else { - stream << "eQ!" << analyzer->macroForLiteral(node->value) << "; "; - } - evIter++; - } - stream << "goto " << name << "NewEvent;"; - stream << " }" << std::endl; - seqIter++; - } - - stream << " " << " fi;" << std::endl; - } - - stream << " " << "}" << std::endl; - stream << " " << "fi;" << std::endl; - stream << name << "Done:" << " skip;" << std::endl; - stream << "}" << std::endl; - - -// std::list<PromelaInline>::iterator sourceIter = eventSources.inlines.begin(); -// int i = 0; -// while(sourceIter != eventSources.inlines.end()) { -// if (sourceIter->type != PromelaInline::PROMELA_EVENT_SOURCE_CUSTOM && sourceIter->type != PromelaInline::PROMELA_EVENT_SOURCE) { -// sourceIter++; -// continue; -// } -// -// std::string sourceName = name + "_"+ toStr(i); -// -// stream << "proctype " << sourceName << "EventSource() {" << std::endl; -// stream << " " << sourceName << "EventSourceDone = 0;" << std::endl; -// stream << " " << sourceName << "NewEvent:" << std::endl; -// stream << " " << "if" << std::endl; -// stream << " " << ":: " << sourceName << "EventSourceDone -> skip;" << std::endl; -// stream << " " << ":: else { " << std::endl; -// -// Trie& trie = analyzer->getTrie(); -// -// if (sourceIter->type == PromelaInline::PROMELA_EVENT_SOURCE_CUSTOM) { -// std::string content = sourceIter->content; -// -// boost::replace_all(content, "#REDO#", sourceName + "NewEvent"); -// boost::replace_all(content, "#DONE#", sourceName + "Done"); -// -// std::list<TrieNode*> eventNames = trie.getChildsWithWords(trie.getNodeWithPrefix("")); -// std::list<TrieNode*>::iterator eventNameIter = eventNames.begin(); -// while(eventNameIter != eventNames.end()) { -// boost::replace_all(content, "#" + (*eventNameIter)->value + "#", (*eventNameIter)->identifier); -// eventNameIter++; -// } -// -// stream << ChartToPromela::beautifyIndentation(content, 2) << std::endl; -// -// } else { -// stream << " " << " if" << std::endl; -//// stream << " " << " :: 1 -> " << "goto " << sourceName << "NewEvent;" << std::endl; -// -// std::list<std::list<std::string> >::const_iterator seqIter = sourceIter->sequences.begin(); -// while(seqIter != sourceIter->sequences.end()) { -// stream << " " << ":: "; -// std::list<std::string>::const_iterator evIter = seqIter->begin(); -// while(evIter != seqIter->end()) { -// TrieNode* node = trie.getNodeWithPrefix(*evIter); -// stream << "eQ!" << node->identifier << "; "; -// evIter++; -// } -// stream << "goto " << sourceName << "NewEvent;" << std::endl; -// seqIter++; -// } -// -// stream << " " << " fi;" << std::endl; -// } -// -// stream << " " << "}" << std::endl; -// stream << " " << "fi;" << std::endl; -// stream << sourceName << "Done:" << " skip;" << std::endl; -// stream << "}" << std::endl; -// -// i++; -// sourceIter++; -// } -} - -PromelaEventSource::PromelaEventSource() { - type = PROMELA_EVENT_SOURCE_INVALID; - analyzer = NULL; -} - -PromelaEventSource::PromelaEventSource(const PromelaInline& source, PromelaCodeAnalyzer* analyzer, uint32_t eQueueLength) { - type = PROMELA_EVENT_SOURCE_INVALID; - this->analyzer = analyzer; - externalQueueLength = eQueueLength; - - this->source = source; - - if (source.type == PromelaInline::PROMELA_EVENT_SOURCE) { - std::stringstream ssLines(source.content); - std::string line; - while(std::getline(ssLines, line)) { - boost::trim(line); - if (line.length() == 0) - continue; - if (boost::starts_with(line, "//")) - continue; - - std::list<std::string> seq; - std::stringstream ssToken(line); - std::string token; - while(std::getline(ssToken, token, ' ')) { - if (token.length() == 0) - continue; - seq.push_back(token); - if (analyzer != NULL) - analyzer->addEvent(token); - } - sequences.push_back(seq); - if (seq.size() > longestSequence) - longestSequence = seq.size(); - } - } -} void PromelaCodeAnalyzer::addCode(const std::string& code, ChartToPromela* interpreter) { PromelaParser parser(code); @@ -570,7 +376,7 @@ std::string PromelaCodeAnalyzer::macroForLiteral(const std::string& literal) { throw std::runtime_error("Literal " + literal + " passed with quotes"); if (_strMacroNames.find(literal) == _strMacroNames.end()) - throw std::runtime_error("No macro for literal " + literal + " known"); + throw std::runtime_error("No macro for literal '" + literal + "' known"); return _strMacroNames[literal]; } @@ -1051,16 +857,6 @@ void ChartToPromela::writeTransition(std::ostream& stream, GlobalTransition* tra } // std::cout << "###" << std::endl; for (std::list<GlobalTransition::Action>::iterator actionIter = transition->actions.begin(); actionIter != transition->actions.end(); actionIter++) { -#if 0 - if (actionIter->onEntry) { - std::cout << "onEntry: " << actionIter->onEntry << std::endl; - } else if (actionIter->raiseDone) { - std::cout << "raiseDone: " << actionIter->raiseDone << std::endl; - } else { - std::cout << "#" << std::endl; - } - foo.insert(*actionIter); -#endif actionsInTransition[transition].insert(*actionIter); } // std::copy(transition->actions.begin(), transition->actions.end(), std::inserter(actionsInTransition[transition], actionsInTransition[transition].begin())); @@ -1163,6 +959,7 @@ void ChartToPromela::writeTransition(std::ostream& stream, GlobalTransition* tra isConditionalized = true; } +#if 0 switch (ecIter->type) { case ExecContentSeqItem::EXEC_CONTENT_ALL_BUT: std::cout << "ALL_BUT" << std::endl; @@ -1177,6 +974,7 @@ void ChartToPromela::writeTransition(std::ostream& stream, GlobalTransition* tra default: break; } +#endif if (action.exited) { // we left a state @@ -1226,86 +1024,31 @@ void ChartToPromela::writeTransition(std::ostream& stream, GlobalTransition* tra // an invoke element if (_machines.find(action.invoke) != _machines.end()) { -#if 1 stream << padding << _prefix << "start!" << _analyzer->macroForLiteral(_machines[action.invoke]->_invokerid) << ";" << std::endl; -#else - - // nested SCXML document - - // set from namelist - if (HAS_ATTR_CAST(action.invoke, "namelist")) { - std::list<std::string> namelist = tokenize(ATTR_CAST(action.invoke, "namelist")); - for (std::list<std::string>::iterator nlIter = namelist.begin(); nlIter != namelist.end(); nlIter++) { - if (_machines[action.invoke]->_dataModelVars.find(*nlIter) != _machines[action.invoke]->_dataModelVars.end()) { - stream << padding << _machines[action.invoke]->_prefix << *nlIter << " = " << _prefix << *nlIter << std::endl; - } - } - } - - // set from params - NodeSet<std::string> invokeParams = filterChildElements(_nsInfo.xmlNSPrefix + "param", action.invoke); - for (int i = 0; i < invokeParams.size(); i++) { - std::string identifier = ATTR_CAST(invokeParams[i], "name"); - std::string expression = ATTR_CAST(invokeParams[i], "expr"); - if (_machines[action.invoke]->_dataModelVars.find(identifier) != _machines[action.invoke]->_dataModelVars.end()) { - stream << padding << _machines[action.invoke]->_prefix << identifier << " = " << ADAPT_SRC(expression) << ";" << std::endl; - } - } - -// stream << padding << " /* assign local variables from invoke request */" << std::endl; -// -// if (_analyzer->usesComplexEventStruct() && _analyzer->usesEventField("data")) { -// for (std::set<std::string>::iterator dmIter = _dataModelVars.begin(); dmIter != _dataModelVars.end(); dmIter++) { -// if (_analyzer->usesEventDataField(*dmIter)) { -// stream << " if" << std::endl; -// stream << " :: " << _prefix << "_event.data." << *dmIter << " -> " << _prefix << *dmIter << " = " << "_event.data." << *dmIter << ";" << std::endl; -// stream << " :: else -> skip;" << std::endl; -// stream << " fi" << std::endl; -// } -// } -// } -// stream << std::endl; - - stream << padding << "run " << _machines[action.invoke]->_prefix << "run() priority 20;" << std::endl; - if (HAS_ATTR_CAST(action.invoke, "idlocation")) { - stream << padding << ADAPT_SRC(ATTR_CAST(action.invoke, "idlocation")) << " = " << _analyzer->macroForLiteral(_machines[_machinesPerId[ATTR_CAST(action.invoke, "id")]]->_invokerid) << ";" << std::endl; - } -#endif } else { - if (HAS_ATTR_CAST(action.invoke, "invokeid") && _invokers.find(ATTR_CAST(action.invoke, "invokeid")) != _invokers.end()) - _invokers[ATTR_CAST(action.invoke, "invokeid")].writeStart(stream, indent); + if (HAS_ATTR_CAST(action.invoke, "id")) { + stream << padding << _prefix << ATTR_CAST(action.invoke, "id") << "Running = true;" << std::endl; + } } } if (action.uninvoke) { - assert(_machines.find(action.uninvoke) != _machines.end()); - stream << padding << "do" << std::endl; - stream << padding << ":: " << _prefix << "start??" << _analyzer->macroForLiteral(_machines[action.uninvoke]->_invokerid) << " -> skip" << std::endl; - stream << padding << ":: else -> break;" << std::endl; - stream << padding << "od" << std::endl; - -// std::cout << action.uninvoke << std::endl; - // an invoke element to uninvoke if (_machines.find(action.uninvoke) != _machines.end()) { - // nested SCXML document - stream << padding << _machines[action.uninvoke]->_prefix << "canceled = true;" << std::endl; - if (_analyzer->usesEventField("delay")) - stream << padding << "removePendingEventsForInvoker(" << _analyzer->macroForLiteral(_machines[action.uninvoke]->_invokerid) << ");" << std::endl; -// writeRemovePendingEventsFromInvoker(stream, _machines[action.uninvoke], indent, false); -#if 0 stream << padding << "do" << std::endl; - if (_allowEventInterleaving) - stream << padding << ":: len(" << _machines[action.uninvoke]->_prefix << "tmpQ) > 0 -> " << _machines[action.uninvoke]->_prefix << "tmpQ?_;" << std::endl; - stream << padding << ":: len(" << _machines[action.uninvoke]->_prefix << "eQ) > 0 -> " << _machines[action.uninvoke]->_prefix << "eQ?_;" << std::endl; + stream << padding << ":: " << _prefix << "start??" << _analyzer->macroForLiteral(_machines[action.uninvoke]->_invokerid) << " -> skip" << std::endl; stream << padding << ":: else -> break;" << std::endl; stream << padding << "od" << std::endl; -#endif + + stream << padding << _machines[action.uninvoke]->_prefix << "canceled = true;" << std::endl; + if (_analyzer->usesEventField("delay")) { + stream << padding << "removePendingEventsForInvoker(" << _analyzer->macroForLiteral(_machines[action.uninvoke]->_invokerid) << ");" << std::endl; + } } else { - if (HAS_ATTR_CAST(action.uninvoke, "invokeid") && _invokers.find(ATTR_CAST(action.invoke, "invokeid")) != _invokers.end()) - stream << padding << ATTR_CAST(action.uninvoke, "invokeid") << "EventSourceDone" << "= 1;" << std::endl; + if (HAS_ATTR_CAST(action.uninvoke, "id")) { + stream << padding << _prefix << ATTR_CAST(action.uninvoke, "id") << "Running = false;" << std::endl; + } } -// continue; } if (isConditionalized) { @@ -1682,17 +1425,7 @@ void ChartToPromela::writeExecutableContent(std::ostream& stream, const Arabica: for (int i = 0; i < indent; i++) { padding += " "; } - - if (node.getNodeType() == Node_base::COMMENT_NODE) { - // we cannot have labels in an atomic block, just process inline promela - PromelaInlines promInls = PromelaInlines::fromNode(node); - // TODO! - // if (promInls) { - // stream << padding << "skip;" << std::endl; - // stream << beautifyIndentation(inlinePromela.str(), indent) << std::endl; - // } - } - + if (node.getNodeType() == Node_base::TEXT_NODE) { if (boost::trim_copy(node.getNodeValue()).length() > 0) stream << beautifyIndentation(ADAPT_SRC(node.getNodeValue()), indent) << std::endl; @@ -1894,94 +1627,168 @@ void ChartToPromela::writeExecutableContent(std::ostream& stream, const Arabica: } } - -PromelaInlines PromelaInlines::fromNodeSet(const NodeSet<std::string>& node, bool recurse) { - PromelaInlines allPromInls; - Arabica::XPath::NodeSet<std::string> comments = InterpreterImpl::filterChildType(Node_base::COMMENT_NODE, node, recurse); - for (int i = 0; i < comments.size(); i++) { - allPromInls.merge(PromelaInlines::fromNode(comments[i])); - } - return allPromInls; - +PromelaInlines::~PromelaInlines() { + return; } -PromelaInlines PromelaInlines::fromNode(const Arabica::DOM::Node<std::string>& node) { - if (node.getNodeType() != Node_base::COMMENT_NODE && node.getNodeType() != Node_base::TEXT_NODE) - return PromelaInlines(); - return PromelaInlines(node.getNodeValue(), node); -} +std::list<PromelaInline*> PromelaInlines::getRelatedTo(const Arabica::DOM::Node<std::string>& node, PromelaInline::PromelaInlineType type) { + std::list<PromelaInline*> related; + + std::map<Arabica::DOM::Node<std::string>, std::list<PromelaInline*> >::iterator inlIter = inlines.begin(); + while (inlIter != inlines.end()) { + std::list<PromelaInline*>::iterator pmlIter = inlIter->second.begin(); + while (pmlIter != inlIter->second.end()) { + if ((type != PromelaInline::PROMELA_NIL || (*pmlIter)->type == type) && (*pmlIter)->relatesTo(node)) { + related.push_back(*pmlIter); + } + pmlIter++; + } + inlIter++; + } + return related; - PromelaInlines PromelaInlines::fromString(const std::string& text) { - return PromelaInlines(text, Arabica::DOM::Node<std::string>()); + return related; } -PromelaInlines::PromelaInlines() : nrProgressLabels(0), nrAcceptLabels(0), nrEndLabels(0), nrEventSources(0), nrCodes(0) { +std::list<PromelaInline*> PromelaInlines::getAllOfType(uint32_t type) { + std::list<PromelaInline*> related; + + std::map<Arabica::DOM::Node<std::string>, std::list<PromelaInline*> >::iterator inlIter = inlines.begin(); + while (inlIter != inlines.end()) { + std::list<PromelaInline*>::iterator pmlIter = inlIter->second.begin(); + while (pmlIter != inlIter->second.end()) { + if ((*pmlIter)->type & type) { + related.push_back(*pmlIter); + } + pmlIter++; + } + inlIter++; + } + return related; } -PromelaInlines::PromelaInlines(const std::string& content, const Arabica::DOM::Node<std::string>& node) - : nrProgressLabels(0), nrAcceptLabels(0), nrEndLabels(0), nrEventSources(0), nrCodes(0) { +PromelaInline::PromelaInline(const Arabica::DOM::Node<std::string>& node) : prevSibling(NULL), nextSibling(NULL), type(PROMELA_NIL) { + if (node.getNodeType() != Node_base::COMMENT_NODE && node.getNodeType() != Node_base::TEXT_NODE) + return; // nothing to do - std::stringstream ssLine(content); + std::stringstream ssLine(node.getNodeValue()); std::string line; + + while(std::getline(ssLine, line)) { + // skip to first promela line + boost::trim(line); + if (boost::starts_with(line, "promela")) + break; + } - bool isInPromelaCode = false; - PromelaInline promInl; + if (!boost::starts_with(line, "promela")) + return; + if (false) { + } else if (boost::starts_with(line, "promela-code")) { + type = PROMELA_CODE; + } else if (boost::starts_with(line, "promela-ltl")) { + type = PROMELA_LTL; + } else if (boost::starts_with(line, "promela-event-all")) { + type = PROMELA_EVENT_ALL_BUT; + } else if (boost::starts_with(line, "promela-event")) { + type = PROMELA_EVENT_ONLY; + } else if (boost::starts_with(line, "promela-progress")) { + type = PROMELA_PROGRESS_LABEL; + } else if (boost::starts_with(line, "promela-accept")) { + type = PROMELA_ACCEPT_LABEL; + } else if (boost::starts_with(line, "promela-end")) { + type = PROMELA_END_LABEL; + } + + std::stringstream contentSS; + size_t endType = line.find_first_of(": \n"); + + std::string seperator; + if (endType != std::string::npos && endType + 1 < line.size()) { + contentSS << line.substr(endType + 1, line.size() - endType + 1); + seperator = "\n"; + } + while(std::getline(ssLine, line)) { - std::string trimLine = boost::trim_copy(line); - if (trimLine.length() == 0) - continue; - if (boost::starts_with(trimLine, "#promela")) { - if (isInPromelaCode) { - code.push_back(promInl); - isInPromelaCode = false; - } - promInl = PromelaInline(); - } - - if (false) { - } else if (boost::starts_with(trimLine, "#promela-progress")) { - nrProgressLabels++; - promInl.type = PromelaInline::PROMELA_PROGRESS_LABEL; - promInl.content = line; - code.push_back(promInl); - } else if (boost::starts_with(trimLine, "#promela-accept")) { - nrAcceptLabels++; - promInl.type = PromelaInline::PROMELA_ACCEPT_LABEL; - promInl.content = line; - code.push_back(promInl); - } else if (boost::starts_with(trimLine, "#promela-end")) { - nrEndLabels++; - promInl.type = PromelaInline::PROMELA_END_LABEL; - promInl.content = line; - code.push_back(promInl); - } else if (boost::starts_with(trimLine, "#promela-inline")) { - nrCodes++; - isInPromelaCode = true; - promInl.type = PromelaInline::PROMELA_CODE; - } else if (boost::starts_with(trimLine, "#promela-event-source-custom")) { - nrEventSources++; - isInPromelaCode = true; - promInl.type = PromelaInline::PROMELA_EVENT_SOURCE_CUSTOM; - } else if (boost::starts_with(trimLine, "#promela-event-source")) { - nrEventSources++; - isInPromelaCode = true; - promInl.type = PromelaInline::PROMELA_EVENT_SOURCE; - } else if (isInPromelaCode) { - promInl.content += line; - promInl.content += "\n"; - } - } - // inline code ends with comment - if (isInPromelaCode) { - code.push_back(promInl); + boost::trim(line); + if (boost::starts_with(line, "promela")) { + std::cerr << "Split multiple #promela pragmas into multiple comments!" << std::endl; + break; + } + contentSS << seperator << line; + seperator = "\n"; } + content = contentSS.str(); +} + + +PromelaInlines::PromelaInlines(const Arabica::DOM::Node<std::string>& node) { + NodeSet<std::string> levelNodes; + levelNodes.push_back(node); + + size_t level = 0; + while(levelNodes.size() > 0) { + PromelaInline* predecessor = NULL; + + // iterate all nodes at given level + for (int i = 0; i < levelNodes.size(); i++) { - // iterate inlinesFound and classify -// PromelaEventSource promES; // TODO! use this + // get all comments + NodeSet<std::string> comments = InterpreterImpl::filterChildType(Node_base::COMMENT_NODE, levelNodes[i]); + for (int j = 0; j < comments.size(); j++) { + PromelaInline* tmp = new PromelaInline(comments[j]); + if (tmp->type == PromelaInline::PROMELA_NIL) { + delete tmp; + continue; + } + if (predecessor != NULL) { + tmp->prevSibling = predecessor; + predecessor->nextSibling = tmp; + } + tmp->level = level; + tmp->container = Element<std::string>(levelNodes[i]); + predecessor = tmp; + inlines[levelNodes[i]].push_back(tmp); + allInlines.push_back(tmp); + } + } + + levelNodes = InterpreterImpl::filterChildType(Node_base::ELEMENT_NODE, levelNodes); + level++; + } } +void PromelaInline::dump() { +#if 0 + switch(type) { + case PROMELA_NIL: + std::cerr << "PROMELA_NIL" << std::endl; + break; + case PROMELA_CODE: + std::cerr << "PROMELA_CODE" << std::endl; + break; + case PROMELA_EVENT_SOURCE_ALL: + std::cerr << "PROMELA_EVENT_SOURCE" << std::endl; + break; + case PROMELA_INVOKER: + std::cerr << "PROMELA_INVOKER" << std::endl; + break; + case PROMELA_PROGRESS_LABEL: + std::cerr << "PROMELA_PROGRESS_LABEL" << std::endl; + break; + case PROMELA_ACCEPT_LABEL: + std::cerr << "PROMELA_ACCEPT_LABEL" << std::endl; + break; + case PROMELA_END_LABEL: + std::cerr << "PROMELA_END_LABEL" << std::endl; + break; + } +#endif +} + + void ChartToPromela::writeIfBlock(std::ostream& stream, const Arabica::XPath::NodeSet<std::string>& condChain, int indent) { if (condChain.size() == 0) return; @@ -2157,6 +1964,13 @@ void ChartToPromela::writeDeclarations(std::ostream& stream) { stream << "_x_t " << _prefix << "_x;" << std::endl; } + std::list<PromelaInline*> pmls = pmlInlines.getAllOfType(PromelaInline::PROMELA_EVENT_ALL_BUT | PromelaInline::PROMELA_EVENT_ONLY); + for (std::list<PromelaInline*>::iterator pmlIter = pmls.begin(); pmlIter != pmls.end(); pmlIter++) { + if ((*pmlIter)->container && LOCALNAME((*pmlIter)->container) == "invoke") { + stream << "bool " << _prefix << ATTR_CAST((*pmlIter)->container, "id") << "Running;" << std::endl; + } + } + stream << std::endl << std::endl; // get all data elements @@ -2206,41 +2020,6 @@ void ChartToPromela::writeDeclarations(std::ostream& stream) { std::string decl = type + " " + _prefix + identifier + arrSize; stream << decl << ";" << std::endl; -#if 0 - - NodeSet<std::string> dataText = filterChildType(Node_base::TEXT_NODE, data, true); - std::string value; - if (dataText.size() > 0) { - value = dataText[0].getNodeValue(); - boost::trim(value); - } - - if (identifier.length() > 0) { - - size_t bracketPos = type.find("["); - if (bracketPos != std::string::npos) { - arrSize = type.substr(bracketPos, type.length() - bracketPos); - type = type.substr(0, bracketPos); - } - std::string decl = type + " " + _prefix + identifier + arrSize; - stream << decl << ";" << std::endl; - - if (arrSize.length() > 0) { - _varInitializers.push_back(value); - } else { - if (expression.length() > 0) { - // id and expr given - _varInitializers.push_back(identifier + " = " + boost::trim_copy(expression) + ";"); - } else if (value.length() > 0) { - // id and text content given - _varInitializers.push_back(identifier + " = " + value + ";"); - } - } - } else if (value.length() > 0) { - // no id but text content given - stream << beautifyIndentation(value) << std::endl; - } -#endif } @@ -2277,33 +2056,10 @@ void ChartToPromela::writeDeclarations(std::ostream& stream) { } stream << std::endl; - if (_globalEventSource || _invokers.size() > 0) - stream << "/* event sources */" << std::endl; - - if (_globalEventSource) { - _globalEventSource.writeDeclarations(stream); - } - - std::map<std::string, PromelaEventSource>::iterator invIter = _invokers.begin(); - while(invIter != _invokers.end()) { - invIter->second.writeDeclarations(stream); - invIter++; - } - + } void ChartToPromela::writeEventSources(std::ostream& stream) { - std::list<PromelaInline>::iterator inlineIter; - - if (_globalEventSource) { - _globalEventSource.writeBody(stream); - } - - std::map<std::string, PromelaEventSource>::iterator invIter = _invokers.begin(); - while(invIter != _invokers.end()) { - invIter->second.writeBody(stream); - invIter++; - } } void ChartToPromela::writeStartInvoker(std::ostream& stream, const Arabica::DOM::Node<std::string>& node, ChartToPromela* invoker, int indent) { @@ -2427,27 +2183,96 @@ void ChartToPromela::writeFSM(std::ostream& stream) { stream << " scheduleMachines();" << std::endl << std::endl; } + std::list<PromelaInline*> eventSources = pmlInlines.getAllOfType(PromelaInline::PROMELA_EVENT_ALL_BUT | + PromelaInline::PROMELA_EVENT_ONLY); + stream << " atomic {" << std::endl; stream << " /* pop an event */" << std::endl; stream << " if" << std::endl; stream << " :: len(" << _prefix << "iQ) != 0 -> " << _prefix << "iQ ? " << _prefix << "_event /* from internal queue */" << std::endl; - stream << " :: else -> " << _prefix << "eQ ? " << _prefix << "_event /* from external queue */" << std::endl; - stream << " fi;" << std::endl << std::endl; + if (eventSources.size() > 0) { + stream << " :: len(" << _prefix << "eQ) != 0 -> " << _prefix << "eQ ? " << _prefix << "_event /* from external queue */" << std::endl; + stream << " :: else -> {" << std::endl; + stream << " /* external queue is empty -> automatically enqueue external event */" << std::endl; + stream << " if" << std::endl; -#if 0 - if (!_analyzer->usesComplexEventStruct()) { - stream << " printf(\"======= Process %d dequeued %d\\n\", _pid, " << _prefix << "_event);" << std::endl; + for (std::list<PromelaInline*>::iterator esIter = eventSources.begin(); esIter != eventSources.end(); esIter++) { + PromelaEventSource es(**esIter); + + std::string condition = "true"; + + if (LOCALNAME(es.container) == "invoke") { + if (HAS_ATTR_CAST(es.container, "id")) { + condition = _prefix + ATTR_CAST(es.container, "id") + "Running"; + } else { + LOG(ERROR) << "Invoker has no id"; + } + } else if (HAS_ATTR(es.container, "id")) { + condition = _prefix + "_x.states[" + _analyzer->macroForLiteral(ATTR(es.container, "id")) + "]"; + } + stream << " :: " << condition << " -> {" << std::endl; + + if (es.type == PromelaInline::PROMELA_EVENT_ALL_BUT) { + std::string excludeEventDescs; + for (std::list<Data>::iterator evIter = es.events.array.begin(); evIter != es.events.array.end(); evIter++) { + excludeEventDescs += " " + evIter->atom; + } + + NodeSet<std::string> transitions = filterChildElements("transition", es.container, true); + std::set<std::string> eventNames; + for (int i = 0; i < transitions.size(); i++) { + if (!HAS_ATTR_CAST(transitions[i], "event")) + continue; + if (HAS_ATTR_CAST(transitions[i], "cond") && ATTR_CAST(transitions[i], "cond").find("_event.") != std::string::npos) + continue; + std::list<std::string> events = InterpreterImpl::tokenizeIdRefs(ATTR_CAST(transitions[i], "event")); + for (std::list<std::string>::iterator evIter = events.begin(); evIter != events.end(); evIter++) { + std::string eventName = *evIter; + if (boost::ends_with(eventName, "*")) + eventName = eventName.substr(0, eventName.size() - 1); + if (boost::ends_with(eventName, ".")) + eventName = eventName.substr(0, eventName.size() - 1); + + // is this event excluded? + if (!InterpreterImpl::nameMatch(excludeEventDescs, eventName)) { + eventNames.insert(eventName); + } + } + } + + if (eventNames.size() > 0) { + stream << " if " << std::endl; + for (std::set<std::string>::iterator evIter = eventNames.begin(); evIter != eventNames.end(); evIter++) { + stream << " :: true -> { " << _prefix << "_event.name = " << _analyzer->macroForLiteral(*evIter) << " }" << std::endl; + } + stream << " fi " << std::endl; + } + + } else if (es.type == PromelaInline::PROMELA_EVENT_ONLY) { + if (es.events.array.size() > 0) { + stream << " if " << std::endl; + for (std::list<Data>::iterator evIter = es.events.array.begin(); evIter != es.events.array.end(); evIter++) { + stream << " :: true -> { " << std::endl; + stream << dataToAssignments(" _event", *evIter); + stream << " } " << std::endl; + } + stream << " fi " << std::endl; + } else { + stream << dataToAssignments(" _event", es.events); + } + } else { + assert(false); + } + stream << " }" << std::endl; + } + + stream << " fi" << std::endl; + stream << " }" << std::endl; } else { - stream << " printf(\"======= Process %d dequeued %d\\n\", _pid, " << _prefix << "_event.name);" << std::endl; - if (_analyzer->usesEventField("sendid")) - stream << " printf(\" sendid: %d\\n\", " << _prefix << "_event.sendid);" << std::endl; - if (_analyzer->usesEventField("invokeid")) - stream << " printf(\" invokeid: %d\\n\", " << _prefix << "_event.invokeid);" << std::endl; - if (_analyzer->usesEventField("delay")) - stream << " printf(\" delay: %d\\n\", " << _prefix << "_event.delay);" << std::endl; + stream << " :: else -> " << _prefix << "eQ ? " << _prefix << "_event /* from external queue */" << std::endl; } - stream << std::endl; -#endif + stream << " fi;" << std::endl << std::endl; + stream << " /* terminate if we are stopped */" << std::endl; stream << " if" << std::endl; @@ -2532,16 +2357,6 @@ void ChartToPromela::writeFSM(std::ostream& stream) { stream << " removePendingEventsForInvoker(" << _analyzer->macroForLiteral(this->_invokerid) << ")" << std::endl; } - // stop all event sources - if (_globalEventSource) - _globalEventSource.writeStop(stream, 2); - - std::map<std::string, PromelaEventSource>::iterator invIter = _invokers.begin(); - while(invIter != _invokers.end()) { - invIter->second.writeStop(stream, 2); - invIter++; - } - stream << " }" << std::endl; stream << "}" << std::endl; } @@ -2907,8 +2722,7 @@ void ChartToPromela::writeMain(std::ostream& stream) { } stream << std::endl; } - if (_globalEventSource) - _globalEventSource.writeStart(stream, 1); + stream << " run " << (_prefix.size() == 0 ? "machine_" : _prefix) << "run() priority 10;" << std::endl; stream << "}" << std::endl; @@ -3175,44 +2989,44 @@ void ChartToPromela::initNodes() { } } } - // external event names from comments and event sources - NodeSet<std::string> promelaEventSourceComments; - NodeSet<std::string> invokers = _xpath.evaluate("//" + _nsInfo.xpathPrefix + "invoke", _scxml).asNodeSet(); - promelaEventSourceComments.push_back(filterChildType(Node_base::COMMENT_NODE, invokers, false)); // comments in invoke elements - promelaEventSourceComments.push_back(filterChildType(Node_base::COMMENT_NODE, _scxml, false)); // comments in scxml element - - for (int i = 0; i < promelaEventSourceComments.size(); i++) { - PromelaInlines promInls = PromelaInlines::fromNode(promelaEventSourceComments[i]); + + { + // gather all inline promela comments + pmlInlines = PromelaInlines(_scxml); + if (pmlInlines.getAllOfType(PromelaInline::PROMELA_EVENT_ONLY).size() > 0) + _analyzer->addCode("_x.states", this); - for ( std::list<PromelaInline>::iterator promIter = promInls.code.begin(); promIter != promInls.code.end(); promIter++) { - if (promIter->type == PromelaInline::PROMELA_EVENT_SOURCE || promIter->type == PromelaInline::PROMELA_EVENT_SOURCE_CUSTOM) { - PromelaEventSource promES(*promIter, _analyzer, _externalQueueLength); - if (TAGNAME_CAST(promelaEventSourceComments[i].getParentNode()) == "scxml") { - promES.type = PromelaEventSource::PROMELA_EVENT_SOURCE_GLOBAL; - promES.name = "global"; - _globalEventSource = promES; - } else { - Element<std::string> invoker = Element<std::string>(promelaEventSourceComments[i].getParentNode()); - if (!HAS_ATTR_CAST(promelaEventSourceComments[i].getParentNode(), "id")) { - invoker.setAttribute("invokeid", "invoker" + toStr(_invokers.size())); // if there is no invokeid, enumerate - } else { - invoker.setAttribute("invokeid", ATTR_CAST(promelaEventSourceComments[i].getParentNode(), "id")); + // register events and string literals + for (std::list<PromelaInline*>::iterator inlIter = pmlInlines.allInlines.begin(); inlIter != pmlInlines.allInlines.end(); inlIter++) { + if ((*inlIter)->type != (PromelaInline::PROMELA_EVENT_ONLY)) + continue; + + Data json = Data::fromJSON((*inlIter)->content); + if (!json.empty()) { + std::list<std::string> eventNames = PromelaInlines::getEventNames(json); + for (std::list<std::string>::iterator evIter = eventNames.begin(); evIter != eventNames.end(); evIter++) { + _analyzer->addEvent(*evIter); + } + + std::list<std::string> stringLiterals = PromelaInlines::getStringLiterals(json); + for (std::list<std::string>::iterator strIter = stringLiterals.begin(); strIter != stringLiterals.end(); strIter++) { + _analyzer->addLiteral(*strIter); + } + + if (json.array.size() > 0) { + for (int i = 0; i < json.array.size(); i++) { + std::string expr = dataToAssignments("_event", json.item(i)); + _analyzer->addCode(expr, this); } - std::string invokeId = ATTR_CAST(promelaEventSourceComments[i].getParentNode(), "invokeid"); - - promES.type = PromelaEventSource::PROMELA_EVENT_SOURCE_INVOKER; - promES.name = invokeId; - _invokers[invokeId] = promES; + } else { + std::string expr = dataToAssignments("_event", json); + _analyzer->addCode(expr, this); + } + } } } - - if (_globalEventSource || _invokers.size() > 0) { - _allowEventInterleaving = true; - } else { - _allowEventInterleaving = false; - } // add platform variables as string literals _analyzer->addLiteral(_prefix + "_sessionid"); @@ -3331,11 +3145,55 @@ void ChartToPromela::initNodes() { } } - +std::list<std::string> PromelaInlines::getStringLiterals(const Data& data) { + std::list<std::string> literals; + if (data.atom.size() > 0 && data.type == Data::VERBATIM) { + literals.push_back(data.atom); + } + if (data.array.size() > 0) { + for (std::list<Data>::const_iterator arrIter = data.array.begin(); arrIter != data.array.end(); arrIter++) { + std::list<std::string> nested = getStringLiterals(*arrIter); + literals.insert(literals.end(), nested.begin(), nested.end()); + } + } + if (data.compound.size() > 0) { + for (std::map<std::string, Data>::const_iterator compIter = data.compound.begin(); compIter != data.compound.end(); compIter++) { + std::list<std::string> nested = getStringLiterals(compIter->second); + literals.insert(literals.end(), nested.begin(), nested.end()); + } + } + return literals; +} + +std::list<std::string> PromelaInlines::getEventNames(const Data& data) { + std::list<std::string> eventNames; + if (data.compound.size() > 0 && data.hasKey("name")) { + eventNames.push_back(data.at("name")); + } + if (data.array.size() > 0) { + for (std::list<Data>::const_iterator arrIter = data.array.begin(); arrIter != data.array.end(); arrIter++) { + std::list<std::string> nested = getEventNames(*arrIter); + eventNames.insert(eventNames.end(), nested.begin(), nested.end()); + } + } + if (data.compound.size() > 0) { + for (std::map<std::string, Data>::const_iterator compIter = data.compound.begin(); compIter != data.compound.end(); compIter++) { + std::list<std::string> nested = getEventNames(compIter->second); + eventNames.insert(eventNames.end(), nested.begin(), nested.end()); + } + } + + return eventNames; +} + std::string ChartToPromela::dataToAssignments(const std::string& prefix, const Data& data) { std::stringstream retVal; if (data.atom.size() > 0) { - retVal << prefix << " = " << data.atom << ";" << std::endl; + if (data.type == Data::VERBATIM) { + retVal << prefix << " = " << _analyzer->macroForLiteral(data.atom) << ";" << std::endl; + } else { + retVal << prefix << " = " << data.atom << ";" << std::endl; + } } else if (data.compound.size() > 0) { for (std::map<std::string, Data>::const_iterator cIter = data.compound.begin(); cIter != data.compound.end(); cIter++) { retVal << dataToAssignments(prefix + "." + cIter->first, cIter->second); @@ -3358,18 +3216,6 @@ std::string ChartToPromela::sanitizeCode(const std::string& code) { return replaced; } -void PromelaInline::dump() { -// std::list<std::list<std::string> >::iterator outerIter = sequences.begin(); -// while(outerIter != sequences.end()) { -// std::list<std::string>::iterator innerIter = outerIter->begin(); -// while(innerIter != outerIter->end()) { -// std::cout << *innerIter << " "; -// innerIter++; -// } -// std::cout << std::endl; -// outerIter++; -// } -} void ChartToPromela::writeProgram(std::ostream& stream) { diff --git a/src/uscxml/transform/ChartToPromela.h b/src/uscxml/transform/ChartToPromela.h index 9a8b0a3..1b0b16d 100644 --- a/src/uscxml/transform/ChartToPromela.h +++ b/src/uscxml/transform/ChartToPromela.h @@ -36,31 +36,96 @@ namespace uscxml { class PromelaCodeAnalyzer; class ChartToPromela; class PromelaParserNode; - + class USCXML_API PromelaInline { public: - PromelaInline() : type(PROMELA_NIL) {} + enum PromelaInlineType { + PROMELA_NIL = 0x0000, + PROMELA_LTL = 0x0001, + PROMELA_CODE = 0x0002, + PROMELA_EVENT_ALL_BUT = 0x0004, + PROMELA_EVENT_ONLY = 0x0008, + PROMELA_PROGRESS_LABEL = 0x0010, + PROMELA_ACCEPT_LABEL = 0x0020, + PROMELA_END_LABEL = 0x0040 + }; + PromelaInline(const Arabica::DOM::Node<std::string>& node); + virtual ~PromelaInline() {} + operator bool() { return (type != PROMELA_NIL); } - void dump(); - - enum PromelaInlineType { - PROMELA_NIL, - PROMELA_CODE, - PROMELA_EVENT_SOURCE, - PROMELA_EVENT_SOURCE_CUSTOM, - PROMELA_PROGRESS_LABEL, - PROMELA_ACCEPT_LABEL, - PROMELA_END_LABEL - }; + std::list<PromelaInline*> children; + PromelaInline* prevSibling; + PromelaInline* nextSibling; + + virtual void dump(); + virtual bool relatesTo(const Arabica::DOM::Node<std::string>& node) { + return container == node; + } + + size_t level; std::string content; + Arabica::DOM::Element<std::string> container; PromelaInlineType type; + +protected: + PromelaInline() : prevSibling(NULL), nextSibling(NULL), type(PROMELA_NIL) {}; +}; + +class USCXML_API PromelaInlines { +public: + + PromelaInlines(const Arabica::DOM::Node<std::string>& node); + PromelaInlines() {} + + virtual ~PromelaInlines(); + + std::list<PromelaInline*> getRelatedTo(const Arabica::DOM::Node<std::string>& node, PromelaInline::PromelaInlineType type); + std::list<PromelaInline*> getAllOfType(uint32_t type); + + std::map<Arabica::DOM::Node<std::string>, std::list<PromelaInline*> > inlines; + std::list<PromelaInline*> allInlines; + + static std::list<std::string> getStringLiterals(const Data& data); + static std::list<std::string> getEventNames(const Data& data); + + +}; + +class USCXML_API PromelaEventSource : public PromelaInline { +public: + PromelaEventSource(const PromelaInline& pmlInline) { + type = pmlInline.type; + container = pmlInline.container; + content = pmlInline.content; + events = Data::fromJSON(pmlInline.content); + } + + virtual bool relatesTo(const Arabica::DOM::Node<std::string>& node) { + return container == node || InterpreterImpl::isDescendant(node, container); + } + + Data events; }; +#if 0 + + +class USCXML_API PromelaInlinesAutoEvents : public PromelaInline { +public: + virtual ~PromelaInlinesAutoEvents() {} + virtual bool relatesTo(const Arabica::DOM::Node<std::string>&); + virtual void setContent(const std::string& content); + virtual void dump(); + + std::map<std::string, Data> states; +}; + + class USCXML_API PromelaEventSource { public: @@ -93,37 +158,8 @@ public: PromelaCodeAnalyzer* analyzer; }; -class USCXML_API PromelaInlines { -public: - - static PromelaInlines fromNodeSet(const Arabica::XPath::NodeSet<std::string>& node, bool recurse = false); - static PromelaInlines fromNode(const Arabica::DOM::Node<std::string>& node); - static PromelaInlines fromString(const std::string& text); +#endif - PromelaInlines(const std::string& text, const Arabica::DOM::Node<std::string>& node); - PromelaInlines(); - - void merge(const PromelaInlines& other) { - code.insert(code.end(), other.code.begin(), other.code.end()); - nrProgressLabels += other.nrProgressLabels; - nrAcceptLabels += other.nrAcceptLabels; - nrEndLabels += other.nrEndLabels; - nrEventSources += other.nrEventSources; - nrCodes += other.nrCodes; - } - - operator bool() { - return code.size() > 0; - } - - std::list<PromelaInline> code; - int nrProgressLabels; - int nrAcceptLabels; - int nrEndLabels; - int nrEventSources; - int nrCodes; -}; - class USCXML_API PromelaCodeAnalyzer { public: class PromelaTypedef { @@ -172,6 +208,9 @@ public: bool usesInPredicate() { return _usesInPredicate; } + void usesInPredicate(bool value) { + _usesInPredicate = value; + } bool usesPlatformVars() { return _usesPlatformVars; } @@ -366,8 +405,9 @@ protected: uint32_t _externalQueueLength; uint32_t _internalQueueLength; - std::map<std::string, PromelaEventSource> _invokers; - PromelaEventSource _globalEventSource; + PromelaInlines pmlInlines; +// std::map<std::string, PromelaEventSource> _invokers; +// PromelaEventSource _globalEventSource; std::map<std::string, std::map<std::string, size_t> > _historyMembers; // ids of all history states std::set<std::string> _dataModelVars; |