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