5 Copyright (c) 2007-2008 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*$'))
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
, call = string.match(a
.xarg
.defaultvalue
, '(.-)(%b())')
137 dv
= dv
or a
.xarg
.defaultvalue
139 if not fullnames
[dv
] then
140 dv
= a
.xarg
.context
..'::'..dv
..call
142 if fullnames
[dv
] then
143 a
.xarg
.defaultvalue
= dv
..call
146 a
.xarg
.defaultvalue
= nil
153 local fix_functions
= function(index
)
154 for f
in pairs(index
) do
156 for i
, a
in ipairs(f
) do
157 -- avoid bogus 'void' arguments
158 if a
.xarg
.type_name
=='void' and i
==1 and f
[2]==nil then break end
159 if a
.label
=='Argument' then
160 table.insert(args
, a
)
164 f
.return_type
= f
.xarg
.type_name
165 if f
.xarg
.type_name
=='void' then
172 local copy_enums
= function(index
)
174 for e
in pairs(index
) do
176 and not string.match(e
.xarg
.fullname
, '%b<>')
177 and e
.xarg
.access
=='public' then
184 local fill_enums
= function(index
)
185 for e
in pairs(index
) do
187 for _
, v
in ipairs(e
) do
188 if v
.label
=='Enumerator' then
189 table.insert(values
, v
)
197 local copy_classes
= function(index
)
199 for e
in pairs(index
) do
201 and e
.xarg
.access
~='private'
202 and not e
.xarg
.fullname
:match
'%b<>' then
203 --if e.xarg.fullname=='QMetaObject' then debug'been here' end
210 local get_qobjects
= function(index
)
212 for c
in pairs(index
) do
213 classes
[c
.xarg
.fullname
] = c
216 is_qobject
= function(c
)
217 if c
==nil then return false end
218 if c
.qobject
then return true end
219 if c
.xarg
.fullname
=='QObject' then
223 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
224 local base
= classes
[b
]
225 if is_qobject(base
) then
226 --debug(c.xarg.fullname, "is a QObject")
233 for c
in pairs(index
) do
234 local qobj
= is_qobject(c
)
239 local fill_virtuals
= function(index
)
241 for c
in pairs(index
) do
242 classes
[c
.xarg
.fullname
] = c
245 get_virtuals
= function(c
)
247 for _
, f
in ipairs(c
) do
248 if f
.label
=='Function' and f
.xarg
.virtual
=='1' then
249 local n
= string.match(f
.xarg
.name
, '~') or f
.xarg
.name
250 if n
~='~' and n
~='metaObject' then ret
[n
] = f
end
253 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
254 local base
= classes
[b
]
255 if type(base
)=='table' then
256 local bv
= get_virtuals(base
)
257 for n
, f
in pairs(bv
) do
258 if not ret
[n
] then ret
[n
] = f
end
262 for _
, f
in ipairs(c
) do
263 if f
.label
=='Function'
264 and f
.xarg
.access
~='private'
265 and (ret
[string.match(f
.xarg
.name
, '~') or f
.xarg
.name
]) then
267 local n
= string.match(f
.xarg
.name
, '~')or f
.xarg
.name
273 for c
in pairs(index
) do
274 c
.virtuals
= get_virtuals(c
)
275 for _
, f
in pairs(c
.virtuals
) do
276 if f
.xarg
.abstract
=='1' then c
.abstract
=true break end
282 local distinguish_methods
= function(index
)
283 for c
in pairs(index
) do
284 local construct
, destruct
, normal
= {}, nil, {}
285 local n
= c
.xarg
.name
287 for _
, f
in ipairs(c
) do
288 if n
==f
.xarg
.name
then
289 table.insert(construct
, f
)
290 elseif f
.xarg
.name
:match
'~' then
293 if (not string.match(f
.xarg
.name
, '^operator%W'))
294 and (not f
.xarg
.member_template_parameters
) then
295 table.insert(normal
, f
)
299 c
.constructors
= construct
300 c
.destructor
= destruct
306 local fill_public_destr
= function(index
)
308 for c
in pairs(index
) do
309 classes
[c
.xarg
.fullname
] = c
311 local destr_is_public
312 destr_is_public
= function(c
)
314 return c
.destructor
.xarg
.access
=='public'
316 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
317 local base
= classes
[b
]
318 if base
and not destr_is_public(base
) then
325 for c
in pairs(index
) do
326 c
.public_destr
= destr_is_public(c
)
331 local fill_copy_constructor
= function(index
)
333 for c
in pairs(index
) do
334 classes
[c
.xarg
.name
] = c
336 for c
in pairs(index
) do
338 for _
, f
in ipairs(c
.constructors
) do
340 and f
.arguments
[1].xarg
.type_name
==c
.xarg
.fullname
..' const&' then
345 c
.copy_constructor
= copy
347 local copy_constr_is_public
348 copy_constr_is_public
= function(c
)
349 if c
.copy_constructor
then
350 return (c
.copy_constructor
.xarg
.access
=='public')
351 or (c
.copy_constructor
.xarg
.access
=='protected')
354 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
355 local base
= classes
[b
]
356 if base
and not copy_constr_is_public(base
) then
363 for c
in pairs(index
) do
364 c
.public_constr
= copy_constr_is_public(c
)
369 local fill_typesystem_with_enums
= function(enums
, types
)
370 local etype
= function(en
)
373 return 'lqtL_pushenum(L, '..n
..', "'..en
..'")', 1
376 return 'static_cast<'..en
..'>'
377 ..'(lqtL_toenum(L, '..n
..', "'..en
..'"))', 1
380 return 'lqtL_isenum(L, '..n
..', "'..en
..'")', 1
385 for e
in pairs(enums
) do
386 if types
[e
.xarg
.fullname
]==nil then
388 types
[e
.xarg
.fullname
] = etype(e
.xarg
.fullname
)
390 --io.stderr:write(e.xarg.fullname, ': already present\n')
396 local put_class_in_filesystem
= lqt
.classes
.insert
397 local fill_typesystem_with_classes
= function(classes
, types
)
399 for c
in pairs(classes
) do
400 ret
[c
] = put_class_in_filesystem(c
.xarg
.fullname
, types
) --, true)
405 local argument_name
= function(tn
, an
)
407 if string.match(tn
, '%(%*%)') then
408 ret
= string.gsub(tn
, '%(%*%)', '(*'..an
..')', 1)
409 elseif string.match(tn
, '%[.*%]') then
410 ret
= string.gsub(tn
, '%s*(%[.*%])', ' '..an
..'%1')
412 ret
= tn
.. ' ' .. an
417 local fill_wrapper_code
= function(f
, types
)
418 if f
.wrapper_code
then return f
end
419 local stackn
, argn
= 1, 1
420 local wrap
, line
= ' int oldtop = lua_gettop(L);\n', ''
421 if f
.xarg
.abstract
then return nil end
422 if f
.xarg
.member_of_class
and f
.xarg
.static
~='1' then
423 if not types
[f
.xarg
.member_of_class
..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
424 local sget
, sn
= types
[f
.xarg
.member_of_class
..'*'].get(stackn
)
425 wrap
= wrap
.. ' ' .. f
.xarg
.member_of_class
.. '* self = ' .. sget
.. ';\n'
429 lua_pushstring(L, "this pointer is NULL");
434 line
= 'self->'..f
.xarg
.fullname
..'('
436 line
= f
.xarg
.fullname
..'('
438 for i
, a
in ipairs(f
.arguments
) do
439 if not types
[a
.xarg
.type_name
] then return nil end
440 local aget
, an
, arg_as
= types
[a
.xarg
.type_name
].get(stackn
)
441 wrap
= wrap
.. ' ' .. argument_name(arg_as
or a
.xarg
.type_name
, 'arg'..argn
) .. ' = '
442 if a
.xarg
.default
=='1' and an
>0 then
443 wrap
= wrap
.. 'lua_isnoneornil(L, '..stackn
..')'
444 for j
= stackn
+1,stackn
+an
-1 do
445 wrap
= wrap
.. ' && lua_isnoneornil(L, '..j
..')'
447 local dv
= a
.xarg
.defaultvalue
448 wrap
= wrap
.. ' ? static_cast< ' .. a
.xarg
.type_name
.. ' >(' .. dv
.. ') : '
450 wrap
= wrap
.. aget
.. ';\n'
451 line
= line
.. (argn
==1 and 'arg' or ', arg') .. argn
456 -- FIXME: hack follows for constructors
457 if f
.calling_line
then line
= f
.calling_line
end
458 if f
.return_type
then line
= f
.return_type
.. ' ret = ' .. line
end
459 wrap
= wrap
.. ' ' .. line
.. ';\n lua_settop(L, oldtop);\n' -- lua_pop(L, '..stackn..');\n'
460 if f
.return_type
then
461 if not types
[f
.return_type
] then return nil end
462 local rput
, rn
= types
[f
.return_type
].push
'ret'
463 wrap
= wrap
.. ' luaL_checkstack(L, '..rn
..', "cannot grow stack for return value");\n'
464 wrap
= wrap
.. ' '..rput
..';\n return '..rn
..';\n'
466 wrap
= wrap
.. ' return 0;\n'
468 f
.wrapper_code
= wrap
472 local fill_test_code
= function(f
, types
)
475 if f
.xarg
.member_of_class
and f
.xarg
.static
~='1' then
476 if not types
[f
.xarg
.member_of_class
..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
477 local stest
, sn
= types
[f
.xarg
.member_of_class
..'*'].test(stackn
)
478 test
= test
.. ' && ' .. stest
481 for i
, a
in ipairs(f
.arguments
) do
482 if not types
[a
.xarg
.type_name
] then return nil end -- print(a.xarg.type_name) return nil end
483 local atest
, an
= types
[a
.xarg
.type_name
].test(stackn
)
484 if a
.xarg
.default
=='1' and an
>0 then
485 test
= test
.. ' && (lqtL_missarg(L, ' .. stackn
.. ', ' .. an
.. ') || '
486 test
= test
.. atest
.. ')'
488 test
= test
.. ' && ' .. atest
492 -- can't make use of default values if I fix number of args
493 test
= '(lua_gettop(L)<' .. stackn
.. ')' .. test
498 local fill_wrappers
= function(functions
, types
)
500 for f
in pairs(functions
) do
501 f
= fill_wrapper_code(f
, types
)
503 f
= assert(fill_test_code(f
, types
), f
.xarg
.fullname
) -- MUST pass
505 --local out = 'extern "C" LQT_EXPORT int lqt_bind'..f.xarg.id..' (lua_State *L) {\n'
506 --.. f.wrapper_code .. '}\n'
513 local make_pushlines
= function(args
, types
)
514 local pushlines
, stack
= '', 0
515 for i
, a
in ipairs(args
) do
516 if not types
[a
.xarg
.type_name
] then return nil end
517 local apush
, an
= types
[a
.xarg
.type_name
].push('arg'..i
)
518 pushlines
= pushlines
.. ' ' .. apush
.. ';\n'
521 return pushlines
, stack
524 local virtual_overload
= function(v
, types
)
526 if v
.virtual_overload
then return v
end
528 if v
.return_type
and not types
[v
.return_type
] then return nil end
529 local rget
, rn
= '', 0
530 if v
.return_type
then rget
, rn
, ret_as
= types
[v
.return_type
].get
'oldtop+1' end
531 local retget
= (v
.return_type
and argument_name(ret_as
or v
.return_type
, 'ret')
532 .. ' = ' .. rget
.. ';' or '') .. 'lua_settop(L, oldtop);return'
533 .. (v
.return_type
and ' ret' or '')
534 -- make argument push
535 local pushlines
, stack
= make_pushlines(v
.arguments
, types
)
536 if not pushlines
then return nil end
538 local luacall
= 'lua_pcall(L, '..(stack
+1)..', '..rn
..', 0)'
539 -- make prototype and fallback
540 local proto
= (v
.return_type
or 'void')..' ;;'..v
.xarg
.name
..' ('
542 for i
, a
in ipairs(v
.arguments
) do
543 proto
= proto
.. (i
>1 and ', ' or '')
544 .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
545 fallback
= fallback
.. (i
>1 and ', arg' or 'arg') .. i
547 proto
= proto
.. ')' .. (v
.xarg
.constant
=='1' and ' const' or '')
548 fallback
= (v
.return_type
and 'return this->' or 'this->')
549 .. v
.xarg
.fullname
.. '(' .. fallback
.. ');\n}\n'
551 int oldtop = lua_gettop(L);
552 lqtL_pushudata(L, this, "]]..string.gsub(v
.xarg
.member_of_class
, '::', '.')..[[*");
553 lua_getfield(L, -1, "]]..v
.xarg
.name
..[[");
554 if (lua_isfunction(L, -1)) {
556 ]] .. pushlines
.. [[
557 if (!]]..luacall
..[[) {
561 lua_settop(L, oldtop);
563 v
.virtual_overload
= ret
564 v
.virtual_proto
= string.gsub(proto
, ';;', '', 1)
568 local fill_shell_class
= function(c
, types
)
569 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
570 local shell
= 'class LQT_EXPORT ' .. shellname
.. ' : public ' .. c
.xarg
.fullname
.. ' {\npublic:\n'
571 shell
= shell
.. ' lua_State *L;\n'
572 for _
, constr
in ipairs(c
.constructors
) do
573 if constr
.xarg
.access
~='private' then
574 local cline
= ' '..shellname
..' (lua_State *l'
576 for i
, a
in ipairs(constr
.arguments
) do
577 cline
= cline
.. ', ' .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
578 argline
= argline
.. (i
>1 and ', arg' or 'arg') .. i
580 cline
= cline
.. ') : ' .. c
.xarg
.fullname
581 .. '(' .. argline
.. '), L(l) '
582 .. '{ lqtL_register(L, this); }\n'
583 shell
= shell
.. cline
586 if c
.copy_constructor
==nil and c
.public_constr
then
587 local cline
= ' '..shellname
..' (lua_State *l, '..c
.xarg
.fullname
..' const& arg1)'
588 cline
= cline
.. ' : ' .. c
.xarg
.fullname
.. '(arg1), L(l) {}\n'
589 shell
= shell
.. cline
591 for i
, v
in pairs(c
.virtuals
) do
592 if v
.xarg
.access
~='private' then
593 if v
.virtual_proto
then shell
= shell
.. ' virtual ' .. v
.virtual_proto
.. ';\n' end
596 shell
= shell
.. ' ~'..shellname
..'() { lqtL_unregister(L, this); }\n'
597 if c
.shell
and c
.qobject
then
598 shell
= shell
.. ' static QMetaObject staticMetaObject;\n'
599 shell
= shell
.. ' virtual const QMetaObject *metaObject() const;\n'
600 shell
= shell
.. ' virtual int qt_metacall(QMetaObject::Call, int, void **);\n'
601 shell
= shell
.. 'private:\n'
602 shell
= shell
.. ' Q_DISABLE_COPY('..shellname
..');\n'
604 shell
= shell
.. '};\n'
605 c
.shell_class
= shell
609 local fill_virtual_overloads
= function(classes
, types
)
610 for c
in pairs(classes
) do
611 for i
, v
in pairs(c
.virtuals
) do
612 if v
.xarg
.access
~='private' then
613 local vret
= virtual_overload(v
, types
)
620 local fill_shell_classes
= function(classes
, types
)
622 for c
in pairs(classes
) do
624 c
= fill_shell_class(c
, types
)
625 if c
then ret
[c
] = true end
632 local print_shell_classes
= function(classes
)
634 for c
in pairs(classes
) do
635 if fhead
then fhead
:close() end
636 local n
= string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
637 fhead
= assert(io
.open(module_name
.._src
..module_name
..'_head_'..n
..'.hpp', 'w'))
638 local print_head
= function(...)
642 print_head('#ifndef LQT_HEAD_'..n
)
643 print_head('#define LQT_HEAD_'..n
)
644 print_head(output_includes
)
645 --print_head('#include <'..string.match(c.xarg.fullname, '^[^:]+')..'>')
649 print_head(c
.shell_class
)
651 --io.stderr:write(c.fullname, '\n')
654 print_head('#endif // LQT_HEAD_'..n
)
656 if fhead
then fhead
:close() end
660 local print_virtual_overloads
= function(classes
)
661 for c
in pairs(classes
) do
664 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
665 for _
,v
in pairs(c
.virtuals
) do
666 if v
.virtual_overload
then
667 vo
= vo
.. string.gsub(v
.virtual_overload
, ';;', shellname
..'::', 1)
670 c
.virtual_overloads
= vo
676 local print_wrappers
= function(index
)
677 for c
in pairs(index
) do
680 for _
, f
in ipairs(c
.methods
) do
681 if f
.wrapper_code
and f
.xarg
.virtual
~='1' then
682 local out
= 'static int lqt_bind'..f
.xarg
.id
683 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
684 if f
.xarg
.access
=='public' then
686 wrappers
= wrappers
.. out
.. '\n'
687 meta
[f
] = f
.xarg
.name
692 for _
, f
in ipairs(c
.constructors
) do
693 if f
.wrapper_code
then
694 local out
= 'static int lqt_bind'..f
.xarg
.id
695 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
696 if f
.xarg
.access
=='public' then
698 wrappers
= wrappers
.. out
.. '\n'
703 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
704 local lua_name
= string.gsub(c
.xarg
.fullname
, '::', '.')
705 local out
= 'static int lqt_delete'..c
.xarg
.id
..' (lua_State *L) {\n'
706 out
= out
..' '..c
.xarg
.fullname
..' *p = static_cast<'
707 ..c
.xarg
.fullname
..'*>(lqtL_toudata(L, 1, "'..lua_name
..'*"));\n'
708 out
= out
.. ' if (p) delete p;\n'
709 out
= out
.. ' lqtL_eraseudata(L, 1, "'..lua_name
..'*");\n return 0;\n}\n'
711 wrappers
= wrappers
.. out
.. '\n'
714 c
.wrappers
= wrappers
719 local print_metatable
= function(c
)
721 local wrappers
= c
.wrappers
722 for m
, n
in pairs(c
.meta
) do
723 methods
[n
] = methods
[n
] or {}
724 table.insert(methods
[n
], m
)
726 for n
, l
in pairs(methods
) do
727 local disp
= 'static int lqt_dispatcher_'..n
..c
.xarg
.id
..' (lua_State *L) {\n'
728 for _
, f
in ipairs(l
) do
729 disp
= disp
..' if ('..f
.test_code
..') return lqt_bind'..f
.xarg
.id
..'(L);\n'
731 disp
= disp
.. ' lua_settop(L, 0);\n'
732 disp
= disp
.. ' lua_pushstring(L, "'..c
.xarg
.fullname
..'::'..n
..': incorrect or extra arguments");\n'
733 disp
= disp
.. ' return lua_error(L);\n}\n'
735 wrappers
= wrappers
.. disp
.. '\n'
737 local metatable
= 'static luaL_Reg lqt_metatable'..c
.xarg
.id
..'[] = {\n'
738 for n
, l
in pairs(methods
) do
739 metatable
= metatable
.. ' { "'..n
..'", lqt_dispatcher_'..n
..c
.xarg
.id
..' },\n'
742 metatable
= metatable
.. ' { "delete", lqt_delete'..c
.xarg
.id
..' },\n'
744 metatable
= metatable
.. ' { 0, 0 },\n};\n'
745 --print_meta(metatable)
746 wrappers
= wrappers
.. metatable
.. '\n'
748 for b
in string.gmatch(c
.xarg
.bases_with_attributes
or '', '([^;]*);') do
749 if not string.match(b
, '^virtual') then
750 b
= string.gsub(b
, '^[^%s]* ', '')
751 bases
= bases
.. '{"' .. b
.. '*", (char*)(void*)static_cast<'..b
..'*>(('..c
.xarg
.fullname
..'*)1)-(char*)1},\n'
754 bases
= 'static lqt_Base lqt_base'..c
.xarg
.id
..'[] = { '..bases
..'{NULL, 0} };\n'
756 wrappers
= wrappers
.. bases
.. '\n'
757 c
.wrappers
= wrappers
761 local print_metatables
= function(classes
)
762 for c
in pairs(classes
) do
770 local print_single_class
= function(c
)
771 local n
= string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
772 local lua_name
= string.gsub(c
.xarg
.fullname
, '::', '.')
773 local cppname
= module_name
..'_meta_'..n
..'.cpp'
774 table.insert(cpp_files
, cppname
);
775 local fmeta
= assert(io
.open(module_name
.._src
..cppname
, 'w'))
776 local print_meta
= function(...)
780 print_meta('#include "'..module_name
..'_head_'..n
..'.hpp'..'"\n\n')
781 print_meta(c
.wrappers
)
782 if c
.virtual_overloads
then
783 print_meta(c
.virtual_overloads
)
785 print_meta('extern "C" LQT_EXPORT int luaopen_'..n
..' (lua_State *L) {')
786 print_meta('\tlqtL_createclass(L, "'
787 ..lua_name
..'*", lqt_metatable'
788 ..c
.xarg
.id
..', lqt_base'
790 print_meta
'\treturn 0;'
793 if c
.shell
and c
.qobject
then
797 QMetaObject lqt_shell_]]..n
..[[::staticMetaObject;
799 const QMetaObject *lqt_shell_]]..n
..[[::metaObject() const {
800 //int oldtop = lua_gettop(L);
801 lqtL_pushudata(L, this, "]]..c
.xarg
.fullname
..[[*");
802 lua_getfield(L, -1, LQT_OBJMETASTRING);
803 if (lua_isnil(L, -1)) {
805 return &]]..c
.xarg
.fullname
..[[::staticMetaObject;
807 lua_getfield(L, -2, LQT_OBJMETADATA);
809 //qDebug() << "copying qmeta object for slots in ]]..c
.xarg
.fullname
..[[";
810 lqt_shell_]]..n
..[[::staticMetaObject.d.superdata = &]]..c
.xarg
.fullname
..[[::staticMetaObject;
811 lqt_shell_]]..n
..[[::staticMetaObject.d.stringdata = lua_tostring(L, -2);
812 lqt_shell_]]..n
..[[::staticMetaObject.d.data = (uint*)lua_touserdata(L, -1);
813 lqt_shell_]]..n
..[[::staticMetaObject.d.extradata = 0; // slot_metaobj->d.extradata;
814 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETADATA);
815 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETASTRING);
817 //qDebug() << (lua_gettop(L) - oldtop);
818 return &lqt_shell_]]..n
..[[::staticMetaObject;
821 int lqt_shell_]]..n
..[[::qt_metacall(QMetaObject::Call call, int index, void **args) {
822 //qDebug() << "fake calling!";
823 index = ]]..c
.xarg
.fullname
..[[::qt_metacall(call, index, args);
824 if (index < 0) return index;
825 return lqtL_qt_metacall(L, this, call, "QWidget*", index, args);
832 local print_merged_build
= function()
833 local path
= module_name
.._src
834 local mergename
= module_name
..'_merged_build'
835 local merged
= assert(io
.open(path
..mergename
..'.cpp', 'w'))
836 for _
, p
in ipairs(cpp_files
) do
837 merged
:write('#include "'..p
..'"\n')
839 local pro_file
= assert(io
.open(path
..mergename
..'.pro', 'w'))
841 local print_pro
= function(...)
845 print_pro('TEMPLATE = lib')
846 print_pro('TARGET = '..module_name
)
847 print_pro('INCLUDEPATH += .')
848 print_pro('HEADERS += '..module_name
..'_slot.hpp')
849 print_pro('SOURCES += ../common/lqt_common.cpp \\')
850 print_pro(' ../common/lqt_qt.cpp \\')
851 print_pro(' '..module_name
..'_enum.cpp \\')
852 print_pro(' '..module_name
..'_meta.cpp \\')
853 print_pro(' '..module_name
..'_slot.cpp \\')
854 print_pro(' '..mergename
..'.cpp')
857 local print_class_list
= function(classes
)
858 local qobject_present
= false
859 local big_picture
= {}
860 local type_list_t
= {}
861 for c
in pairs(classes
) do
862 local n
= string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
863 if n
=='QObject' then qobject_present
= true end
864 print_single_class(c
)
865 table.insert(big_picture
, 'luaopen_'..n
)
866 table.insert(type_list_t
, 'add_class(\''..c
.xarg
.fullname
..'\', types)\n')
869 local type_list_f
= assert(io
.open(module_name
.._src
..module_name
..'_types.lua', 'w'))
872 local types = (...) or {}
873 local add_class = lqt.classes.insert or error('module lqt.classes not loaded')
875 for k
, v
in ipairs(type_list_t
) do
878 type_list_f
:write('return types\n')
882 if fmeta
then fmeta
:close() end
883 fmeta
= assert(io
.open(module_name
.._src
..module_name
..'_meta.cpp', 'w'))
884 local print_meta
= function(...)
889 print_meta('#include "lqt_common.hpp"')
890 print_meta('#include "'..module_name
..'_slot.hpp'..'"\n\n')
891 for _
, p
in ipairs(big_picture
) do
892 print_meta('extern "C" LQT_EXPORT int '..p
..' (lua_State *);')
894 print_meta('void lqt_create_enums_'..module_name
..' (lua_State *);')
895 print_meta('extern "C" LQT_EXPORT int luaopen_'..module_name
..' (lua_State *L) {')
896 for _
, p
in ipairs(big_picture
) do
897 print_meta('\t'..p
..'(L);')
899 print_meta('\tlqt_create_enums_'..module_name
..'(L);')
900 if qobject_present
then
901 print_meta('\tlua_getfield(L, LUA_REGISTRYINDEX, "QObject*");')
902 print_meta('\tlua_pushstring(L, "__addmethod");')
903 print_meta('\tlqtL_pushaddmethod(L);')
904 print_meta('\tlua_rawset(L, -3);')
906 print_meta('\t//lua_pushlightuserdata(L, (void*)&LqtSlotAcceptor::staticMetaObject);')
907 print_meta('\t//lua_setfield(L, LUA_REGISTRYINDEX, LQT_METAOBJECT);')
908 print_meta('\tlua_pushlightuserdata(L, (void*)new LqtSlotAcceptor(L));')
909 print_meta('\tlua_setfield(L, LUA_REGISTRYINDEX, LQT_METACALLER);')
910 print_meta('\treturn 0;\n}')
911 if fmeta
then fmeta
:close() end
915 local fix_methods_wrappers
= function(classes
)
916 for c
in pairs(classes
) do
917 c
.shell
= (not c
.abstract
) and c
.public_destr
918 for _
, constr
in ipairs(c
.constructors
) do
919 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
920 constr
.calling_line
= '*new '..shellname
..'(L'
921 for i
=1,#(constr
.arguments
) do
922 constr
.calling_line
= constr
.calling_line
.. ', arg' .. i
924 constr
.calling_line
= constr
.calling_line
.. ')'
925 constr
.xarg
.static
= '1'
926 constr
.return_type
= constr
.xarg
.type_base
..'&'
929 c
.destructor
.return_type
= nil
935 local print_enum_tables
= function(enums
)
936 for e
in pairs(enums
) do
937 local table = 'static lqt_Enum lqt_enum'..e
.xarg
.id
..'[] = {\n'
938 --io.stderr:write(e.xarg.fullname, '\t', #e.values, '\n')
939 for _
,v
in pairs(e
.values
) do
940 table = table .. ' { "' .. v
.xarg
.name
941 .. '", static_cast<int>('..v
.xarg
.fullname
..') },\n'
943 table = table .. ' { 0, 0 }\n'
944 table = table .. '};\n'
950 local print_enum_creator
= function(enums
, n
)
951 local out
= 'static lqt_Enumlist lqt_enum_list[] = {\n'
952 for e
in pairs(enums
) do
953 out
= out
..' { lqt_enum'..e
.xarg
.id
..', "'..e
.xarg
.fullname
..'" },\n'
955 out
= out
..' { 0, 0 },\n};\n'
956 out
= out
.. 'void lqt_create_enums_'..n
..' (lua_State *L) {\n'
957 out
= out
.. ' lqtL_createenumlist(L, lqt_enum_list); return;\n}\n'
962 local copy_signals
= function(functions
)
964 for f
in pairs(functions
) do
965 if f
.xarg
.signal
=='1' then
972 local slots_for_signals
= function(signals
, types
)
974 for sig
in pairs(signals
) do
975 local args
, comma
= '(', ''
976 for i
, a
in ipairs(sig
.arguments
) do
977 args
= args
.. comma
.. a
.xarg
.type_name
.. ' arg'..i
981 local pushlines
, stack
= make_pushlines(sig
.arguments
, types
)
982 if not ret
['void __slot '..args
] and pushlines
then
983 ret
['void __slot '..args
] = 'void LqtSlotAcceptor::__slot '..args
..[[ {
984 //int oldtop = lua_gettop(L);
985 //lua_getfield(L, -1, "__slot]]..string.gsub(args
, ' arg.', '')..[[");
986 //if (lua_isnil(L, -1)) {
988 //lua_getfield(L, -1, "__slot");
990 //if (!lua_isfunction(L, -1)) {
991 //lua_settop(L, oldtop);
994 lua_pushvalue(L, -2);
995 ]] .. pushlines
.. [[
996 if (lua_pcall(L, ]]..stack
..[[+1, 0, 0)) {
998 qDebug() << lua_tostring(L, -1);
1001 //lua_settop(L, oldtop);
1009 local print_slots
= function(s
)
1010 print_slot_h
'class LqtSlotAcceptor : public QObject {'
1011 print_slot_h
' Q_OBJECT'
1012 print_slot_h
' lua_State *L;'
1013 print_slot_h
' public:'
1014 print_slot_h
' LqtSlotAcceptor(lua_State *l, QObject *p=NULL) : QObject(p), L(l) { lqtL_register(L, this); }'
1015 print_slot_h
' virtual ~LqtSlotAcceptor() { lqtL_unregister(L, this); }'
1016 print_slot_h
' public slots:'
1017 for p
, b
in pairs(s
) do
1018 print_slot_h(' '..p
..';')
1021 for p
, b
in pairs(s
) do
1027 --------------------------------------------------------------------------------------
1029 local typesystem
= dofile(path
..'types.lua')
1032 for i
, ft
in ipairs(typefiles
) do
1033 ts
= assert(loadfile(ft
))(ts
)
1035 setmetatable(typesystem
, {
1036 __newindex
= function(t
, k
, v
)
1037 --debug('added type', k)
1040 __index
= function(t
, k
)
1042 --if not ret then debug("unknown type:", tostring(k), ret) end
1048 fix_arguments(idindex
) -- fixes default arguments if they are context-relative
1049 local functions
= copy_functions(idindex
) -- picks functions and fixes label
1050 local functions
= fix_functions(functions
) -- fixes name and fullname and fills arguments
1052 local enums
= copy_enums(idindex
) -- picks enums if public
1053 local enums
= fill_enums(enums
) -- fills field "values"
1055 local classes
= copy_classes(idindex
) -- picks classes if not private and not blacklisted
1056 local classes
= fill_virtuals(classes
) -- does that, destructor ("~") excluded
1057 local classes
= distinguish_methods(classes
) -- does that
1058 local classes
= fill_public_destr(classes
) -- does that: checks if destructor is public
1059 local classes
= fill_copy_constructor(classes
) -- does that: checks if copy contructor is public or protected
1060 local classes
= fix_methods_wrappers(classes
)
1061 local classes
= get_qobjects(classes
)
1063 for _
, f
in ipairs(filterfiles
) do
1064 classes
, enums
= loadfile(f
)(classes
, enums
)
1067 local enums
= fill_typesystem_with_enums(enums
, typesystem
) -- does that
1068 local classes
= fill_typesystem_with_classes(classes
, typesystem
)
1070 local functions
= fill_wrappers(functions
, typesystem
)
1071 local classes
= fill_virtual_overloads(classes
, typesystem
) -- does that
1072 local classes
= fill_shell_classes(classes
, typesystem
) -- does that
1074 local signals
= copy_signals(functions
)
1075 local slots
= slots_for_signals(signals
, typesystem
)
1078 ------------- BEGIN OUTPUT
1082 print_enum(output_includes
)
1083 print_slot_h(output_includes
)
1084 print_slot_c('#include "'..module_name
..'_slot.hpp'..'"\n\n')
1087 local classes
= print_shell_classes(classes
) -- does that
1088 local classes
= print_virtual_overloads(classes
, typesystem
) -- does that
1089 local enums
= print_enum_tables(enums
) -- does that
1090 local enums
= print_enum_creator(enums
, module_name
) -- does that + print enum list
1091 local classes
= print_wrappers(classes
) -- just compiles metatable list
1092 local classes
= print_metatables(classes
) -- just collects the wrappers + generates dispatchers
1093 local classes
= print_class_list(classes
) -- does that + prints everything related to class
1095 local slots
= print_slots(slots
)
1097 --print_openmodule(module_name) -- does that