openscad/src/nodedumper.cc

102 lines
2.3 KiB
C++

#include "nodedumper.h"
#include "state.h"
#include "module.h"
#include <string>
#include <sstream>
#include <assert.h>
/*!
\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.
*/
bool NodeDumper::isCached(const AbstractNode &node) const
{
return !this->cache[node].empty();
}
/*!
Indent or deindent. Must be called before we output any children.
*/
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);
}
}
/*!
Dumps the block of children contained in this->visitedchildren,
including braces and indentation.
All children are assumed to be cached already.
*/
std::string NodeDumper::dumpChildren(const AbstractNode &node)
{
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++) {
assert(isCached(**iter));
if ((*iter)->modinst->isBackground()) dump << "%";
if ((*iter)->modinst->isHighlight()) dump << "#";
dump << this->cache[**iter] << "\n";
}
dump << this->currindent << "}";
}
else {
dump << ";";
}
return dump.str();
}
/*!
Called for each node in the tree.
Will abort traversal if we're cached
*/
Response NodeDumper::visit(State &state, const AbstractNode &node)
{
if (isCached(node)) return PruneTraversal;
handleIndent(state);
if (state.isPostfix()) {
std::stringstream dump;
dump << this->currindent;
if (this->idprefix) dump << "n" << node.index() << ":";
dump << node;
dump << dumpChildren(node);
this->cache.insert(node, dump.str());
}
handleVisitedChildren(state, node);
return ContinueTraversal;
}
/*!
Adds this given node to its parent's child list.
Should be called for all nodes, including leaf nodes.
*/
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);
}
}
}