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')))
107 local function ignore(name
, cause
)
109 io
.stderr
:write('Ignoring: ', name
, '(', cause
, ')')
113 local xmlstream
, idindex
= dofile(path
..'xml.lua')(readfile(filename
))
115 dofile(path
..'classes.lua') -- this should become a require at some point
117 ----------------------------------------------------------------------------------
119 local copy_functions
= function(index
)
121 for e
in pairs(index
) do
122 if e
.label
:match
'^Function' then
131 local fix_arguments
= function(all
)
133 for e
in pairs(all
or {}) do
134 if e
.xarg
.fullname
then fullnames
[e
.xarg
.fullname
] = true end
136 for a
in pairs(all
) do
137 if a
.label
=='Argument'
138 and a
.xarg
.default
=='1'
139 and (not string.match(a
.xarg
.defaultvalue
, '^[-+]?%d+%.?%d*[L]?$'))
140 and (not string.match(a
.xarg
.defaultvalue
, '^".*"$'))
141 and a
.xarg
.defaultvalue
~='true'
142 and a
.xarg
.defaultvalue
~='false'
143 and (not string.match(a
.xarg
.defaultvalue
, '^0[xX]%d+$')) then
144 local dv
, call = string.match(a
.xarg
.defaultvalue
, '(.-)(%(%))')
145 dv
= dv
or a
.xarg
.defaultvalue
147 local context
= a
.xarg
.context
148 while not fullnames
[context
..'::'..dv
] and context
~='' do
149 context
= string.match(context
, '^(.*)::') or ''
151 if fullnames
[context
..'::'..dv
] then
152 a
.xarg
.defaultvalue
= context
..'::'..dv
..call
153 elseif fullnames
[dv
] then
154 a
.xarg
.defaultvalue
= dv
..call
157 a
.xarg
.defaultvalue
= nil
164 local operatorTrans
= {
173 local get_operator
= function(name
)
174 return name
:match('^operator(.+)$')
177 local is_operator
= function(name
)
178 return name
:match('^operator.')
181 local rename_operator
= function(name
)
182 local trans
= operatorTrans
[get_operator(name
)]
183 if is_operator(name
) and trans
then
189 local fix_functions
= function(index
)
190 for f
in pairs(index
) do
192 for i
, a
in ipairs(f
) do
193 -- avoid bogus 'void' arguments
194 if a
.xarg
.type_name
=='void' and i
==1 and f
[2]==nil then break end
195 if a
.label
=='Argument' then
196 table.insert(args
, a
)
200 f
.return_type
= f
.xarg
.type_name
201 if f
.xarg
.type_name
=='void' then
208 local copy_enums
= function(index
)
210 for e
in pairs(index
) do
212 and not string.match(e
.xarg
.fullname
, '%b<>')
213 and e
.xarg
.access
=='public' then
220 local fill_enums
= function(index
)
221 for e
in pairs(index
) do
223 for _
, v
in ipairs(e
) do
224 if v
.label
=='Enumerator' then
225 table.insert(values
, v
)
233 local class_is_public
= function (fullnames
, c
)
235 if c
.xarg
.access
~='public' then return false end
236 if c
.xarg
.member_of_class
then
237 local p
= fullnames
[c
.xarg
.member_of_class
]
238 assert(p
, 'member_of_class should exist')
239 assert(p
.label
=='Class', 'member_of_class should be a class')
240 c
= fullnames
[c
.xarg
.member_of_class
]
248 local copy_classes
= function(index
)
251 for k
,v
in pairs(index
) do
252 if k
.label
=='Class' then fullnames
[k
.xarg
.fullname
] = k
end
254 for e
in pairs(index
) do
255 if e
.label
=='Class' then
256 if class_is_public(fullnames
, e
)
257 and not e
.xarg
.fullname
:match
'%b<>' then
259 elseif not e
.xarg
.fullname
:match
'%b<>' then
260 ignore(e
.xarg
.fullname
, 'not public')
262 ignore(e
.xarg
.fullname
, 'template')
269 local get_qobjects
= function(index
)
271 for c
in pairs(index
) do
272 classes
[c
.xarg
.fullname
] = c
275 is_qobject
= function(c
)
276 if c
==nil then return false end
277 if c
.qobject
then return true end
278 if c
.xarg
.fullname
=='QObject' then
282 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
283 local base
= classes
[b
]
284 if is_qobject(base
) then
285 --debug(c.xarg.fullname, "is a QObject")
292 for c
in pairs(index
) do
293 local qobj
= is_qobject(c
)
298 local fill_virtuals
= function(index
)
300 for c
in pairs(index
) do
301 classes
[c
.xarg
.fullname
] = c
304 get_virtuals
= function(c
)
306 for _
, f
in ipairs(c
) do
307 if f
.label
=='Function' and f
.xarg
.virtual
=='1' then
308 local n
= string.match(f
.xarg
.name
, '~') or f
.xarg
.name
309 if n
~='~' and n
~='metaObject' then ret
[n
] = f
end
312 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
313 local base
= classes
[b
]
314 if type(base
)=='table' then
315 local bv
= get_virtuals(base
)
316 for n
, f
in pairs(bv
) do
317 if not ret
[n
] then ret
[n
] = f
end
321 for _
, f
in ipairs(c
) do
322 if f
.label
=='Function'
323 and f
.xarg
.access
~='private'
324 and (ret
[string.match(f
.xarg
.name
, '~') or f
.xarg
.name
]) then
326 local n
= string.match(f
.xarg
.name
, '~')or f
.xarg
.name
332 for c
in pairs(index
) do
333 c
.virtuals
= get_virtuals(c
)
334 for _
, f
in pairs(c
.virtuals
) do
335 if f
.xarg
.abstract
=='1' then c
.abstract
=true break end
341 local should_wrap
= function(f
)
342 local name
= f
.xarg
.name
343 -- FIXME: operator and friend, causes trouble with QDataStream
344 if f
.xarg
.friend
then return false end
345 -- not an operator - accept
346 if not name
:match('^operator') then return true end
347 -- accept supported operators
348 if is_operator(name
) and operatorTrans
[get_operator(name
)] then return true end
352 local distinguish_methods
= function(index
)
353 for c
in pairs(index
) do
354 local construct
, destruct
, normal
= {}, nil, {}
355 local n
= c
.xarg
.name
357 for _
, f
in ipairs(c
) do
358 if n
==f
.xarg
.name
then
359 table.insert(construct
, f
)
360 elseif f
.xarg
.name
:match
'~' then
364 and (not f
.xarg
.member_template_parameters
)
365 and (not f
.xarg
.friend
) then
366 table.insert(normal
, f
)
368 ignore(f
.xarg
.name
, 'operator/template/friend')
372 c
.constructors
= construct
373 c
.destructor
= destruct
379 local fill_public_destr
= function(index
)
381 for c
in pairs(index
) do
382 classes
[c
.xarg
.fullname
] = c
384 local destr_is_public
385 destr_is_public
= function(c
)
387 return c
.destructor
.xarg
.access
=='public'
389 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
390 local base
= classes
[b
]
391 if base
and not destr_is_public(base
) then
398 for c
in pairs(index
) do
399 c
.public_destr
= destr_is_public(c
)
404 local fill_copy_constructor
= function(index
)
406 for c
in pairs(index
) do
407 classes
[c
.xarg
.name
] = c
409 for c
in pairs(index
) do
411 for _
, f
in ipairs(c
.constructors
) do
413 and f
.arguments
[1].xarg
.type_name
==c
.xarg
.fullname
..' const&' then
418 c
.copy_constructor
= copy
420 local copy_constr_is_public
421 copy_constr_is_public
= function(c
)
422 if c
.copy_constructor
then
423 return (c
.copy_constructor
.xarg
.access
=='public')
424 or (c
.copy_constructor
.xarg
.access
=='protected')
427 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
428 local base
= classes
[b
]
429 if base
and not copy_constr_is_public(base
) then
436 for c
in pairs(index
) do
437 c
.public_constr
= copy_constr_is_public(c
)
442 local fill_typesystem_with_enums
= function(enums
, types
)
443 local etype
= function(en
)
446 return 'lqtL_pushenum(L, '..n
..', "'..string.gsub(en
, '::', '.')..'")', 1
449 return 'static_cast<'..en
..'>'
450 ..'(lqtL_toenum(L, '..n
..', "'..string.gsub(en
, '::', '.')..'"))', 1
453 return 'lqtL_isenum(L, '..n
..', "'..string.gsub(en
, '::', '.')..'")', 1
455 onstack
= string.gsub(en
, '::', '.')..',',
459 for e
in pairs(enums
) do
460 if types
[e
.xarg
.fullname
]==nil then
462 types
[e
.xarg
.fullname
] = etype(e
.xarg
.fullname
)
464 --io.stderr:write(e.xarg.fullname, ': already present\n')
470 local put_class_in_filesystem
= lqt
.classes
.insert
471 local fill_typesystem_with_classes
= function(classes
, types
)
473 for c
in pairs(classes
) do
474 ret
[c
] = put_class_in_filesystem(c
.xarg
.fullname
, types
) --, true)
479 local argument_name
= function(tn
, an
)
481 if string.match(tn
, '%(%*%)') then
482 ret
= string.gsub(tn
, '%(%*%)', '(*'..an
..')', 1)
483 elseif string.match(tn
, '%[.*%]') then
484 ret
= string.gsub(tn
, '%s*(%[.*%])', ' '..an
..'%1')
486 ret
= tn
.. ' ' .. an
491 local fill_wrapper_code
= function(f
, types
)
492 if f
.wrapper_code
then return f
end
493 local stackn
, argn
= 1, 1
494 local stack_args
, defects
= '', 0
495 local wrap
, line
= ' int oldtop = lua_gettop(L);\n', ''
496 if f
.xarg
.abstract
then return nil end
497 if f
.xarg
.member_of_class
and f
.xarg
.static
~='1' then
498 if not types
[f
.xarg
.member_of_class
..'*'] then
499 ignore(f
.xarg
.member_of_class
, 'not a member of selected class')
502 stack_args
= stack_args
.. types
[f
.xarg
.member_of_class
..'*'].onstack
503 defects
= defects
+ 7 -- FIXME: arbitrary
504 if f
.xarg
.constant
=='1' then
505 defects
= defects
+ 8 -- FIXME: arbitrary
507 local sget
, sn
= types
[f
.xarg
.member_of_class
..'*'].get(stackn
)
508 wrap
= wrap
.. ' ' .. f
.xarg
.member_of_class
.. '* self = ' .. sget
.. ';\n'
512 lua_pushstring(L, "this pointer is NULL");
517 if is_operator(f
.xarg
.name
) then
518 local op
= get_operator(f
.xarg
.name
)
520 -- the ++ and -- operators don't line () at the end, like: *self ++()
521 if op
~= '++' and op
~= '--' then
525 line
= 'self->'..f
.xarg
.fullname
..'('
528 line
= f
.xarg
.fullname
..'('
530 for i
, a
in ipairs(f
.arguments
) do
531 if not types
[a
.xarg
.type_name
] then
532 ignore(f
.xarg
.fullname
, 'unkown argument type: '..a
.xarg
.type_name
)
535 local aget
, an
, arg_as
= types
[a
.xarg
.type_name
].get(stackn
)
536 stack_args
= stack_args
.. types
[a
.xarg
.type_name
].onstack
537 if types
[a
.xarg
.type_name
].defect
then defects
= defects
+ types
[a
.xarg
.type_name
].defect
end
538 wrap
= wrap
.. ' ' .. argument_name(arg_as
or a
.xarg
.type_name
, 'arg'..argn
) .. ' = '
539 if a
.xarg
.default
=='1' and an
>0 then
540 wrap
= wrap
.. 'lua_isnoneornil(L, '..stackn
..')'
541 for j
= stackn
+1,stackn
+an
-1 do
542 wrap
= wrap
.. ' && lua_isnoneornil(L, '..j
..')'
544 local dv
= a
.xarg
.defaultvalue
545 wrap
= wrap
.. ' ? static_cast< ' .. a
.xarg
.type_name
.. ' >(' .. dv
.. ') : '
547 wrap
= wrap
.. aget
.. ';\n'
548 line
= line
.. (argn
==1 and 'arg' or ', arg') .. argn
552 if not f
.xarg
.name
:match('%+%+') and not f
.xarg
.name
:match('%-%-') then
555 -- FIXME: hack follows for constructors
556 if f
.calling_line
then line
= f
.calling_line
end
557 if f
.return_type
then line
= f
.return_type
.. ' ret = ' .. line
end
558 wrap
= wrap
.. ' ' .. line
.. ';\n lua_settop(L, oldtop);\n' -- lua_pop(L, '..stackn..');\n'
559 if f
.return_type
then
560 if not types
[f
.return_type
] then return nil end
561 local rput
, rn
= types
[f
.return_type
].push
'ret'
562 wrap
= wrap
.. ' luaL_checkstack(L, '..rn
..', "cannot grow stack for return value");\n'
563 wrap
= wrap
.. ' '..rput
..';\n return '..rn
..';\n'
565 wrap
= wrap
.. ' return 0;\n'
567 f
.wrapper_code
= wrap
568 f
.stack_arguments
= stack_args
573 local fill_test_code
= function(f
, types
)
576 if f
.xarg
.member_of_class
and f
.xarg
.static
~='1' then
577 if not types
[f
.xarg
.member_of_class
..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
578 local stest
, sn
= types
[f
.xarg
.member_of_class
..'*'].test(stackn
)
579 test
= test
.. ' && ' .. stest
582 for i
, a
in ipairs(f
.arguments
) do
583 if not types
[a
.xarg
.type_name
] then return nil end -- print(a.xarg.type_name) return nil end
584 local atest
, an
= types
[a
.xarg
.type_name
].test(stackn
)
585 if a
.xarg
.default
=='1' and an
>0 then
586 test
= test
.. ' && (lqtL_missarg(L, ' .. stackn
.. ', ' .. an
.. ') || '
587 test
= test
.. atest
.. ')'
589 test
= test
.. ' && ' .. atest
593 -- can't make use of default values if I fix number of args
594 test
= '(lua_gettop(L)<' .. stackn
.. ')' .. test
599 local fill_wrappers
= function(functions
, types
)
601 for f
in pairs(functions
) do
602 f
= fill_wrapper_code(f
, types
)
604 f
= assert(fill_test_code(f
, types
), f
.xarg
.fullname
) -- MUST pass
606 --local out = 'extern "C" LQT_EXPORT int lqt_bind'..f.xarg.id..' (lua_State *L) {\n'
607 --.. f.wrapper_code .. '}\n'
614 local make_pushlines
= function(args
, types
)
615 local pushlines
, stack
= '', 0
616 for i
, a
in ipairs(args
) do
617 if not types
[a
.xarg
.type_name
] then return nil end
618 local apush
, an
= types
[a
.xarg
.type_name
].push('arg'..i
)
619 pushlines
= pushlines
.. ' ' .. apush
.. ';\n'
622 return pushlines
, stack
625 local virtual_overload
= function(v
, types
)
627 if v
.virtual_overload
then return v
end
629 if v
.return_type
and not types
[v
.return_type
] then return nil end
630 local rget
, rn
= '', 0
631 if v
.return_type
then rget
, rn
, ret_as
= types
[v
.return_type
].get
'oldtop+1' end
632 local retget
= (v
.return_type
and argument_name(ret_as
or v
.return_type
, 'ret')
633 .. ' = ' .. rget
.. ';' or '') .. 'lua_settop(L, oldtop);return'
634 .. (v
.return_type
and ' ret' or '')
635 -- make argument push
636 local pushlines
, stack
= make_pushlines(v
.arguments
, types
)
637 if not pushlines
then return nil end
639 local luacall
= 'lqtL_pcall(L, '..(stack
+1)..', '..rn
..', 0)'
640 -- make prototype and fallback
641 local proto
= (v
.return_type
or 'void')..' ;;'..v
.xarg
.name
..' ('
643 for i
, a
in ipairs(v
.arguments
) do
644 proto
= proto
.. (i
>1 and ', ' or '')
645 .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
646 fallback
= fallback
.. (i
>1 and ', arg' or 'arg') .. i
648 proto
= proto
.. ')' .. (v
.xarg
.constant
=='1' and ' const' or '')
649 fallback
= (v
.return_type
and 'return this->' or 'this->')
650 .. v
.xarg
.fullname
.. '(' .. fallback
.. ');\n}\n'
652 int oldtop = lua_gettop(L);
653 lqtL_pushudata(L, this, "]]..string.gsub(v
.xarg
.member_of_class
, '::', '.')..[[*");
654 lqtL_getoverload(L, -1, "]]..v
.xarg
.name
..[[");
655 if (lua_isfunction(L, -1)) {
657 ]] .. pushlines
.. [[
658 if (!]]..luacall
..[[) {
662 lua_settop(L, oldtop);
664 v
.virtual_overload
= ret
665 v
.virtual_proto
= string.gsub(proto
, ';;', '', 1)
669 local fill_shell_class
= function(c
, types
)
670 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
671 local shell
= 'class LQT_EXPORT ' .. shellname
.. ' : public ' .. c
.xarg
.fullname
.. ' {\npublic:\n'
672 shell
= shell
.. ' lua_State *L;\n'
673 for _
, constr
in ipairs(c
.constructors
) do
674 if constr
.xarg
.access
~='private' then
675 local cline
= ' '..shellname
..' (lua_State *l'
677 for i
, a
in ipairs(constr
.arguments
) do
678 cline
= cline
.. ', ' .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
679 argline
= argline
.. (i
>1 and ', arg' or 'arg') .. i
681 cline
= cline
.. ') : ' .. c
.xarg
.fullname
682 .. '(' .. argline
.. '), L(l) '
683 .. '{ lqtL_register(L, this); }\n'
684 shell
= shell
.. cline
687 if c
.copy_constructor
==nil and c
.public_constr
then
688 local cline
= ' '..shellname
..' (lua_State *l, '..c
.xarg
.fullname
..' const& arg1)'
689 cline
= cline
.. ' : ' .. c
.xarg
.fullname
.. '(arg1), L(l) {}\n'
690 shell
= shell
.. cline
692 for i
, v
in pairs(c
.virtuals
) do
693 if v
.xarg
.access
~='private' then
694 if v
.virtual_proto
then shell
= shell
.. ' virtual ' .. v
.virtual_proto
.. ';\n' end
697 shell
= shell
.. ' ~'..shellname
..'() { lqtL_unregister(L, this); }\n'
698 if c
.shell
and c
.qobject
then
699 shell
= shell
.. ' static QMetaObject staticMetaObject;\n'
700 shell
= shell
.. ' virtual const QMetaObject *metaObject() const;\n'
701 shell
= shell
.. ' virtual int qt_metacall(QMetaObject::Call, int, void **);\n'
702 shell
= shell
.. 'private:\n'
703 shell
= shell
.. ' Q_DISABLE_COPY('..shellname
..');\n'
705 shell
= shell
.. '};\n'
706 c
.shell_class
= shell
710 local fill_virtual_overloads
= function(classes
, types
)
711 for c
in pairs(classes
) do
712 for i
, v
in pairs(c
.virtuals
) do
713 if v
.xarg
.access
~='private' then
714 local vret
= virtual_overload(v
, types
)
721 local fill_shell_classes
= function(classes
, types
)
723 for c
in pairs(classes
) do
725 c
= fill_shell_class(c
, types
)
726 if c
then ret
[c
] = true end
733 local print_shell_classes
= function(classes
)
735 for c
in pairs(classes
) do
736 if fhead
then fhead
:close() end
737 local n
= string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
738 fhead
= assert(io
.open(module_name
.._src
..module_name
..'_head_'..n
..'.hpp', 'w'))
739 local print_head
= function(...)
743 print_head('#ifndef LQT_HEAD_'..n
)
744 print_head('#define LQT_HEAD_'..n
)
745 print_head(output_includes
)
746 --print_head('#include <'..string.match(c.xarg.fullname, '^[^:]+')..'>')
750 print_head(c
.shell_class
)
752 --io.stderr:write(c.fullname, '\n')
755 print_head('#endif // LQT_HEAD_'..n
)
757 if fhead
then fhead
:close() end
761 local print_virtual_overloads
= function(classes
)
762 for c
in pairs(classes
) do
765 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
766 for _
,v
in pairs(c
.virtuals
) do
767 if v
.virtual_overload
then
768 vo
= vo
.. string.gsub(v
.virtual_overload
, ';;', shellname
..'::', 1)
771 c
.virtual_overloads
= vo
777 local print_wrappers
= function(index
)
778 for c
in pairs(index
) do
781 for _
, f
in ipairs(c
.methods
) do
782 -- FIXME: should we really discard virtual functions?
783 -- if the virtual overload in the shell uses rawget
784 -- on the environment then we can leave these in the
786 if f
.wrapper_code
and f
.xarg
.abstract
~='1' then
787 local out
= 'static int lqt_bind'..f
.xarg
.id
788 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
789 if f
.xarg
.access
=='public' then
791 wrappers
= wrappers
.. out
.. '\n'
792 meta
[f
] = f
.xarg
.name
796 if not c
.abstract
then
797 for _
, f
in ipairs(c
.constructors
) do
798 if f
.wrapper_code
then
799 local out
= 'static int lqt_bind'..f
.xarg
.id
800 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
801 if f
.xarg
.access
=='public' then
803 wrappers
= wrappers
.. out
.. '\n'
809 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
810 local lua_name
= string.gsub(c
.xarg
.fullname
, '::', '.')
811 local out
= 'static int lqt_delete'..c
.xarg
.id
..' (lua_State *L) {\n'
812 out
= out
..' '..c
.xarg
.fullname
..' *p = static_cast<'
813 ..c
.xarg
.fullname
..'*>(lqtL_toudata(L, 1, "'..lua_name
..'*"));\n'
814 if c
.public_destr
then
815 out
= out
.. ' if (p) delete p;\n'
817 out
= out
.. ' lqtL_eraseudata(L, 1, "'..lua_name
..'*");\n return 0;\n}\n'
819 wrappers
= wrappers
.. out
.. '\n'
821 c
.wrappers
= wrappers
826 local print_metatable
= function(c
)
828 local wrappers
= c
.wrappers
829 for m
, n
in pairs(c
.meta
) do
830 methods
[n
] = methods
[n
] or {}
831 table.insert(methods
[n
], m
)
833 for n
, l
in pairs(methods
) do
834 local duplicates
= {}
835 for _
, f
in ipairs(l
) do
837 for sa
, g
in pairs(duplicates
) do
838 if sa
==f
.stack_arguments
then
839 --debug("function equal: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
840 if f
.defects
<g
.defects
then
844 elseif string.match(sa
, "^"..f
.stack_arguments
) then -- there is already a version with more arguments
845 --debug("function superseded: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
846 elseif string.match(f
.stack_arguments
, '^'..sa
) then -- there is already a version with less arguments
847 --debug("function superseding: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
851 duplicates
[f
.stack_arguments
] = f
857 for sa, f in pairs(l) do
858 numinitial = numinitial + 1
860 for sa, f in pairs(duplicates) do
861 numfinal = numfinal + 1
863 if numinitial-numfinal>0 then debug(c.xarg.fullname, "suppressed:", numinitial-numfinal) end
865 methods
[n
] = duplicates
867 for n
, l
in pairs(methods
) do
868 local name
= rename_operator(n
)
869 local disp
= 'static int lqt_dispatcher_'..name
..c
.xarg
.id
..' (lua_State *L) {\n'
870 for _
, f
in pairs(l
) do
871 disp
= disp
..' if ('..f
.test_code
..') return lqt_bind'..f
.xarg
.id
..'(L);\n'
873 disp
= disp
.. ' lua_settop(L, 0);\n'
874 disp
= disp
.. ' lua_pushstring(L, "'..c
.xarg
.fullname
..'::'..n
..': incorrect or extra arguments");\n'
875 disp
= disp
.. ' return lua_error(L);\n}\n'
877 wrappers
= wrappers
.. disp
.. '\n'
879 local metatable
= 'static luaL_Reg lqt_metatable'..c
.xarg
.id
..'[] = {\n'
880 for n
, l
in pairs(methods
) do
881 metatable
= metatable
.. ' { "'..rename_operator(n
)..'", lqt_dispatcher_'..rename_operator(n
)..c
.xarg
.id
..' },\n'
883 metatable
= metatable
.. ' { "delete", lqt_delete'..c
.xarg
.id
..' },\n'
884 metatable
= metatable
.. ' { 0, 0 },\n};\n'
885 --print_meta(metatable)
886 wrappers
= wrappers
.. metatable
.. '\n'
888 for b
in string.gmatch(c
.xarg
.bases_with_attributes
or '', '([^;]*);') do
889 if not string.match(b
, '^virtual') then
890 b
= string.gsub(b
, '^[^%s]* ', '')
891 bases
= bases
.. ' {"'..string.gsub(b
,'::','.')..'*", (char*)(void*)static_cast<'..b
..'*>(('..c
.xarg
.fullname
..'*)1)-(char*)1},\n'
894 bases
= 'static lqt_Base lqt_base'..c
.xarg
.id
..'[] = {\n'..bases
..' {NULL, 0}\n};\n'
896 wrappers
= wrappers
.. bases
.. '\n'
897 c
.wrappers
= wrappers
901 local print_metatables
= function(classes
)
902 for c
in pairs(classes
) do
910 local print_single_class
= function(c
)
911 local n
= string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
912 local lua_name
= string.gsub(c
.xarg
.fullname
, '::', '.')
913 local cppname
= module_name
..'_meta_'..n
..'.cpp'
914 table.insert(cpp_files
, cppname
);
915 local fmeta
= assert(io
.open(module_name
.._src
..cppname
, 'w'))
916 local print_meta
= function(...)
920 print_meta('#include "'..module_name
..'_head_'..n
..'.hpp'..'"\n\n')
921 print_meta(c
.wrappers
)
922 if c
.virtual_overloads
then
923 print_meta(c
.virtual_overloads
)
925 print_meta('extern "C" LQT_EXPORT int luaopen_'..n
..' (lua_State *L) {')
926 print_meta('\tlqtL_createclass(L, "'
927 ..lua_name
..'*", lqt_metatable'
928 ..c
.xarg
.id
..', lqt_base'
930 print_meta
'\treturn 0;'
933 if c
.shell
and c
.qobject
then
937 QMetaObject lqt_shell_]]..n
..[[::staticMetaObject;
939 const QMetaObject *lqt_shell_]]..n
..[[::metaObject() const {
940 //int oldtop = lua_gettop(L);
941 lqtL_pushudata(L, this, "]]..c
.xarg
.fullname
..[[*");
942 lua_getfield(L, -1, LQT_OBJMETASTRING);
943 if (lua_isnil(L, -1)) {
945 return &]]..c
.xarg
.fullname
..[[::staticMetaObject;
947 lua_getfield(L, -2, LQT_OBJMETADATA);
949 //qDebug() << "copying qmeta object for slots in ]]..c
.xarg
.fullname
..[[";
950 lqt_shell_]]..n
..[[::staticMetaObject.d.superdata = &]]..c
.xarg
.fullname
..[[::staticMetaObject;
951 lqt_shell_]]..n
..[[::staticMetaObject.d.stringdata = lua_tostring(L, -2);
952 lqt_shell_]]..n
..[[::staticMetaObject.d.data = (uint*)lua_touserdata(L, -1);
953 lqt_shell_]]..n
..[[::staticMetaObject.d.extradata = 0; // slot_metaobj->d.extradata;
954 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETADATA);
955 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETASTRING);
957 //qDebug() << (lua_gettop(L) - oldtop);
958 return &lqt_shell_]]..n
..[[::staticMetaObject;
961 int lqt_shell_]]..n
..[[::qt_metacall(QMetaObject::Call call, int index, void **args) {
962 //qDebug() << "fake calling!";
963 index = ]]..c
.xarg
.fullname
..[[::qt_metacall(call, index, args);
964 if (index < 0) return index;
965 return lqtL_qt_metacall(L, this, call, "QWidget*", index, args);
972 local print_merged_build
= function()
973 local path
= module_name
.._src
974 local mergename
= module_name
..'_merged_build'
975 local merged
= assert(io
.open(path
..mergename
..'.cpp', 'w'))
976 for _
, p
in ipairs(cpp_files
) do
977 merged
:write('#include "'..p
..'"\n')
979 local pro_file
= assert(io
.open(path
..mergename
..'.pro', 'w'))
981 local print_pro
= function(...)
985 print_pro('TEMPLATE = lib')
986 print_pro('TARGET = '..module_name
)
987 print_pro('INCLUDEPATH += .')
988 print_pro('HEADERS += '..module_name
..'_slot.hpp')
989 print_pro('SOURCES += ../common/lqt_common.cpp \\')
990 print_pro(' ../common/lqt_qt.cpp \\')
991 print_pro(' '..module_name
..'_enum.cpp \\')
992 print_pro(' '..module_name
..'_meta.cpp \\')
993 print_pro(' '..module_name
..'_slot.cpp \\')
994 print_pro(' '..mergename
..'.cpp')
997 local print_class_list
= function(classes
)
998 local qobject_present
= false
999 local big_picture
= {}
1000 local type_list_t
= {}
1001 for c
in pairs(classes
) do
1002 local n
= string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
1003 if n
=='QObject' then qobject_present
= true end
1004 print_single_class(c
)
1005 table.insert(big_picture
, 'luaopen_'..n
)
1006 table.insert(type_list_t
, 'add_class(\''..c
.xarg
.fullname
..'\', types)\n')
1009 local type_list_f
= assert(io
.open(module_name
.._src
..module_name
..'_types.lua', 'w'))
1010 type_list_f
:write([[
1012 local types = (...) or {}
1013 local add_class = lqt.classes.insert or error('module lqt.classes not loaded')
1015 for k
, v
in ipairs(type_list_t
) do
1016 type_list_f
:write(v
)
1018 type_list_f
:write('return types\n')
1021 print_merged_build()
1022 if fmeta
then fmeta
:close() end
1023 fmeta
= assert(io
.open(module_name
.._src
..module_name
..'_meta.cpp', 'w'))
1024 local print_meta
= function(...)
1029 print_meta('#include "lqt_common.hpp"')
1030 print_meta('#include "'..module_name
..'_slot.hpp'..'"\n\n')
1031 for _
, p
in ipairs(big_picture
) do
1032 print_meta('extern "C" LQT_EXPORT int '..p
..' (lua_State *);')
1034 print_meta('void lqt_create_enums_'..module_name
..' (lua_State *);')
1035 print_meta('extern "C" LQT_EXPORT int luaopen_'..module_name
..' (lua_State *L) {')
1036 for _
, p
in ipairs(big_picture
) do
1037 print_meta('\t'..p
..'(L);')
1039 print_meta('\tlqt_create_enums_'..module_name
..'(L);')
1040 if qobject_present
then
1041 print_meta('\tlua_getfield(L, LUA_REGISTRYINDEX, "QObject*");')
1042 print_meta('\tlua_pushstring(L, "__addmethod");')
1043 print_meta('\tlqtL_pushaddmethod(L);')
1044 print_meta('\tlua_rawset(L, -3);')
1046 print_meta('\t//lua_pushlightuserdata(L, (void*)&LqtSlotAcceptor::staticMetaObject);')
1047 print_meta('\t//lua_setfield(L, LUA_REGISTRYINDEX, LQT_METAOBJECT);')
1048 print_meta('\tlqtL_passudata(L, (void*)(new LqtSlotAcceptor(L)), "QObject*");')
1049 print_meta('\tlua_setfield(L, LUA_REGISTRYINDEX, LQT_METACALLER);')
1050 print_meta('\treturn 0;\n}')
1051 if fmeta
then fmeta
:close() end
1055 local fix_methods_wrappers
= function(classes
)
1056 for c
in pairs(classes
) do
1057 c
.shell
= (not c
.abstract
) and c
.public_destr
1058 c
.shell
= c
.shell
and (next(c
.virtuals
)~=nil)
1059 for _
, constr
in ipairs(c
.constructors
) do
1061 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
1062 constr
.calling_line
= 'new '..shellname
..'(L'
1063 if #(constr
.arguments
)>0 then constr
.calling_line
= constr
.calling_line
.. ', ' end
1065 local shellname
= c
.xarg
.fullname
1066 constr
.calling_line
= 'new '..shellname
..'('
1068 for i
=1,#(constr
.arguments
) do
1069 constr
.calling_line
= constr
.calling_line
.. (i
==1 and '' or ', ') .. 'arg' .. i
1071 constr
.calling_line
= '*('..constr
.calling_line
.. '))'
1072 constr
.xarg
.static
= '1'
1073 constr
.return_type
= constr
.xarg
.type_base
..'&'
1075 if c
.destructor
then
1076 c
.destructor
.return_type
= nil
1082 local print_enum_tables
= function(enums
)
1083 for e
in pairs(enums
) do
1084 local table = 'static lqt_Enum lqt_enum'..e
.xarg
.id
..'[] = {\n'
1085 --io.stderr:write(e.xarg.fullname, '\t', #e.values, '\n')
1086 for _
,v
in pairs(e
.values
) do
1087 table = table .. ' { "' .. v
.xarg
.name
1088 .. '", static_cast<int>('..v
.xarg
.fullname
..') },\n'
1090 table = table .. ' { 0, 0 }\n'
1091 table = table .. '};\n'
1092 e
.enum_table
= table
1097 local print_enum_creator
= function(enums
, n
)
1098 local out
= 'static lqt_Enumlist lqt_enum_list[] = {\n'
1099 for e
in pairs(enums
) do
1100 out
= out
..' { lqt_enum'..e
.xarg
.id
..', "'..string.gsub(e
.xarg
.fullname
, "::", ".")..'" },\n'
1102 out
= out
..' { 0, 0 },\n};\n'
1103 out
= out
.. 'void lqt_create_enums_'..n
..' (lua_State *L) {\n'
1104 out
= out
.. ' lqtL_createenumlist(L, lqt_enum_list); return;\n}\n'
1109 local copy_signals
= function(functions
)
1111 for f
in pairs(functions
) do
1112 if f
.xarg
.signal
=='1' then
1119 local slots_for_signals
= function(signals
, types
)
1121 for sig
in pairs(signals
) do
1122 local args
, comma
= '(', ''
1123 for i
, a
in ipairs(sig
.arguments
) do
1124 args
= args
.. comma
.. a
.xarg
.type_name
.. ' arg'..i
1128 local pushlines
, stack
= make_pushlines(sig
.arguments
, types
)
1129 if not ret
['void __slot '..args
] and pushlines
then
1130 ret
['void __slot '..args
] = 'void LqtSlotAcceptor::__slot '..args
..[[ {
1131 //int oldtop = lua_gettop(L);
1132 //lua_getfield(L, -1, "__slot]]..string.gsub(args
, ' arg.', '')..[[");
1133 //if (lua_isnil(L, -1)) {
1135 //lua_getfield(L, -1, "__slot");
1137 //if (!lua_isfunction(L, -1)) {
1138 //lua_settop(L, oldtop);
1141 lua_pushvalue(L, -2);
1142 ]] .. pushlines
.. [[
1143 if (lqtL_pcall(L, ]]..stack
..[[+1, 0, 0)) {
1145 qDebug() << lua_tostring(L, -1);
1148 //lua_settop(L, oldtop);
1156 local print_slots
= function(s
)
1157 print_slot_h
'class LqtSlotAcceptor : public QObject {'
1158 print_slot_h
' Q_OBJECT'
1159 print_slot_h
' lua_State *L;'
1160 print_slot_h
' public:'
1161 print_slot_h
' LqtSlotAcceptor(lua_State *l, QObject *p=NULL) : QObject(p), L(l) { lqtL_register(L, this); }'
1162 print_slot_h
' virtual ~LqtSlotAcceptor() { lqtL_unregister(L, this); }'
1163 print_slot_h
' public slots:'
1164 for p
, b
in pairs(s
) do
1165 print_slot_h(' '..p
..';')
1168 for p
, b
in pairs(s
) do
1174 --------------------------------------------------------------------------------------
1176 local typesystem
= dofile(path
..'types.lua')
1179 for i
, ft
in ipairs(typefiles
) do
1180 ts
= assert(loadfile(ft
))(ts
)
1182 setmetatable(typesystem
, {
1183 __newindex
= function(t
, k
, v
)
1184 --debug('added type', k)
1187 __index
= function(t
, k
)
1189 --if not ret then debug("unknown type:", tostring(k), ret) end
1195 fix_arguments(idindex
) -- fixes default arguments if they are context-relative
1196 local functions
= copy_functions(idindex
) -- picks functions and fixes label
1197 local functions
= fix_functions(functions
) -- fixes name and fullname and fills arguments
1199 local enums
= copy_enums(idindex
) -- picks enums if public
1200 local enums
= fill_enums(enums
) -- fills field "values"
1202 local classes
= copy_classes(idindex
) -- picks classes if not private and not blacklisted
1203 local classes
= fill_virtuals(classes
) -- does that, destructor ("~") excluded
1204 local classes
= distinguish_methods(classes
) -- does that
1205 local classes
= fill_public_destr(classes
) -- does that: checks if destructor is public
1206 local classes
= fill_copy_constructor(classes
) -- does that: checks if copy contructor is public or protected
1207 local classes
= fix_methods_wrappers(classes
)
1208 local classes
= get_qobjects(classes
)
1210 for _
, f
in ipairs(filterfiles
) do
1211 classes
, enums
= loadfile(f
)(classes
, enums
)
1214 local enums
= fill_typesystem_with_enums(enums
, typesystem
) -- does that
1215 local classes
= fill_typesystem_with_classes(classes
, typesystem
)
1217 local functions
= fill_wrappers(functions
, typesystem
)
1218 local classes
= fill_virtual_overloads(classes
, typesystem
) -- does that
1219 local classes
= fill_shell_classes(classes
, typesystem
) -- does that
1221 local signals
= copy_signals(functions
)
1222 local slots
= slots_for_signals(signals
, typesystem
)
1225 ------------- BEGIN OUTPUT
1229 print_enum(output_includes
)
1230 print_slot_h(output_includes
)
1231 print_slot_c('#include "'..module_name
..'_slot.hpp'..'"\n\n')
1234 local classes
= print_shell_classes(classes
) -- does that
1235 local classes
= print_virtual_overloads(classes
, typesystem
) -- does that
1236 local enums
= print_enum_tables(enums
) -- does that
1237 local enums
= print_enum_creator(enums
, module_name
) -- does that + print enum list
1238 local classes
= print_wrappers(classes
) -- just compiles metatable list
1239 local classes
= print_metatables(classes
) -- just collects the wrappers + generates dispatchers
1240 local classes
= print_class_list(classes
) -- does that + prints everything related to class
1242 local slots
= print_slots(slots
)
1244 --print_openmodule(module_name) -- does that