From: David Reiss Date: Mon, 30 Jul 2007 22:00:27 +0000 (+0000) Subject: Thrift: Change docstring syntax. X-Git-Tag: 0.2.0~1290 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=1ac05803788fb15bcf16e48cdd53b550b3bc5515;p=common%2Fthrift.git Thrift: Change docstring syntax. Summary: The old docstring syntax collided with the syntax for list constants. The new syntax looks a lot like doxygent comments. Trac Bug: #4664 Blame Rev: 32392 Reviewed By: mcslee Test Plan: ../compiler/cpp/thrift -cpp DocTest.thrift (with dump_docs on) and looked at the output. Generated C++ is identical to installed thrift. Revert Plan: ok git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665182 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc index a6f55f98..4d00306c 100644 --- a/compiler/cpp/src/main.cc +++ b/compiler/cpp/src/main.cc @@ -294,6 +294,158 @@ string include_file(string filename) { 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 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::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& typedefs = program->get_typedefs(); + vector::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. */ @@ -596,6 +748,9 @@ void generate(t_program* program) { hs->generate_program(); delete hs; } + if (dump_docs) { + dump_docstrings(program); + } } catch (string s) { printf("Error: %s\n", s.c_str()); diff --git a/compiler/cpp/src/main.h b/compiler/cpp/src/main.h index b8d7971a..a60399b8 100644 --- a/compiler/cpp/src/main.h +++ b/compiler/cpp/src/main.h @@ -64,6 +64,11 @@ std::string directory_name(std::string filename); */ std::string include_file(std::string filename); +/** + * Cleans up text commonly found in doxygen-like comments + */ +char* clean_up_doctext(char* doctext); + /** * Flex utilities */ diff --git a/compiler/cpp/src/thriftl.ll b/compiler/cpp/src/thriftl.ll index 803f786a..5e9fca9a 100644 --- a/compiler/cpp/src/thriftl.ll +++ b/compiler/cpp/src/thriftl.ll @@ -45,10 +45,11 @@ hexconstant ("0x"[0-9A-Fa-f]+) 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 ("'"[^']*"'") @@ -57,6 +58,7 @@ sliteral ("'"[^']*"'") %% {whitespace} { /* do nothing */ } +{sillycomm} { /* do nothing */ } {multicomm} { /* do nothing */ } {comment} { /* do nothing */ } {unixcomment} { /* do nothing */ } @@ -200,8 +202,8 @@ sliteral ("'"[^']*"'") } {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; } diff --git a/compiler/cpp/src/thrifty.yy b/compiler/cpp/src/thrifty.yy index ce11bf86..68384be0 100644 --- a/compiler/cpp/src/thrifty.yy +++ b/compiler/cpp/src/thrifty.yy @@ -361,7 +361,7 @@ DocTextOptional: tok_doctext { pdebug("DocTextOptional -> tok_doctext"); - $$ = $1; + $$ = clean_up_doctext($1); } | { diff --git a/test/DocTest.thrift b/test/DocTest.thrift index 682edffe..c06bd212 100755 --- a/test/DocTest.thrift +++ b/test/DocTest.thrift @@ -6,14 +6,14 @@ cpp_namespace thrift.test # 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, @@ -22,17 +22,17 @@ enum Numberz 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, @@ -46,14 +46,14 @@ struct Xtruct2 3: i32 i32_thing } -[Struct insanity] +/** Struct insanity */ struct Insanity { - [This is doc for field 1] + /** This is doc for field 1 */ 1: map userMap, - [And this is doc for field 2] + /** And this is doc for field 2 */ 2: list xtructs } @@ -73,17 +73,17 @@ struct OneField { 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), @@ -92,10 +92,10 @@ service ThriftTest set testSet(1: set thing), list testList(1: list 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 ), @@ -120,7 +120,94 @@ service ThriftTest 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