remove static from some members, after MonitorSection is now persistent
[ardour.git] / tools / luadevel / devel.cc
1 #include <stdint.h>
2 #include <cstdio>
3 #include <iostream>
4 #include <string>
5 #include <list>
6 #include <vector>
7
8 #define LIBPBD_API
9 #include "../../libs/pbd/pbd/reallocpool.h"
10 #include "../../libs/pbd/reallocpool.cc"
11
12 #include <readline/readline.h>
13 #include <readline/history.h>
14
15 #include "lua/luastate.h"
16 #include "LuaBridge/LuaBridge.h"
17
18 static void my_lua_print (std::string s) {
19         std::cout << s << "\n";
20 }
21
22 luabridge::LuaRef::Proxy&
23 luabridge::LuaRef::Proxy::clone_instance (const void* classkey, void* p) {
24   lua_rawgeti (m_L, LUA_REGISTRYINDEX, m_tableRef);
25   lua_rawgeti (m_L, LUA_REGISTRYINDEX, m_keyRef);
26
27         luabridge::UserdataPtr::push_raw (m_L, p, classkey);
28
29   lua_rawset (m_L, -3);
30   lua_pop (m_L, 1);
31   return *this;
32 }
33
34
35
36 class A {
37         public:
38                 A() { printf ("CTOR %p\n", this); _int = 4; for (int i = 0; i < 256; ++i) {arr[i] = i; ar2[i] = i/256.0; ar3[i] = i;} }
39                 ~A() { printf ("DTOR\n"); }
40
41                 void set_int (int a) { _int = a; }
42                 int  get_int () const { return _int; }
43
44                 int& get_ref () { return _int; }
45                 int get_arg (int &a) { printf ("a = %d\n", a);  a = _int; printf ("a = %d\n", a); return 1; }
46                 void get_arg2 (int &a, int& b) {  a = _int; b = 100; }
47                 void get_args (std::string &a) {  a = "hello"; }
48                 void set_ref (int const &a) { _int = a; }
49
50                 float * get_arr () { return arr; }
51                 float * get_ar2 () { return ar2; }
52                 int * get_ar3 () { return ar3; }
53
54                 void set_list (std::list<std::string> sl) { _sl = sl; }
55                 std::list<std::string>& get_list () { return _sl; }
56
57                 uint32_t minone() { return -1; }
58                 void pointer (float*f) const { printf ("PTR %p", f); }
59
60                 enum EN {
61                         RV1 = 1, RV2, RV3
62                 };
63
64                 enum EN ret_enum () { return _en;}
65                 void set_enum (enum EN en) { _en = en; }
66
67         private:
68                 std::list<std::string> _sl;
69                 int _int;
70                 enum EN _en;
71                 float arr[256];
72                 float ar2[256];
73                 int ar3[256];
74 };
75
76
77 class LuaTableRef {
78         public:
79                 LuaTableRef () {}
80                 ~LuaTableRef () {}
81
82                 int get (lua_State* L) {
83                         luabridge::LuaRef rv (luabridge::newTable (L));
84                         for (std::vector<LuaTableEntry>::const_iterator i = _data.begin (); i != _data.end (); ++i) {
85                                 switch ((*i).keytype) {
86                                         case LUA_TSTRING:
87                                                 assign(&rv, i->k_s, *i);
88                                                 break;
89                                         case LUA_TNUMBER:
90                                                 assign(&rv, i->k_n, *i);
91                                                 break;
92                                 }
93                         }
94                         luabridge::push (L, rv);
95                         return 1;
96                 }
97
98                 int set (lua_State* L) {
99                         if (!lua_istable (L, -1)) { return luaL_error (L, "argument is not a table"); }
100                         _data.clear ();
101
102                         lua_pushvalue (L, -1);
103                         lua_pushnil (L);
104                         while (lua_next (L, -2)) {
105                                 lua_pushvalue (L, -2);
106
107                                 LuaTableEntry s (lua_type(L, -1), lua_type(L, -2));
108                                 switch (lua_type(L, -1)) {
109                                         case LUA_TSTRING:
110                                                 s.k_s = luabridge::Stack<std::string>::get (L, -1);
111                                                 break;
112                                                 ;
113                                         case LUA_TNUMBER:
114                                                 s.k_n = luabridge::Stack<unsigned int>::get (L, -1);
115                                                 break;
116                                         default:
117                                                 // invalid key
118                                                 lua_pop (L, 2);
119                                                 continue;
120                                 }
121
122                                 switch(lua_type(L, -2)) {
123                                         case LUA_TSTRING:
124                                                 s.s = luabridge::Stack<std::string>::get (L, -2);
125                                                 break;
126                                         case LUA_TBOOLEAN:
127                                                 s.b = lua_toboolean (L, -2);
128                                                 break;
129                                         case LUA_TNUMBER:
130                                                 s.n = lua_tonumber (L, -2);
131                                                 break;
132                                         case LUA_TUSERDATA:
133                                                 {
134                                                         bool ok = false;
135                                                         lua_getmetatable (L, -2);
136                                                         lua_rawgetp (L, -1, luabridge::getIdentityKey ());
137                                                         if (lua_isboolean (L, -1)) {
138                                                                 lua_pop (L, 1);
139                                                                 const void* key = lua_topointer (L, -1);
140                                                                 lua_pop (L, 1);
141                                                                 void const* classkey = findclasskey (L, key);
142
143                                                                 if (classkey) {
144                                                                         ok = true;
145                                                                         s.c = classkey;
146                                                                         s.p = luabridge::Userdata::get_ptr (L, -2);
147                                                                 }
148                                                         }  else {
149                                                                 lua_pop (L, 2);
150                                                         }
151
152                                                         if (ok) {
153                                                                 break;
154                                                         }
155                                                         // invalid userdata -- fall through
156                                                 }
157
158                                                 /* fall through */
159                                         case LUA_TFUNCTION: // no support -- we could... string.format("%q", string.dump(value, true))
160                                         case LUA_TTABLE: // no nested tables, sorry.
161                                         case LUA_TNIL: // fallthrough
162                                         default:
163                                                 // invalid value
164                                                 lua_pop (L, 2);
165                                                 continue;
166                                 }
167
168                                 _data.push_back(s);
169                                 lua_pop (L, 2);
170                         }
171                         return 0;
172                 }
173
174                 static void* findclasskey (lua_State *L, const void* key)
175                 {
176                         lua_pushvalue(L, LUA_REGISTRYINDEX);
177                         lua_pushnil (L);
178                         while (lua_next (L, -2)) {
179                                 lua_pushvalue (L, -2);
180                                 if (lua_topointer(L, -2) == key) {
181                                         void* rv = lua_touserdata (L, -1);
182                                         lua_pop (L, 4);
183                                         return rv;
184                                 }
185                                 lua_pop (L, 2);
186                         }
187                         lua_pop (L, 1);
188                         return NULL;
189                 }
190
191         private:
192                 struct LuaTableEntry {
193                         LuaTableEntry (int kt, int vt)
194                                 : keytype (kt)
195                                 , valuetype (vt)
196                         { }
197
198                         int keytype;
199                         std::string k_s;
200                         unsigned int k_n;
201
202                         int valuetype;
203                         // LUA_TUSERDATA
204                         const void* c;
205                         void* p;
206                         // LUA_TBOOLEAN
207                         bool b;
208                         // LUA_TSTRING:
209                         std::string s;
210                         // LUA_TNUMBER:
211                         double n;
212                 };
213
214                 template<typename T>
215                 static void assign (luabridge::LuaRef* rv, T key, const LuaTableEntry& s)
216                 {
217                         switch (s.valuetype) {
218                                 case LUA_TSTRING:
219                                         (*rv)[key] = s.s;
220                                         break;
221                                 case LUA_TBOOLEAN:
222                                         (*rv)[key] = s.b;
223                                         break;
224                                 case LUA_TNUMBER:
225                                         (*rv)[key] = s.n;
226                                         break;
227                                 case LUA_TUSERDATA:
228                                         (*rv)[key].clone_instance (s.c, s.p);
229                                         break;
230                                 default:
231                                         assert (0);
232                                         break;
233                         }
234                 }
235
236                 std::vector<LuaTableEntry> _data;
237 };
238
239
240 #if 0
241 static void* findclasskey (lua_State *L, const void* key)
242 {
243         lua_pushvalue(L, LUA_REGISTRYINDEX);
244         lua_pushnil (L);
245         while (lua_next (L, -2)) {
246                 lua_pushvalue (L, -2);
247                 if (lua_topointer(L, -2) == key) {
248                         void* rv = lua_touserdata (L, -1);
249                         lua_pop (L, 4);
250                         return rv;
251                 }
252                 lua_pop (L, 2);
253         }
254         lua_pop (L, 1);
255         return NULL;
256 }
257
258 static int tableSerialize (lua_State *L)
259 {
260         if (!lua_istable (L, -1)) { return luaL_error (L, "argument is not a table"); }
261
262         luabridge::LuaRef rv (luabridge::newTable (L));
263         std::cout << "CLASS A KEY: " << luabridge::ClassInfo <A>::getClassKey () << "\n";
264         lua_rawgetp (L, LUA_REGISTRYINDEX, luabridge::ClassInfo <A>::getClassKey ());
265         std::cout << " CLASS A TABLE PTR=" << lua_topointer (L, -1) << "\n";
266         lua_pop (L, 1);
267         // for k,v in pairs (debug.getregistry ()) do print (k,v) end
268
269         lua_pushvalue (L, -1);
270         lua_pushnil (L);
271         while (lua_next (L, -2)) {
272                 lua_pushvalue (L, -2);
273                 unsigned int const i = luabridge::Stack<unsigned int>::get (L, -1);
274                 int t = lua_type(L, -2);
275                 switch(t) {
276                         case LUA_TSTRING:
277                                 std::cout << "  " << i << ": '" << lua_tostring(L, -2) << "'\n";
278                                 rv[i] = lua_tostring(L, -2);
279                                 break;
280                         case LUA_TBOOLEAN:
281                                 std::cout << "  " << i << ": " <<
282                                         (lua_toboolean(L, -2) ? "true" : "false") << "\n";
283                                 rv[i] = lua_toboolean(L, -2);
284                                 break;
285                         case LUA_TNUMBER:
286                                 std::cout << "  " << i << ": " << lua_tonumber(L, -2) << "\n";
287                                 rv[i] = lua_tonumber(L, -2);
288                                 break;
289                         case LUA_TUSERDATA:
290                                 {
291                                         lua_getmetatable (L, -2);
292                                         lua_rawgetp (L, -1, luabridge::getIdentityKey ());
293                                         if (lua_isboolean (L, -1)) {
294                                                 lua_pop (L, 1);
295                                                 const void* key = lua_topointer (L, -1);
296                                                 lua_pop (L, 1);
297                                                 void const* classkey = findclasskey (L, key);
298
299                                                 if (classkey) {
300                                                         void* p = luabridge::Userdata::get_ptr (L, -2);
301                                                         rv[i].clone_instance (classkey, p);
302                                                 }
303                                         }  else {
304                                                 lua_pop (L, 2);
305                                         }
306                                 }
307                                 break;
308                         case LUA_TNIL:
309                         case LUA_TTABLE:
310                         case LUA_TFUNCTION:
311                         case LUA_TLIGHTUSERDATA:
312                         default:
313                                 std::cout << "  " << i << ": TYPE=" << t << ": " << lua_topointer(L, -2)<< "\n";
314                                 break;
315                 }
316                 lua_pop (L, 2);
317         }
318         lua_pop (L, 1);
319         lua_pop (L, 2);
320
321         luabridge::push (L, rv);
322         return 1;
323 }
324 #endif
325
326 LuaTableRef globalref;
327
328 int runone (LuaState& lua)
329 {
330 #if 0
331         LuaState lua (*new LuaState);
332 #elif 0
333         PBD::ReallocPool _mempool ("Devel", 1048576);
334         LuaState lua (lua_newstate (&PBD::ReallocPool::lalloc, &_mempool));
335 #endif
336         lua.Print.connect (&my_lua_print);
337         lua_State* L = lua.getState();
338
339
340 #if 1
341         luabridge::getGlobalNamespace (L)
342                 .beginNamespace ("Test")
343                 .beginStdList <std::string> ("StringList")
344                 .endClass ()
345                 .endNamespace ();
346
347         luabridge::getGlobalNamespace (L)
348                 .beginNamespace ("Test")
349                 .beginStdVector <std::string> ("StringVector")
350                 .endClass ()
351                 .endNamespace ();
352
353         luabridge::getGlobalNamespace (L)
354                 .beginNamespace ("Test")
355                 .beginStdMap <std::string,std::string> ("StringStringMap")
356                 .endClass ()
357                 .endNamespace ();
358
359         luabridge::getGlobalNamespace (L)
360                 .beginNamespace ("Test")
361                 .beginStdSet <std::string> ("StringSet")
362                 .endClass ()
363                 .endNamespace ();
364
365
366         luabridge::getGlobalNamespace (L)
367                 .beginNamespace ("Test")
368                 .registerArray <float> ("FloatArray")
369                 .registerArray <int> ("IntArray")
370                 .beginClass <A> ("A")
371                 .addConstructor <void (*) ()> ()
372                 .addFunction ("set_int", &A::set_int)
373                 .addFunction ("get_int", &A::get_int)
374                 .addRefFunction ("get_arg", &A::get_arg)
375                 .addRefFunction ("get_arg2", &A::get_arg2)
376                 .addRefFunction ("get_args", &A::get_args)
377                 .addFunction ("set_ref", &A::set_ref)
378                 .addFunction ("get_list", &A::get_list)
379                 .addFunction ("set_list", &A::set_list)
380                 .addFunction ("ret_enum", &A::ret_enum)
381                 .addFunction ("set_enum", &A::set_enum)
382                 .addFunction ("get_arr", &A::get_arr)
383                 .addFunction ("get_ar2", &A::get_ar2)
384                 .addFunction ("get_ar3", &A::get_ar3)
385                 .endClass ()
386                 .endNamespace ();
387
388         luabridge::getGlobalNamespace (L)
389                 .beginNamespace ("Test")
390                 .beginClass <A> ("A")
391                 .addFunction ("pointer", &A::pointer)
392                 .addFunction ("minone", &A::minone)
393                 .addConst ("cologne", 4711)
394                 .endClass ()
395                 .addConst ("koln", 4711)
396                 .endNamespace ();
397 #endif
398         luabridge::getGlobalNamespace (L)
399                 .beginNamespace ("Dump")
400
401                 .beginClass <LuaTableRef> ("TableRef")
402                 .addCFunction ("get", &LuaTableRef::get)
403                 .addCFunction ("set", &LuaTableRef::set)
404                 .endClass ()
405
406                 //.addCFunction ("dump", tableSerialize)
407                 .endNamespace ();
408
409         luabridge::push <LuaTableRef *> (L, &globalref);
410         lua_setglobal (L, "ref");
411
412
413 #if 0 // session  script test
414         lua.do_command (
415                         "function ArdourSession ()"
416                         "  local self = { scripts = {}, instances = {} }"
417                         ""
418                         "  local foreach = function (fn)"
419                         "   for n, s in pairs (self.scripts) do"
420                         "    fn (n, s)"
421                         "   end"
422                         "  end"
423                         ""
424                         "  local run = function ()"
425                         "   for n, s in pairs (self.instances) do"
426                         "     local status, err = pcall (s)"
427                         "     if not status then print ('fn \"'.. n .. '\": ', err) end"
428                         "   end"
429                         "   collectgarbage()"
430                         "  end"
431                         ""
432                         "  local add = function (n, f, a)"
433                         "   assert(type(n) == 'string', 'function-name must be string')"
434                         "   assert(type(f) == 'function', 'Given script is a not a function')"
435                         "   assert(type(a) == 'table' or type(a) == 'nil', 'Given argument is invalid')"
436                         "   assert(self.scripts[n] == nil, 'Callback \"'.. n ..'\" already exists.')"
437                         "   self.scripts[n] = { ['f'] = f, ['a'] = a }"
438                         "   local env = { print = print, Session = Session, tostring = tostring, assert = assert, ipairs = ipairs, error = error, string = string, type = type, tonumber = tonumber, collectgarbage = collectgarbage, pairs = pairs, math = math, table = table, pcall = pcall }"
439                         "   self.instances[n] = load (string.dump(f), nil, nil, env)(a)"
440                         "  end"
441                         ""
442                         "  local remove = function (n)"
443                         "   self.scripts[n] = nil"
444                         "  end"
445                         ""
446                         "  local list = function ()"
447                         "   local rv = {}"
448                         "   foreach (function (n) rv[n] = true end)"
449                         "   return rv"
450                         "  end"
451                         ""
452                         "  local function basic_serialize (o)"
453                         "    if type(o) == \"number\" then"
454                         "     return tostring(o)"
455                         "    else"
456                         "     return string.format(\"%q\", o)"
457                         "    end"
458                         "  end"
459                         ""
460                         "  local function serialize (name, value)"
461                         "   local rv = name .. ' = '"
462                         "   if type(value) == \"number\" or type(value) == \"string\" or type(value) == \"nil\" then"
463                         "    return rv .. basic_serialize(value) .. ' '"
464                         "   elseif type(value) == \"table\" then"
465                         "    rv = rv .. '{} '"
466                         "    for k,v in pairs(value) do"
467                         "     local fieldname = string.format(\"%s[%s]\", name, basic_serialize(k))"
468                         "     rv = rv .. serialize(fieldname, v) .. ' '"
469                         "    end"
470                         "    return rv;"
471                         "   elseif type(value) == \"function\" then"
472                         "     return rv .. string.format(\"%q\", string.dump(value))"
473                         "   else"
474                         "    error('cannot save a ' .. type(value))"
475                         "   end"
476                         "  end"
477                         ""
478                         ""
479                         "  local save = function ()"
480                         "   return (serialize('scripts', self.scripts))"
481                         "  end"
482                         ""
483                         "  local restore = function (state)"
484                         "   self.scripts = {}"
485                         "   load (state)()"
486                         "   print (scripts)"
487                         "   for n, s in pairs (scripts) do"
488                         "    add (n, load(s['f']), s['a'])"
489                         "   end"
490                         "  end"
491                         ""
492                         " return { run = run, add = add, remove = remove,"
493                   "          list = list, foreach = foreach,"
494                         "          restore = restore, save = save}"
495                         " end"
496                         " "
497                         " sess = ArdourSession ()"
498                         " ArdourSession = nil"
499                         );
500
501         luabridge::LuaRef *lua_run;
502         luabridge::LuaRef *lua_add;
503         luabridge::LuaRef *lua_del;
504         luabridge::LuaRef *lua_save;
505         luabridge::LuaRef *lua_load;
506         {
507                 luabridge::LuaRef lua_sess = luabridge::getGlobal (L, "sess");
508                 lua.do_command ("sess = nil"); // hide it.
509                 lua.do_command ("collectgarbage()");
510
511                 lua_run = new luabridge::LuaRef(lua_sess["run"]);
512                 lua_add = new luabridge::LuaRef(lua_sess["add"]);
513                 lua_del = new luabridge::LuaRef(lua_sess["remove"]);
514                 lua_save = new luabridge::LuaRef(lua_sess["save"]);
515                 lua_load = new luabridge::LuaRef(lua_sess["restore"]);
516         }
517         lua.do_command ("collectgarbage()");
518
519 #if 1
520         lua.do_command ("function factory (t) return function () local p = t or { } local a = t[1] or 'Nibor' print ('Hello ' .. a) end end");
521         luabridge::LuaRef lua_fact = luabridge::getGlobal (L, "factory");
522         luabridge::LuaRef tbl_arg (luabridge::newTable(L));
523         //tbl_arg[1] = "Robin";
524         (*lua_add)("t2", lua_fact, tbl_arg);
525 #else
526         lua.do_command ("function factory (t) return function () print ('Boo') end end");
527         luabridge::LuaRef lua_fact = luabridge::getGlobal (L, "factory");
528         (*lua_add)("t2", lua_fact());
529 #endif
530
531         lua.do_command ("function factory (t) return function () print ('Ahoy') end end");
532         luabridge::LuaRef lua_fact2 = luabridge::getGlobal (L, "factory");
533         (*lua_add)("t1", lua_fact2);
534
535         luabridge::LuaRef savedstate ((*lua_save)());
536         std::string saved = savedstate.cast<std::string>();
537
538         (*lua_del)("t2");
539
540         try {
541                 (*lua_run)();
542         } catch (luabridge::LuaException const& e) { printf ("LuaException: %s\n", e.what ()); }
543
544         (*lua_load)(saved);
545
546         for (int i = 0; i < 2; ++i) {
547         lua.do_command ("collectgarbage()");
548         lua.collect_garbage ();
549         try {
550                 (*lua_run)();
551         } catch (luabridge::LuaException const& e) { printf ("LuaException: %s\n", e.what ()); }
552         }
553
554 #endif
555
556         add_history("a = Test:A() b = 2 c = 3 d = 'a'");
557         add_history("x = a:get_arg(b)  y = a:get_arg2(b, c)  z = a:get_args(d) ");
558         add_history("for i,n in ipairs(y) do print (i, n); end");
559         add_history("t = {} t[2] = 7; t[3] = Test:A() t[4] = Test:A() ref:set (t);  f = ref:get()");
560
561         /////////////////////////////////////////////////////////////////////////////
562         char *line;
563         while ((line = readline ("> "))) {
564                 if (!strcmp (line, "quit")) {
565                         break;
566                 }
567                 if (strlen(line) == 0) {
568                         //lua.do_command("collectgarbage();");
569                         continue;
570                 }
571                 if (!lua.do_command (line)) {
572                         add_history(line); // OK
573                 } else {
574                         add_history(line); // :)
575                 }
576         }
577         printf("\n");
578         return 0;
579 }
580
581 int main (int argc, char **argv)
582 {
583         LuaState lua1;
584         LuaState lua2;
585         runone (lua1);
586         printf ("=====\n");
587         runone (lua2);
588 }