From dd27620566cf83631c309f008a5bc6b4c28b9f07 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Fri, 25 Mar 2016 16:31:16 +0100 Subject: [PATCH] filter declarations in C++, improve luadoc --- tools/doxy2json/ardourdoc.sh | 18 ++--- tools/doxy2json/doxy2json.cc | 142 ++++++++++++++++++++++++++--------- tools/fmt-luadoc.php | 89 +++++++++++++++++++++- 3 files changed, 197 insertions(+), 52 deletions(-) diff --git a/tools/doxy2json/ardourdoc.sh b/tools/doxy2json/ardourdoc.sh index 478ae9326d..616e70343f 100755 --- a/tools/doxy2json/ardourdoc.sh +++ b/tools/doxy2json/ardourdoc.sh @@ -14,6 +14,8 @@ echo "# analyzing source.. -> $TMPFILE" $LLVMINCLUDE -I /usr/include/linux \ -I libs/ardour -I libs/pbd -I libs/lua -I gtk2_ardour -I libs/timecode \ -I libs/ltc -I libs/evoral \ + -X "_" -X "::" -X "sigc" -X "Atk::" -X "Gdk::" -X "Gtk::" -X "Gio::" \ + -X "Glib::" -X "Pango::" -X "luabridge::" \ libs/ardour/ardour/* libs/pbd/pbd/* \ gtk2_ardour/*.h \ /usr/include/cairomm-1.0/cairomm/context.h \ @@ -28,22 +30,12 @@ php << EOF \$api = array (); foreach (json_decode (\$json, true) as \$a) { if (!isset (\$a['decl'])) { continue; } - if (empty (\$a['decl'])) { continue; } - if (\$a['decl'] == '::') { continue; } - if (substr (\$a['decl'], 0, 1) == '_') { continue; } - if (substr (\$a['decl'], 0, 2) == '::') { continue; } - if (substr (\$a['decl'], 0, 4) == 'sigc') { continue; } - if (substr (\$a['decl'], 0, 5) == 'Atk::') { continue; } - if (substr (\$a['decl'], 0, 5) == 'Gdk::') { continue; } - if (substr (\$a['decl'], 0, 5) == 'Gtk::') { continue; } - if (substr (\$a['decl'], 0, 5) == 'Gio::') { continue; } - if (substr (\$a['decl'], 0, 6) == 'Glib::') { continue; } - if (substr (\$a['decl'], 0, 7) == 'Pango::') { continue; } - if (substr (\$a['decl'], 0, 11) == 'luabridge::') { continue; } \$a['decl'] = str_replace ('size_t', 'unsigned long', \$a['decl']); \$a['decl'] = str_replace ('uint32_t', 'unsigned int', \$a['decl']); + \$a['decl'] = str_replace ('int32_t', 'int', \$a['decl']); \$a['decl'] = str_replace ('framepos_t', 'long', \$a['decl']); + \$a['decl'] = str_replace ('framecnt_t', 'long', \$a['decl']); \$a['decl'] = str_replace ('frameoffset_t', 'long', \$a['decl']); \$a['decl'] = str_replace ('int64_t', 'long', \$a['decl']); \$a['decl'] = str_replace ('uint8_t', 'unsigned char', \$a['decl']); @@ -57,7 +49,7 @@ foreach (json_decode (\$json, true) as \$a) { \$a['decl'] = str_replace ('const unsigned long', 'unsigned long', \$a['decl']); \$canon = str_replace (' *', '*', \$a['decl']); \$api[\$canon] = \$a; - } +} \$jout = array (); foreach (\$api as \$k => \$a) { \$jout[] = \$a; diff --git a/tools/doxy2json/doxy2json.cc b/tools/doxy2json/doxy2json.cc index f8242d5d46..2f28257037 100644 --- a/tools/doxy2json/doxy2json.cc +++ b/tools/doxy2json/doxy2json.cc @@ -23,9 +23,49 @@ #include #include #include +#include #include #include +struct dox2js { + dox2js () : clang_argc (2), clang_argv (0), excl_argc (0), excl_argv (0) + { + excl_argv = (char**) calloc (1, sizeof (char*)); + clang_argv = (char**) malloc (clang_argc * sizeof (char*)); + clang_argv[0] = strdup ("-x"); + clang_argv[1] = strdup ("c++"); + } + + ~dox2js () { + for (int i = 0; i < clang_argc; ++i) { + free (clang_argv[i]); + } + for (int i = 0; excl_argv[i]; ++i) { + free (excl_argv[i]); + } + free (clang_argv); + free (excl_argv); + } + + void add_clang_arg (const char *a) { + clang_argv = (char**) realloc (clang_argv, (clang_argc + 2) * sizeof (char*)); + clang_argv[clang_argc++] = strdup ("-I"); + clang_argv[clang_argc++] = strdup (a); + } + + void add_exclude (const char *a) { + excl_argv = (char**) realloc (excl_argv, (excl_argc + 2) * sizeof (char*)); + excl_argv[excl_argc++] = strdup (a); + excl_argv[excl_argc] = NULL; + } + + int clang_argc; + char** clang_argv; + int excl_argc; + char** excl_argv; + std::map results; +}; + static const char* kind_to_txt (CXCursor cursor) { @@ -69,20 +109,37 @@ escape_json (const std::string &s) return o.str (); } -static void recurse_parents (CXCursor cr) { +static std::string +recurse_parents (CXCursor cr) { + std::string rv; CXCursor pc = clang_getCursorSemanticParent (cr); if (CXCursor_TranslationUnit == clang_getCursorKind (pc)) { - return; + return rv; } if (!clang_Cursor_isNull (pc)) { - recurse_parents (pc); - printf ("%s::", clang_getCString (clang_getCursorDisplayName (pc))); + rv += recurse_parents (pc); + rv += clang_getCString (clang_getCursorDisplayName (pc)); + rv += "::"; } + return rv; +} + +static bool +check_excludes (const std::string& decl, CXClientData d) { + struct dox2js* dj = (struct dox2js*) d; + char** excl = dj->excl_argv; + for (int i = 0; excl[i]; ++i) { + if (decl.compare (0, strlen (excl[i]), excl[i]) == 0) { + return true; + } + } + return false; } static enum CXChildVisitResult -traverse (CXCursor cr, CXCursor /*parent*/, CXClientData) +traverse (CXCursor cr, CXCursor /*parent*/, CXClientData d) { + struct dox2js* dj = (struct dox2js*) d; CXComment c = clang_Cursor_getParsedComment (cr); if (clang_Comment_getKind (c) != CXComment_Null @@ -90,45 +147,48 @@ traverse (CXCursor cr, CXCursor /*parent*/, CXClientData) && 0 != strlen (kind_to_txt (cr)) ) { - printf ("{ \"decl\" : \""); - recurse_parents (cr); - // TODO: resolve typedef enum { .. } name; // use clang_getCursorDefinition (clang_getCanonicalCursor (cr)) ?? - printf ("%s\",\n", clang_getCString (clang_getCursorDisplayName (cr))); + std::string decl = recurse_parents (cr); + decl += clang_getCString (clang_getCursorDisplayName (cr)); - if (clang_Cursor_isVariadic (cr)) { - printf (" \"variadic\" : true,\n"); + if (decl.empty () || check_excludes (decl, d)) { + return CXChildVisit_Recurse; } - printf (" \"kind\" : \"%s\",\n", kind_to_txt (cr)); + std::ostringstream o; + o << "{ \"decl\" : \"" << decl << "\",\n"; + + if (clang_Cursor_isVariadic (cr)) { + o << " \"variadic\" : true,\n"; + } CXSourceLocation loc = clang_getCursorLocation (cr); CXFile file; unsigned line, col, off; clang_getFileLocation (loc, &file, &line, &col, &off); - printf (" \"src\" : \"%s:%d\",\n", - clang_getCString (clang_getFileName (file)), line); + o << " \"kind\" : \"" << kind_to_txt (cr) << "\",\n" + << " \"src\" : \"" << clang_getCString (clang_getFileName (file)) << ":" << line << "\",\n" + << " \"doc\" : \"" << escape_json (clang_getCString (clang_FullComment_getAsHTML (c))) << "\"\n" + << "},\n"; - printf (" \"doc\" : \"%s\"\n", - escape_json (clang_getCString (clang_FullComment_getAsHTML (c))).c_str ()); - printf ("},\n"); + dj->results[decl] = o.str (); } return CXChildVisit_Recurse; } static void -process_file (int argc, char **args, const char *fn) +process_file (const char* fn, struct dox2js *dj) { CXIndex index = clang_createIndex (0, 0); - CXTranslationUnit tu = clang_createTranslationUnitFromSourceFile (index, fn, argc, args, 0, 0); + CXTranslationUnit tu = clang_createTranslationUnitFromSourceFile (index, fn, dj->clang_argc, dj->clang_argv, 0, 0); if (tu == NULL) { fprintf (stderr, "Cannot create translation unit for src: %s\n", fn); return; } - clang_visitChildren (clang_getTranslationUnitCursor (tu), traverse, 0); + clang_visitChildren (clang_getTranslationUnitCursor (tu), traverse, (CXClientData) dj); clang_disposeTranslationUnit (tu); clang_disposeIndex (index); @@ -138,23 +198,23 @@ static void usage (int status) { printf ("doxy2json - extract doxygen doc from C++ headers.\n\n"); - fprintf (stderr, "Usage: dox2json [-I path]* [filename]*\n"); + fprintf (stderr, "Usage: dox2json [-I path]* [-X exclude]* [filename]*\n"); exit (status); } -int main (int argc, char **argv) +int main (int argc, char** argv) { - int cnt = 2; - char **args = (char**) malloc (cnt * sizeof (char*)); - args[0] = strdup ("-x"); - args[1] = strdup ("c++"); + struct dox2js dj; + + bool report_progress = false; int c; - while (EOF != (c = getopt (argc, argv, "I:"))) { + while (EOF != (c = getopt (argc, argv, "I:X:"))) { switch (c) { case 'I': - args = (char**) realloc (args, (cnt + 2) * sizeof (char*)); - args[cnt++] = strdup ("-I"); - args[cnt++] = strdup (optarg); + dj.add_clang_arg (optarg); + break; + case 'X': + dj.add_exclude (optarg); break; case 'h': usage (0); @@ -168,16 +228,26 @@ int main (int argc, char **argv) usage (EXIT_FAILURE); } - printf ("[\n"); + const int total = (argc - optind); + if (total > 6) { + report_progress = true; + } + for (int i = optind; i < argc; ++i) { - process_file (cnt, args, argv[i]); + process_file (argv[i], &dj); + if (report_progress) { + fprintf (stderr, "progress: %4.1f%% [%4d / %4d] decl: %ld \r", + 100.f * (1.f + i - optind) / (float)total, i - optind, total, + dj.results.size ()); + fflush (stderr); + } } - printf ("{} ]\n"); - for (int i = 0; i < cnt; ++i) { - free (args[i]); + printf ("[\n"); + for (std::map ::const_iterator i = dj.results.begin (); i != dj.results.end (); ++i) { + printf ("%s\n", (*i).second.c_str ()); } - free (args); + printf ("{} ]\n"); return 0; } diff --git a/tools/fmt-luadoc.php b/tools/fmt-luadoc.php index c764afd79f..f35b829380 100755 --- a/tools/fmt-luadoc.php +++ b/tools/fmt-luadoc.php @@ -601,10 +601,15 @@ h2.enum { background-color: #aaaaaa; } h2.pointerclass { background-color: #eeaa66; } h2.array { background-color: #66aaee; } h2.opaque { background-color: #6666aa; } +p { text-align: justify; } p.cdecl { text-align: right; float:right; font-size:90%; margin:0; padding: 0 0 0 1em;} ul.classindex { columns: 2; -webkit-columns: 2; -moz-columns: 2; } div.clear { clear:both; } p.classinfo { margin: .25em 0;} +div.code { width:80%; margin:.5em auto; } +div.code div { width:45%; } +div.code pre { line-height: 1.2em; margin: .25em 0; } +div.code samp { color: green; font-weight: bold; background-color: #eee; } div.classdox { padding: .1em 1em;} div.classdox p { margin: .5em 0 .5em .6em;} div.classdox p { margin: .5em 0 .5em .6em;} @@ -615,7 +620,7 @@ table.classmembers th { text-align:left; border-bottom:1px solid black; pad table.classmembers td.def { text-align:right; padding-right:.5em; white-space: nowrap;} table.classmembers td.decl { text-align:left; padding-left:.5em; white-space: nowrap; } table.classmembers td.doc { text-align:left; padding-left:.6em; line-height: 1.2em; font-size:80%;} -table.classmembers td.doc div.dox {background-color:#ddd; padding: .1em 1em;} +table.classmembers td.doc div.dox {background-color:#eee; padding: .1em 1em;} table.classmembers td.doc p { margin: .5em 0; } table.classmembers td.doc p.para-brief { font-size:120%; } table.classmembers td.doc p.para-returns { font-size:120%; } @@ -626,7 +631,7 @@ table.classmembers span.em { font-style: italic;} span.functionname abbr { text-decoration:none; cursor:default;} div.header {text-align:center;} div.header h1 {margin:0;} -div.header p {margin:.25em;} +div.header p {margin:.25em; text-align:center;} @@ -664,12 +669,90 @@ Tracks contain specifics. For Example a track has-a diskstream (for fil

Operations are performed on objects. One gets a reference to an object and then calls a method. -e.g obj = Session:route_by_name("Audio") obj:set_name("Guitar") +e.g obj = Session:route_by_name("Audio") obj:set_name("Guitar").

Object lifetimes are managed by the Session. Most Objects cannot be directly created, but one asks the Session to create or destroy them. This is mainly due to realtime constrains: you cannot simply remove a track that is currently processing audio. There are various factory methods for object creation or removal.

+

Pass by Reference

+

+Since lua functions are closures, C++ methods that pass arguments by reference cannot be used as-is. +All parameters passed to a C++ method which uses references are returned as Lua Table. +If the C++ method also returns a value it is prefixed. Two parameters are returned: the value and a Lua Table holding the parameters. +

+ +
+
C++ + +
void set_ref (int& var, long& val)
+{
+	printf ("%d %ld\n", var, val);
+	var = 5;
+	val = 7;
+}
+
+ +
+
Lua + +
local var = 0;
+ref = set_ref (var, 2);
+-- output from C++ printf()
+0 2
+-- var is still 0 here
+print (ref[1], ref[2])
+5 7
+ +
+
+
+
+
+ +
int set_ref2 (int &var, std::string unused)
+{
+	var = 5;
+	return 3;
+}
+
+ +
+
+
rv, ref = set_ref2 (0, "hello");
+print (rv, ref[1], ref[2])
+3 5 hello
+
+
+
+ +

Pointer Classes

+

+Libardour makes extensive use of reference counted boost::shared_ptr to manage lifetimes. +The Lua bindings provide a complete abstration of this. There are no pointers in lua. +For example a is a pointer in C++, but lua functions operate on it like it was a class instance. +

+

+shared_ptr are reference counted. Once assigned to a lua variable, the C++ object will be kept and remains valid. +It is good practice to assign references to lua local variables or reset the variable to nil to drop the ref. +

+

+All pointer classes have a isnil () method. This is for two cases: +Construction may fail. e.g. .newplugin() +may not be able to find the given plugin and hence cannot create an object. +

+

+The second case if for boost::weak_ptr. As opposed to boost::shared_ptr weak-pointers are not reference counted. +The object may vanish at any time. +If lua code calls a method on a nil object, the interpreter will raise an exception and the script will not continue. +This is not unlike a = nil a:test() which results in en error "attempt to index a nil value". +

+

+From the lua side of things there is no distinction between weak and shared pointers. They behave identically. +Below they're inidicated in orange and have an arrow to indicate the pointer type. +Pointer Classes cannot be created in lua scripts. It always requires a call to C++ to create the Object and obtain a reference to it. +

+ Class Documentation'.NL; -- 2.30.2