Make QVariant::setValue work for classes from QtGui module
[lqt/mk.git] / generator / classes.lua
bloba763a9d673b32064147beca01b1b2f4f4ca4bf0f
1 require 'virtuals'
2 require 'templates'
3 require 'operators'
4 require 'signalslot'
5 require 'properties'
7 module('classes', package.seeall)
9 -- collection of all functions
10 local functions = {}
11 -- collection of bound classes
12 local classes = {}
13 -- list of files to be included
14 local cpp_files = {}
15 -- table of classes by their cname
16 local classlist = {}
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
22 e.label = 'Function'
23 functions[e] = true
24 end
25 end
26 end
29 function fix_arguments(index)
30 for a in pairs(index) do
31 if a.label=='Argument'
32 and a.xarg.default=='1'
33 and (not string.match(a.xarg.defaultvalue, '^[-+]?%d+%.?%d*[L]?$'))
34 and (not string.match(a.xarg.defaultvalue, '^".*"$'))
35 and a.xarg.defaultvalue~='true'
36 and a.xarg.defaultvalue~='false'
37 and (not string.match(a.xarg.defaultvalue, '^0[xX]%d+$')) then
38 local dv, call = string.match(a.xarg.defaultvalue, '(.-)(%(%))')
39 dv = dv or a.xarg.defaultvalue
40 call = call or ''
41 local context = a.xarg.context
42 while not fullnames[context..'::'..dv] and context~='' do
43 context = string.match(context, '^(.*)::') or ''
44 end
45 if fullnames[context..'::'..dv] then
46 if fullnames[context..'::'..dv].xarg.name==fullnames[context..'::'..dv].xarg.member_of_class then
47 context = string.match(context, '^(.*)::') or ''
48 end
49 a.xarg.defaultvalue = context..'::'..dv..call
50 elseif fullnames[dv] then
51 a.xarg.defaultvalue = dv..call
52 else
53 a.xarg.default = nil
54 a.xarg.defaultvalue = nil
55 end
56 end
57 end
58 end
61 --- Removes unneeded 'void' parameters and return values.
62 function fix_functions()
63 for f in pairs(functions) do
64 local args = {}
65 for i, a in ipairs(f) do
66 -- avoid bogus 'void' arguments
67 if a.xarg.type_name=='void' and i==1 and f[2]==nil then break end
68 if a.label=='Argument' then
69 table.insert(args, a)
70 end
71 end
72 f.arguments = args
73 f.return_type = f.xarg.type_name
74 if f.xarg.type_name=='void' then
75 f.return_type = nil
76 end
77 end
78 end
80 --- Determines, if a class is public.
81 function class_is_public(c)
82 repeat
83 if c.xarg.access~='public' then return false end
84 if c.xarg.member_of_class then
85 local p = fullnames[c.xarg.member_of_class]
86 assert(p, 'member_of_class should exist')
87 assert(p.label=='Class', 'member_of_class should be a class')
88 c = fullnames[c.xarg.member_of_class]
89 else
90 return true
91 end
92 until true
93 end
95 --- Selects public classes from the index, and creates templated instances
96 -- where appropriate.
97 function copy_classes(index)
98 for e in pairs(index) do
99 if e.label=='Class' then
100 e.xarg.cname = string.gsub(e.xarg.fullname, '::', '_LQT_')
101 if class_is_public(e)
102 and not e.xarg.fullname:match'%b<>' then
103 classes[e] = true
104 elseif not e.xarg.fullname:match'%b<>' then
105 ignore(e.xarg.fullname, 'not public')
106 else
107 if templates.should_copy(e) then
108 templates.create(e, classes)
113 templates.finish(index)
114 for c in pairs(classes) do
115 classlist[c.xarg.cname] = c
119 function fix_methods_wrappers()
120 for c in pairs(classes) do
121 c.shell = c.public_destr
122 c.shell = c.shell and (next(c.virtuals)~=nil)
123 for _, constr in ipairs(c.constructors) do
124 if c.shell then
125 local shellname = 'lqt_shell_'..c.xarg.cname
126 constr.calling_line = 'new '..shellname..'(L'
127 if #(constr.arguments)>0 then constr.calling_line = constr.calling_line .. ', ' end
128 else
129 local shellname = c.xarg.fullname
130 constr.calling_line = 'new '..shellname..'('
132 for i=1,#(constr.arguments) do
133 constr.calling_line = constr.calling_line .. (i==1 and '' or ', ') .. 'arg' .. i
135 constr.calling_line = '*('..constr.calling_line .. '))'
136 constr.xarg.static = '1'
137 constr.return_type = constr.xarg.scope..'&'
139 if c.destructor then
140 c.destructor.return_type = nil
145 --- Determines, whether classes are children of QObject.
146 -- Fills the 'qobject' field on class if it is child of QObject.
147 function get_qobjects()
148 local function is_qobject(c)
149 if c==nil then return false end
150 if c.qobject then return true end
151 if c.xarg.fullname=='QObject' then
152 c.qobject = true
153 return true
155 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
156 local base = fullnames[b]
157 if is_qobject(base) then
158 --debug(c.xarg.fullname, "is a QObject")
159 c.qobject = true
160 return true
163 return false
165 for c in pairs(classes) do
166 local qobj = is_qobject(c)
172 local should_wrap = function(f)
173 local name = f.xarg.name
174 -- unfixed operator and friend, causes trouble with QDataStream
175 -- if f.xarg.friend and #f.arguments ==2 then return false end
176 -- not an operator - accept
177 if not name:match('^operator') then return true end
178 -- accept supported operators
179 if operators.is_operator(name) then return true end
180 return false
185 function distinguish_methods()
186 for c in pairs(classes) do
187 local construct, destruct, normal = {}, nil, {}
188 local n = c.xarg.name:gsub('%b<>', '')
190 local copy = nil
191 for _, f in ipairs(c) do
192 if n==f.xarg.name then
193 table.insert(construct, f)
194 elseif f.xarg.name:match'~' then
195 destruct = f
196 else
197 if should_wrap(f)
198 and (not f.xarg.member_template_parameters) then
199 table.insert(normal, f)
200 else
201 ignore(f.xarg.fullname, 'operator/template/friend', c.xarg.name)
205 c.constructors = construct
206 c.destructor = destruct
207 c.methods = normal
211 --- Determines, if a class has a public destructor. It also scans the superclasses.
212 -- Sets the 'public_destr' fiield on the class.
213 function fill_public_destr()
214 local function destr_is_public(c)
215 if c.destructor then
216 return c.destructor.xarg.access=='public'
217 else
218 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
219 local base = fullnames[b]
220 if base and not destr_is_public(base) then
221 return false
224 return true
227 for c in pairs(classes) do
228 c.public_destr = destr_is_public(c)
233 function generate_default_copy_constructor(c)
234 if not c.xarg then return end
236 local copy = {
237 [1] = {
238 label = "Argument";
239 xarg = {
240 context = c.xarg.name;
241 id = next_id();
242 name = "p";
243 scope = "";
244 type_base = c.xarg.name;
245 type_constant = "1";
246 type_name = c.xarg.name .. " const&";
247 type_reference = "1";
250 label = "Function";
251 return_type = c.xarg.name;
252 xarg = {
253 access = "public";
254 context = c.xarg.name;
255 fullname = c.xarg.name.."::"..c.xarg.name;
256 id = next_id();
257 inline = "1";
258 member_of = c.xarg.name;
259 member_of_class = c.xarg.name;
260 name = c.xarg.name;
261 scope = c.xarg.name;
262 type_base = c.xarg.name;
263 type_name = c.xarg.name;
266 copy.arguments = {copy[1]}
268 table.insert(c, copy)
269 table.insert(c.constructors, copy)
270 functions[copy] = true
272 return copy
275 -- HACK: do not create copy contructors for classes, that
276 -- contain variables of class '*Private' - they will not compile
277 -- in Qt 4.6
278 local function has_private_fields(c)
279 for _,v in ipairs(c) do
280 if v.label == 'Variable' then
281 if v.xarg.type_base:match('Private') then
282 ignore(c.xarg.fullname, 'cannot create copy constructor', v.xarg.fullname .. ' : ' ..v.xarg.type_base)
283 return true
287 return false
290 function fill_copy_constructor()
291 for c in pairs(classes) do
292 local copy = nil
293 for _, f in ipairs(c.constructors) do
294 if #(f.arguments)==1
295 and f.arguments[1].xarg.type_name==c.xarg.fullname..' const&' then
296 copy = f
297 break
300 c.copy_constructor = copy
302 local function copy_constr_is_public(c)
303 if c.copy_constructor then
304 return (c.copy_constructor.xarg.access=='public')
305 or (c.copy_constructor.xarg.access=='protected')
306 else
307 if has_private_fields(c) then return false end
308 local ret = nil
309 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
310 local base = fullnames[b]
311 if base and not copy_constr_is_public(base) then
312 return false
315 return true
318 for c in pairs(classes) do
319 c.public_constr = copy_constr_is_public(c)
320 if c.public_constr and not c.copy_constructor then
321 c.copy_constructor = generate_default_copy_constructor(c)
326 function fill_implicit_constructor()
327 typesystem.can_convert = {}
328 for c in pairs(classes) do
329 for _,f in ipairs(c) do
330 if f.label:match("^Function") then
331 -- find non-explicit constructor, which has 1 argument of type different
332 -- from class, i.e. an implicit conversion constructor
333 if f.xarg.name == c.xarg.name
334 and #f == 1
335 and (not f.xarg.access or f.xarg.access == "public")
336 and f[1].xarg.type_base ~= c.xarg.name
337 and not f[1].xarg.type_base:match('Private$')
338 -- and not f.xarg.explicit
339 and not c.abstract
340 then
341 local class_name = c.xarg.cname
342 local from_type = f[1].xarg.type_base
343 typesystem.can_convert[class_name] = typesystem.can_convert[class_name] or { from = {}, class = c }
344 typesystem.can_convert[class_name].from[ from_type ] = f
345 local safe_from = from_type:gsub('[<>*]', '_'):gsub('::', '_LQT_')
352 local function generate_implicit_code(class_name, t)
353 local c = t.class
354 local fullname = c.xarg.fullname
355 local luaname = fullname:gsub('::', '.')
357 local test_header = 'bool lqt_canconvert_' .. class_name .. '(lua_State *L, int n)'
358 local convert_header = 'void* lqt_convert_' .. class_name .. '(lua_State *L, int n)'
360 local test_code = ""
361 local convert_code = ""
362 local tests = {}
364 local order = {}
365 for _, f in pairs(t.from) do
366 local typ = f[1].xarg.type_name
367 if not typesystem[typ] then
368 ignore(typ, "implicit constructor - unknown type", _)
369 else
370 local test
371 if typesystem[typ].raw_test then
372 test = typesystem[typ].raw_test('n')
373 else
374 test = typesystem[typ].test('n')
376 if not tests[test] then
377 tests[test] = true
378 local test_code =
379 ' if ('..test..')\n'
380 ..' return true;\n'
382 local newtype = fullname .. '(arg)'
383 if c.shell then newtype = 'lqt_shell_'..c.xarg.cname..'(L,arg)' end
385 -- HACK: QVariant with 'char const*' argument - force it to QByteArray
386 if fullname == 'QVariant' and typ == 'char const*' then
387 typ = 'QByteArray'
390 local convert_code =
391 ' if ('..test..') {\n'
392 ..' '..typ..' arg = '..typesystem[typ].get('n')..';\n'
393 ..' '..fullname..' *ret = new '..newtype..';\n'
394 ..' lqtL_passudata(L, ret, "'..luaname..'*");\n'
395 ..' return ret;\n }\n'
397 local item = { type = fullname, test = test, defect = typesystem[typ].defect or 0,
398 test_code = test_code, convert_code = convert_code }
399 table.insert(order, item)
404 table.sort(order, function(a,b) return a.defect < b.defect end)
405 for _,v in ipairs(order) do
406 test_code = test_code .. v.test_code
407 convert_code = convert_code .. v.convert_code
410 test_code = test_code .. ' return false;'
411 convert_code = convert_code..' return NULL;'
413 c.implicit = {
414 headers = { test = test_header, convert = convert_header },
415 test = test_header .. '{\n' .. test_code .. '\n}',
416 convert = convert_header .. '{\n' .. convert_code .. '\n}'
421 function fill_implicit_wrappers()
422 for class_name, t in pairs(typesystem.can_convert) do
423 if not t.class.abstract then
424 generate_implicit_code(class_name, t)
430 local put_class_in_filesystem = lqt.classes.insert
432 function fill_typesystem_with_classes()
433 for c in pairs(classes) do
434 classes[c] = put_class_in_filesystem(c.xarg.fullname)
439 function fill_wrapper_code(f)
440 if f.wrapper_code then return f end
441 local stackn, argn = 1, 1
442 local stack_args, defects = '', 0
443 local has_args = true
444 local wrap, line = ' int oldtop = lua_gettop(L);\n', ''
445 if f.xarg.abstract then
446 ignore(f.xarg.fullname, 'abstract method', f.xarg.member_of_class)
447 return nil
449 if f.xarg.member_of_class and f.xarg.static~='1' then
450 if not typesystem[f.xarg.member_of_class..'*'] then
451 ignore(f.xarg.fullname, 'not a member of wrapped class', f.xarg.member_of_class)
452 return nil
454 stack_args = stack_args .. typesystem[f.xarg.member_of_class..'*'].onstack
455 defects = defects + 7 -- FIXME: arbitrary
456 if f.xarg.constant=='1' then
457 defects = defects + 8 -- FIXME: arbitrary
459 local sget, sn = typesystem[f.xarg.member_of_class..'*'].get(stackn)
460 wrap = wrap .. ' ' .. f.xarg.member_of_class .. '* self = ' .. sget .. ';\n'
461 stackn = stackn + sn
462 wrap = wrap .. ' lqtL_selfcheck(L, self, "'..f.xarg.member_of_class..'");\n'
463 --print(sget, sn)
464 if operators.is_operator(f.xarg.name) then
465 line, has_args = operators.call_line(f)
466 if not line then return nil end
467 else
468 line = 'self->'..f.xarg.fullname..'('
470 else
471 line = f.xarg.fullname..'('
473 for i, a in ipairs(f.arguments) do
474 if not typesystem[a.xarg.type_name] then
475 ignore(f.xarg.fullname, 'unkown argument type', a.xarg.type_name)
476 return nil
478 local aget, an, arg_as = typesystem[a.xarg.type_name].get(stackn)
479 stack_args = stack_args .. typesystem[a.xarg.type_name].onstack
480 if typesystem[a.xarg.type_name].defect then defects = defects + typesystem[a.xarg.type_name].defect end
481 wrap = wrap .. ' ' .. argument_name(arg_as or a.xarg.type_name, 'arg'..argn) .. ' = '
482 if a.xarg.default=='1' and an>0 then
483 wrap = wrap .. 'lua_isnoneornil(L, '..stackn..')'
484 for j = stackn+1,stackn+an-1 do
485 wrap = wrap .. ' && lua_isnoneornil(L, '..j..')'
487 local dv = a.xarg.defaultvalue
488 wrap = wrap .. ' ? static_cast< ' .. a.xarg.type_name .. ' >(' .. dv .. ') : '
490 wrap = wrap .. aget .. ';\n'
491 line = line .. (argn==1 and 'arg' or ', arg') .. argn
492 stackn = stackn + an
493 argn = argn + 1
495 if has_args then
496 line = line .. ')'
498 -- FIXME: hack follows for constructors
499 if f.calling_line then line = f.calling_line end
500 if f.return_type then line = f.return_type .. ' ret = ' .. line end
501 wrap = wrap .. ' ' .. line .. ';\n lua_settop(L, oldtop);\n' -- lua_pop(L, '..stackn..');\n'
502 if f.return_type then
503 if not typesystem[f.return_type] then
504 ignore(f.xarg.fullname, 'unknown return type', f.return_type)
505 return nil
507 local rput, rn = typesystem[f.return_type].push'ret'
508 wrap = wrap .. ' luaL_checkstack(L, '..rn..', "cannot grow stack for return value");\n'
509 wrap = wrap .. ' '..rput..';\n return '..rn..';\n'
510 else
511 wrap = wrap .. ' return 0;\n'
513 f.wrapper_code = wrap
514 f.stack_arguments = stack_args
515 f.defects = defects
516 return f
520 function fill_test_code(f)
521 local stackn = 1
522 local test = ''
523 if f.xarg.member_of_class and f.xarg.static~='1' then
524 if not typesystem[f.xarg.member_of_class..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
525 local stest, sn = typesystem[f.xarg.member_of_class..'*'].test(stackn)
526 test = test .. ' && ' .. stest
527 stackn = stackn + sn
529 for i, a in ipairs(f.arguments) do
530 if not typesystem[a.xarg.type_name] then return nil end -- print(a.xarg.type_name) return nil end
531 local atest, an = typesystem[a.xarg.type_name].test(stackn)
532 if a.xarg.default=='1' and an>0 then
533 test = test .. ' && (lqtL_missarg(L, ' .. stackn .. ', ' .. an .. ') || '
534 test = test .. atest .. ')'
535 else
536 test = test .. ' && ' .. atest
538 stackn = stackn + an
540 -- can't make use of default values if I fix number of args
541 test = '(lua_gettop(L)<' .. stackn .. ')' .. test
542 f.test_code = test
543 return f
548 function fill_wrappers()
549 for f in pairs(functions) do
550 local nf = fill_wrapper_code(f)
551 if nf then
552 nf = assert(fill_test_code(nf), nf.xarg.fullname) -- MUST pass
553 else
554 -- failed to generate wrapper
555 functions[f] = nil
560 ---- Output functions
562 function print_wrappers()
563 for c in pairs(classes) do
564 local meta = {}
565 local wrappers = ''
566 for _, f in ipairs(c.methods) do
567 -- FIXME: should we really discard virtual functions?
568 -- if the virtual overload in the shell uses rawget
569 -- on the environment then we can leave these in the
570 -- metatable
571 if f.wrapper_code and not f.ignore then
572 local out = 'static int lqt_bind'..f.xarg.id
573 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
574 if f.xarg.access=='public' then
575 --print_meta(out)
576 wrappers = wrappers .. out .. '\n'
577 meta[f] = f.xarg.name
581 if not c.abstract then
582 for _, f in ipairs(c.constructors) do
583 if f.wrapper_code then
584 local out = 'static int lqt_bind'..f.xarg.id
585 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
586 if f.xarg.access=='public' then
587 --print_meta(out)
588 wrappers = wrappers .. out .. '\n'
589 meta[f] = 'new'
594 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
595 local lua_name = string.gsub(c.xarg.fullname, '::', '.')
596 local out = 'static int lqt_delete'..c.xarg.id..' (lua_State *L) {\n'
597 out = out ..' '..c.xarg.fullname..' *p = static_cast<'
598 ..c.xarg.fullname..'*>(lqtL_toudata(L, 1, "'..lua_name..'*"));\n'
599 if c.public_destr then
600 out = out .. ' if (p) delete p;\n'
602 out = out .. ' lqtL_eraseudata(L, 1, "'..lua_name..'*");\n return 0;\n}\n'
603 --print_meta(out)
604 wrappers = wrappers .. out .. '\n'
605 c.meta = meta
606 c.wrappers = wrappers
611 local print_metatable = function(c)
612 local methods = {}
613 local wrappers = c.wrappers
614 for m, n in pairs(c.meta) do
615 methods[n] = methods[n] or {}
616 table.insert(methods[n], m)
618 for n, l in pairs(methods) do
619 local duplicates = {}
620 for _, f in ipairs(l) do
621 if not f.ignore then
622 local itisnew = true
623 for sa, g in pairs(duplicates) do
624 if sa==f.stack_arguments then
625 --debug("function equal: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
626 if f.defects<g.defects then
627 else
628 ignore(f.xarg.fullname, "duplicate function", f.stack_arguments)
629 itisnew = false
631 elseif string.match(sa, "^"..f.stack_arguments) then -- there is already a version with more arguments
632 --debug("function superseded: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
633 elseif string.match(f.stack_arguments, '^'..sa) then -- there is already a version with less arguments
634 --debug("function superseding: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
637 if itisnew then
638 duplicates[f.stack_arguments] = f
642 --[[
643 local numinitial = 0
644 local numfinal = 0
645 for sa, f in pairs(l) do
646 numinitial = numinitial + 1
648 for sa, f in pairs(duplicates) do
649 numfinal = numfinal + 1
651 if numinitial-numfinal>0 then debug(c.xarg.fullname, "suppressed:", numinitial-numfinal) end
652 --]]
653 methods[n] = duplicates
655 for n, l in pairs(methods) do
656 local name = operators.rename_operator(n)
657 local disp = 'static int lqt_dispatcher_'..name..c.xarg.id..' (lua_State *L) {\n'
658 local testcode = {}
659 for tc, f in pairs(l) do
660 disp = disp..' if ('..f.test_code..') return lqt_bind'..f.xarg.id..'(L);\n'
661 testcode[#testcode+1] = tc
663 -- disp = disp .. ' lua_settop(L, 0);\n'
664 disp = disp .. ' const char * args = lqtL_getarglist(L);\n'
665 disp = disp .. ' lua_pushfstring(L, "%s(%s): incorrect or extra arguments, expecting: %s.", "' ..
666 c.xarg.fullname..'::'..n..'", args, '..string.format("%q", table.concat(testcode, ' or ')) .. ');\n'
667 disp = disp .. ' return lua_error(L);\n}\n'
668 --print_meta(disp)
669 wrappers = wrappers .. disp .. '\n'
671 local metatable = 'static luaL_Reg lqt_metatable'..c.xarg.id..'[] = {\n'
672 for n, l in pairs(methods) do
673 local nn = operators.rename_operator(n)
674 metatable = metatable .. ' { "'..nn..'", lqt_dispatcher_'..nn..c.xarg.id..' },\n'
676 metatable = metatable .. ' { "delete", lqt_delete'..c.xarg.id..' },\n'
677 metatable = metatable .. ' { 0, 0 },\n};\n'
678 --print_meta(metatable)
679 wrappers = wrappers .. metatable .. '\n'
680 local bases = ''
681 for b in string.gmatch(c.xarg.bases_with_attributes or '', '([^;]*);') do
682 if not string.match(b, '^virtual') then
683 b = string.gsub(b, '^[^%s]* ', '')
684 bases = bases .. ' {"'..string.gsub(b,'::','.')..'*", (char*)(void*)static_cast<'..b..'*>(('..c.xarg.fullname..'*)1)-(char*)1},\n'
687 bases = 'static lqt_Base lqt_base'..c.xarg.id..'[] = {\n'..bases..' {NULL, 0}\n};\n'
688 --print_meta(bases)
689 wrappers = wrappers .. bases .. '\n'
690 c.wrappers = wrappers
691 return c
695 function print_metatables()
696 for c in pairs(classes) do
697 print_metatable(c)
702 function print_single_class(c)
703 local n = c.xarg.cname
704 local lua_name = string.gsub(c.xarg.fullname, '::', '.')
705 local cppname = module_name..'_meta_'..n..'.cpp'
706 table.insert(cpp_files, n) -- global cpp_files
707 local fmeta = assert(io.open(module_name.._src..cppname, 'w'))
708 local print_meta = function(...)
709 fmeta:write(...)
710 fmeta:write'\n'
712 print_meta('#include "'..module_name..'_head_'..n..'.hpp'..'"\n\n')
714 if c.implicit then
715 print_meta(c.implicit.test)
716 print_meta(c.implicit.convert)
719 print_meta(c.wrappers)
720 if c.virtual_overloads then
721 print_meta(c.virtual_overloads)
724 local getters_setters = 'NULL, NULL'
725 if c.properties then
726 print_meta(c.properties)
727 getters_setters = 'lqt_getters'..c.xarg.id..', lqt_setters'..c.xarg.id
730 print_meta('extern "C" LQT_EXPORT int luaopen_'..n..' (lua_State *L) {')
731 print_meta('\tlqtL_createclass(L, "'
732 ..lua_name..'*", lqt_metatable'
733 ..c.xarg.id..', '..getters_setters..', lqt_base'
734 ..c.xarg.id..');')
736 if c.implicit then
737 print_meta('\tluaL_getmetatable(L, "'..lua_name..'*");')
738 print_meta('\tlua_pushliteral(L, "__test");')
739 print_meta('\tlua_pushlightuserdata(L, (void*)&lqt_canconvert_'..c.xarg.cname..');')
740 print_meta('\tlua_rawset(L, -3);')
741 print_meta('\tlua_pushliteral(L, "__convert");')
742 print_meta('\tlua_pushlightuserdata(L, (void*)&lqt_convert_'..c.xarg.cname..');')
743 print_meta('\tlua_rawset(L, -3);')
744 print_meta('\tlua_pop(L, 1);')
747 print_meta'\treturn 0;'
748 print_meta'}'
749 print_meta''
750 if c.shell and c.qobject then
751 print_meta([[
752 #include <QDebug>
754 QMetaObject lqt_shell_]]..n..[[::staticMetaObject;
756 const QMetaObject *lqt_shell_]]..n..[[::metaObject() const {
757 //int oldtop = lua_gettop(L);
758 lqtL_pushudata(L, this, "]]..c.xarg.fullname..[[*");
759 lua_getfield(L, -1, LQT_OBJMETASTRING);
760 if (lua_isnil(L, -1)) {
761 lua_pop(L, 2);
762 return &]]..c.xarg.fullname..[[::staticMetaObject;
764 lua_getfield(L, -2, LQT_OBJMETADATA);
765 lqtL_touintarray(L);
766 //qDebug() << "copying qmeta object for slots in ]]..c.xarg.fullname..[[";
767 lqt_shell_]]..n..[[::staticMetaObject.d.superdata = &]]..c.xarg.fullname..[[::staticMetaObject;
768 lqt_shell_]]..n..[[::staticMetaObject.d.stringdata = lua_tostring(L, -2);
769 lqt_shell_]]..n..[[::staticMetaObject.d.data = (uint*)lua_touserdata(L, -1);
770 lqt_shell_]]..n..[[::staticMetaObject.d.extradata = 0; // slot_metaobj->d.extradata;
771 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETADATA);
772 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETASTRING);
773 lua_pop(L, 1);
774 //qDebug() << (lua_gettop(L) - oldtop);
775 return &lqt_shell_]]..n..[[::staticMetaObject;
778 int lqt_shell_]]..n..[[::qt_metacall(QMetaObject::Call call, int index, void **args) {
779 //qDebug() << "fake calling!";
780 index = ]]..c.xarg.fullname..[[::qt_metacall(call, index, args);
781 if (index < 0) return index;
782 return lqtL_qt_metacall(L, this, lqtSlotAcceptor_]]..module_name..[[, call, "]]..c.xarg.fullname..[[*", index, args);
786 fmeta:close()
789 function print_merged_build()
790 local path = module_name.._src
791 local mergename = module_name..'_merged_build'
792 local merged = assert(io.open(path..mergename..'.cpp', 'w'))
793 for _, p in ipairs(cpp_files) do
794 merged:write('#include "',module_name,'_head_',p,'.hpp"\n')
796 merged:write('\n')
797 for _, p in ipairs(cpp_files) do
798 merged:write('#include "',module_name,'_meta_',p,'.cpp"\n')
800 local pro_file = assert(io.open(path..mergename..'.pro', 'w'))
802 local print_pro= function(...)
803 pro_file:write(...)
804 pro_file:write'\n'
806 print_pro('TEMPLATE = lib')
807 print_pro('TARGET = '..module_name)
808 print_pro('INCLUDEPATH += .')
809 print_pro('HEADERS += '..module_name..'_slot.hpp')
810 print_pro('SOURCES += ../common/lqt_common.cpp \\')
811 print_pro(' ../common/lqt_qt.cpp \\')
812 print_pro(' '..module_name..'_enum.cpp \\')
813 print_pro(' '..module_name..'_meta.cpp \\')
814 print_pro(' '..module_name..'_slot.cpp \\')
815 print_pro(' '..mergename..'.cpp')
819 function print_class_list()
820 local qobject_present = false
821 local big_picture = {}
822 local type_list_t = {}
823 for c in pairs(classes) do
824 local n = c.xarg.cname
825 if n=='QObject' then qobject_present = true end
826 print_single_class(c)
827 table.insert(big_picture, n)
828 table.insert(type_list_t, 'add_class \''..c.xarg.fullname..'\'\n')
831 local type_list_f = assert(io.open(module_name.._src..module_name..'_types.lua', 'w'))
832 type_list_f:write([[
833 #!/usr/bin/lua
834 local types = (...) or {}
835 assert(lqt.classes.insert, 'module lqt.classes not loaded')
836 local function add_class(class)
837 lqt.classes.insert(class, true)
840 for k, v in ipairs(type_list_t) do
841 type_list_f:write(v)
843 type_list_f:write('return types\n')
844 type_list_f:close()
846 print_merged_build()
847 local fmeta = assert(io.open(module_name.._src..module_name..'_meta.cpp', 'w'))
848 local print_meta = function(...)
849 fmeta:write(...)
850 fmeta:write'\n'
852 print_meta()
853 print_meta('#include "lqt_common.hpp"')
854 print_meta('#include "'..module_name..'_slot.hpp'..'"\n\n')
855 for _, p in ipairs(big_picture) do
856 print_meta('extern "C" LQT_EXPORT int luaopen_'..p..' (lua_State *);')
858 print_meta('void lqt_create_enums_'..module_name..' (lua_State *);')
859 print_meta('extern "C" LQT_EXPORT int luaopen_'..module_name..' (lua_State *L) {')
860 for _, p in ipairs(big_picture) do
861 print_meta('\tluaopen_'..p..'(L);')
863 print_meta('\tlqt_create_enums_'..module_name..'(L);')
864 if qobject_present then
865 print_meta('\tlqtL_qobject_custom(L);')
867 if module_name == "qtcore" then
868 print_meta("\tlqtL_qvariant_custom(L);")
869 elseif module_name == "qtgui" then
870 print_meta("\tlqtL_qvariant_custom_qtgui(L);")
872 print_meta('\tlqtL_register_super(L);')
873 print_meta('\tlqtSlotAcceptor_'..module_name..' = new LqtSlotAcceptor(L);')
874 print_meta('\treturn 0;\n}')
875 if fmeta then fmeta:close() end
878 ------------------------------------------------------------
880 function preprocess(index)
881 copy_classes(index) -- picks classes if not private and not blacklisted
882 copy_functions(index) -- picks functions and fixes label
883 fix_arguments(index) -- fixes default arguments if they are context-relative
884 fix_functions() -- fixes name and fullname and fills arguments
885 operators.fix_operators(index)
888 function process(index, typesystem, filterfiles)
889 for _, f in ipairs(filterfiles) do
890 classes = loadfile(f)(classes)
893 virtuals.fill_virtuals(classes) -- does that, destructor ("~") excluded
894 distinguish_methods() -- does that
895 fill_public_destr() -- does that: checks if destructor is public
896 fill_copy_constructor() -- does that: checks if copy contructor is public or protected
897 fill_implicit_constructor()
898 fix_methods_wrappers()
899 get_qobjects()
901 fill_typesystem_with_classes()
902 fill_wrappers()
903 virtuals.fill_virtual_overloads(classes) -- does that
904 virtuals.fill_shell_classes(classes) -- does that
905 properties.fill_properties(classes)
906 fill_implicit_wrappers()
908 signalslot.process(functions)
911 function output()
912 virtuals.print_shell_classes(classes) -- does that, and outputs headers
913 virtuals.print_virtual_overloads(classes) -- does that
915 print_wrappers(classes) -- just compiles metatable list
916 print_metatables(classes) -- just collects the wrappers + generates dispatchers
917 print_class_list(classes) -- does that + prints everything related to class
919 signalslot.output()