return std::string();
}
+/**
+ * Cleans up text commonly found in doxygen-like comments
+ *
+ * Warning: if you mix tabs and spaces in a non-uniform way,
+ * you will get what you deserve.
+ */
+char* clean_up_doctext(char* doctext) {
+ // Convert to C++ string, and remove Windows's carriage returns.
+ string docstring = doctext;
+ docstring.erase(
+ remove(docstring.begin(), docstring.end(), '\r'),
+ docstring.end());
+
+ // Separate into lines.
+ vector<string> lines;
+ string::size_type pos = string::npos;
+ string::size_type last;
+ while (true) {
+ last = (pos == string::npos) ? 0 : pos+1;
+ pos = docstring.find('\n', last);
+ if (pos == string::npos) {
+ // First bit of cleaning. If the last line is only whitespace, drop it.
+ string::size_type nonwhite = docstring.find_first_not_of(" \t", last);
+ if (nonwhite != string::npos) {
+ lines.push_back(docstring.substr(last));
+ }
+ break;
+ }
+ lines.push_back(docstring.substr(last, pos-last));
+ }
+
+ // A very profound docstring.
+ if (lines.empty()) {
+ return NULL;
+ }
+
+ // Clear leading whitespace from the first line.
+ pos = lines.front().find_first_not_of(" \t");
+ lines.front().erase(0, pos);
+
+ // If every nonblank line after the first has the same number of spaces/tabs,
+ // then a star, remove them.
+ bool have_prefix = true;
+ bool found_prefix = false;
+ string::size_type prefix_len = 0;
+ vector<string>::iterator l_iter;
+ for (l_iter = lines.begin()+1; l_iter != lines.end(); ++l_iter) {
+ if (l_iter->empty()) {
+ continue;
+ }
+
+ pos = l_iter->find_first_not_of(" \t");
+ if (!found_prefix) {
+ if (pos != string::npos) {
+ if (l_iter->at(pos) == '*') {
+ found_prefix = true;
+ prefix_len = pos;
+ } else {
+ have_prefix = false;
+ break;
+ }
+ } else {
+ // Whitespace-only line. Truncate it.
+ l_iter->clear();
+ }
+ } else if (l_iter->size() > pos
+ && l_iter->at(pos) == '*'
+ && pos == prefix_len) {
+ // Business as usual.
+ } else if (pos == string::npos) {
+ // Whitespace-only line. Let's truncate it for them.
+ l_iter->clear();
+ } else {
+ // The pattern has been broken.
+ have_prefix = false;
+ break;
+ }
+ }
+
+ // If our prefix survived, delete it from every line.
+ if (have_prefix) {
+ // Get the star too.
+ prefix_len++;
+ for (l_iter = lines.begin()+1; l_iter != lines.end(); ++l_iter) {
+ l_iter->erase(0, prefix_len);
+ }
+ }
+
+ // Now delete the minimum amount of leading whitespace from each line.
+ prefix_len = string::npos;
+ for (l_iter = lines.begin()+1; l_iter != lines.end(); ++l_iter) {
+ if (l_iter->empty()) {
+ continue;
+ }
+ pos = l_iter->find_first_not_of(" \t");
+ if (pos != string::npos
+ && (prefix_len == string::npos || pos < prefix_len)) {
+ prefix_len = pos;
+ }
+ }
+
+ // If our prefix survived, delete it from every line.
+ if (prefix_len != string::npos) {
+ for (l_iter = lines.begin()+1; l_iter != lines.end(); ++l_iter) {
+ l_iter->erase(0, prefix_len);
+ }
+ }
+
+ // Remove trailing whitespace from every line.
+ for (l_iter = lines.begin(); l_iter != lines.end(); ++l_iter) {
+ pos = l_iter->find_last_not_of(" \t");
+ if (pos != string::npos && pos != l_iter->length()-1) {
+ l_iter->erase(pos+1);
+ }
+ }
+
+ // If the first line is empty, remove it.
+ // Don't do this earlier because a lot of steps skip the first line.
+ if (lines.front().empty()) {
+ lines.erase(lines.begin());
+ }
+
+ // Now rejoin the lines and copy them back into doctext.
+ docstring.clear();
+ for (l_iter = lines.begin(); l_iter != lines.end(); ++l_iter) {
+ docstring += *l_iter;
+ docstring += '\n';
+ }
+
+ assert(docstring.length() <= strlen(doctext));
+ strcpy(doctext, docstring.c_str());
+ return doctext;
+}
+
+/** Set to true to debug docstring parsing */
+static bool dump_docs = false;
+
+/**
+ * Dumps docstrings to stdout
+ * Only works for typedefs
+ */
+void dump_docstrings(t_program* program) {
+ const vector<t_typedef*>& typedefs = program->get_typedefs();
+ vector<t_typedef*>::const_iterator t_iter;
+ for (t_iter = typedefs.begin(); t_iter != typedefs.end(); ++t_iter) {
+ t_typedef* td = *t_iter;
+ if (td->has_doc()) {
+ printf("%s:\n%s\n", td->get_name().c_str(), td->get_doc().c_str());
+ }
+ }
+}
+
/**
* Diplays the usage message and then exits with an error code.
*/
hs->generate_program();
delete hs;
}
+ if (dump_docs) {
+ dump_docstrings(program);
+ }
} catch (string s) {
printf("Error: %s\n", s.c_str());
dubconstant ([+-]?[0-9]*(\.[0-9]+)?([eE][+-]?[0-9]+)?)
identifier ([a-zA-Z_][\.a-zA-Z_0-9]*)
whitespace ([ \t\r\n]*)
-multicomm ("/*""/"*([^*/]|[^*]"/"|"*"[^/])*"*"*"*/")
+sillycomm ("/*""*"*"*/")
+multicomm ("/*"[^*]"/"*([^*/]|[^*]"/"|"*"[^/])*"*"*"*/")
+doctext ("/**"([^*/]|[^*]"/"|"*"[^/])*"*"*"*/")
comment ("//"[^\n]*)
unixcomment ("#"[^\n]*)
-doctext ("["(("["[^\]\[]*"]")|[^\]\[])*"]") /* allows one level of nesting */
symbol ([:;\,\{\}\(\)\=<>\[\]])
dliteral ("\""[^"]*"\"")
sliteral ("'"[^']*"'")
%%
{whitespace} { /* do nothing */ }
+{sillycomm} { /* do nothing */ }
{multicomm} { /* do nothing */ }
{comment} { /* do nothing */ }
{unixcomment} { /* do nothing */ }
}
{doctext} {
- yylval.id = strdup(yytext + 1);
- yylval.id[strlen(yylval.id) - 1] = '\0';
+ yylval.id = strdup(yytext + 3);
+ yylval.id[strlen(yylval.id) - 2] = '\0';
return tok_doctext;
}
# the new unix comment
-[Some doc text goes here. Wow I am [nesting these].]
+/** Some doc text goes here. Wow I am [nesting these] (no more nesting.) */
enum Numberz
{
- [This is how to document a parameter]
+ /** This is how to document a parameter */
ONE = 1,
- [And this is a doc for a parameter that has no specific value assigned]
+ /** And this is a doc for a parameter that has no specific value assigned */
TWO,
THREE,
EIGHT = 8
}
-[This is how you would do a typedef doc]
+/** This is how you would do a typedef doc */
typedef i64 UserId
-[And this is where you would document a struct]
+/** And this is where you would document a struct */
struct Xtruct
{
- [And the members of a struct]
+ /** And the members of a struct */
1: string string_thing
- [doct text goes before a comma]
+ /** doct text goes before a comma */
4: byte byte_thing,
9: i32 i32_thing,
3: i32 i32_thing
}
-[Struct insanity]
+/** Struct insanity */
struct Insanity
{
- [This is doc for field 1]
+ /** This is doc for field 1 */
1: map<Numberz, UserId> userMap,
- [And this is doc for field 2]
+ /** And this is doc for field 2 */
2: list<Xtruct> xtructs
}
1: EmptyStruct field
}
-[This is where you would document a Service]
+/** This is where you would document a Service */
service ThriftTest
{
- [And this is how you would document functions in a service]
+ /** And this is how you would document functions in a service */
void testVoid(),
string testString(1: string thing),
byte testByte(1: byte thing),
i32 testI32(1: i32 thing),
- [Like this one]
+ /** Like this one */
i64 testI64(1: i64 thing),
double testDouble(1: double thing),
Xtruct testStruct(1: Xtruct thing),
set<i32> testSet(1: set<i32> thing),
list<i32> testList(1: list<i32> thing),
- [This is an example of a function with params documented]
+ /** This is an example of a function with params documented */
Numberz testEnum(
- [This param is a thing]
+ /** This param is a thing */
1: Numberz thing
),
Xtruct testMultiException(string arg0, string arg1) throws(Xception err1, Xception2 err2)
}
-service SecondService
-{
- void blahBlah()
-}
+/// This style of Doxy-comment doesn't work.
+typedef i32 SorryNoGo
+
+/**
+ * This is a trivial example of a multiline docstring.
+ */
+typedef i32 TrivialMultiLine
+
+/**
+ * This is the cannonical example
+ * of a multiline docstring.
+ */
+typedef i32 StandardMultiLine
+
+/**
+ * The last line is non-blank.
+ * I said non-blank! */
+typedef i32 LastLine
+
+/** Both the first line
+ * are non blank. ;-)
+ * and the last line */
+typedef i32 FirstAndLastLine
+
+/**
+ * INDENTED TITLE
+ * The text is less indented.
+ */
+typedef i32 IndentedTitle
+
+/** First line indented.
+ * Unfortunately, this does not get indented.
+ */
+typedef i32 FirstLineIndent
+
+
+/**
+ * void code_in_comment() {
+ * printf("hooray code!");
+ * }
+ */
+typedef i32 CodeInComment
+
+ /**
+ * Indented Docstring.
+ * This whole docstring is indented.
+ * This line is indented further.
+ */
+typedef i32 IndentedDocstring
+
+/** Irregular docstring.
+ * We will have to punt
+ * on this thing */
+typedef i32 Irregular1
+
+/**
+ * note the space
+ * before these lines
+* but not this
+ * one
+ */
+typedef i32 Irregular2
+
+/**
+* Flush against
+* the left.
+*/
+typedef i32 Flush
+
+/**
+ No stars in this one.
+ It should still work fine, though.
+ Including indenting.
+ */
+typedef i32 NoStars
+
+/** Trailing whitespace
+Sloppy trailing whitespace
+is truncated. */
+typedef i32 TrailingWhitespace
+
+/**
+ * This is a big one.
+ *
+ * We'll have some blank lines in it.
+ *
+ * void as_well_as(some code) {
+ * puts("YEEHAW!");
+ * }
+ */
+typedef i32 BigDog