5 Copyright (c) 2007-2009 Mauro Iazzi
6 Copyright (c) 2008 Peter Kümmel
8 Permission is hereby granted, free of charge, to any person
9 obtaining a copy of this software and associated documentation
10 files (the "Software"), to deal in the Software without
11 restriction, including without limitation the rights to use,
12 copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the
14 Software is furnished to do so, subject to the following
17 The above copyright notice and this permission notice shall be
18 included in all copies or substantial portions of the Software.
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 OTHER DEALINGS IN THE SOFTWARE.
31 local osseparator
= package
.config
:sub(1,1)
33 local path
= string.match(arg
[0], '(.*'..osseparator
..')[^%'..osseparator
..']+') or ''
35 --- remove script name
36 path
= string.sub(arg
[0], 1, #arg
[0] - #'generator.lua')
41 local module_name
= nil
43 local filterfiles
= {}
44 local output_includes
= {
50 while select(i
, ...) do
51 local argi
= select(i
, ...)
54 module_name
= select(i
, ...)
55 elseif argi
=='-i' then
57 table.insert(output_includes
, (select(i
, ...)))
58 elseif argi
=='-t' then
60 table.insert(typefiles
, (select(i
, ...)))
61 elseif argi
=='-f' then
63 table.insert(filterfiles
, (select(i
, ...)))
65 filename
= filename
and error'duplicate filename' or argi
71 local my_includes
= ''
72 for _
, i
in ipairs(output_includes
) do
73 if string.match(i
, '^<.+>$') then
74 my_includes
= my_includes
.. '#include '..i
..'\n'
75 elseif string.match(i
, '^".+"$') then
76 my_includes
= my_includes
.. '#include '..i
..'\n'
78 my_includes
= my_includes
.. '#include "'..i
..'"\n'
81 output_includes
= my_includes
.. '\n'
83 local readfile
= function(fn
)
84 local f
= assert(io
.open(fn
))
90 local fprint
= function(f
)
92 for i
= 1, select('#',...) do
93 f
:write((i
==1) and '' or '\t', tostring(select(i
,...)))
100 local _src
= '_src'..osseparator
101 local debug
= fprint(io
.stderr
)
102 local print_enum
= fprint(assert(io
.open(module_name
.._src
..module_name
..'_enum.cpp', 'w')))
103 local print_slot_h
= fprint(assert(io
.open(module_name
.._src
..module_name
..'_slot.hpp', 'w')))
104 local print_slot_c
= fprint(assert(io
.open(module_name
.._src
..module_name
..'_slot.cpp', 'w')))
106 local xmlstream
, idindex
= dofile(path
..'xml.lua')(readfile(filename
))
108 dofile(path
..'classes.lua') -- this should become a require at some point
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*[L]?$'))
133 and (not string.match(a
.xarg
.defaultvalue
, '^".*"$'))
134 and a
.xarg
.defaultvalue
~='true'
135 and a
.xarg
.defaultvalue
~='false'
136 and (not string.match(a
.xarg
.defaultvalue
, '^0[xX]%d+$')) then
137 local dv
, call = string.match(a
.xarg
.defaultvalue
, '(.-)(%(%))')
138 dv
= dv
or a
.xarg
.defaultvalue
140 local context
= a
.xarg
.context
141 while not fullnames
[context
..'::'..dv
] and context
~='' do
142 context
= string.match(context
, '^(.*)::') or ''
144 if fullnames
[context
..'::'..dv
] then
145 a
.xarg
.defaultvalue
= context
..'::'..dv
..call
146 elseif fullnames
[dv
] then
147 a
.xarg
.defaultvalue
= dv
..call
150 a
.xarg
.defaultvalue
= nil
157 local fix_functions
= function(index
)
158 for f
in pairs(index
) do
160 for i
, a
in ipairs(f
) do
161 -- avoid bogus 'void' arguments
162 if a
.xarg
.type_name
=='void' and i
==1 and f
[2]==nil then break end
163 if a
.label
=='Argument' then
164 table.insert(args
, a
)
168 f
.return_type
= f
.xarg
.type_name
169 if f
.xarg
.type_name
=='void' then
176 local copy_enums
= function(index
)
178 for e
in pairs(index
) do
180 and not string.match(e
.xarg
.fullname
, '%b<>')
181 and e
.xarg
.access
=='public' then
188 local fill_enums
= function(index
)
189 for e
in pairs(index
) do
191 for _
, v
in ipairs(e
) do
192 if v
.label
=='Enumerator' then
193 table.insert(values
, v
)
201 local class_is_public
= function (fullnames
, c
)
203 if c
.xarg
.access
~='public' then return false end
204 if c
.xarg
.member_of_class
then
205 local p
= fullnames
[c
.xarg
.member_of_class
]
206 assert(p
, 'member_of_class should exist')
207 assert(p
.label
=='Class', 'member_of_class should be a class')
208 c
= fullnames
[c
.xarg
.member_of_class
]
216 local copy_classes
= function(index
)
219 for k
,v
in pairs(index
) do
220 if k
.label
=='Class' then fullnames
[k
.xarg
.fullname
] = k
end
222 for e
in pairs(index
) do
224 and class_is_public(fullnames
, e
)
225 and not e
.xarg
.fullname
:match
'%b<>' then
227 elseif e
.label
=='Class'
228 and not e
.xarg
.fullname
:match
'%b<>' then
229 --print('class', e.xarg.fullname, 'rejected because not public')
235 local get_qobjects
= function(index
)
237 for c
in pairs(index
) do
238 classes
[c
.xarg
.fullname
] = c
241 is_qobject
= function(c
)
242 if c
==nil then return false end
243 if c
.qobject
then return true end
244 if c
.xarg
.fullname
=='QObject' then
248 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
249 local base
= classes
[b
]
250 if is_qobject(base
) then
251 --debug(c.xarg.fullname, "is a QObject")
258 for c
in pairs(index
) do
259 local qobj
= is_qobject(c
)
264 local fill_virtuals
= function(index
)
266 for c
in pairs(index
) do
267 classes
[c
.xarg
.fullname
] = c
270 get_virtuals
= function(c
)
272 for _
, f
in ipairs(c
) do
273 if f
.label
=='Function' and f
.xarg
.virtual
=='1' then
274 local n
= string.match(f
.xarg
.name
, '~') or f
.xarg
.name
275 if n
~='~' and n
~='metaObject' then ret
[n
] = f
end
278 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
279 local base
= classes
[b
]
280 if type(base
)=='table' then
281 local bv
= get_virtuals(base
)
282 for n
, f
in pairs(bv
) do
283 if not ret
[n
] then ret
[n
] = f
end
287 for _
, f
in ipairs(c
) do
288 if f
.label
=='Function'
289 and f
.xarg
.access
~='private'
290 and (ret
[string.match(f
.xarg
.name
, '~') or f
.xarg
.name
]) then
292 local n
= string.match(f
.xarg
.name
, '~')or f
.xarg
.name
298 for c
in pairs(index
) do
299 c
.virtuals
= get_virtuals(c
)
300 for _
, f
in pairs(c
.virtuals
) do
301 if f
.xarg
.abstract
=='1' then c
.abstract
=true break end
307 local distinguish_methods
= function(index
)
308 for c
in pairs(index
) do
309 local construct
, destruct
, normal
= {}, nil, {}
310 local n
= c
.xarg
.name
312 for _
, f
in ipairs(c
) do
313 if n
==f
.xarg
.name
then
314 table.insert(construct
, f
)
315 elseif f
.xarg
.name
:match
'~' then
318 if (not string.match(f
.xarg
.name
, '^operator%W'))
319 and (not f
.xarg
.member_template_parameters
) then
320 table.insert(normal
, f
)
324 c
.constructors
= construct
325 c
.destructor
= destruct
331 local fill_public_destr
= function(index
)
333 for c
in pairs(index
) do
334 classes
[c
.xarg
.fullname
] = c
336 local destr_is_public
337 destr_is_public
= function(c
)
339 return c
.destructor
.xarg
.access
=='public'
341 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
342 local base
= classes
[b
]
343 if base
and not destr_is_public(base
) then
350 for c
in pairs(index
) do
351 c
.public_destr
= destr_is_public(c
)
356 local fill_copy_constructor
= function(index
)
358 for c
in pairs(index
) do
359 classes
[c
.xarg
.name
] = c
361 for c
in pairs(index
) do
363 for _
, f
in ipairs(c
.constructors
) do
365 and f
.arguments
[1].xarg
.type_name
==c
.xarg
.fullname
..' const&' then
370 c
.copy_constructor
= copy
372 local copy_constr_is_public
373 copy_constr_is_public
= function(c
)
374 if c
.copy_constructor
then
375 return (c
.copy_constructor
.xarg
.access
=='public')
376 or (c
.copy_constructor
.xarg
.access
=='protected')
379 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
380 local base
= classes
[b
]
381 if base
and not copy_constr_is_public(base
) then
388 for c
in pairs(index
) do
389 c
.public_constr
= copy_constr_is_public(c
)
394 local fill_typesystem_with_enums
= function(enums
, types
)
395 local etype
= function(en
)
398 return 'lqtL_pushenum(L, '..n
..', "'..string.gsub(en
, '::', '.')..'")', 1
401 return 'static_cast<'..en
..'>'
402 ..'(lqtL_toenum(L, '..n
..', "'..string.gsub(en
, '::', '.')..'"))', 1
405 return 'lqtL_isenum(L, '..n
..', "'..string.gsub(en
, '::', '.')..'")', 1
407 onstack
= string.gsub(en
, '::', '.')..',',
411 for e
in pairs(enums
) do
412 if types
[e
.xarg
.fullname
]==nil then
414 types
[e
.xarg
.fullname
] = etype(e
.xarg
.fullname
)
416 --io.stderr:write(e.xarg.fullname, ': already present\n')
422 local put_class_in_filesystem
= lqt
.classes
.insert
423 local fill_typesystem_with_classes
= function(classes
, types
)
425 for c
in pairs(classes
) do
426 ret
[c
] = put_class_in_filesystem(c
.xarg
.fullname
, types
) --, true)
431 local argument_name
= function(tn
, an
)
433 if string.match(tn
, '%(%*%)') then
434 ret
= string.gsub(tn
, '%(%*%)', '(*'..an
..')', 1)
435 elseif string.match(tn
, '%[.*%]') then
436 ret
= string.gsub(tn
, '%s*(%[.*%])', ' '..an
..'%1')
438 ret
= tn
.. ' ' .. an
443 local fill_wrapper_code
= function(f
, types
)
444 if f
.wrapper_code
then return f
end
445 local stackn
, argn
= 1, 1
446 local stack_args
, defects
= '', 0
447 local wrap
, line
= ' int oldtop = lua_gettop(L);\n', ''
448 if f
.xarg
.abstract
then return nil end
449 if f
.xarg
.member_of_class
and f
.xarg
.static
~='1' then
450 if not types
[f
.xarg
.member_of_class
..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
451 stack_args
= stack_args
.. types
[f
.xarg
.member_of_class
..'*'].onstack
452 defects
= defects
+ 7 -- FIXME: arbitrary
453 if f
.xarg
.constant
=='1' then
454 defects
= defects
+ 8 -- FIXME: arbitrary
456 local sget
, sn
= types
[f
.xarg
.member_of_class
..'*'].get(stackn
)
457 wrap
= wrap
.. ' ' .. f
.xarg
.member_of_class
.. '* self = ' .. sget
.. ';\n'
461 lua_pushstring(L, "this pointer is NULL");
466 line
= 'self->'..f
.xarg
.fullname
..'('
468 line
= f
.xarg
.fullname
..'('
470 for i
, a
in ipairs(f
.arguments
) do
471 if not types
[a
.xarg
.type_name
] then return nil end
472 local aget
, an
, arg_as
= types
[a
.xarg
.type_name
].get(stackn
)
473 stack_args
= stack_args
.. types
[a
.xarg
.type_name
].onstack
474 if types
[a
.xarg
.type_name
].defect
then defects
= defects
+ types
[a
.xarg
.type_name
].defect
end
475 wrap
= wrap
.. ' ' .. argument_name(arg_as
or a
.xarg
.type_name
, 'arg'..argn
) .. ' = '
476 if a
.xarg
.default
=='1' and an
>0 then
477 wrap
= wrap
.. 'lua_isnoneornil(L, '..stackn
..')'
478 for j
= stackn
+1,stackn
+an
-1 do
479 wrap
= wrap
.. ' && lua_isnoneornil(L, '..j
..')'
481 local dv
= a
.xarg
.defaultvalue
482 wrap
= wrap
.. ' ? static_cast< ' .. a
.xarg
.type_name
.. ' >(' .. dv
.. ') : '
484 wrap
= wrap
.. aget
.. ';\n'
485 line
= line
.. (argn
==1 and 'arg' or ', arg') .. argn
490 -- FIXME: hack follows for constructors
491 if f
.calling_line
then line
= f
.calling_line
end
492 if f
.return_type
then line
= f
.return_type
.. ' ret = ' .. line
end
493 wrap
= wrap
.. ' ' .. line
.. ';\n lua_settop(L, oldtop);\n' -- lua_pop(L, '..stackn..');\n'
494 if f
.return_type
then
495 if not types
[f
.return_type
] then return nil end
496 local rput
, rn
= types
[f
.return_type
].push
'ret'
497 wrap
= wrap
.. ' luaL_checkstack(L, '..rn
..', "cannot grow stack for return value");\n'
498 wrap
= wrap
.. ' '..rput
..';\n return '..rn
..';\n'
500 wrap
= wrap
.. ' return 0;\n'
502 f
.wrapper_code
= wrap
503 f
.stack_arguments
= stack_args
508 local fill_test_code
= function(f
, types
)
511 if f
.xarg
.member_of_class
and f
.xarg
.static
~='1' then
512 if not types
[f
.xarg
.member_of_class
..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
513 local stest
, sn
= types
[f
.xarg
.member_of_class
..'*'].test(stackn
)
514 test
= test
.. ' && ' .. stest
517 for i
, a
in ipairs(f
.arguments
) do
518 if not types
[a
.xarg
.type_name
] then return nil end -- print(a.xarg.type_name) return nil end
519 local atest
, an
= types
[a
.xarg
.type_name
].test(stackn
)
520 if a
.xarg
.default
=='1' and an
>0 then
521 test
= test
.. ' && (lqtL_missarg(L, ' .. stackn
.. ', ' .. an
.. ') || '
522 test
= test
.. atest
.. ')'
524 test
= test
.. ' && ' .. atest
528 -- can't make use of default values if I fix number of args
529 test
= '(lua_gettop(L)<' .. stackn
.. ')' .. test
534 local fill_wrappers
= function(functions
, types
)
536 for f
in pairs(functions
) do
537 f
= fill_wrapper_code(f
, types
)
539 f
= assert(fill_test_code(f
, types
), f
.xarg
.fullname
) -- MUST pass
541 --local out = 'extern "C" LQT_EXPORT int lqt_bind'..f.xarg.id..' (lua_State *L) {\n'
542 --.. f.wrapper_code .. '}\n'
549 local make_pushlines
= function(args
, types
)
550 local pushlines
, stack
= '', 0
551 for i
, a
in ipairs(args
) do
552 if not types
[a
.xarg
.type_name
] then return nil end
553 local apush
, an
= types
[a
.xarg
.type_name
].push('arg'..i
)
554 pushlines
= pushlines
.. ' ' .. apush
.. ';\n'
557 return pushlines
, stack
560 local virtual_overload
= function(v
, types
)
562 if v
.virtual_overload
then return v
end
564 if v
.return_type
and not types
[v
.return_type
] then return nil end
565 local rget
, rn
= '', 0
566 if v
.return_type
then rget
, rn
, ret_as
= types
[v
.return_type
].get
'oldtop+1' end
567 local retget
= (v
.return_type
and argument_name(ret_as
or v
.return_type
, 'ret')
568 .. ' = ' .. rget
.. ';' or '') .. 'lua_settop(L, oldtop);return'
569 .. (v
.return_type
and ' ret' or '')
570 -- make argument push
571 local pushlines
, stack
= make_pushlines(v
.arguments
, types
)
572 if not pushlines
then return nil end
574 local luacall
= 'lqtL_pcall(L, '..(stack
+1)..', '..rn
..', 0)'
575 -- make prototype and fallback
576 local proto
= (v
.return_type
or 'void')..' ;;'..v
.xarg
.name
..' ('
578 for i
, a
in ipairs(v
.arguments
) do
579 proto
= proto
.. (i
>1 and ', ' or '')
580 .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
581 fallback
= fallback
.. (i
>1 and ', arg' or 'arg') .. i
583 proto
= proto
.. ')' .. (v
.xarg
.constant
=='1' and ' const' or '')
584 fallback
= (v
.return_type
and 'return this->' or 'this->')
585 .. v
.xarg
.fullname
.. '(' .. fallback
.. ');\n}\n'
587 int oldtop = lua_gettop(L);
588 lqtL_pushudata(L, this, "]]..string.gsub(v
.xarg
.member_of_class
, '::', '.')..[[*");
589 lqtL_getoverload(L, -1, "]]..v
.xarg
.name
..[[");
590 if (lua_isfunction(L, -1)) {
592 ]] .. pushlines
.. [[
593 if (!]]..luacall
..[[) {
597 lua_settop(L, oldtop);
599 v
.virtual_overload
= ret
600 v
.virtual_proto
= string.gsub(proto
, ';;', '', 1)
604 local fill_shell_class
= function(c
, types
)
605 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
606 local shell
= 'class LQT_EXPORT ' .. shellname
.. ' : public ' .. c
.xarg
.fullname
.. ' {\npublic:\n'
607 shell
= shell
.. ' lua_State *L;\n'
608 for _
, constr
in ipairs(c
.constructors
) do
609 if constr
.xarg
.access
~='private' then
610 local cline
= ' '..shellname
..' (lua_State *l'
612 for i
, a
in ipairs(constr
.arguments
) do
613 cline
= cline
.. ', ' .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
614 argline
= argline
.. (i
>1 and ', arg' or 'arg') .. i
616 cline
= cline
.. ') : ' .. c
.xarg
.fullname
617 .. '(' .. argline
.. '), L(l) '
618 .. '{ lqtL_register(L, this); }\n'
619 shell
= shell
.. cline
622 if c
.copy_constructor
==nil and c
.public_constr
then
623 local cline
= ' '..shellname
..' (lua_State *l, '..c
.xarg
.fullname
..' const& arg1)'
624 cline
= cline
.. ' : ' .. c
.xarg
.fullname
.. '(arg1), L(l) {}\n'
625 shell
= shell
.. cline
627 for i
, v
in pairs(c
.virtuals
) do
628 if v
.xarg
.access
~='private' then
629 if v
.virtual_proto
then shell
= shell
.. ' virtual ' .. v
.virtual_proto
.. ';\n' end
632 shell
= shell
.. ' ~'..shellname
..'() { lqtL_unregister(L, this); }\n'
633 if c
.shell
and c
.qobject
then
634 shell
= shell
.. ' static QMetaObject staticMetaObject;\n'
635 shell
= shell
.. ' virtual const QMetaObject *metaObject() const;\n'
636 shell
= shell
.. ' virtual int qt_metacall(QMetaObject::Call, int, void **);\n'
637 shell
= shell
.. 'private:\n'
638 shell
= shell
.. ' Q_DISABLE_COPY('..shellname
..');\n'
640 shell
= shell
.. '};\n'
641 c
.shell_class
= shell
645 local fill_virtual_overloads
= function(classes
, types
)
646 for c
in pairs(classes
) do
647 for i
, v
in pairs(c
.virtuals
) do
648 if v
.xarg
.access
~='private' then
649 local vret
= virtual_overload(v
, types
)
656 local fill_shell_classes
= function(classes
, types
)
658 for c
in pairs(classes
) do
660 c
= fill_shell_class(c
, types
)
661 if c
then ret
[c
] = true end
668 local print_shell_classes
= function(classes
)
670 for c
in pairs(classes
) do
671 if fhead
then fhead
:close() end
672 local n
= string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
673 fhead
= assert(io
.open(module_name
.._src
..module_name
..'_head_'..n
..'.hpp', 'w'))
674 local print_head
= function(...)
678 print_head('#ifndef LQT_HEAD_'..n
)
679 print_head('#define LQT_HEAD_'..n
)
680 print_head(output_includes
)
681 --print_head('#include <'..string.match(c.xarg.fullname, '^[^:]+')..'>')
685 print_head(c
.shell_class
)
687 --io.stderr:write(c.fullname, '\n')
690 print_head('#endif // LQT_HEAD_'..n
)
692 if fhead
then fhead
:close() end
696 local print_virtual_overloads
= function(classes
)
697 for c
in pairs(classes
) do
700 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
701 for _
,v
in pairs(c
.virtuals
) do
702 if v
.virtual_overload
then
703 vo
= vo
.. string.gsub(v
.virtual_overload
, ';;', shellname
..'::', 1)
706 c
.virtual_overloads
= vo
712 local print_wrappers
= function(index
)
713 for c
in pairs(index
) do
716 for _
, f
in ipairs(c
.methods
) do
717 -- FIXME: should we really discard virtual functions?
718 -- if the virtual overload in the shell uses rawget
719 -- on the environment then we can leave these in the
721 if f
.wrapper_code
and f
.xarg
.virtual
~='1' then
722 local out
= 'static int lqt_bind'..f
.xarg
.id
723 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
724 if f
.xarg
.access
=='public' then
726 wrappers
= wrappers
.. out
.. '\n'
727 meta
[f
] = f
.xarg
.name
731 if not c
.abstract
then
732 for _
, f
in ipairs(c
.constructors
) do
733 if f
.wrapper_code
then
734 local out
= 'static int lqt_bind'..f
.xarg
.id
735 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
736 if f
.xarg
.access
=='public' then
738 wrappers
= wrappers
.. out
.. '\n'
744 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
745 local lua_name
= string.gsub(c
.xarg
.fullname
, '::', '.')
746 local out
= 'static int lqt_delete'..c
.xarg
.id
..' (lua_State *L) {\n'
747 out
= out
..' '..c
.xarg
.fullname
..' *p = static_cast<'
748 ..c
.xarg
.fullname
..'*>(lqtL_toudata(L, 1, "'..lua_name
..'*"));\n'
749 if c
.public_destr
then
750 out
= out
.. ' if (p) delete p;\n'
752 out
= out
.. ' lqtL_eraseudata(L, 1, "'..lua_name
..'*");\n return 0;\n}\n'
754 wrappers
= wrappers
.. out
.. '\n'
756 c
.wrappers
= wrappers
761 local print_metatable
= function(c
)
763 local wrappers
= c
.wrappers
764 for m
, n
in pairs(c
.meta
) do
765 methods
[n
] = methods
[n
] or {}
766 table.insert(methods
[n
], m
)
768 for n
, l
in pairs(methods
) do
769 local duplicates
= {}
770 for _
, f
in ipairs(l
) do
772 for sa
, g
in pairs(duplicates
) do
773 if sa
==f
.stack_arguments
then
774 --debug("function equal: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
775 if f
.defects
<g
.defects
then
779 elseif string.match(sa
, "^"..f
.stack_arguments
) then -- there is already a version with more arguments
780 --debug("function superseded: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
781 elseif string.match(f
.stack_arguments
, '^'..sa
) then -- there is already a version with less arguments
782 --debug("function superseding: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
786 duplicates
[f
.stack_arguments
] = f
792 for sa, f in pairs(l) do
793 numinitial = numinitial + 1
795 for sa, f in pairs(duplicates) do
796 numfinal = numfinal + 1
798 if numinitial-numfinal>0 then debug(c.xarg.fullname, "suppressed:", numinitial-numfinal) end
801 for n
, l
in pairs(methods
) do
802 local disp
= 'static int lqt_dispatcher_'..n
..c
.xarg
.id
..' (lua_State *L) {\n'
803 for _
, f
in ipairs(l
) do
804 disp
= disp
..' if ('..f
.test_code
..') return lqt_bind'..f
.xarg
.id
..'(L);\n'
806 disp
= disp
.. ' lua_settop(L, 0);\n'
807 disp
= disp
.. ' lua_pushstring(L, "'..c
.xarg
.fullname
..'::'..n
..': incorrect or extra arguments");\n'
808 disp
= disp
.. ' return lua_error(L);\n}\n'
810 wrappers
= wrappers
.. disp
.. '\n'
812 local metatable
= 'static luaL_Reg lqt_metatable'..c
.xarg
.id
..'[] = {\n'
813 for n
, l
in pairs(methods
) do
814 metatable
= metatable
.. ' { "'..n
..'", lqt_dispatcher_'..n
..c
.xarg
.id
..' },\n'
816 metatable
= metatable
.. ' { "delete", lqt_delete'..c
.xarg
.id
..' },\n'
817 metatable
= metatable
.. ' { 0, 0 },\n};\n'
818 --print_meta(metatable)
819 wrappers
= wrappers
.. metatable
.. '\n'
821 for b
in string.gmatch(c
.xarg
.bases_with_attributes
or '', '([^;]*);') do
822 if not string.match(b
, '^virtual') then
823 b
= string.gsub(b
, '^[^%s]* ', '')
824 bases
= bases
.. ' {"'..string.gsub(b
,'::','.')..'*", (char*)(void*)static_cast<'..b
..'*>(('..c
.xarg
.fullname
..'*)1)-(char*)1},\n'
827 bases
= 'static lqt_Base lqt_base'..c
.xarg
.id
..'[] = {\n'..bases
..' {NULL, 0}\n};\n'
829 wrappers
= wrappers
.. bases
.. '\n'
830 c
.wrappers
= wrappers
834 local print_metatables
= function(classes
)
835 for c
in pairs(classes
) do
843 local print_single_class
= function(c
)
844 local n
= string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
845 local lua_name
= string.gsub(c
.xarg
.fullname
, '::', '.')
846 local cppname
= module_name
..'_meta_'..n
..'.cpp'
847 table.insert(cpp_files
, cppname
);
848 local fmeta
= assert(io
.open(module_name
.._src
..cppname
, 'w'))
849 local print_meta
= function(...)
853 print_meta('#include "'..module_name
..'_head_'..n
..'.hpp'..'"\n\n')
854 print_meta(c
.wrappers
)
855 if c
.virtual_overloads
then
856 print_meta(c
.virtual_overloads
)
858 print_meta('extern "C" LQT_EXPORT int luaopen_'..n
..' (lua_State *L) {')
859 print_meta('\tlqtL_createclass(L, "'
860 ..lua_name
..'*", lqt_metatable'
861 ..c
.xarg
.id
..', lqt_base'
863 print_meta
'\treturn 0;'
866 if c
.shell
and c
.qobject
then
870 QMetaObject lqt_shell_]]..n
..[[::staticMetaObject;
872 const QMetaObject *lqt_shell_]]..n
..[[::metaObject() const {
873 //int oldtop = lua_gettop(L);
874 lqtL_pushudata(L, this, "]]..c
.xarg
.fullname
..[[*");
875 lua_getfield(L, -1, LQT_OBJMETASTRING);
876 if (lua_isnil(L, -1)) {
878 return &]]..c
.xarg
.fullname
..[[::staticMetaObject;
880 lua_getfield(L, -2, LQT_OBJMETADATA);
882 //qDebug() << "copying qmeta object for slots in ]]..c
.xarg
.fullname
..[[";
883 lqt_shell_]]..n
..[[::staticMetaObject.d.superdata = &]]..c
.xarg
.fullname
..[[::staticMetaObject;
884 lqt_shell_]]..n
..[[::staticMetaObject.d.stringdata = lua_tostring(L, -2);
885 lqt_shell_]]..n
..[[::staticMetaObject.d.data = (uint*)lua_touserdata(L, -1);
886 lqt_shell_]]..n
..[[::staticMetaObject.d.extradata = 0; // slot_metaobj->d.extradata;
887 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETADATA);
888 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETASTRING);
890 //qDebug() << (lua_gettop(L) - oldtop);
891 return &lqt_shell_]]..n
..[[::staticMetaObject;
894 int lqt_shell_]]..n
..[[::qt_metacall(QMetaObject::Call call, int index, void **args) {
895 //qDebug() << "fake calling!";
896 index = ]]..c
.xarg
.fullname
..[[::qt_metacall(call, index, args);
897 if (index < 0) return index;
898 return lqtL_qt_metacall(L, this, call, "QWidget*", index, args);
905 local print_merged_build
= function()
906 local path
= module_name
.._src
907 local mergename
= module_name
..'_merged_build'
908 local merged
= assert(io
.open(path
..mergename
..'.cpp', 'w'))
909 for _
, p
in ipairs(cpp_files
) do
910 merged
:write('#include "'..p
..'"\n')
912 local pro_file
= assert(io
.open(path
..mergename
..'.pro', 'w'))
914 local print_pro
= function(...)
918 print_pro('TEMPLATE = lib')
919 print_pro('TARGET = '..module_name
)
920 print_pro('INCLUDEPATH += .')
921 print_pro('HEADERS += '..module_name
..'_slot.hpp')
922 print_pro('SOURCES += ../common/lqt_common.cpp \\')
923 print_pro(' ../common/lqt_qt.cpp \\')
924 print_pro(' '..module_name
..'_enum.cpp \\')
925 print_pro(' '..module_name
..'_meta.cpp \\')
926 print_pro(' '..module_name
..'_slot.cpp \\')
927 print_pro(' '..mergename
..'.cpp')
930 local print_class_list
= function(classes
)
931 local qobject_present
= false
932 local big_picture
= {}
933 local type_list_t
= {}
934 for c
in pairs(classes
) do
935 local n
= string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
936 if n
=='QObject' then qobject_present
= true end
937 print_single_class(c
)
938 table.insert(big_picture
, 'luaopen_'..n
)
939 table.insert(type_list_t
, 'add_class(\''..c
.xarg
.fullname
..'\', types)\n')
942 local type_list_f
= assert(io
.open(module_name
.._src
..module_name
..'_types.lua', 'w'))
945 local types = (...) or {}
946 local add_class = lqt.classes.insert or error('module lqt.classes not loaded')
948 for k
, v
in ipairs(type_list_t
) do
951 type_list_f
:write('return types\n')
955 if fmeta
then fmeta
:close() end
956 fmeta
= assert(io
.open(module_name
.._src
..module_name
..'_meta.cpp', 'w'))
957 local print_meta
= function(...)
962 print_meta('#include "lqt_common.hpp"')
963 print_meta('#include "'..module_name
..'_slot.hpp'..'"\n\n')
964 for _
, p
in ipairs(big_picture
) do
965 print_meta('extern "C" LQT_EXPORT int '..p
..' (lua_State *);')
967 print_meta('void lqt_create_enums_'..module_name
..' (lua_State *);')
968 print_meta('extern "C" LQT_EXPORT int luaopen_'..module_name
..' (lua_State *L) {')
969 for _
, p
in ipairs(big_picture
) do
970 print_meta('\t'..p
..'(L);')
972 print_meta('\tlqt_create_enums_'..module_name
..'(L);')
973 if qobject_present
then
974 print_meta('\tlua_getfield(L, LUA_REGISTRYINDEX, "QObject*");')
975 print_meta('\tlua_pushstring(L, "__addmethod");')
976 print_meta('\tlqtL_pushaddmethod(L);')
977 print_meta('\tlua_rawset(L, -3);')
979 print_meta('\t//lua_pushlightuserdata(L, (void*)&LqtSlotAcceptor::staticMetaObject);')
980 print_meta('\t//lua_setfield(L, LUA_REGISTRYINDEX, LQT_METAOBJECT);')
981 print_meta('\tlqtL_passudata(L, (void*)(new LqtSlotAcceptor(L)), "QObject*");')
982 print_meta('\tlua_setfield(L, LUA_REGISTRYINDEX, LQT_METACALLER);')
983 print_meta('\treturn 0;\n}')
984 if fmeta
then fmeta
:close() end
988 local fix_methods_wrappers
= function(classes
)
989 for c
in pairs(classes
) do
990 c
.shell
= (not c
.abstract
) and c
.public_destr
991 c
.shell
= c
.shell
and (next(c
.virtuals
)~=nil)
992 for _
, constr
in ipairs(c
.constructors
) do
994 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
995 constr
.calling_line
= 'new '..shellname
..'(L'
996 if #(constr
.arguments
)>0 then constr
.calling_line
= constr
.calling_line
.. ', ' end
998 local shellname
= c
.xarg
.fullname
999 constr
.calling_line
= 'new '..shellname
..'('
1001 for i
=1,#(constr
.arguments
) do
1002 constr
.calling_line
= constr
.calling_line
.. (i
==1 and '' or ', ') .. 'arg' .. i
1004 constr
.calling_line
= '*('..constr
.calling_line
.. '))'
1005 constr
.xarg
.static
= '1'
1006 constr
.return_type
= constr
.xarg
.type_base
..'&'
1008 if c
.destructor
then
1009 c
.destructor
.return_type
= nil
1015 local print_enum_tables
= function(enums
)
1016 for e
in pairs(enums
) do
1017 local table = 'static lqt_Enum lqt_enum'..e
.xarg
.id
..'[] = {\n'
1018 --io.stderr:write(e.xarg.fullname, '\t', #e.values, '\n')
1019 for _
,v
in pairs(e
.values
) do
1020 table = table .. ' { "' .. v
.xarg
.name
1021 .. '", static_cast<int>('..v
.xarg
.fullname
..') },\n'
1023 table = table .. ' { 0, 0 }\n'
1024 table = table .. '};\n'
1025 e
.enum_table
= table
1030 local print_enum_creator
= function(enums
, n
)
1031 local out
= 'static lqt_Enumlist lqt_enum_list[] = {\n'
1032 for e
in pairs(enums
) do
1033 out
= out
..' { lqt_enum'..e
.xarg
.id
..', "'..string.gsub(e
.xarg
.fullname
, "::", ".")..'" },\n'
1035 out
= out
..' { 0, 0 },\n};\n'
1036 out
= out
.. 'void lqt_create_enums_'..n
..' (lua_State *L) {\n'
1037 out
= out
.. ' lqtL_createenumlist(L, lqt_enum_list); return;\n}\n'
1042 local copy_signals
= function(functions
)
1044 for f
in pairs(functions
) do
1045 if f
.xarg
.signal
=='1' then
1052 local slots_for_signals
= function(signals
, types
)
1054 for sig
in pairs(signals
) do
1055 local args
, comma
= '(', ''
1056 for i
, a
in ipairs(sig
.arguments
) do
1057 args
= args
.. comma
.. a
.xarg
.type_name
.. ' arg'..i
1061 local pushlines
, stack
= make_pushlines(sig
.arguments
, types
)
1062 if not ret
['void __slot '..args
] and pushlines
then
1063 ret
['void __slot '..args
] = 'void LqtSlotAcceptor::__slot '..args
..[[ {
1064 //int oldtop = lua_gettop(L);
1065 //lua_getfield(L, -1, "__slot]]..string.gsub(args
, ' arg.', '')..[[");
1066 //if (lua_isnil(L, -1)) {
1068 //lua_getfield(L, -1, "__slot");
1070 //if (!lua_isfunction(L, -1)) {
1071 //lua_settop(L, oldtop);
1074 lua_pushvalue(L, -2);
1075 ]] .. pushlines
.. [[
1076 if (lqtL_pcall(L, ]]..stack
..[[+1, 0, 0)) {
1078 qDebug() << lua_tostring(L, -1);
1081 //lua_settop(L, oldtop);
1089 local print_slots
= function(s
)
1090 print_slot_h
'class LqtSlotAcceptor : public QObject {'
1091 print_slot_h
' Q_OBJECT'
1092 print_slot_h
' lua_State *L;'
1093 print_slot_h
' public:'
1094 print_slot_h
' LqtSlotAcceptor(lua_State *l, QObject *p=NULL) : QObject(p), L(l) { lqtL_register(L, this); }'
1095 print_slot_h
' virtual ~LqtSlotAcceptor() { lqtL_unregister(L, this); }'
1096 print_slot_h
' public slots:'
1097 for p
, b
in pairs(s
) do
1098 print_slot_h(' '..p
..';')
1101 for p
, b
in pairs(s
) do
1107 --------------------------------------------------------------------------------------
1109 local typesystem
= dofile(path
..'types.lua')
1112 for i
, ft
in ipairs(typefiles
) do
1113 ts
= assert(loadfile(ft
))(ts
)
1115 setmetatable(typesystem
, {
1116 __newindex
= function(t
, k
, v
)
1117 --debug('added type', k)
1120 __index
= function(t
, k
)
1122 --if not ret then debug("unknown type:", tostring(k), ret) end
1128 fix_arguments(idindex
) -- fixes default arguments if they are context-relative
1129 local functions
= copy_functions(idindex
) -- picks functions and fixes label
1130 local functions
= fix_functions(functions
) -- fixes name and fullname and fills arguments
1132 local enums
= copy_enums(idindex
) -- picks enums if public
1133 local enums
= fill_enums(enums
) -- fills field "values"
1135 local classes
= copy_classes(idindex
) -- picks classes if not private and not blacklisted
1136 local classes
= fill_virtuals(classes
) -- does that, destructor ("~") excluded
1137 local classes
= distinguish_methods(classes
) -- does that
1138 local classes
= fill_public_destr(classes
) -- does that: checks if destructor is public
1139 local classes
= fill_copy_constructor(classes
) -- does that: checks if copy contructor is public or protected
1140 local classes
= fix_methods_wrappers(classes
)
1141 local classes
= get_qobjects(classes
)
1143 for _
, f
in ipairs(filterfiles
) do
1144 classes
, enums
= loadfile(f
)(classes
, enums
)
1147 local enums
= fill_typesystem_with_enums(enums
, typesystem
) -- does that
1148 local classes
= fill_typesystem_with_classes(classes
, typesystem
)
1150 local functions
= fill_wrappers(functions
, typesystem
)
1151 local classes
= fill_virtual_overloads(classes
, typesystem
) -- does that
1152 local classes
= fill_shell_classes(classes
, typesystem
) -- does that
1154 local signals
= copy_signals(functions
)
1155 local slots
= slots_for_signals(signals
, typesystem
)
1158 ------------- BEGIN OUTPUT
1162 print_enum(output_includes
)
1163 print_slot_h(output_includes
)
1164 print_slot_c('#include "'..module_name
..'_slot.hpp'..'"\n\n')
1167 local classes
= print_shell_classes(classes
) -- does that
1168 local classes
= print_virtual_overloads(classes
, typesystem
) -- does that
1169 local enums
= print_enum_tables(enums
) -- does that
1170 local enums
= print_enum_creator(enums
, module_name
) -- does that + print enum list
1171 local classes
= print_wrappers(classes
) -- just compiles metatable list
1172 local classes
= print_metatables(classes
) -- just collects the wrappers + generates dispatchers
1173 local classes
= print_class_list(classes
) -- does that + prints everything related to class
1175 local slots
= print_slots(slots
)
1177 --print_openmodule(module_name) -- does that