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