add debug mode to clang doxygen parser tool (print compile errors)
[ardour.git] / tools / fmt-luadoc.php
1 #!/usr/bin/php
2 <?php
3 ## USAGE
4 #
5 ## generate doc/luadoc.json.gz (lua binding doc)
6 # ./waf configure --luadoc ....
7 # ./waf
8 # ./gtk2_ardour/arluadoc > doc/luadoc.json.gz
9 #
10 ## generate doc/ardourapi.json.gz (ardour header doxygen doc)
11 # cd ../../tools/doxy2json
12 # ./ardourdoc.sh
13 # cd -
14 #
15 ## format HTML (using this scripterl)
16 # php tools/fmt-luadoc.php > /tmp/luadoc.html
17 #
18
19 ################################################################################
20 ################################################################################
21
22 $json = gzdecode (file_get_contents (dirname (__FILE__).'/../doc/luadoc.json.gz'));
23 $doc = array ();
24 $ardourversion = '';
25 foreach (json_decode ($json, true) as $b) {
26         if (!isset ($b['type'])) {
27                 if (isset ($b['version'])) { $ardourversion = $b['version']; }
28                 continue;
29         }
30         $b ['ldec'] = preg_replace ('/ const/', '', preg_replace ('/ const&/', '', $b['decl']));
31         if (isset ($b['ret'])) {
32                 $b['ret'] = preg_replace ('/ const/', '', preg_replace ('/ const&/', '', $b['ret']));
33         }
34         $doc[] = $b;
35 }
36
37 if (count ($doc) == 0) {
38         fwrite (STDERR, "Failed to read luadoc.json\n");
39         exit (1);
40 }
41
42 ################################################################################
43 ## Global result variables
44 ################################################################################
45
46 $classlist = array ();
47 $constlist = array ();
48
49
50 ################################################################################
51 ## Pre-process the data, collect functions, parse arguments, cross reference
52 ################################################################################
53
54
55 ################################################################################
56 # some internal helper functions first
57
58 $funclist = array ();
59 $classes = array ();
60 $consts = array ();
61
62 function my_die ($msg) {
63         fwrite (STDERR, $msg."\n");
64         exit (1);
65 }
66
67 ##function ptr_strip ($ctype) {
68 #       # boost::shared_ptr<std::list<boost::shared_ptr<ARDOUR::Route>> > >
69 #       # -> std::list<ARDOUR::Route>
70 #       $ctype = preg_replace ('/boost::shared_ptr<([^>]*)[ ]*>/', '$1', $ctype);
71 #       return preg_replace ('/boost::shared_ptr<([^>]*)[ ]*>/', '$1', $ctype);
72 #}
73
74 function arg2lua ($argtype, $flags = 0) {
75         global $classes;
76         global $consts;
77
78         # LuaBridge abstracts C++ references
79         $flags |= preg_match ('/&$/', $argtype);
80         $arg = preg_replace ('/&$/', '', $argtype);
81         $arg = preg_replace ('/ $/', '', $arg);
82
83         # filter out basic types
84         $builtin = array ('float', 'double', 'bool', 'std::string', 'int', 'long', 'unsigned long', 'unsigned int', 'unsigned char', 'char', 'void', 'char*', 'unsigned char*', 'void*');
85         if (in_array ($arg, $builtin)) {
86                 return array ($arg => $flags);
87         }
88
89         # check Class declarations first
90         foreach (array_merge ($classes, $consts) as $b) {
91                 if ($b['ldec'] == $arg) {
92                         return array ($b['lua'] => $flags);
93                 }
94         }
95
96         # strip class pointers -- TODO Check C'tor for given class
97         $arg = preg_replace ('/[&*]*$/', '', $argtype);
98         foreach (array_merge ($classes, $consts) as $b) {
99                 if ($b['ldec'] == $arg) {
100                         return array ($b['lua'] => $flags);
101                 }
102         }
103         if ($flags & 2) {
104                 return array ($argtype => ($flags | 4));
105         } else {
106                 return array ('--MISSING (' . $argtype . ')--' => ($flags | 4));
107         }
108 }
109
110 function stripclass ($classname, $name) {
111         $classname .= ':';
112         if (strpos ($name, $classname) !== 0) {
113                 my_die ('invalid class prefix: ' .$classname. ' -- '. $name);
114         }
115         return substr ($name, strlen ($classname));
116 }
117
118 function datatype ($decl) {
119         # TODO handle spaces in type. Works because
120         # we don't yet have templated types (with_space <here >)
121         return substr ($decl, 0, strpos ($decl, ' '));
122 }
123
124 function luafn2class ($lua) {
125         return substr ($lua, 0, strrpos ($lua, ':'));
126 }
127
128 function checkclass ($b) {
129         global $classlist;
130         if (!isset ($classlist[luafn2class ($b['lua'])])) {
131                 my_die ('MISSING CLASS FOR '. print_r ($b['lua'], true));
132         }
133 }
134
135 # parse functions argument list to lua-names
136 function decl2args ($decl) {
137         $start = strrpos ($decl, '(');
138         $end = strrpos ($decl, ')');
139         $args = substr ($decl, $start + 1, $end - $start - 1);
140         $arglist = preg_split ('/, */', $args);
141         $rv = array ();
142         foreach ($arglist as $a) {
143                 if (empty ($a)) { continue; }
144                 $rv[] = arg2lua ($a);
145         }
146         return $rv;
147 }
148
149 function canonical_ctor ($b) {
150         $rv = '';
151         if (preg_match('/[^(]*\(([^)*]*)\*\)(\(.*\))/', $b['decl'], $matches)) {
152                 $lc = luafn2class ($b['lua']);
153                 $cn = str_replace (':', '::', $lc);
154                 $fn = substr ($lc, 1 + strrpos ($lc, ':'));
155                 $rv = $cn . '::'. $fn . $matches[2];
156         }
157         return $rv;
158 }
159
160 function canonical_decl ($b) {
161         $rv = '';
162         $pfx = '';
163         # match clang's declatation format
164         if (preg_match('/[^(]*\(([^)*]*)\*\)\((.*)\)/', $b['decl'], $matches)) {
165                 if (strpos ($b['type'], 'Free Function') !== false) {
166                         $pfx = str_replace (':', '::', luafn2class ($b['lua'])) . '::';
167                 }
168                 $fn = substr ($b['lua'], 1 + strrpos ($b['lua'], ':'));
169                 $rv = $matches[1] . $fn . '(';
170                 $arglist = preg_split ('/, */', $matches[2]);
171                 $first = true;
172                 foreach ($arglist as $a) {
173                         if (!$first) { $rv .= ', '; }; $first = false;
174                         if (empty ($a)) { continue; }
175                         $a = preg_replace ('/([^>]) >/', '$1>', $a);
176                         $a = preg_replace ('/^Cairo::/', '', $a); // special case cairo enums
177                         $a = preg_replace ('/([^ ])&/', '$1 &', $a);
178                         $a = str_replace ('vector', 'std::vector', $a);
179                         $a = str_replace ('std::string', 'string', $a);
180                         $a = str_replace ('string const', 'const string', $a);
181                         $a = str_replace ('string', 'std::string', $a);
182                         $rv .= $a;
183                 }
184                 $rv .= ')';
185         }
186         return $pfx . $rv;
187 }
188
189 ################################################################################
190 # step 1: build class indices
191
192 foreach ($doc as $b) {
193         if (strpos ($b['type'], "[C] ") === 0) {
194                 $classes[] = $b;
195                 $classlist[$b['lua']] = $b;
196                 if (strpos ($b['type'], 'Pointer Class') === false) {
197                         $classdecl[$b['ldec']] = $b;
198                 }
199         }
200 }
201
202 foreach ($classes as $c) {
203         if (strpos ($c['type'], 'Pointer Class') !== false) { continue; }
204         if (isset ($c['parent'])) {
205                 if (isset ($classdecl[$c['parent']])) {
206                         $classlist[$c['lua']]['luaparent'][] = $classdecl[$c['parent']]['lua'];
207                 } else {
208                         my_die ('unknown parent class: ' . print_r ($c, true));
209                 }
210         }
211 }
212
213 # step 2: extract constants/enum
214 foreach ($doc as $b) {
215         switch ($b['type']) {
216         case "Constant/Enum":
217         case "Constant/Enum Member":
218                 if (strpos ($b['ldec'], '::') === false) {
219                         # for extern c enums, use the Lua Namespace
220                         $b['ldec'] = str_replace (':', '::', luafn2class ($b['lua']));
221                 }
222                 $ns = str_replace ('::', ':', $b['ldec']);
223                 $constlist[$ns][] = $b;
224                 # arg2lua lookup
225                 $b['lua'] = $ns;
226                 $consts[] = $b;
227                 break;
228         default:
229                 break;
230         }
231 }
232
233 # step 3: process functions
234 foreach ($doc as $b) {
235         switch ($b['type']) {
236         case "Constructor":
237         case "Weak/Shared Pointer Constructor":
238                 checkclass ($b);
239                 $classlist[luafn2class ($b['lua'])]['ctor'][] = array (
240                         'name' => luafn2class ($b['lua']),
241                         'args' => decl2args ($b['ldec']),
242                         'cand' => canonical_ctor ($b)
243                 );
244                 break;
245         case "Data Member":
246                 checkclass ($b);
247                 $classlist[luafn2class ($b['lua'])]['data'][] = array (
248                         'name' => $b['lua'],
249                         'ret'  => arg2lua (datatype ($b['ldec']))
250                 );
251                 break;
252         case "C Function":
253                 # we required C functions to be in a class namespace
254         case "Ext C Function":
255                 checkclass ($b);
256                 $args = array (array ('--lua--' => 0));
257                 $ret = array ('...' => 0);
258                 $ns = luafn2class ($b['lua']);
259                 $cls = $classlist[$ns];
260                 ## std::Vector std::List types
261                 if (preg_match ('/.*<([^>]*)[ ]*>/', $cls['ldec'], $templ)) {
262                         // XXX -> move to C-source
263                         switch (stripclass($ns, $b['lua'])) {
264                         case 'add':
265                                 #$args = array (array ('LuaTable {'.$templ[1].'}' => 0));
266                                 $args = array (arg2lua ($templ[1], 2));
267                                 $ret = array ('LuaTable' => 0);
268                                 break;
269                         case 'iter':
270                                 $args = array ();
271                                 $ret = array ('LuaIter' => 0);
272                                 break;
273                         case 'table':
274                                 $args = array ();
275                                 $ret = array ('LuaTable' => 0);
276                                 break;
277                         default:
278                                 break;
279                         }
280                 } else if (strpos ($cls['type'], ' Array') !== false) {
281                         $templ = preg_replace ('/[&*]*$/', '', $cls['ldec']);
282                         switch (stripclass($ns, $b['lua'])) {
283                         case 'array':
284                                 $args = array ();
285                                 $ret = array ('LuaMetaTable' => 0);
286                                 break;
287                         case 'get_table':
288                                 $args = array ();
289                                 $ret = array ('LuaTable' => 0);
290                                 break;
291                         case 'set_table':
292                                 $args = array (array ('LuaTable {'.$templ.'}' => 0));
293                                 $ret = array ('void' => 0);
294                                 break;
295                         default:
296                                 break;
297                         }
298                 }
299                 $classlist[luafn2class ($b['lua'])]['func'][] = array (
300                         'bind' => $b,
301                         'name' => $b['lua'],
302                         'args' => $args,
303                         'ret'  => $ret,
304                         'ref'  => true,
305                         'ext'  => true,
306                         'cand' => canonical_decl ($b)
307                 );
308                 break;
309         case "Free Function":
310         case "Free Function RefReturn":
311                 $funclist[luafn2class ($b['lua'])][] = array (
312                         'bind' => $b,
313                         'name' => $b['lua'],
314                         'args' => decl2args ($b['ldec']),
315                         'ret'  => arg2lua ($b['ret']),
316                         'ref'  => (strpos ($b['type'], "RefReturn") !== false),
317                         'cand' => canonical_decl ($b)
318                 );
319                 break;
320         case "Member Function":
321         case "Member Function RefReturn":
322         case "Member Pointer Function":
323         case "Weak/Shared Pointer Function":
324         case "Weak/Shared Pointer Function RefReturn":
325         case "Weak/Shared Null Check":
326         case "Weak/Shared Pointer Cast":
327         case "Static Member Function":
328                 checkclass ($b);
329                 $classlist[luafn2class ($b['lua'])]['func'][] = array (
330                         'bind' => $b,
331                         'name' => $b['lua'],
332                         'args' => decl2args ($b['ldec']),
333                         'ret'  => arg2lua ($b['ret']),
334                         'ref'  => (strpos ($b['type'], "RefReturn") !== false),
335                         'cand' => canonical_decl ($b)
336                 );
337                 break;
338         case "Constant/Enum":
339         case "Constant/Enum Member":
340                 # already handled -> $consts
341                 break;
342         default:
343                 if (strpos ($b['type'], "[C] ") !== 0) {
344                         my_die ('unhandled type: ' . $b['type']);
345                 }
346                 break;
347         }
348 }
349
350
351 # step 4: collect/group/sort
352
353 # step 4a: unify weak/shared Ptr classes
354 foreach ($classlist as $ns => $cl) {
355         if (strpos ($cl['type'], ' Array') !== false) {
356                 $classlist[$ns]['arr'] = true;
357                 continue;
358         }
359         foreach ($classes as $c) {
360                 if ($c['lua'] == $ns) {
361                         if (strpos ($c['type'], 'Pointer Class') !== false) {
362                                 $classlist[$ns]['ptr'] = true;
363                                 $classlist[$ns]['decl'] = 'boost::shared_ptr< '.$c['decl']. ' >, boost::weak_ptr< '.$c['decl']. ' >';
364                                 break;
365                         }
366                 }
367         }
368 }
369
370 # step4b: sanity check
371 foreach ($classlist as $ns => $cl) {
372         if (isset ($classes[$ns]['parent']) && !isset ($classlist[$ns]['luaparent'])) {
373                 my_die ('missing parent class: ' . print_r ($cl, true));
374         }
375 }
376
377 # step 4c: merge free functions into classlist
378 foreach ($funclist as $ns => $fl) {
379         if (isset ($classlist[$ns])) {
380                 my_die ('Free Funcion in existing namespace: '.$ns.' '. print_r ($ns, true));
381         }
382         $classlist[$ns]['func'] = $fl;
383         $classlist[$ns]['free'] = true;
384 }
385
386 # step 4d: order to chaos
387 # no array_multisort() here, sub-types are sorted after merging parents
388 ksort ($classlist);
389
390
391 ################################################################################
392 ################################################################################
393 ################################################################################
394
395
396 #### -- split here --  ####
397
398 # from here on, only $classlist and $constlist arrays are relevant.
399 # we also pull in C++ header annotation from doxygen to $api
400
401
402 # read documentation from doxygen
403 $json = gzdecode (file_get_contents (dirname (__FILE__).'/../doc/ardourapi.json.gz'));
404 $api = array ();
405 foreach (json_decode ($json, true) as $a) {
406         if (!isset ($a['decl'])) { continue; }
407         if (empty ($a['decl'])) { continue; }
408         $canon = str_replace (' *', '*', $a['decl']);
409         $api[$canon] = $a;
410 }
411
412 # keep track of found/missing doc
413 $dox_found = 0;
414 $dox_miss = 0;
415
416 # retrive a value from $api
417 function doxydoc ($canonical_declaration) {
418         global $api;
419         global $dox_found;
420         global $dox_miss;
421         if (isset ($api[$canonical_declaration])) {
422                 $dox_found++;
423                 return $api[$canonical_declaration]['doc'];
424         } else {
425                 $dox_miss++;
426                 return '';
427         }
428 }
429
430 ################################################################################
431 # OUTPUT
432 ################################################################################
433
434
435 ################################################################################
436 # Helper functions
437 define ('NL', "\n");
438
439 # constructors, enums (constants) use a dot.  (e.g. "LuaOSC.Address" -> "LuaOSC.Address" )
440 function ctorname ($name) {
441         return htmlentities (str_replace (':', '.', $name));
442 }
443
444 # strip class prefix (e.g "Evoral:MidiEvent:channel"  -> "channel")
445 function shortname ($name) {
446         return htmlentities (substr ($name, strrpos ($name, ':') + 1));
447 }
448
449 # retrieve variable name from    array["VARNAME"] => FLAGS
450 function varname ($a) {
451         return array_keys ($a)[0];
452 }
453
454 # recusively collect class parents (derived classes)
455 function traverse_parent ($ns, &$inherited) {
456         global $classlist;
457         $rv = '';
458         if (isset ($classlist[$ns]['luaparent'])) {
459                 $parents = array_unique ($classlist[$ns]['luaparent']);
460                 asort ($parents);
461                 foreach ($parents as $p) {
462                         if (!empty ($rv)) { $rv .= ', '; }
463                         $rv .= typelink ($p);
464                         $inherited[$p] = $classlist[$p];
465                         traverse_parent ($p, $inherited);
466                 }
467         }
468         return $rv;
469 }
470
471 # create a cross-reference to a type (class or enum)
472 # *all* <a> links are generated here, currently anchors on a single page.
473 function typelink ($a, $short = false, $argcls = '', $linkcls = '', $suffix = '') {
474         global $classlist;
475         global $constlist;
476         if (isset($classlist[$a]['free'])) {
477                 return '<a class="'.$linkcls.'" href="#'.htmlentities ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
478         } else if (in_array ($a, array_keys ($classlist))) {
479                 return '<a class="'.$linkcls.'" href="#'.htmlentities($a).'">'.($short ? shortname($a) : htmlentities($a)).$suffix.'</a>';
480         } else if (in_array ($a, array_keys ($constlist))) {
481                 return '<a class="'.$linkcls.'" href="#'.ctorname ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
482         } else {
483                 return '<span class="'.$argcls.'">'.htmlentities($a).$suffix.'</span>';
484         }
485 }
486
487 # output format function arguments
488 function format_args ($args) {
489         $rv = '<span class="functionargs"> (';
490         $first = true;
491         foreach ($args as $a) {
492                 if (!$first) { $rv .= ', '; }; $first = false;
493                 $flags = $a[varname ($a)];
494                 if ($flags & 2) {
495                         $rv .= '<em>LuaTable</em> {'.typelink (varname ($a), true, 'em').'}';
496                 }
497                 elseif ($flags & 1) {
498                         $rv .= typelink (varname ($a), true, 'em', '', '&amp;');
499                 }
500                 else {
501                         $rv .= typelink (varname ($a), true, 'em');
502                 }
503         }
504         $rv .= ')</span>';
505         return $rv;
506 }
507
508 # format doxygen documentation for class-definition
509 function format_doxyclass ($cl) {
510         $rv = '';
511         if (isset ($cl['decl'])) {
512                 $doc = doxydoc ($cl['decl']);
513                 if (!empty ($doc)) {
514                         $rv.= '<div class="classdox">'.$doc.'</div>'.NL;
515                 }
516         }
517         return $rv;
518 }
519
520 # format doxygen documentation for class-members
521 function format_doxydoc ($f) {
522         $rv = '';
523         if (isset ($f['cand'])) {
524                 $doc = doxydoc ($f['cand']);
525                 if (!empty ($doc)) {
526                         $rv.= '<tr><td></td><td class="doc" colspan="2"><div class="dox">'.$doc;
527                         $rv.= '</div></td></tr>'.NL;
528                 } else if (0) { # debug
529                         $rv.= '<tr><td></td><td class="doc" colspan="2"><p>'.htmlentities($f['cand']).'</p>';
530                         $rv.= '</td></tr>'.NL;
531                 }
532         }
533         return $rv;
534 }
535
536 # usort() callback for class-members
537 function name_sort_cb ($a, $b) {
538         return strcmp ($a['name'], $b['name']);
539 }
540
541 # main output function for every class
542 function format_class_members ($ns, $cl, &$dups) {
543         $rv = '';
544         # print contructor - if any
545         if (isset ($cl['ctor'])) {
546                 usort ($cl['ctor'], 'name_sort_cb');
547                 $rv.= ' <tr><th colspan="3">Constructor</th></tr>'.NL;
548                 foreach ($cl['ctor'] as $f) {
549                         $rv.= ' <tr><td class="def">&Copf;</td><td class="decl">';
550                         $rv.= '<span class="functionname">'.ctorname ($f['name']).'</span>';
551                         $rv.= format_args ($f['args']);
552                         $rv.= '</td><td class="fill"></td></tr>'.NL;
553                         # doxygen documentation (may be empty)
554                         $rv.= format_doxydoc($f);
555                 }
556         }
557
558         # strip duplicates (inherited or derived methods)
559         # e.g  AudioTrack -> Track -> Route -> SessionObject -> Stateful
560         # all 5 have "isnil()"
561         $nondups = array ();
562         if (isset ($cl['func'])) {
563                 foreach ($cl['func'] as $f) {
564                         if (in_array (stripclass ($ns, $f['name']), $dups)) { continue; }
565                         $nondups[] = $f;
566                 }
567         }
568
569         # print methods - if any
570         if (count ($nondups) > 0) {
571                 usort ($nondups, 'name_sort_cb');
572                 $rv.= ' <tr><th colspan="3">Methods</th></tr>'.NL;
573                 foreach ($nondups as $f) {
574                         $dups[] = stripclass ($ns, $f['name']);
575                         # return value/type
576                         $rv.= ' <tr><td class="def">';
577                         if ($f['ref'] && isset ($f['ext'])) {
578                                 # external C functions
579                                 $rv.= '<em>'.varname ($f['ret']).'</em>';
580                         } elseif ($f['ref'] && varname ($f['ret']) == 'void') {
581                                 # void functions with reference args
582                                 $rv.= '<em>LuaTable</em>(...)';
583                         } elseif ($f['ref']) {
584                                 # functions with reference args and return value
585                                 $rv.= '<em>LuaTable</em>('.typelink (varname ($f['ret']), true, 'em').', ...)';
586                         } else {
587                                 # normal class members
588                                 $rv.= typelink (varname ($f['ret']), true, 'em');
589                         }
590                         # function declaration and arguments
591                         $rv.= '</td><td class="decl">';
592                         $rv.= '<span class="functionname"><abbr title="'.htmlentities($f['bind']['decl']).'">'.stripclass ($ns, $f['name']).'</abbr></span>';
593                         $rv.= format_args ($f['args']);
594                         $rv.= '</td><td class="fill"></td></tr>'.NL;
595                         # doxygen documentation (may be empty)
596                         $rv.= format_doxydoc($f);
597                 }
598         }
599         # print data members - if any
600         if (isset ($cl['data'])) {
601                 usort ($cl['data'], 'name_sort_cb');
602                 $rv.= ' <tr><th colspan="3">Data Members</th></tr>'.NL;
603                 foreach ($cl['data'] as $f) {
604                         $rv.= ' <tr><td class="def">'.typelink (array_keys ($f['ret'])[0], false, 'em').'</td><td class="decl">';
605                         $rv.= '<span class="functionname">'.stripclass ($ns, $f['name']).'</span>';
606                         $rv.= '</td><td class="fill"></td></tr>'.NL;
607                 }
608         }
609         return $rv;
610 }
611
612
613 ################################################################################
614 # Start Output
615
616 ?><!DOCTYPE html>
617 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
618 <head>
619 <title>Ardour Lua Bindings</title>
620 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
621 <style type="text/css">
622 div.header         { text-align:center; }
623 div.header h2      { margin:0; }
624 div.header p       { margin:.25em; text-align:center; }
625 div.luafooter      { text-align:center; font-size:80%; color: #888; margin: 2em 0; }
626 #luaref            { max-width:60em; margin: 1em auto; }
627
628 #luaref h2                 { margin:2em 0 0 0; padding:0em; border-bottom: 1px solid black; }
629 #luaref h3.cls             { margin:2em 0 0 0; padding: 0 0 0 1em; border: 1px dashed #6666ee; }
630 #luaref h3.cls abbr        { text-decoration:none; cursor:default; }
631 #luaref h4.cls             { margin:1em 0 0 0; }
632 #luaref h3.class           { background-color: #aaee66; }
633 #luaref h3.enum            { background-color: #aaaaaa; }
634 #luaref h3.pointerclass    { background-color: #eeaa66; }
635 #luaref h3.array           { background-color: #66aaee; }
636 #luaref h3.opaque          { background-color: #6666aa; }
637 #luaref p                  { text-align: justify; }
638 #luaref p.cdecl            { text-align: right; float:right; font-size:90%; margin:0; padding: 0 0 0 1em; }
639 #luaref ul.classindex      { columns: 2; -webkit-columns: 2; -moz-columns: 2; }
640 #luaref div.clear          { clear:both; }
641 #luaref p.classinfo        { margin: .25em 0; }
642 #luaref div.code           { width:80%; margin:.5em auto; }
643 #luaref div.code div       { width:45%; }
644 #luaref div.code pre       { line-height: 1.2em; margin: .25em 0; }
645 #luaref div.code samp      { color: green; font-weight: bold; background-color: #eee; }
646 #luaref div.classdox       { padding: .1em 1em; }
647 #luaref div.classdox p     { margin: .5em 0 .5em .6em; }
648 #luaref div.classdox p     { margin: .5em 0 .5em .6em; }
649 #luaref div.classdox       { padding: .1em 1em; }
650 #luaref div.classdox p     { margin: .5em 0 .5em .6em; }
651 #luaref table.classmembers { width: 100%; }
652 #luaref table.classmembers th      { text-align:left; border-bottom:1px solid black; padding-top:1em; }
653 #luaref table.classmembers td.def  { text-align:right; padding-right:.5em;  white-space: nowrap; }
654 #luaref table.classmembers td.decl { text-align:left; padding-left:.5em; white-space: nowrap; }
655 #luaref table.classmembers td.doc  { text-align:left; padding-left:.6em; line-height: 1.2em; font-size:80%; }
656 #luaref table.classmembers td.doc div.dox {background-color:#eee; padding: .1em 1em; }
657 #luaref table.classmembers td.doc p { margin: .5em 0; }
658 #luaref table.classmembers td.doc p.para-brief { font-size:120%; }
659 #luaref table.classmembers td.doc p.para-returns { font-size:120%; }
660 #luaref table.classmembers td.doc dl { font-size:120%; line-height: 1.3em; }
661 #luaref table.classmembers td.doc dt { font-style: italic; }
662 #luaref table.classmembers td.fill { width: 99%; }
663 #luaref table.classmembers span.em { font-style: italic; }
664 #luaref span.functionname abbr     { text-decoration:none; cursor:default; }
665 </style>
666 </head>
667 <body>
668 <div class="header">
669 <h2>Ardour Lua Bindings</h2>
670 <p>
671 <a href="#h_classes">Class Documentation</a>
672 &nbsp;|&nbsp;
673 <a href="#h_enum">Enum/Constants</a>
674 &nbsp;|&nbsp;
675 <a href="#h_index">Index</a>
676 </p>
677 </div>
678
679 <!-- #### SNIP  #### !-->
680
681 <div id="luaref">
682
683 <?php
684
685 ################################################################################
686 # some general documentation -- should really go elsehere
687
688 ?>
689
690 <h2 id="h_intro">Overview</h2>
691 <p>
692 The top-level entry point are <?=typelink('ARDOUR:Session')?> and <?=typelink('ArdourUI:Editor')?>.
693 Most other Classes are used indirectly starting with a Session function. e.g. Session:get_routes().
694 </p>
695 <p>
696 A few classes are dedicated to certain script types, e.g. Lua DSP processors have exclusive access to
697 <?=typelink('ARDOUR:DSP')?> and <?=typelink('ARDOUR:ChanMapping')?>. Action Hooks Scripts to
698 <?=typelink('LuaSignal:Set')?> etc.
699 </p>
700 <p>
701 Detailed documentation (parameter names, method description) is not yet available. Please stay tuned.
702 </p>
703 <h3>Short introduction to Ardour classes</h3>
704 <p>
705 Ardour's structure is object oriented. The main object is the Session. A Session contains Audio Tracks, Midi Tracks and Busses.
706 Audio and Midi tracks are derived from a more general "Track" Object,  which in turn is derived from a "Route" (aka Bus).
707 (We say "An Audio Track <em>is-a</em> Track <em>is-a</em> Route").
708 Tracks contain specifics. For Example a track <em>has-a</em> diskstream (for file i/o).
709 </p>
710 <p>
711 Operations are performed on objects. One gets a reference to an object and then calls a method.
712 e.g <code>obj = Session:route_by_name("Audio")   obj:set_name("Guitar")</code>.
713 </p>
714 <p>
715 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:
716 you cannot simply remove a track that is currently processing audio. There are various <em>factory</em> methods for object creation or removal.
717 </p>
718 <h3>Pass by Reference</h3>
719 <p>
720 Since lua functions are closures, C++ methods that pass arguments by reference cannot be used as-is.
721 All parameters passed to a C++ method which uses references are returned as Lua Table.
722 If the C++ method also returns a value it is prefixed. Two parameters are returned: the value and a Lua Table holding the parameters.
723 </p>
724
725 <div class="code">
726         <div style="float:left;">C++
727
728 <pre><code class="cxx">void set_ref (int&amp; var, long&amp; val)
729 {
730         printf ("%d %ld\n", var, val);
731         var = 5;
732         val = 7;
733 }
734 </code></pre>
735
736         </div>
737         <div style="float:right;">Lua
738
739 <pre><code class="lua">local var = 0;
740 ref = set_ref (var, 2);
741 -- output from C++ printf()
742 </code><samp class="lua">0 2</samp><code>
743 -- var is still 0 here
744 print (ref[1], ref[2])
745 </code><samp class="lua">5 7</samp></pre>
746
747         </div>
748 </div>
749 <div class="clear"></div>
750 <div class="code">
751         <div style="float:left;">
752
753 <pre><code class="cxx">int set_ref2 (int &amp;var, std::string unused)
754 {
755         var = 5;
756         return 3;
757 }
758 </code></pre>
759
760         </div>
761         <div style="float:right;">
762 <pre><code class="lua">rv, ref = set_ref2 (0, "hello");
763 print (rv, ref[1], ref[2])
764 </code><samp class="lua">3 5 hello</samp></pre>
765         </div>
766 </div>
767 <div class="clear"></div>
768
769 <h3>Pointer Classes</h3>
770 <p>
771 Libardour makes extensive use of reference counted <code>boost::shared_ptr</code> to manage lifetimes.
772 The Lua bindings provide a complete abstration of this. There are no pointers in lua.
773 For example a <?=typelink('ARDOUR:Route')?> is a pointer in C++, but lua functions operate on it like it was a class instance.
774 </p>
775 <p>
776 <code>shared_ptr</code> are reference counted. Once assigned to a lua variable, the C++ object will be kept and remains valid.
777 It is good practice to assign references to lua <code>local</code> variables or reset the variable to <code>nil</code> to drop the ref.
778 </p>
779 <p>
780 All pointer classes have a <code>isnil ()</code> method. This is for two cases:
781 Construction may fail. e.g. <code><?=typelink('ARDOUR:LuaAPI')?>.newplugin()</code>
782 may not be able to find the given plugin and hence cannot create an object.
783 </p>
784 <p>
785 The second case if for <code>boost::weak_ptr</code>. As opposed to <code>boost::shared_ptr</code> weak-pointers are not reference counted.
786 The object may vanish at any time.
787 If lua code calls a method on a nil object, the interpreter will raise an exception and the script will not continue.
788 This is not unlike <code>a = nil a:test()</code> which results in en error "<em>attempt to index a nil value</em>".
789 </p>
790 <p>
791 From the lua side of things there is no distinction between weak and shared pointers. They behave identically.
792 Below they're inidicated in orange and have an arrow to indicate the pointer type.
793 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.
794 </p>
795
796
797 <?php
798
799 #################################
800 # Main output function -- Classes
801
802 echo '<h2 id="h_classes">Class Documentation</h2>'.NL;
803 foreach ($classlist as $ns => $cl) {
804         $dups = array ();
805         $tbl =  format_class_members ($ns, $cl, $dups);
806
807         # format class title - depending on type
808         if (empty ($tbl)) {
809                 # classes with no members (no ctor, no methods, no data)
810                 echo '<h3 id="'.htmlentities ($ns).'" class="cls opaque"><abbr title="Opaque Object">&empty;</abbr>&nbsp;'.htmlentities ($ns).'</h3>'.NL;
811         }
812         else if (isset ($classlist[$ns]['free'])) {
813                 # free functions (no class)
814                 echo '<h3 id="'.htmlentities ($ns).'" class="cls freeclass"><abbr title="Namespace">&Nopf;</abbr>&nbsp;'.ctorname($ns).'</h3>'.NL;
815         }
816         else if (isset ($classlist[$ns]['arr'])) {
817                 # C Arrays
818                 echo '<h3 id="'.htmlentities ($ns).'" class="cls array"><abbr title="C Array">&ctdot;</abbr>&nbsp;'.htmlentities ($ns).'</h3>'.NL;
819         }
820         else if (isset ($classlist[$ns]['ptr'])) {
821                 # Pointer Classes
822                 echo '<h3 id="'.htmlentities ($ns).'" class="cls pointerclass"><abbr title="Pointer Class">&Rarr;</abbr>&nbsp;'. htmlentities ($ns).'</h3>'.NL;
823         }
824         else {
825                 # Normal Class
826                 echo '<h3 id="'.htmlentities ($ns).'" class="cls class"><abbr title="Class">&comp;</abbr>&nbsp;'.htmlentities ($ns).'</h3>'.NL;
827         }
828
829         # show original C++ declaration
830         if (isset ($cl['decl'])) {
831                 echo '<p class="cdecl"><em>C&#8225;</em>: '.htmlentities ($cl['decl']).'</p>'.NL;
832         }
833
834         # print class inheritance (direct parent *name* only)
835         $inherited = array ();
836         $isa = traverse_parent ($ns, $inherited);
837         if (!empty ($isa)) {
838                 echo ' <p class="classinfo">is-a: '.$isa.'</p>'.NL;
839         }
840         echo '<div class="clear"></div>'.NL;
841
842
843         # class documentation (if any)
844         echo format_doxyclass ($cl);
845
846         # member documentation
847         if (empty ($tbl)) {
848                 echo '<p class="classinfo">This class object is only used indirectly as return-value and function-parameter. It provides no methods by itself.</p>'.NL;
849         } else {
850                 echo '<table class="classmembers">'.NL;
851                 echo $tbl;
852                 echo ' </table>'.NL;
853         }
854
855         # traverse parent classes (all inherited members)
856         foreach ($inherited as $pns => $pcl) {
857                 $tbl = format_class_members ($pns, $pcl, $dups);
858                 if (!empty ($tbl)) {
859                         echo '<h4 class="cls">Inherited from '.$pns.'</h4>'.NL;
860                         echo '<table class="classmembers">'.NL;
861                         echo $tbl;
862                         echo '</table>'.NL;
863                 }
864         }
865 }
866
867 ####################
868 # Enum and Constants
869
870 echo '<h2 id="h_enum">Enum/Constants</h2>'.NL;
871 foreach ($constlist as $ns => $cs) {
872         echo '<h3 id="'.ctorname ($ns).'" class="cls enum"><abbr title="Enum">&isin;</abbr>&nbsp;'.ctorname ($ns).'</h3>'.NL;
873         echo '<ul class="enum">'.NL;
874         foreach ($cs as $c) {
875                 echo '<li class="const">'.ctorname ($c['lua']).'</li>'.NL;
876         }
877         echo '</ul>'.NL;
878 }
879
880 ######################
881 # Index of all classes
882
883 echo '<h2 id="h_index" >Class Index</h2>'.NL;
884 echo '<ul class="classindex">'.NL;
885 foreach ($classlist as $ns => $cl) {
886         echo '<li>'.typelink($ns).'</li>'.NL;
887 }
888 echo '</ul>'.NL;
889
890
891 # see how far there is still to go...
892 fwrite (STDERR, "Found $dox_found annotations. missing: $dox_miss\n");
893
894 ?>
895 </div>
896 <div class="luafooter">Ardour <?=$ardourversion?> &nbsp;-&nbsp; <?=date('r')?></div>
897
898 <!-- #### SNIP  #### !-->
899
900 </body>
901 </html>