summaryrefslogtreecommitdiffstats
path: root/src/uscxml/transform/ChartToPromela.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/uscxml/transform/ChartToPromela.cpp')
-rw-r--r--src/uscxml/transform/ChartToPromela.cpp181
1 files changed, 154 insertions, 27 deletions
diff --git a/src/uscxml/transform/ChartToPromela.cpp b/src/uscxml/transform/ChartToPromela.cpp
index 7676a37..dba8d90 100644
--- a/src/uscxml/transform/ChartToPromela.cpp
+++ b/src/uscxml/transform/ChartToPromela.cpp
@@ -308,10 +308,11 @@ PromelaEventSource::PromelaEventSource(const PromelaInline& source, PromelaCodeA
}
}
}
-
+
void PromelaCodeAnalyzer::addCode(const std::string& code, ChartToPromela* interpreter) {
PromelaParser parser(code);
-
+// parser.dump();
+
// find all strings
std::list<PromelaParserNode*> astNodes;
astNodes.push_back(parser.ast);
@@ -339,6 +340,10 @@ void PromelaCodeAnalyzer::addCode(const std::string& code, ChartToPromela* inter
assignedValue = strTo<int>(node->operands.back()->value);
}
}
+ if (node->operands.back()->type == PML_STRING) {
+ // remember strings for later
+ astNodes.push_back(node->operands.back());
+ }
if (node->operands.front()->type == PML_CMPND)
node = node->operands.front();
if (node->operands.front()->type != PML_NAME)
@@ -414,6 +419,11 @@ void PromelaCodeAnalyzer::addCode(const std::string& code, ChartToPromela* inter
_typeDefs.types[node->value].occurrences.insert(interpreter);
_typeDefs.types[node->value].minValue = 0;
_typeDefs.types[node->value].maxValue = 1;
+ // test325
+ if (node->value.compare("_ioprocessors") == 0) {
+ addCode("_ioprocessors.scxml.location", interpreter);
+ }
+
break;
}
@@ -766,6 +776,7 @@ void ChartToPromela::writeTypeDefs(std::ostream& stream) {
for (std::list<PromelaCodeAnalyzer::PromelaTypedef>::reverse_iterator rIter = individualDefs.rbegin(); rIter != individualDefs.rend(); rIter++) {
PromelaCodeAnalyzer::PromelaTypedef currDef = *rIter;
+
if (currDef.types.size() == 0 || currDef.name.size() == 0)
continue;
@@ -1614,17 +1625,10 @@ void ChartToPromela::writeExecutableContent(std::ostream& stream, const Arabica:
writeIfBlock(stream, condChain, indent);
} else if(TAGNAME(nodeElem) == "assign") {
- if (HAS_ATTR(nodeElem, "location")) {
- stream << padding << _prefix << ATTR(nodeElem, "location") << " = ";
- }
- if (HAS_ATTR(nodeElem, "expr")) {
- stream << ADAPT_SRC(ATTR(nodeElem, "expr")) << ";" << std::endl;
- } else {
- NodeSet<std::string> assignTexts = filterChildType(Node_base::TEXT_NODE, nodeElem, true);
- if (assignTexts.size() > 0) {
- stream << ADAPT_SRC(boost::trim_copy(assignTexts[0].getNodeValue())) << ";" << std::endl;
- }
- }
+ NodeSet<std::string> assignTexts = filterChildType(Node_base::TEXT_NODE, nodeElem, true);
+ assert(assignTexts.size() > 0);
+ stream << ADAPT_SRC(boost::trim_copy(assignTexts[0].getNodeValue())) << std::endl;
+
} else if(TAGNAME(nodeElem) == "send" || TAGNAME(nodeElem) == "raise") {
std::string targetQueue;
if (TAGNAME(nodeElem) == "raise") {
@@ -2066,11 +2070,14 @@ void ChartToPromela::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 for " << _prefix << " */" << std::endl;
+ stream << "/* data model variables" << (_prefix.size() > 0 ? " for " + _prefix : "") << " */" << std::endl;
std::set<std::string> processedIdentifiers;
+
+ // automatic types
+ PromelaCodeAnalyzer::PromelaTypedef allTypes = _analyzer->getTypes();
+
for (int i = 0; i < datas.size(); i++) {
Node<std::string> data = datas[i];
@@ -2078,23 +2085,37 @@ void ChartToPromela::writeDeclarations(std::ostream& stream) {
continue;
std::string identifier = (HAS_ATTR_CAST(data, "id") ? ATTR_CAST(data, "id") : "");
- std::string expression = (HAS_ATTR_CAST(data, "expr") ? ATTR_CAST(data, "expr") : "");
- if (expression.size() == 0 && HAS_ATTR_CAST(data, "src")) {
- URL dataSrc(ATTR_CAST(data, "src"));
- dataSrc.toAbsolute(_baseURI);
- expression = dataSrc.getInContent();
- }
std::string type = boost::trim_copy(HAS_ATTR_CAST(data, "type") ? ATTR_CAST(data, "type") : "");
_dataModelVars.insert(identifier);
if (processedIdentifiers.find(identifier) != processedIdentifiers.end())
continue;
+
processedIdentifiers.insert(identifier);
if (boost::starts_with(type, "string")) {
type = "int" + type.substr(6, type.length() - 6);
}
+
+ if (type.length() == 0 || type == "auto") {
+ if (allTypes.types.find(identifier) != allTypes.types.end()) {
+ type = allTypes.types[identifier].name;
+ } else {
+ LOG(ERROR) << "Automatic or no type for '" << identifier << "' but no type resolved";
+ continue;
+ }
+ }
+
std::string arrSize;
+ 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 0
NodeSet<std::string> dataText = filterChildType(Node_base::TEXT_NODE, data, true);
std::string value;
@@ -2128,9 +2149,11 @@ void ChartToPromela::writeDeclarations(std::ostream& stream) {
// no id but text content given
stream << beautifyIndentation(value) << std::endl;
}
+#endif
}
- PromelaCodeAnalyzer::PromelaTypedef allTypes = _analyzer->getTypes();
+
+ // implicit and dynamic types
std::map<std::string, PromelaCodeAnalyzer::PromelaTypedef>::iterator typeIter = allTypes.types.begin();
while(typeIter != allTypes.types.end()) {
if (typeIter->second.occurrences.find(this) == typeIter->second.occurrences.end()) {
@@ -2231,6 +2254,13 @@ void ChartToPromela::writeFSM(std::ostream& stream) {
// transitions = filterChildElements(_nsInfo.xmlNSPrefix + "transition", _startState);
// assert(transitions.size() == 1);
+ stream << std::endl << "/* global scripts */" << std::endl;
+ NodeSet<std::string> scripts = filterChildElements(_nsInfo.xmlNSPrefix + "script", _scxml, false);
+ for (int i = 0; i < scripts.size(); i++) {
+ writeExecutableContent(stream, scripts[i], 1);
+ }
+ stream << std::endl;
+
stream << "/* transition to initial state */" << std::endl;
assert(_start->sortedOutgoing.size() == 1);
// initial transition has to be first one for control flow at start
@@ -2620,9 +2650,10 @@ void ChartToPromela::writeMain(std::ostream& stream) {
stream << std::endl;
stream << "init {" << std::endl;
if (_varInitializers.size() > 0) {
+ stream << "/* initialize data model variables */" << std::endl;
std::list<std::string>::iterator initIter = _varInitializers.begin();
while(initIter != _varInitializers.end()) {
- stream << ADAPT_SRC(beautifyIndentation(*initIter)) << std::endl;
+ stream << ADAPT_SRC(beautifyIndentation(*initIter, 1)) << std::endl;
initIter++;
}
stream << std::endl;
@@ -2700,8 +2731,8 @@ void ChartToPromela::initNodes() {
Interpreter nested;
if (HAS_ATTR_CAST(invokes[i], "src")) {
URL absUrl(ATTR_CAST(invokes[i], "src"));
- absUrl.toAbsolute(_baseURI);
- nested = Interpreter::fromURI(absUrl);
+ absUrl.toAbsolute(_baseURL[_scxml]);
+ nested = Interpreter::fromURL(absUrl);
} else {
NodeSet<std::string> nestedContent = InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "content", invokes[i]);
@@ -2714,7 +2745,7 @@ void ChartToPromela::initNodes() {
Node<std::string> importRoot = nestedDoc.importNode(nestedRoot[0], true);
nestedDoc.appendChild(importRoot);
- nested = Interpreter::fromDOM(nestedDoc, _nsInfo, _sourceURI);
+ nested = Interpreter::fromDOM(nestedDoc, _nsInfo, _sourceURL);
}
// std::cout << invokes[i] << std::endl;
@@ -2784,6 +2815,69 @@ void ChartToPromela::initNodes() {
}
}
+ // transform data / assign json into PROMELA statements
+ {
+ NodeSet<std::string> asgn;
+ asgn.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "data", _scxml, true));
+ asgn.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "assign", _scxml, true));
+
+ for (int i = 0; i < asgn.size(); i++) {
+ if (isInEmbeddedDocument(asgn[i]))
+ continue;
+
+ Element<std::string> asgnElem(asgn[i]);
+
+ std::string key;
+ if (HAS_ATTR(asgnElem, "id")) {
+ key = ATTR(asgnElem, "id");
+ } else if (HAS_ATTR(asgnElem, "location")) {
+ key = ATTR(asgnElem, "location");
+ }
+
+ if (key.length() == 0)
+ continue;
+
+ std::string value;
+ if (HAS_ATTR(asgnElem, "expr")) {
+ value = ATTR(asgnElem, "expr");
+ } else if (HAS_ATTR(asgnElem, "src")) {
+ URL absUrl(ATTR_CAST(asgnElem, "src"));
+ absUrl.toAbsolute(_baseURL[_scxml]);
+ value = absUrl.getInContent();
+ } else {
+ NodeSet<std::string> textChilds = filterChildType(Node_base::TEXT_NODE, asgnElem);
+ if (textChilds.size() > 0) {
+ for (int j = 0; j < textChilds.size(); j++) {
+ value += textChilds[j].getNodeValue();
+ }
+ }
+ }
+
+ boost::trim(value);
+ if (value.size() == 0)
+ continue;
+
+ // remove all children, we will replae by suitable promela statements
+ while(asgnElem.hasChildNodes())
+ asgnElem.removeChild(asgnElem.getFirstChild());
+
+ std::string newValue;
+ Data json = Data::fromJSON(value);
+ if (!json.empty()) {
+ newValue = dataToAssignments(key, json);
+ } else {
+ newValue = key + " = " + value + ";";
+ }
+ newValue = sanitizeCode(newValue);
+ _analyzer->addCode(newValue, this);
+
+ if (asgnElem.getLocalName() == "data")
+ _varInitializers.push_back(newValue);
+ Text<std::string> newText = _document.createTextNode(newValue);
+ asgnElem.insertBefore(newText, Node<std::string>());
+ }
+ }
+
// do we need sendid / invokeid?
{
NodeSet<std::string> invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _scxml, true);
@@ -2926,7 +3020,7 @@ void ChartToPromela::initNodes() {
{
NodeSet<std::string> withText;
withText.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "script", _scxml, true));
- withText.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "data", _scxml, true));
+// withText.push_back(filterChildElements(_nsInfo.xmlNSPrefix + "data", _scxml, true));
for (int i = 0; i < withText.size(); i++) {
NodeSet<std::string> texts = filterChildType(Node_base::TEXT_NODE, withText[i], true);
for (int j = 0; j < texts.size(); j++) {
@@ -2940,6 +3034,17 @@ void ChartToPromela::initNodes() {
}
}
}
+ {
+ NodeSet<std::string> foreachs = filterChildElements(_nsInfo.xmlNSPrefix + "foreach", _scxml, true);
+ for (int i = 0; i < foreachs.size(); i++) {
+ if (HAS_ATTR_CAST(foreachs[i], "index")) {
+ allCode.insert(ATTR_CAST(foreachs[i], "index"));
+ }
+ if (HAS_ATTR_CAST(foreachs[i], "item")) {
+ allCode.insert(ATTR_CAST(foreachs[i], "item"));
+ }
+ }
+ }
for (std::set<std::string>::const_iterator codeIter = allCode.begin(); codeIter != allCode.end(); codeIter++) {
_analyzer->addCode(*codeIter, this);
}
@@ -2961,6 +3066,25 @@ void ChartToPromela::initNodes() {
}
}
+
+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;
+ } 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);
+ }
+ } else if (data.array.size() > 0) {
+ size_t index = 0;
+ for(std::list<Data>::const_iterator aIter = data.array.begin(); aIter != data.array.end(); aIter++) {
+ retVal << dataToAssignments(prefix + "[" + toStr(index) + "]", *aIter);
+ index++;
+ }
+ }
+ return retVal.str();
+}
+
std::string ChartToPromela::sanitizeCode(const std::string& code) {
std::string replaced = code;
boost::replace_all(replaced, "\"", "'");
@@ -3000,6 +3124,9 @@ void ChartToPromela::writeProgram(std::ostream& stream) {
// std::cerr << _scxml << std::endl;
+ stream << "/* " << _sourceURL.asString() << " */" << std::endl;
+ stream << std::endl;
+
initNodes();
for (std::map<Arabica::DOM::Node<std::string>, ChartToPromela*>::iterator nestedIter = _machines.begin(); nestedIter != _machines.end(); nestedIter++) {