X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=tools%2Ffmt-luadoc.php;h=7f7b35d589c74084deb71a85cb4dd516611cead9;hb=dab31732c5ebcc0536c110682ed57e9d76160979;hp=c764afd79f8c6ddd3101fecd9e07e19a169b113d;hpb=83fdfd89f735775cffb98d38e14015fd073a20d5;p=ardour.git diff --git a/tools/fmt-luadoc.php b/tools/fmt-luadoc.php index c764afd79f..7f7b35d589 100755 --- a/tools/fmt-luadoc.php +++ b/tools/fmt-luadoc.php @@ -16,13 +16,27 @@ # php tools/fmt-luadoc.php > /tmp/luadoc.html # +$options = getopt("m"); +if (isset ($options['m'])) { + $HTMLOUTPUT = false; ## set to false to output ardour-manual +} else { + $HTMLOUTPUT = true; ## set to false to output ardour-manual +} + ################################################################################ ################################################################################ $json = gzdecode (file_get_contents (dirname (__FILE__).'/../doc/luadoc.json.gz')); $doc = array (); +$ardourversion = ''; foreach (json_decode ($json, true) as $b) { - if (!isset ($b['type'])) { continue; } + if (!isset ($b['type'])) { + if (isset ($b['version'])) { $ardourversion = $b['version']; } + continue; + } + # reserved lua words + $b ['lua'] = preg_replace ('/:_end/', ':end', $b ['lua']); + $b ['lua'] = preg_replace ('/:_type/', ':type', $b ['lua']); $b ['ldec'] = preg_replace ('/ const/', '', preg_replace ('/ const&/', '', $b['decl'])); if (isset ($b['ret'])) { $b['ret'] = preg_replace ('/ const/', '', preg_replace ('/ const&/', '', $b['ret'])); @@ -114,13 +128,22 @@ function stripclass ($classname, $name) { function datatype ($decl) { # TODO handle spaces in type. Works because # we don't yet have templated types (with_space ) - return substr ($decl, 0, strpos ($decl, ' ')); + return substr ($decl, 0, strrpos ($decl, ' ')); } function luafn2class ($lua) { return substr ($lua, 0, strrpos ($lua, ':')); } +function luafn2name ($lua) { + $fn = strrpos ($lua, ':'); + if ($fn !== 0 && strlen($lua) > $fn + 1) { + return substr ($lua, $fn + 1); + } + my_die ('invalid class prefix: '. $name); +} + + function checkclass ($b) { global $classlist; if (!isset ($classlist[luafn2class ($b['lua'])])) { @@ -245,6 +268,26 @@ foreach ($doc as $b) { 'ret' => arg2lua (datatype ($b['ldec'])) ); break; + case "Static C Function": + checkclass ($b); + if (strpos ($b['lua'], 'ARDOUR:DataType:') === 0) { + # special case ARDOUR:DataType convenience c'tor + $args = array (); + $ret = array (luafn2class ($b['lua']) => 0); + $canon = 'ARDOUR::LuaAPI::datatype_ctor_'.strtolower (luafn2name ($b['lua'])).'(lua_State*)'; + } else { + my_die ('unhandled Static C: ' . print_r($b, true)); + } + $classlist[luafn2class ($b['lua'])]['func'][] = array ( + 'bind' => $b, + 'name' => $b['lua'], + 'args' => $args, + 'ret' => $ret, + 'ref' => false, + 'ext' => false, + 'cand' => $canon + ); + break; case "C Function": # we required C functions to be in a class namespace case "Ext C Function": @@ -253,9 +296,8 @@ foreach ($doc as $b) { $ret = array ('...' => 0); $ns = luafn2class ($b['lua']); $cls = $classlist[$ns]; - ## std::Vector std::List types if (preg_match ('/.*<([^>]*)[ ]*>/', $cls['ldec'], $templ)) { - // XXX -> move to C-source + # std::vector, std::list types switch (stripclass($ns, $b['lua'])) { case 'add': #$args = array (array ('LuaTable {'.$templ[1].'}' => 0)); @@ -274,6 +316,7 @@ foreach ($doc as $b) { break; } } else if (strpos ($cls['type'], ' Array') !== false) { + # catches C:FloatArray, C:IntArray $templ = preg_replace ('/[&*]*$/', '', $cls['ldec']); switch (stripclass($ns, $b['lua'])) { case 'array': @@ -302,6 +345,17 @@ foreach ($doc as $b) { 'cand' => canonical_decl ($b) ); break; + case "Free C Function": + $funclist[luafn2class ($b['lua'])][] = array ( + 'bind' => $b, + 'name' => $b['lua'], + 'args' => $args, + 'ret' => $ret, + 'ref' => false, + 'ext' => true, + 'cand' => str_replace (':', '::', $b['lua']).'(lua_State*)' + ); + break; case "Free Function": case "Free Function RefReturn": $funclist[luafn2class ($b['lua'])][] = array ( @@ -319,7 +373,6 @@ foreach ($doc as $b) { case "Weak/Shared Pointer Function": case "Weak/Shared Pointer Function RefReturn": case "Weak/Shared Null Check": - case "Weak/Shared Pointer Cast": case "Static Member Function": checkclass ($b); $classlist[luafn2class ($b['lua'])]['func'][] = array ( @@ -331,6 +384,18 @@ foreach ($doc as $b) { 'cand' => canonical_decl ($b) ); break; + case "Cast": + case "Weak/Shared Pointer Cast": + checkclass ($b); + $classlist[luafn2class ($b['lua'])]['cast'][] = array ( + 'bind' => $b, + 'name' => $b['lua'], + 'args' => decl2args ($b['ldec']), + 'ret' => arg2lua ($b['ret']), + 'ref' => (strpos ($b['type'], "RefReturn") !== false), + 'cand' => canonical_decl ($b) + ); + break; case "Constant/Enum": case "Constant/Enum Member": # already handled -> $consts @@ -350,14 +415,17 @@ foreach ($doc as $b) { foreach ($classlist as $ns => $cl) { if (strpos ($cl['type'], ' Array') !== false) { $classlist[$ns]['arr'] = true; + $classlist[$ns]['cdecl'] = $cl['decl']; continue; } foreach ($classes as $c) { if ($c['lua'] == $ns) { if (strpos ($c['type'], 'Pointer Class') !== false) { $classlist[$ns]['ptr'] = true; - $classlist[$ns]['decl'] = 'boost::shared_ptr< '.$c['decl']. ' >, boost::weak_ptr< '.$c['decl']. ' >'; + $classlist[$ns]['cdecl'] = 'boost::shared_ptr< '.$c['decl']. ' >, boost::weak_ptr< '.$c['decl']. ' >'; break; + } else { + $classlist[$ns]['cdecl'] = $c['decl']; } } } @@ -392,8 +460,10 @@ ksort ($classlist); #### -- split here -- #### # from here on, only $classlist and $constlist arrays are relevant. +# we also pull in C++ header annotation from doxygen to $api + -# read function documentation from doxygen +# read documentation from doxygen $json = gzdecode (file_get_contents (dirname (__FILE__).'/../doc/ardourapi.json.gz')); $api = array (); foreach (json_decode ($json, true) as $a) { @@ -403,8 +473,11 @@ foreach (json_decode ($json, true) as $a) { $api[$canon] = $a; } +# keep track of found/missing doc $dox_found = 0; $dox_miss = 0; + +# retrive a value from $api function doxydoc ($canonical_declaration) { global $api; global $dox_found; @@ -413,14 +486,18 @@ function doxydoc ($canonical_declaration) { $dox_found++; return $api[$canonical_declaration]['doc']; } - elseif (isset ($api['ARDOUR::'.$canonical_declaration])) { + // remove template namespace e.g. + // "ARDOUR::Track::bounceable(boost::shared_ptr" + // "ARDOUR::Track::bounceable(boost::shared_ptr" + $cn = preg_replace ('/<[^>]*::([^>]*)>/', '<$1>', $canonical_declaration); + if (isset ($api[$cn])) { $dox_found++; - return $api['ARDOUR::'.$canonical_declaration]['doc']; - } - else { - $dox_miss++; - return ''; + return $api[$cn]['doc']; } + #fwrite (STDERR, $canonical_declaration."\n"); # XXX DEBUG + + $dox_miss++; + return ''; } ################################################################################ @@ -432,22 +509,22 @@ function doxydoc ($canonical_declaration) { # Helper functions define ('NL', "\n"); +# constructors, enums (constants) use a dot. (e.g. "LuaOSC.Address" -> "LuaOSC.Address" ) function ctorname ($name) { return htmlentities (str_replace (':', '.', $name)); } +# strip class prefix (e.g "Evoral:MidiEvent:channel" -> "channel") function shortname ($name) { return htmlentities (substr ($name, strrpos ($name, ':') + 1)); } +# retrieve variable name from array["VARNAME"] => FLAGS function varname ($a) { return array_keys ($a)[0]; } -function name_sort_cb ($a, $b) { - return strcmp ($a['name'], $b['name']); -} - +# recusively collect class parents (derived classes) function traverse_parent ($ns, &$inherited) { global $classlist; $rv = ''; @@ -464,11 +541,11 @@ function traverse_parent ($ns, &$inherited) { return $rv; } +# create a cross-reference to a type (class or enum) +# *all* links are generated here, currently anchors on a single page. function typelink ($a, $short = false, $argcls = '', $linkcls = '', $suffix = '') { global $classlist; global $constlist; - # all cross-reference links are generated here. - # currently anchors on a single page. if (isset($classlist[$a]['free'])) { return ''.($short ? shortname($a) : ctorname($a)).$suffix.''; } else if (in_array ($a, array_keys ($classlist))) { @@ -480,6 +557,7 @@ function typelink ($a, $short = false, $argcls = '', $linkcls = '', $suffix = '' } } +# output format function arguments function format_args ($args) { $rv = ' ('; $first = true; @@ -500,6 +578,7 @@ function format_args ($args) { return $rv; } +# format doxygen documentation for class-definition function format_doxyclass ($cl) { $rv = ''; if (isset ($cl['decl'])) { @@ -511,6 +590,7 @@ function format_doxyclass ($cl) { return $rv; } +# format doxygen documentation for class-members function format_doxydoc ($f) { $rv = ''; if (isset ($f['cand'])) { @@ -525,8 +605,16 @@ function format_doxydoc ($f) { } return $rv; } + +# usort() callback for class-members +function name_sort_cb ($a, $b) { + return strcmp ($a['name'], $b['name']); +} + +# main output function for every class function format_class_members ($ns, $cl, &$dups) { $rv = ''; + # print contructor - if any if (isset ($cl['ctor'])) { usort ($cl['ctor'], 'name_sort_cb'); $rv.= ' Constructor'.NL; @@ -535,9 +623,14 @@ function format_class_members ($ns, $cl, &$dups) { $rv.= ''.ctorname ($f['name']).''; $rv.= format_args ($f['args']); $rv.= ''.NL; + # doxygen documentation (may be empty) $rv.= format_doxydoc($f); } } + + # strip duplicates (inherited or derived methods) + # e.g AudioTrack -> Track -> Route -> SessionObject -> Stateful + # all 5 have "isnil()" $nondups = array (); if (isset ($cl['func'])) { foreach ($cl['func'] as $f) { @@ -545,30 +638,55 @@ function format_class_members ($ns, $cl, &$dups) { $nondups[] = $f; } } + + # print methods - if any if (count ($nondups) > 0) { usort ($nondups, 'name_sort_cb'); $rv.= ' Methods'.NL; foreach ($nondups as $f) { $dups[] = stripclass ($ns, $f['name']); + # return value/type $rv.= ' '; if ($f['ref'] && isset ($f['ext'])) { # external C functions $rv.= ''.varname ($f['ret']).''; } elseif ($f['ref'] && varname ($f['ret']) == 'void') { - # functions with reference args return args + # void functions with reference args $rv.= 'LuaTable(...)'; } elseif ($f['ref']) { + # functions with reference args and return value $rv.= 'LuaTable('.typelink (varname ($f['ret']), true, 'em').', ...)'; } else { + # normal class members $rv.= typelink (varname ($f['ret']), true, 'em'); } + # function declaration and arguments + $rv.= ''; + $rv.= ''.stripclass ($ns, $f['name']).''; + $rv.= format_args ($f['args']); + $rv.= ''.NL; + # doxygen documentation (may be empty) + $rv.= format_doxydoc($f); + } + } + # print cast - if any + if (isset ($cl['cast'])) { + usort ($cl['cast'], 'name_sort_cb'); + $rv.= ' Cast'.NL; + foreach ($cl['cast'] as $f) { + $rv.= ' '; + $rv.= typelink (varname ($f['ret']), true, 'em'); + # function declaration and arguments $rv.= ''; $rv.= ''.stripclass ($ns, $f['name']).''; $rv.= format_args ($f['args']); $rv.= ''.NL; + # doxygen documentation (may be empty) $rv.= format_doxydoc($f); } } + + # print data members - if any if (isset ($cl['data'])) { usort ($cl['data'], 'name_sort_cb'); $rv.= ' Data Members'.NL; @@ -585,53 +703,62 @@ function format_class_members ($ns, $cl, &$dups) { ################################################################################ # Start Output +if ($HTMLOUTPUT) { + ?> Ardour Lua Bindings
-

