summaryrefslogtreecommitdiff
path: root/cpp/src/Slice/Parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/Slice/Parser.cpp')
-rw-r--r--cpp/src/Slice/Parser.cpp380
1 files changed, 380 insertions, 0 deletions
diff --git a/cpp/src/Slice/Parser.cpp b/cpp/src/Slice/Parser.cpp
index 3b5cb054be2..ec9496f705d 100644
--- a/cpp/src/Slice/Parser.cpp
+++ b/cpp/src/Slice/Parser.cpp
@@ -280,6 +280,62 @@ Slice::DefinitionContext::initSuppressedWarnings()
}
// ----------------------------------------------------------------------
+// Comment
+// ----------------------------------------------------------------------
+
+bool
+Slice::Comment::isDeprecated() const
+{
+ return _isDeprecated;
+}
+
+StringList
+Slice::Comment::deprecated() const
+{
+ return _deprecated;
+}
+
+StringList
+Slice::Comment::overview() const
+{
+ return _overview;
+}
+
+StringList
+Slice::Comment::misc() const
+{
+ return _misc;
+}
+
+StringList
+Slice::Comment::seeAlso() const
+{
+ return _seeAlso;
+}
+
+StringList
+Slice::Comment::returns() const
+{
+ return _returns;
+}
+
+map<string, StringList>
+Slice::Comment::parameters() const
+{
+ return _parameters;
+}
+
+map<string, StringList>
+Slice::Comment::exceptions() const
+{
+ return _exceptions;
+}
+
+Slice::Comment::Comment()
+{
+}
+
+// ----------------------------------------------------------------------
// SyntaxTreeBase
// ----------------------------------------------------------------------
@@ -538,6 +594,330 @@ Slice::Contained::comment() const
return _comment;
}
+namespace
+{
+
+void
+trimLines(StringList& l)
+{
+ //
+ // Remove empty trailing lines.
+ //
+ while(!l.empty() && l.back().empty())
+ {
+ l.pop_back();
+ }
+}
+
+StringList
+splitComment(const string& c, bool stripMarkup)
+{
+ string comment = c;
+
+ if(stripMarkup)
+ {
+ //
+ // Strip HTML markup and javadoc links.
+ //
+ string::size_type pos = 0;
+ do
+ {
+ pos = comment.find('<', pos);
+ if(pos != string::npos)
+ {
+ string::size_type endpos = comment.find('>', pos);
+ if(endpos == string::npos)
+ {
+ break;
+ }
+ comment.erase(pos, endpos - pos + 1);
+ }
+ }
+ while(pos != string::npos);
+
+ const string link = "{@link";
+ pos = 0;
+ do
+ {
+ pos = comment.find(link, pos);
+ if(pos != string::npos)
+ {
+ comment.erase(pos, link.size() + 1); // Erase trailing white space too.
+ string::size_type endpos = comment.find('}', pos);
+ if(endpos != string::npos)
+ {
+ string ident = comment.substr(pos, endpos - pos);
+ comment.erase(pos, endpos - pos + 1);
+
+ //
+ // Replace links of the form {@link Type#member} with "Type.member".
+ //
+ string::size_type hash = ident.find('#');
+ string rest;
+ if(hash != string::npos)
+ {
+ rest = ident.substr(hash + 1);
+ ident = ident.substr(0, hash);
+ if(!ident.empty())
+ {
+ if(!rest.empty())
+ {
+ ident += "." + rest;
+ }
+ }
+ else if(!rest.empty())
+ {
+ ident = rest;
+ }
+ }
+
+ comment.insert(pos, ident);
+ }
+ }
+ }
+ while(pos != string::npos);
+ }
+
+ StringList result;
+
+ string::size_type pos = 0;
+ string::size_type nextPos;
+ while((nextPos = comment.find_first_of('\n', pos)) != string::npos)
+ {
+ result.push_back(IceUtilInternal::trim(string(comment, pos, nextPos - pos)));
+ pos = nextPos + 1;
+ }
+ string lastLine = IceUtilInternal::trim(string(comment, pos));
+ if(!lastLine.empty())
+ {
+ result.push_back(lastLine);
+ }
+
+ trimLines(result);
+
+ return result;
+}
+
+bool
+parseCommentLine(const string& l, const string& tag, bool namedTag, string& name, string& doc)
+{
+ doc.clear();
+
+ if(l.find(tag) == 0)
+ {
+ const string ws = " \t";
+
+ if(namedTag)
+ {
+ string::size_type n = l.find_first_not_of(ws, tag.size());
+ if(n == string::npos)
+ {
+ return false; // Malformed line, ignore it.
+ }
+ string::size_type end = l.find_first_of(ws, n);
+ if(end == string::npos)
+ {
+ return false; // Malformed line, ignore it.
+ }
+ name = l.substr(n, end - n);
+ n = l.find_first_not_of(ws, end);
+ if(n != string::npos)
+ {
+ doc = l.substr(n);
+ }
+ }
+ else
+ {
+ name.clear();
+
+ string::size_type n = l.find_first_not_of(ws, tag.size());
+ if(n == string::npos)
+ {
+ return false; // Malformed line, ignore it.
+ }
+ doc = l.substr(n);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+}
+
+CommentPtr
+Slice::Contained::parseComment(bool stripMarkup) const
+{
+ CommentPtr comment = new Comment;
+
+ comment->_isDeprecated = false;
+
+ //
+ // First check metadata for a deprecated tag.
+ //
+ string deprecateMetadata;
+ if(findMetaData("deprecate", deprecateMetadata))
+ {
+ comment->_isDeprecated = true;
+ if(deprecateMetadata.find("deprecate:") == 0 && deprecateMetadata.size() > 10)
+ {
+ comment->_deprecated.push_back(IceUtilInternal::trim(deprecateMetadata.substr(10)));
+ }
+ }
+
+ if(!comment->_isDeprecated && _comment.empty())
+ {
+ return 0;
+ }
+
+ //
+ // Split up the comment into lines.
+ //
+ StringList lines = splitComment(_comment, stripMarkup);
+
+ StringList::const_iterator i;
+ for(i = lines.begin(); i != lines.end(); ++i)
+ {
+ const string l = *i;
+ if(l[0] == '@')
+ {
+ break;
+ }
+ comment->_overview.push_back(l);
+ }
+
+ enum State { StateMisc, StateParam, StateThrows, StateReturn, StateDeprecated };
+ State state = StateMisc;
+ string name;
+ const string ws = " \t";
+ const string paramTag = "@param";
+ const string throwsTag = "@throws";
+ const string exceptionTag = "@exception";
+ const string returnTag = "@return";
+ const string deprecatedTag = "@deprecated";
+ const string seeTag = "@see";
+ for(; i != lines.end(); ++i)
+ {
+ const string l = IceUtilInternal::trim(*i);
+ string line;
+ if(parseCommentLine(l, paramTag, true, name, line))
+ {
+ if(!line.empty())
+ {
+ state = StateParam;
+ StringList sl;
+ sl.push_back(line); // The first line of the description.
+ comment->_parameters[name] = sl;
+ }
+ }
+ else if(parseCommentLine(l, throwsTag, true, name, line))
+ {
+ if(!line.empty())
+ {
+ state = StateThrows;
+ StringList sl;
+ sl.push_back(line); // The first line of the description.
+ comment->_exceptions[name] = sl;
+ }
+ }
+ else if(parseCommentLine(l, exceptionTag, true, name, line))
+ {
+ if(!line.empty())
+ {
+ state = StateThrows;
+ StringList sl;
+ sl.push_back(line); // The first line of the description.
+ comment->_exceptions[name] = sl;
+ }
+ }
+ else if(parseCommentLine(l, seeTag, false, name, line))
+ {
+ if(!line.empty())
+ {
+ comment->_seeAlso.push_back(line);
+ }
+ }
+ else if(parseCommentLine(l, returnTag, false, name, line))
+ {
+ if(!line.empty())
+ {
+ state = StateReturn;
+ comment->_returns.push_back(line); // The first line of the description.
+ }
+ }
+ else if(parseCommentLine(l, deprecatedTag, false, name, line))
+ {
+ comment->_isDeprecated = true;
+ if(!line.empty())
+ {
+ state = StateDeprecated;
+ comment->_deprecated.push_back(line); // The first line of the description.
+ }
+ }
+ else if(!l.empty())
+ {
+ if(l[0] == '@')
+ {
+ //
+ // Treat all other tags as miscellaneous comments.
+ //
+ state = StateMisc;
+ }
+
+ switch(state)
+ {
+ case StateMisc:
+ {
+ comment->_misc.push_back(l);
+ break;
+ }
+ case StateParam:
+ {
+ assert(!name.empty());
+ StringList sl;
+ if(comment->_parameters.find(name) != comment->_parameters.end())
+ {
+ sl = comment->_parameters[name];
+ }
+ sl.push_back(l);
+ comment->_parameters[name] = sl;
+ break;
+ }
+ case StateThrows:
+ {
+ assert(!name.empty());
+ StringList sl;
+ if(comment->_exceptions.find(name) != comment->_exceptions.end())
+ {
+ sl = comment->_exceptions[name];
+ }
+ sl.push_back(l);
+ comment->_exceptions[name] = sl;
+ break;
+ }
+ case StateReturn:
+ {
+ comment->_returns.push_back(l);
+ break;
+ }
+ case StateDeprecated:
+ {
+ comment->_deprecated.push_back(l);
+ break;
+ }
+ }
+ }
+ }
+
+ trimLines(comment->_overview);
+ trimLines(comment->_deprecated);
+ trimLines(comment->_misc);
+ trimLines(comment->_returns);
+
+ return comment;
+}
+
int
Slice::Contained::includeLevel() const
{