X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=tools%2Ffmt-luadoc.php;h=b13e38617caf77f2b7c31a75ca67ba958f20d006;hb=5d17c6aac3c6a48b8c8bcd906372bcd779751fe3;hp=80b59698948f9b5cf6986f96e80acc93635bd5d3;hpb=323ae44c2544f331b3a83ecf3ddbb238eef727f6;p=ardour.git diff --git a/tools/fmt-luadoc.php b/tools/fmt-luadoc.php index 80b5969894..b13e38617c 100755 --- a/tools/fmt-luadoc.php +++ b/tools/fmt-luadoc.php @@ -2,20 +2,51 @@ doc/luadoc.json +# ./gtk2_ardour/arluadoc > doc/luadoc.json.gz # +## generate doc/ardourapi.json.gz (ardour header doxygen doc) +# cd ../../tools/doxy2json +# ./ardourdoc.sh +# cd - +# +## format HTML (using this scripterl) # 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 = file_get_contents (dirname (__FILE__).'/../doc/luadoc.json'); +$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'])); + $b ['ldec'] = preg_replace ('/_VampHost::/', '', $b['ldec']); + $b ['decl'] = preg_replace ('/_VampHost::/', '', $b['decl']); + if (isset ($b['ret'])) { + $b['ret'] = preg_replace ('/ const/', '', preg_replace ('/ const&/', '', $b['ret'])); + $b['ret'] = preg_replace ('/_VampHost::/', '', $b['ret']); + } + if (isset ($b['parent'])) { + $b ['parent'] = preg_replace ('/_VampHost::/', '', $b['parent']); + } $doc[] = $b; } @@ -56,23 +87,28 @@ function my_die ($msg) { # return preg_replace ('/boost::shared_ptr<([^>]*)[ ]*>/', '$1', $ctype); #} -function arg2lua ($argtype) { +function arg2lua ($argtype, $flags = 0) { global $classes; global $consts; # LuaBridge abstracts C++ references - $flags = preg_match ('/&$/', $argtype); + $flags |= preg_match ('/&$/', $argtype); $arg = preg_replace ('/&$/', '', $argtype); + $arg = preg_replace ('/ $/', '', $arg); # filter out basic types - $builtin = array ('float', 'double', 'bool', 'std::string', 'int', 'long', 'unsigned long', 'unsigned int', 'unsigned char', 'char', 'void', 'char*', 'unsigned char*', 'void*'); + $builtin = array ('float', 'double', 'bool', 'std::string', 'int', 'short', 'long', 'unsigned int', 'unsigned short', 'unsigned long', 'unsigned char', 'char', 'void', 'char*', 'unsigned char*', 'void*'); if (in_array ($arg, $builtin)) { return array ($arg => $flags); } + if ($arg == 'luabridge::LuaRef') { + return array ('Lua-Function' => $flags | 4); + } + # check Class declarations first foreach (array_merge ($classes, $consts) as $b) { - if ($b['decl'] == $arg) { + if ($b['ldec'] == $arg) { return array ($b['lua'] => $flags); } } @@ -80,11 +116,15 @@ function arg2lua ($argtype) { # strip class pointers -- TODO Check C'tor for given class $arg = preg_replace ('/[&*]*$/', '', $argtype); foreach (array_merge ($classes, $consts) as $b) { - if ($b['decl'] == $arg) { + if ($b['ldec'] == $arg) { return array ($b['lua'] => $flags); } } - return array ('--MISSING (' . $argtype . ')--' => ($flags | 4)); + if ($flags & 2) { + return array ($argtype => ($flags | 4)); + } else { + return array ('--MISSING (' . $argtype . ')--' => ($flags | 4)); + } } function stripclass ($classname, $name) { @@ -98,13 +138,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'])])) { @@ -126,6 +175,48 @@ function decl2args ($decl) { return $rv; } +function canonical_ctor ($b) { + $rv = ''; + if (preg_match('/[^(]*\(([^)*]*)\*\)(\(.*\))/', $b['decl'], $matches)) { + $lc = luafn2class ($b['lua']); + $cn = str_replace (':', '::', $lc); + $fn = substr ($lc, 1 + strrpos ($lc, ':')); + $rv = $cn . '::'. $fn . $matches[2]; + } + return $rv; +} + +function canonical_decl ($b) { + $rv = ''; + $pfx = ''; + # match clang's declatation format + if (preg_match('/[^(]*\(([^)*]*)\*\)\((.*)\)/', $b['decl'], $matches)) { + if (strpos ($b['type'], 'Free Function') !== false) { + $pfx = str_replace (':', '::', luafn2class ($b['lua'])) . '::'; + } + $fn = substr ($b['lua'], 1 + strrpos ($b['lua'], ':')); + $rv = $matches[1] . $fn . '('; + $arglist = preg_split ('/, */', $matches[2]); + $first = true; + foreach ($arglist as $a) { + if (!$first) { $rv .= ', '; }; $first = false; + if (empty ($a)) { continue; } + $a = preg_replace ('/([^>]) >/', '$1>', $a); + $a = preg_replace ('/^Cairo::/', '', $a); // special case cairo enums + $a = preg_replace ('/([^ ])&/', '$1 &', $a); + $a = preg_replace ('/std::vector<([^>]*)> const/', 'const std::vector<$1>', $a); + $a = str_replace ('std::vector', 'vector', $a); + $a = str_replace ('vector', 'std::vector', $a); + $a = str_replace ('std::string', 'string', $a); + $a = str_replace ('string const', 'const string', $a); + $a = str_replace ('string', 'std::string', $a); + $rv .= $a; + } + $rv .= ')'; + } + return $pfx . $rv; +} + ################################################################################ # step 1: build class indices @@ -134,7 +225,7 @@ foreach ($doc as $b) { $classes[] = $b; $classlist[$b['lua']] = $b; if (strpos ($b['type'], 'Pointer Class') === false) { - $classdecl[$b['decl']] = $b; + $classdecl[$b['ldec']] = $b; } } } @@ -155,11 +246,11 @@ foreach ($doc as $b) { switch ($b['type']) { case "Constant/Enum": case "Constant/Enum Member": - if (strpos ($b['decl'], '::') === false) { + if (strpos ($b['ldec'], '::') === false) { # for extern c enums, use the Lua Namespace - $b['decl'] = str_replace (':', '::', luafn2class ($b['lua'])); + $b['ldec'] = str_replace (':', '::', luafn2class ($b['lua'])); } - $ns = str_replace ('::', ':', $b['decl']); + $ns = str_replace ('::', ':', $b['ldec']); $constlist[$ns][] = $b; # arg2lua lookup $b['lua'] = $ns; @@ -178,30 +269,68 @@ foreach ($doc as $b) { checkclass ($b); $classlist[luafn2class ($b['lua'])]['ctor'][] = array ( 'name' => luafn2class ($b['lua']), - 'args' => decl2args ($b['decl']), + 'args' => decl2args ($b['ldec']), + 'cand' => canonical_ctor ($b), + 'nil' => false + ); + break; + case "Weak/Shared Pointer NIL Constructor": + checkclass ($b); + $classlist[luafn2class ($b['lua'])]['ctor'][] = array ( + 'name' => luafn2class ($b['lua']), + 'args' => decl2args ($b['ldec']), + 'cand' => canonical_ctor ($b), + 'nil' => true + ); + break; + case "Property": + checkclass ($b); + $classlist[luafn2class ($b['lua'])]['props'][] = array ( + 'name' => $b['lua'], + 'ret' => arg2lua (datatype ($b['ldec'])) ); break; case "Data Member": checkclass ($b); $classlist[luafn2class ($b['lua'])]['data'][] = array ( 'name' => $b['lua'], - 'ret' => arg2lua (datatype ($b['decl'])) + '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": checkclass ($b); - $args = array (array ('--custom--' => 0)); + $args = array (array ('--lua--' => 0)); $ret = array ('...' => 0); $ns = luafn2class ($b['lua']); $cls = $classlist[$ns]; - ## std::Vector std::List types - if (preg_match ('/.*<([^>]*)[ ]*>/', $cls['decl'], $templ)) { - // XXX -> move to C-source + if (preg_match ('/.*<([^>]*)[ ]*>/', $cls['ldec'], $templ)) { + # std::vector, std::list types switch (stripclass($ns, $b['lua'])) { case 'add': - $args = array (array ('LuaTable {'.$templ[1].'}' => 0)); + #$args = array (array ('LuaTable {'.$templ[1].'}' => 0)); + $args = array (arg2lua ($templ[1], 2)); $ret = array ('LuaTable' => 0); break; case 'iter': @@ -216,7 +345,8 @@ foreach ($doc as $b) { break; } } else if (strpos ($cls['type'], ' Array') !== false) { - $templ = preg_replace ('/[&*]*$/', '', $cls['decl']); + # catches C:FloatArray, C:IntArray + $templ = preg_replace ('/[&*]*$/', '', $cls['ldec']); switch (stripclass($ns, $b['lua'])) { case 'array': $args = array (); @@ -240,7 +370,19 @@ foreach ($doc as $b) { 'args' => $args, 'ret' => $ret, 'ref' => true, - 'ext' => true + 'ext' => true, + '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": @@ -248,9 +390,10 @@ foreach ($doc as $b) { $funclist[luafn2class ($b['lua'])][] = array ( 'bind' => $b, 'name' => $b['lua'], - 'args' => decl2args ($b['decl']), + 'args' => decl2args ($b['ldec']), 'ret' => arg2lua ($b['ret']), - 'ref' => (strpos ($b['type'], "RefReturn") !== false) + 'ref' => (strpos ($b['type'], "RefReturn") !== false), + 'cand' => canonical_decl ($b) ); break; case "Member Function": @@ -259,15 +402,27 @@ 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 ( 'bind' => $b, 'name' => $b['lua'], - 'args' => decl2args ($b['decl']), + 'args' => decl2args ($b['ldec']), + 'ret' => arg2lua ($b['ret']), + 'ref' => (strpos ($b['type'], "RefReturn") !== false), + '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) + 'ref' => (strpos ($b['type'], "RefReturn") !== false), + 'cand' => canonical_decl ($b) ); break; case "Constant/Enum": @@ -289,14 +444,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']; } } } @@ -331,11 +489,45 @@ 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 + -# TODO: read function documentation from doxygen -# and/or reference source-code lines e.g from CSV list: -# ctags -o /tmp/tags.csv --fields=+afiKkmnsSzt libs/ardour/ardour/session.h +# read documentation from doxygen +$json = gzdecode (file_get_contents (dirname (__FILE__).'/../doc/ardourapi.json.gz')); +$api = array (); +foreach (json_decode ($json, true) as $a) { + if (!isset ($a['decl'])) { continue; } + if (empty ($a['decl'])) { continue; } + $canon = str_replace (' *', '*', $a['decl']); + $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; + global $dox_miss; + if (isset ($api[$canonical_declaration])) { + $dox_found++; + return $api[$canonical_declaration]['doc']; + } + // 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[$cn]['doc']; + } + #fwrite (STDERR, $canonical_declaration."\n"); # XXX DEBUG + + $dox_miss++; + return ''; +} ################################################################################ # OUTPUT @@ -346,22 +538,22 @@ ksort ($classlist); # 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 = ''; @@ -370,6 +562,7 @@ function traverse_parent ($ns, &$inherited) { asort ($parents); foreach ($parents as $p) { if (!empty ($rv)) { $rv .= ', '; } + if ($p == $ns) { continue; } $rv .= typelink ($p); $inherited[$p] = $classlist[$p]; traverse_parent ($p, $inherited); @@ -378,11 +571,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))) { @@ -394,15 +587,23 @@ function typelink ($a, $short = false, $argcls = '', $linkcls = '', $suffix = '' } } +# output format function arguments function format_args ($args) { $rv = ' ('; $first = true; foreach ($args as $a) { if (!$first) { $rv .= ', '; }; $first = false; $flags = $a[varname ($a)]; - if ($flags & 1) { + if ($flags & 4) { + $rv .= ''.varname ($a).''; + } + else if ($flags & 2) { + $rv .= 'LuaTable {'.typelink (varname ($a), true, 'em').'}'; + } + elseif ($flags & 1) { $rv .= typelink (varname ($a), true, 'em', '', '&'); - } else { + } + else { $rv .= typelink (varname ($a), true, 'em'); } } @@ -410,18 +611,65 @@ function format_args ($args) { return $rv; } +# format doxygen documentation for class-definition +function format_doxyclass ($cl) { + $rv = ''; + if (isset ($cl['decl'])) { + $doc = doxydoc ($cl['decl']); + if (!empty ($doc)) { + $rv.= '
'.$doc.'
'.NL; + } + } + return $rv; +} + +# format doxygen documentation for class-members +function format_doxydoc ($f) { + $rv = ''; + if (isset ($f['cand'])) { + $doc = doxydoc ($f['cand']); + if (!empty ($doc)) { + $rv.= '
'.$doc; + $rv.= '
'.NL; + } else if (0) { # debug + $rv.= '

