Merge branch 'vadz-doxygen'

This is the Doxygen work begun in Google Summer of Code projects 2008
and 2012 and subsequently improved by numerous contributors.

* vadz-doxygen: (314 commits)
  Add changes entry for Doxygen support
  Add some missing doctype tyemaps
  Doxygen warnings cleanup
  Move doxygen warning numbers
  Add Python doxygen example
  Doxygen example
  Add Doxygen to include paths
  Doxygen source rename
  More merge fixes from doxygen branches
  Correct python example headers
  Correct source code headers
  Another merge fix from doxygen branches
  Java enums output format fixes
  Add omitted doxygen_parsing_enums testcase
  PEP8 conformance for comment verifier module
  Clean up merge problem
  Doxygen html tweaks
  Update html chapter numbering for added Doxygen chapter
  Fixes to makechap.py to detect ill-formed headers
  html fixes for Doxygen
  Add missing CPlusPlus17.html file
  Format files to unix format
  Doxygen testcase tweak to match that in the html docs
  Doxygen html documentation updates and corrections
  Remove doxygen Examples subdirectory
  Beautify doxygen source code
  Code formatting fixes in doxygen code
  Remove unused doxygen code
  new_node refactor
  Various merge fixes in doxygen branches
  Unused variable warning fix
  Fix wrongly resetting indent after formulae in Doxygen comments
  Add support for doxygen:alias feature
  Get rid of meaningless return type of DoxygenParser methods
  Return enum, not untyped int, when classifying Doxygen commands
  Get rid of unnecessary "typedef enum" in C++ code
  Use slash, not backslash, in "C/C++" in the documentation
  Replace literal "<" with "&lt;" in HTML documentation
  Fix broken link to java.sun.com in Doxygen documentation
  Fix using com.sun.tools.javadoc package under macOS
  Fix error reporting for special characters in Doxygen parsing code
  Switch Python Doxygen unit tests to use inspect.getdoc()
  Use correct separator in Java class path under Windows.
  Remove executable permission from appveyor.yml.
  Use JAVA_HOME value in configure to detect Java.
  Display JAVA_HOME value in "make java_version".
  Fix harmless MSVC warning in DoxygenTranslator code.
  Reset "_last" for all but first enum elements.
  Don't duplicate Javadoc from global enum Doxygen comments twice.
  Move Doxygen comments concatenation from the parser to the lexer.
  Fix shift/reduce conflicts in Doxygen pre/post comment parsing.
  Rewrote part of the grammar dealing with Doxygen comments for enums.
  No changes, just remove spurious white space only differences.
  Move Doxygen comment mangling from the parser to the lexer.
  Merge "-builtin" autodoc bugs workarounds from master into test.
  Quote JAVA_HOME variable value in Java test suite makefile.
  Remove unused C_COMMENT_STRING terminal from the grammar.
  Fix missing returns in the Doxygen test suite code.
  Fix trimming whitespace from Doxygen comments.
  Remove code not doing anything from PyDocConverter.
  Remove unused <sstream> header.
  Remove unreferenced struct declaration.
  Remove unused Swig_warn() function.
  Remove any whitespace before ignored Doxygen commands.
  Remove trailing space from one of Doxygen tests.
  Fix autodoc strings generated in Python builtin case and the test.
  Fix Doxygen unit test in Python "-builtin" case.
  Use class docstrings in "-builtin" Python case.
  Don't indent Doxygen doc strings in generated Python code.
  Add a possibility to flexibly ignore custom Doxygen tags.
  Stop completely ignoring many Doxygen comments.
  Fix structural Doxygen comment recognition in the parser.
  No changes, just make checking for Doxygen structural tags more sane.
  Use "//", not "#", for comments in SWIG input.
  Allow upper case letters and digits in Doxygen words.
  Pass the node the Doxygen comment is attached to to DoxygenParser.
  Get rid of findCommand() which duplicaed commandBelongs().
  Recognize unknown Doxygen tags correctly.
  No real changes, just pass original command to commandBelongs().
  Describe Doxygen-specific %features in a single place.
  Give warnings for unknown Doxygen commands in Doxygen parser.
  Document the return type when translating Doxygen @return to Python.
  Fix translated Doxygen comments for overloaded functions in Python.
  Also merge Doxygen comments for overloaded constructors in Python.
  Allow using enum elements as default values for Python functions.
  Don't always use "*args" for all Python wrapper functions.
  No real changes, just make PYTHON::check_kwargs() const.
  Refactor: move makeParameterName() to common Language base class.
  Remove long line wrapping from Python parameter list generation code.
  Simplify and make more efficient building Python docstrings.
  Translate Doxygen code blocks to Sphinx code blocks.
  Add a simple test of multiple parameters to Doxygen test suite.
  Make Python parameters types hyperlinks in the doc strings.
  Make Language::classLookup() and enumLookup() static.
  Fix arguments of @param, @return etc translations to Python.
  Remove unused method from PyDocConverter.
  No real changes, just remove an unnecessary variable.
  Preserve relative indentation when parsing Doxygen comments.
  Use Sphinx-friendly formatting for overloaded functions documentation.
  Add poor man trailing white space detection to Doxygen Python tests.
  ...
This commit is contained in:
William S Fulton 2018-06-07 08:13:10 +01:00
commit 33921666a1
123 changed files with 12964 additions and 1344 deletions

View file