Ardour Lua Bindings

+

Ardour Lua Bindings

Class Documentation  |  @@ -640,9 +767,38 @@ div.header p {margin:.25em;} Index

-
-

Overview

+ + + +--- +layout: default +style: luadoc +title: Class Reference +--- + +

+This documentation is far from complete may be inaccurate and subject to change. +

+ + + +
+ + + +

Overview

The top-level entry point are and . Most other Classes are used indirectly starting with a Session function. e.g. Session:get_routes(). @@ -655,7 +811,7 @@ A few classes are dedicated to certain script types, e.g. Lua DSP processors hav

Detailed documentation (parameter names, method description) is not yet available. Please stay tuned.

-

Short introduction to Ardour classes

+

Short introduction to Ardour classes

Ardour's structure is object oriented. The main object is the Session. A Session contains Audio Tracks, Midi Tracks and Busses. Audio and Midi tracks are derived from a more general "Track" Object, which in turn is derived from a "Route" (aka Bus). @@ -664,40 +820,135 @@ 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"). +

+

+Lua automatically follows C++ class inheritance. e.g one can directly call all SessionObject and Route methods on Track object. However lua does not automatically promote objects. A Route object which just happens to be a Track needs to be explicily cast to a Track. Methods for casts are provided with each class. Note that the cast may fail and return a nil reference. +

