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 if f
.wrapper_code
and f
.xarg
.virtual
~='1' then
686 local out
= 'static int lqt_bind'..f
.xarg
.id
687 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
688 if f
.xarg
.access
=='public' then
690 wrappers
= wrappers
.. out
.. '\n'
691 meta
[f
] = f
.xarg
.name
695 if not c
.abstract
then
696 for _
, f
in ipairs(c
.constructors
) do
697 if f
.wrapper_code
then
698 local out
= 'static int lqt_bind'..f
.xarg
.id
699 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
700 if f
.xarg
.access
=='public' then
702 wrappers
= wrappers
.. out
.. '\n'
708 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
709 local lua_name
= string.gsub(c
.xarg
.fullname
, '::', '.')
710 local out
= 'static int lqt_delete'..c
.xarg
.id
..' (lua_State *L) {\n'
711 out
= out
..' '..c
.xarg
.fullname
..' *p = static_cast<'
712 ..c
.xarg
.fullname
..'*>(lqtL_toudata(L, 1, "'..lua_name
..'*"));\n'
713 if c
.public_destr
then
714 out
= out
.. ' if (p) delete p;\n'
716 out
= out
.. ' lqtL_eraseudata(L, 1, "'..lua_name
..'*");\n return 0;\n}\n'
718 wrappers
= wrappers
.. out
.. '\n'
720 c
.wrappers
= wrappers
725 local print_metatable
= function(c
)
727 local wrappers
= c
.wrappers
728 for m
, n
in pairs(c
.meta
) do
729 methods
[n
] = methods
[n
] or {}
730 table.insert(methods
[n
], m
)
732 for n
, l
in pairs(methods
) do
733 local disp
= 'static int lqt_dispatcher_'..n
..c
.xarg
.id
..' (lua_State *L) {\n'
734 for _
, f
in ipairs(l
) do
735 disp
= disp
..' if ('..f
.test_code
..') return lqt_bind'..f
.xarg
.id
..'(L);\n'
737 disp
= disp
.. ' lua_settop(L, 0);\n'
738 disp
= disp
.. ' lua_pushstring(L, "'..c
.xarg
.fullname
..'::'..n
..': incorrect or extra arguments");\n'
739 disp
= disp
.. ' return lua_error(L);\n}\n'
741 wrappers
= wrappers
.. disp
.. '\n'
743 local metatable
= 'static luaL_Reg lqt_metatable'..c
.xarg
.id
..'[] = {\n'
744 for n
, l
in pairs(methods
) do
745 metatable
= metatable
.. ' { "'..n
..'", lqt_dispatcher_'..n
..c
.xarg
.id
..' },\n'
747 metatable
= metatable
.. ' { "delete", lqt_delete'..c
.xarg
.id
..' },\n'
748 metatable
= metatable
.. ' { 0, 0 },\n};\n'
749 --print_meta(metatable)
750 wrappers
= wrappers
.. metatable
.. '\n'
752 for b
in string.gmatch(c
.xarg
.bases_with_attributes
or '', '([^;]*);') do
753 if not string.match(b
, '^virtual') then
754 b
= string.gsub(b
, '^[^%s]* ', '')
755 bases
= bases
.. ' {"'..string.gsub(b
,'::','.')..'*", (char*)(void*)static_cast<'..b
..'*>(('..c
.xarg
.fullname
..'*)1)-(char*)1},\n'
758 bases
= 'static lqt_Base lqt_base'..c
.xarg
.id
..'[] = {\n'..bases
..' {NULL, 0}\n};\n'
760 wrappers
= wrappers
.. bases
.. '\n'
761 c
.wrappers
= wrappers
765 local print_metatables
= function(classes
)
766 for c
in pairs(classes
) do
774 local print_single_class
= function(c
)
775 local n
= string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
776 local lua_name
= string.gsub(c
.xarg
.fullname
, '::', '.')
777 local cppname
= module_name
..'_meta_'..n
..'.cpp'
778 table.insert(cpp_files
, cppname
);
779 local fmeta
= assert(io
.open(module_name
.._src
..cppname
, 'w'))
780 local print_meta
= function(...)
784 print_meta('#include "'..module_name
..'_head_'..n
..'.hpp'..'"\n\n')
785 print_meta(c
.wrappers
)
786 if c
.virtual_overloads
then
787 print_meta(c
.virtual_overloads
)
789 print_meta('extern "C" LQT_EXPORT int luaopen_'..n
..' (lua_State *L) {')
790 print_meta('\tlqtL_createclass(L, "'
791 ..lua_name
..'*", lqt_metatable'
792 ..c
.xarg
.id
..', lqt_base'
794 print_meta
'\treturn 0;'
797 if c
.shell
and c
.qobject
then
801 QMetaObject lqt_shell_]]..n
..[[::staticMetaObject;
803 const QMetaObject *lqt_shell_]]..n
..[[::metaObject() const {
804 //int oldtop = lua_gettop(L);
805 lqtL_pushudata(L, this, "]]..c
.xarg
.fullname
..[[*");
806 lua_getfield(L, -1, LQT_OBJMETASTRING);
807 if (lua_isnil(L, -1)) {
809 return &]]..c
.xarg
.fullname
..[[::staticMetaObject;
811 lua_getfield(L, -2, LQT_OBJMETADATA);
813 //qDebug() << "copying qmeta object for slots in ]]..c
.xarg
.fullname
..[[";
814 lqt_shell_]]..n
..[[::staticMetaObject.d.superdata = &]]..c
.xarg
.fullname
..[[::staticMetaObject;
815 lqt_shell_]]..n
..[[::staticMetaObject.d.stringdata = lua_tostring(L, -2);
816 lqt_shell_]]..n
..[[::staticMetaObject.d.data = (uint*)lua_touserdata(L, -1);
817 lqt_shell_]]..n
..[[::staticMetaObject.d.extradata = 0; // slot_metaobj->d.extradata;
818 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETADATA);
819 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETASTRING);
821 //qDebug() << (lua_gettop(L) - oldtop);
822 return &lqt_shell_]]..n
..[[::staticMetaObject;
825 int lqt_shell_]]..n
..[[::qt_metacall(QMetaObject::Call call, int index, void **args) {
826 //qDebug() << "fake calling!";
827 index = ]]..c
.xarg
.fullname
..[[::qt_metacall(call, index, args);
828 if (index < 0) return index;
829 return lqtL_qt_metacall(L, this, call, "QWidget*", index, args);
836 local print_merged_build
= function()
837 local path
= module_name
.._src
838 local mergename
= module_name
..'_merged_build'
839 local merged
= assert(io
.open(path
..mergename
..'.cpp', 'w'))
840 for _
, p
in ipairs(cpp_files
) do
841 merged
:write('#include "'..p
..'"\n')
843 local pro_file
= assert(io
.open(path
..mergename
..'.pro', 'w'))
845 local print_pro
= function(...)
849 print_pro('TEMPLATE = lib')
850 print_pro('TARGET = '..module_name
)
851 print_pro('INCLUDEPATH += .')
852 print_pro('HEADERS += '..module_name
..'_slot.hpp')
853 print_pro('SOURCES += ../common/lqt_common.cpp \\')
854 print_pro(' ../common/lqt_qt.cpp \\')
855 print_pro(' '..module_name
..'_enum.cpp \\')
856 print_pro(' '..module_name
..'_meta.cpp \\')
857 print_pro(' '..module_name
..'_slot.cpp \\')
858 print_pro(' '..mergename
..'.cpp')
861 local print_class_list
= function(classes
)
862 local qobject_present
= false
863 local big_picture
= {}
864 local type_list_t
= {}
865 for c
in pairs(classes
) do
866 local n
= string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
867 if n
=='QObject' then qobject_present
= true end
868 print_single_class(c
)
869 table.insert(big_picture
, 'luaopen_'..n
)
870 table.insert(type_list_t
, 'add_class(\''..c
.xarg
.fullname
..'\', types)\n')
873 local type_list_f
= assert(io
.open(module_name
.._src
..module_name
..'_types.lua', 'w'))
876 local types = (...) or {}
877 local add_class = lqt.classes.insert or error('module lqt.classes not loaded')
879 for k
, v
in ipairs(type_list_t
) do
882 type_list_f
:write('return types\n')
886 if fmeta
then fmeta
:close() end
887 fmeta
= assert(io
.open(module_name
.._src
..module_name
..'_meta.cpp', 'w'))
888 local print_meta
= function(...)
893 print_meta('#include "lqt_common.hpp"')
894 print_meta('#include "'..module_name
..'_slot.hpp'..'"\n\n')
895 for _
, p
in ipairs(big_picture
) do
896 print_meta('extern "C" LQT_EXPORT int '..p
..' (lua_State *);')
898 print_meta('void lqt_create_enums_'..module_name
..' (lua_State *);')
899 print_meta('extern "C" LQT_EXPORT int luaopen_'..module_name
..' (lua_State *L) {')
900 for _
, p
in ipairs(big_picture
) do
901 print_meta('\t'..p
..'(L);')
903 print_meta('\tlqt_create_enums_'..module_name
..'(L);')
904 if qobject_present
then
905 print_meta('\tlua_getfield(L, LUA_REGISTRYINDEX, "QObject*");')
906 print_meta('\tlua_pushstring(L, "__addmethod");')
907 print_meta('\tlqtL_pushaddmethod(L);')
908 print_meta('\tlua_rawset(L, -3);')
910 print_meta('\t//lua_pushlightuserdata(L, (void*)&LqtSlotAcceptor::staticMetaObject);')
911 print_meta('\t//lua_setfield(L, LUA_REGISTRYINDEX, LQT_METAOBJECT);')
912 print_meta('\tlua_pushlightuserdata(L, (void*)new LqtSlotAcceptor(L));')
913 print_meta('\tlua_setfield(L, LUA_REGISTRYINDEX, LQT_METACALLER);')
914 print_meta('\treturn 0;\n}')
915 if fmeta
then fmeta
:close() end
919 local fix_methods_wrappers
= function(classes
)
920 for c
in pairs(classes
) do
921 c
.shell
= (not c
.abstract
) and c
.public_destr
922 for _
, constr
in ipairs(c
.constructors
) do
924 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
925 constr
.calling_line
= '*new '..shellname
..'(L'
926 if #(constr
.arguments
)>0 then constr
.calling_line
= constr
.calling_line
.. ', ' end
928 local shellname
= c
.xarg
.fullname
929 constr
.calling_line
= '*new '..shellname
..'('
931 for i
=1,#(constr
.arguments
) do
932 constr
.calling_line
= constr
.calling_line
.. (i
==1 and '' or ', ') .. 'arg' .. i
934 constr
.calling_line
= constr
.calling_line
.. ')'
935 constr
.xarg
.static
= '1'
936 constr
.return_type
= constr
.xarg
.type_base
..'&'
939 c
.destructor
.return_type
= nil
945 local print_enum_tables
= function(enums
)
946 for e
in pairs(enums
) do
947 local table = 'static lqt_Enum lqt_enum'..e
.xarg
.id
..'[] = {\n'
948 --io.stderr:write(e.xarg.fullname, '\t', #e.values, '\n')
949 for _
,v
in pairs(e
.values
) do
950 table = table .. ' { "' .. v
.xarg
.name
951 .. '", static_cast<int>('..v
.xarg
.fullname
..') },\n'
953 table = table .. ' { 0, 0 }\n'
954 table = table .. '};\n'
960 local print_enum_creator
= function(enums
, n
)
961 local out
= 'static lqt_Enumlist lqt_enum_list[] = {\n'
962 for e
in pairs(enums
) do
963 out
= out
..' { lqt_enum'..e
.xarg
.id
..', "'..e
.xarg
.fullname
..'" },\n'
965 out
= out
..' { 0, 0 },\n};\n'
966 out
= out
.. 'void lqt_create_enums_'..n
..' (lua_State *L) {\n'
967 out
= out
.. ' lqtL_createenumlist(L, lqt_enum_list); return;\n}\n'
972 local copy_signals
= function(functions
)
974 for f
in pairs(functions
) do
975 if f
.xarg
.signal
=='1' then
982 local slots_for_signals
= function(signals
, types
)
984 for sig
in pairs(signals
) do
985 local args
, comma
= '(', ''
986 for i
, a
in ipairs(sig
.arguments
) do
987 args
= args
.. comma
.. a
.xarg
.type_name
.. ' arg'..i
991 local pushlines
, stack
= make_pushlines(sig
.arguments
, types
)
992 if not ret
['void __slot '..args
] and pushlines
then
993 ret
['void __slot '..args
] = 'void LqtSlotAcceptor::__slot '..args
..[[ {
994 //int oldtop = lua_gettop(L);
995 //lua_getfield(L, -1, "__slot]]..string.gsub(args
, ' arg.', '')..[[");
996 //if (lua_isnil(L, -1)) {
998 //lua_getfield(L, -1, "__slot");
1000 //if (!lua_isfunction(L, -1)) {
1001 //lua_settop(L, oldtop);
1004 lua_pushvalue(L, -2);
1005 ]] .. pushlines
.. [[
1006 if (lua_pcall(L, ]]..stack
..[[+1, 0, 0)) {
1008 qDebug() << lua_tostring(L, -1);
1011 //lua_settop(L, oldtop);
1019 local print_slots
= function(s
)
1020 print_slot_h
'class LqtSlotAcceptor : public QObject {'
1021 print_slot_h
' Q_OBJECT'
1022 print_slot_h
' lua_State *L;'
1023 print_slot_h
' public:'
1024 print_slot_h
' LqtSlotAcceptor(lua_State *l, QObject *p=NULL) : QObject(p), L(l) { lqtL_register(L, this); }'
1025 print_slot_h
' virtual ~LqtSlotAcceptor() { lqtL_unregister(L, this); }'
1026 print_slot_h
' public slots:'
1027 for p
, b
in pairs(s
) do
1028 print_slot_h(' '..p
..';')
1031 for p
, b
in pairs(s
) do
1037 --------------------------------------------------------------------------------------
1039 local typesystem
= dofile(path
..'types.lua')
1042 for i
, ft
in ipairs(typefiles
) do
1043 ts
= assert(loadfile(ft
))(ts
)
1045 setmetatable(typesystem
, {
1046 __newindex
= function(t
, k
, v
)
1047 --debug('added type', k)
1050 __index
= function(t
, k
)
1052 --if not ret then debug("unknown type:", tostring(k), ret) end
1058 fix_arguments(idindex
) -- fixes default arguments if they are context-relative
1059 local functions
= copy_functions(idindex
) -- picks functions and fixes label
1060 local functions
= fix_functions(functions
) -- fixes name and fullname and fills arguments
1062 local enums
= copy_enums(idindex
) -- picks enums if public
1063 local enums
= fill_enums(enums
) -- fills field "values"
1065 local classes
= copy_classes(idindex
) -- picks classes if not private and not blacklisted
1066 local classes
= fill_virtuals(classes
) -- does that, destructor ("~") excluded
1067 local classes
= distinguish_methods(classes
) -- does that
1068 local classes
= fill_public_destr(classes
) -- does that: checks if destructor is public
1069 local classes
= fill_copy_constructor(classes
) -- does that: checks if copy contructor is public or protected
1070 local classes
= fix_methods_wrappers(classes
)
1071 local classes
= get_qobjects(classes
)
1073 for _
, f
in ipairs(filterfiles
) do
1074 classes
, enums
= loadfile(f
)(classes
, enums
)
1077 local enums
= fill_typesystem_with_enums(enums
, typesystem
) -- does that
1078 local classes
= fill_typesystem_with_classes(classes
, typesystem
)
1080 local functions
= fill_wrappers(functions
, typesystem
)
1081 local classes
= fill_virtual_overloads(classes
, typesystem
) -- does that
1082 local classes
= fill_shell_classes(classes
, typesystem
) -- does that
1084 local signals
= copy_signals(functions
)
1085 local slots
= slots_for_signals(signals
, typesystem
)
1088 ------------- BEGIN OUTPUT
1092 print_enum(output_includes
)
1093 print_slot_h(output_includes
)
1094 print_slot_c('#include "'..module_name
..'_slot.hpp'..'"\n\n')
1097 local classes
= print_shell_classes(classes
) -- does that
1098 local classes
= print_virtual_overloads(classes
, typesystem
) -- does that
1099 local enums
= print_enum_tables(enums
) -- does that
1100 local enums
= print_enum_creator(enums
, module_name
) -- does that + print enum list
1101 local classes
= print_wrappers(classes
) -- just compiles metatable list
1102 local classes
= print_metatables(classes
) -- just collects the wrappers + generates dispatchers
1103 local classes
= print_class_list(classes
) -- does that + prints everything related to class
1105 local slots
= print_slots(slots
)
1107 --print_openmodule(module_name) -- does that