summaryrefslogtreecommitdiff
path: root/cpp/src/slice2html/Gen.cpp
diff options
context:
space:
mode:
authorMichi Henning <michi@zeroc.com>2006-11-22 08:35:01 +0000
committerMichi Henning <michi@zeroc.com>2006-11-22 08:35:01 +0000
commit9073302574725750291e339e0bb4a60b1475c114 (patch)
treee2cf193e77df8aa481b5f2683802e56b25113787 /cpp/src/slice2html/Gen.cpp
parentchange .dll extension to .pyd to support Python 2.5 on Windows (diff)
downloadice-9073302574725750291e339e0bb4a60b1475c114.tar.bz2
ice-9073302574725750291e339e0bb4a60b1475c114.tar.xz
ice-9073302574725750291e339e0bb4a60b1475c114.zip
Intermediate check-in for slice2html.
Diffstat (limited to 'cpp/src/slice2html/Gen.cpp')
-rw-r--r--cpp/src/slice2html/Gen.cpp1955
1 files changed, 1955 insertions, 0 deletions
diff --git a/cpp/src/slice2html/Gen.cpp b/cpp/src/slice2html/Gen.cpp
new file mode 100644
index 00000000000..6ae96c6b1a7
--- /dev/null
+++ b/cpp/src/slice2html/Gen.cpp
@@ -0,0 +1,1955 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2006 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <IceUtil/DisableWarnings.h>
+#include <IceUtil/Functional.h>
+#include <Gen.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef _WIN32
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+
+#ifdef __BCPLUSPLUS__
+# include <iterator>
+#endif
+
+using namespace std;
+using namespace Slice;
+using namespace IceUtil;
+
+namespace Slice
+{
+
+void
+generate(const UnitPtr& unit, const ::std::string& dir,
+ const ::std::string& header, const ::std::string& footer, unsigned indexCount)
+{
+ unit->mergeModules();
+
+ //
+ // I don't want the top-level module to be sorted, therefore no
+ // p->sort() before or after the p->sortContents().
+ //
+ unit->sortContents(false);
+
+ GeneratorBase::setOutputDir(dir);
+ GeneratorBase::setHeader(header);
+ GeneratorBase::setFooter(footer);
+ GeneratorBase::setIndexCount(indexCount);
+
+ IndexVisitor iv;
+ unit->visit(&iv, false);
+
+ Visitor v;
+ unit->visit(&v, false);
+}
+
+}
+
+string Slice::GeneratorBase::_dir = ".";
+string Slice::GeneratorBase::_header1;
+string Slice::GeneratorBase::_header2;
+string Slice::GeneratorBase::_footer;
+unsigned Slice::GeneratorBase::_indexCount = 0;
+
+void
+Slice::GeneratorBase::setOutputDir(const string& dir)
+{
+ if(!dir.empty())
+ {
+ _dir = dir;
+ makeDir(_dir);
+ }
+}
+
+void
+Slice::GeneratorBase::setHeader(const string& header)
+{
+ if(header.empty())
+ {
+ ostringstream hdr1;
+ XMLOutput O1(hdr1);
+ O1 << "<!-- Generated by Ice version " << ICE_STRING_VERSION << " -->";
+ O1 << sp;
+ O1 << nl << "<!DOCTYPE html PUBLIC \"-//W3C//dtD html 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">";
+ O1 << se("html");
+ O1 << se("head");
+ O1 << se("title") << nl;
+ _header1 = hdr1.str();
+
+ // _header1 and _header2 store the bit preceding and following the title.
+ // _header1, the title text, and _header2 are written by openDoc().
+
+ ostringstream hdr2;
+ XMLOutput O2(hdr2);
+ O2.inc();
+ O2.inc();
+ O2 << nl << "<title/>";
+ O2.dec();
+ O2 << nl << "</head>";
+ O2 << nl << "<body>";
+ _header2 = hdr2.str();
+ }
+ else
+ {
+ readFile(header, _header1, _header2);
+ }
+}
+
+void
+Slice::GeneratorBase::setFooter(const string& footer)
+{
+ ostringstream ftr;
+ XMLOutput O(ftr);
+ if(footer.empty())
+ {
+ O << " </body>";
+ }
+ else
+ {
+ O << readFile(footer);
+ }
+ O << nl << "</html>";
+ _footer = ftr.str();
+}
+
+void
+Slice::GeneratorBase::setIndexCount(int ic)
+{
+ _indexCount = ic;
+}
+
+Slice::GeneratorBase::GeneratorBase(XMLOutput& o)
+ : _out(o)
+{
+}
+
+Slice::GeneratorBase::~GeneratorBase()
+{
+}
+
+void
+Slice::GeneratorBase::openDoc(const string& file, const string& title)
+{
+ openStream(_dir + "/" + file);
+
+ _out << _header1;
+ _out << title;
+ _out << _header2;
+ _out.inc();
+ _out.inc();
+}
+
+void
+Slice::GeneratorBase::openDoc(const ContainedPtr& c)
+{
+ string path = _dir;
+ StringList components = toStringList(c);
+ StringList::const_iterator i = components.begin();
+ for(StringList::size_type num = 0; num < components.size() - 1; ++num, ++i)
+ {
+ path += "/" + *i;
+ makeDir(path);
+ }
+ path += "/" + *i + ".html";
+
+ openStream(path);
+
+ _out << _header1;
+ _out << c->scoped().substr(2); // Text for title element.
+ _out << _header2;
+ _out.inc();
+ _out.inc();
+}
+
+void
+Slice::GeneratorBase::closeDoc()
+{
+ _out.dec();
+ _out.dec();
+ _out << nl << _footer;
+ _out << nl;
+}
+
+void
+Slice::GeneratorBase::start(const std::string& element, const std::string& classes)
+{
+ string s = element;
+ if(!classes.empty())
+ {
+ s += " class=\"" + classes + "\"";
+ }
+ _out << se(s);
+}
+
+void
+Slice::GeneratorBase::end()
+{
+ _out << ee;
+}
+
+string
+Slice::GeneratorBase::getComment(const ContainedPtr& contained, const ContainerPtr& container, bool summary)
+{
+ string s = contained->comment();
+ string comment;
+ for(unsigned int i = 0; i < s.size(); ++i)
+ {
+ if(s[i] == '\\' && i + 1 < s.size() && s[i + 1] == '[')
+ {
+ comment += '[';
+ ++i;
+ }
+ else if(s[i] == '[')
+ {
+ string literal;
+ for(++i; i < s.size(); ++i)
+ {
+ if(s[i] == ']')
+ {
+ break;
+ }
+
+ literal += s[i];
+ }
+ comment += toString(literal, container);
+ }
+ else if(summary && s[i] == '.' && (i + 1 >= s.size() || isspace(s[i + 1])))
+ {
+ comment += '.';
+ break;
+ }
+ else
+ {
+ comment += s[i];
+ }
+
+ }
+ return comment;
+}
+
+void
+Slice::GeneratorBase::printComment(const ContainedPtr& p, const string& deprecateReason)
+{
+#ifndef NDEBUG
+ int indent = _out.currIndent();
+#endif
+
+ ContainerPtr container = ContainerPtr::dynamicCast(p);
+ if(!container)
+ {
+ container = p->container();
+ }
+
+ string comment = getComment(p, container, false);
+ StringList par = getTagged("param", comment);
+ StringList ret = getTagged("return", comment);
+ StringList throws = getTagged("throws", comment);
+ StringList see = getTagged("see", comment);
+
+ string::size_type pos = comment.find_last_not_of(" \t\r\n");
+ if(pos != string::npos)
+ {
+ comment.erase(pos + 1);
+ _out.zeroIndent();
+ _out << nl << comment;
+ _out.restoreIndent();
+ }
+
+ if(!deprecateReason.empty())
+ {
+ end();
+ start("dd");
+ _out << nl << deprecateReason;
+ }
+
+ assert(_out.currIndent() == indent);
+
+ bool startedList = false;
+
+ if(!par.empty())
+ {
+ start("dl");
+ startedList = true;
+ start("dt", "Heading");
+ _out << "Parameters";
+ end();
+ start("dd");
+ start("dl");
+ for(StringList::const_iterator q = par.begin(); q != par.end(); ++q)
+ {
+ string term;
+ pos = q->find_first_of(" \t\r\n");
+ if(pos != string::npos)
+ {
+ term = q->substr(0, pos);
+ }
+ string item;
+ pos = q->find_first_not_of(" \t\r\n", pos);
+ if(pos != string::npos)
+ {
+ item = q->substr(pos);
+ }
+
+ start("dt", "Symbol");
+ _out << term;
+ end();
+ start("dd");
+ _out << nl << item;
+ end();
+ }
+ end();
+ end();
+ }
+
+ if(!ret.empty())
+ {
+ if(!startedList)
+ {
+ start("dl");
+ startedList = true;
+ }
+ start("dt");
+ _out << "Return Value";
+ end();
+ start("dd", "Symbol");
+ _out << ret.front();
+ end();
+ }
+
+
+ if(!throws.empty())
+ {
+ if(!startedList)
+ {
+ start("dl");
+ startedList = true;
+ }
+ start("dt", "Heading");
+ _out << "Exceptions";
+ end();
+ start("dd");
+ start("dl");
+ for(StringList::const_iterator q = throws.begin(); q != throws.end(); ++q)
+ {
+ string term;
+ pos = q->find_first_of(" \t\r\n");
+ if(pos != string::npos)
+ {
+ term = q->substr(0, pos);
+ }
+ string item;
+ pos = q->find_first_not_of(" \t\r\n", pos);
+ if(pos != string::npos)
+ {
+ item = q->substr(pos);
+ }
+
+ start("dt", "Symbol");
+ _out << toString(term, container);
+ end();
+ start("dd");
+ _out << nl << item;
+ end();
+ }
+ end();
+ end();
+ }
+
+
+ ClassList derivedClasses;
+ ClassDefPtr def = ClassDefPtr::dynamicCast(p);
+ if(def)
+ {
+ derivedClasses = p->unit()->findDerivedClasses(def);
+ }
+ if(!derivedClasses.empty())
+ {
+ if(!startedList)
+ {
+ start("dl");
+ startedList = true;
+ }
+ start("dt", "Heading");
+ _out << "Derived Classes and Interfaces";
+ end();
+ start("dd");
+ start("dl");
+ for(ClassList::const_iterator q = derivedClasses.begin(); q != derivedClasses.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, container);
+ end();
+ }
+ end();
+ end();
+ }
+
+ ExceptionList derivedExceptions;
+ ExceptionPtr ex = ExceptionPtr::dynamicCast(p);
+ if(ex)
+ {
+ derivedExceptions = p->unit()->findDerivedExceptions(ex);
+ if(!derivedExceptions.empty())
+ {
+ if(!startedList)
+ {
+ start("dl");
+ startedList = true;
+ }
+ start("dt", "Heading");
+ _out << "Derived Exceptions";
+ end();
+ start("dd");
+ start("dl");
+ for(ExceptionList::const_iterator q = derivedExceptions.begin(); q != derivedExceptions.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, container);
+ end();
+ }
+ end();
+ end();
+ }
+
+ ContainedList usedBy;
+ usedBy = p->unit()->findUsedBy(ex);
+ if(!usedBy.empty())
+ {
+ if(!startedList)
+ {
+ start("dl");
+ startedList = true;
+ }
+ start("dt", "Heading");
+ _out << "Used By";
+ end();
+ start("dd");
+ start("dl", "UsedBy");
+ //
+ // We first extract the symbol names from the used-by list and sort
+ // them, otherwise the symbols appear in random order.
+ //
+ StringList sl;
+ for(ContainedList::const_iterator q = usedBy.begin(); q != usedBy.end(); ++q)
+ {
+ sl.push_back(toString(*q, container));
+ }
+ sl.sort();
+ for(StringList::const_iterator r = sl.begin(); r != sl.end(); ++r)
+ {
+ start("dt", "Symbol");
+ _out << *r;
+ end();
+ }
+ end();
+ end();
+ }
+ }
+
+ ContainedList usedBy;
+ ConstructedPtr constructed;
+ if(def)
+ {
+ constructed = def->declaration();
+ }
+ else
+ {
+ constructed = ConstructedPtr::dynamicCast(p);
+ }
+ if(constructed)
+ {
+ usedBy = p->unit()->findUsedBy(constructed);
+ }
+ if(!usedBy.empty())
+ {
+ //
+ // We first accumulate the strings in a list instead of printing
+ // each stringified entry in the usedBy list. This is necessary because
+ // the usedBy list can contain operations and parameters. But toString()
+ // on a parameter returns the string for the parameter's operation, so
+ // we can end up printing the same operation name more than once.
+ //
+ StringList strings;
+ for(ContainedList::const_iterator q = usedBy.begin(); q != usedBy.end(); ++q)
+ {
+ strings.push_back(toString(*q, container));
+ }
+ strings.sort();
+ strings.unique();
+
+ if(!startedList)
+ {
+ start("dl");
+ startedList = true;
+ }
+ start("dt", "Heading");
+ _out << "Used By";
+ end();
+ start("dd");
+ start("dl", "UsedBy");
+ for(list<string>::const_iterator p = strings.begin(); p != strings.end(); ++p)
+ {
+ start("dt", "Symbol");
+ _out << *p;
+ end();
+ }
+ end();
+ end();
+ }
+
+ if(!see.empty())
+ {
+ if(!startedList)
+ {
+ start("dl");
+ startedList = true;
+ }
+ start("dt", "Heading");
+ _out << "See Also";
+ end();
+ start("dd");
+ start("dl", "UsedBy");
+ for(StringList::const_iterator q = see.begin(); q != see.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, container);
+ end();
+ }
+ end();
+ end();
+ }
+
+ if(startedList)
+ {
+ end();
+ }
+
+ assert(_out.currIndent() == indent);
+}
+
+void
+Slice::GeneratorBase::printMetaData(const ContainedPtr& p)
+{
+ list<string> metaData = p->getMetaData();
+
+ if(!metaData.empty())
+ {
+ _out << "[";
+ list<string>::const_iterator q = metaData.begin();
+ while(q != metaData.end())
+ {
+ _out << " \"" << *q << "\"";
+ if(++q != metaData.end())
+ {
+ _out << ",";
+ }
+ }
+ _out << " ]" << nl;
+ }
+}
+
+void
+Slice::GeneratorBase::printSummary(const ContainedPtr& p, bool deprecated)
+{
+ ContainerPtr container = ContainerPtr::dynamicCast(p);
+ if(!container)
+ {
+ container = p->container();
+ }
+
+ string summary = getComment(p, container, true);
+ start("dd", "Summary");
+ _out << nl << summary;
+ end();
+
+ if(deprecated)
+ {
+ start("dd", "Deprecated");
+ _out << nl << "Deprecated.";
+ end();
+ }
+}
+
+string
+Slice::GeneratorBase::toString(const SyntaxTreeBasePtr& p, const ContainerPtr& container, bool asTarget)
+{
+ string linkend;
+ string s;
+
+ static const char* builtinTable[] =
+ {
+ "byte",
+ "bool",
+ "short",
+ "int",
+ "long",
+ "float",
+ "double",
+ "string",
+ "Object",
+ "Object*",
+ "LocalObject"
+ };
+
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(p);
+ if(builtin)
+ {
+ s = builtinTable[builtin->kind()];
+ }
+
+ ProxyPtr proxy = ProxyPtr::dynamicCast(p);
+ if(proxy)
+ {
+ if(proxy->_class()->includeLevel() == 0)
+ {
+ linkend = containedToId(proxy->_class(), asTarget);
+ }
+ s = getScopedMinimized(proxy->_class(), container);
+ s += "*";
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(p);
+ if(cl)
+ {
+ //
+ // We must generate the id from the definition, not from the
+ // declaration, provided that a definition is available.
+ //
+ ContainedPtr definition = cl->definition();
+ if(definition && definition->includeLevel() == 0)
+ {
+ linkend = containedToId(definition, asTarget);
+ }
+ s = getScopedMinimized(cl, container);
+ }
+
+ ExceptionPtr ex = ExceptionPtr::dynamicCast(p);
+ if(ex)
+ {
+ if(ex->includeLevel() == 0)
+ {
+ linkend = containedToId(ex, asTarget);
+ }
+ s = getScopedMinimized(ex, container);
+ }
+
+ StructPtr st = StructPtr::dynamicCast(p);
+ if(st)
+ {
+ if(st->includeLevel() == 0)
+ {
+ linkend = containedToId(st, asTarget);
+ }
+ s = getScopedMinimized(st, container);
+ }
+
+ EnumeratorPtr en = EnumeratorPtr::dynamicCast(p);
+ if(en)
+ {
+ if(en->includeLevel() == 0)
+ {
+ linkend = containedToId(en, asTarget);
+ }
+ s = getScopedMinimized(en, container);
+ }
+
+ OperationPtr op = OperationPtr::dynamicCast(p);
+ if(op)
+ {
+ if(op->includeLevel() == 0)
+ {
+ linkend = containedToId(op, asTarget);
+ }
+ s = getScopedMinimized(op, container);
+ }
+
+ ParamDeclPtr pd = ParamDeclPtr::dynamicCast(p);
+ if(pd)
+ {
+ op = OperationPtr::dynamicCast(pd->container());
+ assert(op);
+ if(pd->includeLevel() == 0)
+ {
+ linkend = containedToId(op, asTarget);
+ }
+ s = getScopedMinimized(op, container);
+ }
+
+ if(s.empty())
+ {
+ ContainedPtr contained = ContainedPtr::dynamicCast(p);
+ assert(contained);
+ if(contained->includeLevel() == 0)
+ {
+ linkend = containedToId(contained, asTarget);
+ }
+ s = getScopedMinimized(contained, container);
+ }
+
+ if(linkend.empty())
+ {
+ return s;
+ }
+ else
+ {
+ string ret = "<a ";
+ ret += asTarget ? "name" : "href";
+ ret += "=" + linkend + + ">" + s + "</a>";
+ return ret;
+ }
+}
+
+string
+Slice::GeneratorBase::toString(const string& str, const ContainerPtr& container, bool asTarget)
+{
+ string s = str;
+
+ TypeList types = container->lookupType(s, false);
+ if(!types.empty())
+ {
+ return toString(types.front(), container, asTarget);
+ }
+
+ ContainedList contList = container->lookupContained(s, false);
+ if(!contList.empty())
+ {
+ return toString(contList.front(), container, asTarget);
+ }
+
+ //
+ // If we can't find the string, printing it in typewriter
+ // font is the best we can do.
+ //
+ return "<span class=Symbol>" + s + "</span>";
+}
+
+StringList
+Slice::GeneratorBase::getTagged(const string& tag, string& comment)
+{
+ StringList result;
+ string::size_type begin = 0;
+ while(begin < comment.size())
+ {
+ begin = comment.find("@" + tag, begin);
+ if(begin == string::npos)
+ {
+ return result;
+ }
+
+ string::size_type pos1 = comment.find_first_not_of(" \t\r\n", begin + tag.size() + 1);
+ if(pos1 == string::npos)
+ {
+ comment.erase(begin);
+ return result;
+ }
+
+ string::size_type pos2 = comment.find('@', pos1);
+ string line = comment.substr(pos1, pos2 - pos1);
+ comment.erase(begin, pos2 - 1 - begin);
+
+ string::size_type pos3 = line.find_last_not_of(" \t\r\n");
+ if(pos3 != string::npos)
+ {
+ line.erase(pos3 + 1);
+ }
+ result.push_back(line);
+ }
+
+ return result;
+}
+
+#if 0
+string
+Slice::GeneratorBase::getScopedMinimized(const ContainedPtr& contained, const ContainerPtr& container)
+{
+ cerr << "contained is " << contained->scoped() << endl;
+ cerr << "container is " << ContainedPtr::dynamicCast(container)->scoped() << endl;
+ StringList anchors;
+ ContainedPtr c = contained;
+ while(!ExceptionPtr::dynamicCast(c) &&
+ !ClassDeclPtr::dynamicCast(c) &&
+ !ClassDefPtr::dynamicCast(c) &&
+ !StructPtr::dynamicCast(c) &&
+ !ModulePtr::dynamicCast(c))
+ {
+ cerr << "Pushing " << c->name() << endl;
+ anchors.push_front(c->name());
+ c = ContainedPtr::dynamicCast(c->container());
+ }
+
+ cerr << "c is " << ContainedPtr::dynamicCast(c)->scoped() << endl;
+#if 0
+ StringList from = toStringList(contained);
+ StringList to = toStringList(ContainedPtr::dynamicCast(container));
+
+ StringList::const_iterator f = from.begin();
+ StringList::const_iterator t = to.begin();
+ while(f != from.end() && t != to.end())
+ {
+ }
+#endif
+ cerr << "returning" << endl;
+ return "";
+}
+#endif
+
+string
+Slice::GeneratorBase::getScopedMinimized(const ContainedPtr& contained, const ContainerPtr& container)
+{
+ cerr << "get" << endl;
+ cerr << "contained: " << contained->scoped() << endl;
+ if(container)
+ {
+ cerr << "container: " << ContainedPtr::dynamicCast(container)->scoped() << endl;
+ }
+ string s = contained->scoped();
+ ContainerPtr p = container;
+ ContainedPtr q = ContainedPtr::dynamicCast(p);
+
+ if(!q) // Container is the global module
+ {
+ return s.substr(2);
+ }
+
+ do
+ {
+ string s2 = q->scoped();
+ s2 += "::";
+
+ if(s.find(s2) == 0)
+ {
+ return s.substr(s2.size());
+ }
+
+ p = q->container();
+ q = ContainedPtr::dynamicCast(p);
+ }
+ while(q);
+
+ return s;
+}
+
+string
+Slice::GeneratorBase::containedToId(const ContainedPtr& contained, bool asTarget)
+{
+ assert(contained);
+
+ string scoped = contained->scoped();
+ if(scoped[0] == ':')
+ {
+ scoped.erase(0, 2);
+ }
+
+ string id;
+ id.reserve(scoped.size());
+
+ for(unsigned int i = 0; i < scoped.size(); ++i)
+ {
+ if(scoped[i] == ':')
+ {
+ id += '.';
+ ++i;
+ }
+ else
+ {
+ id += scoped[i];
+ }
+ }
+
+ //
+ // A link name cannot start with a period.
+ //
+ if(id[0] == '.')
+ {
+ id.erase(0, 1);
+ }
+
+ return '"' + id + '"';
+}
+
+void
+Slice::GeneratorBase::openStream(const string& path)
+{
+ _out.open(path.c_str());
+ if(!_out.isOpen())
+ {
+ string err = "cannot open `" + path + "' for writing";
+ throw err;
+ }
+}
+
+StringList
+Slice::GeneratorBase::toStringList(const ContainedPtr& c)
+{
+ string scoped = c->scoped();
+ assert(scoped.size() > 2);
+ assert(scoped[0] == ':');
+ assert(scoped[1] == ':');
+
+ StringList ids;
+ string::size_type next = 2;
+ string::size_type endpos;
+ while((endpos = scoped.find("::", next)) != string::npos)
+ {
+ ids.push_back(scoped.substr(next, endpos - next));
+ next = endpos;
+ if(next != string::npos)
+ {
+ ++next;
+ ++next;
+ }
+ }
+ ids.push_back(scoped.substr(next));
+
+ return ids;
+}
+
+void
+Slice::GeneratorBase::makeDir(const string& dir)
+{
+ struct stat st;
+ int rc = stat(dir.c_str(), &st);
+ if(rc == 0)
+ {
+ return;
+ }
+#ifdef _WIN32
+ rc = mkdir(dir.c_str())
+#else
+ rc = mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+#endif
+ if(rc != 0)
+ {
+ string err = "cannot create directory `" + dir + "'";
+ throw err;
+ }
+}
+
+string
+Slice::GeneratorBase::readFile(const string& file)
+{
+ ifstream in(file.c_str());
+ if(!in)
+ {
+ string err = "cannot open `" + file + "' for reading";
+ throw err;
+ }
+
+ ostringstream result;
+ string line;
+ getline(in, line);
+ while(!line.empty())
+ {
+ result << line << '\n';
+ getline(in, line);
+ }
+
+ return result.str();
+}
+
+void
+Slice::GeneratorBase::readFile(const string& file, string& part1, string& part2)
+{
+ ifstream in(file.c_str());
+ if(!in)
+ {
+ string err = "cannot open `" + file + "' for reading";
+ throw err;
+ }
+
+ string line;
+
+ ostringstream p1;
+ getline(in, line);
+ while(!line.empty() && line != "TITLE")
+ {
+ p1 << line << '\n';
+ getline(in, line);
+ }
+ part1 = p1.str();
+
+ if(line.empty())
+ {
+ string err = "no TITLE marker in `" + file + "'";
+ throw err;
+ }
+
+ ostringstream p2;
+ p2 << endl;
+ getline(in, line);
+ while(!line.empty())
+ {
+ p2 << line << '\n';
+ getline(in, line);
+ }
+ part2 = p2.str();
+}
+
+Slice::IndexGenerator::IndexGenerator()
+ : GeneratorBase(_out)
+{
+ openDoc("index.html", "Slice Documentation Index");
+}
+
+Slice::IndexGenerator::~IndexGenerator()
+{
+ ::std::sort(_modules.begin(), _modules.end());
+
+ start("dl");
+ start("dt");
+ _out << "Modules";
+ end();
+ start("dd");
+ start("dl");
+ for(ModuleDescriptions::const_iterator i = _modules.begin(); i != _modules.end(); ++i)
+ {
+ start("dt");
+ _out << i->first;
+ end();
+ start("dd");
+ _out << i->second;
+ end();
+ }
+ end();
+ end();
+ end();
+
+ closeDoc();
+}
+
+void
+Slice::IndexGenerator::generate(const ModulePtr& m)
+{
+ string name = toString(m, 0, false);
+ string comment = getComment(m, 0, true);
+ _modules.push_back(make_pair(name, comment));
+}
+
+Slice::IndexVisitor::IndexVisitor()
+{
+}
+
+bool
+Slice::IndexVisitor::visitUnitStart(const UnitPtr& unit)
+{
+ return true;
+}
+
+bool
+Slice::IndexVisitor::visitModuleStart(const ModulePtr& m)
+{
+ _ig.generate(m);
+ return false;
+}
+
+Slice::ModuleGenerator::ModuleGenerator(XMLOutput& o)
+ : GeneratorBase(o)
+{
+}
+
+void
+Slice::ModuleGenerator::generate(const ModulePtr& m)
+{
+#ifndef NDEBUG
+ int indent = _out.currIndent();
+#endif
+
+ openDoc(m);
+
+ start("dl");
+ start("dt", "Symbol");
+ _out << m->name();
+ end();
+
+ start("dd");
+ start("dl");
+ string metadata, deprecateReason;
+ if(m->findMetaData("deprecate", metadata))
+ {
+ deprecateReason = "This module is deprecated.";
+ if(metadata.find("deprecate:") == 0 && metadata.size() > 10)
+ {
+ deprecateReason = metadata.substr(10);
+ }
+ }
+ start("dt", "Heading");
+ _out << "Overview";
+ end();
+ start("dd");
+ start("dl");
+ start("dt");
+ start("span", "Synopsis");
+ printMetaData(m);
+ _out << "module " << m->name();
+ end();
+ end();
+ start("dd");
+ printComment(m, deprecateReason);
+ end();
+ end();
+
+ visitContainer(m);
+
+ end();
+ end();
+ end();
+ end();
+
+ closeDoc();
+
+ assert(_out.currIndent() == indent);
+}
+
+void
+Slice::ModuleGenerator::visitContainer(const ContainerPtr& p)
+{
+#ifndef NDEBUG
+ int indent = _out.currIndent();
+#endif
+
+ ModuleList modules = p->modules();
+ modules.erase(remove_if(modules.begin(), modules.end(), ::IceUtil::constMemFun(&Contained::includeLevel)),
+ modules.end());
+
+ if(_indexCount > 0 && modules.size() >= _indexCount)
+ {
+ start("dt", "Heading");
+ _out << "Module Index";
+ end();
+ start("dd");
+ start("dl");
+ for(ModuleList::const_iterator q = modules.begin(); q != modules.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, p);
+ end();
+ start("dd");
+ string metadata;
+ printSummary(*q, (*q)->findMetaData("deprecate", metadata));
+ end();
+ }
+ end();
+ end();
+ }
+
+ assert(_out.currIndent() == indent);
+
+ ClassList classesAndInterfaces = p->classes();
+ classesAndInterfaces.erase(remove_if(classesAndInterfaces.begin(), classesAndInterfaces.end(),
+ ::IceUtil::constMemFun(&Contained::includeLevel)),
+ classesAndInterfaces.end());
+ ClassList classes;
+ ClassList interfaces;
+ remove_copy_if(classesAndInterfaces.begin(), classesAndInterfaces.end(), back_inserter(classes),
+ ::IceUtil::constMemFun(&ClassDef::isInterface));
+ remove_copy_if(classesAndInterfaces.begin(), classesAndInterfaces.end(), back_inserter(interfaces),
+ not1(::IceUtil::constMemFun(&ClassDef::isInterface)));
+
+ if(_indexCount > 0 && classes.size() >= _indexCount)
+ {
+ start("dt", "Heading");
+ _out << "Class Index";
+ end();
+ start("dd");
+ start("dl");
+ for(ClassList::const_iterator q = classes.begin(); q != classes.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, p);
+ end();
+ start("dd");
+ string metadata;
+ printSummary(*q, (*q)->findMetaData("deprecate", metadata));
+ end();
+ }
+ end();
+ end();
+ }
+
+ assert(_out.currIndent() == indent);
+
+ if(_indexCount > 0 && interfaces.size() >= _indexCount)
+ {
+ start("dt", "Heading");
+ _out << "Interface Index";
+ end();
+ start("dd");
+ start("dl");
+ for(ClassList::const_iterator q = interfaces.begin(); q != interfaces.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, p);
+ end();
+ start("dd");
+ string metadata;
+ printSummary(*q, (*q)->findMetaData("deprecate", metadata));
+ end();
+ }
+ end();
+ end();
+ }
+
+ assert(_out.currIndent() == indent);
+
+ ExceptionList exceptions = p->exceptions();
+ exceptions.erase(remove_if(exceptions.begin(), exceptions.end(), ::IceUtil::constMemFun(&Contained::includeLevel)),
+ exceptions.end());
+
+ if(_indexCount > 0 && exceptions.size() >= _indexCount)
+ {
+ start("dt", "Heading");
+ _out << "Exception Index";
+ end();
+ start("dd");
+ start("dl");
+ for(ExceptionList::const_iterator q = exceptions.begin(); q != exceptions.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, p);
+ end();
+ start("dd");
+ string metadata;
+ printSummary(*q, (*q)->findMetaData("deprecate", metadata));
+ end();
+ }
+ end();
+ end();
+ }
+
+ assert(_out.currIndent() == indent);
+
+ StructList structs = p->structs();
+ structs.erase(remove_if(structs.begin(), structs.end(), ::IceUtil::constMemFun(&Contained::includeLevel)),
+ structs.end());
+
+ if(_indexCount > 0 && structs.size() >= _indexCount)
+ {
+ start("dt", "Heading");
+ _out << "Structure Index";
+ end();
+ start("dd");
+ start("dl");
+ for(StructList::const_iterator q = structs.begin(); q != structs.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, p);
+ end();
+ start("dd");
+ string metadata;
+ printSummary(*q, (*q)->findMetaData("deprecate", metadata));
+ end();
+ }
+ end();
+ end();
+ }
+
+ assert(_out.currIndent() == indent);
+
+ SequenceList sequences = p->sequences();
+ sequences.erase(remove_if(sequences.begin(), sequences.end(), ::IceUtil::constMemFun(&Contained::includeLevel)),
+ sequences.end());
+
+ if(_indexCount > 0 && sequences.size() >= _indexCount)
+ {
+ start("dt", "Heading");
+ _out << "Sequence Index";
+ end();
+ start("dd");
+ start("dl");
+ for(SequenceList::const_iterator q = sequences.begin(); q != sequences.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, p);
+ end();
+ start("dd");
+ string metadata;
+ printSummary(*q, (*q)->findMetaData("deprecate", metadata));
+ end();
+ }
+ end();
+ end();
+ }
+
+ assert(_out.currIndent() == indent);
+
+ DictionaryList dictionaries = p->dictionaries();
+ dictionaries.erase(remove_if(dictionaries.begin(), dictionaries.end(),
+ ::IceUtil::constMemFun(&Contained::includeLevel)),
+ dictionaries.end());
+
+ if(_indexCount > 0 && dictionaries.size() >= _indexCount)
+ {
+ start("dt", "Heading");
+ _out << "Dictionary Index";
+ end();
+ start("dd");
+ start("dl");
+ for(DictionaryList::const_iterator q = dictionaries.begin(); q != dictionaries.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, p);
+ end();
+ start("dd");
+ string metadata;
+ printSummary(*q, (*q)->findMetaData("deprecate", metadata));
+ end();
+ }
+ end();
+ end();
+ }
+
+ assert(_out.currIndent() == indent);
+
+ EnumList enums = p->enums();
+ enums.erase(remove_if(enums.begin(), enums.end(), ::IceUtil::constMemFun(&Contained::includeLevel)),
+ enums.end());
+
+ if(_indexCount > 0 && enums.size() >= _indexCount)
+ {
+ start("dt", "Heading");
+ _out << "Enumeration Index";
+ end();
+ start("dd");
+ start("dl");
+ for(EnumList::const_iterator q = enums.begin(); q != enums.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, p);
+ end();
+ start("dd");
+ string metadata;
+ printSummary(*q, (*q)->findMetaData("deprecate", metadata));
+ end();
+ }
+ end();
+ end();
+ }
+
+ assert(_out.currIndent() == indent);
+
+ if(!sequences.empty())
+ {
+ start("dt", "Heading");
+ _out << "Sequences";
+ end();
+ start("dd");
+ for(SequenceList::const_iterator q = sequences.begin(); q != sequences.end(); ++q)
+ {
+ start("dl");
+ start("dt");
+ start("span", "Synopsis");
+ printMetaData(*q);
+ if((*q)->isLocal())
+ {
+ _out << "local ";
+ }
+ TypePtr type = (*q)->type();
+ _out << "sequence&lt;" << toString(type, p) << "&gt; " << (*q)->name();
+ end();
+ end();
+
+ start("dd");
+ string metadata, deprecateReason;
+ if((*q)->findMetaData("deprecate", metadata))
+ {
+ deprecateReason = "This type is deprecated.";
+ if(metadata.find("deprecate:") == 0 && metadata.size() > 10)
+ {
+ deprecateReason = metadata.substr(10);
+ }
+ }
+
+ printComment(*q, deprecateReason);
+ end();
+ end();
+ }
+ end();
+ }
+
+ if(!dictionaries.empty())
+ {
+ start("dt", "Heading");
+ _out << "Dictionaries";
+ end();
+ start("dd");
+ for(DictionaryList::const_iterator q = dictionaries.begin(); q != dictionaries.end(); ++q)
+ {
+ start("dl");
+ start("dt");
+ start("span", "Synopsis");
+ printMetaData(*q);
+ if((*q)->isLocal())
+ {
+ _out << "local ";
+ }
+ TypePtr keyType = (*q)->keyType();
+ TypePtr valueType = (*q)->valueType();
+ _out << "dictionary&lt;" << toString(keyType, p) << ", " << toString(valueType, p) << "&gt; "
+ << (*q)->name();
+ end();
+ end();
+
+ start("dd");
+ string metadata, deprecateReason;
+ if((*q)->findMetaData("deprecate", metadata))
+ {
+ deprecateReason = "This type is deprecated.";
+ if(metadata.find("deprecate:") == 0 && metadata.size() > 10)
+ {
+ deprecateReason = metadata.substr(10);
+ }
+ }
+
+ printComment(*q, deprecateReason);
+ end();
+ end();
+ }
+ end();
+ }
+}
+
+Slice::ExceptionGenerator::ExceptionGenerator(XMLOutput& o)
+ : GeneratorBase(o)
+{
+}
+
+void
+Slice::ExceptionGenerator::generate(const ExceptionPtr& e)
+{
+#ifndef NDEBUG
+ int indent = _out.currIndent();
+#endif
+
+ openDoc(e);
+
+ start("dl");
+ start("dt", "Symbol, Heading");
+ _out << e->name();
+ end();
+
+ string metadata, deprecateReason;
+ bool deprecatedException = e->findMetaData("deprecate", metadata);
+ if(deprecatedException)
+ {
+ deprecateReason = "This module is deprecated.";
+ if(metadata.find("deprecate:") == 0 && metadata.size() > 10)
+ {
+ deprecateReason = metadata.substr(10);
+ }
+ }
+
+ start("dd");
+ start("dl");
+ start("dt", "Heading");
+ _out << "Overview";
+ end();
+
+ start("dd");
+ start("dl");
+ start("dt");
+ start("span", "Synopsis");
+ printMetaData(e);
+ if(e->isLocal())
+ {
+ _out << "local ";
+ }
+ _out << "exception " << e->name();
+ ExceptionPtr base = e->base();
+ if(base)
+ {
+ _out.inc();
+ _out << nl << "extends ";
+ _out.inc();
+ _out << nl << toString(base, e);
+ _out.dec();
+ _out.dec();
+ }
+ end();
+ end();
+ start("dd");
+ printComment(e, deprecateReason);
+ end();
+ end();
+
+ DataMemberList dataMembers = e->dataMembers();
+ if(!dataMembers.empty())
+ {
+ start("dt", "Heading");
+ _out << "Data Members";
+ end();
+ start("dd");
+ start("dl");
+ for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
+ {
+ start("dt", "Symbol");
+ printMetaData(*q);
+ TypePtr type = (*q)->type();
+ _out << toString(type, e) << " " << (*q)->name() << ";";
+ end();
+
+ start("dd");
+ string reason;
+ metadata.clear();
+ if(deprecatedException || (*q)->findMetaData("deprecate", metadata))
+ {
+ reason = "This member is deprecated.";
+ if(metadata.find("deprecate:") == 0 && metadata.size() > 10)
+ {
+ reason = metadata.substr(10);
+ }
+ }
+
+ printComment(*q, reason);
+ end();
+ }
+ end();
+ end();
+ }
+ end();
+ end();
+ end();
+ end();
+
+ closeDoc();
+
+ assert(_out.currIndent() == indent);
+}
+
+Slice::ClassGenerator::ClassGenerator(XMLOutput& o)
+ : GeneratorBase(o)
+{
+}
+
+void
+Slice::ClassGenerator::generate(const ClassDefPtr& c)
+{
+#ifndef NDEBUG
+ int indent = _out.currIndent();
+#endif
+
+ openDoc(c);
+
+ start("dl");
+ start("dt", "Symbol");
+ _out << c->name();
+ end();
+
+ string metadata, deprecateReason;
+ bool deprecatedClass = c->findMetaData("deprecate", metadata);
+ if(deprecatedClass)
+ {
+ deprecateReason = "This ";
+ deprecateReason += c->isInterface() ? "interface" : "class";
+ deprecateReason += " is deprecated.";
+ if(metadata.find("deprecate:") == 0 && metadata.size() > 10)
+ {
+ deprecateReason = metadata.substr(10);
+ }
+ }
+
+ start("dd");
+ start("dl");
+ start("dt", "Heading");
+ _out << "Overview";
+ end();
+ start("dd");
+ start("dl");
+ start("dt");
+ start("span", "Synopsis");
+ printMetaData(c);
+ if(c->isLocal())
+ {
+ _out << "local ";
+ }
+ _out << (c->isInterface() ? "interface" : "class" )<< " " << c->name();
+
+ ClassList bases = c->bases();
+ if(!bases.empty() && !bases.front()->isInterface())
+ {
+ _out << " extends " << toString(bases.front(), c);
+ bases.pop_front();
+ }
+
+ if(!bases.empty())
+ {
+ _out << (c->isInterface() ? " extends " : " implements ");
+ ClassList::const_iterator q = bases.begin();
+ while(q != bases.end())
+ {
+ _out << toString(*q, c);
+ if(++q != bases.end())
+ {
+ _out << ", ";
+ }
+ }
+ }
+ end();
+ end();
+
+ start("dd");
+ printComment(c, deprecateReason);
+ end();
+ end();
+ end();
+
+ OperationList operations = c->operations();
+ if(!operations.empty())
+ {
+ start("dt", "Heading");
+ _out << "Operations";
+ end();
+ start("dd");
+ start("dl");
+ for(OperationList::const_iterator q = operations.begin(); q != operations.end(); ++q)
+ {
+ start("dt");
+ start("span", "Synopsis");
+ TypePtr returnType = (*q)->returnType();
+ _out << (returnType ? toString(returnType, c) : string("void")) << " "<< (*q)->name() << "(";
+ ParamDeclList params = (*q)->parameters();
+ ParamDeclList::const_iterator r = params.begin();
+ while(r != params.end())
+ {
+ if((*r)->isOutParam())
+ {
+ _out << "out ";
+ }
+ _out << toString((*r)->type(), *q) << " " << (*r)->name();
+ if(++r != params.end())
+ {
+ _out << ", ";
+ }
+ }
+ _out << ")";
+ ExceptionList throws = (*q)->throws();
+ if(!throws.empty())
+ {
+ _out << " throws ";
+ ExceptionList::const_iterator t = throws.begin();
+ while(t != throws.end())
+ {
+ _out << toString(*t, c);
+ if(++t != throws.end())
+ {
+ _out << ", ";
+ }
+ }
+ }
+ end();
+ end();
+
+ start("dd");
+ string reason;
+ metadata.clear();
+ if(deprecatedClass || (*q)->findMetaData("deprecate", metadata))
+ {
+ reason = "This operation is deprecated.";
+ if(metadata.find("deprecate:") == 0 && metadata.size() > 10)
+ {
+ reason = metadata.substr(10);
+ }
+ }
+ printComment(*q, reason);
+ end();
+ }
+ end();
+ end();
+ }
+
+ DataMemberList dataMembers = c->dataMembers();
+ if(!dataMembers.empty())
+ {
+ start("dl");
+ start("dt", "Heading");
+ _out << "Data Members";
+ end();
+ start("dl");
+ for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
+ {
+ start("dt");
+ start("span", "Synopsis");
+ printMetaData(*q);
+ TypePtr type = (*q)->type();
+ _out << toString(type, c) << " " << (*q)->name() << ";";
+ end();
+ end();
+
+ start("dd");
+ string reason;
+ metadata.clear();
+ if(deprecatedClass || (*q)->findMetaData("deprecate", metadata))
+ {
+ reason = "This member is deprecated.";
+ if(metadata.find("deprecate:") == 0 && metadata.size() > 10)
+ {
+ reason = metadata.substr(10);
+ }
+ }
+
+ printComment(*q, reason);
+ end();
+ }
+ end();
+ end();
+ }
+
+ end();
+ end();
+ end();
+
+ closeDoc();
+
+ assert(_out.currIndent() == indent);
+}
+
+Slice::StructGenerator::StructGenerator(XMLOutput& o)
+ : GeneratorBase(o)
+{
+}
+
+void
+Slice::StructGenerator::generate(const StructPtr& s)
+{
+#ifndef NDEBUG
+ int indent = _out.currIndent();
+#endif
+
+ openDoc(s);
+
+ start("dl");
+ start("dt", "Symbol, Heading");
+ _out << s->name();
+ end();
+
+ string metadata, deprecateReason;
+ bool deprecatedException = s->findMetaData("deprecate", metadata);
+ if(deprecatedException)
+ {
+ deprecateReason = "This module is deprecated.";
+ if(metadata.find("deprecate:") == 0 && metadata.size() > 10)
+ {
+ deprecateReason = metadata.substr(10);
+ }
+ }
+
+ start("dd");
+ start("dl");
+ start("dt", "Heading");
+ _out << "Overview";
+ end();
+
+ start("dd");
+ start("dl");
+ start("dt");
+ start("span", "Synopsis");
+ printMetaData(s);
+ if(s->isLocal())
+ {
+ _out << "local ";
+ }
+ _out << "struct " << s->name();
+ end();
+ end();
+ start("dd");
+ printComment(s, deprecateReason);
+ end();
+ end();
+
+ DataMemberList dataMembers = s->dataMembers();
+ if(!dataMembers.empty())
+ {
+ start("dt", "Heading");
+ _out << "Data Members";
+ end();
+ start("dd");
+ start("dl");
+ for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
+ {
+ start("dt", "Symbol");
+ printMetaData(*q);
+ TypePtr type = (*q)->type();
+ _out << toString(type, s) << " " << (*q)->name() << ";";
+ end();
+
+ start("dd");
+ string reason;
+ metadata.clear();
+ if(deprecatedException || (*q)->findMetaData("deprecate", metadata))
+ {
+ reason = "This member is deprecated.";
+ if(metadata.find("deprecate:") == 0 && metadata.size() > 10)
+ {
+ reason = metadata.substr(10);
+ }
+ }
+
+ printComment(*q, reason);
+ end();
+ }
+ end();
+ end();
+ }
+ end();
+ end();
+ end();
+ end();
+
+ closeDoc();
+
+ assert(_out.currIndent() == indent);
+}
+
+Slice::EnumGenerator::EnumGenerator(XMLOutput& o)
+ : GeneratorBase(o)
+{
+}
+
+void
+Slice::EnumGenerator::generate(const EnumPtr& e)
+{
+#ifndef NDEBUG
+ int indent = _out.currIndent();
+#endif
+
+ openDoc(e);
+
+ start("dl");
+ start("dt", "Symbol, Heading");
+ _out << e->name();
+ end();
+
+ string metadata, deprecateReason;
+ bool deprecatedException = e->findMetaData("deprecate", metadata);
+ if(deprecatedException)
+ {
+ deprecateReason = "This enumeration is deprecated.";
+ if(metadata.find("deprecate:") == 0 && metadata.size() > 10)
+ {
+ deprecateReason = metadata.substr(10);
+ }
+ }
+
+ start("dd");
+ start("dl");
+ start("dt", "Heading");
+ _out << "Overview";
+ end();
+
+ start("dd");
+ start("dl");
+ start("dt");
+ start("span", "Synopsis");
+ printMetaData(e);
+ if(e->isLocal())
+ {
+ _out << "local ";
+ }
+ _out << "enum " << e->name();
+ end();
+ end();
+
+ start("dd");
+ printComment(e, deprecateReason);
+ end();
+ end();
+
+ EnumeratorList enumerators = e->getEnumerators();
+ if(!enumerators.empty())
+ {
+ start("dt", "Heading");
+ _out << "Enumerators";
+ end();
+ start("dd");
+ start("dl");
+ for(EnumeratorList::const_iterator q = enumerators.begin(); q != enumerators.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << (*q)->name();
+ end();
+
+ start("dd");
+ string reason;
+ //
+ // Enumerators do not support metadata.
+ //
+ printComment(*q, reason);
+ end();
+ }
+ end();
+ end();
+ }
+ end();
+ end();
+ end();
+ end();
+
+ closeDoc();
+
+ assert(_out.currIndent() == indent);
+}
+
+Slice::Visitor::Visitor()
+{
+}
+
+bool
+Slice::Visitor::visitUnitStart(const UnitPtr& unit)
+{
+ return true;
+}
+
+bool
+Slice::Visitor::visitModuleStart(const ModulePtr& m)
+{
+ XMLOutput O;
+ ModuleGenerator mg(O);
+ mg.generate(m);
+ return true;
+}
+
+bool
+Slice::Visitor::visitExceptionStart(const ExceptionPtr& e)
+{
+ XMLOutput O;
+ ExceptionGenerator eg(O);
+ eg.generate(e);
+ return true;
+}
+
+bool
+Slice::Visitor::visitClassDefStart(const ClassDefPtr& c)
+{
+ XMLOutput O;
+ ClassGenerator cg(O);
+ cg.generate(c);
+ return true;
+}
+
+bool
+Slice::Visitor::visitStructStart(const StructPtr& s)
+{
+ XMLOutput O;
+ StructGenerator sg(O);
+ sg.generate(s);
+ return true;
+}
+
+void
+Slice::Visitor::visitEnum(const EnumPtr& e)
+{
+ XMLOutput O;
+ EnumGenerator eg(O);
+ eg.generate(e);
+}