+

+Likewise multiple inheritance is a non-trivial issue in lua. To avoid performance penalties involved with lookups, explicit casts are required in this case. One example is which is-a StatefulDestructible which inhertis from both Stateful and Destructible.

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; +################################# +# Main output function -- Classes + +echo '

Class Documentation

'.NL; foreach ($classlist as $ns => $cl) { $dups = array (); $tbl = format_class_members ($ns, $cl, $dups); - # format class title + # format class title - depending on type if (empty ($tbl)) { - echo '

 '.htmlentities ($ns).'

'.NL; + # classes with no members (no ctor, no methods, no data) + echo '

 '.htmlentities ($ns).'

'.NL; } else if (isset ($classlist[$ns]['free'])) { - echo '

 '.ctorname($ns).'

'.NL; + # free functions (no class) + echo '

 '.ctorname($ns).'

'.NL; } else if (isset ($classlist[$ns]['arr'])) { - echo '

 '.htmlentities ($ns).'

'.NL; + # C Arrays + echo '

 '.htmlentities ($ns).'

'.NL; } else if (isset ($classlist[$ns]['ptr'])) { - echo '

 '. htmlentities ($ns).'

'.NL; - } else { - echo '

 '.htmlentities ($ns).'

'.NL; + # Pointer Classes + echo '

 '. htmlentities ($ns).'