'.htmlentities($f['cand']).'

'; + $rv.= ''.NL; + } + } + 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; foreach ($cl['ctor'] as $f) { - $rv.= ' ℂ'; + $rv.= ' '; + if ($f['nil']) { + $rv.= ''; + } else { + $rv.= 'ℂ'; + } + $rv.= ''; $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) { @@ -429,29 +677,66 @@ 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']) { - $rv.= 'LuaTable('.typelink (varname ($f['ret'], false, 'em')).', ...)'; + # 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 properties - if any + if (isset ($cl['props'])) { + usort ($cl['props'], 'name_sort_cb'); + $rv.= ' Properties'.NL; + foreach ($cl['props'] as $f) { + $rv.= ' '.typelink (array_keys ($f['ret'])[0], false, 'em').''; + $rv.= ''.stripclass ($ns, $f['name']).''; + $rv.= ''.NL; + } + } + + # print data members - if any if (isset ($cl['data'])) { usort ($cl['data'], 'name_sort_cb'); $rv.= ' Data Members'.NL; @@ -459,6 +744,8 @@ function format_class_members ($ns, $cl, &$dups) { $rv.= ' '.typelink (array_keys ($f['ret'])[0], false, 'em').''; $rv.= ''.stripclass ($ns, $f['name']).''; $rv.= ''.NL; + $f['cand'] = str_replace (':', '::', $f['name']); + $rv.= format_doxydoc($f); } } return $rv; @@ -468,40 +755,63 @@ function format_class_members ($ns, $cl, &$dups) { ################################################################################ # Start Output +if ($HTMLOUTPUT) { + ?> Ardour Lua Bindings
-

Ardour Lua Bindings

+

Ardour Lua Bindings

Class Documentation  |  @@ -510,9 +820,33 @@ div.header p {margin:.25em;} Index

-
-

Overview

+ + + + +

+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(). @@ -525,7 +859,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). @@ -534,61 +868,160 @@ 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; } - # print class inheritance + # show original C++ declaration + if (isset ($cl['cdecl'])) { + echo '

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

'.NL; + } + + # print class inheritance (direct parent *name* only) $inherited = array (); $isa = traverse_parent ($ns, $inherited); if (!empty ($isa)) { - echo '

is-a: '.$isa.'

'.NL; + echo '

is-a: '.$isa.'

'.NL; } echo '
'.NL; + + # class documentation (if any) + echo format_doxyclass ($cl); + # member documentation if (empty ($tbl)) { - echo '

This class object is only used indirectly as return-value and function-parameter.

'.NL; + echo '

This class object is only used indirectly as return-value and function-parameter. It provides no methods by itself.

'.NL; } else { echo ''.NL; echo $tbl; 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; @@ -596,9 +1029,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; @@ -606,14 +1042,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; +}