added software versions list
[lqt.git] / generator / generator.lua
blob8360d43e0d7b3fe5f2d222f90aa3fc9db244e50f
1 #!/usr/bin/lua
3 --[[
5 Copyright (c) 2007-2008 Mauro Iazzi
7 Permission is hereby granted, free of charge, to any person
8 obtaining a copy of this software and associated documentation
9 files (the "Software"), to deal in the Software without
10 restriction, including without limitation the rights to use,
11 copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the
13 Software is furnished to do so, subject to the following
14 conditions:
16 The above copyright notice and this permission notice shall be
17 included in all copies or substantial portions of the Software.
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 OTHER DEALINGS IN THE SOFTWARE.
28 --]]
30 local path = string.match(arg[0], '(.*/)[^%/]+') or ''
31 local filename = nil
32 local dirname = nil
33 local module_name = nil
34 local typefiles = {}
35 local filterfiles = {}
36 local output_includes = {
37 '"lqt_common.hpp"',
41 local i = 1
42 while select(i, ...) do
43 local argi = select(i, ...)
44 if argi=='-n' then
45 i = i + 1
46 module_name = select(i, ...)
47 elseif argi=='-i' then
48 i = i + 1
49 table.insert(output_includes, (select(i, ...)))
50 elseif argi=='-t' then
51 i = i + 1
52 table.insert(typefiles, (select(i, ...)))
53 elseif argi=='-f' then
54 i = i + 1
55 table.insert(filterfiles, (select(i, ...)))
56 else
57 filename = filename and error'duplicate filename' or argi
58 end
59 i = i + 1
60 end
61 end
63 local readfile = function(fn)
64 local f = assert(io.open(fn))
65 local s = f:read'*a'
66 f:close()
67 return s
68 end
70 local fprint = function(f)
71 return function(...)
72 for i = 1, select('#',...) do
73 f:write((i==1) and '' or '\t', tostring(select(i,...)))
74 end
75 f:write'\n'
76 f:flush()
77 end
78 end
80 local debug = fprint(io.stderr)
81 local print_head = fprint(assert(io.open(module_name..'_src/'..module_name..'_head.hpp', 'w')))
82 local print_enum = fprint(assert(io.open(module_name..'_src/'..module_name..'_enum.cpp', 'w')))
83 local print_slot_h = fprint(assert(io.open(module_name..'_src/'..module_name..'_slot.hpp', 'w')))
84 local print_slot_c = fprint(assert(io.open(module_name..'_src/'..module_name..'_slot.cpp', 'w')))
85 local print_type = fprint(assert(io.open(module_name..'_src/'..module_name..'_type.lua', 'w')))
87 local meta_printer
89 local n = 0
90 meta_printer = function()
91 n = n + 1
92 local f = assert(io.open(module_name..'_src/'..module_name..'_meta_'..n..'.cpp', 'w'))
93 f:write('#include "'..module_name..'_head.hpp'..'"\n\n\n')
94 return function(s)
95 if s==nil then
96 f:close()
97 return 0
98 else
99 s = tostring(s)
100 f:write(s, '\n')
101 f:flush()
102 return #s
104 end, n
108 local xmlstream, idindex = dofile(path..'xml.lua')(readfile(filename))
110 ----------------------------------------------------------------------------------
112 local copy_functions = function(index)
113 local ret = {}
114 for e in pairs(index) do
115 if e.label:match'^Function' then
116 e.label = 'Function'
117 ret[e] = true
120 return ret
124 local fix_arguments = function(all)
125 local fullnames = {}
126 for e in pairs(all or {}) do
127 if e.xarg.fullname then fullnames[e.xarg.fullname] = true end
129 for a in pairs(all) do
130 if a.label=='Argument'
131 and a.xarg.default=='1'
132 and (not string.match(a.xarg.defaultvalue, '^[-+]?%d+%.?%d*$'))
133 and a.xarg.defaultvalue~='true'
134 and a.xarg.defaultvalue~='false'
135 and (not string.match(a.xarg.defaultvalue, '^0[xX]%d+$')) then
136 local dv = a.xarg.defaultvalue
137 if not fullnames[dv] then
138 dv = a.xarg.context..'::'..dv
140 if fullnames[dv] then
141 a.xarg.defaultvalue = dv
142 else
143 a.xarg.default = nil
144 a.xarg.defaultvalue = nil
148 return all
151 local fix_functions = function(index)
152 for f in pairs(index) do
153 local args = {}
154 for i, a in ipairs(f) do
155 -- avoid bogus 'void' arguments
156 if a.xarg.type_name=='void' and i==1 and f[2]==nil then break end
157 if a.label=='Argument' then
158 table.insert(args, a)
161 f.arguments = args
162 f.return_type = f.xarg.type_name
163 if f.xarg.type_name=='void' then
164 f.return_type = nil
167 return index
170 local copy_enums = function(index)
171 local ret = {}
172 for e in pairs(index) do
173 if e.label=='Enum'
174 and not string.match(e.xarg.fullname, '%b<>')
175 and e.xarg.access=='public' then
176 ret[e] = true
179 return ret
182 local fill_enums = function(index)
183 for e in pairs(index) do
184 local values = {}
185 for _, v in ipairs(e) do
186 if v.label=='Enumerator' then
187 table.insert(values, v)
190 e.values = values
192 return index
195 local copy_classes = function(index)
196 local ret = {}
197 for e in pairs(index) do
198 if e.label=='Class'
199 and e.xarg.access~='private'
200 and not e.xarg.fullname:match'%b<>' then
201 ret[e] = true
204 return ret
207 local fill_virtuals = function(index)
208 local classes = {}
209 for c in pairs(index) do
210 classes[c.xarg.fullname] = c
212 local get_virtuals
213 get_virtuals = function(c)
214 local ret = {}
215 for _, f in ipairs(c) do
216 if f.label=='Function' and f.xarg.virtual=='1' then
217 local n = string.match(f.xarg.name, '~') or f.xarg.name
218 if n~='~' then ret[n] = f end
221 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
222 local base = classes[b]
223 if type(base)=='table' then
224 local bv = get_virtuals(base)
225 for n, f in pairs(bv) do
226 if not ret[n] then ret[n] = f end
230 for _, f in ipairs(c) do
231 if f.label=='Function'
232 and f.xarg.access~='private'
233 and (ret[string.match(f.xarg.name, '~') or f.xarg.name]) then
234 f.xarg.virtual = '1'
235 local n = string.match(f.xarg.name, '~')or f.xarg.name
236 ret[n] = f
239 return ret
241 for c in pairs(index) do
242 c.virtuals = get_virtuals(c)
243 for _, f in pairs(c.virtuals) do
244 if f.xarg.abstract=='1' then c.abstract=true break end
247 return index
250 local distinguish_methods = function(index)
251 for c in pairs(index) do
252 local construct, destruct, normal = {}, nil, {}
253 local n = c.xarg.name
254 local copy = nil
255 for _, f in ipairs(c) do
256 if n==f.xarg.name then
257 table.insert(construct, f)
258 elseif f.xarg.name:match'~' then
259 destruct = f
260 else
261 if (not string.match(f.xarg.name, '^operator%W'))
262 and (not f.xarg.member_template_parameters) then
263 table.insert(normal, f)
267 c.constructors = construct
268 c.destructor = destruct
269 c.methods = normal
271 return index
274 local fill_public_destr = function(index)
275 local classes = {}
276 for c in pairs(index) do
277 classes[c.xarg.fullname] = c
279 local destr_is_public
280 destr_is_public = function(c)
281 if c.destructor then
282 return c.destructor.xarg.access=='public'
283 else
284 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
285 local base = classes[b]
286 if base and not destr_is_public(base) then
287 return false
290 return true
293 for c in pairs(index) do
294 c.public_destr = destr_is_public(c)
296 return index
299 local fill_copy_constructor = function(index)
300 local classes = {}
301 for c in pairs(index) do
302 classes[c.xarg.name] = c
304 for c in pairs(index) do
305 local copy = nil
306 for _, f in ipairs(c.constructors) do
307 if #(f.arguments)==1
308 and f.arguments[1].xarg.type_name==c.xarg.fullname..' const&' then
309 copy = f
310 break
313 c.copy_constructor = copy
315 local copy_constr_is_public
316 copy_constr_is_public = function(c)
317 if c.copy_constructor then
318 return (c.copy_constructor.xarg.access=='public')
319 or (c.copy_constructor.xarg.access=='protected')
320 else
321 local ret = nil
322 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
323 local base = classes[b]
324 if base and not copy_constr_is_public(base) then
325 return false
328 return true
331 for c in pairs(index) do
332 c.public_constr = copy_constr_is_public(c)
334 return index
337 local typesystem_enum_filler = function(enums)
338 local ret = {}
339 for e in pairs(enums) do
340 local en = e.xarg.fullname
341 table.insert(ret, [[
342 types[']]..en..[['] = {
343 push = function(n)
344 return 'lqtL_pushenum(L, '..n..', "]]..en..[[")', 1
345 end,
346 get = function(n)
347 return 'static_cast<]]..en..[[>'
348 ..'(lqtL_toenum(L, '..n..', "]]..en..[["))', 1
349 end,
350 test = function(n)
351 return 'lqtL_isenum(L, '..n..', "]]..en..[[")', 1
352 end,
356 return ret
359 local fill_typesystem_with_enums = function(enums, types)
360 local etype = function(en)
361 return {
362 push = function(n)
363 return 'lqtL_pushenum(L, '..n..', "'..en..'")', 1
364 end,
365 get = function(n)
366 return 'static_cast<'..en..'>'
367 ..'(lqtL_toenum(L, '..n..', "'..en..'"))', 1
368 end,
369 test = function(n)
370 return 'lqtL_isenum(L, '..n..', "'..en..'")', 1
371 end,
374 local ret = {}
375 for e in pairs(enums) do
376 if types[e.xarg.fullname]==nil then
377 ret[e] = true
378 types[e.xarg.fullname] = etype(e.xarg.fullname)
379 else
380 --io.stderr:write(e.xarg.fullname, ': already present\n')
383 return ret
386 local typesystem_class_filler = function(classes)
387 local pointer_t = function(fn)
388 return [[
389 types[']]..fn..[[*'] = {
390 -- the argument is a pointer to class
391 push = function(n)
392 return 'lqtL_passudata(L, '..n..', "]]..fn..[[*")', 1
393 end,
394 get = function(n)
395 return 'static_cast<]]..fn..[[*>'
396 ..'(lqtL_toudata(L, '..n..', "]]..fn..[[*"))', 1
397 end,
398 test = function(n)
399 return 'lqtL_isudata(L, '..n..', "]]..fn..[[*")', 1
400 end,
404 local pointer_const_t = function(fn)
405 return [[
406 types[']]..fn..[[ const*'] = {
407 -- the argument is a pointer to constant class
408 push = function(n)
409 return 'lqtL_passudata(L, '..n..', "]]..fn..[[*")', 1
410 end,
411 get = function(n)
412 return 'static_cast<]]..fn..[[*>'
413 ..'(lqtL_toudata(L, '..n..', "]]..fn..[[*"))', 1
414 end,
415 test = function(n)
416 return 'lqtL_isudata(L, '..n..', "]]..fn..[[*")', 1
417 end,
421 local ref_t = function(fn)
422 return [[
423 types[']]..fn..[[&'] = {
424 -- the argument is a reference to class
425 push = function(n)
426 return 'lqtL_passudata(L, &'..n..', "]]..fn..[[*")', 1
427 end,
428 get = function(n)
429 return '*static_cast<]]..fn..[[*>'
430 ..'(lqtL_toudata(L, '..n..', "]]..fn..[[*"))', 1
431 end,
432 test = function(n)
433 return 'lqtL_isudata(L, '..n..', "]]..fn..[[*")', 1
434 end,
438 local instance_t = function(fn, sn)
439 return [[
440 types[']]..fn..[['] = {
441 -- the argument is a instance of class
442 push = function(n)
443 return 'lqtL_passudata(L, new ]]..sn
444 ..[[(L, '..n..'), "]]..fn..[[*")', 1
445 end,
446 get = function(n)
447 return '*static_cast<]]..fn..[[*>'
448 ..'(lqtL_toudata(L, '..n..', "]]..fn..[[*"))', 1
449 end,
450 test = function(n)
451 return 'lqtL_isudata(L, '..n..', "]]..fn..[[*")', 1
452 end,
456 local const_ref_t = function(fn, sn)
457 return [[
458 types[']]..fn..[[ const&'] = {
459 -- the argument is a constant ref to class
460 push = function(n)
461 return 'lqtL_passudata(L, new ]]..sn
462 ..[[(L, '..n..'), "]]..fn..[[*")', 1
463 end,
464 get = function(n)
465 return '*static_cast<]]..fn..[[*>'
466 ..'(lqtL_toudata(L, '..n..', "]]..fn..[[*"))', 1
467 end,
468 test = function(n)
469 return 'lqtL_isudata(L, '..n..', "]]..fn..[[*")', 1
470 end,
474 local ret = {}
475 for c in pairs(classes) do
476 local ctype = ''
477 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
478 ctype = ctype .. pointer_t(c.xarg.fullname)
479 ctype = ctype .. pointer_const_t(c.xarg.fullname)
480 ctype = ctype .. ref_t(c.xarg.fullname)
481 if c.public_constr and c.shell then
482 ctype = ctype .. instance_t(c.xarg.fullname, shellname)
483 ctype = ctype .. const_ref_t(c.xarg.fullname, shellname)
484 else
485 ctype = ctype .. 'types["'..c.xarg.fullname..'"] = false\n'
487 table.insert(ret, ctype)
489 return ret
492 local fill_typesystem_with_classes = function(classes, types)
493 local pointer_t = function(fn)
494 return {
495 -- the argument is a pointer to class
496 push = function(n)
497 return 'lqtL_passudata(L, '..n..', "'..fn..'*")', 1
498 end,
499 get = function(n)
500 return 'static_cast<'..fn..'*>'
501 ..'(lqtL_toudata(L, '..n..', "'..fn..'*"))', 1
502 end,
503 test = function(n)
504 return 'lqtL_isudata(L, '..n..', "'..fn..'*")', 1
505 end,
508 local pointer_const_t = function(fn)
509 return {
510 -- the argument is a pointer to constant class instance
511 push = function(n)
512 return 'lqtL_passudata(L, '..n..', "'..fn..'*")', 1
513 end,
514 get = function(n)
515 return 'static_cast<'..fn..'*>'
516 ..'(lqtL_toudata(L, '..n..', "'..fn..'*"))', 1
517 end,
518 test = function(n)
519 return 'lqtL_isudata(L, '..n..', "'..fn..'*")', 1
520 end,
523 local ref_t = function(fn)
524 return {
525 -- the argument is a reference to class
526 push = function(n)
527 return 'lqtL_passudata(L, &'..n..', "'..fn..'*")', 1
528 end,
529 get = function(n)
530 return '*static_cast<'..fn..'*>'
531 ..'(lqtL_toudata(L, '..n..', "'..fn..'*"))', 1
532 end,
533 test = function(n)
534 return 'lqtL_isudata(L, '..n..', "'..fn..'*")', 1
535 end,
538 local instance_t = function(fn, sn)
539 return {
540 -- the argument is the class itself
541 push = function(n)
542 return 'lqtL_passudata(L, new '..sn
543 ..'(L, '..n..'), "'..fn..'*")', 1
544 end,
545 get = function(n)
546 return '*static_cast<'..fn..'*>'
547 ..'(lqtL_toudata(L, '..n..', "'..fn..'*"))', 1
548 end,
549 test = function(n)
550 return 'lqtL_isudata(L, '..n..', "'..fn..'*")', 1
551 end,
554 local const_ref_t = function(fn, sn)
555 return {
556 -- the argument is a pointer to class
557 push = function(n)
558 return 'lqtL_passudata(L, new '..sn
559 ..'(L, '..n..'), "'..fn..'*")', 1
560 end,
561 get = function(n)
562 return '*static_cast<'..fn..'*>'
563 ..'(lqtL_toudata(L, '..n..', "'..fn..'*"))', 1
564 end,
565 test = function(n)
566 return 'lqtL_isudata(L, '..n..', "'..fn..'*")', 1
567 end,
570 local ret = {}
571 for c in pairs(classes) do
572 if types[c.xarg.fullname]==nil then
573 ret[c] = true
574 types[c.xarg.fullname..'*'] = pointer_t(c.xarg.fullname)
575 types[c.xarg.fullname..' const*'] = pointer_const_t(c.xarg.fullname)
576 types[c.xarg.fullname..'&'] = ref_t(c.xarg.fullname)
577 if c.public_constr and c.shell then
578 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
579 types[c.xarg.fullname] = instance_t(c.xarg.fullname, shellname)
580 types[c.xarg.fullname..' const&'] = const_ref_t(c.xarg.fullname, shellname)
584 return ret
587 local argument_name = function(tn, an)
588 local ret
589 if string.match(tn, '%(%*%)') then
590 ret = string.gsub(tn, '%(%*%)', '(*'..an..')', 1)
591 elseif string.match(tn, '%[.*%]') then
592 ret = string.gsub(tn, '(%[.*%])', an..'%1')
593 else
594 ret = tn .. ' ' .. an
596 return ret
599 local fill_wrapper_code = function(f, types)
600 if f.wrapper_code then return f end
601 local stackn, argn = 1, 1
602 local wrap, line = ' int oldtop = lua_gettop(L);\n', ''
603 if f.xarg.abstract then return nil end
604 if f.xarg.member_of_class and f.xarg.static~='1' then
605 if not types[f.xarg.member_of_class..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
606 local sget, sn = types[f.xarg.member_of_class..'*'].get(stackn)
607 wrap = wrap .. ' ' .. f.xarg.member_of_class .. '* self = ' .. sget .. ';\n'
608 stackn = stackn + sn
609 wrap = wrap .. [[
610 if (NULL==self) {
611 lua_pushstring(L, "this pointer is NULL");
612 lua_error(L);
615 --print(sget, sn)
616 line = 'self->'..f.xarg.fullname..'('
617 else
618 line = f.xarg.fullname..'('
620 for i, a in ipairs(f.arguments) do
621 if not types[a.xarg.type_name] then return nil end
622 local aget, an, arg_as = types[a.xarg.type_name].get(stackn)
623 wrap = wrap .. ' ' .. argument_name(arg_as or a.xarg.type_name, 'arg'..argn) .. ' = '
624 if a.xarg.default=='1' and an>0 then
625 wrap = wrap .. 'lua_isnoneornil(L, '..stackn..')'
626 for j = stackn+1,stackn+an-1 do
627 wrap = wrap .. ' && lua_isnoneornil(L, '..j..')'
629 local dv = a.xarg.defaultvalue
630 wrap = wrap .. ' ? static_cast< ' .. a.xarg.type_name .. ' >(' .. dv .. ') : '
632 wrap = wrap .. aget .. ';\n'
633 line = line .. (argn==1 and 'arg' or ', arg') .. argn
634 stackn = stackn + an
635 argn = argn + 1
637 line = line .. ')'
638 -- FIXME: hack follows for constructors
639 if f.calling_line then line = f.calling_line end
640 if f.return_type then line = f.return_type .. ' ret = ' .. line end
641 wrap = wrap .. ' ' .. line .. ';\n lua_settop(L, oldtop);\n' -- lua_pop(L, '..stackn..');\n'
642 if f.return_type then
643 if not types[f.return_type] then return nil end
644 local rput, rn = types[f.return_type].push'ret'
645 wrap = wrap .. ' luaL_checkstack(L, '..rn..', "cannot grow stack for return value");\n'
646 wrap = wrap .. ' '..rput..';\n return '..rn..';\n'
647 else
648 wrap = wrap .. ' return 0;\n'
650 f.wrapper_code = wrap
651 return f
654 local fill_test_code = function(f, types)
655 local stackn = 1
656 local test = ''
657 if f.xarg.member_of_class and f.xarg.static~='1' then
658 if not types[f.xarg.member_of_class..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
659 local stest, sn = types[f.xarg.member_of_class..'*'].test(stackn)
660 test = test .. ' && ' .. stest
661 stackn = stackn + sn
663 for i, a in ipairs(f.arguments) do
664 if not types[a.xarg.type_name] then return nil end -- print(a.xarg.type_name) return nil end
665 local atest, an = types[a.xarg.type_name].test(stackn)
666 if a.xarg.default=='1' and an>0 then
667 test = test .. ' && (lqtL_missarg(L, ' .. stackn .. ', ' .. an .. ') || '
668 test = test .. atest .. ')'
669 else
670 test = test .. ' && ' .. atest
672 stackn = stackn + an
674 -- can't make use of default values if I fix number of args
675 test = '(lua_gettop(L)<' .. stackn .. ')' .. test
676 f.test_code = test
677 return f
680 local fill_wrappers = function(functions, types)
681 local ret = {}
682 for f in pairs(functions) do
683 f = fill_wrapper_code(f, types)
684 if f then
685 f = assert(fill_test_code(f, types), f.xarg.fullname) -- MUST pass
686 ret[f] = true
687 --local out = 'extern "C" int lqt_bind'..f.xarg.id..' (lua_State *L) {\n'
688 --.. f.wrapper_code .. '}\n'
689 --print(out)
692 return ret
695 local make_pushlines = function(args, types)
696 local pushlines, stack = '', 0
697 for i, a in ipairs(args) do
698 if not types[a.xarg.type_name] then return nil end
699 local apush, an = types[a.xarg.type_name].push('arg'..i)
700 pushlines = pushlines .. ' ' .. apush .. ';\n'
701 stack = stack + an
703 return pushlines, stack
706 local virtual_overload = function(v, types)
707 local ret = ''
708 if v.virtual_overload then return v end
709 -- make return type
710 if v.return_type and not types[v.return_type] then return nil end
711 local rget, rn = '', 0
712 if v.return_type then rget, rn, ret_as = types[v.return_type].get'oldtop+1' end
713 local retget = (v.return_type and argument_name(ret_as or v.return_type, 'ret')
714 .. ' = ' .. rget .. ';' or '') .. 'lua_settop(L, oldtop);return'
715 .. (v.return_type and ' ret' or '')
716 -- make argument push
717 local pushlines, stack = make_pushlines(v.arguments, types)
718 if not pushlines then return nil end
719 -- make lua call
720 local luacall = 'lua_pcall(L, '..(stack+1)..', '..rn..', 0)'
721 -- make prototype and fallback
722 local proto = (v.return_type or 'void')..' ;;'..v.xarg.name..' ('
723 local fallback = ''
724 for i, a in ipairs(v.arguments) do
725 proto = proto .. (i>1 and ', ' or '')
726 .. argument_name(a.xarg.type_name, 'arg'..i)
727 fallback = fallback .. (i>1 and ', arg' or 'arg') .. i
729 proto = proto .. ')' .. (v.xarg.constant=='1' and ' const' or '')
730 fallback = (v.return_type and 'return this->' or 'this->')
731 .. v.xarg.fullname .. '(' .. fallback .. ');\n}\n'
732 ret = proto .. [[ {
733 int oldtop = lua_gettop(L);
734 lqtL_pushudata(L, this, "]]..v.xarg.member_of_class..[[*");
735 lua_getfield(L, -1, "]]..v.xarg.name..[[");
736 if (lua_isfunction(L, -1)) {
737 lua_insert(L, -2);
738 ]] .. pushlines .. [[
739 if (!]]..luacall..[[) {
740 ]]..retget..[[;
743 lua_settop(L, oldtop);
744 ]] .. fallback
745 v.virtual_overload = ret
746 v.virtual_proto = string.gsub(proto, ';;', '', 1)
747 return v
750 local fill_shell_class = function(c, types)
751 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
752 local shell = 'class ' .. shellname .. ' : public ' .. c.xarg.fullname .. ' {\npublic:\n'
753 shell = shell .. ' lua_State *L;\n'
754 for _, constr in ipairs(c.constructors) do
755 if constr.xarg.access~='private' then
756 local cline = ' '..shellname..' (lua_State *l'
757 local argline = ''
758 for i, a in ipairs(constr.arguments) do
759 cline = cline .. ', ' .. argument_name(a.xarg.type_name, 'arg'..i)
760 argline = argline .. (i>1 and ', arg' or 'arg') .. i
762 cline = cline .. ') : ' .. c.xarg.fullname
763 .. '(' .. argline .. '), L(l) '
764 .. '{ lqtL_register(L, this); }\n'
765 shell = shell .. cline
768 if c.copy_constructor==nil and c.public_constr then
769 local cline = ' '..shellname..' (lua_State *l, '..c.xarg.fullname..' const& arg1)'
770 cline = cline .. ' : ' .. c.xarg.fullname .. '(arg1), L(l) {}\n'
771 shell = shell .. cline
773 for i, v in pairs(c.virtuals) do
774 if v.xarg.access~='private' then
775 if v.virtual_proto then shell = shell .. ' virtual ' .. v.virtual_proto .. ';\n' end
778 shell = shell .. ' ~'..shellname..'() { lqtL_unregister(L, this); }\n'
779 shell = shell .. '};\n'
780 c.shell_class = shell
781 return c
784 local fill_virtual_overloads = function(classes, types)
785 for c in pairs(classes) do
786 for i, v in pairs(c.virtuals) do
787 if v.xarg.access~='private' then
788 local vret = virtual_overload(v, types)
792 return classes
795 local fill_shell_classes = function(classes, types)
796 local ret = {}
797 for c in pairs(classes) do
798 if c.shell then
799 c = fill_shell_class(c, types)
800 if c then ret[c] = true end
802 ret[c] = true
804 return ret
807 local print_shell_classes = function(classes)
808 for c in pairs(classes) do
809 if c.shell then
810 if c then
811 print_head(c.shell_class)
812 else
813 --io.stderr:write(c.fullname, '\n')
817 return classes
820 local print_virtual_overloads = function(classes)
821 for c in pairs(classes) do
822 if c.shell then
823 local vo = ''
824 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
825 for _,v in pairs(c.virtuals) do
826 if v.virtual_overload then
827 vo = vo .. string.gsub(v.virtual_overload, ';;', shellname..'::', 1)
830 c.virtual_overloads = vo
833 return classes
836 local print_wrappers = function(index)
837 for c in pairs(index) do
838 local meta = {}
839 local wrappers = ''
840 for _, f in ipairs(c.methods) do
841 if f.wrapper_code and f.xarg.virtual~='1' then
842 local out = 'static int lqt_bind'..f.xarg.id
843 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
844 if f.xarg.access=='public' then
845 --print_meta(out)
846 wrappers = wrappers .. out .. '\n'
847 meta[f] = f.xarg.name
851 if c.shell then
852 for _, f in ipairs(c.constructors) do
853 if f.wrapper_code then
854 local out = 'static int lqt_bind'..f.xarg.id
855 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
856 if f.xarg.access=='public' then
857 --print_meta(out)
858 wrappers = wrappers .. out .. '\n'
859 meta[f] = 'new'
863 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
864 local out = 'static int lqt_delete'..c.xarg.id..' (lua_State *L) {\n'
865 out = out ..' '..c.xarg.fullname..' *p = static_cast<'
866 ..c.xarg.fullname..'*>(lqtL_toudata(L, 1, "'..c.xarg.fullname..'*"));\n'
867 out = out .. ' if (p) delete p;\n return 0;\n}\n'
868 --print_meta(out)
869 wrappers = wrappers .. out .. '\n'
871 c.meta = meta
872 c.wrappers = wrappers
874 return index
877 local print_metatable = function(c)
878 local methods = {}
879 local wrappers = c.wrappers
880 for m, n in pairs(c.meta) do
881 methods[n] = methods[n] or {}
882 table.insert(methods[n], m)
884 for n, l in pairs(methods) do
885 local disp = 'static int lqt_dispatcher_'..n..c.xarg.id..' (lua_State *L) {\n'
886 for _, f in ipairs(l) do
887 disp = disp..' if ('..f.test_code..') return lqt_bind'..f.xarg.id..'(L);\n'
889 disp = disp .. ' lua_settop(L, 0);\n'
890 disp = disp .. ' lua_pushstring(L, "incorrect or extra arguments");\n'
891 disp = disp .. ' return lua_error(L);\n}\n'
892 --print_meta(disp)
893 wrappers = wrappers .. disp .. '\n'
895 local metatable = 'static luaL_Reg lqt_metatable'..c.xarg.id..'[] = {\n'
896 for n, l in pairs(methods) do
897 metatable = metatable .. ' { "'..n..'", lqt_dispatcher_'..n..c.xarg.id..' },\n'
899 if c.shell then
900 metatable = metatable .. ' { "delete", lqt_delete'..c.xarg.id..' },\n'
902 metatable = metatable .. ' { 0, 0 },\n};\n'
903 --print_meta(metatable)
904 wrappers = wrappers .. metatable .. '\n'
905 local bases = ''
906 for b in string.gmatch(c.xarg.bases or '', '([^;]*);') do
907 bases = bases .. '{"' .. b .. '*"}, '
909 bases = 'static lqt_Base lqt_base'..c.xarg.id..'[] = { '..bases..'{NULL} };\n'
910 --print_meta(bases)
911 wrappers = wrappers .. bases .. '\n'
912 c.wrappers = wrappers
913 return c
916 local print_metatables = function(classes)
917 for c in pairs(classes) do
918 print_metatable(c)
920 return classes
923 local print_class_list = function(classes)
924 local print_meta, n, bytes, list
925 local begin = function()
926 print_meta, n = meta_printer()
927 bytes = 0
928 list = 'static lqt_Class lqt_class_list_'..n..'[] = {\n'
930 local finish = function()
931 list = list .. ' { 0, 0, 0 },\n};\n'
932 .. 'void lqtopen_meta_'..n..' (lua_State *L) {\n'
933 .. ' lqtL_createclasses(L, lqt_class_list_'..n..');\n}'
935 -- begin
936 begin()
937 for c in pairs(classes) do
938 class = '{ lqt_metatable'..c.xarg.id..', lqt_base'..c.xarg.id..', "'..c.xarg.fullname..'*" },\n'
939 list = list .. ' ' .. class
940 bytes = bytes + print_meta(c.wrappers)
941 if c.virtual_overloads then
942 bytes = bytes + print_meta(c.virtual_overloads)
944 if bytes > 300000 then
945 finish()
946 print_meta(list)
947 begin()
950 finish()
951 print_meta(list)
952 for i = 1, n do
953 print_meta('void lqtopen_meta_'..i..'(lua_State *);\n')
955 print_meta([[
957 void lqt_create_enums_]]..module_name..[[(lua_State*);
958 extern "C" int lqt_slot (lua_State *);
960 extern "C" int luaopen_]]..module_name..[[ (lua_State *L) {
961 lqt_create_enums_]]..module_name..[[(L);]])
962 for i = 1, n do
963 print_meta(' lqtopen_meta_'..i..'(L);')
965 print_meta(' lua_pushcfunction(L, lqt_slot);\n lua_setglobal(L, "newslot");\n')
966 print_meta(' return 0;\n}\n')
967 return classes
970 local fix_methods_wrappers = function(classes)
971 for c in pairs(classes) do
972 -- if class seems abstract but has a shell class
973 if c.abstract then
974 -- is it really abstract?
975 local a = false
976 for _, f in pairs(c.virtuals) do
977 -- if it is abstract but we cannot overload
978 -- FIXME: this always fails: f.virtual_overload is not filled yet
979 -- maybe this check must be moved later:
980 -- we don't use shell class to move instances to Lua
981 -- but we want to instantiate if we can wrap all virtuals...
982 if f.xarg.abstract=='1' and not f.virtual_overload then a = true break end
984 c.abstract = a
986 c.shell = (not c.abstract) and c.public_destr
987 for _, constr in ipairs(c.constructors) do
988 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
989 constr.calling_line = '*new '..shellname..'(L'
990 for i=1,#(constr.arguments) do
991 constr.calling_line = constr.calling_line .. ', arg' .. i
993 constr.calling_line = constr.calling_line .. ')'
994 constr.xarg.static = '1'
995 constr.return_type = constr.xarg.type_base..'&'
997 if c.destructor then
998 c.destructor.return_type = nil
1001 return classes
1004 local print_enum_tables = function(enums)
1005 for e in pairs(enums) do
1006 local table = 'static lqt_Enum lqt_enum'..e.xarg.id..'[] = {\n'
1007 --io.stderr:write(e.xarg.fullname, '\t', #e.values, '\n')
1008 for _,v in pairs(e.values) do
1009 table = table .. ' { "' .. v.xarg.name
1010 .. '", static_cast<int>('..v.xarg.fullname..') },\n'
1012 table = table .. ' { 0, 0 }\n'
1013 table = table .. '};\n'
1014 e.enum_table = table
1015 print_enum(table)
1017 return enums
1019 local print_enum_creator = function(enums, n)
1020 local out = 'static lqt_Enumlist lqt_enum_list[] = {\n'
1021 for e in pairs(enums) do
1022 out = out..' { lqt_enum'..e.xarg.id..', "'..e.xarg.fullname..'" },\n'
1024 out = out..' { 0, 0 },\n};\n'
1025 out = out .. 'void lqt_create_enums_'..n..' (lua_State *L) {\n'
1026 out = out .. ' lqtL_createenumlist(L, lqt_enum_list); return;\n}\n'
1027 print_enum(out)
1028 return enums
1031 local copy_signals = function(functions)
1032 local ret = {}
1033 for f in pairs(functions) do
1034 if f.xarg.signal=='1' then
1035 ret[f] = 1
1038 return ret
1041 local slots_for_signals = function(signals, types)
1042 local ret = {}
1043 for sig in pairs(signals) do
1044 local args, comma = '(', ''
1045 for i, a in ipairs(sig.arguments) do
1046 args = args .. comma .. a.xarg.type_name .. ' arg'..i
1047 comma = ', '
1049 args = args .. ')'
1050 local pushlines, stack = make_pushlines(sig.arguments, types)
1051 if not ret['void slot '..args] and pushlines then
1052 ret['void slot '..args] = 'void LqtSlotAcceptor::slot '..args..[[ {
1053 int oldtop = lua_gettop(L);
1054 lqtL_pushudata(L, this, "QObject*");
1055 lua_getfield(L, -1, "slot]]..string.gsub(args, ' arg.', '')..[[");
1056 if (lua_isnil(L, -1)) {
1057 lua_pop(L, 1);
1058 lua_getfield(L, -1, "slot");
1060 if (!lua_isfunction(L, -1)) {
1061 lua_settop(L, oldtop);
1062 return;
1064 lua_insert(L, -2);
1065 ]] .. pushlines .. [[
1066 if (lua_pcall(L, ]]..stack..[[+1, 0, 0)) {
1067 lua_error(L);
1069 lua_settop(L, oldtop);
1074 return ret
1077 local print_slots = function(s)
1078 print_slot_h'class LqtSlotAcceptor : public QObject {'
1079 print_slot_h' Q_OBJECT'
1080 print_slot_h' lua_State *L;'
1081 print_slot_h' public:'
1082 print_slot_h' LqtSlotAcceptor(lua_State *l, QObject *p=NULL) : QObject(p), L(l) { lqtL_register(L, this); }'
1083 print_slot_h' virtual ~LqtSlotAcceptor() { lqtL_unregister(L, this); }'
1084 print_slot_h' public slots:'
1085 for p, b in pairs(s) do
1086 print_slot_h(' '..p..';')
1088 print_slot_h'};\n'
1089 for p, b in pairs(s) do
1090 print_slot_c(b)
1092 print_slot_c[[
1094 extern "C" int lqt_slot (lua_State *L) {
1095 QObject *parent = static_cast<QObject*>(lqtL_toudata(L, 1, "QObject*"));
1096 lqtL_passudata(L, new LqtSlotAcceptor(L, parent), "QObject*");
1097 return 1;
1103 --------------------------------------------------------------------------------------
1105 local typesystem = {}
1107 local ts = {}
1108 for i, ft in ipairs(typefiles) do
1109 ts = loadfile(ft)(ts)
1111 setmetatable(typesystem, {
1112 __newindex = function(t, k, v)
1113 --debug('added type', k)
1114 ts[k] = v
1115 end,
1116 __index = function(t, k)
1117 local ret = ts[k]
1118 --if not ret then debug("unknown type:", tostring(k), ret) end
1119 return ret
1120 end,
1124 fix_arguments(idindex) -- fixes default arguments if they are context-relative
1125 local functions = copy_functions(idindex) -- picks functions and fixes label
1126 local functions = fix_functions(functions) -- fixes name and fullname and fills arguments
1128 local enums = copy_enums(idindex) -- picks enums if public
1129 local enums = fill_enums(enums) -- fills field "values"
1131 local classes = copy_classes(idindex) -- picks classes if not private and not blacklisted
1132 local classes = fill_virtuals(classes) -- does that, destructor ("~") excluded
1133 local classes = distinguish_methods(classes) -- does that
1134 local classes = fill_public_destr(classes) -- does that: checks if destructor is public
1135 local classes = fill_copy_constructor(classes) -- does that: checks if copy contructor is public or protected
1136 local classes = fix_methods_wrappers(classes)
1138 for _, f in ipairs(filterfiles) do
1139 classes, enums = loadfile(f)(classes, enums)
1142 local enums = fill_typesystem_with_enums(enums, typesystem) -- does that
1143 local classes = fill_typesystem_with_classes(classes, typesystem)
1145 local functions = fill_wrappers(functions, typesystem)
1146 local classes = fill_virtual_overloads(classes, typesystem) -- does that
1147 local classes = fill_shell_classes(classes, typesystem) -- does that
1149 local signals = copy_signals(functions)
1150 local slots = slots_for_signals(signals, typesystem)
1153 ------------- BEGIN OUTPUT
1156 print_head('#ifndef LQT_BIND_'..module_name)
1157 print_head('#define LQT_BIND_'..module_name)
1158 print_head()
1159 print_head()
1160 for _, i in ipairs(output_includes) do
1161 print_head('#include '..i)
1163 print_head()
1165 print_enum('#include "'..module_name..'_head.hpp'..'"\n\n')
1166 print_slot_h('#include "'..module_name..'_head.hpp'..'"\n\n')
1167 print_slot_c('#include "'..module_name..'_slot.hpp'..'"\n\n')
1169 print_type'local types = ... or {}\n'
1170 for i, v in ipairs(typesystem_enum_filler(enums)) do
1171 print_type(v)
1173 for i, v in ipairs(typesystem_class_filler(classes)) do
1174 print_type(v)
1176 print_type'return types\n'
1178 local classes = print_shell_classes(classes) -- does that
1179 local classes = print_virtual_overloads(classes, typesystem) -- does that
1180 local enums = print_enum_tables(enums) -- does that
1181 local enums = print_enum_creator(enums, module_name) -- does that + print enum list
1182 local classes = print_wrappers(classes) -- just compiles metatable list
1183 local classes = print_metatables(classes) -- just collects the wrappers + generates dispatchers
1184 local classes = print_class_list(classes) -- does that + prints everything related to class
1186 local slots = print_slots(slots)
1188 --print_openmodule(module_name) -- does that
1190 print_head('#endif // LQT_BIND_'..module_name)