'.NL; } - if (isset ($cl['decl'])) { - echo '

C‡: '.htmlentities ($cl['decl']).'

'.NL; + else { + # Normal Class + echo '

 '.htmlentities ($ns).'

'.NL; + } + + # show original C++ declaration + if (isset ($cl['cdecl'])) { + echo '

C‡: '.htmlentities ($cl['cdecl']).'

'.NL; } - # print class inheritance + # print class inheritance (direct parent *name* only) $inherited = array (); $isa = traverse_parent ($ns, $inherited); if (!empty ($isa)) { @@ -705,6 +956,8 @@ foreach ($classlist as $ns => $cl) { } echo '
'.NL; + + # class documentation (if any) echo format_doxyclass ($cl); # member documentation @@ -716,11 +969,11 @@ foreach ($classlist as $ns => $cl) { echo ' '.NL; } - # traverse parent classes (inherited members) + # traverse parent classes (all inherited members) foreach ($inherited as $pns => $pcl) { $tbl = format_class_members ($pns, $pcl, $dups); if (!empty ($tbl)) { - echo '

Inherited from '.$pns.'

'.NL; + echo '

Inherited from '.$pns.'

'.NL; echo ''.NL; echo $tbl; echo '
'.NL; @@ -728,9 +981,12 @@ foreach ($classlist as $ns => $cl) { } } -echo '

Enum/Constants

'.NL; +#################### +# Enum and Constants + +echo '

Enum/Constants

'.NL; foreach ($constlist as $ns => $cs) { - echo '

 '.ctorname ($ns).'

'.NL; + echo '

 '.ctorname ($ns).'

'.NL; echo '
    '.NL; foreach ($cs as $c) { echo '
  • '.ctorname ($c['lua']).'
  • '.NL; @@ -738,15 +994,28 @@ foreach ($constlist as $ns => $cs) { echo '
'.NL; } -echo '

Class Index

'.NL; +###################### +# Index of all classes + +echo '

Class Index

'.NL; echo '
    '.NL; foreach ($classlist as $ns => $cl) { echo '
  • '.typelink($ns).'
  • '.NL; } echo '
'.NL; + +# see how far there is still to go... fwrite (STDERR, "Found $dox_found annotations. missing: $dox_miss\n"); +echo ''.NL; + ?>
- - +
Ardour  - 
+'.NL; + echo ''.NL; + echo ''.NL; +}