@ -28,6 +28,7 @@ extern "C" {
extern int cparse_cplusplusout;
extern int cparse_start_line;
extern String *cparse_unknown_directive;
extern int scan_doxygen_comments;
extern void Swig_cparse_cplusplus(int);
extern void Swig_cparse_cplusplusout(int);
@ -61,7 +62,7 @@ extern "C" {
extern void cparse_normalize_void(Node *);
extern Parm *Swig_cparse_parm(String *s);
extern ParmList *Swig_cparse_parms(String *s, Node *file_line_node);
extern Node *new_node(const_String_or_char_ptr tag);
extern Node *Swig_cparse_new_node(const_String_or_char_ptr tag);
/* templ.c */
extern int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab *tscope);

View file

@ -50,6 +50,57 @@ static int last_brace = 0;
static int last_id = 0;
static int rename_active = 0;
/* Doxygen comments scanning */
int scan_doxygen_comments = 0;
int isStructuralDoxygen(String *s) {
static const char* const structuralTags[] = {
"addtogroup",
"callgraph",
"callergraph",
"category",
"def",
"defgroup",
"dir",
"example",
"file",
"headerfile",
"internal",
"mainpage",
"name",
"nosubgrouping",
"overload",
"package",
"page",
"protocol",
"relates",
"relatesalso",
"showinitializer",
"weakgroup",
};
unsigned n;
char *slashPointer = Strchr(s, '\\');
char *atPointer = Strchr(s,'@');
if (slashPointer == NULL && atPointer == NULL)
return 0;
else if(slashPointer == NULL)
slashPointer = atPointer;
slashPointer++; /* skip backslash or at sign */
for (n = 0; n < sizeof(structuralTags)/sizeof(structuralTags[0]); n++) {
const size_t len = strlen(structuralTags[n]);
if (strncmp(slashPointer, structuralTags[n], len) == 0) {
/* Take care to avoid false positives with prefixes of other tags. */
if (slashPointer[len] == '\0' || isspace(slashPointer[len]))
return 1;
}
}
return 0;
}
/* -----------------------------------------------------------------------------
* Swig_cparse_cplusplus()
* ----------------------------------------------------------------------------- */
@ -367,10 +418,70 @@ static int yylook(void) {
case SWIG_TOKEN_COMMENT:
{
String *cmt = Scanner_text(scan);
char *loc = Char(cmt);
if ((strncmp(loc,"/*@SWIG",7) == 0) && (loc[Len(cmt)-3] == '@')) {
Scanner_locator(scan, cmt);
typedef enum {
DOX_COMMENT_PRE = -1,
DOX_COMMENT_NONE,
DOX_COMMENT_POST
} comment_kind_t;
comment_kind_t existing_comment = DOX_COMMENT_NONE;
/* Concatenate or skip all consecutive comments at once. */
do {
String *cmt = Scanner_text(scan);
char *loc = Char(cmt);
if ((strncmp(loc, "/*@SWIG", 7) == 0) && (loc[Len(cmt)-3] == '@')) {
Scanner_locator(scan, cmt);
}
if (scan_doxygen_comments) { /* else just skip this node, to avoid crashes in parser module*/
/* Check for all possible Doxygen comment start markers while ignoring
comments starting with a row of asterisks or slashes just as
Doxygen itself does. */
if (Len(cmt) > 3 && loc[0] == '/' &&
((loc[1] == '/' && ((loc[2] == '/' && loc[3] != '/') || loc[2] == '!')) ||
(loc[1] == '*' && ((loc[2] == '*' && loc[3] != '*') || loc[2] == '!')))) {
comment_kind_t this_comment = loc[3] == '<' ? DOX_COMMENT_POST : DOX_COMMENT_PRE;
if (existing_comment != DOX_COMMENT_NONE && this_comment != existing_comment) {
/* We can't concatenate together Doxygen pre- and post-comments. */
break;
}
if (this_comment == DOX_COMMENT_POST || !isStructuralDoxygen(loc)) {
String *str;
int begin = this_comment == DOX_COMMENT_POST ? 4 : 3;
int end = Len(cmt);
if (loc[end - 1] == '/' && loc[end - 2] == '*') {
end -= 2;
}
str = NewStringWithSize(loc + begin, end - begin);
if (existing_comment == DOX_COMMENT_NONE) {
yylval.str = str;
Setline(yylval.str, Scanner_start_line(scan));
Setfile(yylval.str, Scanner_file(scan));
} else {
Append(yylval.str, str);
}
existing_comment = this_comment;
}
}
}
do {
tok = Scanner_token(scan);
} while (tok == SWIG_TOKEN_ENDLINE);
} while (tok == SWIG_TOKEN_COMMENT);
Scanner_pushtoken(scan, tok, Scanner_text(scan));
switch (existing_comment) {
case DOX_COMMENT_PRE:
return DOXYGENSTRING;
case DOX_COMMENT_NONE:
break;
case DOX_COMMENT_POST:
return DOXYGENPOSTSTRING;
}
}
break;
@ -907,6 +1018,8 @@ int yylex(void) {
return (ID);
case POUND:
return yylex();
case SWIG_TOKEN_COMMENT:
return yylex();
default:
return (l);
}

View file

@ -64,6 +64,13 @@ static int template_reduce = 0;
static int cparse_externc = 0;
int ignore_nested_classes = 0;
int kwargs_supported = 0;
/* -----------------------------------------------------------------------------
* Doxygen Comment Globals
* ----------------------------------------------------------------------------- */
static String *currentDeclComment = NULL; /* Comment of C/C++ declaration. */
static Node *previousNode = NULL; /* Pointer to the previous node (for post comments) */
static Node *currentNode = NULL; /* Pointer to the current node (for post comments) */
/* -----------------------------------------------------------------------------
* Assist Functions
* ----------------------------------------------------------------------------- */
@ -75,6 +82,14 @@ static void yyerror (const char *e) {
(void)e;
}
static Node *new_node(const_String_or_char_ptr tag) {
Node *n = Swig_cparse_new_node(tag);
/* Remember the previous node in case it will need a post-comment */
previousNode = currentNode;
currentNode = n;
return n;
}
/* Copies a node. Does not copy tree links or symbol table data (except for
sym:name) */
@ -159,6 +174,36 @@ static Node *copy_node(Node *n) {
return nn;
}
static void set_comment(Node *n, String *comment) {
String *name;
Parm *p;
if (!n || !comment)
return;
if (Getattr(n, "doxygen"))
Append(Getattr(n, "doxygen"), comment);
else {
Setattr(n, "doxygen", comment);
/* This is the first comment, populate it with @params, if any */
p = Getattr(n, "parms");
while (p) {
if (Getattr(p, "doxygen"))
Printv(comment, "\n@param ", Getattr(p, "name"), Getattr(p, "doxygen"), NIL);
p=nextSibling(p);
}
}
/* Append same comment to every generated overload */
name = Getattr(n, "name");
if (!name)
return;
n = nextSibling(n);
while (n && Getattr(n, "name") && Strcmp(Getattr(n, "name"), name) == 0) {
Setattr(n, "doxygen", comment);
n = nextSibling(n);
}
}
/* -----------------------------------------------------------------------------
* Variables
* ----------------------------------------------------------------------------- */
@ -1553,6 +1598,9 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier)
%token <str> CONVERSIONOPERATOR
%token PARSETYPE PARSEPARM PARSEPARMS
%token <str> DOXYGENSTRING
%token <str> DOXYGENPOSTSTRING
%left CAST
%left QUESTIONMARK
%left LOR
@ -1579,11 +1627,11 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier)
/* C declarations */
%type <node> c_declaration c_decl c_decl_tail c_enum_key c_enum_inherit c_enum_decl c_enum_forward_decl c_constructor_decl;
%type <node> enumlist edecl;
%type <node> enumlist enumlist_tail enumlist_item edecl_with_dox edecl;
/* C++ declarations */
%type <node> cpp_declaration cpp_class_decl cpp_forward_class_decl cpp_template_decl cpp_alternate_rettype;
%type <node> cpp_members cpp_member;
%type <node> cpp_members cpp_member cpp_member_no_dox;
%type <node> cpp_constructor_decl cpp_destructor_decl cpp_protection_decl cpp_conversion_operator cpp_static_assert;
%type <node> cpp_swig_directive cpp_template_possible cpp_opt_declarators ;
%type <node> cpp_using_decl cpp_namespace_decl cpp_catch_decl cpp_lambda_decl;
@ -1595,7 +1643,7 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier)
%type <id> storage_class extern_string;
%type <pl> parms ptail rawparms varargs_parms ;
%type <pl> templateparameters templateparameterstail;
%type <p> parm valparm rawvalparms valparms valptail ;
%type <p> parm_no_dox parm valparm rawvalparms valparms valptail ;
%type <p> typemap_parm tm_list tm_tail ;
%type <p> templateparameter ;
%type <id> templcpptype cpptype classkey classkeyopt access_specifier;
@ -1628,7 +1676,6 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier)
%type <node> featattr;
%type <node> lambda_introducer lambda_body;
%type <pl> lambda_tail;
%type <node> optional_constant_directive;
%type <str> virt_specifier_seq virt_specifier_seq_opt;
%%
@ -1675,9 +1722,24 @@ program : interface {
interface : interface declaration {
/* add declaration to end of linked list (the declaration isn't always a single declaration, sometimes it is a linked list itself) */
if (currentDeclComment != NULL) {
set_comment($2, currentDeclComment);
currentDeclComment = NULL;
}
appendChild($1,$2);
$$ = $1;
}
| interface DOXYGENSTRING {
currentDeclComment = $2;
$$ = $1;
}
| interface DOXYGENPOSTSTRING {
Node *node = lastChild($1);
if (node) {
set_comment(node, $2);
}
$$ = $1;
}
| empty {
$$ = new_node("top");
}
@ -4553,7 +4615,7 @@ cpp_members : cpp_member cpp_members {
/* A class member. May be data or a function. Static or virtual as well */
cpp_member : c_declaration { $$ = $1; }
cpp_member_no_dox : c_declaration { $$ = $1; }
| cpp_constructor_decl {
$$ = $1;
if (extendmode && current_class) {
@ -4587,6 +4649,18 @@ cpp_member : c_declaration { $$ = $1; }
| fragment_directive {$$ = $1; }
| types_directive {$$ = $1; }
| SEMI { $$ = 0; }
cpp_member : cpp_member_no_dox {
$$ = $1;
}
| DOXYGENSTRING cpp_member_no_dox {
$$ = $2;
set_comment($2, $1);
}
| cpp_member_no_dox DOXYGENPOSTSTRING {
$$ = $1;
set_comment($1, $2);
}
;
/* Possibly a constructor */
@ -4974,20 +5048,31 @@ rawparms : parm ptail {
set_nextSibling($1,$2);
$$ = $1;
}
| empty { $$ = 0; }
| empty {
$$ = 0;
previousNode = currentNode;
currentNode=0;
}
;
ptail : COMMA parm ptail {
set_nextSibling($2,$3);
$$ = $2;
}
| COMMA DOXYGENPOSTSTRING parm ptail {
set_comment(previousNode, $2);
set_nextSibling($3, $4);
$$ = $3;
}
| empty { $$ = 0; }
;
parm : rawtype parameter_declarator {
parm_no_dox : rawtype parameter_declarator {
SwigType_push($1,$2.type);
$$ = NewParmWithoutFileLineInfo($1,$2.id);
previousNode = currentNode;
currentNode = $$;
Setfile($$,cparse_file);
Setline($$,cparse_line);
if ($2.defarg) {
@ -4997,6 +5082,8 @@ parm : rawtype parameter_declarator {
| TEMPLATE LESSTHAN cpptype GREATERTHAN cpptype idcolon def_args {
$$ = NewParmWithoutFileLineInfo(NewStringf("template<class> %s %s", $5,$6), 0);
previousNode = currentNode;
currentNode = $$;
Setfile($$,cparse_file);
Setline($$,cparse_line);
if ($7.val) {
@ -5006,11 +5093,26 @@ parm : rawtype parameter_declarator {
| PERIOD PERIOD PERIOD {
SwigType *t = NewString("v(...)");
$$ = NewParmWithoutFileLineInfo(t, 0);
previousNode = currentNode;
currentNode = $$;
Setfile($$,cparse_file);
Setline($$,cparse_line);
}
;
parm : parm_no_dox {
$$ = $1;
}
| DOXYGENSTRING parm_no_dox {
$$ = $2;
set_comment($2, $1);
}
| parm_no_dox DOXYGENPOSTSTRING {
$$ = $1;
set_comment($1, $2);
}
;
valparms : rawvalparms {
Parm *p;
$$ = $1;
@ -6217,28 +6319,70 @@ ename : identifier { $$ = $1; }
| empty { $$ = (char *) 0;}
;
optional_constant_directive : constant_directive { $$ = $1; }
| empty { $$ = 0; }
;
optional_ignored_define
: constant_directive
| empty
;
optional_ignored_define_after_comma
: empty
| COMMA
| COMMA constant_directive
;
/* Enum lists - any #define macros (constant directives) within the enum list are ignored. Trailing commas accepted. */
enumlist : enumlist COMMA optional_constant_directive edecl optional_constant_directive {
Node *leftSibling = Getattr($1,"_last");
set_nextSibling(leftSibling,$4);
Setattr($1,"_last",$4);
$$ = $1;
}
| enumlist COMMA optional_constant_directive {
$$ = $1;
}
| optional_constant_directive edecl optional_constant_directive {
Setattr($2,"_last",$2);
$$ = $2;
}
| optional_constant_directive {
$$ = 0;
}
;
enumlist : enumlist_item optional_ignored_define_after_comma {
Setattr($1,"_last",$1);
$$ = $1;
}
| enumlist_item enumlist_tail optional_ignored_define_after_comma {
set_nextSibling($1, $2);
Setattr($1,"_last",Getattr($2,"_last"));
Setattr($2,"_last",NULL);
$$ = $1;
}
| optional_ignored_define {
$$ = 0;
}
;
enumlist_tail : COMMA enumlist_item {
Setattr($2,"_last",$2);
$$ = $2;
}
| enumlist_tail COMMA enumlist_item {
set_nextSibling(Getattr($1,"_last"), $3);
Setattr($1,"_last",$3);
$$ = $1;
}
;
enumlist_item : optional_ignored_define edecl_with_dox optional_ignored_define {
$$ = $2;
}
;
edecl_with_dox : edecl {
$$ = $1;
}
| DOXYGENSTRING edecl {
$$ = $2;
set_comment($2, $1);
}
| edecl DOXYGENPOSTSTRING {
$$ = $1;
set_comment($1, $2);
}
| DOXYGENPOSTSTRING edecl {
$$ = $2;
set_comment(previousNode, $1);
}
| DOXYGENPOSTSTRING edecl DOXYGENPOSTSTRING {
$$ = $2;
set_comment(previousNode, $1);
set_comment($2, $3);
}
;
edecl : identifier {
SwigType *type = NewSwigType(T_INT);

View file

@ -112,12 +112,12 @@ void cparse_normalize_void(Node *n) {
}
/* -----------------------------------------------------------------------------
* new_node()
* Swig_cparse_new_node()
*
* Create an empty parse node, setting file and line number information
* ----------------------------------------------------------------------------- */
Node *new_node(const_String_or_char_ptr tag) {
Node *Swig_cparse_new_node(const_String_or_char_ptr tag) {
Node *n = NewHash();
set_nodeType(n,tag);
Setfile(n,cparse_file);

View file

@ -0,0 +1,170 @@
/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.html.
*
* doxycommands.h
*
* Part of the Doxygen comment translation module of SWIG.
* ----------------------------------------------------------------------------- */
#ifndef DOXYGENCOMMANDS_H
#define DOXYGENCOMMANDS_H
// doxy commands are not processed inside this block
const char *CMD_HTML_ONLY = "htmlonly";
// doxy commands are not processed inside this block
const char *CMD_VERBATIM = "verbatim";
const char *CMD_LATEX_1 = "f$";
const char *CMD_LATEX_2 = "f{";
const char *CMD_LATEX_3 = "f[";
const char *CMD_END_HTML_ONLY = "endhtmlonly";
const char *CMD_END_VERBATIM = "endverbatim";
const char *CMD_END_LATEX_1 = "f$";
const char *CMD_END_LATEX_2 = "f}";
const char *CMD_END_LATEX_3 = "f]";
const char *sectionIndicators[] = {
"attention", "author", "authors", "brief", "bug", "cond", "date",
"deprecated", "details", "else", "elseif", "endcond", "endif",
"exception", "if", "ifnot", "invariant", "note", "par", "param",
"tparam", "post", "pre", "remarks", "remark", "result", "return",
"returns", "retval", "sa", "see", "since", "test", "throw", "throws",
"todo", "version", "warning", "xrefitem"
};
const int sectionIndicatorsSize = sizeof(sectionIndicators) / sizeof(*sectionIndicators);
/* All of the doxygen commands divided up by how they are parsed */
const char *simpleCommands[] = {
// the first line are escaped chars, except \~, which is a language ID command.
"n", "$", "@", "\\", "&", "~", "<", ">", "#", "%", "\"", ".", "::",
"endcond",
"callgraph", "callergraph", "showinitializer", "hideinitializer", "internal",
"nosubgrouping", "public", "publicsection", "private", "privatesection",
"protected", "protectedsection", "tableofcontents"
};
const int simpleCommandsSize = sizeof(simpleCommands) / sizeof(*simpleCommands);
const char *commandWords[] = {
"a", "b", "c", "e", "em", "p", "def", "enum", "package", "relates",
"namespace", "relatesalso", "anchor", "dontinclude", "include",
"includelineno", "copydoc", "copybrief", "copydetails", "verbinclude",
"htmlinclude", "extends", "implements", "memberof", "related", "relatedalso",
"cite"
};
const int commandWordsSize = sizeof(commandWords) / sizeof(*commandWords);
const char *commandLines[] = {
"addindex", "fn", "name", "line", "var", "skipline", "typedef", "skip",
"until", "property"
};
const int commandLinesSize = sizeof(commandLines) / sizeof(*commandLines);
const char *commandParagraph[] = {
"partofdescription", "result", "return", "returns", "remarks", "remark",
"since", "test", "sa", "see", "pre", "post", "details", "invariant",
"deprecated", "date", "note", "warning", "version", "todo", "bug",
"attention", "brief", "author", "authors", "copyright", "short"
};
const int commandParagraphSize = sizeof(commandParagraph) / sizeof(*commandParagraph);
const char *commandEndCommands[] = {
CMD_HTML_ONLY, "latexonly", "manonly", "xmlonly", "link", "rtfonly"
};
const int commandEndCommandsSize = sizeof(commandEndCommands) / sizeof(*commandEndCommands);
const char *commandWordParagraphs[] = {
"param", "tparam", "throw", "throws", "retval", "exception", "example"
};
const int commandWordParagraphsSize = sizeof(commandWordParagraphs) / sizeof(*commandWordParagraphs);
const char *commandWordLines[] = {
"page", "subsection", "subsubsection", "section", "paragraph", "defgroup",
"snippet", "mainpage"
};
const int commandWordLinesSize = sizeof(commandWordLines) / sizeof(*commandWordLines);
const char *commandWordOWordOWords[] = {
"category", "class", "protocol", "interface", "struct", "union"
};
const int commandWordOWordOWordsSize = sizeof(commandWordOWordOWords) / sizeof(*commandWordOWordOWords);
const char *commandOWords[] = {
"dir", "file", "cond"
};
const int commandOWordsSize = sizeof(commandOWords) / sizeof(*commandOWords);
const char *commandErrorThrowings[] = {
"annotatedclassstd::list", "classhierarchy", "define", "functionindex", "header",
"headerfilestd::list", "inherit", "l", "postheader", "endcode", "enddot", "endmsc", "endhtmlonly",
"endlatexonly", "endmanonly", "endlink", "endverbatim", "endxmlonly", "f]", "f}", "endif", "else",
"endrtfonly"
};
const int commandErrorThrowingsSize = sizeof(commandErrorThrowings) / sizeof(*commandErrorThrowings);
const char *commandUniques[] = {
"xrefitem", "arg", "ingroup", "par", "headerfile", "overload", "weakgroup", "ref", "subpage", "dotfile", "image", "addtogroup", "li",
"if", "ifnot", "elseif", "else", "mscfile", "code", CMD_VERBATIM, "f{", "f[", "f$", "dot", "msc"
};
const int commandUniquesSize = sizeof(commandUniques) / sizeof(*commandUniques);
// These HTML commands are transformed when producing output in other formats.
// Other commands are left intact, but '<' and '> are replaced with entities in HTML
// output. So <varName> appears as &lt;varName&gt; in HTML output. The same
// behavior must be repeated by SWIG. See Doxygen doc for the list of commands.
// '<' is prepended to distinguish HTML tags from Doxygen commands.
const char *commandHtml[] = {
"<a", "<b", "<blockquote", "<body", "<br", "<center", "<caption", "<code", "<dd", "<dfn",
"<div", "<dl", "<dt", "<em", "<form", "<hr", "<h1", "<h2", "<h3", "<i", "<input", "<img",
"<li", "<meta", "<multicol", "<ol", "<p", "<pre", "<small", "<span", "<strong",
"<sub", "<sup", "<table", "<td", "<th", "<tr", "<tt", "<kbd", "<ul", "<var"
};
const int commandHtmlSize = sizeof(commandHtml) / sizeof(*commandHtml);
// Only entities which are translatable to plain text are used here. Others
// are copied unchanged to output.
const char *commandHtmlEntities[] = {
"&copy", // (C)
"&trade", // (TM)
"&reg", // (R)
"&lt", // less-than symbol
"&gt", // greater-than symbol
"&amp", // ampersand
"&apos", // single quotation mark (straight)
"&quot", // double quotation mark (straight)
"&lsquo", // left single quotation mark
"&rsquo", // right single quotation mark
"&ldquo", // left double quotation mark
"&rdquo", // right double quotation mark
"&ndash", // n-dash (for numeric ranges, e.g. 28)
"&mdash", // --
"&nbsp", //
"&times", // x
"&minus", // -
"&sdot", // .
"&sim", // ~
"&le", // <=
"&ge", // >=
"&larr", // <--
"&rarr" // -->
};
const int commandHtmlEntitiesSize = sizeof(commandHtmlEntities) / sizeof(*commandHtmlEntities);
#endif

View file

@ -0,0 +1,69 @@
/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.html.
*
* doxyentity.cxx
*
* Part of the Doxygen comment translation module of SWIG.
* ----------------------------------------------------------------------------- */
#include "doxyentity.h"
#include <iostream>
using std::cout;
DoxygenEntity::DoxygenEntity(const std::string &typeEnt):typeOfEntity(typeEnt), isLeaf(true) {
}
/* Basic node for commands that have
* only 1 item after them
* example: \b word
* OR holding a std::string
*/
DoxygenEntity::DoxygenEntity(const std::string &typeEnt, const std::string &param1) : typeOfEntity(typeEnt), data(param1), isLeaf(true) {
}
/* Nonterminal node
* contains
*/
DoxygenEntity::DoxygenEntity(const std::string &typeEnt, const DoxygenEntityList &entList) : typeOfEntity(typeEnt), isLeaf(false), entityList(entList) {
}
void DoxygenEntity::printEntity(int level) const {
int thisLevel = level;
if (isLeaf) {
for (int i = 0; i < thisLevel; i++) {
cout << "\t";
}
cout << "Node Leaf Command: '" << typeOfEntity << "', ";
if (!data.empty()) {
cout << "Node Data: '" << data << "'";
}
cout << std::endl;
} else {
for (int i = 0; i < thisLevel; i++) {
cout << "\t";
}
cout << "Node Command: '" << typeOfEntity << "'" << std::endl;
thisLevel++;
for (DoxygenEntityListCIt p = entityList.begin(); p != entityList.end(); p++) {
p->printEntity(thisLevel);
}
}
}

View file

@ -0,0 +1,45 @@
/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.html.
*
* doxyentity.h
*
* Part of the Doxygen comment translation module of SWIG.
* ----------------------------------------------------------------------------- */
#ifndef DOXYGENENTITY_H_
#define DOXYGENENTITY_H_
#include <string>
#include <list>
class DoxygenEntity;
typedef std::list<DoxygenEntity> DoxygenEntityList;
typedef DoxygenEntityList::iterator DoxygenEntityListIt;
typedef DoxygenEntityList::const_iterator DoxygenEntityListCIt;
/*
* Structure to represent a doxygen comment entry
*/
class DoxygenEntity {
public:
std::string typeOfEntity;
std::string data;
bool isLeaf;
DoxygenEntityList entityList;
DoxygenEntity(const std::string &typeEnt);
DoxygenEntity(const std::string &typeEnt, const std::string &param1);
DoxygenEntity(const std::string &typeEnt, const DoxygenEntityList &entList);
void printEntity(int level) const;
};
#endif

File diff suppressed because it is too large Load diff

372
Source/Doxygen/doxyparser.h Normal file
View file

@ -0,0 +1,372 @@
/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.html.
*
* doxyparser.h
* ----------------------------------------------------------------------------- */
#ifndef DOXYGENPARSER_H_
#define DOXYGENPARSER_H_
#include <string>
#include <list>
#include <map>
#include <vector>
#include <set>
#include "swig.h"
#include "doxyentity.h"
class DoxygenParser {
private:
enum DoxyCommandEnum {
NONE = -1,
SIMPLECOMMAND,
COMMANDWORD,
COMMANDLINE,
COMMANDPARAGRAPH,
COMMANDENDCOMMAND,
COMMANDWORDPARAGRAPH,
COMMANDWORDLINE,
COMMANDWORDOWORDWORD,
COMMANDOWORD,
COMMANDERRORTHROW,
COMMANDUNIQUE,
COMMAND_HTML,
COMMAND_HTML_ENTITY,
COMMAND_ALIAS,
COMMAND_IGNORE,
END_LINE,
PARAGRAPH_END,
PLAINSTRING,
COMMAND
};
/** This class contains parts of Doxygen comment as a token. */
class Token {
public:
DoxyCommandEnum m_tokenType;
std::string m_tokenString; /* the data , such as param for @param */
Token(DoxyCommandEnum tType, std::string tString) : m_tokenType(tType), m_tokenString(tString) {
}
std::string toString() const {
switch (m_tokenType) {
case END_LINE:
return "{END OF LINE}";
case PARAGRAPH_END:
return "{END OF PARAGRAPH}";
case PLAINSTRING:
return "{PLAINSTRING :" + m_tokenString + "}";
case COMMAND:
return "{COMMAND : " + m_tokenString + "}";
default:
return "";
}
}
};
typedef std::vector<Token> TokenList;
typedef TokenList::const_iterator TokenListCIt;
typedef TokenList::iterator TokenListIt;
TokenList m_tokenList;
TokenListCIt m_tokenListIt;
typedef std::map<std::string, DoxyCommandEnum> DoxyCommandsMap;
typedef DoxyCommandsMap::iterator DoxyCommandsMapIt;
/*
* Map of Doxygen commands to determine if a string is a
* command and how it needs to be parsed
*/
static DoxyCommandsMap doxygenCommands;
static std::set<std::string> doxygenSectionIndicators;
bool m_isVerbatimText; // used to handle \htmlonly and \verbatim commands
bool m_isInQuotedString;
Node *m_node;
std::string m_fileName;
int m_fileLineNo;
/*
* Return the end command for a command appearing in "ignore" feature or empty
* string if this is a simple command and not a block one.
*/
std::string getIgnoreFeatureEndCommand(const std::string &theCommand) const;
/*
* Helper for getting the value of doxygen:ignore feature or its argument.
*/
String *getIgnoreFeature(const std::string &theCommand, const char *argument = NULL) const;
/*
* Whether to print lots of debug info during parsing
*/
bool noisy;
/*
*Changes a std::string to all lower case
*/
std::string stringToLower(const std::string &stringToConvert);
/*
* isSectionIndicator returns a boolean if the command is a section indicator
* This is a helper method for finding the end of a paragraph
* by Doxygen's terms
*/
bool isSectionIndicator(const std::string &smallString);
/*
* Determines how a command should be handled (what group it belongs to
* for parsing rules
*/
DoxyCommandEnum commandBelongs(const std::string &theCommand);
/*
*prints the parse tree
*/
void printTree(const std::list<DoxygenEntity> &rootList);
/**
* Returns true if the next token is end of line token. This is important
* when single word commands like \c are at the end of line.
*/
bool isEndOfLine();
/**
* Skips spaces, tabs, and end of line tokens.
*/
void skipWhitespaceTokens();
/**
* Removes all spaces and tabs from beginning end end of string.
*/
std::string trim(const std::string &text);
/*
* Returns string of the next token if the next token is PLAINSTRING. Returns
* empty string otherwise.
*/
std::string getNextToken();
/*
* Returns the next word ON THE CURRENT LINE ONLY
* if a new line is encountered, returns a blank std::string.
* Updates the iterator if successful.
*/
std::string getNextWord();
/*
* Returns the next word, which is not necessarily on the same line.
* Updates the iterator if successful.
*/
std::string getNextWordInComment();
/*
* Returns the location of the end of the line as
* an iterator.
*/
TokenListCIt getOneLine(const TokenList &tokList);
/*
* Returns a properly formatted std::string
* up til ANY command or end of line is encountered.
*/
std::string getStringTilCommand(const TokenList &tokList);
/*
* Returns a properly formatted std::string
* up til the command specified is encountered
*/
//TODO check that this behaves properly for formulas
std::string getStringTilEndCommand(const std::string &theCommand, const TokenList &tokList);
/*
* Returns the end of a Paragraph as an iterator-
* Paragraph is defined in Doxygen to be a paragraph of text
* separated by either a structural command or a blank line
*/
TokenListCIt getEndOfParagraph(const TokenList &tokList);
/*
* Returns the end of a section, defined as the first blank line OR first
* encounter of the same command. Example of this behaviour is \arg.
* If no end is encountered, returns the last token of the std::list.
*/
TokenListCIt getEndOfSection(const std::string &theCommand, const TokenList &tokList);
/*
* This method is for returning the end of a specific form of doxygen command
* that begins with a \command and ends in \endcommand
* such as \code and \endcode. The proper usage is
* progressTilEndCommand("endcode", tokenList);
* If the end is never encountered, it returns the end of the std::list.
*/
TokenListCIt getEndCommand(const std::string &theCommand, const TokenList &tokList);
/*
* A special method for commands such as \arg that end at the end of a
* paragraph OR when another \arg is encountered
//TODO getTilAnyCommand
TokenListCIt getTilAnyCommand(const std::string &theCommand, const TokenList &tokList);
*/
/**
* This methods skips end of line token, if it is the next token to be
* processed. It is called with comment commands which have args till the
* end of line, such as 'addtogroup' or 'addindex'.
* It is up to translator to specific language to decide whether
* to insert eol or not. For example, if a command is ignored in target
* language, new lines may make formatting ugly (Python).
*/
void skipEndOfLine();
/*
* Method for Adding a Simple Command
* Format: @command
* Plain commands, such as newline etc, they contain no other data
* \n \\ \@ \& \$ \# \< \> \%
*/
void addSimpleCommand(const std::string &theCommand, DoxygenEntityList &doxyList);
/*
* CommandWord
* Format: @command <word>
* Commands with a single WORD after then such as @b
* "a", "b", "c", "e", "em", "p", "def", "enum", "example", "package",
* "relates", "namespace", "relatesalso","anchor", "dontinclude", "include",
* "includelineno"
*/
void addCommandWord(const std::string &theCommand, const TokenList &tokList, DoxygenEntityList &doxyList);
/*
* CommandLine
* Format: @command (line)
* Commands with a single LINE after then such as @var
* "addindex", "fn", "name", "line", "var", "skipline", "typedef", "skip",
* "until", "property"
*/
void addCommandLine(const std::string &theCommand, const TokenList &tokList, DoxygenEntityList &doxyList);
/*
* CommandParagraph
* Format: @command {paragraph}
* Commands with a single paragraph after then such as @return
* "return", "remarks", "since", "test", "sa", "see", "pre", "post",
* "details", "invariant", "deprecated", "date", "note", "warning",
* "version", "todo", "bug", "attention", "brief", "arg", "author"
*/
void addCommandParagraph(const std::string &theCommand, const TokenList &tokList, DoxygenEntityList &doxyList);
/*
* Command EndCommand
* Format: @command and ends at @endcommand
* Commands that take in a block of text such as @code:
* "code", "dot", "msc", "f$", "f[", "f{environment}{", "htmlonly",
* "latexonly", "manonly", "verbatim", "xmlonly", "cond", "if", "ifnot",
* "link"
* Returns 1 if success, 0 if the endcommand is never encountered.
*/
void addCommandEndCommand(const std::string &theCommand, const TokenList &tokList, DoxygenEntityList &doxyList);
/*
* CommandWordParagraph
* Format: @command <word> {paragraph}
* Commands such as param
* "param", "tparam", "throw", "throws", "retval", "exception"
*/
void addCommandWordParagraph(const std::string &theCommand, const TokenList &tokList, DoxygenEntityList &doxyList);
/*
* CommandWordLine
* Format: @command <word> (line)
* Commands such as param
* "page", "subsection", "subsubsection", "section", "paragraph", "defgroup"
*/
void addCommandWordLine(const std::string &theCommand, const TokenList &tokList, DoxygenEntityList &doxyList);
/*
* Command Word Optional Word Optional Word
* Format: @command <word> [<header-file>] [<header-name>]
* Commands such as class
* "category", "class", "protocol", "interface", "struct", "union"
*/
void addCommandWordOWordOWord(const std::string &theCommand, const TokenList &tokList, DoxygenEntityList &doxyList);
/*
* Command Optional Word
* Format: @command [<word>]
* Commands such as dir
* "dir", "file", "cond"
*/
void addCommandOWord(const std::string &theCommand, const TokenList &tokList, DoxygenEntityList &doxyList);
/*
* Commands that should not be encountered (such as PHP only)
* goes til the end of line then returns
*/
void addCommandErrorThrow(const std::string &theCommand, const TokenList &tokList, DoxygenEntityList &doxyList);
void addCommandHtml(const std::string &theCommand, const TokenList &tokList, DoxygenEntityList &doxyList);
void addCommandHtmlEntity(const std::string &theCommand, const TokenList &tokList, DoxygenEntityList &doxyList);
/*
*Adds the unique commands- different process for each unique command
*/
void addCommandUnique(const std::string &theCommand, const TokenList &tokList, DoxygenEntityList &doxyList);
/*
* Replace the given command with its predefined alias expansion.
*/
void aliasCommand(const std::string &theCommand, const TokenList &tokList, DoxygenEntityList &doxyList);
/*
* Simply ignore the given command, possibly with the word following it or
* until the matching end command.
*/
void ignoreCommand(const std::string &theCommand, const TokenList &tokList, DoxygenEntityList &doxyList);
/*
* The actual "meat" of the doxygen parser. Calls the correct addCommand...()
* function.
*/
void addCommand(const std::string &commandString, const TokenList &tokList, DoxygenEntityList &doxyList);
DoxygenEntityList parse(TokenListCIt endParsingIndex, const TokenList &tokList, bool root = false);
/*
* Fill static doxygenCommands and sectionIndicators containers
*/
void fillTables();
/** Processes comment when \htmlonly and \verbatim commands are encountered. */
size_t processVerbatimText(size_t pos, const std::string &line);
bool processEscapedChars(size_t &pos, const std::string &line);
void processWordCommands(size_t &pos, const std::string &line);
void processHtmlTags(size_t &pos, const std::string &line);
void processHtmlEntities(size_t &pos, const std::string &line);
/** Processes comment outside \htmlonly and \verbatim commands. */
size_t processNormalComment(size_t pos, const std::string &line);
void tokenizeDoxygenComment(const std::string &doxygenComment, const std::string &fileName, int fileLine);
void printList();
void printListError(int warningType, const std::string &message);
typedef std::vector<std::string> StringVector;
typedef StringVector::const_iterator StringVectorCIt;
StringVector split(const std::string &text, char separator);
bool isStartOfDoxyCommentChar(char c);
bool addDoxyCommand(DoxygenParser::TokenList &tokList, const std::string &cmd);
public:
DoxygenParser(bool noisy = false);
virtual ~DoxygenParser();
DoxygenEntityList createTree(Node *node, String *documentation);
};
#endif

View file

@ -0,0 +1,50 @@
/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.html.
*
* doxytranslator.cxx
*
* Module to return documentation for nodes formatted for various documentation
* systems.
* ----------------------------------------------------------------------------- */
#include "doxytranslator.h"
DoxygenTranslator::DoxygenTranslator(int flags) : m_flags(flags), parser((flags &debug_parser) != 0) {
}
DoxygenTranslator::~DoxygenTranslator() {
}
bool DoxygenTranslator::hasDocumentation(Node *node) {
return getDoxygenComment(node) != NULL;
}
String *DoxygenTranslator::getDoxygenComment(Node *node) {
return Getattr(node, "doxygen");
}
String *DoxygenTranslator::getDocumentation(Node *node) {
if (!hasDocumentation(node)) {
return NewString("");
}
return makeDocumentation(node);
}
void DoxygenTranslator::printTree(const DoxygenEntityList &entityList) {
for (DoxygenEntityListCIt p = entityList.begin(); p != entityList.end(); p++) {
p->printEntity(0);
}
}

View file

@ -0,0 +1,89 @@
/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.html.
*
* doxytranslator.h
*
* Module to return documentation for nodes formatted for various documentation
* systems.
* ----------------------------------------------------------------------------- */
#ifndef DOXYGENTRANSLATOR_H_
#define DOXYGENTRANSLATOR_H_
#include "swig.h"
#include "doxyentity.h"
#include "doxyparser.h"
#include <list>
#include <string>
/*
* This is a base class for translator classes. It defines the basic interface
* for translators, which convert Doxygen comments into alternative formats for
* target languages.
*/
class DoxygenTranslator {
public:
/*
* Bit flags for the translator ctor.
*
* Derived classes may define additional flags.
*/
enum {
// Use DoxygenParser in "noisy" mode.
debug_parser = 1,
// Output results of translating Doxygen comments.
debug_translator = 2
};
/*
* Constructor
*/
DoxygenTranslator(int flags = 0);
/*
* Virtual destructor.
*/
virtual ~DoxygenTranslator();
/*
* Return the documentation for a given node formated for the correct
* documentation system.
*/
String *getDocumentation(Node *node);
/*
* Returns truem is the specified node has comment attached.
*/
bool hasDocumentation(Node *node);
/*
* Get original comment string in Doxygen-format.
*/
String *getDoxygenComment(Node *node);
protected:
// The flags passed to the ctor.
const int m_flags;
DoxygenParser parser;
/*
* Returns the documentation formatted for a target language.
*/
virtual String *makeDocumentation(Node *node) = 0;
/*
* Prints the details of a parsed entity list to stdout (for debugging).
*/
void printTree(const DoxygenEntityList &entityList);
};
#endif

844
Source/Doxygen/javadoc.cxx Normal file
View file

@ -0,0 +1,844 @@
/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.html.
*
* javadoc.cxx
* ----------------------------------------------------------------------------- */
#include "javadoc.h"
#include "doxyparser.h"
#include <iostream>
#include <vector>
#include <list>
#include "swigmod.h"
#define APPROX_LINE_LENGTH 64 // characters per line allowed
#define TAB_SIZE 8 // current tab size in spaces
//TODO {@link} {@linkplain} {@docRoot}, and other useful doxy commands that are not a javadoc tag
// define static tables, they are filled in JavaDocConverter's constructor
std::map<std::string, std::pair<JavaDocConverter::tagHandler, std::string> > JavaDocConverter::tagHandlers;
using std::string;
using std::list;
using std::vector;
void JavaDocConverter::fillStaticTables() {
if (tagHandlers.size()) // fill only once
return;
/*
* Some translation rules:
*
* @ and \ must be escaped for both Java and Python to appear on output: \@, \\,
* while Doxygen produces output in both cases.
* Rule: @ and \ with space on the right should get to output.
*
* :: remains intact, even in class::method(). But you can use class#method also
* in C++ comment and it is properly translated to C++ output (changed by doxygen to ::)
* and Java output (remains #).
* Rule: SWIG type system can't be used to convert C::m to C#m, because in Java it is C.m
* Use string replacement :: --> # in tag see and links.
*
* HTML tags must be translated - remain in Java, to markdown in Python
*
* Unknown HTML tags, for example <x> is translated to &lt;x&gt; by doxygen, while
* Java src is <x> and therefore invisible on output - browser ignores unknown command.
* This is handy in syntax descriptions, for example: more <fileName>.
*
* Standalone < and > need not be translated, they are rendered properly in
* all three outputs.
*
* ., %, and " need not to be translated
*
* entities must be translated - remain in Java, something meaningful in Python (&lt, ...)
*
* - Python
* - add comments also to auto-generated methods like equals(), delete() in Java,
* and methods for std::vector(), ...
* Commenting methods of std types is simple - add comment to std_*.i file.
*/
// these commands insert HTML tags
tagHandlers["a"] = make_pair(&JavaDocConverter::handleTagHtml, "i");
tagHandlers["arg"] = make_pair(&JavaDocConverter::handleTagHtml, "li");
tagHandlers["b"] = make_pair(&JavaDocConverter::handleTagHtml, "b");
tagHandlers["c"] = make_pair(&JavaDocConverter::handleTagHtml, "code");
tagHandlers["cite"] = make_pair(&JavaDocConverter::handleTagHtml, "i");
tagHandlers["e"] = make_pair(&JavaDocConverter::handleTagHtml, "i");
tagHandlers["em"] = make_pair(&JavaDocConverter::handleTagHtml, "i");
tagHandlers["li"] = make_pair(&JavaDocConverter::handleTagHtml, "li");
tagHandlers["p"] = make_pair(&JavaDocConverter::handleTagHtml, "code");
// these commands insert just a single char, some of them need to be escaped
tagHandlers["$"] = make_pair(&JavaDocConverter::handleTagChar, "");
tagHandlers["@"] = make_pair(&JavaDocConverter::handleTagChar, "");
tagHandlers["\\"] = make_pair(&JavaDocConverter::handleTagChar, "");
tagHandlers["<"] = make_pair(&JavaDocConverter::handleTagChar, "&lt;");
tagHandlers[">"] = make_pair(&JavaDocConverter::handleTagChar, "&gt;");
tagHandlers["&"] = make_pair(&JavaDocConverter::handleTagChar, "&amp;");
tagHandlers["#"] = make_pair(&JavaDocConverter::handleTagChar, "");
tagHandlers["%"] = make_pair(&JavaDocConverter::handleTagChar, "");
tagHandlers["~"] = make_pair(&JavaDocConverter::handleTagChar, "");
tagHandlers["\""] = make_pair(&JavaDocConverter::handleTagChar, "&quot;");
tagHandlers["."] = make_pair(&JavaDocConverter::handleTagChar, "");
tagHandlers["::"] = make_pair(&JavaDocConverter::handleTagChar, "");
// these commands are stripped out
tagHandlers["attention"] = make_pair(&JavaDocConverter::handleParagraph, "");
tagHandlers["anchor"] = make_pair(&JavaDocConverter::handleTagAnchor, "");
tagHandlers["brief"] = make_pair(&JavaDocConverter::handleParagraph, "");
tagHandlers["bug"] = make_pair(&JavaDocConverter::handleParagraph, "");
tagHandlers["date"] = make_pair(&JavaDocConverter::handleParagraph, "");
tagHandlers["details"] = make_pair(&JavaDocConverter::handleParagraph, "");
// this command is inserts text accumulated after cmd htmlonly -
// see DoxygenParser - CMD_HTML_ONLY.
tagHandlers["htmlonly"] = make_pair(&JavaDocConverter::handleParagraph, "");
tagHandlers["invariant"] = make_pair(&JavaDocConverter::handleParagraph, "");
tagHandlers["latexonly"] = make_pair(&JavaDocConverter::handleParagraph, "");
tagHandlers["manonly"] = make_pair(&JavaDocConverter::handleParagraph, "");
tagHandlers["partofdescription"] = make_pair(&JavaDocConverter::handleParagraph, "");
tagHandlers["rtfonly"] = make_pair(&JavaDocConverter::handleParagraph, "");
tagHandlers["short"] = make_pair(&JavaDocConverter::handleParagraph, "");
tagHandlers["xmlonly"] = make_pair(&JavaDocConverter::handleParagraph, "");
// these commands are kept as-is, they are supported by JavaDoc
tagHandlers["author"] = make_pair(&JavaDocConverter::handleTagSame, "");
tagHandlers["authors"] = make_pair(&JavaDocConverter::handleTagSame, "author");
tagHandlers["deprecated"] = make_pair(&JavaDocConverter::handleTagSame, "");
tagHandlers["exception"] = make_pair(&JavaDocConverter::handleTagSame, "");
tagHandlers["package"] = make_pair(&JavaDocConverter::handleTagSame, "");
tagHandlers["param"] = make_pair(&JavaDocConverter::handleTagParam, "");
tagHandlers["tparam"] = make_pair(&JavaDocConverter::handleTagParam, "");
tagHandlers["ref"] = make_pair(&JavaDocConverter::handleTagRef, "");
tagHandlers["result"] = make_pair(&JavaDocConverter::handleTagSame, "return");
tagHandlers["return"] = make_pair(&JavaDocConverter::handleTagSame, "");
tagHandlers["returns"] = make_pair(&JavaDocConverter::handleTagSame, "return");
//tagHandlers["see"] = make_pair(&JavaDocConverter::handleTagSame, "");
//tagHandlers["sa"] = make_pair(&JavaDocConverter::handleTagSame, "see");
tagHandlers["since"] = make_pair(&JavaDocConverter::handleTagSame, "");
tagHandlers["throws"] = make_pair(&JavaDocConverter::handleTagSame, "");
tagHandlers["throw"] = make_pair(&JavaDocConverter::handleTagSame, "throws");
tagHandlers["version"] = make_pair(&JavaDocConverter::handleTagSame, "");
// these commands have special handlers
tagHandlers["code"] = make_pair(&JavaDocConverter::handleTagExtended, "code");
tagHandlers["cond"] = make_pair(&JavaDocConverter::handleTagMessage, "Conditional comment: ");
tagHandlers["copyright"] = make_pair(&JavaDocConverter::handleTagMessage, "Copyright: ");
tagHandlers["else"] = make_pair(&JavaDocConverter::handleTagIf, "Else: ");
tagHandlers["elseif"] = make_pair(&JavaDocConverter::handleTagIf, "Else if: ");
tagHandlers["endcond"] = make_pair(&JavaDocConverter::handleTagMessage, "End of conditional comment.");
// space in second arg prevents Javadoc to treat '@ example' as command. File name of
// example is still informative to user.
tagHandlers["example"] = make_pair(&JavaDocConverter::handleTagSame, " example");
tagHandlers["if"] = make_pair(&JavaDocConverter::handleTagIf, "If: ");
tagHandlers["ifnot"] = make_pair(&JavaDocConverter::handleTagIf, "If not: ");
tagHandlers["image"] = make_pair(&JavaDocConverter::handleTagImage, "");
tagHandlers["link"] = make_pair(&JavaDocConverter::handleTagLink, "");
tagHandlers["see"] = make_pair(&JavaDocConverter::handleTagSee, "");
tagHandlers["sa"] = make_pair(&JavaDocConverter::handleTagSee, "");
tagHandlers["note"] = make_pair(&JavaDocConverter::handleTagMessage, "Note: ");
tagHandlers["overload"] = make_pair(&JavaDocConverter::handleTagMessage,
"This is an overloaded member function, provided for"
" convenience. It differs from the above function only in what" " argument(s) it accepts.");
tagHandlers["par"] = make_pair(&JavaDocConverter::handleTagPar, "");
tagHandlers["remark"] = make_pair(&JavaDocConverter::handleTagMessage, "Remarks: ");
tagHandlers["remarks"] = make_pair(&JavaDocConverter::handleTagMessage, "Remarks: ");
tagHandlers["todo"] = make_pair(&JavaDocConverter::handleTagMessage, "TODO: ");
tagHandlers["verbatim"] = make_pair(&JavaDocConverter::handleTagExtended, "literal");
// \f commands output literal Latex formula, which is still better than nothing.
tagHandlers["f$"] = make_pair(&JavaDocConverter::handleTagVerbatim, "");
tagHandlers["f["] = make_pair(&JavaDocConverter::handleTagVerbatim, "");
tagHandlers["f{"] = make_pair(&JavaDocConverter::handleTagVerbatim, "");
tagHandlers["warning"] = make_pair(&JavaDocConverter::handleTagMessage, "Warning: ");
// this command just prints it's contents
// (it is internal command of swig's parser, contains plain text)
tagHandlers["plainstd::string"] = make_pair(&JavaDocConverter::handlePlainString, "");
tagHandlers["plainstd::endl"] = make_pair(&JavaDocConverter::handleNewLine, "");
tagHandlers["n"] = make_pair(&JavaDocConverter::handleNewLine, "");
// HTML tags
tagHandlers["<a"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<a");
tagHandlers["<b"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<b");
tagHandlers["<blockquote"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<blockquote");
tagHandlers["<body"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<body");
tagHandlers["<br"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<br");
tagHandlers["<center"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<center");
tagHandlers["<caption"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<caption");
tagHandlers["<code"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<code");
tagHandlers["<dd"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<dd");
tagHandlers["<dfn"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<dfn");
tagHandlers["<div"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<div");
tagHandlers["<dl"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<dl");
tagHandlers["<dt"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<dt");
tagHandlers["<em"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<em");
tagHandlers["<form"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<form");
tagHandlers["<hr"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<hr");
tagHandlers["<h1"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<h1");
tagHandlers["<h2"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<h2");
tagHandlers["<h3"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<h3");
tagHandlers["<i"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<i");
tagHandlers["<input"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<input");
tagHandlers["<img"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<img");
tagHandlers["<li"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<li");
tagHandlers["<meta"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<meta");
tagHandlers["<multicol"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<multicol");
tagHandlers["<ol"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<ol");
tagHandlers["<p"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<p");
tagHandlers["<pre"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<pre");
tagHandlers["<small"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<small");
tagHandlers["<span"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<span");
tagHandlers["<strong"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<strong");
tagHandlers["<sub"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<sub");
tagHandlers["<sup"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<sup");
tagHandlers["<table"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<table");
tagHandlers["<td"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<td");
tagHandlers["<th"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<th");
tagHandlers["<tr"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<tr");
tagHandlers["<tt"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<tt");
tagHandlers["<kbd"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<kbd");
tagHandlers["<ul"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<ul");
tagHandlers["<var"] = make_pair(&JavaDocConverter::handleDoxyHtmlTag, "<var");
// HTML entities
tagHandlers["&copy"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&copy");
tagHandlers["&trade"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&trade");
tagHandlers["&reg"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&reg");
tagHandlers["&lt"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&lt");
tagHandlers["&gt"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&gt");
tagHandlers["&amp"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&amp");
tagHandlers["&apos"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&apos");
tagHandlers["&quot"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&quot");
tagHandlers["&lsquo"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&lsquo");
tagHandlers["&rsquo"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&rsquo");
tagHandlers["&ldquo"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&ldquo");
tagHandlers["&rdquo"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&rdquo");
tagHandlers["&ndash"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&ndash");
tagHandlers["&mdash"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&mdash");
tagHandlers["&nbsp"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&nbsp");
tagHandlers["&times"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&times");
tagHandlers["&minus"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&minus");
tagHandlers["&sdot"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&sdot");
tagHandlers["&sim"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&sim");
tagHandlers["&le"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&le");
tagHandlers["&ge"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&ge");
tagHandlers["&larr"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&larr");
tagHandlers["&rarr"] = make_pair(&JavaDocConverter::handleHtmlEntity, "&rarr");
}
JavaDocConverter::JavaDocConverter(int flags) :
DoxygenTranslator(flags) {
fillStaticTables();
}
/**
* Formats comment lines by inserting '\n *' at to long lines and tabs for
* indent. Currently it is disabled, which means original comment format is
* preserved. Experience shows, that this is usually better than breaking
* lines automatically, especially because original line endings are not removed,
* which results in short lines. To be useful, this function should have much
* better algorithm.
*/
std::string JavaDocConverter::formatCommand(std::string unformattedLine, int indent) {
std::string formattedLines;
return unformattedLine; // currently disabled
int lastPosition = 0;
int i = 0;
int isFirstLine = 1;
while (i != -1 && i < (int) unformattedLine.length()) {
lastPosition = i;
if (isFirstLine) {
i += APPROX_LINE_LENGTH;
} else {
i += APPROX_LINE_LENGTH - indent * TAB_SIZE;
}
i = unformattedLine.find(" ", i);
if (i > 0 && i + 1 < (int) unformattedLine.length()) {
if (!isFirstLine)
for (int j = 0; j < indent; j++) {
formattedLines.append("\t");
} else {
isFirstLine = 0;
}
formattedLines.append(unformattedLine.substr(lastPosition, i - lastPosition + 1));
formattedLines.append("\n *");
}
}
if (lastPosition < (int) unformattedLine.length()) {
if (!isFirstLine) {
for (int j = 0; j < indent; j++) {
formattedLines.append("\t");
}
}
formattedLines.append(unformattedLine.substr(lastPosition, unformattedLine.length() - lastPosition));
}
return formattedLines;
}
/**
* Returns true, if the given parameter exists in the current node
* (for example param is a name of function parameter). If feature
* 'doxygen:nostripparams' is set, then this method always returns
* true - parameters are copied to output regardless of presence in
* function params list.
*/
bool JavaDocConverter::paramExists(std::string param) {
if (GetFlag(currentNode, "feature:doxygen:nostripparams")) {
return true;
}
ParmList *plist = CopyParmList(Getattr(currentNode, "parms"));
for (Parm *p = plist; p;) {
if (Getattr(p, "name") && Char(Getattr(p, "name")) == param) {
return true;
}
/* doesn't seem to work always: in some cases (especially for 'self' parameters)
* tmap:in is present, but tmap:in:next is not and so this code skips all the parameters
*/
//p = Getattr(p, "tmap:in") ? Getattr(p, "tmap:in:next") : nextSibling(p);
p = nextSibling(p);
}
Delete(plist);
return false;
}
std::string JavaDocConverter::translateSubtree(DoxygenEntity &doxygenEntity) {
std::string translatedComment;
if (doxygenEntity.isLeaf) {
return translatedComment;
}
for (DoxygenEntityListIt p = doxygenEntity.entityList.begin(); p != doxygenEntity.entityList.end(); p++) {
translateEntity(*p, translatedComment);
translateSubtree(*p);
}
return translatedComment;
}
/**
* Checks if a handler for the given tag exists, and calls it.
*/
void JavaDocConverter::translateEntity(DoxygenEntity &tag, std::string &translatedComment) {
std::map<std::string, std::pair<tagHandler, std::string> >::iterator it;
it = tagHandlers.find(tag.typeOfEntity);
if (it != tagHandlers.end()) {
(this->*(it->second.first))(tag, translatedComment, it->second.second);
} else {
// do NOT print warning, since there are many tags, which are not
// translatable - many warnings hide important ones
// addError(WARN_DOXYGEN_COMMAND_ERROR, "Unknown doxygen or HTML tag: " + tag.typeOfEntity);
}
}
void JavaDocConverter::handleTagAnchor(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
translatedComment += "<a id=\"" + translateSubtree(tag) + "\"></a>";
}
void JavaDocConverter::handleTagHtml(DoxygenEntity &tag, std::string &translatedComment, std::string &arg) {
if (tag.entityList.size()) { // do not include empty tags
std::string tagData = translateSubtree(tag);
// wrap the thing, ignoring whitespace
size_t wsPos = tagData.find_last_not_of("\n\t ");
if (wsPos != std::string::npos)
translatedComment += "<" + arg + ">" + tagData.substr(0, wsPos + 1) + "</" + arg + ">" + tagData.substr(wsPos + 1);
else
translatedComment += "<" + arg + ">" + translateSubtree(tag) + "</" + arg + "> ";
}
}
void JavaDocConverter::handleDoxyHtmlTag(DoxygenEntity &tag, std::string &translatedComment, std::string &arg) {
std::string htmlTagArgs = tag.data;
if (htmlTagArgs == "/") {
// end html tag, for example "</ul>
translatedComment += "</" + arg.substr(1) + ">";
} else {
translatedComment += arg + htmlTagArgs + ">";
}
}
void JavaDocConverter::handleHtmlEntity(DoxygenEntity &, std::string &translatedComment, std::string &arg) {
// html entities can be preserved for Java
translatedComment += arg + ';';
}
void JavaDocConverter::handleNewLine(DoxygenEntity &, std::string &translatedComment, std::string &) {
// <br> tag is added, because otherwise to much text is joined
// into same paragraph by javadoc. For example, doxy list:
// - item one
// - item two
// becomes one paragraph with surrounding text without newlines.
// This way we get to many empty lines in javadoc output, but this
// is still better than joined lines. Possibility for improvements
// exists.
translatedComment += "<br>\n * ";
}
void JavaDocConverter::handleTagChar(DoxygenEntity &tag, std::string &translatedComment, std::string &arg) {
// escape it if we need to, else just print
if (arg.size())
translatedComment += arg;
else
translatedComment += tag.typeOfEntity;
}
// handles tags which are the same in Doxygen and Javadoc.
void JavaDocConverter::handleTagSame(DoxygenEntity &tag, std::string &translatedComment, std::string &arg) {
if (arg.size())
tag.typeOfEntity = arg;
translatedComment += formatCommand(std::string("@" + tag.typeOfEntity + " " + translateSubtree(tag)), 2);
}
void JavaDocConverter::handleParagraph(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
translatedComment += formatCommand(translateSubtree(tag), 0);
}
void JavaDocConverter::handlePlainString(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
translatedComment += tag.data;
// if (tag.data.size() && tag.data[tag.data.size()-1] != ' ')
// translatedComment += " ";
}
void JavaDocConverter::handleTagVerbatim(DoxygenEntity &tag, std::string &translatedComment, std::string &arg) {
translatedComment += arg + " ";
for (DoxygenEntityListCIt it = tag.entityList.begin(); it != tag.entityList.end(); it++) {
translatedComment += it->data;
}
}
void JavaDocConverter::handleTagExtended(DoxygenEntity &tag, std::string &translatedComment, std::string &arg) {
std::string dummy;
translatedComment += "{@" + arg + " ";
handleParagraph(tag, translatedComment, dummy);
translatedComment += "}";
}
void JavaDocConverter::handleTagIf(DoxygenEntity &tag, std::string &translatedComment, std::string &arg) {
std::string dummy;
translatedComment += arg;
if (tag.entityList.size()) {
translatedComment += tag.entityList.begin()->data;
tag.entityList.pop_front();
translatedComment += " {" + translateSubtree(tag) + "}";
}
}
void JavaDocConverter::handleTagMessage(DoxygenEntity &tag, std::string &translatedComment, std::string &arg) {
std::string dummy;
translatedComment += formatCommand(arg, 0);
handleParagraph(tag, translatedComment, dummy);
}
void JavaDocConverter::handleTagImage(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
if (tag.entityList.size() < 2)
return;
std::string file;
std::string title;
std::list<DoxygenEntity>::iterator it = tag.entityList.begin();
if (it->data != "html")
return;
it++;
file = it->data;
it++;
if (it != tag.entityList.end())
title = it->data;
translatedComment += "<img src=" + file;
if (title.size())
translatedComment += " alt=" + title;
// the size indication is supported for Latex only in Doxygen, see manual
translatedComment += "/>";
}
void JavaDocConverter::handleTagPar(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
std::string dummy;
translatedComment += "<p";
if (tag.entityList.size()) {
translatedComment += " alt=\"" + tag.entityList.begin()->data + "\"";
translatedComment += ">";
tag.entityList.pop_front();
handleParagraph(tag, translatedComment, dummy);
}
translatedComment += "</p>";
}
void JavaDocConverter::handleTagParam(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
std::string dummy;
if (!tag.entityList.size())
return;
if (!paramExists(tag.entityList.begin()->data))
return;
translatedComment += "@param ";
translatedComment += tag.entityList.begin()->data;
tag.entityList.pop_front();
handleParagraph(tag, translatedComment, dummy);
}
void JavaDocConverter::handleTagRef(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
std::string dummy;
if (!tag.entityList.size())
return;
// we translate to link, although \page is not supported in Java, but
// reader at least knows what to look at. Also for \anchor tag on the same
// page this link works.
string anchor = tag.entityList.begin()->data;
tag.entityList.pop_front();
string anchorText = anchor;
if (!tag.entityList.empty()) {
anchorText = tag.entityList.begin()->data;
}
translatedComment += "<a href=\"#" + anchor + "\">" + anchorText + "</a>";
}
string JavaDocConverter::convertLink(string linkObject) {
if (GetFlag(currentNode, "feature:doxygen:nolinktranslate"))
return linkObject;
// find the params in function in linkObject (if any)
size_t lbracePos = linkObject.find('(', 0);
size_t rbracePos = linkObject.find(')', 0);
if (lbracePos == string::npos || rbracePos == string::npos || lbracePos >= rbracePos)
return "";
string paramsStr = linkObject.substr(lbracePos + 1,
rbracePos - lbracePos - 1);
// strip the params, to fill them later
string additionalObject = linkObject.substr(rbracePos + 1, string::npos);
linkObject = linkObject.substr(0, lbracePos);
// find all the params
vector<string> params;
size_t lastPos = 0, commaPos = 0;
while (true) {
commaPos = paramsStr.find(',', lastPos);
if (commaPos == string::npos)
commaPos = paramsStr.size();
string param = paramsStr.substr(lastPos, commaPos - lastPos);
// if any param type is empty, we are failed
if (!param.size())
return "";
params.push_back(param);
lastPos = commaPos + 1;
if (lastPos >= paramsStr.size())
break;
}
linkObject += "(";
for (size_t i = 0; i < params.size(); i++) {
// translate c/c++ type string to swig's type
// i e 'int **arr[100][10]' -> 'a(100).a(10).p.p.int'
// also converting arrays to pointers
string paramStr = params[i];
String *swigType = NewString("");
// handle const qualifier
if (paramStr.find("const") != string::npos)
SwigType_add_qualifier(swigType, "const");
// handle pointers, references and arrays
for (int j = (int)params[i].size() - 1; j >= 0; j--) {
// skip all the [...] blocks, write 'p.' for every of it
if (paramStr[j] == ']') {
while (j >= 0 && paramStr[j] != '[')
j--;
// no closing brace
if (j < 0)
return "";
SwigType_add_pointer(swigType);
continue;
} else if (paramStr[j] == '*')
SwigType_add_pointer(swigType);
else if (paramStr[j] == '&')
SwigType_add_reference(swigType);
else if (isalnum(paramStr[j])) {
size_t typeNameStart = paramStr.find_last_of(' ', j + 1);
if (typeNameStart == string::npos)
typeNameStart = 0;
else
typeNameStart++;
Append(swigType, paramStr.substr(typeNameStart, j - typeNameStart + 1).c_str());
break;
}
}
// make dummy param list, to lookup typemaps for it
Parm *dummyParam = NewParm(swigType, "", 0);
Swig_typemap_attach_parms("jstype", dummyParam, NULL);
Language::instance()->replaceSpecialVariables(0, Getattr(dummyParam, "tmap:jstype"), dummyParam);
//Swig_print(dummyParam, 1);
linkObject += Char(Getattr(dummyParam, "tmap:jstype"));
if (i != params.size() - 1)
linkObject += ",";
Delete(dummyParam);
Delete(swigType);
}
linkObject += ")";
return linkObject + additionalObject;
}
void JavaDocConverter::handleTagLink(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
std::string dummy;
if (!tag.entityList.size())
return;
string linkObject = convertLink(tag.entityList.begin()->data);
if (!linkObject.size())
linkObject = tag.entityList.begin()->data;
tag.entityList.pop_front();
translatedComment += "{@link ";
translatedComment += linkObject + " ";
handleParagraph(tag, translatedComment, dummy);
translatedComment += "}";
}
void JavaDocConverter::handleTagSee(DoxygenEntity &tag, std::string &translatedComment, std::string &) {
std::string dummy;
if (!tag.entityList.size())
return;
// tag.entity list contains contents of the @see paragraph. It should contain
// one link (references) to method with or without parameters. Doxygen supports
// arbitrary text and types mixed, but this feature is not supported here.
// :: or # may be used as a separator between class name and method name.
list<DoxygenEntity>::iterator it;
string methodRef;
for (it = tag.entityList.begin(); it != tag.entityList.end(); it++) {
if (it->typeOfEntity == "plainstd::endl") {
// handleNewLine(*it, translatedComment, dummy);
continue;
}
// restore entities which may be used in C++ type declaration
if (it->typeOfEntity == "&amp") {
methodRef += '&';
} else if (it->typeOfEntity == "&lt") {
methodRef += '<';
} else if (it->typeOfEntity == "&gt") {
methodRef += '>';
} else {
methodRef += it->data;
}
}
// replace :: with #, but only if it appears before left brace
size_t lbrace = methodRef.find('(');
size_t dblColon = methodRef.find("::");
if (dblColon < lbrace) {
methodRef = methodRef.substr(0, dblColon) + '#' + methodRef.substr(dblColon + 2);
}
translatedComment += "@see ";
string linkObject = convertLink(methodRef);
if (!linkObject.size()) {
linkObject = methodRef;
}
translatedComment += linkObject;
}
/* This function moves all line endings at the end of child entities
* out of the child entities to the parent.
* For example, entity tree:
-root
|-param
|-paramText
|-endline
should be turned to
-root
|-param
|-paramText
|-endline
*
*/
int JavaDocConverter::shiftEndlinesUpTree(DoxygenEntity &root, int level) {
DoxygenEntityListIt it = root.entityList.begin();
while (it != root.entityList.end()) {
// remove line endings
int ret = shiftEndlinesUpTree(*it, level + 1);
// insert them after this element
it++;
for (int i = 0; i < ret; i++) {
root.entityList.insert(it, DoxygenEntity("plainstd::endl"));
}
}
// continue only if we are not root
if (!level) {
return 0;
}
int removedCount = 0;
while (!root.entityList.empty()
&& root.entityList.rbegin()->typeOfEntity == "plainstd::endl") {
root.entityList.pop_back();
removedCount++;
}
return removedCount;
}
/**
* This makes sure that all comment lines contain '*'. It is not mandatory in doxygen,
* but highly recommended for Javadoc. '*' in empty lines are indented according
* to indentation of the first line. Indentation of non-empty lines is not
* changed - garbage in garbage out.
*/
std::string JavaDocConverter::indentAndInsertAsterisks(const string &doc) {
size_t idx = doc.find('\n');
size_t indent = 0;
// Detect indentation.
// The first line in comment is the one after '/**', which may be
// spaces and '\n' or the text. In any case it is not suitable to detect
// indentation, so we have to skip the first '\n'.
if (idx != string::npos) {
size_t nonspaceIdx = doc.find_first_not_of(" \t", idx + 1);
if (nonspaceIdx != string::npos) {
indent = nonspaceIdx - idx;
}
}
if (indent == 0) {
// we can't indent the first line less than 0
indent = 1;
}
// Create the first line of Javadoc comment.
string indentStr(indent - 1, ' ');
string translatedStr = indentStr + "/**";
if (indent > 1) {
// remove the first space, so that '*' will be aligned
translatedStr = translatedStr.substr(1);
}
translatedStr += doc;
// insert '*' before each comment line, if it does not have it
idx = translatedStr.find('\n');
while (idx != string::npos) {
size_t nonspaceIdx = translatedStr.find_first_not_of(" \t", idx + 1);
if (nonspaceIdx != string::npos && translatedStr[nonspaceIdx] != '*') {
// line without '*' found - is it empty?
if (translatedStr[nonspaceIdx] != '\n') {
// add '* ' to each line without it
translatedStr = translatedStr.substr(0, nonspaceIdx) + "* " + translatedStr.substr(nonspaceIdx);
//printf(translatedStr.c_str());
} else {
// we found empty line, replace it with indented '*'
translatedStr = translatedStr.substr(0, idx + 1) + indentStr + "* " + translatedStr.substr(nonspaceIdx);
}
}
idx = translatedStr.find('\n', nonspaceIdx);
}
// Add the last comment line properly indented
size_t nonspaceEndIdx = translatedStr.find_last_not_of(" \t");
if (nonspaceEndIdx != string::npos) {
if (translatedStr[nonspaceEndIdx] != '\n') {
translatedStr += '\n';
} else {
// remove trailing spaces
translatedStr = translatedStr.substr(0, nonspaceEndIdx + 1);
}
}
translatedStr += indentStr + "*/\n";
return translatedStr;
}
String *JavaDocConverter::makeDocumentation(Node *node) {
String *documentation = getDoxygenComment(node);
if (documentation == NULL) {
return NewString("");
}
if (GetFlag(node, "feature:doxygen:notranslate")) {
string doc = Char(documentation);
string translatedStr = indentAndInsertAsterisks(doc);
String *comment = NewString(translatedStr.c_str());
// Append(comment, documentation); Replaceall(comment, "\n", "\n * ");
return comment;
}
DoxygenEntityList entityList = parser.createTree(node, documentation);
// entityList.sort(CompareDoxygenEntities()); sorting currently not used,
if (m_flags & debug_translator) {
std::cout << "---RESORTED LIST---" << std::endl;
printTree(entityList);
}
// store the current node
// (currently just to handle params)
currentNode = node;
std::string javaDocString = "/**\n * ";
DoxygenEntity root("root", entityList);
shiftEndlinesUpTree(root);
// strip line endings at the beginning
while (!root.entityList.empty()
&& root.entityList.begin()->typeOfEntity == "plainstd::endl") {
root.entityList.pop_front();
}
// and at the end
while (!root.entityList.empty()
&& root.entityList.rbegin()->typeOfEntity == "plainstd::endl") {
root.entityList.pop_back();
}
javaDocString += translateSubtree(root);
javaDocString += "\n */\n";
if (m_flags & debug_translator) {
std::cout << "\n---RESULT IN JAVADOC---" << std::endl;
std::cout << javaDocString;
}
return NewString(javaDocString.c_str());
}
void JavaDocConverter::addError(int warningType, const std::string &message) {
Swig_warning(warningType, "", 0, "Doxygen parser warning: %s. \n", message.c_str());
}

169
Source/Doxygen/javadoc.h Normal file
View file

@ -0,0 +1,169 @@
/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.html.
*
* javadoc.h
*
* Module to return documentation for nodes formatted for JavaDoc
* ----------------------------------------------------------------------------- */
#ifndef JAVADOCCONVERTER_H_
#define JAVADOCCONVERTER_H_
#include "doxytranslator.h"
#include <map>
/*
* A class to translate doxygen comments into JavaDoc style comments.
*/
class JavaDocConverter : public DoxygenTranslator {
public:
JavaDocConverter(int flags = 0);
String *makeDocumentation(Node *node);
protected:
/*
* Used to properly format JavaDoc-style command
*/
std::string formatCommand(std::string unformattedLine, int indent);
/*
* Translate every entity in a tree.
*/
std::string translateSubtree(DoxygenEntity &doxygenEntity);
/*
* Translate one entity with the appropriate handler, according
* to the tagHandlers
*/
void translateEntity(DoxygenEntity &tag, std::string &translatedComment);
/*
* Fix all endlines location, etc
*/
int shiftEndlinesUpTree(DoxygenEntity &root, int level = 0);
/*
* Convert params in link-objects and references
*/
std::string convertLink(std::string linkObject);
/*
* Typedef for the function that handles one tag
* arg - some string argument to easily pass it through lookup table
*/
typedef void (JavaDocConverter::*tagHandler) (DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/**
* Copies verbatim args of the tag to output, used for commands like \f$, ...
*/
void handleTagVerbatim(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/** Creates anchor link. */
void handleTagAnchor(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/*
* Wrap the command data with the html tag
* arg - html tag, with no braces
*/
void handleTagHtml(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/* Handles HTML tags recognized by Doxygen, like <A ...>, <ul>, <table>, ... */
void handleDoxyHtmlTag(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/* Handles HTML entities recognized by Doxygen, like &lt;, &copy;, ... */
void handleHtmlEntity(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/*
* Just prints new line
*/
void handleNewLine(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/*
* Print the name of tag to the output, used for escape-commands
* arg - html-escaped variant, if not provided the command data is used
*/
void handleTagChar(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/*
* Do not translate and print as-is
* arg - the new tag name, if it needs to be renamed
*/
void handleTagSame(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/*
* Print only the content and strip original tag
*/
void handleParagraph(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/*
* Print only data part of code
*/
void handlePlainString(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/*
* Print extended Javadoc command, like {@code ...} or {@literal ...}
* arg - command name
*/
void handleTagExtended(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/*
* Print the if-elseif-else-endif section
*/
void handleTagIf(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/*
* Prints the specified message, than the contents of the tag
* arg - message
*/
void handleTagMessage(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/*
* Insert <img src=... /> tag if the 'format' field is specified as 'html'
*/
void handleTagImage(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/*
* Insert <p alt='title'>...</p>
*/
void handleTagPar(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/*
* Insert \@param command, if it is really a function param
*/
void handleTagParam(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/*
* Writes link for \ref tag.
*/
void handleTagRef(DoxygenEntity &tag, std::string &translatedComment, std::string &);
/*
* Insert {@link...} command, and handle all the <link-object>s correctly
* (like converting types of params, etc)
*/
void handleTagLink(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
/*
* Insert @see command, and handle all the <link-object>s correctly
* (like converting types of params, etc)
*/
void handleTagSee(DoxygenEntity &tag, std::string &translatedComment, std::string &arg);
private:
Node *currentNode;
// this contains the handler pointer and one string argument
static std::map<std::string, std::pair<tagHandler, std::string> > tagHandlers;
void fillStaticTables();
bool paramExists(std::string param);
std::string indentAndInsertAsterisks(const std::string &doc);
void addError(int warningType, const std::string &message);
};
#endif

843
Source/Doxygen/pydoc.cxx Normal file
View file

@ -0,0 +1,843 @@
/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.html.
*
* pydoc.cxx
*
* Module to return documentation for nodes formatted for PyDoc
* ----------------------------------------------------------------------------- */
#include "pydoc.h"
#include "doxyparser.h"
#include <sstream>
#include <string>
#include <vector>
#include <iostream>
#include "swigmod.h"
// define static tables, they are filled in PyDocConverter's constructor
PyDocConverter::TagHandlersMap PyDocConverter::tagHandlers;
std::map<std::string, std::string> PyDocConverter::sectionTitles;
using std::string;
// Helper class increasing the provided indent string in its ctor and decreasing
// it in its dtor.
class IndentGuard {
public:
// One indent level.
static const char *Level() {
return " ";
}
// Default ctor doesn't do anything and prevents the dtor from doing anything// too and should only be used when the guard needs to be initialized// conditionally as Init() can then be called after checking some condition.// Otherwise, prefer to use the non default ctor below.
IndentGuard() {
m_initialized = false;
}
// Ctor takes the output to determine the current indent and to remove the
// extra indent added to it in the dtor and the variable containing the indent
// to use, which must be used after every new line by the code actually
// updating the output.
IndentGuard(string &output, string &indent) {
Init(output, indent);
}
// Really initializes the object created using the default ctor.
void Init(string &output, string &indent) {
m_output = &output;
m_indent = &indent;
const size_t lastNonSpace = m_output->find_last_not_of(' ');
if (lastNonSpace == string::npos) {
m_firstLineIndent = m_output->length();
} else if ((*m_output)[lastNonSpace] == '\n') {
m_firstLineIndent = m_output->length() - (lastNonSpace + 1);
} else {
m_firstLineIndent = 0;
}
// Notice that the indent doesn't include the first line indent because it's
// implicit, i.e. it is present in the input and so is copied into the
// output anyhow.
*m_indent = Level();
m_initialized = true;
}
// Get the indent for the first line of the paragraph, which is smaller than
// the indent for the subsequent lines.
string getFirstLineIndent() const {
return string(m_firstLineIndent, ' ');
}
~IndentGuard() {
if (!m_initialized)
return;
m_indent->clear();
// Get rid of possible remaining extra indent, e.g. if there were any trailing
// new lines: we shouldn't add the extra indent level to whatever follows
// this paragraph.
static const size_t lenIndentLevel = strlen(Level());
if (m_output->length() > lenIndentLevel) {
const size_t start = m_output->length() - lenIndentLevel;
if (m_output->compare(start, string::npos, Level()) == 0)
m_output->erase(start);
}
}
private:
string *m_output;
string *m_indent;
unsigned m_firstLineIndent;
bool m_initialized;
IndentGuard(const IndentGuard &);
IndentGuard &operator=(const IndentGuard &);
};
// Return the indent of the given multiline string, i.e. the maximal number of
// spaces present in the beginning of all its non-empty lines.
static size_t determineIndent(const string &s) {
size_t minIndent = static_cast<size_t>(-1);
for (size_t lineStart = 0; lineStart < s.length();) {
const size_t lineEnd = s.find('\n', lineStart);
const size_t firstNonSpace = s.find_first_not_of(' ', lineStart);
// If inequality doesn't hold, it means that this line contains only spaces
// (notice that this works whether lineEnd is valid or string::npos), in
// which case it doesn't matter when determining the indent.
if (firstNonSpace < lineEnd) {
// Here we can be sure firstNonSpace != string::npos.
const size_t lineIndent = firstNonSpace - lineStart;
if (lineIndent < minIndent)
minIndent = lineIndent;
}
if (lineEnd == string::npos)
break;
lineStart = lineEnd + 1;
}
return minIndent;
}
static void trimWhitespace(string &s) {
const size_t lastNonSpace = s.find_last_not_of(' ');
if (lastNonSpace == string::npos)
s.clear();
else
s.erase(lastNonSpace + 1);
}
/* static */
PyDocConverter::TagHandlersMap::mapped_type PyDocConverter::make_handler(tagHandler handler) {
return make_pair(handler, std::string());
}
/* static */
PyDocConverter::TagHandlersMap::mapped_type PyDocConverter::make_handler(tagHandler handler, const char *arg) {
return make_pair(handler, arg);
}
void PyDocConverter::fillStaticTables() {
if (tagHandlers.size()) // fill only once
return;
// table of section titles, they are printed only once
// for each group of specified doxygen commands
sectionTitles["author"] = "Author: ";
sectionTitles["authors"] = "Authors: ";
sectionTitles["copyright"] = "Copyright: ";
sectionTitles["deprecated"] = "Deprecated: ";
sectionTitles["example"] = "Example: ";
sectionTitles["note"] = "Notes: ";
sectionTitles["remark"] = "Remarks: ";
sectionTitles["remarks"] = "Remarks: ";
sectionTitles["warning"] = "Warning: ";
// sectionTitles["sa"] = "See also: ";
// sectionTitles["see"] = "See also: ";
sectionTitles["since"] = "Since: ";
sectionTitles["todo"] = "TODO: ";
sectionTitles["version"] = "Version: ";
tagHandlers["a"] = make_handler(&PyDocConverter::handleTagWrap, "*");
tagHandlers["b"] = make_handler(&PyDocConverter::handleTagWrap, "**");
// \c command is translated as single quotes around next word
tagHandlers["c"] = make_handler(&PyDocConverter::handleTagWrap, "``");
tagHandlers["cite"] = make_handler(&PyDocConverter::handleTagWrap, "'");
tagHandlers["e"] = make_handler(&PyDocConverter::handleTagWrap, "*");
// these commands insert just a single char, some of them need to be escaped
tagHandlers["$"] = make_handler(&PyDocConverter::handleTagChar);
tagHandlers["@"] = make_handler(&PyDocConverter::handleTagChar);
tagHandlers["\\"] = make_handler(&PyDocConverter::handleTagChar);
tagHandlers["<"] = make_handler(&PyDocConverter::handleTagChar);
tagHandlers[">"] = make_handler(&PyDocConverter::handleTagChar);
tagHandlers["&"] = make_handler(&PyDocConverter::handleTagChar);
tagHandlers["#"] = make_handler(&PyDocConverter::handleTagChar);
tagHandlers["%"] = make_handler(&PyDocConverter::handleTagChar);
tagHandlers["~"] = make_handler(&PyDocConverter::handleTagChar);
tagHandlers["\""] = make_handler(&PyDocConverter::handleTagChar);
tagHandlers["."] = make_handler(&PyDocConverter::handleTagChar);
tagHandlers["::"] = make_handler(&PyDocConverter::handleTagChar);
// these commands are stripped out, and only their content is printed
tagHandlers["attention"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["author"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["authors"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["brief"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["bug"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["code"] = make_handler(&PyDocConverter::handleCode);
tagHandlers["copyright"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["date"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["deprecated"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["details"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["em"] = make_handler(&PyDocConverter::handleParagraph, " ");
tagHandlers["example"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["exception"] = tagHandlers["throw"] = tagHandlers["throws"] = make_handler(&PyDocConverter::handleTagException);
tagHandlers["htmlonly"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["invariant"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["latexonly"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["link"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["manonly"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["note"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["p"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["partofdescription"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["rtfonly"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["remark"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["remarks"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["sa"] = make_handler(&PyDocConverter::handleTagMessage, "See also: ");
tagHandlers["see"] = make_handler(&PyDocConverter::handleTagMessage, "See also: ");
tagHandlers["since"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["short"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["todo"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["version"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["verbatim"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["warning"] = make_handler(&PyDocConverter::handleParagraph);
tagHandlers["xmlonly"] = make_handler(&PyDocConverter::handleParagraph);
// these commands have special handlers
tagHandlers["arg"] = make_handler(&PyDocConverter::handleTagMessage, "* ");
tagHandlers["cond"] = make_handler(&PyDocConverter::handleTagMessage, "Conditional comment: ");
tagHandlers["else"] = make_handler(&PyDocConverter::handleTagIf, "Else: ");
tagHandlers["elseif"] = make_handler(&PyDocConverter::handleTagIf, "Else if: ");
tagHandlers["endcond"] = make_handler(&PyDocConverter::handleTagMessage, "End of conditional comment.");
tagHandlers["if"] = make_handler(&PyDocConverter::handleTagIf, "If: ");
tagHandlers["ifnot"] = make_handler(&PyDocConverter::handleTagIf, "If not: ");
tagHandlers["image"] = make_handler(&PyDocConverter::handleTagImage);
tagHandlers["li"] = make_handler(&PyDocConverter::handleTagMessage, "* ");
tagHandlers["overload"] = make_handler(&PyDocConverter::handleTagMessage,
"This is an overloaded member function, provided for"
" convenience.\nIt differs from the above function only in what" " argument(s) it accepts.");
tagHandlers["par"] = make_handler(&PyDocConverter::handleTagPar);
tagHandlers["param"] = tagHandlers["tparam"] = make_handler(&PyDocConverter::handleTagParam);
tagHandlers["ref"] = make_handler(&PyDocConverter::handleTagRef);
tagHandlers["result"] = tagHandlers["return"] = tagHandlers["returns"] = make_handler(&PyDocConverter::handleTagReturn);
// this command just prints it's contents
// (it is internal command of swig's parser, contains plain text)
tagHandlers["plainstd::string"] = make_handler(&PyDocConverter::handlePlainString);
tagHandlers["plainstd::endl"] = make_handler(&PyDocConverter::handleNewLine);
tagHandlers["n"] = make_handler(&PyDocConverter::handleNewLine);
// \f commands output literal Latex formula, which is still better than nothing.
tagHandlers["f$"] = tagHandlers["f["] = tagHandlers["f{"] = make_handler(&PyDocConverter::handleMath);
// HTML tags
tagHandlers["<a"] = make_handler(&PyDocConverter::handleDoxyHtmlTag_A);
tagHandlers["<b"] = make_handler(&PyDocConverter::handleDoxyHtmlTag2, "**");
tagHandlers["<blockquote"] = make_handler(&PyDocConverter::handleDoxyHtmlTag_A, "Quote: ");
tagHandlers["<body"] = make_handler(&PyDocConverter::handleDoxyHtmlTag);
tagHandlers["<br"] = make_handler(&PyDocConverter::handleDoxyHtmlTag, "\n");
// there is no formatting for this tag as it was deprecated in HTML 4.01 and
// not used in HTML 5
tagHandlers["<center"] = make_handler(&PyDocConverter::handleDoxyHtmlTag);
tagHandlers["<caption"] = make_handler(&PyDocConverter::handleDoxyHtmlTag);
tagHandlers["<code"] = make_handler(&PyDocConverter::handleDoxyHtmlTag2, "``");
tagHandlers["<dl"] = make_handler(&PyDocConverter::handleDoxyHtmlTag);
tagHandlers["<dd"] = make_handler(&PyDocConverter::handleDoxyHtmlTag, " ");
tagHandlers["<dt"] = make_handler(&PyDocConverter::handleDoxyHtmlTag);
tagHandlers["<dfn"] = make_handler(&PyDocConverter::handleDoxyHtmlTag);
tagHandlers["<div"] = make_handler(&PyDocConverter::handleDoxyHtmlTag);
tagHandlers["<em"] = make_handler(&PyDocConverter::handleDoxyHtmlTag2, "**");
tagHandlers["<form"] = make_handler(&PyDocConverter::handleDoxyHtmlTag);
tagHandlers["<hr"] = make_handler(&PyDocConverter::handleDoxyHtmlTag, "--------------------------------------------------------------------\n");
tagHandlers["<h1"] = make_handler(&PyDocConverter::handleDoxyHtmlTag, "# ");
tagHandlers["<h2"] = make_handler(&PyDocConverter::handleDoxyHtmlTag, "## ");
tagHandlers["<h3"] = make_handler(&PyDocConverter::handleDoxyHtmlTag, "### ");
tagHandlers["<i"] = make_handler(&PyDocConverter::handleDoxyHtmlTag2, "*");
tagHandlers["<input"] = make_handler(&PyDocConverter::handleDoxyHtmlTag);
tagHandlers["<img"] = make_handler(&PyDocConverter::handleDoxyHtmlTag, "Image:");
tagHandlers["<li"] = make_handler(&PyDocConverter::handleDoxyHtmlTag, "* ");
tagHandlers["<meta"] = make_handler(&PyDocConverter::handleDoxyHtmlTag);
tagHandlers["<multicol"] = make_handler(&PyDocConverter::handleDoxyHtmlTag);
tagHandlers["<ol"] = make_handler(&PyDocConverter::handleDoxyHtmlTag);
tagHandlers["<p"] = make_handler(&PyDocConverter::handleDoxyHtmlTag, "\n");
tagHandlers["<pre"] = make_handler(&PyDocConverter::handleDoxyHtmlTag);
tagHandlers["<small"] = make_handler(&PyDocConverter::handleDoxyHtmlTag);
tagHandlers["<span"] = make_handler(&PyDocConverter::handleDoxyHtmlTag2, "'");
tagHandlers["<strong"] = make_handler(&PyDocConverter::handleDoxyHtmlTag2, "**");
// make a space between text and super/sub script.
tagHandlers["<sub"] = make_handler(&PyDocConverter::handleDoxyHtmlTag, " ");
tagHandlers["<sup"] = make_handler(&PyDocConverter::handleDoxyHtmlTag, " ");
tagHandlers["<table"] = make_handler(&PyDocConverter::handleDoxyHtmlTagNoParam);
tagHandlers["<td"] = make_handler(&PyDocConverter::handleDoxyHtmlTag_td);
tagHandlers["<th"] = make_handler(&PyDocConverter::handleDoxyHtmlTag_th);
tagHandlers["<tr"] = make_handler(&PyDocConverter::handleDoxyHtmlTag_tr);
tagHandlers["<tt"] = make_handler(&PyDocConverter::handleDoxyHtmlTag);
tagHandlers["<kbd"] = make_handler(&PyDocConverter::handleDoxyHtmlTag);
tagHandlers["<ul"] = make_handler(&PyDocConverter::handleDoxyHtmlTag);
tagHandlers["<var"] = make_handler(&PyDocConverter::handleDoxyHtmlTag2, "*");
// HTML entities
tagHandlers["&copy"] = make_handler(&PyDocConverter::handleHtmlEntity, "(C)");
tagHandlers["&trade"] = make_handler(&PyDocConverter::handleHtmlEntity, " TM");
tagHandlers["&reg"] = make_handler(&PyDocConverter::handleHtmlEntity, "(R)");
tagHandlers["&lt"] = make_handler(&PyDocConverter::handleHtmlEntity, "<");
tagHandlers["&gt"] = make_handler(&PyDocConverter::handleHtmlEntity, ">");
tagHandlers["&amp"] = make_handler(&PyDocConverter::handleHtmlEntity, "&");
tagHandlers["&apos"] = make_handler(&PyDocConverter::handleHtmlEntity, "'");
tagHandlers["&quot"] = make_handler(&PyDocConverter::handleHtmlEntity, "\"");
tagHandlers["&lsquo"] = make_handler(&PyDocConverter::handleHtmlEntity, "`");
tagHandlers["&rsquo"] = make_handler(&PyDocConverter::handleHtmlEntity, "'");
tagHandlers["&ldquo"] = make_handler(&PyDocConverter::handleHtmlEntity, "\"");
tagHandlers["&rdquo"] = make_handler(&PyDocConverter::handleHtmlEntity, "\"");
tagHandlers["&ndash"] = make_handler(&PyDocConverter::handleHtmlEntity, "-");
tagHandlers["&mdash"] = make_handler(&PyDocConverter::handleHtmlEntity, "--");
tagHandlers["&nbsp"] = make_handler(&PyDocConverter::handleHtmlEntity, " ");
tagHandlers["&times"] = make_handler(&PyDocConverter::handleHtmlEntity, "x");
tagHandlers["&minus"] = make_handler(&PyDocConverter::handleHtmlEntity, "-");
tagHandlers["&sdot"] = make_handler(&PyDocConverter::handleHtmlEntity, ".");
tagHandlers["&sim"] = make_handler(&PyDocConverter::handleHtmlEntity, "~");
tagHandlers["&le"] = make_handler(&PyDocConverter::handleHtmlEntity, "<=");
tagHandlers["&ge"] = make_handler(&PyDocConverter::handleHtmlEntity, ">=");
tagHandlers["&larr"] = make_handler(&PyDocConverter::handleHtmlEntity, "<--");
tagHandlers["&rarr"] = make_handler(&PyDocConverter::handleHtmlEntity, "-->");
}
PyDocConverter::PyDocConverter(int flags):
DoxygenTranslator(flags), m_tableLineLen(0), m_prevRowIsTH(false) {
fillStaticTables();
}
// Return the type as it should appear in the output documentation.
static std::string getPyDocType(Node *n, const_String_or_char_ptr lname = "") {
std::string type;
String *s = Swig_typemap_lookup("doctype", n, lname, 0);
if (!s)
s = SwigType_str(Getattr(n, "type"), "");
if (Language::classLookup(s)) {
// In Python C++ namespaces are flattened, so remove all but last component
// of the name.
String *const last = Swig_scopename_last(s);
// We are not actually sure whether it's a documented class or not, but
// there doesn't seem to be any harm in making it a reference if it isn't,
// while there is a lot of benefit in having a hyperlink if it is.
type = ":py:class:`";
type += Char(last);
type += "`";
Delete(last);
} else {
type = Char(s);
}
Delete(s);
return type;
}
std::string PyDocConverter::getParamType(std::string param) {
std::string type;
ParmList *plist = CopyParmList(Getattr(currentNode, "parms"));
for (Parm *p = plist; p; p = nextSibling(p)) {
String *pname = Getattr(p, "name");
if (Char(pname) != param)
continue;
type = getPyDocType(p, pname);
break;
}
Delete(plist);
return type;
}
std::string PyDocConverter::translateSubtree(DoxygenEntity &doxygenEntity) {
std::string translatedComment;
if (doxygenEntity.isLeaf)
return translatedComment;
std::string currentSection;
std::list<DoxygenEntity>::iterator p = doxygenEntity.entityList.begin();
while (p != doxygenEntity.entityList.end()) {
std::map<std::string, std::string>::iterator it;
it = sectionTitles.find(p->typeOfEntity);
if (it != sectionTitles.end()) {
if (it->second != currentSection) {
currentSection = it->second;
translatedComment += currentSection;
}
}
translateEntity(*p, translatedComment);
translateSubtree(*p);
p++;
}
return translatedComment;
}
void PyDocConverter::translateEntity(DoxygenEntity &doxyEntity, std::string &translatedComment) {
// check if we have needed handler and call it
std::map<std::string, std::pair<tagHandler, std::string> >::iterator it;
it = tagHandlers.find(doxyEntity.typeOfEntity);
if (it != tagHandlers.end())
(this->*(it->second.first)) (doxyEntity, translatedComment, it->second.second);
}
void PyDocConverter::handleParagraph(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
translatedComment += translateSubtree(tag);
}
void PyDocConverter::handleMath(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
IndentGuard indent;
// Only \f$ is translated to inline formulae, \f[ and \f{ are for the block ones.
const bool inlineFormula = tag.typeOfEntity == "f$";
string formulaNL;
if (inlineFormula) {
translatedComment += ":math:`";
} else {
indent.Init(translatedComment, m_indent);
trimWhitespace(translatedComment);
translatedComment += '\n';
const string formulaIndent = indent.getFirstLineIndent();
translatedComment += formulaIndent;
translatedComment += ".. math::\n";
formulaNL = '\n';
formulaNL += formulaIndent;
formulaNL += m_indent;
translatedComment += formulaNL;
}
std::string formula;
handleTagVerbatim(tag, formula, arg);
// It is important to ensure that we have no spaces around the inline math
// contents, so strip them.
const size_t start = formula.find_first_not_of(" \t\n");
const size_t end = formula.find_last_not_of(" \t\n");
if (start != std::string::npos) {
for (size_t n = start; n <= end; n++) {
if (formula[n] == '\n') {
// New lines must be suppressed in inline maths and indented in the block ones.
if (!inlineFormula)
translatedComment += formulaNL;
} else {
// Just copy everything else.
translatedComment += formula[n];
}
}
}
if (inlineFormula) {
translatedComment += "`";
} else {
translatedComment += '\n';
}
}
void PyDocConverter::handleCode(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
IndentGuard indent(translatedComment, m_indent);
trimWhitespace(translatedComment);
translatedComment += '\n';
// Use the current indent for the code-block line itself.
string codeIndent = indent.getFirstLineIndent();
translatedComment += codeIndent;
// Go out on a limb and assume that examples in the C or C++ sources use C++.
// In the worst case, we'll highlight C code using C++ syntax which is not a
// big deal (TODO: handle Doxygen code command language argument).
translatedComment += ".. code-block:: c++\n\n";
// For now on, use extra indent level for all the subsequent lines.
codeIndent += m_indent;
std::string code;
handleTagVerbatim(tag, code, arg);
translatedComment += codeIndent;
for (size_t n = 0; n < code.length(); n++) {
if (code[n] == '\n') {
// Don't leave trailing white space, this results in PEP8 validation
// errors in Python code (which are performed by our own unit tests).
trimWhitespace(translatedComment);
translatedComment += '\n';
// Ensure that we indent all the lines by the code indent.
translatedComment += codeIndent;
} else {
// Just copy everything else.
translatedComment += code[n];
}
}
trimWhitespace(translatedComment);
if (*translatedComment.rbegin() != '\n')
translatedComment += '\n';
}
void PyDocConverter::handlePlainString(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
translatedComment += tag.data;
}
void PyDocConverter::handleTagVerbatim(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
translatedComment += arg + " ";
for (DoxygenEntityListCIt it = tag.entityList.begin(); it != tag.entityList.end(); it++) {
translatedComment += it->data;
}
}
void PyDocConverter::handleTagMessage(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
translatedComment += arg;
handleParagraph(tag, translatedComment);
}
void PyDocConverter::handleTagChar(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
translatedComment += tag.typeOfEntity;
}
void PyDocConverter::handleTagIf(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
translatedComment += arg;
if (tag.entityList.size()) {
translatedComment += tag.entityList.begin()->data;
tag.entityList.pop_front();
translatedComment += " {" + translateSubtree(tag) + "}";
}
}
void PyDocConverter::handleTagPar(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
translatedComment += "Title: ";
if (tag.entityList.size())
translatedComment += tag.entityList.begin()->data;
tag.entityList.pop_front();
handleParagraph(tag, translatedComment);
}
void PyDocConverter::handleTagImage(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
if (tag.entityList.size() < 2)
return;
tag.entityList.pop_front();
translatedComment += "Image: ";
translatedComment += tag.entityList.begin()->data;
tag.entityList.pop_front();
if (tag.entityList.size())
translatedComment += "(" + tag.entityList.begin()->data + ")";
}
void PyDocConverter::handleTagParam(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
if (tag.entityList.size() < 2)
return;
IndentGuard indent(translatedComment, m_indent);
DoxygenEntity paramNameEntity = *tag.entityList.begin();
tag.entityList.pop_front();
const std::string &paramName = paramNameEntity.data;
const std::string paramType = getParamType(paramName);
if (!paramType.empty()) {
translatedComment += ":type " + paramName + ": " + paramType + "\n";
translatedComment += indent.getFirstLineIndent();
}
translatedComment += ":param " + paramName + ":";
handleParagraph(tag, translatedComment);
}
void PyDocConverter::handleTagReturn(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
IndentGuard indent(translatedComment, m_indent);
const std::string pytype = getPyDocType(currentNode);
if (!pytype.empty()) {
translatedComment += ":rtype: ";
translatedComment += pytype;
translatedComment += "\n";
translatedComment += indent.getFirstLineIndent();
}
translatedComment += ":return: ";
handleParagraph(tag, translatedComment);
}
void PyDocConverter::handleTagException(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
IndentGuard indent(translatedComment, m_indent);
translatedComment += ":raises: ";
handleParagraph(tag, translatedComment);
}
void PyDocConverter::handleTagRef(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
if (!tag.entityList.size())
return;
string anchor = tag.entityList.begin()->data;
tag.entityList.pop_front();
string anchorText = anchor;
if (!tag.entityList.empty()) {
anchorText = tag.entityList.begin()->data;
}
translatedComment += "'" + anchorText + "'";
}
void PyDocConverter::handleTagWrap(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
if (tag.entityList.size()) { // do not include empty tags
std::string tagData = translateSubtree(tag);
// wrap the thing, ignoring whitespace
size_t wsPos = tagData.find_last_not_of("\n\t ");
if (wsPos != std::string::npos && wsPos != tagData.size() - 1)
translatedComment += arg + tagData.substr(0, wsPos + 1) + arg + tagData.substr(wsPos + 1);
else
translatedComment += arg + tagData + arg;
}
}
void PyDocConverter::handleDoxyHtmlTag(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
std::string htmlTagArgs = tag.data;
if (htmlTagArgs == "/") {
// end html tag, for example "</ul>
// translatedComment += "</" + arg.substr(1) + ">";
} else {
translatedComment += arg + htmlTagArgs;
}
}
void PyDocConverter::handleDoxyHtmlTagNoParam(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
std::string htmlTagArgs = tag.data;
if (htmlTagArgs == "/") {
// end html tag, for example "</ul>
} else {
translatedComment += arg;
}
}
void PyDocConverter::handleDoxyHtmlTag_A(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
std::string htmlTagArgs = tag.data;
if (htmlTagArgs == "/") {
// end html tag, "</a>
translatedComment += " (" + m_url + ')';
m_url.clear();
} else {
m_url.clear();
size_t pos = htmlTagArgs.find('=');
if (pos != string::npos) {
m_url = htmlTagArgs.substr(pos + 1);
}
translatedComment += arg;
}
}
void PyDocConverter::handleDoxyHtmlTag2(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg) {
std::string htmlTagArgs = tag.data;
if (htmlTagArgs == "/") {
// end html tag, for example "</em>
translatedComment += arg;
} else {
translatedComment += arg;
}
}
void PyDocConverter::handleDoxyHtmlTag_tr(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
std::string htmlTagArgs = tag.data;
size_t nlPos = translatedComment.rfind('\n');
if (htmlTagArgs == "/") {
// end tag, </tr> appends vertical table line '|'
translatedComment += '|';
if (nlPos != string::npos) {
size_t startOfTableLinePos = translatedComment.find_first_not_of(" \t", nlPos + 1);
if (startOfTableLinePos != string::npos) {
m_tableLineLen = translatedComment.size() - startOfTableLinePos;
}
}
} else {
if (m_prevRowIsTH) {
// if previous row contained <th> tag, add horizontal separator
// but first get leading spaces, because they'll be needed for the next row
size_t numLeadingSpaces = translatedComment.size() - nlPos - 1;
translatedComment += string(m_tableLineLen, '-') + '\n';
if (nlPos != string::npos) {
translatedComment += string(numLeadingSpaces, ' ');
}
m_prevRowIsTH = false;
}
}
}
void PyDocConverter::handleDoxyHtmlTag_th(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
std::string htmlTagArgs = tag.data;
if (htmlTagArgs == "/") {
// end tag, </th> is ignored
} else {
translatedComment += '|';
m_prevRowIsTH = true;
}
}
void PyDocConverter::handleDoxyHtmlTag_td(DoxygenEntity &tag, std::string &translatedComment, const std::string &) {
std::string htmlTagArgs = tag.data;
if (htmlTagArgs == "/") {
// end tag, </td> is ignored
} else {
translatedComment += '|';
}
}
void PyDocConverter::handleHtmlEntity(DoxygenEntity &, std::string &translatedComment, const std::string &arg) {
// html entities
translatedComment += arg;
}
void PyDocConverter::handleNewLine(DoxygenEntity &, std::string &translatedComment, const std::string &) {
trimWhitespace(translatedComment);
translatedComment += "\n";
if (!m_indent.empty())
translatedComment += m_indent;
}
String *PyDocConverter::makeDocumentation(Node *n) {
String *documentation;
std::string pyDocString;
// store the node, we may need it later
currentNode = n;
// for overloaded functions we must concat documentation for underlying overloads
if (Getattr(n, "sym:overloaded")) {
// rewind to the first overload
while (Getattr(n, "sym:previousSibling"))
n = Getattr(n, "sym:previousSibling");
std::vector<std::string> allDocumentation;
// minimal indent of any documentation comments, not initialized yet
size_t minIndent = static_cast<size_t>(-1);
// for each real method (not a generated overload) append the documentation
string oneDoc;
while (n) {
documentation = getDoxygenComment(n);
if (!Swig_is_generated_overload(n) && documentation) {
currentNode = n;
if (GetFlag(n, "feature:doxygen:notranslate")) {
String *comment = NewString("");
Append(comment, documentation);
Replaceall(comment, "\n *", "\n");
oneDoc = Char(comment);
Delete(comment);
} else {
std::list<DoxygenEntity> entityList = parser.createTree(n, documentation);
DoxygenEntity root("root", entityList);
oneDoc = translateSubtree(root);
}
// find the minimal indent of this documentation comment, we need to
// ensure that the entire comment is indented by it to avoid the leading
// parts of the other lines being simply discarded later
const size_t oneIndent = determineIndent(oneDoc);
if (oneIndent < minIndent)
minIndent = oneIndent;
allDocumentation.push_back(oneDoc);
}
n = Getattr(n, "sym:nextSibling");
}
// construct final documentation string
if (allDocumentation.size() > 1) {
string indentStr;
if (minIndent != static_cast<size_t>(-1))
indentStr.assign(minIndent, ' ');
std::ostringstream concatDocString;
for (size_t realOverloadCount = 0; realOverloadCount < allDocumentation.size(); realOverloadCount++) {
if (realOverloadCount != 0) {
// separate it from the preceding one.
concatDocString << "\n" << indentStr << "|\n\n";
}
oneDoc = allDocumentation[realOverloadCount];
trimWhitespace(oneDoc);
concatDocString << indentStr << "*Overload " << (realOverloadCount + 1) << ":*\n" << oneDoc;
}
pyDocString = concatDocString.str();
} else if (allDocumentation.size() == 1) {
pyDocString = *(allDocumentation.begin());
}
}
// for other nodes just process as normal
else {
documentation = getDoxygenComment(n);
if (documentation != NULL) {
if (GetFlag(n, "feature:doxygen:notranslate")) {
String *comment = NewString("");
Append(comment, documentation);
Replaceall(comment, "\n *", "\n");
pyDocString = Char(comment);
Delete(comment);
} else {
std::list<DoxygenEntity> entityList = parser.createTree(n, documentation);
DoxygenEntity root("root", entityList);
pyDocString = translateSubtree(root);
}
}
}
// if we got something log the result
if (!pyDocString.empty()) {
// remove the last '\n' since additional one is added during writing to file
if (pyDocString[pyDocString.size() - 1] == '\n') {
pyDocString.erase(pyDocString.size() - 1);
}
if (m_flags & debug_translator) {
std::cout << "\n---RESULT IN PYDOC---" << std::endl;
std::cout << pyDocString;
std::cout << std::endl;
}
}
return NewString(pyDocString.c_str());
}

198
Source/Doxygen/pydoc.h Normal file
View file

@ -0,0 +1,198 @@
/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.html.
*
* pydoc.h
*
* Module to return documentation for nodes formatted for PyDoc
* ----------------------------------------------------------------------------- */
#ifndef PYDOCCONVERTER_H_
#define PYDOCCONVERTER_H_
#include <list>
#include <string>
#include "swig.h"
#include "doxyentity.h"
#include "doxytranslator.h"
#define DOC_STRING_LENGTH 64 // characters per line allowed
#define DOC_PARAM_STRING_LENGTH 30 // characters reserved for param name / type
class PyDocConverter : public DoxygenTranslator {
public:
PyDocConverter(int flags = 0);
String *makeDocumentation(Node *node);
protected:
size_t m_tableLineLen;
bool m_prevRowIsTH;
std::string m_url;
/*
* Translate every entity in a tree, also manages sections
* display. Prints title for every group of tags that have
* a section title associated with them
*/
std::string translateSubtree(DoxygenEntity &doxygenEntity);
/*
* Translate one entity with the appropriate handler, according
* to the tagHandlers
*/
void translateEntity(DoxygenEntity &doxyEntity, std::string &translatedComment);
/*
* Typedef for the function that handles one tag
* arg - some string argument to easily pass it through lookup table
*/
typedef void (PyDocConverter::*tagHandler) (DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Wrap the command data with the some string
* arg - string to wrap with, like '_' or '*'
*/
void handleTagWrap(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Just prints new line
*/
void handleNewLine(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Print the name of tag to the output, used for escape-commands
*/
void handleTagChar(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Format the contents of the \exception tag or its synonyms.
*/
void handleTagException(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Print only the content and strip original tag
*/
void handleParagraph(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg = std::string());
/*
* Handle one of the Doxygen formula-related tags.
*/
void handleMath(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Handle a code snippet.
*/
void handleCode(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Print only data part of code
*/
void handlePlainString(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/**
* Copies verbatim args of the tag to output, used for commands like \f$, ...
*/
void handleTagVerbatim(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Print the if-elseif-else-endif section
*/
void handleTagIf(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Prints the specified message, than the contents of the tag
* arg - message
*/
void handleTagMessage(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Insert 'Title: ...'
*/
void handleTagPar(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Insert 'Image: ...'
*/
void handleTagImage(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Format nice param description with type information
*/
void handleTagParam(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Format the contents of the \return tag or its synonyms.
*/
void handleTagReturn(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Writes text for \ref tag.
*/
void handleTagRef(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/* Handles HTML tags recognized by Doxygen, like <A ...>, <ul>, <table>, ... */
void handleDoxyHtmlTag(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/** Does not output params of HTML tag, for example in <table border='1'>
* 'border=1' is not written to output.
*/
void handleDoxyHtmlTagNoParam(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/** Translates tag <a href = "url">text</a> to: text ("url"). */
void handleDoxyHtmlTag_A(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/*
* Handles HTML tags, which are translated to markdown-like syntax, for example
* <i>text</i> --> _text_. Appends arg for start HTML tag and end HTML tag.
*/
void handleDoxyHtmlTag2(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/* Handles HTML table, tag <tr> */
void handleDoxyHtmlTag_tr(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/* Handles HTML table, tag <th> */
void handleDoxyHtmlTag_th(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/* Handles HTML table, tag <td> */
void handleDoxyHtmlTag_td(DoxygenEntity &tag, std::string &translatedComment, const std::string &arg);
/* Handles HTML entities recognized by Doxygen, like &lt;, &copy;, ... */
void handleHtmlEntity(DoxygenEntity &, std::string &translatedComment, const std::string &arg);
/*
* Simple helper function that calculates correct parameter type
* of the node stored in 'currentNode'
* If param with specified name is not found, empty string is returned
*/
std::string getParamType(std::string name);
private:
// temporary thing, should be refactored somehow
Node *currentNode;
// Extra indent for the current paragraph, must be output after each new line.
std::string m_indent;
// this contains the handler pointer and one string argument
typedef std::map<std::string, std::pair<tagHandler, std::string> >TagHandlersMap;
static TagHandlersMap tagHandlers;
// this contains the sections tittles, like 'Arguments:' or 'Notes:', that are printed only once
static std::map<std::string, std::string> sectionTitles;
// Helper functions for fillStaticTables(): make a new tag handler object.
TagHandlersMap::mapped_type make_handler(tagHandler handler);
TagHandlersMap::mapped_type make_handler(tagHandler handler, const char *arg);
void fillStaticTables();
};
#endif

View file

@ -209,6 +209,15 @@
#define WARN_LANG_EXTEND_CONSTRUCTOR 522
#define WARN_LANG_EXTEND_DESTRUCTOR 523
/* -- Doxygen comments -- */
#define WARN_DOXYGEN_UNKNOWN_COMMAND 560
#define WARN_DOXYGEN_UNEXPECTED_END_OF_COMMENT 561
#define WARN_DOXYGEN_COMMAND_EXPECTED 562
#define WARN_DOXYGEN_HTML_ERROR 563
#define WARN_DOXYGEN_COMMAND_ERROR 564
#define WARN_DOXYGEN_UNKNOWN_CHARACTER 565
/* -- Reserved (600-799) -- */
/* -- Language module specific warnings (700 - 899) -- */

View file

@ -13,6 +13,7 @@ AM_CPPFLAGS = -I$(BUILD_SOURCE_DIR)/Include \
-I$(SOURCE_DIR)/Include \
-I$(SOURCE_DIR)/DOH \
-I$(SOURCE_DIR)/CParse \
-I$(SOURCE_DIR)/Doxygen \
-I$(SOURCE_DIR)/Preprocessor \
-I$(SOURCE_DIR)/Swig \
-I$(SOURCE_DIR)/Modules
@ -34,6 +35,16 @@ eswig_SOURCES = CParse/cscanner.c \
DOH/memory.c \
DOH/string.c \
DOH/void.c \
Doxygen/doxyentity.cxx \
Doxygen/doxyentity.h \
Doxygen/doxyparser.cxx \
Doxygen/doxyparser.h \
Doxygen/doxytranslator.cxx \
Doxygen/doxytranslator.h \
Doxygen/javadoc.cxx \
Doxygen/javadoc.h \
Doxygen/pydoc.cxx \
Doxygen/pydoc.h \
Modules/allegrocl.cxx \
Modules/allocate.cxx \
Modules/browser.cxx \
@ -90,8 +101,8 @@ eswig_SOURCES = CParse/cscanner.c \
Swig/stype.c \
Swig/symbol.c \
Swig/tree.c \
Swig/typeobj.c \
Swig/typemap.c \
Swig/typeobj.c \
Swig/typesys.c \
Swig/wrapfunc.c

View file

@ -15,6 +15,7 @@
#include <limits.h> // for INT_MAX
#include "cparse.h"
#include <ctype.h>
#include "javadoc.h"
/* Hash type used for upcalls from C/C++ */
typedef DOH UpcallData;
@ -46,7 +47,9 @@ class JAVA:public Language {
bool global_variable_flag; // Flag for when wrapping a global variable
bool old_variable_names; // Flag for old style variable names in the intermediary class
bool member_func_flag; // flag set when wrapping a member function
bool doxygen; //flag for converting found doxygen to javadoc
bool comment_creation_chatter; //flag for getting information about where comments were created in java.cxx
String *imclass_name; // intermediary class name
String *module_class_name; // module class name
String *constants_interface_name; // constants interface name
@ -120,6 +123,8 @@ public:
global_variable_flag(false),
old_variable_names(false),
member_func_flag(false),
doxygen(false),
comment_creation_chatter(false),
imclass_name(NULL),
module_class_name(NULL),
constants_interface_name(NULL),
@ -164,6 +169,10 @@ public:
director_multiple_inheritance = 0;
director_language = 1;
}
~JAVA() {
delete doxygenTranslator;
}
/* -----------------------------------------------------------------------------
* constructIntermediateClassName()
@ -256,6 +265,8 @@ public:
SWIG_library_directory("java");
int doxygen_translator_flags = 0;
// Look for certain command line options
for (int i = 1; i < argc; i++) {
if (argv[i]) {
@ -277,6 +288,16 @@ public:
Printf(stderr, "Deprecated command line option: %s. Proxy classes are now generated by default.\n", argv[i]);
Swig_mark_arg(i);
proxy_flag = true;
} else if ((strcmp(argv[i], "-doxygen") == 0)) {
Swig_mark_arg(i);
doxygen = true;
scan_doxygen_comments = true;
} else if ((strcmp(argv[i], "-debug-doxygen-translator") == 0)) {
Swig_mark_arg(i);
doxygen_translator_flags |= DoxygenTranslator::debug_translator;
} else if ((strcmp(argv[i], "-debug-doxygen-parser") == 0)) {
Swig_mark_arg(i);
doxygen_translator_flags |= DoxygenTranslator::debug_parser;
} else if ((strcmp(argv[i], "-noproxy") == 0)) {
Swig_mark_arg(i);
proxy_flag = false;
@ -300,6 +321,9 @@ public:
}
}
}
if (doxygen)
doxygenTranslator = new JavaDocConverter(doxygen_translator_flags);
// Add a symbol to the parser for conditional compilation
Preprocessor_define("SWIGJAVA 1", 0);
@ -567,6 +591,13 @@ public:
if (module_imports)
Printf(f_module, "%s\n", module_imports);
if (doxygen && doxygenTranslator->hasDocumentation(n)) {
String *doxygen_comments = doxygenTranslator->getDocumentation(n);
if (comment_creation_chatter)
Printf(f_module, "/* This was generated from top() */");
Printv(f_module, Char(doxygen_comments), NIL);
Delete(doxygen_comments);
}
if (Len(module_class_modifiers) > 0)
Printf(f_module, "%s ", module_class_modifiers);
Printf(f_module, "%s ", module_class_name);
@ -1243,6 +1274,15 @@ public:
EnumFeature enum_feature = decodeEnumFeature(n);
String *typemap_lookup_type = Getattr(n, "name");
if (doxygen && doxygenTranslator->hasDocumentation(n)) {
String *doxygen_comments = doxygenTranslator->getDocumentation(n);
if (comment_creation_chatter) {
Printf(enum_code, "/* This was generated from enumDeclaration() */");
}
Printv(enum_code, Char(doxygen_comments), NIL);
Delete(doxygen_comments);
}
if ((enum_feature != SimpleEnum) && symname && typemap_lookup_type) {
// Wrap (non-anonymous) C/C++ enum within a typesafe, typeunsafe or proper Java enum
@ -1265,8 +1305,16 @@ public:
Replaceall(enum_code, "$static ", "");
Delete(scope);
} else {
// Wrap C++ enum with integers - just indicate start of enum with a comment, no comment for anonymous enums of any sort
if (symname && !Getattr(n, "unnamedinstance"))
// Translate and write javadoc comment for the enum itself if flagged
if (doxygen && doxygenTranslator->hasDocumentation(n)) {
String *doxygen_comments = doxygenTranslator->getDocumentation(n);
if (comment_creation_chatter)
Printf(constants_code, "/* This was generated from enumDeclaration() */");
Printf(constants_code, "/* Comment for enum %s */\n", Getattr(n, "unnamedinstance") ? "" : symname);
Printf(constants_code, Char(doxygen_comments));
Printf(constants_code, "\n");
Delete(doxygen_comments);
} else if (symname && !Getattr(n, "unnamedinstance"))
Printf(constants_code, " // %s \n", symname);
}
@ -1418,12 +1466,24 @@ public:
}
if (!addSymbol(symname, n, scope))
return SWIG_ERROR;
if ((enum_feature == ProperEnum) && parent_name && !unnamedinstance) {
if (!GetFlag(n, "firstenumitem"))
Printf(enum_code, ",\n");
}
// Translate and write javadoc comment if flagged
if (doxygen && doxygenTranslator->hasDocumentation(n)) {
String *doxygen_comments = doxygenTranslator->getDocumentation(n);
if (comment_creation_chatter)
Printf(enum_code, "/* This was generated from enumvalueDeclaration() */");
Printv(enum_code, Char(doxygen_comments), NIL);
Delete(doxygen_comments);
}
if ((enum_feature == ProperEnum) && parent_name && !unnamedinstance) {
// Wrap (non-anonymous) C/C++ enum with a proper Java enum
// Emit the enum item.
if (!GetFlag(n, "firstenumitem"))
Printf(enum_code, ",\n");
Printf(enum_code, " %s", symname);
if (Getattr(n, "enumvalue")) {
String *value = enumValue(n);
@ -1497,6 +1557,15 @@ public:
String *constants_code = NewString("");
Swig_save("constantWrapper", n, "value", NIL);
// Translate and write javadoc comment if flagged
if (doxygen && doxygenTranslator->hasDocumentation(n)) {
String *doxygen_comments = doxygenTranslator->getDocumentation(n);
if (comment_creation_chatter)
Printf(constants_code, "/* This was generated from constantWrapper() */");
Printv(constants_code, Char(doxygen_comments), NIL);
Delete(doxygen_comments);
}
bool is_enum_item = (Cmp(nodeType(n), "enumitem") == 0);
const String *itemname = (proxy_flag && wrapping_member_flag) ? variable_name : symname;
@ -1936,6 +2005,16 @@ public:
// Pure Java interfaces
const String *pure_interfaces = typemapLookup(n, "javainterfaces", typemap_lookup_type, WARN_NONE);
// Translate and write javadoc comment if flagged
if (doxygen && doxygenTranslator->hasDocumentation(n)) {
String *doxygen_comments = doxygenTranslator->getDocumentation(n);
if (comment_creation_chatter)
Printf(proxy_class_def, "/* This was generated from emitProxyClassDefAndCPPCasts() */");
Printv(proxy_class_def, Char(doxygen_comments), NIL);
Delete(doxygen_comments);
}
if (*Char(interface_list) && *Char(pure_interfaces))
Append(interface_list, ", ");
Append(interface_list, pure_interfaces);
@ -2424,6 +2503,15 @@ public:
setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(getNSpace(), Swig_name_member(0, getClassPrefix(), variable_name))) == 0);
}
// Translate and write javadoc comment if flagged
if (doxygen && doxygenTranslator->hasDocumentation(n)) {
String *doxygen_comments = doxygenTranslator->getDocumentation(n);
if (comment_creation_chatter)
Printf(function_code, "/* This was generated from proxyclassfunctionhandler() */");
Printv(function_code, Char(doxygen_comments), NIL);
Delete(doxygen_comments);
}
/* Start generating the proxy function */
const String *methodmods = Getattr(n, "feature:java:methodmodifiers");
methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string);
@ -2614,7 +2702,7 @@ public:
Printf(interface_class_code, ";\n");
}
generateThrowsClause(n, function_code);
Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string);
Printf(function_code, " %s\n\n", tm ? tm : empty_string);
Printv(proxy_class_code, function_code, NIL);
Delete(pre_code);
@ -2659,6 +2747,15 @@ public:
tm = Getattr(n, "tmap:jtype"); // typemaps were attached earlier to the node
Printf(im_return_type, "%s", tm);
// Translate and write javadoc comment if flagged
if (doxygen && doxygenTranslator->hasDocumentation(n)) {
String *doxygen_comments = doxygenTranslator->getDocumentation(n);
if (comment_creation_chatter)
Printf(function_code, "/* This was generated from constructionhandler() */");
Printv(function_code, Char(doxygen_comments), NIL);
Delete(doxygen_comments);
}
Printf(function_code, " %s %s(", methodmods, proxy_class_name);
Printf(helper_code, " static private %s SwigConstruct%s(", im_return_type, proxy_class_name);
@ -2924,6 +3021,15 @@ public:
String *pre_code = NewString("");
String *post_code = NewString("");
// Translate and write javadoc comment if flagged
if (doxygen && doxygenTranslator->hasDocumentation(n)) {
String *doxygen_comments = doxygenTranslator->getDocumentation(n);
if (comment_creation_chatter)
Printf(function_code, "/* This was generated from moduleClassFunctionHandler() */");
Printv(function_code, doxygen_comments, NIL);
Delete(doxygen_comments);
}
if (l) {
if (SwigType_type(Getattr(l, "type")) == T_VOID) {
l = nextSibling(l);
@ -3076,7 +3182,7 @@ public:
}
generateThrowsClause(n, function_code);
Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string);
Printf(function_code, " %s\n\n", tm ? tm : empty_string);
Printv(module_class_code, function_code, NIL);
Delete(pre_code);
@ -4873,6 +4979,9 @@ extern "C" Language *swig_java(void) {
const char *JAVA::usage = "\
Java Options (available with -java)\n\
-doxygen - Convert C++ doxygen comments to JavaDoc comments in proxy classes\n\
-debug-doxygen-parser - Display doxygen parser module debugging information\n\
-debug-doxygen-translator - Display doxygen translator module debugging information\n\
-nopgcpp - Suppress premature garbage collection prevention parameter\n\
-noproxy - Generate the low-level functional interface instead\n\
of proxy classes\n\

View file

@ -307,15 +307,12 @@ int Dispatcher::namespaceDeclaration(Node *n) {
return defaultHandler(n);
}
/* Allocators */
Language::Language():
none_comparison(NewString("$arg != 0")),
director_ctor_code(NewString("")),
director_prot_ctor_code(0),
symtabs(NewHash()),
classtypes(NewHash()),
enumtypes(NewHash()),
overloading(0),
multiinput(0),
cplus_runtime(0),
@ -336,12 +333,12 @@ directors(0) {
director_language = 0;
assert(!this_);
this_ = this;
doxygenTranslator = NULL;
}
Language::~Language() {
Delete(symtabs);
Delete(classtypes);
Delete(enumtypes);
Delete(director_ctor_code);
Delete(none_comparison);
this_ = 0;
@ -3264,11 +3261,13 @@ Node *Language::symbolLookup(const String *s, const_String_or_char_ptr scope) {
* Tries to locate a class from a type definition
* ----------------------------------------------------------------------------- */
Node *Language::classLookup(const SwigType *s) const {
Node *Language::classLookup(const SwigType *s) {
static Hash *classtypes = 0;
Node *n = 0;
/* Look in hash of cached values */
n = Getattr(classtypes, s);
n = classtypes ? Getattr(classtypes, s) : 0;
if (!n) {
Symtab *stab = 0;
SwigType *ty1 = SwigType_typedef_resolve_all(s);
@ -3331,6 +3330,8 @@ Node *Language::classLookup(const SwigType *s) const {
}
if (acceptable_prefix) {
SwigType *cs = Copy(s);
if (!classtypes)
classtypes = NewHash();
Setattr(classtypes, cs, n);
Delete(cs);
} else {
@ -3357,10 +3358,12 @@ Node *Language::classLookup(const SwigType *s) const {
* ----------------------------------------------------------------------------- */
Node *Language::enumLookup(SwigType *s) {
static Hash *enumtypes = 0;
Node *n = 0;
/* Look in hash of cached values */
n = Getattr(enumtypes, s);
n = enumtypes ? Getattr(enumtypes, s) : 0;
if (!n) {
Symtab *stab = 0;
SwigType *lt = SwigType_ltype(s);
@ -3401,6 +3404,8 @@ Node *Language::enumLookup(SwigType *s) {
if (n) {
/* Found a match. Look at the prefix. We only allow simple types. */
if (Len(prefix) == 0) { /* Simple type */
if (!enumtypes)
enumtypes = NewHash();
Setattr(enumtypes, Copy(s), n);
} else {
n = 0;

View file

@ -17,6 +17,7 @@
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include "pydoc.h"
#include <iostream>
#include <stdint.h>
@ -90,6 +91,7 @@ static int buildnone = 0;
static int nobuildnone = 0;
static int safecstrings = 0;
static int dirvtable = 0;
static int doxygen = 0;
static int proxydel = 1;
static int fastunpack = 0;
static int fastproxy = 0;
@ -111,7 +113,8 @@ enum autodoc_t {
AUTODOC_DTOR,
AUTODOC_STATICFUNC,
AUTODOC_FUNC,
AUTODOC_METHOD
AUTODOC_METHOD,
AUTODOC_CONST
};
@ -125,6 +128,9 @@ Python Options (available with -python)\n\
-classptr - Generate shadow 'ClassPtr' as in older swig versions\n\
-cppcast - Enable C++ casting operators (default) \n\
-dirvtable - Generate a pseudo virtual table for directors for faster dispatch \n\
-doxygen - Convert C++ doxygen comments to pydoc comments in proxy classes \n\
-debug-doxygen-parser - Display doxygen parser module debugging information\n\
-debug-doxygen-translator - Display doxygen translator module debugging information\n\
-extranative - Return extra native C++ wraps for std containers when possible \n\
-fastinit - Use fast init mechanism for classes (default)\n\
-fastunpack - Use fast unpack mechanism to parse the argument functions \n\
@ -261,6 +267,11 @@ public:
director_multiple_inheritance = 1;
director_language = 1;
}
~PYTHON() {
delete doxygenTranslator;
}
/* ------------------------------------------------------------
* Thread Implementation
* ------------------------------------------------------------ */
@ -336,6 +347,8 @@ public:
SWIG_library_directory("python");
int doxygen_translator_flags = 0;
for (int i = 1; i < argc; i++) {
if (argv[i]) {
if (strcmp(argv[i], "-interface") == 0) {
@ -426,6 +439,16 @@ public:
} else if (strcmp(argv[i], "-nodirvtable") == 0) {
dirvtable = 0;
Swig_mark_arg(i);
} else if (strcmp(argv[i], "-doxygen") == 0) {
doxygen = 1;
scan_doxygen_comments = 1;
Swig_mark_arg(i);
} else if (strcmp(argv[i], "-debug-doxygen-translator") == 0) {
doxygen_translator_flags |= DoxygenTranslator::debug_translator;
Swig_mark_arg(i);
} else if (strcmp(argv[i], "-debug-doxygen-parser") == 0) {
doxygen_translator_flags |= DoxygenTranslator::debug_parser;
Swig_mark_arg(i);
} else if (strcmp(argv[i], "-fastunpack") == 0) {
fastunpack = 1;
Swig_mark_arg(i);
@ -547,6 +570,9 @@ public:
if (cppcast) {
Preprocessor_define((DOH *) "SWIG_CPLUSPLUS_CAST", 0);
}
if (doxygen)
doxygenTranslator = new PyDocConverter(doxygen_translator_flags);
if (!global_name)
global_name = NewString("cvar");
@ -1654,7 +1680,89 @@ public:
bool have_docstring(Node *n) {
String *str = Getattr(n, "feature:docstring");
return (str && Len(str) > 0) || (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc"));
return ((str && Len(str) > 0)
|| (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc"))
|| (doxygen && doxygenTranslator->hasDocumentation(n))
);
}
/* ------------------------------------------------------------
* build_combined_docstring()
*
* Build the full docstring which may be a combination of the
* explicit docstring and autodoc string or, if none of them
* is specified, obtained by translating Doxygen comment to
* Python.
*
* Return new string to be deleted by caller (never NIL but
* may be empty if there is no docstring).
* ------------------------------------------------------------ */
String *build_combined_docstring(Node *n, autodoc_t ad_type, const String *indent = "") {
String *docstr = Getattr(n, "feature:docstring");
if (docstr && Len(docstr)) {
docstr = Copy(docstr);
char *t = Char(docstr);
if (*t == '{') {
Delitem(docstr, 0);
Delitem(docstr, DOH_END);
}
}
if (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")) {
String *autodoc = make_autodoc(n, ad_type);
if (autodoc && Len(autodoc) > 0) {
if (docstr && Len(docstr)) {
Append(autodoc, "\n");
Append(autodoc, docstr);
}
String *tmp = autodoc;
autodoc = docstr;
docstr = tmp;
}
Delete(autodoc);
}
if (!docstr || !Len(docstr)) {
if (doxygen) {
docstr = Getattr(n, "python:docstring");
if (!docstr && doxygenTranslator->hasDocumentation(n)) {
docstr = doxygenTranslator->getDocumentation(n);
// Avoid rebuilding it again the next time: notice that we can't do
// this for the combined doc string as autodoc part of it depends on
// the sym:name of the node and it is changed while handling it, so
// the cached results become incorrect. But Doxygen docstring only
// depends on the comment which is not going to change, so we can
// safely cache it.
Setattr(n, "python:docstring", Copy(docstr));
}
}
}
if (!docstr)
docstr = NewString("");
// If there is more than one line then make docstrings like this:
//
// """
// This is line1
// And here is line2 followed by the rest of them
// """
//
// otherwise, put it all on a single line
if (Strchr(docstr, '\n')) {
String *tmp = NewString("");
Append(tmp, "\n");
Append(tmp, indent_docstring(docstr, indent));
Append(tmp, indent);
Delete(docstr);
docstr = tmp;
}
return docstr;
}
/* ------------------------------------------------------------
@ -1665,74 +1773,39 @@ public:
* set then it will build a combined docstring.
* ------------------------------------------------------------ */
String *docstring(Node *n, autodoc_t ad_type, const String *indent, bool use_triple = true) {
String *str = Getattr(n, "feature:docstring");
bool have_ds = (str && Len(str) > 0);
bool have_auto = (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc"));
const char *triple_double = use_triple ? "\"\"\"" : "";
String *autodoc = NULL;
String *doc = NULL;
String *docstring(Node *n, autodoc_t ad_type, const String *indent) {
String *docstr = build_combined_docstring(n, ad_type, indent);
if (!Len(docstr))
return docstr;
if (have_ds) {
char *t = Char(str);
if (*t == '{') {
Delitem(str, 0);
Delitem(str, DOH_END);
}
}
// Notice that all comments are created as raw strings (prefix "r"),
// because '\' is used often in comments, but may break Python module from
// loading. For example, in doxy comment one may write path in quotes:
//
// This is path to file "C:\x\file.txt"
//
// Python will not load the module with such comment because of illegal
// escape '\x'. '\' may additionally appear in verbatim or htmlonly sections
// of doxygen doc, Latex expressions, ...
String *doc = NewString("");
Append(doc, "r\"\"\"");
Append(doc, docstr);
Append(doc, "\"\"\"");
Delete(docstr);
if (have_auto) {
autodoc = make_autodoc(n, ad_type);
have_auto = (autodoc && Len(autodoc) > 0);
}
// If there is more than one line then make docstrings like this:
//
// """
// This is line1
// And here is line2 followed by the rest of them
// """
//
// otherwise, put it all on a single line
//
if (have_auto && have_ds) { // Both autodoc and docstring are present
doc = NewString("");
Printv(doc, triple_double, "\n",
indent_docstring(autodoc, indent), "\n",
indent_docstring(str, indent), indent, triple_double, NIL);
} else if (!have_auto && have_ds) { // only docstring
if (Strchr(str, '\n') == 0) {
doc = NewStringf("%s%s%s", triple_double, str, triple_double);
} else {
doc = NewString("");
Printv(doc, triple_double, "\n", indent_docstring(str, indent), indent, triple_double, NIL);
}
} else if (have_auto && !have_ds) { // only autodoc
if (Strchr(autodoc, '\n') == 0) {
doc = NewStringf("%s%s%s", triple_double, autodoc, triple_double);
} else {
doc = NewString("");
Printv(doc, triple_double, "\n", indent_docstring(autodoc, indent), indent, triple_double, NIL);
}
} else
doc = NewString("");
// Save the generated strings in the parse tree in case they are used later
// by post processing tools
Setattr(n, "python:docstring", doc);
Setattr(n, "python:autodoc", autodoc);
return doc;
}
}
/* ------------------------------------------------------------
* cdocstring()
*
* Get the docstring text as it would appear in C-language
* source code.
* source code (but without quotes around it).
* ------------------------------------------------------------ */
String *cdocstring(Node *n, autodoc_t ad_type)
{
String *ds = docstring(n, ad_type, "", false);
String *ds = build_combined_docstring(n, ad_type);
Replaceall(ds, "\\", "\\\\");
Replaceall(ds, "\"", "\\\"");
Replaceall(ds, "\n", "\\n\"\n\t\t\"");
@ -2008,17 +2081,24 @@ public:
break;
case AUTODOC_METHOD:
String *paramList = make_autodocParmList(n, showTypes);
Printf(doc, "%s(", symname);
if (showTypes)
Printf(doc, "%s ", class_name);
if (Len(paramList))
Printf(doc, "self, %s)", paramList);
else
Printf(doc, "self)");
if (type_str)
Printf(doc, " -> %s", type_str);
{
String *paramList = make_autodocParmList(n, showTypes);
Printf(doc, "%s(", symname);
if (showTypes)
Printf(doc, "%s ", class_name);
if (Len(paramList))
Printf(doc, "self, %s)", paramList);
else
Printf(doc, "self)");
if (type_str)
Printf(doc, " -> %s", type_str);
}
break;
case AUTODOC_CONST:
// There is no autodoc support for constants currently, this enum
// element only exists to allow calling docstring() with it.
return NULL;
}
Delete(type_str);
}
@ -3641,20 +3721,21 @@ public:
}
if (!builtin && (shadow) && (!(shadow & PYSHADOW_MEMBER))) {
String *f_s;
if (!in_class) {
if(needs_swigconstant(n)) {
Printv(f_shadow, "\n",NIL);
Printv(f_shadow, module, ".", iname, "_swigconstant(",module,")\n", NIL);
}
Printv(f_shadow, iname, " = ", module, ".", iname, "\n", NIL);
f_s = f_shadow;
} else {
if (!(Getattr(n, "feature:python:callback"))) {
if(needs_swigconstant(n)) {
Printv(f_shadow_stubs, "\n",NIL);
Printv(f_shadow_stubs, module, ".", iname, "_swigconstant(", module, ")\n", NIL);
}
Printv(f_shadow_stubs, iname, " = ", module, ".", iname, "\n", NIL);
f_s = Getattr(n, "feature:python:callback") ? NIL : f_shadow_stubs;
}
if (f_s) {
if (needs_swigconstant(n)) {
Printv(f_s, "\n",NIL);
Printv(f_s, module, ".", iname, "_swigconstant(",module,")\n", NIL);
}
Printv(f_s, iname, " = ", module, ".", iname, "\n", NIL);
if (have_docstring(n))
Printv(f_s, docstring(n, AUTODOC_CONST, tab4), "\n", NIL);
}
}
return SWIG_OK;
@ -4137,7 +4218,16 @@ public:
Printv(f, "#else\n", NIL);
printSlot(f, getSlot(n, "feature:python:tp_flags", tp_flags), "tp_flags");
Printv(f, "#endif\n", NIL);
printSlot(f, quoted_tp_doc_str, "tp_doc");
if (have_docstring(n)) {
String *ds = cdocstring(n, AUTODOC_CLASS);
String *tp_doc = NewString("");
Printf(tp_doc, "\"%s\"", ds);
Delete(ds);
printSlot(f, tp_doc, "tp_doc");
Delete(tp_doc);
} else {
printSlot(f, quoted_tp_doc_str, "tp_doc");
}
printSlot(f, getSlot(n, "feature:python:tp_traverse"), "tp_traverse", "traverseproc");
printSlot(f, getSlot(n, "feature:python:tp_clear"), "tp_clear", "inquiry");
printSlot(f, getSlot(n, "feature:python:tp_richcompare", richcompare_func), "tp_richcompare", "richcmpfunc");
@ -4473,6 +4563,8 @@ public:
}
Printf(f_shadow, ":\n");
// write docstrings if requested
if (have_docstring(n)) {
String *str = docstring(n, AUTODOC_CLASS, tab4);
if (str && Len(str))
@ -4703,7 +4795,7 @@ public:
String *wname = Swig_name_wrapper(fullname);
Setattr(class_members, symname, n);
int argcount = Getattr(n, "python:argcount") ? atoi(Char(Getattr(n, "python:argcount"))) : 2;
String *ds = have_docstring(n) ? cdocstring(n, AUTODOC_FUNC) : NewString("");
String *ds = have_docstring(n) ? cdocstring(n, AUTODOC_METHOD) : NewString("");
if (check_kwargs(n)) {
Printf(builtin_methods, " { \"%s\", (PyCFunction) %s, METH_VARARGS|METH_KEYWORDS, (char *) \"%s\" },\n", symname, wname, ds);
} else if (argcount == 0) {
@ -5218,6 +5310,8 @@ public:
Swig_restore(n);
} else if (shadow) {
Printv(f_shadow, tab4, symname, " = ", module, ".", Swig_name_member(NSPACE_TODO, class_name, symname), "\n", NIL);
if (have_docstring(n))
Printv(f_shadow, tab4, docstring(n, AUTODOC_CONST, tab4), "\n", NIL);
}
return SWIG_OK;
}

View file

@ -214,8 +214,8 @@ public:
virtual Hash* symbolAddScope(const_String_or_char_ptr scope);
virtual Hash* symbolScopeLookup(const_String_or_char_ptr scope);
virtual Hash* symbolScopePseudoSymbolLookup(const_String_or_char_ptr scope);
virtual Node *classLookup(const SwigType *s) const; /* Class lookup */
virtual Node *enumLookup(SwigType *s); /* Enum lookup */
static Node *classLookup(const SwigType *s); /* Class lookup */
static Node *enumLookup(SwigType *s); /* Enum lookup */
virtual int abstractClassTest(Node *n); /* Is class really abstract? */
virtual int is_assignable(Node *n); /* Is variable assignable? */
virtual String *runtimeCode(); /* returns the language specific runtime code */
@ -342,10 +342,11 @@ protected:
/* Director language module */
int director_language;
/* Used to translate Doxygen comments to target documentation format */
class DoxygenTranslator *doxygenTranslator;
private:
Hash *symtabs; /* symbol tables */
Hash *classtypes;
Hash *enumtypes;
int overloading;
int multiinput;
int cplus_runtime;

View file

@ -106,10 +106,10 @@ void Swig_extend_append_previous(Node *cls, Node *am) {
set_nextSibling(n,0);
/* typemaps and fragments need to be prepended */
if (((Cmp(nodeType(n),"typemap") == 0) || (Cmp(nodeType(n),"fragment") == 0))) {
if (!pe) pe = new_node("extend");
if (!pe) pe = Swig_cparse_new_node("extend");
appendChild(pe, n);
} else {
if (!ae) ae = new_node("extend");
if (!ae) ae = Swig_cparse_new_node("extend");
appendChild(ae, n);
}
n = ne;

View file

@ -1484,6 +1484,17 @@ String *Swig_pcre_version(void) {
#endif
/* ------------------------------------------------------------
* Swig_is_generated_overload()
* Check if the function is an automatically generated
* overload created because a method has default parameters.
* ------------------------------------------------------------ */
int Swig_is_generated_overload(Node *n) {
Node *base_method = Getattr(n, "sym:overloaded");
Node *default_args = Getattr(n, "defaultargs");
return ((base_method != NULL) && (default_args != NULL) && (base_method == default_args));
}
/* -----------------------------------------------------------------------------
* Swig_init()
*

View file

@ -335,7 +335,9 @@ extern int ParmList_is_compactdefargs(ParmList *p);
extern void Swig_offset_string(String *s, int number);
extern String *Swig_pcre_version(void);
extern void Swig_init(void);
extern int Swig_value_wrapper_mode(int mode);
extern int Swig_is_generated_overload(Node *n);
typedef enum { EMF_STANDARD, EMF_MICROSOFT } ErrorMessageFormat;