2010-03-02 21:22:31 +03:00
|
|
|
#include "nodedumper.h"
|
|
|
|
#include "state.h"
|
2014-02-05 08:49:10 +04:00
|
|
|
#include "module.h"
|
2010-03-02 21:22:31 +03:00
|
|
|
|
2011-10-01 03:36:30 +04:00
|
|
|
#include <string>
|
2010-03-02 21:22:31 +03:00
|
|
|
#include <sstream>
|
2010-03-28 19:57:39 +04:00
|
|
|
#include <assert.h>
|
2010-03-02 21:22:31 +03:00
|
|
|
|
2010-04-12 04:16:36 +04:00
|
|
|
/*!
|
|
|
|
\class NodeDumper
|
|
|
|
|
|
|
|
A visitor responsible for creating a text dump of a node tree. Also
|
|
|
|
contains a cache for fast retrieval of the text representation of
|
|
|
|
any node or subtree.
|
|
|
|
*/
|
2010-03-02 21:22:31 +03:00
|
|
|
|
2010-04-12 04:16:36 +04:00
|
|
|
bool NodeDumper::isCached(const AbstractNode &node) const
|
2010-03-02 21:22:31 +03:00
|
|
|
{
|
|
|
|
return !this->cache[node].empty();
|
|
|
|
}
|
|
|
|
|
2010-04-12 04:16:36 +04:00
|
|
|
/*!
|
|
|
|
Indent or deindent. Must be called before we output any children.
|
|
|
|
*/
|
2010-03-02 21:22:31 +03:00
|
|
|
void NodeDumper::handleIndent(const State &state)
|
|
|
|
{
|
|
|
|
if (state.isPrefix()) {
|
|
|
|
this->currindent += "\t";
|
|
|
|
}
|
|
|
|
else if (state.isPostfix()) {
|
|
|
|
this->currindent.erase((this->currindent.length() >= 1) ?
|
|
|
|
this->currindent.length() - 1 : 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-12 04:16:36 +04:00
|
|
|
/*!
|
|
|
|
Dumps the block of children contained in this->visitedchildren,
|
|
|
|
including braces and indentation.
|
|
|
|
All children are assumed to be cached already.
|
|
|
|
*/
|
2011-10-01 03:36:30 +04:00
|
|
|
std::string NodeDumper::dumpChildren(const AbstractNode &node)
|
2010-03-02 21:22:31 +03:00
|
|
|
{
|
|
|
|
std::stringstream dump;
|
|
|
|
if (!this->visitedchildren[node.index()].empty()) {
|
|
|
|
dump << " {\n";
|
|
|
|
|
|
|
|
for (ChildList::const_iterator iter = this->visitedchildren[node.index()].begin();
|
|
|
|
iter != this->visitedchildren[node.index()].end();
|
|
|
|
iter++) {
|
2010-04-12 04:16:36 +04:00
|
|
|
assert(isCached(**iter));
|
2014-02-05 08:49:10 +04:00
|
|
|
if ((*iter)->modinst->isBackground()) dump << "%";
|
2014-05-17 19:53:11 +04:00
|
|
|
if ((*iter)->modinst->isHighlight()) dump << "#";
|
2010-03-02 21:22:31 +03:00
|
|
|
dump << this->cache[**iter] << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
dump << this->currindent << "}";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dump << ";";
|
|
|
|
}
|
|
|
|
return dump.str();
|
|
|
|
}
|
|
|
|
|
2010-04-12 04:16:36 +04:00
|
|
|
/*!
|
|
|
|
Called for each node in the tree.
|
|
|
|
Will abort traversal if we're cached
|
|
|
|
*/
|
2010-08-28 19:34:22 +04:00
|
|
|
Response NodeDumper::visit(State &state, const AbstractNode &node)
|
2010-03-02 21:22:31 +03:00
|
|
|
{
|
|
|
|
if (isCached(node)) return PruneTraversal;
|
2010-04-12 04:16:36 +04:00
|
|
|
|
|
|
|
handleIndent(state);
|
2010-03-02 21:22:31 +03:00
|
|
|
if (state.isPostfix()) {
|
|
|
|
std::stringstream dump;
|
2010-04-12 04:16:36 +04:00
|
|
|
dump << this->currindent;
|
|
|
|
if (this->idprefix) dump << "n" << node.index() << ":";
|
|
|
|
dump << node;
|
2010-03-02 21:22:31 +03:00
|
|
|
dump << dumpChildren(node);
|
|
|
|
this->cache.insert(node, dump.str());
|
|
|
|
}
|
|
|
|
|
|
|
|
handleVisitedChildren(state, node);
|
|
|
|
return ContinueTraversal;
|
|
|
|
}
|
|
|
|
|
2010-03-19 06:07:38 +03:00
|
|
|
/*!
|
|
|
|
Adds this given node to its parent's child list.
|
|
|
|
Should be called for all nodes, including leaf nodes.
|
|
|
|
*/
|
2010-03-02 21:22:31 +03:00
|
|
|
void NodeDumper::handleVisitedChildren(const State &state, const AbstractNode &node)
|
|
|
|
{
|
|
|
|
if (state.isPostfix()) {
|
|
|
|
this->visitedchildren.erase(node.index());
|
|
|
|
if (!state.parent()) {
|
|
|
|
this->root = &node;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this->visitedchildren[state.parent()->index()].push_back(&node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|