7 module('classes', package
.seeall
)
9 -- collection of all functions
11 -- collection of bound classes
13 -- list of files to be included
15 -- table of classes by their cname
18 --- Copies functions from the index.
19 function copy_functions(index
)
20 for e
in pairs(index
) do
21 if e
.label
:match
'^Function' then
28 function class_contains(where
, what
)
29 local class
= fullnames
[where
]
30 if not class
then return false end
31 for _
, child
in ipairs(class
) do
32 if child
.xarg
.name
== what
then return true
33 elseif child
.label
== 'Enum' then
34 for _
, enum
in ipairs(child
) do
35 if enum
.xarg
.name
== what
then return true end
42 --- Fixes default arguments.
43 -- Default arguments are processed outside of the enclosing class, so every reference to an
44 -- enum or variable needs to be properly prefixed with the class name.
45 function fix_arguments(index
)
46 for a
in pairs(index
) do
47 if a
.label
=='Argument'
48 and a
.xarg
.default
=='1'
49 and (not string.match(a
.xarg
.defaultvalue
, '^[-+]?%d+%.?%d*[L]?$'))
50 and (not string.match(a
.xarg
.defaultvalue
, '^".*"$'))
51 and a
.xarg
.defaultvalue
~='true'
52 and a
.xarg
.defaultvalue
~='false'
53 and (not string.match(a
.xarg
.defaultvalue
, '^0[.xX][%da-fA-F]+$'))
55 local dv
, call = string.match(a
.xarg
.defaultvalue
, '(.-)(%(.-%))')
56 dv
= dv
or a
.xarg
.defaultvalue
58 local context
= a
.xarg
.context
59 -- try to determine the class scope which contains the default value (dv)
60 while not fullnames
[context
..'::'..dv
] and context
~='' do
61 context
= string.match(context
, '^(.*)::') or ''
63 -- try in superclass (FIXME: try all superclasses)
64 if not fullnames
[context
..'::'..dv
] then
65 context
= a
.xarg
.context
66 local class
= fullnames
[context
]
67 if class
.xarg
.bases
then
68 context
= class
.xarg
.bases
:match('[^;]+')
71 -- workaround for enums and values in the context class
72 local callValue
= call:sub(2,-2)
74 callValue
= callValue
:gsub('[%a][%a%d]+', function(id
)
75 if class_contains(context
, id
) then return context
..'::'..id
end
77 call = '('..callValue
..')'
79 local firstChar
= dv
:sub(1,1)
80 if fullnames
[context
..'::'..dv
] then
81 -- remove unneeded context prefix
82 if fullnames
[context
..'::'..dv
].xarg
.name
==fullnames
[context
..'::'..dv
].xarg
.member_of_class
then
83 context
= string.match(context
, '^(.*)::') or ''
85 a
.xarg
.defaultvalue
= context
..'::'..dv
..call
86 elseif fullnames
[dv
] or dv
== dv
:upper() or (firstChar
== 'Q' and #call == 0) or firstChar
== "'" then
87 a
.xarg
.defaultvalue
= dv
..call
89 ignore(a
.xarg
.context
..'::'..a
.xarg
.name
, 'Unsupported default value', a
.xarg
.defaultvalue
)
91 a
.xarg
.defaultvalue
= nil
98 --- Removes unneeded 'void' parameters and return values.
99 function fix_functions()
100 for f
in pairs(functions
) do
102 for i
, a
in ipairs(f
) do
103 -- avoid bogus 'void' arguments
104 if a
.xarg
.type_name
=='void' and i
==1 and f
[2]==nil then break end
105 if a
.label
=='Argument' then
106 table.insert(args
, a
)
110 f
.return_type
= f
.xarg
.type_name
111 if f
.xarg
.type_name
=='void' then
117 --- Determines, if a class is public.
118 function class_is_public(c
)
120 if c
.xarg
.access
~='public' then return false end
121 if c
.xarg
.member_of_class
then
122 local p
= fullnames
[c
.xarg
.member_of_class
]
123 assert(p
, 'member_of_class should exist')
124 assert(p
.label
=='Class', 'member_of_class should be a class')
125 c
= fullnames
[c
.xarg
.member_of_class
]
132 --- Selects public classes from the index, and creates templated instances
133 -- where appropriate.
134 function copy_classes(index
)
135 for e
in pairs(index
) do
136 if e
.label
=='Class' then
137 e
.xarg
.cname
= string.gsub(e
.xarg
.fullname
, '::', '_LQT_')
138 if class_is_public(e
)
139 and not e
.xarg
.fullname
:match
'%b<>' then
141 elseif not e
.xarg
.fullname
:match
'%b<>' then
142 ignore(e
.xarg
.fullname
, 'not public')
144 if templates
.should_copy(e
) then
145 templates
.create(e
, classes
)
150 templates
.finish(index
)
151 for c
in pairs(classes
) do
152 classlist
[c
.xarg
.cname
] = c
156 function fix_methods_wrappers()
157 for c
in pairs(classes
) do
158 c
.shell
= c
.public_destr
159 c
.shell
= c
.shell
and (next(c
.virtuals
)~=nil)
160 for _
, constr
in ipairs(c
.constructors
) do
162 local shellname
= 'lqt_shell_'..c
.xarg
.cname
163 constr
.calling_line
= 'new '..shellname
..'(L'
164 if #(constr
.arguments
)>0 then constr
.calling_line
= constr
.calling_line
.. ', ' end
166 local shellname
= c
.xarg
.fullname
167 constr
.calling_line
= 'new '..shellname
..'('
169 for i
=1,#(constr
.arguments
) do
170 constr
.calling_line
= constr
.calling_line
.. (i
==1 and '' or ', ') .. 'arg' .. i
172 constr
.calling_line
= '*('..constr
.calling_line
.. '))'
173 constr
.xarg
.static
= '1'
174 constr
.return_type
= constr
.xarg
.scope
..'&'
177 c
.destructor
.return_type
= nil
182 --- Determines, whether classes are children of QObject.
183 -- Fills the 'qobject' field on class if it is child of QObject.
184 function get_qobjects()
185 local function is_qobject(c
)
186 if c
==nil then return false end
187 if c
.qobject
then return true end
188 if c
.xarg
.fullname
=='QObject' then
192 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
193 local base
= fullnames
[b
]
194 if is_qobject(base
) then
195 --debug(c.xarg.fullname, "is a QObject")
202 for c
in pairs(classes
) do
203 local qobj
= is_qobject(c
)
209 local should_wrap
= function(f
)
210 local name
= f
.xarg
.name
211 -- unfixed operator and friend, causes trouble with QDataStream
212 -- if f.xarg.friend and #f.arguments ==2 then return false end
213 -- not an operator - accept
214 if not name
:match('^operator') then return true end
215 -- accept supported operators
216 if operators
.is_operator(name
) then return true end
222 function distinguish_methods()
223 for c
in pairs(classes
) do
224 local construct
, destruct
, normal
= {}, nil, {}
225 local n
= c
.xarg
.name
:gsub('%b<>', '')
228 for _
, f
in ipairs(c
) do
229 if n
==f
.xarg
.name
then
230 table.insert(construct
, f
)
231 elseif f
.xarg
.name
:match
'~' then
235 and (not f
.xarg
.member_template_parameters
) then
236 table.insert(normal
, f
)
238 ignore(f
.xarg
.fullname
, 'operator/template/friend', c
.xarg
.name
)
242 c
.constructors
= construct
243 c
.destructor
= destruct
248 --- Determines, if a class has a public destructor. It also scans the superclasses.
249 -- Sets the 'public_destr' fiield on the class.
250 function fill_public_destr()
251 local function destr_is_public(c
)
253 return c
.destructor
.xarg
.access
=='public'
255 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
256 local base
= fullnames
[b
]
257 if base
and not destr_is_public(base
) then
264 for c
in pairs(classes
) do
265 c
.public_destr
= destr_is_public(c
)
270 function generate_default_copy_constructor(c
)
271 if not c
.xarg
then return end
277 context
= c
.xarg
.name
;
281 type_base
= c
.xarg
.name
;
283 type_name
= c
.xarg
.name
.. " const&";
284 type_reference
= "1";
288 return_type
= c
.xarg
.name
;
291 context
= c
.xarg
.name
;
292 fullname
= c
.xarg
.name
.."::"..c
.xarg
.name
;
295 member_of
= c
.xarg
.name
;
296 member_of_class
= c
.xarg
.name
;
299 type_base
= c
.xarg
.name
;
300 type_name
= c
.xarg
.name
;
303 copy
.arguments
= {copy
[1]}
305 table.insert(c
, copy
)
306 table.insert(c
.constructors
, copy
)
307 functions
[copy
] = true
312 -- HACK: do not create copy contructors for classes, that
313 -- contain variables of class '*Private' - they will not compile
315 local function has_private_fields(c
)
316 for _
,v
in ipairs(c
) do
317 if v
.label
== 'Variable' then
318 if v
.xarg
.type_base
:match('Private') then
319 ignore(c
.xarg
.fullname
, 'cannot create copy constructor', v
.xarg
.fullname
.. ' : ' ..v
.xarg
.type_base
)
327 function fill_copy_constructor()
328 for c
in pairs(classes
) do
330 for _
, f
in ipairs(c
.constructors
) do
332 and f
.arguments
[1].xarg
.type_name
==c
.xarg
.fullname
..' const&' then
337 c
.copy_constructor
= copy
339 local function copy_constr_is_public(c
)
340 if c
.copy_constructor
then
341 return (c
.copy_constructor
.xarg
.access
=='public')
342 or (c
.copy_constructor
.xarg
.access
=='protected')
344 if has_private_fields(c
) then return false end
346 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
347 local base
= fullnames
[b
]
348 if base
and not copy_constr_is_public(base
) then
355 for c
in pairs(classes
) do
356 c
.public_constr
= copy_constr_is_public(c
)
357 if c
.public_constr
and not c
.copy_constructor
then
358 c
.copy_constructor
= generate_default_copy_constructor(c
)
363 function fill_implicit_constructor()
364 typesystem
.can_convert
= {}
365 for c
in pairs(classes
) do
366 for _
,f
in ipairs(c
) do
367 if f
.label
:match("^Function") then
368 -- find non-explicit constructor, which has 1 argument of type different
369 -- from class, i.e. an implicit conversion constructor
370 if f
.xarg
.name
== c
.xarg
.name
372 and (not f
.xarg
.access
or f
.xarg
.access
== "public")
373 and f
[1].xarg
.type_base
~= c
.xarg
.name
374 and not f
[1].xarg
.type_base
:match('Private$')
375 -- and not f.xarg.explicit
378 local class_name
= c
.xarg
.cname
379 local from_type
= f
[1].xarg
.type_base
380 typesystem
.can_convert
[class_name
] = typesystem
.can_convert
[class_name
] or { from
= {}, class
= c
}
381 typesystem
.can_convert
[class_name
].from
[ from_type
] = f
382 local safe_from
= from_type
:gsub('[<>*]', '_'):gsub('::', '_LQT_')
389 local function generate_implicit_code(class_name
, t
)
391 local fullname
= c
.xarg
.fullname
392 local luaname
= fullname
:gsub('::', '.')
394 local test_header
= 'bool lqt_canconvert_' .. class_name
.. '(lua_State *L, int n)'
395 local convert_header
= 'void* lqt_convert_' .. class_name
.. '(lua_State *L, int n)'
398 local convert_code
= ""
402 for _
, f
in pairs(t
.from
) do
403 local typ
= f
[1].xarg
.type_name
404 if not typesystem
[typ
] then
405 ignore(typ
, "implicit constructor - unknown type", _
)
408 if typesystem
[typ
].raw_test
then
409 test
= typesystem
[typ
].raw_test('n')
411 test
= typesystem
[typ
].test('n')
413 if not tests
[test
] then
419 local newtype
= fullname
.. '(arg)'
420 if c
.shell
then newtype
= 'lqt_shell_'..c
.xarg
.cname
..'(L,arg)' end
422 -- HACK: QVariant with 'char const*' argument - force it to QByteArray
423 if fullname
== 'QVariant' and typ
== 'char const*' then
428 ' if ('..test
..') {\n'
429 ..' '..typ
..' arg = '..typesystem
[typ
].get('n')..';\n'
430 ..' '..fullname
..' *ret = new '..newtype
..';\n'
431 ..' lqtL_passudata(L, ret, "'..luaname
..'*");\n'
432 ..' return ret;\n }\n'
434 local item
= { type = fullname
, test
= test
, defect
= typesystem
[typ
].defect
or 0,
435 test_code
= test_code
, convert_code
= convert_code
}
436 table.insert(order
, item
)
441 table.sort(order
, function(a
,b
) return a
.defect
< b
.defect
end)
442 for _
,v
in ipairs(order
) do
443 test_code
= test_code
.. v
.test_code
444 convert_code
= convert_code
.. v
.convert_code
447 test_code
= test_code
.. ' return false;'
448 convert_code
= convert_code
..' return NULL;'
451 headers
= { test
= test_header
, convert
= convert_header
},
452 test
= test_header
.. '{\n' .. test_code
.. '\n}',
453 convert
= convert_header
.. '{\n' .. convert_code
.. '\n}'
458 function fill_implicit_wrappers()
459 for class_name
, t
in pairs(typesystem
.can_convert
) do
460 if not t
.class
.abstract
then
461 generate_implicit_code(class_name
, t
)
467 local put_class_in_filesystem
= lqt
.classes
.insert
469 function fill_typesystem_with_classes()
470 for c
in pairs(classes
) do
471 classes
[c
] = put_class_in_filesystem(c
.xarg
.fullname
)
476 function fill_wrapper_code(f
)
477 if f
.wrapper_code
then return f
end
478 local stackn
, argn
= 1, 1
479 local stack_args
, defects
= '', 0
480 local has_args
= true
481 local wrap
, line
= ' int oldtop = lua_gettop(L);\n', ''
483 if f
.xarg
.abstract
then
484 ignore(f
.xarg
.fullname
, 'abstract method', f
.xarg
.member_of_class
)
487 if f
.xarg
.member_of_class
and f
.xarg
.static
~='1' then
488 if not typesystem
[f
.xarg
.member_of_class
..'*'] then
489 ignore(f
.xarg
.fullname
, 'not a member of wrapped class', f
.xarg
.member_of_class
)
492 stack_args
= stack_args
.. typesystem
[f
.xarg
.member_of_class
..'*'].onstack
493 defects
= defects
+ 7 -- FIXME: arbitrary
494 if f
.xarg
.constant
=='1' then
495 defects
= defects
+ 8 -- FIXME: arbitrary
497 local sget
, sn
= typesystem
[f
.xarg
.member_of_class
..'*'].get(stackn
)
498 wrap
= wrap
.. ' ' .. f
.xarg
.member_of_class
.. '* self = ' .. sget
.. ';\n'
500 wrap
= wrap
.. ' lqtL_selfcheck(L, self, "'..f
.xarg
.member_of_class
..'");\n'
502 if operators
.is_operator(f
.xarg
.name
) then
503 line
, has_args
= operators
.call_line(f
)
504 if not line
then return nil end
506 line
= 'self->'..f
.xarg
.fullname
..'('
508 if VERBOSE_BUILD
then
509 wrap
= wrap
.. ' printf("[%lx; %p] %s :: %s (%d)\\n", ' ..
510 'QThread::currentThreadId(), self, ' ..
511 '"'..(f
.xarg
.member_of_class
or f
.xarg
.fullname
)..'", ' ..
512 '"'..f
.xarg
.name
..'", '..
516 line
= f
.xarg
.fullname
..'('
517 if VERBOSE_BUILD
then
518 wrap
= wrap
.. ' printf("[%lx; static] %s :: %s (%d)\\n", ' ..
519 'QThread::currentThreadId(), ' ..
520 '"'..(f
.xarg
.member_of_class
or f
.xarg
.fullname
)..'", ' ..
521 '"'..f
.xarg
.name
..'", '..
525 for i
, a
in ipairs(f
.arguments
) do
526 if not typesystem
[a
.xarg
.type_name
] then
527 ignore(f
.xarg
.fullname
, 'unkown argument type', a
.xarg
.type_name
)
530 local aget
, an
, arg_as
= typesystem
[a
.xarg
.type_name
].get(stackn
)
531 stack_args
= stack_args
.. typesystem
[a
.xarg
.type_name
].onstack
532 if typesystem
[a
.xarg
.type_name
].defect
then defects
= defects
+ typesystem
[a
.xarg
.type_name
].defect
end
533 wrap
= wrap
.. ' ' .. argument_name(arg_as
or a
.xarg
.type_name
, 'arg'..argn
) .. ' = '
534 if a
.xarg
.default
=='1' and an
>0 then
535 wrap
= wrap
.. 'lua_isnoneornil(L, '..stackn
..')'
536 for j
= stackn
+1,stackn
+an
-1 do
537 wrap
= wrap
.. ' && lua_isnoneornil(L, '..j
..')'
539 local dv
= a
.xarg
.defaultvalue
540 wrap
= wrap
.. ' ? static_cast< ' .. a
.xarg
.type_name
.. ' >(' .. dv
.. ') : '
542 wrap
= wrap
.. aget
.. ';\n'
543 line
= line
.. (argn
==1 and 'arg' or ', arg') .. argn
550 -- FIXME: hack follows for constructors
551 if f
.calling_line
then line
= f
.calling_line
end
552 if f
.return_type
then line
= f
.return_type
.. ' ret = ' .. line
end
553 wrap
= wrap
.. ' ' .. line
.. ';\n lua_settop(L, oldtop);\n' -- lua_pop(L, '..stackn..');\n'
554 if f
.return_type
then
555 if not typesystem
[f
.return_type
] then
556 ignore(f
.xarg
.fullname
, 'unknown return type', f
.return_type
)
559 local rput
, rn
= typesystem
[f
.return_type
].push
'ret'
560 wrap
= wrap
.. ' luaL_checkstack(L, '..rn
..', "cannot grow stack for return value");\n'
561 wrap
= wrap
.. ' '..rput
..';\n return '..rn
..';\n'
563 wrap
= wrap
.. ' return 0;\n'
565 f
.wrapper_code
= wrap
566 f
.stack_arguments
= stack_args
572 function fill_test_code(f
)
575 if f
.xarg
.member_of_class
and f
.xarg
.static
~='1' then
576 if not typesystem
[f
.xarg
.member_of_class
..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
577 local stest
, sn
= typesystem
[f
.xarg
.member_of_class
..'*'].test(stackn
)
578 test
= test
.. ' && ' .. stest
581 for i
, a
in ipairs(f
.arguments
) do
582 if not typesystem
[a
.xarg
.type_name
] then return nil end -- print(a.xarg.type_name) return nil end
583 local atest
, an
= typesystem
[a
.xarg
.type_name
].test(stackn
)
584 if a
.xarg
.default
=='1' and an
>0 then
585 test
= test
.. ' && (lqtL_missarg(L, ' .. stackn
.. ', ' .. an
.. ') || '
586 test
= test
.. atest
.. ')'
588 test
= test
.. ' && ' .. atest
592 -- can't make use of default values if I fix number of args
593 test
= '(lua_gettop(L)<' .. stackn
.. ')' .. test
600 function fill_wrappers()
601 for f
in pairs(functions
) do
602 local nf
= fill_wrapper_code(f
)
604 nf
= assert(fill_test_code(nf
), nf
.xarg
.fullname
) -- MUST pass
606 -- failed to generate wrapper
612 ---- Output functions
614 function print_wrappers()
615 for c
in pairs(classes
) do
618 for _
, f
in ipairs(c
.methods
) do
619 if f
.wrapper_code
and not f
.ignore
then
620 if f
.xarg
.access
~='private' then
621 local out
= 'static int lqt_bind'..f
.xarg
.id
622 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
624 wrappers
= wrappers
.. out
.. '\n'
625 meta
[f
] = f
.xarg
.name
629 if not c
.abstract
then
630 for _
, f
in ipairs(c
.constructors
) do
631 if f
.wrapper_code
then
632 if f
.xarg
.access
=='public' then
633 local out
= 'static int lqt_bind'..f
.xarg
.id
634 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
636 wrappers
= wrappers
.. out
.. '\n'
642 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
643 local lua_name
= string.gsub(c
.xarg
.fullname
, '::', '.')
644 local out
= 'static int lqt_delete'..c
.xarg
.id
..' (lua_State *L) {\n'
645 out
= out
..' '..c
.xarg
.fullname
..' *p = static_cast<'
646 ..c
.xarg
.fullname
..'*>(lqtL_toudata(L, 1, "'..lua_name
..'*"));\n'
647 if c
.public_destr
then
648 out
= out
.. ' if (p) delete p;\n'
650 out
= out
.. ' lqtL_eraseudata(L, 1, "'..lua_name
..'*");\n return 0;\n}\n'
652 wrappers
= wrappers
.. out
.. '\n'
654 c
.wrappers
= wrappers
659 local print_metatable
= function(c
)
661 local wrappers
= c
.wrappers
662 for m
, n
in pairs(c
.meta
) do
663 methods
[n
] = methods
[n
] or {}
664 table.insert(methods
[n
], m
)
666 for n
, l
in pairs(methods
) do
667 local duplicates
= {}
668 for _
, f
in ipairs(l
) do
671 for sa
, g
in pairs(duplicates
) do
672 if sa
==f
.stack_arguments
then
673 --debug("function equal: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
674 if f
.defects
<g
.defects
then
676 ignore(f
.xarg
.fullname
, "duplicate function", f
.stack_arguments
)
679 elseif string.match(sa
, "^"..f
.stack_arguments
) then -- there is already a version with more arguments
680 --debug("function superseded: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
681 elseif string.match(f
.stack_arguments
, '^'..sa
) then -- there is already a version with less arguments
682 --debug("function superseding: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
686 duplicates
[f
.stack_arguments
] = f
693 for sa, f in pairs(l) do
694 numinitial = numinitial + 1
696 for sa, f in pairs(duplicates) do
697 numfinal = numfinal + 1
699 if numinitial-numfinal>0 then debug(c.xarg.fullname, "suppressed:", numinitial-numfinal) end
701 methods
[n
] = duplicates
703 for n
, l
in pairs(methods
) do
704 local name
= operators
.rename_operator(n
)
705 local disp
= 'static int lqt_dispatcher_'..name
..c
.xarg
.id
..' (lua_State *L) {\n'
707 for tc
, f
in pairs(l
) do
708 disp
= disp
..' if ('..f
.test_code
..') return lqt_bind'..f
.xarg
.id
..'(L);\n'
709 testcode
[#testcode
+1] = tc
711 -- disp = disp .. ' lua_settop(L, 0);\n'
712 disp
= disp
.. ' const char * args = lqtL_getarglist(L);\n'
713 disp
= disp
.. ' lua_pushfstring(L, "%s(%s): incorrect or extra arguments, expecting: %s.", "' ..
714 c
.xarg
.fullname
..'::'..n
..'", args, '..string.format("%q", table.concat(testcode
, ' or ')) .. ');\n'
715 disp
= disp
.. ' return lua_error(L);\n}\n'
717 wrappers
= wrappers
.. disp
.. '\n'
719 local metatable
= 'static luaL_Reg lqt_metatable'..c
.xarg
.id
..'[] = {\n'
720 for n
, l
in pairs(methods
) do
721 local nn
= operators
.rename_operator(n
)
722 metatable
= metatable
.. ' { "'..nn
..'", lqt_dispatcher_'..nn
..c
.xarg
.id
..' },\n'
724 metatable
= metatable
.. ' { "delete", lqt_delete'..c
.xarg
.id
..' },\n'
725 metatable
= metatable
.. ' { 0, 0 },\n};\n'
726 --print_meta(metatable)
727 wrappers
= wrappers
.. metatable
.. '\n'
729 for b
in string.gmatch(c
.xarg
.bases_with_attributes
or '', '([^;]*);') do
730 if not string.match(b
, '^virtual') then
731 b
= string.gsub(b
, '^[^%s]* ', '')
732 bases
= bases
.. ' {"'..string.gsub(b
,'::','.')..'*", (char*)(void*)static_cast<'..b
..'*>(('..c
.xarg
.fullname
..'*)1)-(char*)1},\n'
735 bases
= 'static lqt_Base lqt_base'..c
.xarg
.id
..'[] = {\n'..bases
..' {NULL, 0}\n};\n'
737 wrappers
= wrappers
.. bases
.. '\n'
738 c
.wrappers
= wrappers
743 function print_metatables()
744 for c
in pairs(classes
) do
750 function print_single_class(c
)
751 local n
= c
.xarg
.cname
752 local lua_name
= string.gsub(c
.xarg
.fullname
, '::', '.')
753 local cppname
= module_name
..'_meta_'..n
..'.cpp'
754 table.insert(cpp_files
, n
) -- global cpp_files
755 local fmeta
= assert(io
.open(module_name
.._src
..cppname
, 'w'))
756 local print_meta
= function(...)
760 print_meta('#include "'..module_name
..'_head_'..n
..'.hpp'..'"\n\n')
763 print_meta(c
.implicit
.test
)
764 print_meta(c
.implicit
.convert
)
767 print_meta(c
.wrappers
)
769 local virtual_methods
771 virtual_methods
= virtuals
.sort_by_index(c
)
772 local shellname
= 'lqt_shell_'..c
.xarg
.cname
773 for _
, v
in ipairs(virtual_methods
) do
774 if v
.virtual_overload
then
775 local method
= string.gsub(v
.virtual_overload
, ';;', shellname
..'::', 1)
776 method
= string.gsub(method
, 'VIRTUAL_INDEX', v
.virtual_index
)
782 local getters_setters
= 'NULL, NULL'
784 print_meta(c
.properties
)
785 getters_setters
= 'lqt_getters'..c
.xarg
.id
..', lqt_setters'..c
.xarg
.id
788 local shellname
= 'lqt_shell_'..n
790 local overrides
= 'NULL'
792 overrides
= shellname
..'::lqtAddOverride'
795 print_meta('extern "C" LQT_EXPORT int luaopen_'..n
..' (lua_State *L) {')
796 print_meta('\tlqtL_createclass(L, "'
797 ..lua_name
..'*", lqt_metatable'
798 ..c
.xarg
.id
..', '..getters_setters
..', '..overrides
..', lqt_base'
802 print_meta('\tluaL_getmetatable(L, "'..lua_name
..'*");')
803 print_meta('\tlua_pushliteral(L, "__test");')
804 print_meta('\tlua_pushlightuserdata(L, (void*)&lqt_canconvert_'..c
.xarg
.cname
..');')
805 print_meta('\tlua_rawset(L, -3);')
806 print_meta('\tlua_pushliteral(L, "__convert");')
807 print_meta('\tlua_pushlightuserdata(L, (void*)&lqt_convert_'..c
.xarg
.cname
..');')
808 print_meta('\tlua_rawset(L, -3);')
809 print_meta('\tlua_pop(L, 1);')
812 print_meta
'\treturn 0;'
817 print_meta('int '..shellname
..'::lqtAddOverride(lua_State *L) {')
818 print_meta(' '..shellname
..' *self = static_cast<'..shellname
..'*>('..typesystem
[c
.xarg
.fullname
..'*'].get(1)..');')
819 print_meta(' const char *name = luaL_checkstring(L, 2);')
820 if VERBOSE_BUILD
then
821 print_meta(' printf("Overriding \'%s\' in %s [%p]\\n", name, "'..shellname
..'", self);')
823 for _
, v
in ipairs(virtual_methods
) do
824 print_meta(' if (!strcmp(name, "'..v
.xarg
.name
..'")) {')
825 print_meta(' self->hasOverride.setBit('..v
.virtual_index
..');')
826 if VERBOSE_BUILD
then
827 print_meta(' printf("-> updated %d to %d\\n", '..v
.virtual_index
..', (bool)self->hasOverride['..v
.virtual_index
..']);')
829 print_meta(' return 0;')
835 if c
.shell
and c
.qobject
then
839 QMetaObject lqt_shell_]]..n
..[[::staticMetaObject;
841 const QMetaObject *lqt_shell_]]..n
..[[::metaObject() const {
842 //int oldtop = lua_gettop(L);
843 lqtL_pushudata(L, this, "]]..c
.xarg
.fullname
..[[*");
844 lua_getfield(L, -1, LQT_OBJMETASTRING);
845 if (lua_isnil(L, -1)) {
847 return &]]..c
.xarg
.fullname
..[[::staticMetaObject;
849 lua_getfield(L, -2, LQT_OBJMETADATA);
851 //qDebug() << "copying qmeta object for slots in ]]..c
.xarg
.fullname
..[[";
852 lqt_shell_]]..n
..[[::staticMetaObject.d.superdata = &]]..c
.xarg
.fullname
..[[::staticMetaObject;
853 lqt_shell_]]..n
..[[::staticMetaObject.d.stringdata = lua_tostring(L, -2);
854 lqt_shell_]]..n
..[[::staticMetaObject.d.data = (uint*)lua_touserdata(L, -1);
855 lqt_shell_]]..n
..[[::staticMetaObject.d.extradata = 0; // slot_metaobj->d.extradata;
856 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETADATA);
857 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETASTRING);
859 //qDebug() << (lua_gettop(L) - oldtop);
860 return &lqt_shell_]]..n
..[[::staticMetaObject;
863 int lqt_shell_]]..n
..[[::qt_metacall(QMetaObject::Call call, int index, void **args) {
864 //qDebug() << "fake calling!";
865 index = ]]..c
.xarg
.fullname
..[[::qt_metacall(call, index, args);
866 if (index < 0) return index;
867 return lqtL_qt_metacall(L, this, lqtSlotAcceptor_]]..module_name
..[[, call, "]]..c
.xarg
.fullname
..[[*", index, args);
874 function print_merged_build()
875 local path
= module_name
.._src
876 local mergename
= module_name
..'_merged_build'
877 local merged
= assert(io
.open(path
..mergename
..'.cpp', 'w'))
878 for _
, p
in ipairs(cpp_files
) do
879 merged
:write('#include "',module_name
,'_head_',p
,'.hpp"\n')
882 for _
, p
in ipairs(cpp_files
) do
883 merged
:write('#include "',module_name
,'_meta_',p
,'.cpp"\n')
885 local pro_file
= assert(io
.open(path
..mergename
..'.pro', 'w'))
887 local print_pro
= function(...)
891 print_pro('TEMPLATE = lib')
892 print_pro('TARGET = '..module_name
)
893 print_pro('INCLUDEPATH += .')
894 print_pro('HEADERS += '..module_name
..'_slot.hpp')
895 print_pro('SOURCES += ../common/lqt_common.cpp \\')
896 print_pro(' ../common/lqt_qt.cpp \\')
897 print_pro(' '..module_name
..'_enum.cpp \\')
898 print_pro(' '..module_name
..'_meta.cpp \\')
899 print_pro(' '..module_name
..'_slot.cpp \\')
900 print_pro(' '..mergename
..'.cpp')
904 function print_class_list()
905 local qobject_present
= false
906 local big_picture
= {}
907 local type_list_t
= {}
908 for c
in pairs(classes
) do
909 local n
= c
.xarg
.cname
910 if n
=='QObject' then qobject_present
= true end
911 print_single_class(c
)
912 table.insert(big_picture
, n
)
913 table.insert(type_list_t
, 'add_class \''..c
.xarg
.fullname
..'\'\n')
916 local type_list_f
= assert(io
.open(module_name
.._src
..module_name
..'_types.lua', 'w'))
919 local types = (...) or {}
920 assert(lqt.classes.insert, 'module lqt.classes not loaded')
921 local function add_class(class)
922 lqt.classes.insert(class, true)
925 for k
, v
in ipairs(type_list_t
) do
928 type_list_f
:write('return types\n')
932 local fmeta
= assert(io
.open(module_name
.._src
..module_name
..'_meta.cpp', 'w'))
933 local print_meta
= function(...)
938 print_meta('#include "lqt_common.hpp"')
939 print_meta('#include "'..module_name
..'_slot.hpp'..'"\n\n')
940 for _
, p
in ipairs(big_picture
) do
941 print_meta('extern "C" LQT_EXPORT int luaopen_'..p
..' (lua_State *);')
943 print_meta('void lqt_create_enums_'..module_name
..' (lua_State *);')
944 print_meta('extern "C" LQT_EXPORT int luaopen_'..module_name
..' (lua_State *L) {')
945 for _
, p
in ipairs(big_picture
) do
946 print_meta('\tluaopen_'..p
..'(L);')
948 print_meta('\tlqt_create_enums_'..module_name
..'(L);')
949 if qobject_present
then
950 print_meta('\tlqtL_qobject_custom(L);')
952 if module_name
== "qtcore" then
953 print_meta("\tlqtL_qvariant_custom(L);")
954 elseif module_name
== "qtgui" then
955 print_meta("\tlqtL_qvariant_custom_qtgui(L);")
957 print_meta('\tlqtL_register_super(L);')
958 print_meta('\tlqtSlotAcceptor_'..module_name
..' = new LqtSlotAcceptor(L);')
959 print_meta('\treturn 0;\n}')
960 if fmeta
then fmeta
:close() end
963 ------------------------------------------------------------
965 function preprocess(index
)
966 copy_classes(index
) -- picks classes if not private and not blacklisted
967 copy_functions(index
) -- picks functions and fixes label
968 fix_arguments(index
) -- fixes default arguments if they are context-relative
969 fix_functions() -- fixes name and fullname and fills arguments
970 operators
.fix_operators(index
)
973 function process(index
, typesystem
, filterfiles
)
974 for _
, f
in ipairs(filterfiles
) do
975 classes
= loadfile(f
)(classes
)
978 virtuals
.fill_virtuals(classes
) -- does that, destructor ("~") excluded
979 distinguish_methods() -- does that
980 fill_public_destr() -- does that: checks if destructor is public
981 fill_copy_constructor() -- does that: checks if copy contructor is public or protected
982 fill_implicit_constructor()
983 fix_methods_wrappers()
986 fill_typesystem_with_classes()
988 virtuals
.fill_virtual_overloads(classes
) -- does that
989 virtuals
.fill_shell_classes(classes
) -- does that
990 properties
.fill_properties(classes
)
991 fill_implicit_wrappers()
993 signalslot
.process(functions
)
997 virtuals
.print_shell_classes(classes
) -- does that, and outputs headers
999 print_wrappers(classes
) -- just compiles metatable list
1000 print_metatables(classes
) -- just collects the wrappers + generates dispatchers
1001 print_class_list(classes
) -- does that + prints everything related to class