5 # ./waf configure --luadoc ....
7 # ./gtk2_ardour/arluadoc > doc/luadoc.json
9 # php tools/fmt-luadoc.php > /tmp/luadoc.html
12 ################################################################################
13 ################################################################################
15 $json = file_get_contents (dirname (__FILE__).'/../doc/luadoc.json');
17 foreach (json_decode ($json, true) as $b) {
18 if (!isset ($b['type'])) { continue; }
22 if (count ($doc) == 0) {
23 fwrite (STDERR, "Failed to read luadoc.json\n");
27 ################################################################################
28 ## Global result variables
29 ################################################################################
31 $classlist = array ();
33 $constlist = array ();
36 ################################################################################
37 ## Pre-process the data, collect functions, parse arguments, cross reference
38 ################################################################################
41 ################################################################################
42 # some internal helper functions first
47 function my_die ($msg) {
48 fwrite (STDERR, $msg."\n");
52 ##function ptr_strip ($ctype) {
53 # # boost::shared_ptr<std::list<boost::shared_ptr<ARDOUR::Route>> > >
54 # # -> std::list<ARDOUR::Route>
55 # $ctype = preg_replace ('/boost::shared_ptr<([^>]*)[ ]*>/', '$1', $ctype);
56 # return preg_replace ('/boost::shared_ptr<([^>]*)[ ]*>/', '$1', $ctype);
59 function arg2lua ($argtype) {
63 # LuaBridge abstracts C++ references
64 $flags = preg_match ('/&$/', $argtype);
65 $arg = preg_replace ('/&$/', '', $argtype);
67 # filter out basic types
68 $builtin = array ('float', 'double', 'bool', 'std::string', 'int', 'long', 'unsigned long', 'unsigned int', 'unsigned char', 'char', 'void', 'char*', 'unsigned char*', 'void*');
69 if (in_array ($arg, $builtin)) {
70 return array ($arg => $flags);
73 # check Class declarations first
74 foreach (array_merge ($classes, $consts) as $b) {
75 if ($b['decl'] == $arg) {
76 return array ($b['lua'] => $flags);
80 # strip class pointers -- TODO Check C'tor for given class
81 $arg = preg_replace ('/[&*]*$/', '', $argtype);
82 foreach (array_merge ($classes, $consts) as $b) {
83 if ($b['decl'] == $arg) {
84 return array ($b['lua'] => $flags);
87 return array ('--MISSING (' . $argtype . ')--' => ($flags | 4));
90 function stripclass ($classname, $name) {
92 if (strpos ($name, $classname) !== 0) {
93 my_die ('invalid class prefix: ' .$classname. ' -- '. $name);
95 return substr ($name, strlen ($classname));
98 function datatype ($decl) {
99 # TODO handle spaces in type. Works because
100 # we don't yet have templated types (with_space <here >)
101 return substr ($decl, 0, strpos ($decl, ' '));
104 function luafn2class ($lua) {
105 return substr ($lua, 0, strrpos ($lua, ':'));
108 function checkclass ($b) {
110 if (!isset ($classlist[luafn2class ($b['lua'])])) {
111 my_die ('MISSING CLASS FOR '. print_r ($b['lua'], true));
115 # parse functions argument list to lua-names
116 function decl2args ($decl) {
117 $start = strrpos ($decl, '(');
118 $end = strrpos ($decl, ')');
119 $args = substr ($decl, $start + 1, $end - $start - 1);
120 $arglist = preg_split ('/, */', $args);
122 foreach ($arglist as $a) {
123 if (empty ($a)) { continue; }
124 $rv[] = arg2lua ($a);
129 ################################################################################
130 # step 1: build class indices
132 foreach ($doc as $b) {
133 if (strpos ($b['type'], "[C] ") === 0) {
135 $classlist[$b['lua']] = $b;
136 if (strpos ($b['type'], 'Pointer Class') === false) {
137 $classdecl[$b['decl']] = $b;
142 foreach ($classes as $c) {
143 if (strpos ($c['type'], 'Pointer Class') !== false) { continue; }
144 if (isset ($c['parent'])) {
145 if (isset ($classdecl[$c['parent']])) {
146 $classlist[$c['lua']]['luaparent'][] = $classdecl[$c['parent']]['lua'];
148 my_die ('unknown parent class: ' . print_r ($c, true));
153 # step 2: extract constants/enum
154 foreach ($doc as $b) {
155 switch ($b['type']) {
156 case "Constant/Enum":
157 case "Constant/Enum Member":
158 if (strpos ($b['decl'], '::') === false) {
159 # for extern c enums, use the Lua Namespace
160 $b['decl'] = str_replace (':', '::', luafn2class ($b['lua']));
162 $ns = str_replace ('::', ':', $b['decl']);
163 $constlist[$ns][] = $b;
173 # step 3: process functions
174 foreach ($doc as $b) {
175 switch ($b['type']) {
177 case "Weak/Shared Pointer Constructor":
179 $classlist[luafn2class ($b['lua'])]['ctor'][] = array (
180 'name' => luafn2class ($b['lua']),
181 'args' => decl2args ($b['decl']),
186 $classlist[luafn2class ($b['lua'])]['data'][] = array (
188 'ret' => arg2lua (datatype ($b['decl']))
192 # we required C functions to be in a class namespace
193 case "Ext C Function":
195 $classlist[luafn2class ($b['lua'])]['func'][] = array (
197 'args' => array (array ('--custom--' => 0)), // XXX
198 'ret' => array ('...' => 0), // XXX
203 case "Free Function":
204 case "Free Function RefReturn":
205 $funclist[luafn2class ($b['lua'])][] = array (
207 'args' => decl2args ($b['decl']),
208 'ret' => arg2lua ($b['ret']),
209 'ref' => (strpos ($b['type'], "RefReturn") !== false)
212 case "Member Function":
213 case "Member Function RefReturn":
214 case "Member Pointer Function":
215 case "Weak/Shared Pointer Function":
216 case "Weak/Shared Pointer Function RefReturn":
217 case "Weak/Shared Null Check":
218 case "Weak/Shared Pointer Cast":
219 case "Static Member Function":
221 $classlist[luafn2class ($b['lua'])]['func'][] = array (
223 'args' => decl2args ($b['decl']),
224 'ret' => arg2lua ($b['ret']),
225 'ref' => (strpos ($b['type'], "RefReturn") !== false)
228 case "Constant/Enum":
229 case "Constant/Enum Member":
230 # already handled -> $consts
233 if (strpos ($b['type'], "[C] ") !== 0) {
234 my_die ('unhandled type: ' . $b['type']);
241 # step 4: collect/group/sort
243 # step 4a: unify weak/shared Ptr classes
244 foreach ($classlist as $ns => $cl) {
245 if (strpos ($cl['type'], ' Array') !== false) {
246 $classlist[$ns]['arr'] = true;
249 foreach ($classes as $c) {
250 if ($c['lua'] == $ns) {
251 if (strpos ($c['type'], 'Pointer Class') !== false) {
252 $classlist[$ns]['ptr'] = true;
253 $classlist[$ns]['decl'] = 'boost::shared_ptr< '.$c['decl']. ' >, boost::weak_ptr< '.$c['decl']. ' >';
260 # step4b: sanity check
261 foreach ($classlist as $ns => $cl) {
262 if (isset ($classes[$ns]['parent']) && !isset ($classlist[$ns]['luaparent'])) {
263 my_die ('missing parent class: ' . print_r ($cl, true));
267 # step 4c: merge free functions into classlist
268 foreach ($funclist as $ns => $fl) {
269 if (isset ($classlist[$ns])) {
270 my_die ('Free Funcion in existing namespace: '.$ns.' '. print_r ($ns, true));
272 $classlist[$ns]['func'] = $fl;
273 $classlist[$ns]['free'] = true;
276 # step 4d: order to chaos
277 # no array_multisort() here, sub-types are sorted after merging parents
281 ################################################################################
283 ################################################################################
286 ################################################################################
290 function ctorname ($name) {
291 return htmlentities (str_replace (':', '.', $name));
294 function varname ($a) {
295 return array_keys ($a)[0];
298 function name_sort_cb ($a, $b) {
299 return strcmp ($a['name'], $b['name']);
302 function typelink ($a, $linkcls = '', $argcls = '') {
305 if (in_array ($a, array_keys ($classlist))) {
306 return '<a class="'.$linkcls.'" href="#'.$a.'">'.$a.'</a>';
307 } else if (in_array ($a, array_keys ($constlist))) {
308 return '<a class="'.$linkcls.'" href="#'.ctorname ($a).'">'.ctorname ($a).'</a>';
310 return '<span class="'.$argcls.'">'.$a.'</span>';
314 function format_args ($args) {
315 $rv = '<span class="functionargs"> (';
317 foreach ($args as $a) {
318 if (!$first) { $rv .= ', '; }; $first = false;
319 $flags = $a[varname ($a)];
321 $rv .= typelink (varname ($a).'&', '', 'em');
323 $rv .= typelink (varname ($a), '', 'em');
330 function format_class_members ($ns, $cl, &$dups) {
332 if (isset ($cl['ctor'])) {
333 usort ($cl['ctor'], 'name_sort_cb');
334 $rv.= ' <tr><th colspan="3">Constructor</th></tr>'.NL;
335 foreach ($cl['ctor'] as $f) {
336 $rv.= ' <tr><td class="def">ℂ</td><td class="decl">';
337 $rv.= '<span class="functionname">'.ctorname ($f['name']).'</span>';
338 $rv.= format_args ($f['args']);
339 $rv.= '</td><td class="fill"></td></tr>'.NL;
343 if (isset ($cl['func'])) {
344 foreach ($cl['func'] as $f) {
345 if (in_array (stripclass ($ns, $f['name']), $dups)) { continue; }
349 if (count ($nondups) > 0) {
350 usort ($nondups, 'name_sort_cb');
351 $rv.= ' <tr><th colspan="3">Methods</th></tr>'.NL;
352 foreach ($nondups as $f) {
353 $dups[] = stripclass ($ns, $f['name']);
354 $rv.= ' <tr><td class="def">';
355 if ($f['ref'] && isset ($f['ext'])) {
356 # external C functions
357 $rv.= '<em>LuaTable</em>';
358 } elseif ($f['ref'] && varname ($f['ret']) == 'void') {
359 # functions with reference args return args
360 $rv.= '<em>LuaTable</em>(...)';
361 } elseif ($f['ref']) {
362 $rv.= '<em>LuaTable</em>('.typelink (varname ($f['ret'])).', ...)';
364 $rv.= typelink (varname ($f['ret']));
366 $rv.= '</td><td class="decl">';
367 $rv.= '<span class="functionname">'.stripclass ($ns, $f['name']).'</span>';
368 $rv.= format_args ($f['args']);
369 $rv.= '</td><td class="fill"></td></tr>'.NL;
372 if (isset ($cl['data'])) {
373 usort ($cl['data'], 'name_sort_cb');
374 $rv.= ' <tr><th colspan="3">Data Members</th></tr>'.NL;
375 foreach ($cl['data'] as $f) {
376 $rv.= ' <tr><td class="def">'.typelink (array_keys ($f['ret'])[0]).'</td><td class="decl">';
377 $rv.= '<span class="functionname">'.stripclass ($ns, $f['name']).'</span>';
378 $rv.= '</td><td class="fill"></td></tr>'.NL;
385 ################################################################################
388 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
390 <title>Ardour Lua Bindings</title>
391 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
392 <style type="text/css">
393 div.content { max-width:60em; margin: 1em auto; }
394 h1 { margin:2em 0 0 0; padding:0em; border-bottom: 1px solid black;}
395 h2.cls { margin:2em 0 0 0; padding-left:1em; border: 1px dashed #6666ee;}
396 h2.cls abbr { text-decoration:none; cursor:default;}
397 h3.cls { margin:1em 0 0 0;}
398 h2.class { background-color: #aaee66; }
399 h2.enum { background-color: #aaaaaa; }
400 h2.pointerclass { background-color: #eeaa66; }
401 h2.array { background-color: #66aaee; }
402 h2.opaque { background-color: #6666aa; }
403 p.cdecl { text-align: right; float:right; font-size:90%; margin:0; padding: 0 0 0 1em;}
404 ul.classlist { columns: 2; -webkit-columns: 2; -moz-columns: 2; }
405 div.clear { clear:both; }
406 table.classmembers { width: 100%; }
407 table.classmembers th { text-align:left; border-bottom:1px solid black; padding-top:1em; }
408 table.classmembers td.def { text-align:right; padding-right:.5em; white-space: nowrap;}
409 table.classmembers td.decl { text-align:left; padding-left:.5em; white-space: nowrap; }
410 table.classmembers td.fill { width: 99%;}
411 table.classmembers span.em { font-style: italic;}
412 div.header {text-align:center;}
413 div.header h1 {margin:0;}
414 div.header p {margin:.25em;}
419 <h1>Ardour Lua Bindings</h1>
421 <a href="#h_classes">Class Documentation</a>
423 <a href="#h_enum">Enum/Constants</a>
425 <a href="#h_index">Index</a>
428 <div class="content">
431 echo '<h1 id="h_classes">Class Documentation</h1>'.NL;
433 foreach ($classlist as $ns => $cl) {
435 $tbl = format_class_members ($ns, $cl, $dups);
438 # place-holder class (maybe collect at bottom??)
439 echo '<h2 id="'.$ns.'" class="cls opaque"><abbr title="Opaque Object">∅</abbr> '.$ns.'</h2>'.NL;
441 else if (isset ($classlist[$ns]['free'])) {
442 echo '<h2 id="'.$ns.'" class="cls freeclass"><abbr title="Namespace">ℕ</abbr> '.$ns.'</h2>'.NL;
444 else if (isset ($classlist[$ns]['arr'])) {
445 echo '<h2 id="'.$ns.'" class="cls array"><abbr title="C Array">⋯</abbr> '.$ns.'</h2>'.NL;
447 else if (isset ($classlist[$ns]['ptr'])) {
448 echo '<h2 id="'.$ns.'" class="cls pointerclass"><abbr title="Pointer Class">↠</abbr> '.$ns.'</h2>'.NL;
450 echo '<h2 id="'.htmlentities ($ns).'" class="cls class"><abbr title="Class">∁</abbr> '.htmlentities ($ns).'</h2>'.NL;
452 if (isset ($cl['decl'])) {
453 echo '<p class="cdecl"><em>C‡</em>: '.htmlentities ($cl['decl']).'</p>'.NL;
456 $inherited = array ();
457 if (isset ($classlist[$ns]['luaparent'])) {
458 $parents = array_unique ($classlist[$ns]['luaparent']);
462 foreach ($parents as $p) {
463 if (!$first) { echo ', '; }; $first = false;
465 $inherited[$p] = $classlist[$p];
469 echo '<div class="clear"></div>'.NL;
472 echo '<p>This class object is only used indirectly as return-value and function-parameter.</p>'.NL;
474 echo '<table class="classmembers">'.NL;
479 // traverse all parent classes..
480 foreach ($inherited as $pns => $pcl) {
481 $tbl = format_class_members ($pns, $pcl, $dups);
483 echo '<h3 class="cls">Inherited from '.$pns.'</h3>'.NL;
484 echo '<table class="classmembers">'.NL;
491 echo '<h1 id="h_enum">Enum/Constants</h1>'.NL;
492 foreach ($constlist as $ns => $cs) {
493 echo '<h2 id="'.ctorname ($ns).'" class="cls enum"><abbr title="Enum">∈</abbr> '.ctorname ($ns).'</h2>'.NL;
494 echo '<ul class="enum">'.NL;
495 foreach ($cs as $c) {
496 echo '<li class="const">'.ctorname ($c['lua']).'</li>'.NL;
501 echo '<h1 id="h_index" >Class Index</h1>'.NL;
502 echo '<ul class="classlist">'.NL;
503 foreach ($classlist as $ns => $cl) {
504 echo '<li><a href="#'.$ns.'">'.$ns.'</a></li>'.NL;