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
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.
30 local path
= string.match(arg
[0], '(.*/)[^%/]+') or ''
33 local module_name
= nil
35 local filterfiles
= {}
36 local output_includes
= {
42 while select(i
, ...) do
43 local argi
= select(i
, ...)
46 module_name
= select(i
, ...)
47 elseif argi
=='-i' then
49 table.insert(output_includes
, (select(i
, ...)))
50 elseif argi
=='-t' then
52 table.insert(typefiles
, (select(i
, ...)))
53 elseif argi
=='-f' then
55 table.insert(filterfiles
, (select(i
, ...)))
57 filename
= filename
and error'duplicate filename' or argi
63 local readfile
= function(fn
)
64 local f
= assert(io
.open(fn
))
70 local fprint
= function(f
)
72 for i
= 1, select('#',...) do
73 f
:write((i
==1) and '' or '\t', tostring(select(i
,...)))
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')))
90 meta_printer
= function()
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')
108 local xmlstream
, idindex
= dofile(path
..'xml.lua')(readfile(filename
))
110 ----------------------------------------------------------------------------------
112 local copy_functions
= function(index
)
114 for e
in pairs(index
) do
115 if e
.label
:match
'^Function' then
124 local fix_arguments
= function(all
)
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
144 a
.xarg
.defaultvalue
= nil
151 local fix_functions
= function(index
)
152 for f
in pairs(index
) do
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
)
162 f
.return_type
= f
.xarg
.type_name
163 if f
.xarg
.type_name
=='void' then
170 local copy_enums
= function(index
)
172 for e
in pairs(index
) do
174 and not string.match(e
.xarg
.fullname
, '%b<>')
175 and e
.xarg
.access
=='public' then
182 local fill_enums
= function(index
)
183 for e
in pairs(index
) do
185 for _
, v
in ipairs(e
) do
186 if v
.label
=='Enumerator' then
187 table.insert(values
, v
)
195 local copy_classes
= function(index
)
197 for e
in pairs(index
) do
199 and e
.xarg
.access
~='private'
200 and not e
.xarg
.fullname
:match
'%b<>' then
207 local fill_virtuals
= function(index
)
209 for c
in pairs(index
) do
210 classes
[c
.xarg
.fullname
] = c
213 get_virtuals
= function(c
)
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
235 local n
= string.match(f
.xarg
.name
, '~')or f
.xarg
.name
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
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
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
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
274 local fill_public_destr
= function(index
)
276 for c
in pairs(index
) do
277 classes
[c
.xarg
.fullname
] = c
279 local destr_is_public
280 destr_is_public
= function(c
)
282 return c
.destructor
.xarg
.access
=='public'
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
293 for c
in pairs(index
) do
294 c
.public_destr
= destr_is_public(c
)
299 local fill_copy_constructor
= function(index
)
301 for c
in pairs(index
) do
302 classes
[c
.xarg
.name
] = c
304 for c
in pairs(index
) do
306 for _
, f
in ipairs(c
.constructors
) do
308 and f
.arguments
[1].xarg
.type_name
==c
.xarg
.fullname
..' const&' then
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')
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
331 for c
in pairs(index
) do
332 c
.public_constr
= copy_constr_is_public(c
)
337 local typesystem_enum_filler
= function(enums
)
339 for e
in pairs(enums
) do
340 local en
= e
.xarg
.fullname
342 types[']]..en
..[['] = {
344 return 'lqtL_pushenum(L, '..n..', "]]..en
..[[")', 1
347 return 'static_cast<]]..en
..[[>'
348 ..'(lqtL_toenum(L, '..n..', "]]..en
..[["))', 1
351 return 'lqtL_isenum(L, '..n..', "]]..en
..[[")', 1
359 local fill_typesystem_with_enums
= function(enums
, types
)
360 local etype
= function(en
)
363 return 'lqtL_pushenum(L, '..n
..', "'..en
..'")', 1
366 return 'static_cast<'..en
..'>'
367 ..'(lqtL_toenum(L, '..n
..', "'..en
..'"))', 1
370 return 'lqtL_isenum(L, '..n
..', "'..en
..'")', 1
375 for e
in pairs(enums
) do
376 if types
[e
.xarg
.fullname
]==nil then
378 types
[e
.xarg
.fullname
] = etype(e
.xarg
.fullname
)
380 --io.stderr:write(e.xarg.fullname, ': already present\n')
386 local typesystem_class_filler
= function(classes
)
387 local pointer_t
= function(fn
)
389 types[']]..fn
..[[*'] = {
390 -- the argument is a pointer to class
392 return 'lqtL_passudata(L, '..n..', "]]..fn
..[[*")', 1
395 return 'static_cast<]]..fn
..[[*>'
396 ..'(lqtL_toudata(L, '..n..', "]]..fn
..[[*"))', 1
399 return 'lqtL_isudata(L, '..n..', "]]..fn
..[[*")', 1
404 local pointer_const_t
= function(fn
)
406 types[']]..fn
..[[ const*'] = {
407 -- the argument is a pointer to constant class
409 return 'lqtL_passudata(L, '..n..', "]]..fn
..[[*")', 1
412 return 'static_cast<]]..fn
..[[*>'
413 ..'(lqtL_toudata(L, '..n..', "]]..fn
..[[*"))', 1
416 return 'lqtL_isudata(L, '..n..', "]]..fn
..[[*")', 1
421 local ref_t
= function(fn
)
423 types[']]..fn
..[[&'] = {
424 -- the argument is a reference to class
426 return 'lqtL_passudata(L, &'..n..', "]]..fn
..[[*")', 1
429 return '*static_cast<]]..fn
..[[*>'
430 ..'(lqtL_toudata(L, '..n..', "]]..fn
..[[*"))', 1
433 return 'lqtL_isudata(L, '..n..', "]]..fn
..[[*")', 1
438 local instance_t
= function(fn
, sn
)
440 types[']]..fn
..[['] = {
441 -- the argument is a instance of class
443 return 'lqtL_passudata(L, new ]]..sn
444 ..[[(L, '..n..'), "]]..fn
..[[*")', 1
447 return '*static_cast<]]..fn
..[[*>'
448 ..'(lqtL_toudata(L, '..n..', "]]..fn
..[[*"))', 1
451 return 'lqtL_isudata(L, '..n..', "]]..fn
..[[*")', 1
456 local const_ref_t
= function(fn
, sn
)
458 types[']]..fn
..[[ const&'] = {
459 -- the argument is a constant ref to class
461 return 'lqtL_passudata(L, new ]]..sn
462 ..[[(L, '..n..'), "]]..fn
..[[*")', 1
465 return '*static_cast<]]..fn
..[[*>'
466 ..'(lqtL_toudata(L, '..n..', "]]..fn
..[[*"))', 1
469 return 'lqtL_isudata(L, '..n..', "]]..fn
..[[*")', 1
475 for c
in pairs(classes
) do
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
)
485 ctype
= ctype
.. 'types["'..c
.xarg
.fullname
..'"] = false\n'
487 table.insert(ret
, ctype
)
492 local fill_typesystem_with_classes
= function(classes
, types
)
493 local pointer_t
= function(fn
)
495 -- the argument is a pointer to class
497 return 'lqtL_passudata(L, '..n
..', "'..fn
..'*")', 1
500 return 'static_cast<'..fn
..'*>'
501 ..'(lqtL_toudata(L, '..n
..', "'..fn
..'*"))', 1
504 return 'lqtL_isudata(L, '..n
..', "'..fn
..'*")', 1
508 local pointer_const_t
= function(fn
)
510 -- the argument is a pointer to constant class instance
512 return 'lqtL_passudata(L, '..n
..', "'..fn
..'*")', 1
515 return 'static_cast<'..fn
..'*>'
516 ..'(lqtL_toudata(L, '..n
..', "'..fn
..'*"))', 1
519 return 'lqtL_isudata(L, '..n
..', "'..fn
..'*")', 1
523 local ref_t
= function(fn
)
525 -- the argument is a reference to class
527 return 'lqtL_passudata(L, &'..n
..', "'..fn
..'*")', 1
530 return '*static_cast<'..fn
..'*>'
531 ..'(lqtL_toudata(L, '..n
..', "'..fn
..'*"))', 1
534 return 'lqtL_isudata(L, '..n
..', "'..fn
..'*")', 1
538 local instance_t
= function(fn
, sn
)
540 -- the argument is the class itself
542 return 'lqtL_passudata(L, new '..sn
543 ..'(L, '..n
..'), "'..fn
..'*")', 1
546 return '*static_cast<'..fn
..'*>'
547 ..'(lqtL_toudata(L, '..n
..', "'..fn
..'*"))', 1
550 return 'lqtL_isudata(L, '..n
..', "'..fn
..'*")', 1
554 local const_ref_t
= function(fn
, sn
)
556 -- the argument is a pointer to class
558 return 'lqtL_passudata(L, new '..sn
559 ..'(L, '..n
..'), "'..fn
..'*")', 1
562 return '*static_cast<'..fn
..'*>'
563 ..'(lqtL_toudata(L, '..n
..', "'..fn
..'*"))', 1
566 return 'lqtL_isudata(L, '..n
..', "'..fn
..'*")', 1
571 for c
in pairs(classes
) do
572 if types
[c
.xarg
.fullname
]==nil then
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
)
587 local argument_name
= function(tn
, an
)
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')
594 ret
= tn
.. ' ' .. an
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'
611 lua_pushstring(L, "this pointer is NULL");
616 line
= 'self->'..f
.xarg
.fullname
..'('
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
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'
648 wrap
= wrap
.. ' return 0;\n'
650 f
.wrapper_code
= wrap
654 local fill_test_code
= function(f
, types
)
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
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
.. ')'
670 test
= test
.. ' && ' .. atest
674 -- can't make use of default values if I fix number of args
675 test
= '(lua_gettop(L)<' .. stackn
.. ')' .. test
680 local fill_wrappers
= function(functions
, types
)
682 for f
in pairs(functions
) do
683 f
= fill_wrapper_code(f
, types
)
685 f
= assert(fill_test_code(f
, types
), f
.xarg
.fullname
) -- MUST pass
687 --local out = 'extern "C" int lqt_bind'..f.xarg.id..' (lua_State *L) {\n'
688 --.. f.wrapper_code .. '}\n'
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'
703 return pushlines
, stack
706 local virtual_overload
= function(v
, types
)
708 if v
.virtual_overload
then return v
end
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
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
..' ('
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'
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)) {
738 ]] .. pushlines
.. [[
739 if (!]]..luacall
..[[) {
743 lua_settop(L, oldtop);
745 v
.virtual_overload
= ret
746 v
.virtual_proto
= string.gsub(proto
, ';;', '', 1)
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'
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
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
)
795 local fill_shell_classes
= function(classes
, types
)
797 for c
in pairs(classes
) do
799 c
= fill_shell_class(c
, types
)
800 if c
then ret
[c
] = true end
807 local print_shell_classes
= function(classes
)
808 for c
in pairs(classes
) do
811 print_head(c
.shell_class
)
813 --io.stderr:write(c.fullname, '\n')
820 local print_virtual_overloads
= function(classes
)
821 for c
in pairs(classes
) do
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
836 local print_wrappers
= function(index
)
837 for c
in pairs(index
) do
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
846 wrappers
= wrappers
.. out
.. '\n'
847 meta
[f
] = f
.xarg
.name
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
858 wrappers
= wrappers
.. out
.. '\n'
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'
869 wrappers
= wrappers
.. out
.. '\n'
872 c
.wrappers
= wrappers
877 local print_metatable
= function(c
)
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'
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'
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'
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'
911 wrappers
= wrappers
.. bases
.. '\n'
912 c
.wrappers
= wrappers
916 local print_metatables
= function(classes
)
917 for c
in pairs(classes
) do
923 local print_class_list
= function(classes
)
924 local print_meta
, n
, bytes
, list
925 local begin
= function()
926 print_meta
, n
= meta_printer()
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}'
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
953 print_meta('void lqtopen_meta_'..i
..'(lua_State *);\n')
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);]])
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')
970 local fix_methods_wrappers
= function(classes
)
971 for c
in pairs(classes
) do
972 -- if class seems abstract but has a shell class
974 -- is it really abstract?
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
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
..'&'
998 c
.destructor
.return_type
= nil
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
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'
1031 local copy_signals
= function(functions
)
1033 for f
in pairs(functions
) do
1034 if f
.xarg
.signal
=='1' then
1041 local slots_for_signals
= function(signals
, types
)
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
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)) {
1058 lua_getfield(L, -1, "slot");
1060 if (!lua_isfunction(L, -1)) {
1061 lua_settop(L, oldtop);
1065 ]] .. pushlines
.. [[
1066 if (lua_pcall(L, ]]..stack
..[[+1, 0, 0)) {
1069 lua_settop(L, oldtop);
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
..';')
1089 for p
, b
in pairs(s
) do
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*");
1103 --------------------------------------------------------------------------------------
1105 local typesystem
= {}
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)
1116 __index
= function(t
, k
)
1118 --if not ret then debug("unknown type:", tostring(k), ret) 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
)
1160 for _
, i
in ipairs(output_includes
) do
1161 print_head('#include '..i
)
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
1173 for i
, v
in ipairs(typesystem_class_filler(classes
)) do
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
)