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_virt
= fprint(assert(io
.open(module_name
..'_src/'..module_name
..'_virt.cpp', 'w')))
84 local print_type
= fprint(assert(io
.open(module_name
..'_src/'..module_name
..'_type.lua', 'w')))
89 meta_printer
= function()
91 local f
= assert(io
.open(module_name
..'_src/'..module_name
..'_meta_'..n
..'.cpp', 'w'))
92 f
:write('#include "'..module_name
..'_head.hpp'..'"\n\n\n')
107 local xmlstream
, idindex
= dofile(path
..'xml.lua')(readfile(filename
))
109 ----------------------------------------------------------------------------------
111 local copy_functions
= function(index
)
113 for e
in pairs(index
) do
114 if e
.label
:match
'^Function' then
123 local fix_arguments
= function(all
)
125 for e
in pairs(all
or {}) do
126 if e
.xarg
.fullname
then fullnames
[e
.xarg
.fullname
] = true end
128 for a
in pairs(all
) do
129 if a
.label
=='Argument'
130 and a
.xarg
.default
=='1'
131 and string.match(a
.xarg
.defaultvalue
, '%D') then
132 local dv
= a
.xarg
.defaultvalue
133 if not fullnames
[dv
] then
134 dv
= a
.xarg
.context
..'::'..dv
136 if fullnames
[dv
] then
137 a
.xarg
.defaultvalue
= dv
140 a
.xarg
.defaultvalue
= nil
147 local fix_functions
= function(index
)
148 for f
in pairs(index
) do
150 for i
, a
in ipairs(f
) do
151 -- avoid bogus 'void' arguments
152 if a
.xarg
.type_name
=='void' and i
==1 and f
[2]==nil then break end
153 if a
.label
=='Argument' then
154 table.insert(args
, a
)
158 f
.return_type
= f
.xarg
.type_name
159 if f
.xarg
.type_name
=='void' then
166 local copy_enums
= function(index
)
168 for e
in pairs(index
) do
170 and not string.match(e
.xarg
.fullname
, '%b<>')
171 and e
.xarg
.access
=='public' then
178 local fill_enums
= function(index
)
179 for e
in pairs(index
) do
181 for _
, v
in ipairs(e
) do
182 if v
.label
=='Enumerator' then
183 table.insert(values
, v
)
191 local copy_classes
= function(index
)
193 for e
in pairs(index
) do
195 and e
.xarg
.access
~='private'
196 and not (e
.xarg
.fullname
:match
'%b<>'
197 or e
.xarg
.fullname
=='QDebug::Stream'
198 or e
.xarg
.fullname
=='QForeachContainerBase'
199 or e
.xarg
.fullname
=='QByteArray::Data'
200 or e
.xarg
.fullname
=='QVariant::Private::Data'
201 or e
.xarg
.fullname
=='QRegion::QRegionData'
202 or e
.xarg
.fullname
=='QTextStreamManipulator'
203 or e
.xarg
.fullname
=='QString::Data'
204 or e
.xarg
.fullname
=='QThreadStorageData'
212 local fill_virtuals
= function(index
)
214 for c
in pairs(index
) do
215 classes
[c
.xarg
.fullname
] = c
218 get_virtuals
= function(c
)
220 for _
, f
in ipairs(c
) do
221 if f
.label
=='Function' and f
.xarg
.virtual
=='1' then
222 local n
= string.match(f
.xarg
.name
, '~') or f
.xarg
.name
223 if n
~='~' then ret
[n
] = f
end
226 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
227 local base
= classes
[b
]
228 if type(base
)=='table' then
229 local bv
= get_virtuals(base
)
230 for n
, f
in pairs(bv
) do
231 if not ret
[n
] then ret
[n
] = f
end
235 for _
, f
in ipairs(c
) do
236 if f
.label
=='Function'
237 and f
.xarg
.access
~='private'
238 and (ret
[string.match(f
.xarg
.name
, '~') or f
.xarg
.name
]) then
240 local n
= string.match(f
.xarg
.name
, '~')or f
.xarg
.name
246 for c
in pairs(index
) do
247 c
.virtuals
= get_virtuals(c
)
248 for _
, f
in pairs(c
.virtuals
) do
249 if f
.xarg
.abstract
=='1' then c
.abstract
=true break end
255 local distinguish_methods
= function(index
)
256 for c
in pairs(index
) do
257 local construct
, destruct
, normal
= {}, nil, {}
258 local n
= c
.xarg
.name
260 for _
, f
in ipairs(c
) do
261 if n
==f
.xarg
.name
then
262 table.insert(construct
, f
)
263 elseif f
.xarg
.name
:match
'~' then
266 if (not string.match(f
.xarg
.name
, '^operator%W'))
267 and (not f
.xarg
.member_template_parameters
) then
268 table.insert(normal
, f
)
272 c
.constructors
= construct
273 c
.destructor
= destruct
279 local fill_public_destr
= function(index
)
281 for c
in pairs(index
) do
282 classes
[c
.xarg
.fullname
] = c
284 local destr_is_public
285 destr_is_public
= function(c
)
287 return c
.destructor
.xarg
.access
=='public'
289 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
290 local base
= classes
[b
]
291 if base
and not destr_is_public(base
) then
298 for c
in pairs(index
) do
299 c
.public_destr
= destr_is_public(c
)
304 local fill_copy_constructor
= function(index
)
306 for c
in pairs(index
) do
307 classes
[c
.xarg
.name
] = c
309 for c
in pairs(index
) do
311 for _
, f
in ipairs(c
.constructors
) do
313 and f
.arguments
[1].xarg
.type_name
==c
.xarg
.fullname
..' const&' then
318 c
.copy_constructor
= copy
320 local copy_constr_is_public
321 copy_constr_is_public
= function(c
)
322 if c
.copy_constructor
then
323 return (c
.copy_constructor
.xarg
.access
=='public')
324 or (c
.copy_constructor
.xarg
.access
=='protected')
327 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
328 local base
= classes
[b
]
329 if base
and not copy_constr_is_public(base
) then
336 for c
in pairs(index
) do
337 c
.public_constr
= copy_constr_is_public(c
)
342 local typesystem_enum_filler
= function(enums
)
344 for e
in pairs(enums
) do
345 local en
= e
.xarg
.fullname
347 types[']]..en
..[['] = {
349 return 'lqtL_pushenum(L, '..n..', "]]..en
..[[")', 1
352 return 'static_cast<]]..en
..[[>'
353 ..'(lqtL_toenum(L, '..n..', "]]..en
..[["))', 1
356 return 'lqtL_isenum(L, '..n..', "]]..en
..[[")', 1
364 local fill_typesystem_with_enums
= function(enums
, types
)
365 local etype
= function(en
)
368 return 'lqtL_pushenum(L, '..n
..', "'..en
..'")', 1
371 return 'static_cast<'..en
..'>'
372 ..'(lqtL_toenum(L, '..n
..', "'..en
..'"))', 1
375 return 'lqtL_isenum(L, '..n
..', "'..en
..'")', 1
380 for e
in pairs(enums
) do
381 if types
[e
.xarg
.fullname
]==nil then
383 types
[e
.xarg
.fullname
] = etype(e
.xarg
.fullname
)
385 --io.stderr:write(e.xarg.fullname, ': already present\n')
391 local typesystem_class_filler
= function(classes
)
392 local pointer_t
= function(fn
)
394 types[']]..fn
..[[*'] = {
395 -- the argument is a pointer to class
397 return 'lqtL_passudata(L, '..n..', "]]..fn
..[[*")', 1
400 return 'static_cast<]]..fn
..[[*>'
401 ..'(lqtL_toudata(L, '..n..', "]]..fn
..[[*"))', 1
404 return 'lqtL_isudata(L, '..n..', "]]..fn
..[[*")', 1
409 local pointer_const_t
= function(fn
)
411 types[']]..fn
..[[ const*'] = {
412 -- the argument is a pointer to constant class
414 return 'lqtL_passudata(L, '..n..', "]]..fn
..[[*")', 1
417 return 'static_cast<]]..fn
..[[*>'
418 ..'(lqtL_toudata(L, '..n..', "]]..fn
..[[*"))', 1
421 return 'lqtL_isudata(L, '..n..', "]]..fn
..[[*")', 1
426 local ref_t
= function(fn
)
428 types[']]..fn
..[[&'] = {
429 -- the argument is a reference to class
431 return 'lqtL_passudata(L, &'..n..', "]]..fn
..[[*")', 1
434 return '*static_cast<]]..fn
..[[*>'
435 ..'(lqtL_toudata(L, '..n..', "]]..fn
..[[*"))', 1
438 return 'lqtL_isudata(L, '..n..', "]]..fn
..[[*")', 1
443 local instance_t
= function(fn
, sn
)
445 types[']]..fn
..[['] = {
446 -- the argument is a instance of class
448 return 'lqtL_passudata(L, new ]]..sn
449 ..[[(L, '..n..'), "]]..fn
..[[*")', 1
452 return '*static_cast<]]..fn
..[[*>'
453 ..'(lqtL_toudata(L, '..n..', "]]..fn
..[[*"))', 1
456 return 'lqtL_isudata(L, '..n..', "]]..fn
..[[*")', 1
461 local const_ref_t
= function(fn
, sn
)
463 types[']]..fn
..[[ const&'] = {
464 -- the argument is a constant ref to class
466 return 'lqtL_passudata(L, new ]]..sn
467 ..[[(L, '..n..'), "]]..fn
..[[*")', 1
470 return '*static_cast<]]..fn
..[[*>'
471 ..'(lqtL_toudata(L, '..n..', "]]..fn
..[[*"))', 1
474 return 'lqtL_isudata(L, '..n..', "]]..fn
..[[*")', 1
480 for c
in pairs(classes
) do
482 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
483 ctype
= ctype
.. pointer_t(c
.xarg
.fullname
)
484 ctype
= ctype
.. pointer_const_t(c
.xarg
.fullname
)
485 ctype
= ctype
.. ref_t(c
.xarg
.fullname
)
486 if c
.public_constr
and c
.shell
then
487 ctype
= ctype
.. instance_t(c
.xarg
.fullname
, shellname
)
488 ctype
= ctype
.. const_ref_t(c
.xarg
.fullname
, shellname
)
490 ctype
= ctype
.. 'types["'..c
.xarg
.fullname
..'"] = false\n'
492 table.insert(ret
, ctype
)
497 local fill_typesystem_with_classes
= function(classes
, types
)
498 local pointer_t
= function(fn
)
500 -- the argument is a pointer to class
502 return 'lqtL_passudata(L, '..n
..', "'..fn
..'*")', 1
505 return 'static_cast<'..fn
..'*>'
506 ..'(lqtL_toudata(L, '..n
..', "'..fn
..'*"))', 1
509 return 'lqtL_isudata(L, '..n
..', "'..fn
..'*")', 1
513 local pointer_const_t
= function(fn
)
515 -- the argument is a pointer to constant class instance
517 return 'lqtL_passudata(L, '..n
..', "'..fn
..'*")', 1
520 return 'static_cast<'..fn
..'*>'
521 ..'(lqtL_toudata(L, '..n
..', "'..fn
..'*"))', 1
524 return 'lqtL_isudata(L, '..n
..', "'..fn
..'*")', 1
528 local ref_t
= function(fn
)
530 -- the argument is a reference to class
532 return 'lqtL_passudata(L, &'..n
..', "'..fn
..'*")', 1
535 return '*static_cast<'..fn
..'*>'
536 ..'(lqtL_toudata(L, '..n
..', "'..fn
..'*"))', 1
539 return 'lqtL_isudata(L, '..n
..', "'..fn
..'*")', 1
543 local instance_t
= function(fn
, sn
)
545 -- the argument is the class itself
547 return 'lqtL_passudata(L, new '..sn
548 ..'(L, '..n
..'), "'..fn
..'*")', 1
551 return '*static_cast<'..fn
..'*>'
552 ..'(lqtL_toudata(L, '..n
..', "'..fn
..'*"))', 1
555 return 'lqtL_isudata(L, '..n
..', "'..fn
..'*")', 1
559 local const_ref_t
= function(fn
, sn
)
561 -- the argument is a pointer to class
563 return 'lqtL_passudata(L, new '..sn
564 ..'(L, '..n
..'), "'..fn
..'*")', 1
567 return '*static_cast<'..fn
..'*>'
568 ..'(lqtL_toudata(L, '..n
..', "'..fn
..'*"))', 1
571 return 'lqtL_isudata(L, '..n
..', "'..fn
..'*")', 1
576 for c
in pairs(classes
) do
577 if types
[c
.xarg
.fullname
]==nil then
579 types
[c
.xarg
.fullname
..'*'] = pointer_t(c
.xarg
.fullname
)
580 types
[c
.xarg
.fullname
..' const*'] = pointer_const_t(c
.xarg
.fullname
)
581 types
[c
.xarg
.fullname
..'&'] = ref_t(c
.xarg
.fullname
)
582 if c
.public_constr
and c
.shell
then
583 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
584 types
[c
.xarg
.fullname
] = instance_t(c
.xarg
.fullname
, shellname
)
585 types
[c
.xarg
.fullname
..' const&'] = const_ref_t(c
.xarg
.fullname
, shellname
)
592 local argument_name
= function(tn
, an
)
594 if string.match(tn
, '%(%*%)') then
595 ret
= string.gsub(tn
, '%(%*%)', '(*'..an
..')', 1)
596 elseif string.match(tn
, '%[.*%]') then
597 ret
= string.gsub(tn
, '(%[.*%])', an
..'%1')
599 ret
= tn
.. ' ' .. an
604 local fill_wrapper_code
= function(f
, types
)
605 if f
.wrapper_code
then return f
end
606 local stackn
, argn
= 1, 1
607 local wrap
, line
= ' int oldtop = lua_gettop(L);\n', ''
608 if f
.xarg
.abstract
then return nil end
609 if f
.xarg
.member_of_class
and f
.xarg
.static
~='1' then
610 if not types
[f
.xarg
.member_of_class
..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
611 local sget
, sn
= types
[f
.xarg
.member_of_class
..'*'].get(stackn
)
612 wrap
= wrap
.. ' ' .. f
.xarg
.member_of_class
.. '* self = ' .. sget
.. ';\n'
616 lua_pushstring(L, "this pointer is NULL");
621 line
= 'self->'..f
.xarg
.fullname
..'('
623 line
= f
.xarg
.fullname
..'('
625 for i
, a
in ipairs(f
.arguments
) do
626 if not types
[a
.xarg
.type_name
] then return nil end
627 local aget
, an
, arg_as
= types
[a
.xarg
.type_name
].get(stackn
)
628 wrap
= wrap
.. ' ' .. argument_name(arg_as
or a
.xarg
.type_name
, 'arg'..argn
) .. ' = '
629 if a
.xarg
.default
=='1' and an
>0 then
630 wrap
= wrap
.. 'lua_isnoneornil(L, '..stackn
..')'
631 for j
= stackn
+1,stackn
+an
-1 do
632 wrap
= wrap
.. ' && lua_isnoneornil(L, '..j
..')'
634 local dv
= a
.xarg
.defaultvalue
635 wrap
= wrap
.. ' ? static_cast< ' .. a
.xarg
.type_name
.. ' >(' .. dv
.. ') : '
637 wrap
= wrap
.. aget
.. ';\n'
638 line
= line
.. (argn
==1 and 'arg' or ', arg') .. argn
643 -- FIXME: hack follows for constructors
644 if f
.calling_line
then line
= f
.calling_line
end
645 if f
.return_type
then line
= f
.return_type
.. ' ret = ' .. line
end
646 wrap
= wrap
.. ' ' .. line
.. ';\n lua_settop(L, oldtop);\n' -- lua_pop(L, '..stackn..');\n'
647 if f
.return_type
then
648 if not types
[f
.return_type
] then return nil end
649 local rput
, rn
= types
[f
.return_type
].push
'ret'
650 wrap
= wrap
.. ' luaL_checkstack(L, '..rn
..', "cannot grow stack for return value");\n'
651 wrap
= wrap
.. ' '..rput
..';\n return '..rn
..';\n'
653 wrap
= wrap
.. ' return 0;\n'
655 f
.wrapper_code
= wrap
659 local fill_test_code
= function(f
, types
)
662 if f
.xarg
.member_of_class
and f
.xarg
.static
~='1' then
663 if not types
[f
.xarg
.member_of_class
..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
664 local stest
, sn
= types
[f
.xarg
.member_of_class
..'*'].test(stackn
)
665 test
= test
.. ' && ' .. stest
668 for i
, a
in ipairs(f
.arguments
) do
669 if not types
[a
.xarg
.type_name
] then return nil end -- print(a.xarg.type_name) return nil end
670 local atest
, an
= types
[a
.xarg
.type_name
].test(stackn
)
671 if a
.xarg
.default
=='1' and an
>0 then
672 test
= test
.. ' && (lqtL_missarg(L, ' .. stackn
.. ', ' .. an
.. ') || '
673 test
= test
.. atest
.. ')'
675 test
= test
.. ' && ' .. atest
679 -- can't make use of default values if I fix number of args
680 test
= '(lua_gettop(L)<' .. stackn
.. ')' .. test
685 local fill_wrappers
= function(functions
, types
)
687 for f
in pairs(functions
) do
688 f
= fill_wrapper_code(f
, types
)
690 f
= assert(fill_test_code(f
, types
), f
.xarg
.fullname
) -- MUST pass
692 --local out = 'extern "C" int lqt_bind'..f.xarg.id..' (lua_State *L) {\n'
693 --.. f.wrapper_code .. '}\n'
700 local virtual_overload
= function(v
, types
)
702 if v
.virtual_overload
then return v
end
704 if v
.return_type
and not types
[v
.return_type
] then return nil end
705 local rget
, rn
= '', 0
706 if v
.return_type
then rget
, rn
, ret_as
= types
[v
.return_type
].get
'oldtop+1' end
707 local retget
= (v
.return_type
and argument_name(ret_as
or v
.return_type
, 'ret')
708 .. ' = ' .. rget
.. ';' or '') .. 'lua_settop(L, oldtop);return'
709 .. (v
.return_type
and ' ret' or '')
710 -- make argument push
711 local pushlines
, stack
= '', 0
712 for i
, a
in ipairs(v
.arguments
) do
713 if not types
[a
.xarg
.type_name
] then return nil end
714 local apush
, an
= types
[a
.xarg
.type_name
].push('arg'..i
)
715 pushlines
= pushlines
.. ' ' .. apush
.. ';\n'
719 local luacall
= 'lua_pcall(L, '..(stack
+1)..', '..rn
..', 0)'
720 -- make prototype and fallback
721 local proto
= (v
.return_type
or 'void')..' ;;'..v
.xarg
.name
..' ('
723 for i
, a
in ipairs(v
.arguments
) do
724 proto
= proto
.. (i
>1 and ', ' or '')
725 .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
726 fallback
= fallback
.. (i
>1 and ', arg' or 'arg') .. i
728 proto
= proto
.. ')' .. (v
.xarg
.constant
=='1' and ' const' or '')
729 fallback
= (v
.return_type
and 'return this->' or 'this->')
730 .. v
.xarg
.fullname
.. '(' .. fallback
.. ');\n}\n'
732 int oldtop = lua_gettop(L);
733 lqtL_pushudata(L, this, "]]..v
.xarg
.member_of_class
..[[*");
734 lua_getfield(L, -1, "]]..v
.xarg
.name
..[[");
735 if (lua_isfunction(L, -1)) {
737 ]] .. pushlines
.. [[
738 if (!]]..luacall
..[[) {
742 lua_settop(L, oldtop);
744 v
.virtual_overload
= ret
745 v
.virtual_proto
= string.gsub(proto
, ';;', '', 1)
749 local fill_shell_class
= function(c
, types
)
750 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
751 local shell
= 'class ' .. shellname
.. ' : public ' .. c
.xarg
.fullname
.. ' {\npublic:\n'
752 shell
= shell
.. ' lua_State *L;\n'
753 for _
, constr
in ipairs(c
.constructors
) do
754 if constr
.xarg
.access
~='private' then
755 local cline
= ' '..shellname
..' (lua_State *l'
757 for i
, a
in ipairs(constr
.arguments
) do
758 cline
= cline
.. ', ' .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
759 argline
= argline
.. (i
>1 and ', arg' or 'arg') .. i
761 cline
= cline
.. ') : ' .. c
.xarg
.fullname
762 .. '(' .. argline
.. '), L(l) '
763 .. '{ lqtL_register(L, this); }\n'
764 shell
= shell
.. cline
767 if c
.copy_constructor
==nil and c
.public_constr
then
768 local cline
= ' '..shellname
..' (lua_State *l, '..c
.xarg
.fullname
..' const& arg1)'
769 cline
= cline
.. ' : ' .. c
.xarg
.fullname
.. '(arg1), L(l) {}\n'
770 shell
= shell
.. cline
772 for i
, v
in pairs(c
.virtuals
) do
773 if v
.xarg
.access
~='private' then
774 if v
.virtual_proto
then shell
= shell
.. ' virtual ' .. v
.virtual_proto
.. ';\n' end
777 shell
= shell
.. ' ~'..shellname
..'() { lqtL_unregister(L, this); }\n'
778 shell
= shell
.. '};\n'
779 c
.shell_class
= shell
783 local fill_virtual_overloads
= function(classes
, types
)
784 for c
in pairs(classes
) do
785 for i
, v
in pairs(c
.virtuals
) do
786 if v
.xarg
.access
~='private' then
787 local vret
= virtual_overload(v
, types
)
794 local fill_shell_classes
= function(classes
, types
)
796 for c
in pairs(classes
) do
798 c
= fill_shell_class(c
, types
)
799 if c
then ret
[c
] = true end
806 local print_shell_classes
= function(classes
)
807 for c
in pairs(classes
) do
810 print_head(c
.shell_class
)
812 --io.stderr:write(c.fullname, '\n')
819 local print_virtual_overloads
= function(classes
)
820 for c
in pairs(classes
) do
822 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
823 for _
,v
in pairs(c
.virtuals
) do
824 if v
.virtual_overload
then
825 print_virt((string.gsub(v
.virtual_overload
, ';;', shellname
..'::', 1)))
833 local print_wrappers
= function(index
)
834 for c
in pairs(index
) do
837 for _
, f
in ipairs(c
.methods
) do
838 if f
.wrapper_code
then
839 local out
= 'static int lqt_bind'..f
.xarg
.id
840 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
841 if f
.xarg
.access
=='public' then
843 wrappers
= wrappers
.. out
.. '\n'
844 meta
[f
] = f
.xarg
.name
849 for _
, f
in ipairs(c
.constructors
) do
850 if f
.wrapper_code
then
851 local out
= 'static int lqt_bind'..f
.xarg
.id
852 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
853 if f
.xarg
.access
=='public' then
855 wrappers
= wrappers
.. out
.. '\n'
860 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
861 local out
= 'static int lqt_delete'..c
.xarg
.id
..' (lua_State *L) {\n'
862 out
= out
..' '..c
.xarg
.fullname
..' *p = static_cast<'
863 ..c
.xarg
.fullname
..'*>(lqtL_toudata(L, 1, "'..c
.xarg
.fullname
..'*"));\n'
864 out
= out
.. ' if (p) delete p;\n return 0;\n}\n'
866 wrappers
= wrappers
.. out
.. '\n'
869 c
.wrappers
= wrappers
874 local print_metatable
= function(c
)
876 local wrappers
= c
.wrappers
877 for m
, n
in pairs(c
.meta
) do
878 methods
[n
] = methods
[n
] or {}
879 table.insert(methods
[n
], m
)
881 for n
, l
in pairs(methods
) do
882 local disp
= 'static int lqt_dispatcher_'..n
..c
.xarg
.id
..' (lua_State *L) {\n'
883 for _
, f
in ipairs(l
) do
884 disp
= disp
..' if ('..f
.test_code
..') return lqt_bind'..f
.xarg
.id
..'(L);\n'
886 disp
= disp
.. ' lua_settop(L, 0);\n'
887 disp
= disp
.. ' lua_pushstring(L, "incorrect or extra arguments");\n'
888 disp
= disp
.. ' return lua_error(L);\n}\n'
890 wrappers
= wrappers
.. disp
.. '\n'
892 local metatable
= 'static luaL_Reg lqt_metatable'..c
.xarg
.id
..'[] = {\n'
893 for n
, l
in pairs(methods
) do
894 metatable
= metatable
.. ' { "'..n
..'", lqt_dispatcher_'..n
..c
.xarg
.id
..' },\n'
897 metatable
= metatable
.. ' { "delete", lqt_delete'..c
.xarg
.id
..' },\n'
899 metatable
= metatable
.. ' { 0, 0 },\n};\n'
900 --print_meta(metatable)
901 wrappers
= wrappers
.. metatable
.. '\n'
903 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]*);') do
904 bases
= bases
.. '{"' .. b
.. '*"}, '
906 bases
= 'static lqt_Base lqt_base'..c
.xarg
.id
..'[] = { '..bases
..'{NULL} };\n'
908 wrappers
= wrappers
.. bases
.. '\n'
909 c
.wrappers
= wrappers
913 local print_metatables
= function(classes
)
914 for c
in pairs(classes
) do
920 local print_class_list
= function(classes
)
921 local print_meta
, n
, lines
, list
922 local begin
= function()
923 print_meta
, n
= meta_printer()
925 list
= 'static lqt_Class lqt_class_list_'..n
..'[] = {\n'
927 local finish
= function()
928 list
= list
.. ' { 0, 0, 0 },\n};\n'
929 .. 'void lqtopen_meta_'..n
..' (lua_State *L) {\n'
930 .. ' lqtL_createclasses(L, lqt_class_list_'..n
..');\n}'
934 for c
in pairs(classes
) do
935 class
= '{ lqt_metatable'..c
.xarg
.id
..', lqt_base'..c
.xarg
.id
..', "'..c
.xarg
.fullname
..'*" },\n'
936 list
= list
.. ' ' .. class
937 lines
= lines
+ print_meta(c
.wrappers
)
938 if lines
> 100000 then
947 print_meta('void lqtopen_meta_'..i
..'(lua_State *);\n')
951 void lqt_create_enums_]]..module_name
..[[(lua_State*);
953 extern "C" int luaopen_]]..module_name
..[[ (lua_State *L) {
954 lqt_create_enums_]]..module_name
..[[(L);]])
956 print_meta(' lqtopen_meta_'..i
..'(L);')
958 print_meta(' return 0;\n}\n')
962 local fix_methods_wrappers
= function(classes
)
963 for c
in pairs(classes
) do
964 -- if class seems abstract but has a shell class
966 -- is it really abstract?
968 for _
, f
in pairs(c
.virtuals
) do
969 -- if it is abstract but we cannot overload
970 -- FIXME: this always fails: f.virtual_overload is not filled yet
971 -- maybe this check must be moved later:
972 -- we don't use shell class to move instances to Lua
973 -- but we want to instantiate if we can wrap all virtuals...
974 if f
.xarg
.abstract
=='1' and not f
.virtual_overload
then a
= true break end
978 c
.shell
= (not c
.abstract
) and c
.public_destr
979 for _
, constr
in ipairs(c
.constructors
) do
980 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
981 constr
.calling_line
= '*new '..shellname
..'(L'
982 for i
=1,#(constr
.arguments
) do
983 constr
.calling_line
= constr
.calling_line
.. ', arg' .. i
985 constr
.calling_line
= constr
.calling_line
.. ')'
986 constr
.xarg
.static
= '1'
987 constr
.return_type
= constr
.xarg
.type_base
..'&'
990 c
.destructor
.return_type
= nil
996 local print_enum_tables
= function(enums
)
997 for e
in pairs(enums
) do
998 local table = 'static lqt_Enum lqt_enum'..e
.xarg
.id
..'[] = {\n'
999 --io.stderr:write(e.xarg.fullname, '\t', #e.values, '\n')
1000 for _
,v
in pairs(e
.values
) do
1001 table = table .. ' { "' .. v
.xarg
.name
1002 .. '", static_cast<int>('..v
.xarg
.fullname
..') },\n'
1004 table = table .. ' { 0, 0 }\n'
1005 table = table .. '};\n'
1006 e
.enum_table
= table
1011 local print_enum_creator
= function(enums
, n
)
1012 local out
= 'static lqt_Enumlist lqt_enum_list[] = {\n'
1013 for e
in pairs(enums
) do
1014 out
= out
..' { lqt_enum'..e
.xarg
.id
..', "'..e
.xarg
.fullname
..'" },\n'
1016 out
= out
..' { 0, 0 },\n};\n'
1017 out
= out
.. 'void lqt_create_enums_'..n
..' (lua_State *L) {\n'
1018 out
= out
.. ' lqtL_createenumlist(L, lqt_enum_list); return;\n}\n'
1023 --------------------------------------------------------------------------------------
1025 local typesystem
= {}
1028 for i
, ft
in ipairs(typefiles
) do
1029 ts
= loadfile(ft
)(ts
)
1031 setmetatable(typesystem
, {
1032 __newindex
= function(t
, k
, v
)
1033 --debug('added type', k)
1036 __index
= function(t
, k
)
1038 --if not ret then debug("unknown type:", tostring(k), ret) end
1044 fix_arguments(idindex
) -- fixes default arguments if they are context-relative
1045 local functions
= copy_functions(idindex
) -- picks functions and fixes label
1046 local functions
= fix_functions(functions
) -- fixes name and fullname and fills arguments
1048 local enums
= copy_enums(idindex
) -- picks enums if public
1049 local enums
= fill_enums(enums
) -- fills field "values"
1051 local classes
= copy_classes(idindex
) -- picks classes if not private and not blacklisted
1052 local classes
= fill_virtuals(classes
) -- does that, destructor ("~") excluded
1053 local classes
= distinguish_methods(classes
) -- does that
1054 local classes
= fill_public_destr(classes
) -- does that: checks if destructor is public
1055 local classes
= fill_copy_constructor(classes
) -- does that: checks if copy contructor is public or protected
1056 local classes
= fix_methods_wrappers(classes
)
1058 for _
, f
in ipairs(filterfiles
) do
1059 classes
, enums
= loadfile(f
)(classes
, enums
)
1062 local enums
= fill_typesystem_with_enums(enums
, typesystem
) -- does that
1063 local classes
= fill_typesystem_with_classes(classes
, typesystem
)
1065 local functions
= fill_wrappers(functions
, typesystem
)
1066 local classes
= fill_virtual_overloads(classes
, typesystem
) -- does that
1067 local classes
= fill_shell_classes(classes
, typesystem
) -- does that
1070 ------------- BEGIN OUTPUT
1073 print_head('#ifndef LQT_BIND_'..module_name
)
1074 print_head('#define LQT_BIND_'..module_name
)
1077 for _
, i
in ipairs(output_includes
) do
1078 print_head('#include '..i
)
1082 print_enum('#include "'..module_name
..'_head.hpp'..'"\n\n')
1083 print_virt('#include "'..module_name
..'_head.hpp'..'"\n\n')
1085 print_type
'local types = ... or {}\n'
1086 for i
, v
in ipairs(typesystem_enum_filler(enums
)) do
1089 for i
, v
in ipairs(typesystem_class_filler(classes
)) do
1092 print_type
'return types\n'
1094 local classes
= print_shell_classes(classes
) -- does that
1095 local classes
= print_virtual_overloads(classes
, typesystem
) -- does that
1096 local enums
= print_enum_tables(enums
) -- does that
1097 local enums
= print_enum_creator(enums
, module_name
) -- does that + print enum list
1098 local classes
= print_wrappers(classes
) -- does that + compiles metatable list
1099 local classes
= print_metatables(classes
) -- does that + print dispatchers
1100 local classes
= print_class_list(classes
) -- does that
1102 --print_openmodule(module_name) -- does that
1104 print_head('#endif // LQT_BIND_'..module_name
)