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*$'))
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 copy_classes
= function(index
)
203 for e
in pairs(index
) do
205 and e
.xarg
.access
~='private'
206 and not e
.xarg
.fullname
:match
'%b<>' then
207 --if e.xarg.fullname=='QMetaObject' then debug'been here' end
214 local get_qobjects
= function(index
)
216 for c
in pairs(index
) do
217 classes
[c
.xarg
.fullname
] = c
220 is_qobject
= function(c
)
221 if c
==nil then return false end
222 if c
.qobject
then return true end
223 if c
.xarg
.fullname
=='QObject' then
227 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
228 local base
= classes
[b
]
229 if is_qobject(base
) then
230 --debug(c.xarg.fullname, "is a QObject")
237 for c
in pairs(index
) do
238 local qobj
= is_qobject(c
)
243 local fill_virtuals
= function(index
)
245 for c
in pairs(index
) do
246 classes
[c
.xarg
.fullname
] = c
249 get_virtuals
= function(c
)
251 for _
, f
in ipairs(c
) do
252 if f
.label
=='Function' and f
.xarg
.virtual
=='1' then
253 local n
= string.match(f
.xarg
.name
, '~') or f
.xarg
.name
254 if n
~='~' and n
~='metaObject' then ret
[n
] = f
end
257 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
258 local base
= classes
[b
]
259 if type(base
)=='table' then
260 local bv
= get_virtuals(base
)
261 for n
, f
in pairs(bv
) do
262 if not ret
[n
] then ret
[n
] = f
end
266 for _
, f
in ipairs(c
) do
267 if f
.label
=='Function'
268 and f
.xarg
.access
~='private'
269 and (ret
[string.match(f
.xarg
.name
, '~') or f
.xarg
.name
]) then
271 local n
= string.match(f
.xarg
.name
, '~')or f
.xarg
.name
277 for c
in pairs(index
) do
278 c
.virtuals
= get_virtuals(c
)
279 for _
, f
in pairs(c
.virtuals
) do
280 if f
.xarg
.abstract
=='1' then c
.abstract
=true break end
286 local distinguish_methods
= function(index
)
287 for c
in pairs(index
) do
288 local construct
, destruct
, normal
= {}, nil, {}
289 local n
= c
.xarg
.name
291 for _
, f
in ipairs(c
) do
292 if n
==f
.xarg
.name
then
293 table.insert(construct
, f
)
294 elseif f
.xarg
.name
:match
'~' then
297 if (not string.match(f
.xarg
.name
, '^operator%W'))
298 and (not f
.xarg
.member_template_parameters
) then
299 table.insert(normal
, f
)
303 c
.constructors
= construct
304 c
.destructor
= destruct
310 local fill_public_destr
= function(index
)
312 for c
in pairs(index
) do
313 classes
[c
.xarg
.fullname
] = c
315 local destr_is_public
316 destr_is_public
= function(c
)
318 return c
.destructor
.xarg
.access
=='public'
320 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
321 local base
= classes
[b
]
322 if base
and not destr_is_public(base
) then
329 for c
in pairs(index
) do
330 c
.public_destr
= destr_is_public(c
)
335 local fill_copy_constructor
= function(index
)
337 for c
in pairs(index
) do
338 classes
[c
.xarg
.name
] = c
340 for c
in pairs(index
) do
342 for _
, f
in ipairs(c
.constructors
) do
344 and f
.arguments
[1].xarg
.type_name
==c
.xarg
.fullname
..' const&' then
349 c
.copy_constructor
= copy
351 local copy_constr_is_public
352 copy_constr_is_public
= function(c
)
353 if c
.copy_constructor
then
354 return (c
.copy_constructor
.xarg
.access
=='public')
355 or (c
.copy_constructor
.xarg
.access
=='protected')
358 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
359 local base
= classes
[b
]
360 if base
and not copy_constr_is_public(base
) then
367 for c
in pairs(index
) do
368 c
.public_constr
= copy_constr_is_public(c
)
373 local fill_typesystem_with_enums
= function(enums
, types
)
374 local etype
= function(en
)
377 return 'lqtL_pushenum(L, '..n
..', "'..en
..'")', 1
380 return 'static_cast<'..en
..'>'
381 ..'(lqtL_toenum(L, '..n
..', "'..en
..'"))', 1
384 return 'lqtL_isenum(L, '..n
..', "'..en
..'")', 1
389 for e
in pairs(enums
) do
390 if types
[e
.xarg
.fullname
]==nil then
392 types
[e
.xarg
.fullname
] = etype(e
.xarg
.fullname
)
394 --io.stderr:write(e.xarg.fullname, ': already present\n')
400 local put_class_in_filesystem
= lqt
.classes
.insert
401 local fill_typesystem_with_classes
= function(classes
, types
)
403 for c
in pairs(classes
) do
404 ret
[c
] = put_class_in_filesystem(c
.xarg
.fullname
, types
) --, true)
409 local argument_name
= function(tn
, an
)
411 if string.match(tn
, '%(%*%)') then
412 ret
= string.gsub(tn
, '%(%*%)', '(*'..an
..')', 1)
413 elseif string.match(tn
, '%[.*%]') then
414 ret
= string.gsub(tn
, '%s*(%[.*%])', ' '..an
..'%1')
416 ret
= tn
.. ' ' .. an
421 local fill_wrapper_code
= function(f
, types
)
422 if f
.wrapper_code
then return f
end
423 local stackn
, argn
= 1, 1
424 local wrap
, line
= ' int oldtop = lua_gettop(L);\n', ''
425 if f
.xarg
.abstract
then return nil end
426 if f
.xarg
.member_of_class
and f
.xarg
.static
~='1' then
427 if not types
[f
.xarg
.member_of_class
..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
428 local sget
, sn
= types
[f
.xarg
.member_of_class
..'*'].get(stackn
)
429 wrap
= wrap
.. ' ' .. f
.xarg
.member_of_class
.. '* self = ' .. sget
.. ';\n'
433 lua_pushstring(L, "this pointer is NULL");
438 line
= 'self->'..f
.xarg
.fullname
..'('
440 line
= f
.xarg
.fullname
..'('
442 for i
, a
in ipairs(f
.arguments
) do
443 if not types
[a
.xarg
.type_name
] then return nil end
444 local aget
, an
, arg_as
= types
[a
.xarg
.type_name
].get(stackn
)
445 wrap
= wrap
.. ' ' .. argument_name(arg_as
or a
.xarg
.type_name
, 'arg'..argn
) .. ' = '
446 if a
.xarg
.default
=='1' and an
>0 then
447 wrap
= wrap
.. 'lua_isnoneornil(L, '..stackn
..')'
448 for j
= stackn
+1,stackn
+an
-1 do
449 wrap
= wrap
.. ' && lua_isnoneornil(L, '..j
..')'
451 local dv
= a
.xarg
.defaultvalue
452 wrap
= wrap
.. ' ? static_cast< ' .. a
.xarg
.type_name
.. ' >(' .. dv
.. ') : '
454 wrap
= wrap
.. aget
.. ';\n'
455 line
= line
.. (argn
==1 and 'arg' or ', arg') .. argn
460 -- FIXME: hack follows for constructors
461 if f
.calling_line
then line
= f
.calling_line
end
462 if f
.return_type
then line
= f
.return_type
.. ' ret = ' .. line
end
463 wrap
= wrap
.. ' ' .. line
.. ';\n lua_settop(L, oldtop);\n' -- lua_pop(L, '..stackn..');\n'
464 if f
.return_type
then
465 if not types
[f
.return_type
] then return nil end
466 local rput
, rn
= types
[f
.return_type
].push
'ret'
467 wrap
= wrap
.. ' luaL_checkstack(L, '..rn
..', "cannot grow stack for return value");\n'
468 wrap
= wrap
.. ' '..rput
..';\n return '..rn
..';\n'
470 wrap
= wrap
.. ' return 0;\n'
472 f
.wrapper_code
= wrap
476 local fill_test_code
= function(f
, types
)
479 if f
.xarg
.member_of_class
and f
.xarg
.static
~='1' then
480 if not types
[f
.xarg
.member_of_class
..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
481 local stest
, sn
= types
[f
.xarg
.member_of_class
..'*'].test(stackn
)
482 test
= test
.. ' && ' .. stest
485 for i
, a
in ipairs(f
.arguments
) do
486 if not types
[a
.xarg
.type_name
] then return nil end -- print(a.xarg.type_name) return nil end
487 local atest
, an
= types
[a
.xarg
.type_name
].test(stackn
)
488 if a
.xarg
.default
=='1' and an
>0 then
489 test
= test
.. ' && (lqtL_missarg(L, ' .. stackn
.. ', ' .. an
.. ') || '
490 test
= test
.. atest
.. ')'
492 test
= test
.. ' && ' .. atest
496 -- can't make use of default values if I fix number of args
497 test
= '(lua_gettop(L)<' .. stackn
.. ')' .. test
502 local fill_wrappers
= function(functions
, types
)
504 for f
in pairs(functions
) do
505 f
= fill_wrapper_code(f
, types
)
507 f
= assert(fill_test_code(f
, types
), f
.xarg
.fullname
) -- MUST pass
509 --local out = 'extern "C" LQT_EXPORT int lqt_bind'..f.xarg.id..' (lua_State *L) {\n'
510 --.. f.wrapper_code .. '}\n'
517 local make_pushlines
= function(args
, types
)
518 local pushlines
, stack
= '', 0
519 for i
, a
in ipairs(args
) do
520 if not types
[a
.xarg
.type_name
] then return nil end
521 local apush
, an
= types
[a
.xarg
.type_name
].push('arg'..i
)
522 pushlines
= pushlines
.. ' ' .. apush
.. ';\n'
525 return pushlines
, stack
528 local virtual_overload
= function(v
, types
)
530 if v
.virtual_overload
then return v
end
532 if v
.return_type
and not types
[v
.return_type
] then return nil end
533 local rget
, rn
= '', 0
534 if v
.return_type
then rget
, rn
, ret_as
= types
[v
.return_type
].get
'oldtop+1' end
535 local retget
= (v
.return_type
and argument_name(ret_as
or v
.return_type
, 'ret')
536 .. ' = ' .. rget
.. ';' or '') .. 'lua_settop(L, oldtop);return'
537 .. (v
.return_type
and ' ret' or '')
538 -- make argument push
539 local pushlines
, stack
= make_pushlines(v
.arguments
, types
)
540 if not pushlines
then return nil end
542 local luacall
= 'lua_pcall(L, '..(stack
+1)..', '..rn
..', 0)'
543 -- make prototype and fallback
544 local proto
= (v
.return_type
or 'void')..' ;;'..v
.xarg
.name
..' ('
546 for i
, a
in ipairs(v
.arguments
) do
547 proto
= proto
.. (i
>1 and ', ' or '')
548 .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
549 fallback
= fallback
.. (i
>1 and ', arg' or 'arg') .. i
551 proto
= proto
.. ')' .. (v
.xarg
.constant
=='1' and ' const' or '')
552 fallback
= (v
.return_type
and 'return this->' or 'this->')
553 .. v
.xarg
.fullname
.. '(' .. fallback
.. ');\n}\n'
555 int oldtop = lua_gettop(L);
556 lqtL_pushudata(L, this, "]]..string.gsub(v
.xarg
.member_of_class
, '::', '.')..[[*");
557 lua_getfield(L, -1, "]]..v
.xarg
.name
..[[");
558 if (lua_isfunction(L, -1)) {
560 ]] .. pushlines
.. [[
561 if (!]]..luacall
..[[) {
565 lua_settop(L, oldtop);
567 v
.virtual_overload
= ret
568 v
.virtual_proto
= string.gsub(proto
, ';;', '', 1)
572 local fill_shell_class
= function(c
, types
)
573 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
574 local shell
= 'class LQT_EXPORT ' .. shellname
.. ' : public ' .. c
.xarg
.fullname
.. ' {\npublic:\n'
575 shell
= shell
.. ' lua_State *L;\n'
576 for _
, constr
in ipairs(c
.constructors
) do
577 if constr
.xarg
.access
~='private' then
578 local cline
= ' '..shellname
..' (lua_State *l'
580 for i
, a
in ipairs(constr
.arguments
) do
581 cline
= cline
.. ', ' .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
582 argline
= argline
.. (i
>1 and ', arg' or 'arg') .. i
584 cline
= cline
.. ') : ' .. c
.xarg
.fullname
585 .. '(' .. argline
.. '), L(l) '
586 .. '{ lqtL_register(L, this); }\n'
587 shell
= shell
.. cline
590 if c
.copy_constructor
==nil and c
.public_constr
then
591 local cline
= ' '..shellname
..' (lua_State *l, '..c
.xarg
.fullname
..' const& arg1)'
592 cline
= cline
.. ' : ' .. c
.xarg
.fullname
.. '(arg1), L(l) {}\n'
593 shell
= shell
.. cline
595 for i
, v
in pairs(c
.virtuals
) do
596 if v
.xarg
.access
~='private' then
597 if v
.virtual_proto
then shell
= shell
.. ' virtual ' .. v
.virtual_proto
.. ';\n' end
600 shell
= shell
.. ' ~'..shellname
..'() { lqtL_unregister(L, this); }\n'
601 if c
.shell
and c
.qobject
then
602 shell
= shell
.. ' static QMetaObject staticMetaObject;\n'
603 shell
= shell
.. ' virtual const QMetaObject *metaObject() const;\n'
604 shell
= shell
.. ' virtual int qt_metacall(QMetaObject::Call, int, void **);\n'
605 shell
= shell
.. 'private:\n'
606 shell
= shell
.. ' Q_DISABLE_COPY('..shellname
..');\n'
608 shell
= shell
.. '};\n'
609 c
.shell_class
= shell
613 local fill_virtual_overloads
= function(classes
, types
)
614 for c
in pairs(classes
) do
615 for i
, v
in pairs(c
.virtuals
) do
616 if v
.xarg
.access
~='private' then
617 local vret
= virtual_overload(v
, types
)
624 local fill_shell_classes
= function(classes
, types
)
626 for c
in pairs(classes
) do
628 c
= fill_shell_class(c
, types
)
629 if c
then ret
[c
] = true end
636 local print_shell_classes
= function(classes
)
638 for c
in pairs(classes
) do
639 if fhead
then fhead
:close() end
640 local n
= string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
641 fhead
= assert(io
.open(module_name
.._src
..module_name
..'_head_'..n
..'.hpp', 'w'))
642 local print_head
= function(...)
646 print_head('#ifndef LQT_HEAD_'..n
)
647 print_head('#define LQT_HEAD_'..n
)
648 print_head(output_includes
)
649 --print_head('#include <'..string.match(c.xarg.fullname, '^[^:]+')..'>')
653 print_head(c
.shell_class
)
655 --io.stderr:write(c.fullname, '\n')
658 print_head('#endif // LQT_HEAD_'..n
)
660 if fhead
then fhead
:close() end
664 local print_virtual_overloads
= function(classes
)
665 for c
in pairs(classes
) do
668 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
669 for _
,v
in pairs(c
.virtuals
) do
670 if v
.virtual_overload
then
671 vo
= vo
.. string.gsub(v
.virtual_overload
, ';;', shellname
..'::', 1)
674 c
.virtual_overloads
= vo
680 local print_wrappers
= function(index
)
681 for c
in pairs(index
) do
684 for _
, f
in ipairs(c
.methods
) do
685 -- FIXME: should we really discard virtual functions?
686 -- if the virtual overload in the shell uses rawget
687 -- on the environment then we can leave these in the
689 if f
.wrapper_code
and f
.xarg
.virtual
~='1' then
690 local out
= 'static int lqt_bind'..f
.xarg
.id
691 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
692 if f
.xarg
.access
=='public' then
694 wrappers
= wrappers
.. out
.. '\n'
695 meta
[f
] = f
.xarg
.name
699 if not c
.abstract
then
700 for _
, f
in ipairs(c
.constructors
) do
701 if f
.wrapper_code
then
702 local out
= 'static int lqt_bind'..f
.xarg
.id
703 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
704 if f
.xarg
.access
=='public' then
706 wrappers
= wrappers
.. out
.. '\n'
712 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
713 local lua_name
= string.gsub(c
.xarg
.fullname
, '::', '.')
714 local out
= 'static int lqt_delete'..c
.xarg
.id
..' (lua_State *L) {\n'
715 out
= out
..' '..c
.xarg
.fullname
..' *p = static_cast<'
716 ..c
.xarg
.fullname
..'*>(lqtL_toudata(L, 1, "'..lua_name
..'*"));\n'
717 if c
.public_destr
then
718 out
= out
.. ' if (p) delete p;\n'
720 out
= out
.. ' lqtL_eraseudata(L, 1, "'..lua_name
..'*");\n return 0;\n}\n'
722 wrappers
= wrappers
.. out
.. '\n'
724 c
.wrappers
= wrappers
729 local print_metatable
= function(c
)
731 local wrappers
= c
.wrappers
732 for m
, n
in pairs(c
.meta
) do
733 methods
[n
] = methods
[n
] or {}
734 table.insert(methods
[n
], m
)
736 for n
, l
in pairs(methods
) do
737 local disp
= 'static int lqt_dispatcher_'..n
..c
.xarg
.id
..' (lua_State *L) {\n'
738 for _
, f
in ipairs(l
) do
739 disp
= disp
..' if ('..f
.test_code
..') return lqt_bind'..f
.xarg
.id
..'(L);\n'
741 disp
= disp
.. ' lua_settop(L, 0);\n'
742 disp
= disp
.. ' lua_pushstring(L, "'..c
.xarg
.fullname
..'::'..n
..': incorrect or extra arguments");\n'
743 disp
= disp
.. ' return lua_error(L);\n}\n'
745 wrappers
= wrappers
.. disp
.. '\n'
747 local metatable
= 'static luaL_Reg lqt_metatable'..c
.xarg
.id
..'[] = {\n'
748 for n
, l
in pairs(methods
) do
749 metatable
= metatable
.. ' { "'..n
..'", lqt_dispatcher_'..n
..c
.xarg
.id
..' },\n'
751 metatable
= metatable
.. ' { "delete", lqt_delete'..c
.xarg
.id
..' },\n'
752 metatable
= metatable
.. ' { 0, 0 },\n};\n'
753 --print_meta(metatable)
754 wrappers
= wrappers
.. metatable
.. '\n'
756 for b
in string.gmatch(c
.xarg
.bases_with_attributes
or '', '([^;]*);') do
757 if not string.match(b
, '^virtual') then
758 b
= string.gsub(b
, '^[^%s]* ', '')
759 bases
= bases
.. ' {"'..string.gsub(b
,'::','.')..'*", (char*)(void*)static_cast<'..b
..'*>(('..c
.xarg
.fullname
..'*)1)-(char*)1},\n'
762 bases
= 'static lqt_Base lqt_base'..c
.xarg
.id
..'[] = {\n'..bases
..' {NULL, 0}\n};\n'
764 wrappers
= wrappers
.. bases
.. '\n'
765 c
.wrappers
= wrappers
769 local print_metatables
= function(classes
)
770 for c
in pairs(classes
) do
778 local print_single_class
= function(c
)
779 local n
= string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
780 local lua_name
= string.gsub(c
.xarg
.fullname
, '::', '.')
781 local cppname
= module_name
..'_meta_'..n
..'.cpp'
782 table.insert(cpp_files
, cppname
);
783 local fmeta
= assert(io
.open(module_name
.._src
..cppname
, 'w'))
784 local print_meta
= function(...)
788 print_meta('#include "'..module_name
..'_head_'..n
..'.hpp'..'"\n\n')
789 print_meta(c
.wrappers
)
790 if c
.virtual_overloads
then
791 print_meta(c
.virtual_overloads
)
793 print_meta('extern "C" LQT_EXPORT int luaopen_'..n
..' (lua_State *L) {')
794 print_meta('\tlqtL_createclass(L, "'
795 ..lua_name
..'*", lqt_metatable'
796 ..c
.xarg
.id
..', lqt_base'
798 print_meta
'\treturn 0;'
801 if c
.shell
and c
.qobject
then
805 QMetaObject lqt_shell_]]..n
..[[::staticMetaObject;
807 const QMetaObject *lqt_shell_]]..n
..[[::metaObject() const {
808 //int oldtop = lua_gettop(L);
809 lqtL_pushudata(L, this, "]]..c
.xarg
.fullname
..[[*");
810 lua_getfield(L, -1, LQT_OBJMETASTRING);
811 if (lua_isnil(L, -1)) {
813 return &]]..c
.xarg
.fullname
..[[::staticMetaObject;
815 lua_getfield(L, -2, LQT_OBJMETADATA);
817 //qDebug() << "copying qmeta object for slots in ]]..c
.xarg
.fullname
..[[";
818 lqt_shell_]]..n
..[[::staticMetaObject.d.superdata = &]]..c
.xarg
.fullname
..[[::staticMetaObject;
819 lqt_shell_]]..n
..[[::staticMetaObject.d.stringdata = lua_tostring(L, -2);
820 lqt_shell_]]..n
..[[::staticMetaObject.d.data = (uint*)lua_touserdata(L, -1);
821 lqt_shell_]]..n
..[[::staticMetaObject.d.extradata = 0; // slot_metaobj->d.extradata;
822 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETADATA);
823 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETASTRING);
825 //qDebug() << (lua_gettop(L) - oldtop);
826 return &lqt_shell_]]..n
..[[::staticMetaObject;
829 int lqt_shell_]]..n
..[[::qt_metacall(QMetaObject::Call call, int index, void **args) {
830 //qDebug() << "fake calling!";
831 index = ]]..c
.xarg
.fullname
..[[::qt_metacall(call, index, args);
832 if (index < 0) return index;
833 return lqtL_qt_metacall(L, this, call, "QWidget*", index, args);
840 local print_merged_build
= function()
841 local path
= module_name
.._src
842 local mergename
= module_name
..'_merged_build'
843 local merged
= assert(io
.open(path
..mergename
..'.cpp', 'w'))
844 for _
, p
in ipairs(cpp_files
) do
845 merged
:write('#include "'..p
..'"\n')
847 local pro_file
= assert(io
.open(path
..mergename
..'.pro', 'w'))
849 local print_pro
= function(...)
853 print_pro('TEMPLATE = lib')
854 print_pro('TARGET = '..module_name
)
855 print_pro('INCLUDEPATH += .')
856 print_pro('HEADERS += '..module_name
..'_slot.hpp')
857 print_pro('SOURCES += ../common/lqt_common.cpp \\')
858 print_pro(' ../common/lqt_qt.cpp \\')
859 print_pro(' '..module_name
..'_enum.cpp \\')
860 print_pro(' '..module_name
..'_meta.cpp \\')
861 print_pro(' '..module_name
..'_slot.cpp \\')
862 print_pro(' '..mergename
..'.cpp')
865 local print_class_list
= function(classes
)
866 local qobject_present
= false
867 local big_picture
= {}
868 local type_list_t
= {}
869 for c
in pairs(classes
) do
870 local n
= string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
871 if n
=='QObject' then qobject_present
= true end
872 print_single_class(c
)
873 table.insert(big_picture
, 'luaopen_'..n
)
874 table.insert(type_list_t
, 'add_class(\''..c
.xarg
.fullname
..'\', types)\n')
877 local type_list_f
= assert(io
.open(module_name
.._src
..module_name
..'_types.lua', 'w'))
880 local types = (...) or {}
881 local add_class = lqt.classes.insert or error('module lqt.classes not loaded')
883 for k
, v
in ipairs(type_list_t
) do
886 type_list_f
:write('return types\n')
890 if fmeta
then fmeta
:close() end
891 fmeta
= assert(io
.open(module_name
.._src
..module_name
..'_meta.cpp', 'w'))
892 local print_meta
= function(...)
897 print_meta('#include "lqt_common.hpp"')
898 print_meta('#include "'..module_name
..'_slot.hpp'..'"\n\n')
899 for _
, p
in ipairs(big_picture
) do
900 print_meta('extern "C" LQT_EXPORT int '..p
..' (lua_State *);')
902 print_meta('void lqt_create_enums_'..module_name
..' (lua_State *);')
903 print_meta('extern "C" LQT_EXPORT int luaopen_'..module_name
..' (lua_State *L) {')
904 for _
, p
in ipairs(big_picture
) do
905 print_meta('\t'..p
..'(L);')
907 print_meta('\tlqt_create_enums_'..module_name
..'(L);')
908 if qobject_present
then
909 print_meta('\tlua_getfield(L, LUA_REGISTRYINDEX, "QObject*");')
910 print_meta('\tlua_pushstring(L, "__addmethod");')
911 print_meta('\tlqtL_pushaddmethod(L);')
912 print_meta('\tlua_rawset(L, -3);')
914 print_meta('\t//lua_pushlightuserdata(L, (void*)&LqtSlotAcceptor::staticMetaObject);')
915 print_meta('\t//lua_setfield(L, LUA_REGISTRYINDEX, LQT_METAOBJECT);')
916 print_meta('\tlua_pushlightuserdata(L, (void*)new LqtSlotAcceptor(L));')
917 print_meta('\tlua_setfield(L, LUA_REGISTRYINDEX, LQT_METACALLER);')
918 print_meta('\treturn 0;\n}')
919 if fmeta
then fmeta
:close() end
923 local fix_methods_wrappers
= function(classes
)
924 for c
in pairs(classes
) do
925 c
.shell
= (not c
.abstract
) and c
.public_destr
926 for _
, constr
in ipairs(c
.constructors
) do
928 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
929 constr
.calling_line
= '*new '..shellname
..'(L'
930 if #(constr
.arguments
)>0 then constr
.calling_line
= constr
.calling_line
.. ', ' end
932 local shellname
= c
.xarg
.fullname
933 constr
.calling_line
= '*new '..shellname
..'('
935 for i
=1,#(constr
.arguments
) do
936 constr
.calling_line
= constr
.calling_line
.. (i
==1 and '' or ', ') .. 'arg' .. i
938 constr
.calling_line
= constr
.calling_line
.. ')'
939 constr
.xarg
.static
= '1'
940 constr
.return_type
= constr
.xarg
.type_base
..'&'
943 c
.destructor
.return_type
= nil
949 local print_enum_tables
= function(enums
)
950 for e
in pairs(enums
) do
951 local table = 'static lqt_Enum lqt_enum'..e
.xarg
.id
..'[] = {\n'
952 --io.stderr:write(e.xarg.fullname, '\t', #e.values, '\n')
953 for _
,v
in pairs(e
.values
) do
954 table = table .. ' { "' .. v
.xarg
.name
955 .. '", static_cast<int>('..v
.xarg
.fullname
..') },\n'
957 table = table .. ' { 0, 0 }\n'
958 table = table .. '};\n'
964 local print_enum_creator
= function(enums
, n
)
965 local out
= 'static lqt_Enumlist lqt_enum_list[] = {\n'
966 for e
in pairs(enums
) do
967 out
= out
..' { lqt_enum'..e
.xarg
.id
..', "'..e
.xarg
.fullname
..'" },\n'
969 out
= out
..' { 0, 0 },\n};\n'
970 out
= out
.. 'void lqt_create_enums_'..n
..' (lua_State *L) {\n'
971 out
= out
.. ' lqtL_createenumlist(L, lqt_enum_list); return;\n}\n'
976 local copy_signals
= function(functions
)
978 for f
in pairs(functions
) do
979 if f
.xarg
.signal
=='1' then
986 local slots_for_signals
= function(signals
, types
)
988 for sig
in pairs(signals
) do
989 local args
, comma
= '(', ''
990 for i
, a
in ipairs(sig
.arguments
) do
991 args
= args
.. comma
.. a
.xarg
.type_name
.. ' arg'..i
995 local pushlines
, stack
= make_pushlines(sig
.arguments
, types
)
996 if not ret
['void __slot '..args
] and pushlines
then
997 ret
['void __slot '..args
] = 'void LqtSlotAcceptor::__slot '..args
..[[ {
998 //int oldtop = lua_gettop(L);
999 //lua_getfield(L, -1, "__slot]]..string.gsub(args
, ' arg.', '')..[[");
1000 //if (lua_isnil(L, -1)) {
1002 //lua_getfield(L, -1, "__slot");
1004 //if (!lua_isfunction(L, -1)) {
1005 //lua_settop(L, oldtop);
1008 lua_pushvalue(L, -2);
1009 ]] .. pushlines
.. [[
1010 if (lua_pcall(L, ]]..stack
..[[+1, 0, 0)) {
1012 qDebug() << lua_tostring(L, -1);
1015 //lua_settop(L, oldtop);
1023 local print_slots
= function(s
)
1024 print_slot_h
'class LqtSlotAcceptor : public QObject {'
1025 print_slot_h
' Q_OBJECT'
1026 print_slot_h
' lua_State *L;'
1027 print_slot_h
' public:'
1028 print_slot_h
' LqtSlotAcceptor(lua_State *l, QObject *p=NULL) : QObject(p), L(l) { lqtL_register(L, this); }'
1029 print_slot_h
' virtual ~LqtSlotAcceptor() { lqtL_unregister(L, this); }'
1030 print_slot_h
' public slots:'
1031 for p
, b
in pairs(s
) do
1032 print_slot_h(' '..p
..';')
1035 for p
, b
in pairs(s
) do
1041 --------------------------------------------------------------------------------------
1043 local typesystem
= dofile(path
..'types.lua')
1046 for i
, ft
in ipairs(typefiles
) do
1047 ts
= assert(loadfile(ft
))(ts
)
1049 setmetatable(typesystem
, {
1050 __newindex
= function(t
, k
, v
)
1051 --debug('added type', k)
1054 __index
= function(t
, k
)
1056 --if not ret then debug("unknown type:", tostring(k), ret) end
1062 fix_arguments(idindex
) -- fixes default arguments if they are context-relative
1063 local functions
= copy_functions(idindex
) -- picks functions and fixes label
1064 local functions
= fix_functions(functions
) -- fixes name and fullname and fills arguments
1066 local enums
= copy_enums(idindex
) -- picks enums if public
1067 local enums
= fill_enums(enums
) -- fills field "values"
1069 local classes
= copy_classes(idindex
) -- picks classes if not private and not blacklisted
1070 local classes
= fill_virtuals(classes
) -- does that, destructor ("~") excluded
1071 local classes
= distinguish_methods(classes
) -- does that
1072 local classes
= fill_public_destr(classes
) -- does that: checks if destructor is public
1073 local classes
= fill_copy_constructor(classes
) -- does that: checks if copy contructor is public or protected
1074 local classes
= fix_methods_wrappers(classes
)
1075 local classes
= get_qobjects(classes
)
1077 for _
, f
in ipairs(filterfiles
) do
1078 classes
, enums
= loadfile(f
)(classes
, enums
)
1081 local enums
= fill_typesystem_with_enums(enums
, typesystem
) -- does that
1082 local classes
= fill_typesystem_with_classes(classes
, typesystem
)
1084 local functions
= fill_wrappers(functions
, typesystem
)
1085 local classes
= fill_virtual_overloads(classes
, typesystem
) -- does that
1086 local classes
= fill_shell_classes(classes
, typesystem
) -- does that
1088 local signals
= copy_signals(functions
)
1089 local slots
= slots_for_signals(signals
, typesystem
)
1092 ------------- BEGIN OUTPUT
1096 print_enum(output_includes
)
1097 print_slot_h(output_includes
)
1098 print_slot_c('#include "'..module_name
..'_slot.hpp'..'"\n\n')
1101 local classes
= print_shell_classes(classes
) -- does that
1102 local classes
= print_virtual_overloads(classes
, typesystem
) -- does that
1103 local enums
= print_enum_tables(enums
) -- does that
1104 local enums
= print_enum_creator(enums
, module_name
) -- does that + print enum list
1105 local classes
= print_wrappers(classes
) -- just compiles metatable list
1106 local classes
= print_metatables(classes
) -- just collects the wrappers + generates dispatchers
1107 local classes
= print_class_list(classes
) -- does that + prints everything related to class
1109 local slots
= print_slots(slots
)
1111 --print_openmodule(module_name) -- does that