5 Copyright (c) 2007-2009 Mauro Iazzi
6 Copyright (c) 2008 Peter Kümmel
8 Permission is hereby granted, free of charge, to any person
9 obtaining a copy of this software and associated documentation
10 files (the "Software"), to deal in the Software without
11 restriction, including without limitation the rights to use,
12 copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the
14 Software is furnished to do so, subject to the following
17 The above copyright notice and this permission notice shall be
18 included in all copies or substantial portions of the Software.
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 OTHER DEALINGS IN THE SOFTWARE.
31 local osseparator
= package
.config
:sub(1,1)
33 local path
= string.match(arg
[0], '(.*'..osseparator
..')[^%'..osseparator
..']+') or ''
35 --- remove script name
36 path
= string.sub(arg
[0], 1, #arg
[0] - #'generator.lua')
41 local module_name
= nil
43 local filterfiles
= {}
44 local output_includes
= {
50 while select(i
, ...) do
51 local argi
= select(i
, ...)
54 module_name
= select(i
, ...)
55 elseif argi
=='-i' then
57 table.insert(output_includes
, (select(i
, ...)))
58 elseif argi
=='-t' then
60 table.insert(typefiles
, (select(i
, ...)))
61 elseif argi
=='-f' then
63 table.insert(filterfiles
, (select(i
, ...)))
65 filename
= filename
and error'duplicate filename' or argi
71 local my_includes
= ''
72 for _
, i
in ipairs(output_includes
) do
73 if string.match(i
, '^<.+>$') then
74 my_includes
= my_includes
.. '#include '..i
..'\n'
75 elseif string.match(i
, '^".+"$') then
76 my_includes
= my_includes
.. '#include '..i
..'\n'
78 my_includes
= my_includes
.. '#include "'..i
..'"\n'
81 output_includes
= my_includes
.. '\n'
83 local readfile
= function(fn
)
84 local f
= assert(io
.open(fn
))
90 local fprint
= function(f
)
92 for i
= 1, select('#',...) do
93 f
:write((i
==1) and '' or '\t', tostring(select(i
,...)))
100 local _src
= '_src'..osseparator
101 local debug
= fprint(io
.stderr
)
102 local print_enum
= fprint(assert(io
.open(module_name
.._src
..module_name
..'_enum.cpp', 'w')))
103 local print_slot_h
= fprint(assert(io
.open(module_name
.._src
..module_name
..'_slot.hpp', 'w')))
104 local print_slot_c
= fprint(assert(io
.open(module_name
.._src
..module_name
..'_slot.cpp', 'w')))
106 local xmlstream
, idindex
= dofile(path
..'xml.lua')(readfile(filename
))
108 dofile(path
..'classes.lua') -- this should become a require at some point
110 ----------------------------------------------------------------------------------
112 local copy_functions
= function(index
)
114 for e
in pairs(index
) do
115 if e
.label
:match
'^Function' then
124 local fix_arguments
= function(all
)
126 for e
in pairs(all
or {}) do
127 if e
.xarg
.fullname
then fullnames
[e
.xarg
.fullname
] = true end
129 for a
in pairs(all
) do
130 if a
.label
=='Argument'
131 and a
.xarg
.default
=='1'
132 and (not string.match(a
.xarg
.defaultvalue
, '^[-+]?%d+%.?%d*[L]?$'))
133 and (not string.match(a
.xarg
.defaultvalue
, '^".*"$'))
134 and a
.xarg
.defaultvalue
~='true'
135 and a
.xarg
.defaultvalue
~='false'
136 and (not string.match(a
.xarg
.defaultvalue
, '^0[xX]%d+$')) then
137 local dv
, call = string.match(a
.xarg
.defaultvalue
, '(.-)(%(%))')
138 dv
= dv
or a
.xarg
.defaultvalue
140 local context
= a
.xarg
.context
141 while not fullnames
[context
..'::'..dv
] and context
~='' do
142 context
= string.match(context
, '^(.*)::') or ''
144 if fullnames
[context
..'::'..dv
] then
145 a
.xarg
.defaultvalue
= context
..'::'..dv
..call
146 elseif fullnames
[dv
] then
147 a
.xarg
.defaultvalue
= dv
..call
150 a
.xarg
.defaultvalue
= nil
157 local fix_functions
= function(index
)
158 for f
in pairs(index
) do
160 for i
, a
in ipairs(f
) do
161 -- avoid bogus 'void' arguments
162 if a
.xarg
.type_name
=='void' and i
==1 and f
[2]==nil then break end
163 if a
.label
=='Argument' then
164 table.insert(args
, a
)
168 f
.return_type
= f
.xarg
.type_name
169 if f
.xarg
.type_name
=='void' then
176 local copy_enums
= function(index
)
178 for e
in pairs(index
) do
180 and not string.match(e
.xarg
.fullname
, '%b<>')
181 and e
.xarg
.access
=='public' then
188 local fill_enums
= function(index
)
189 for e
in pairs(index
) do
191 for _
, v
in ipairs(e
) do
192 if v
.label
=='Enumerator' then
193 table.insert(values
, v
)
201 local class_is_public
= function (fullnames
, c
)
203 if c
.xarg
.access
~='public' then return false end
204 if c
.xarg
.member_of_class
then
205 local p
= fullnames
[c
.xarg
.member_of_class
]
206 assert(p
, 'member_of_class should exist')
207 assert(p
.label
=='Class', 'member_of_class should be a class')
208 c
= fullnames
[c
.xarg
.member_of_class
]
216 local copy_classes
= function(index
)
219 for k
,v
in pairs(index
) do
220 if k
.label
=='Class' then fullnames
[k
.xarg
.fullname
] = k
end
222 for e
in pairs(index
) do
224 and class_is_public(fullnames
, e
)
225 and not e
.xarg
.fullname
:match
'%b<>' then
227 elseif e
.label
=='Class'
228 and not e
.xarg
.fullname
:match
'%b<>' then
229 --print('class', e.xarg.fullname, 'rejected because not public')
235 local get_qobjects
= function(index
)
237 for c
in pairs(index
) do
238 classes
[c
.xarg
.fullname
] = c
241 is_qobject
= function(c
)
242 if c
==nil then return false end
243 if c
.qobject
then return true end
244 if c
.xarg
.fullname
=='QObject' then
248 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
249 local base
= classes
[b
]
250 if is_qobject(base
) then
251 --debug(c.xarg.fullname, "is a QObject")
258 for c
in pairs(index
) do
259 local qobj
= is_qobject(c
)
264 local fill_virtuals
= function(index
)
266 for c
in pairs(index
) do
267 classes
[c
.xarg
.fullname
] = c
270 get_virtuals
= function(c
)
272 for _
, f
in ipairs(c
) do
273 if f
.label
=='Function' and f
.xarg
.virtual
=='1' then
274 local n
= string.match(f
.xarg
.name
, '~') or f
.xarg
.name
275 if n
~='~' and n
~='metaObject' then ret
[n
] = f
end
278 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
279 local base
= classes
[b
]
280 if type(base
)=='table' then
281 local bv
= get_virtuals(base
)
282 for n
, f
in pairs(bv
) do
283 if not ret
[n
] then ret
[n
] = f
end
287 for _
, f
in ipairs(c
) do
288 if f
.label
=='Function'
289 and f
.xarg
.access
~='private'
290 and (ret
[string.match(f
.xarg
.name
, '~') or f
.xarg
.name
]) then
292 local n
= string.match(f
.xarg
.name
, '~')or f
.xarg
.name
298 for c
in pairs(index
) do
299 c
.virtuals
= get_virtuals(c
)
300 for _
, f
in pairs(c
.virtuals
) do
301 if f
.xarg
.abstract
=='1' then c
.abstract
=true break end
307 local distinguish_methods
= function(index
)
308 for c
in pairs(index
) do
309 local construct
, destruct
, normal
= {}, nil, {}
310 local n
= c
.xarg
.name
312 for _
, f
in ipairs(c
) do
313 if n
==f
.xarg
.name
then
314 table.insert(construct
, f
)
315 elseif f
.xarg
.name
:match
'~' then
318 if (not string.match(f
.xarg
.name
, '^operator%W'))
319 and (not f
.xarg
.member_template_parameters
)
320 and (not f
.xarg
.friend
) then
321 table.insert(normal
, f
)
325 c
.constructors
= construct
326 c
.destructor
= destruct
332 local fill_public_destr
= function(index
)
334 for c
in pairs(index
) do
335 classes
[c
.xarg
.fullname
] = c
337 local destr_is_public
338 destr_is_public
= function(c
)
340 return c
.destructor
.xarg
.access
=='public'
342 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
343 local base
= classes
[b
]
344 if base
and not destr_is_public(base
) then
351 for c
in pairs(index
) do
352 c
.public_destr
= destr_is_public(c
)
357 local fill_copy_constructor
= function(index
)
359 for c
in pairs(index
) do
360 classes
[c
.xarg
.name
] = c
362 for c
in pairs(index
) do
364 for _
, f
in ipairs(c
.constructors
) do
366 and f
.arguments
[1].xarg
.type_name
==c
.xarg
.fullname
..' const&' then
371 c
.copy_constructor
= copy
373 local copy_constr_is_public
374 copy_constr_is_public
= function(c
)
375 if c
.copy_constructor
then
376 return (c
.copy_constructor
.xarg
.access
=='public')
377 or (c
.copy_constructor
.xarg
.access
=='protected')
380 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
381 local base
= classes
[b
]
382 if base
and not copy_constr_is_public(base
) then
389 for c
in pairs(index
) do
390 c
.public_constr
= copy_constr_is_public(c
)
395 local fill_typesystem_with_enums
= function(enums
, types
)
396 local etype
= function(en
)
399 return 'lqtL_pushenum(L, '..n
..', "'..string.gsub(en
, '::', '.')..'")', 1
402 return 'static_cast<'..en
..'>'
403 ..'(lqtL_toenum(L, '..n
..', "'..string.gsub(en
, '::', '.')..'"))', 1
406 return 'lqtL_isenum(L, '..n
..', "'..string.gsub(en
, '::', '.')..'")', 1
408 onstack
= string.gsub(en
, '::', '.')..',',
412 for e
in pairs(enums
) do
413 if types
[e
.xarg
.fullname
]==nil then
415 types
[e
.xarg
.fullname
] = etype(e
.xarg
.fullname
)
417 --io.stderr:write(e.xarg.fullname, ': already present\n')
423 local put_class_in_filesystem
= lqt
.classes
.insert
424 local fill_typesystem_with_classes
= function(classes
, types
)
426 for c
in pairs(classes
) do
427 ret
[c
] = put_class_in_filesystem(c
.xarg
.fullname
, types
) --, true)
432 local argument_name
= function(tn
, an
)
434 if string.match(tn
, '%(%*%)') then
435 ret
= string.gsub(tn
, '%(%*%)', '(*'..an
..')', 1)
436 elseif string.match(tn
, '%[.*%]') then
437 ret
= string.gsub(tn
, '%s*(%[.*%])', ' '..an
..'%1')
439 ret
= tn
.. ' ' .. an
444 local fill_wrapper_code
= function(f
, types
)
445 if f
.wrapper_code
then return f
end
446 local stackn
, argn
= 1, 1
447 local stack_args
, defects
= '', 0
448 local wrap
, line
= ' int oldtop = lua_gettop(L);\n', ''
449 if f
.xarg
.abstract
then return nil end
450 if f
.xarg
.member_of_class
and f
.xarg
.static
~='1' then
451 if not types
[f
.xarg
.member_of_class
..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
452 stack_args
= stack_args
.. types
[f
.xarg
.member_of_class
..'*'].onstack
453 defects
= defects
+ 7 -- FIXME: arbitrary
454 if f
.xarg
.constant
=='1' then
455 defects
= defects
+ 8 -- FIXME: arbitrary
457 local sget
, sn
= types
[f
.xarg
.member_of_class
..'*'].get(stackn
)
458 wrap
= wrap
.. ' ' .. f
.xarg
.member_of_class
.. '* self = ' .. sget
.. ';\n'
462 lua_pushstring(L, "this pointer is NULL");
467 line
= 'self->'..f
.xarg
.fullname
..'('
469 line
= f
.xarg
.fullname
..'('
471 for i
, a
in ipairs(f
.arguments
) do
472 if not types
[a
.xarg
.type_name
] then return nil end
473 local aget
, an
, arg_as
= types
[a
.xarg
.type_name
].get(stackn
)
474 stack_args
= stack_args
.. types
[a
.xarg
.type_name
].onstack
475 if types
[a
.xarg
.type_name
].defect
then defects
= defects
+ types
[a
.xarg
.type_name
].defect
end
476 wrap
= wrap
.. ' ' .. argument_name(arg_as
or a
.xarg
.type_name
, 'arg'..argn
) .. ' = '
477 if a
.xarg
.default
=='1' and an
>0 then
478 wrap
= wrap
.. 'lua_isnoneornil(L, '..stackn
..')'
479 for j
= stackn
+1,stackn
+an
-1 do
480 wrap
= wrap
.. ' && lua_isnoneornil(L, '..j
..')'
482 local dv
= a
.xarg
.defaultvalue
483 wrap
= wrap
.. ' ? static_cast< ' .. a
.xarg
.type_name
.. ' >(' .. dv
.. ') : '
485 wrap
= wrap
.. aget
.. ';\n'
486 line
= line
.. (argn
==1 and 'arg' or ', arg') .. argn
491 -- FIXME: hack follows for constructors
492 if f
.calling_line
then line
= f
.calling_line
end
493 if f
.return_type
then line
= f
.return_type
.. ' ret = ' .. line
end
494 wrap
= wrap
.. ' ' .. line
.. ';\n lua_settop(L, oldtop);\n' -- lua_pop(L, '..stackn..');\n'
495 if f
.return_type
then
496 if not types
[f
.return_type
] then return nil end
497 local rput
, rn
= types
[f
.return_type
].push
'ret'
498 wrap
= wrap
.. ' luaL_checkstack(L, '..rn
..', "cannot grow stack for return value");\n'
499 wrap
= wrap
.. ' '..rput
..';\n return '..rn
..';\n'
501 wrap
= wrap
.. ' return 0;\n'
503 f
.wrapper_code
= wrap
504 f
.stack_arguments
= stack_args
509 local fill_test_code
= function(f
, types
)
512 if f
.xarg
.member_of_class
and f
.xarg
.static
~='1' then
513 if not types
[f
.xarg
.member_of_class
..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
514 local stest
, sn
= types
[f
.xarg
.member_of_class
..'*'].test(stackn
)
515 test
= test
.. ' && ' .. stest
518 for i
, a
in ipairs(f
.arguments
) do
519 if not types
[a
.xarg
.type_name
] then return nil end -- print(a.xarg.type_name) return nil end
520 local atest
, an
= types
[a
.xarg
.type_name
].test(stackn
)
521 if a
.xarg
.default
=='1' and an
>0 then
522 test
= test
.. ' && (lqtL_missarg(L, ' .. stackn
.. ', ' .. an
.. ') || '
523 test
= test
.. atest
.. ')'
525 test
= test
.. ' && ' .. atest
529 -- can't make use of default values if I fix number of args
530 test
= '(lua_gettop(L)<' .. stackn
.. ')' .. test
535 local fill_wrappers
= function(functions
, types
)
537 for f
in pairs(functions
) do
538 f
= fill_wrapper_code(f
, types
)
540 f
= assert(fill_test_code(f
, types
), f
.xarg
.fullname
) -- MUST pass
542 --local out = 'extern "C" LQT_EXPORT int lqt_bind'..f.xarg.id..' (lua_State *L) {\n'
543 --.. f.wrapper_code .. '}\n'
550 local make_pushlines
= function(args
, types
)
551 local pushlines
, stack
= '', 0
552 for i
, a
in ipairs(args
) do
553 if not types
[a
.xarg
.type_name
] then return nil end
554 local apush
, an
= types
[a
.xarg
.type_name
].push('arg'..i
)
555 pushlines
= pushlines
.. ' ' .. apush
.. ';\n'
558 return pushlines
, stack
561 local virtual_overload
= function(v
, types
)
563 if v
.virtual_overload
then return v
end
565 if v
.return_type
and not types
[v
.return_type
] then return nil end
566 local rget
, rn
= '', 0
567 if v
.return_type
then rget
, rn
, ret_as
= types
[v
.return_type
].get
'oldtop+1' end
568 local retget
= (v
.return_type
and argument_name(ret_as
or v
.return_type
, 'ret')
569 .. ' = ' .. rget
.. ';' or '') .. 'lua_settop(L, oldtop);return'
570 .. (v
.return_type
and ' ret' or '')
571 -- make argument push
572 local pushlines
, stack
= make_pushlines(v
.arguments
, types
)
573 if not pushlines
then return nil end
575 local luacall
= 'lqtL_pcall(L, '..(stack
+1)..', '..rn
..', 0)'
576 -- make prototype and fallback
577 local proto
= (v
.return_type
or 'void')..' ;;'..v
.xarg
.name
..' ('
579 for i
, a
in ipairs(v
.arguments
) do
580 proto
= proto
.. (i
>1 and ', ' or '')
581 .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
582 fallback
= fallback
.. (i
>1 and ', arg' or 'arg') .. i
584 proto
= proto
.. ')' .. (v
.xarg
.constant
=='1' and ' const' or '')
585 fallback
= (v
.return_type
and 'return this->' or 'this->')
586 .. v
.xarg
.fullname
.. '(' .. fallback
.. ');\n}\n'
588 int oldtop = lua_gettop(L);
589 lqtL_pushudata(L, this, "]]..string.gsub(v
.xarg
.member_of_class
, '::', '.')..[[*");
590 lqtL_getoverload(L, -1, "]]..v
.xarg
.name
..[[");
591 if (lua_isfunction(L, -1)) {
593 ]] .. pushlines
.. [[
594 if (!]]..luacall
..[[) {
598 lua_settop(L, oldtop);
600 v
.virtual_overload
= ret
601 v
.virtual_proto
= string.gsub(proto
, ';;', '', 1)
605 local fill_shell_class
= function(c
, types
)
606 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
607 local shell
= 'class LQT_EXPORT ' .. shellname
.. ' : public ' .. c
.xarg
.fullname
.. ' {\npublic:\n'
608 shell
= shell
.. ' lua_State *L;\n'
609 for _
, constr
in ipairs(c
.constructors
) do
610 if constr
.xarg
.access
~='private' then
611 local cline
= ' '..shellname
..' (lua_State *l'
613 for i
, a
in ipairs(constr
.arguments
) do
614 cline
= cline
.. ', ' .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
615 argline
= argline
.. (i
>1 and ', arg' or 'arg') .. i
617 cline
= cline
.. ') : ' .. c
.xarg
.fullname
618 .. '(' .. argline
.. '), L(l) '
619 .. '{ lqtL_register(L, this); }\n'
620 shell
= shell
.. cline
623 if c
.copy_constructor
==nil and c
.public_constr
then
624 local cline
= ' '..shellname
..' (lua_State *l, '..c
.xarg
.fullname
..' const& arg1)'
625 cline
= cline
.. ' : ' .. c
.xarg
.fullname
.. '(arg1), L(l) {}\n'
626 shell
= shell
.. cline
628 for i
, v
in pairs(c
.virtuals
) do
629 if v
.xarg
.access
~='private' then
630 if v
.virtual_proto
then shell
= shell
.. ' virtual ' .. v
.virtual_proto
.. ';\n' end
633 shell
= shell
.. ' ~'..shellname
..'() { lqtL_unregister(L, this); }\n'
634 if c
.shell
and c
.qobject
then
635 shell
= shell
.. ' static QMetaObject staticMetaObject;\n'
636 shell
= shell
.. ' virtual const QMetaObject *metaObject() const;\n'
637 shell
= shell
.. ' virtual int qt_metacall(QMetaObject::Call, int, void **);\n'
638 shell
= shell
.. 'private:\n'
639 shell
= shell
.. ' Q_DISABLE_COPY('..shellname
..');\n'
641 shell
= shell
.. '};\n'
642 c
.shell_class
= shell
646 local fill_virtual_overloads
= function(classes
, types
)
647 for c
in pairs(classes
) do
648 for i
, v
in pairs(c
.virtuals
) do
649 if v
.xarg
.access
~='private' then
650 local vret
= virtual_overload(v
, types
)
657 local fill_shell_classes
= function(classes
, types
)
659 for c
in pairs(classes
) do
661 c
= fill_shell_class(c
, types
)
662 if c
then ret
[c
] = true end
669 local print_shell_classes
= function(classes
)
671 for c
in pairs(classes
) do
672 if fhead
then fhead
:close() end
673 local n
= string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
674 fhead
= assert(io
.open(module_name
.._src
..module_name
..'_head_'..n
..'.hpp', 'w'))
675 local print_head
= function(...)
679 print_head('#ifndef LQT_HEAD_'..n
)
680 print_head('#define LQT_HEAD_'..n
)
681 print_head(output_includes
)
682 --print_head('#include <'..string.match(c.xarg.fullname, '^[^:]+')..'>')
686 print_head(c
.shell_class
)
688 --io.stderr:write(c.fullname, '\n')
691 print_head('#endif // LQT_HEAD_'..n
)
693 if fhead
then fhead
:close() end
697 local print_virtual_overloads
= function(classes
)
698 for c
in pairs(classes
) do
701 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
702 for _
,v
in pairs(c
.virtuals
) do
703 if v
.virtual_overload
then
704 vo
= vo
.. string.gsub(v
.virtual_overload
, ';;', shellname
..'::', 1)
707 c
.virtual_overloads
= vo
713 local print_wrappers
= function(index
)
714 for c
in pairs(index
) do
717 for _
, f
in ipairs(c
.methods
) do
718 -- FIXME: should we really discard virtual functions?
719 -- if the virtual overload in the shell uses rawget
720 -- on the environment then we can leave these in the
722 if f
.wrapper_code
and f
.xarg
.virtual
~='1' then
723 local out
= 'static int lqt_bind'..f
.xarg
.id
724 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
725 if f
.xarg
.access
=='public' then
727 wrappers
= wrappers
.. out
.. '\n'
728 meta
[f
] = f
.xarg
.name
732 if not c
.abstract
then
733 for _
, f
in ipairs(c
.constructors
) do
734 if f
.wrapper_code
then
735 local out
= 'static int lqt_bind'..f
.xarg
.id
736 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
737 if f
.xarg
.access
=='public' then
739 wrappers
= wrappers
.. out
.. '\n'
745 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
746 local lua_name
= string.gsub(c
.xarg
.fullname
, '::', '.')
747 local out
= 'static int lqt_delete'..c
.xarg
.id
..' (lua_State *L) {\n'
748 out
= out
..' '..c
.xarg
.fullname
..' *p = static_cast<'
749 ..c
.xarg
.fullname
..'*>(lqtL_toudata(L, 1, "'..lua_name
..'*"));\n'
750 if c
.public_destr
then
751 out
= out
.. ' if (p) delete p;\n'
753 out
= out
.. ' lqtL_eraseudata(L, 1, "'..lua_name
..'*");\n return 0;\n}\n'
755 wrappers
= wrappers
.. out
.. '\n'
757 c
.wrappers
= wrappers
762 local print_metatable
= function(c
)
764 local wrappers
= c
.wrappers
765 for m
, n
in pairs(c
.meta
) do
766 methods
[n
] = methods
[n
] or {}
767 table.insert(methods
[n
], m
)
769 for n
, l
in pairs(methods
) do
770 local duplicates
= {}
771 for _
, f
in ipairs(l
) do
773 for sa
, g
in pairs(duplicates
) do
774 if sa
==f
.stack_arguments
then
775 --debug("function equal: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
776 if f
.defects
<g
.defects
then
780 elseif string.match(sa
, "^"..f
.stack_arguments
) then -- there is already a version with more arguments
781 --debug("function superseded: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
782 elseif string.match(f
.stack_arguments
, '^'..sa
) then -- there is already a version with less arguments
783 --debug("function superseding: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
787 duplicates
[f
.stack_arguments
] = f
793 for sa, f in pairs(l) do
794 numinitial = numinitial + 1
796 for sa, f in pairs(duplicates) do
797 numfinal = numfinal + 1
799 if numinitial-numfinal>0 then debug(c.xarg.fullname, "suppressed:", numinitial-numfinal) end
801 methods
[n
] = duplicates
803 for n
, l
in pairs(methods
) do
804 local disp
= 'static int lqt_dispatcher_'..n
..c
.xarg
.id
..' (lua_State *L) {\n'
805 for _
, f
in pairs(l
) do
806 disp
= disp
..' if ('..f
.test_code
..') return lqt_bind'..f
.xarg
.id
..'(L);\n'
808 disp
= disp
.. ' lua_settop(L, 0);\n'
809 disp
= disp
.. ' lua_pushstring(L, "'..c
.xarg
.fullname
..'::'..n
..': incorrect or extra arguments");\n'
810 disp
= disp
.. ' return lua_error(L);\n}\n'
812 wrappers
= wrappers
.. disp
.. '\n'
814 local metatable
= 'static luaL_Reg lqt_metatable'..c
.xarg
.id
..'[] = {\n'
815 for n
, l
in pairs(methods
) do
816 metatable
= metatable
.. ' { "'..n
..'", lqt_dispatcher_'..n
..c
.xarg
.id
..' },\n'
818 metatable
= metatable
.. ' { "delete", lqt_delete'..c
.xarg
.id
..' },\n'
819 metatable
= metatable
.. ' { 0, 0 },\n};\n'
820 --print_meta(metatable)
821 wrappers
= wrappers
.. metatable
.. '\n'
823 for b
in string.gmatch(c
.xarg
.bases_with_attributes
or '', '([^;]*);') do
824 if not string.match(b
, '^virtual') then
825 b
= string.gsub(b
, '^[^%s]* ', '')
826 bases
= bases
.. ' {"'..string.gsub(b
,'::','.')..'*", (char*)(void*)static_cast<'..b
..'*>(('..c
.xarg
.fullname
..'*)1)-(char*)1},\n'
829 bases
= 'static lqt_Base lqt_base'..c
.xarg
.id
..'[] = {\n'..bases
..' {NULL, 0}\n};\n'
831 wrappers
= wrappers
.. bases
.. '\n'
832 c
.wrappers
= wrappers
836 local print_metatables
= function(classes
)
837 for c
in pairs(classes
) do
845 local print_single_class
= function(c
)
846 local n
= string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
847 local lua_name
= string.gsub(c
.xarg
.fullname
, '::', '.')
848 local cppname
= module_name
..'_meta_'..n
..'.cpp'
849 table.insert(cpp_files
, cppname
);
850 local fmeta
= assert(io
.open(module_name
.._src
..cppname
, 'w'))
851 local print_meta
= function(...)
855 print_meta('#include "'..module_name
..'_head_'..n
..'.hpp'..'"\n\n')
856 print_meta(c
.wrappers
)
857 if c
.virtual_overloads
then
858 print_meta(c
.virtual_overloads
)
860 print_meta('extern "C" LQT_EXPORT int luaopen_'..n
..' (lua_State *L) {')
861 print_meta('\tlqtL_createclass(L, "'
862 ..lua_name
..'*", lqt_metatable'
863 ..c
.xarg
.id
..', lqt_base'
865 print_meta
'\treturn 0;'
868 if c
.shell
and c
.qobject
then
872 QMetaObject lqt_shell_]]..n
..[[::staticMetaObject;
874 const QMetaObject *lqt_shell_]]..n
..[[::metaObject() const {
875 //int oldtop = lua_gettop(L);
876 lqtL_pushudata(L, this, "]]..c
.xarg
.fullname
..[[*");
877 lua_getfield(L, -1, LQT_OBJMETASTRING);
878 if (lua_isnil(L, -1)) {
880 return &]]..c
.xarg
.fullname
..[[::staticMetaObject;
882 lua_getfield(L, -2, LQT_OBJMETADATA);
884 //qDebug() << "copying qmeta object for slots in ]]..c
.xarg
.fullname
..[[";
885 lqt_shell_]]..n
..[[::staticMetaObject.d.superdata = &]]..c
.xarg
.fullname
..[[::staticMetaObject;
886 lqt_shell_]]..n
..[[::staticMetaObject.d.stringdata = lua_tostring(L, -2);
887 lqt_shell_]]..n
..[[::staticMetaObject.d.data = (uint*)lua_touserdata(L, -1);
888 lqt_shell_]]..n
..[[::staticMetaObject.d.extradata = 0; // slot_metaobj->d.extradata;
889 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETADATA);
890 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETASTRING);
892 //qDebug() << (lua_gettop(L) - oldtop);
893 return &lqt_shell_]]..n
..[[::staticMetaObject;
896 int lqt_shell_]]..n
..[[::qt_metacall(QMetaObject::Call call, int index, void **args) {
897 //qDebug() << "fake calling!";
898 index = ]]..c
.xarg
.fullname
..[[::qt_metacall(call, index, args);
899 if (index < 0) return index;
900 return lqtL_qt_metacall(L, this, call, "QWidget*", index, args);
907 local print_merged_build
= function()
908 local path
= module_name
.._src
909 local mergename
= module_name
..'_merged_build'
910 local merged
= assert(io
.open(path
..mergename
..'.cpp', 'w'))
911 for _
, p
in ipairs(cpp_files
) do
912 merged
:write('#include "'..p
..'"\n')
914 local pro_file
= assert(io
.open(path
..mergename
..'.pro', 'w'))
916 local print_pro
= function(...)
920 print_pro('TEMPLATE = lib')
921 print_pro('TARGET = '..module_name
)
922 print_pro('INCLUDEPATH += .')
923 print_pro('HEADERS += '..module_name
..'_slot.hpp')
924 print_pro('SOURCES += ../common/lqt_common.cpp \\')
925 print_pro(' ../common/lqt_qt.cpp \\')
926 print_pro(' '..module_name
..'_enum.cpp \\')
927 print_pro(' '..module_name
..'_meta.cpp \\')
928 print_pro(' '..module_name
..'_slot.cpp \\')
929 print_pro(' '..mergename
..'.cpp')
932 local print_class_list
= function(classes
)
933 local qobject_present
= false
934 local big_picture
= {}
935 local type_list_t
= {}
936 for c
in pairs(classes
) do
937 local n
= string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
938 if n
=='QObject' then qobject_present
= true end
939 print_single_class(c
)
940 table.insert(big_picture
, 'luaopen_'..n
)
941 table.insert(type_list_t
, 'add_class(\''..c
.xarg
.fullname
..'\', types)\n')
944 local type_list_f
= assert(io
.open(module_name
.._src
..module_name
..'_types.lua', 'w'))
947 local types = (...) or {}
948 local add_class = lqt.classes.insert or error('module lqt.classes not loaded')
950 for k
, v
in ipairs(type_list_t
) do
953 type_list_f
:write('return types\n')
957 if fmeta
then fmeta
:close() end
958 fmeta
= assert(io
.open(module_name
.._src
..module_name
..'_meta.cpp', 'w'))
959 local print_meta
= function(...)
964 print_meta('#include "lqt_common.hpp"')
965 print_meta('#include "'..module_name
..'_slot.hpp'..'"\n\n')
966 for _
, p
in ipairs(big_picture
) do
967 print_meta('extern "C" LQT_EXPORT int '..p
..' (lua_State *);')
969 print_meta('void lqt_create_enums_'..module_name
..' (lua_State *);')
970 print_meta('extern "C" LQT_EXPORT int luaopen_'..module_name
..' (lua_State *L) {')
971 for _
, p
in ipairs(big_picture
) do
972 print_meta('\t'..p
..'(L);')
974 print_meta('\tlqt_create_enums_'..module_name
..'(L);')
975 if qobject_present
then
976 print_meta('\tlua_getfield(L, LUA_REGISTRYINDEX, "QObject*");')
977 print_meta('\tlua_pushstring(L, "__addmethod");')
978 print_meta('\tlqtL_pushaddmethod(L);')
979 print_meta('\tlua_rawset(L, -3);')
981 print_meta('\t//lua_pushlightuserdata(L, (void*)&LqtSlotAcceptor::staticMetaObject);')
982 print_meta('\t//lua_setfield(L, LUA_REGISTRYINDEX, LQT_METAOBJECT);')
983 print_meta('\tlqtL_passudata(L, (void*)(new LqtSlotAcceptor(L)), "QObject*");')
984 print_meta('\tlua_setfield(L, LUA_REGISTRYINDEX, LQT_METACALLER);')
985 print_meta('\treturn 0;\n}')
986 if fmeta
then fmeta
:close() end
990 local fix_methods_wrappers
= function(classes
)
991 for c
in pairs(classes
) do
992 c
.shell
= (not c
.abstract
) and c
.public_destr
993 c
.shell
= c
.shell
and (next(c
.virtuals
)~=nil)
994 for _
, constr
in ipairs(c
.constructors
) do
996 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
997 constr
.calling_line
= 'new '..shellname
..'(L'
998 if #(constr
.arguments
)>0 then constr
.calling_line
= constr
.calling_line
.. ', ' end
1000 local shellname
= c
.xarg
.fullname
1001 constr
.calling_line
= 'new '..shellname
..'('
1003 for i
=1,#(constr
.arguments
) do
1004 constr
.calling_line
= constr
.calling_line
.. (i
==1 and '' or ', ') .. 'arg' .. i
1006 constr
.calling_line
= '*('..constr
.calling_line
.. '))'
1007 constr
.xarg
.static
= '1'
1008 constr
.return_type
= constr
.xarg
.type_base
..'&'
1010 if c
.destructor
then
1011 c
.destructor
.return_type
= nil
1017 local print_enum_tables
= function(enums
)
1018 for e
in pairs(enums
) do
1019 local table = 'static lqt_Enum lqt_enum'..e
.xarg
.id
..'[] = {\n'
1020 --io.stderr:write(e.xarg.fullname, '\t', #e.values, '\n')
1021 for _
,v
in pairs(e
.values
) do
1022 table = table .. ' { "' .. v
.xarg
.name
1023 .. '", static_cast<int>('..v
.xarg
.fullname
..') },\n'
1025 table = table .. ' { 0, 0 }\n'
1026 table = table .. '};\n'
1027 e
.enum_table
= table
1032 local print_enum_creator
= function(enums
, n
)
1033 local out
= 'static lqt_Enumlist lqt_enum_list[] = {\n'
1034 for e
in pairs(enums
) do
1035 out
= out
..' { lqt_enum'..e
.xarg
.id
..', "'..string.gsub(e
.xarg
.fullname
, "::", ".")..'" },\n'
1037 out
= out
..' { 0, 0 },\n};\n'
1038 out
= out
.. 'void lqt_create_enums_'..n
..' (lua_State *L) {\n'
1039 out
= out
.. ' lqtL_createenumlist(L, lqt_enum_list); return;\n}\n'
1044 local copy_signals
= function(functions
)
1046 for f
in pairs(functions
) do
1047 if f
.xarg
.signal
=='1' then
1054 local slots_for_signals
= function(signals
, types
)
1056 for sig
in pairs(signals
) do
1057 local args
, comma
= '(', ''
1058 for i
, a
in ipairs(sig
.arguments
) do
1059 args
= args
.. comma
.. a
.xarg
.type_name
.. ' arg'..i
1063 local pushlines
, stack
= make_pushlines(sig
.arguments
, types
)
1064 if not ret
['void __slot '..args
] and pushlines
then
1065 ret
['void __slot '..args
] = 'void LqtSlotAcceptor::__slot '..args
..[[ {
1066 //int oldtop = lua_gettop(L);
1067 //lua_getfield(L, -1, "__slot]]..string.gsub(args
, ' arg.', '')..[[");
1068 //if (lua_isnil(L, -1)) {
1070 //lua_getfield(L, -1, "__slot");
1072 //if (!lua_isfunction(L, -1)) {
1073 //lua_settop(L, oldtop);
1076 lua_pushvalue(L, -2);
1077 ]] .. pushlines
.. [[
1078 if (lqtL_pcall(L, ]]..stack
..[[+1, 0, 0)) {
1080 qDebug() << lua_tostring(L, -1);
1083 //lua_settop(L, oldtop);
1091 local print_slots
= function(s
)
1092 print_slot_h
'class LqtSlotAcceptor : public QObject {'
1093 print_slot_h
' Q_OBJECT'
1094 print_slot_h
' lua_State *L;'
1095 print_slot_h
' public:'
1096 print_slot_h
' LqtSlotAcceptor(lua_State *l, QObject *p=NULL) : QObject(p), L(l) { lqtL_register(L, this); }'
1097 print_slot_h
' virtual ~LqtSlotAcceptor() { lqtL_unregister(L, this); }'
1098 print_slot_h
' public slots:'
1099 for p
, b
in pairs(s
) do
1100 print_slot_h(' '..p
..';')
1103 for p
, b
in pairs(s
) do
1109 --------------------------------------------------------------------------------------
1111 local typesystem
= dofile(path
..'types.lua')
1114 for i
, ft
in ipairs(typefiles
) do
1115 ts
= assert(loadfile(ft
))(ts
)
1117 setmetatable(typesystem
, {
1118 __newindex
= function(t
, k
, v
)
1119 --debug('added type', k)
1122 __index
= function(t
, k
)
1124 --if not ret then debug("unknown type:", tostring(k), ret) end
1130 fix_arguments(idindex
) -- fixes default arguments if they are context-relative
1131 local functions
= copy_functions(idindex
) -- picks functions and fixes label
1132 local functions
= fix_functions(functions
) -- fixes name and fullname and fills arguments
1134 local enums
= copy_enums(idindex
) -- picks enums if public
1135 local enums
= fill_enums(enums
) -- fills field "values"
1137 local classes
= copy_classes(idindex
) -- picks classes if not private and not blacklisted
1138 local classes
= fill_virtuals(classes
) -- does that, destructor ("~") excluded
1139 local classes
= distinguish_methods(classes
) -- does that
1140 local classes
= fill_public_destr(classes
) -- does that: checks if destructor is public
1141 local classes
= fill_copy_constructor(classes
) -- does that: checks if copy contructor is public or protected
1142 local classes
= fix_methods_wrappers(classes
)
1143 local classes
= get_qobjects(classes
)
1145 for _
, f
in ipairs(filterfiles
) do
1146 classes
, enums
= loadfile(f
)(classes
, enums
)
1149 local enums
= fill_typesystem_with_enums(enums
, typesystem
) -- does that
1150 local classes
= fill_typesystem_with_classes(classes
, typesystem
)
1152 local functions
= fill_wrappers(functions
, typesystem
)
1153 local classes
= fill_virtual_overloads(classes
, typesystem
) -- does that
1154 local classes
= fill_shell_classes(classes
, typesystem
) -- does that
1156 local signals
= copy_signals(functions
)
1157 local slots
= slots_for_signals(signals
, typesystem
)
1160 ------------- BEGIN OUTPUT
1164 print_enum(output_includes
)
1165 print_slot_h(output_includes
)
1166 print_slot_c('#include "'..module_name
..'_slot.hpp'..'"\n\n')
1169 local classes
= print_shell_classes(classes
) -- does that
1170 local classes
= print_virtual_overloads(classes
, typesystem
) -- does that
1171 local enums
= print_enum_tables(enums
) -- does that
1172 local enums
= print_enum_creator(enums
, module_name
) -- does that + print enum list
1173 local classes
= print_wrappers(classes
) -- just compiles metatable list
1174 local classes
= print_metatables(classes
) -- just collects the wrappers + generates dispatchers
1175 local classes
= print_class_list(classes
) -- does that + prints everything related to class
1177 local slots
= print_slots(slots
)
1179 --print_openmodule(module_name) -- does that