Implicit conversion constructor implementation
[lqt/mk.git] / generator / classes.lua
blobbffc950b5f31eac431b2db36259ffcbe2af551af
1 require 'virtuals'
2 require 'templates'
3 require 'operators'
4 require 'signalslot'
6 module('classes', package.seeall)
8 -- collection of all functions
9 local functions = {}
10 -- collection of bound classes
11 local classes = {}
12 -- list of files to be included
13 local cpp_files = {}
14 -- table of classes by their cname
15 local classlist = {}
17 --- Copies functions from the index.
18 function copy_functions(index)
19 for e in pairs(index) do
20 if e.label:match'^Function' then
21 e.label = 'Function'
22 functions[e] = true
23 end
24 end
25 end
28 function fix_arguments(index)
29 for a in pairs(index) do
30 if a.label=='Argument'
31 and a.xarg.default=='1'
32 and (not string.match(a.xarg.defaultvalue, '^[-+]?%d+%.?%d*[L]?$'))
33 and (not string.match(a.xarg.defaultvalue, '^".*"$'))
34 and a.xarg.defaultvalue~='true'
35 and a.xarg.defaultvalue~='false'
36 and (not string.match(a.xarg.defaultvalue, '^0[xX]%d+$')) then
37 local dv, call = string.match(a.xarg.defaultvalue, '(.-)(%(%))')
38 dv = dv or a.xarg.defaultvalue
39 call = call or ''
40 local context = a.xarg.context
41 while not fullnames[context..'::'..dv] and context~='' do
42 context = string.match(context, '^(.*)::') or ''
43 end
44 if fullnames[context..'::'..dv] then
45 if fullnames[context..'::'..dv].xarg.name==fullnames[context..'::'..dv].xarg.member_of_class then
46 context = string.match(context, '^(.*)::') or ''
47 end
48 a.xarg.defaultvalue = context..'::'..dv..call
49 elseif fullnames[dv] then
50 a.xarg.defaultvalue = dv..call
51 else
52 a.xarg.default = nil
53 a.xarg.defaultvalue = nil
54 end
55 end
56 end
57 end
60 --- Removes unneeded 'void' parameters and return values.
61 function fix_functions()
62 for f in pairs(functions) do
63 local args = {}
64 for i, a in ipairs(f) do
65 -- avoid bogus 'void' arguments
66 if a.xarg.type_name=='void' and i==1 and f[2]==nil then break end
67 if a.label=='Argument' then
68 table.insert(args, a)
69 end
70 end
71 f.arguments = args
72 f.return_type = f.xarg.type_name
73 if f.xarg.type_name=='void' then
74 f.return_type = nil
75 end
76 end
77 end
79 --- Determines, if a class is public.
80 function class_is_public(c)
81 repeat
82 if c.xarg.access~='public' then return false end
83 if c.xarg.member_of_class then
84 local p = fullnames[c.xarg.member_of_class]
85 assert(p, 'member_of_class should exist')
86 assert(p.label=='Class', 'member_of_class should be a class')
87 c = fullnames[c.xarg.member_of_class]
88 else
89 return true
90 end
91 until true
92 end
94 --- Selects public classes from the index, and creates templated instances
95 -- where appropriate.
96 function copy_classes(index)
97 for e in pairs(index) do
98 if e.label=='Class' then
99 e.xarg.cname = string.gsub(e.xarg.fullname, '::', '_LQT_')
100 if class_is_public(e)
101 and not e.xarg.fullname:match'%b<>' then
102 classes[e] = true
103 elseif not e.xarg.fullname:match'%b<>' then
104 ignore(e.xarg.fullname, 'not public')
105 else
106 if templates.should_copy(e) then
107 templates.create(e, classes)
112 templates.finish(index)
113 for c in pairs(classes) do
114 classlist[c.xarg.cname] = c
118 function fix_methods_wrappers()
119 for c in pairs(classes) do
120 c.shell = c.public_destr
121 c.shell = c.shell and (next(c.virtuals)~=nil)
122 for _, constr in ipairs(c.constructors) do
123 if c.shell then
124 local shellname = 'lqt_shell_'..c.xarg.cname
125 constr.calling_line = 'new '..shellname..'(L'
126 if #(constr.arguments)>0 then constr.calling_line = constr.calling_line .. ', ' end
127 else
128 local shellname = c.xarg.fullname
129 constr.calling_line = 'new '..shellname..'('
131 for i=1,#(constr.arguments) do
132 constr.calling_line = constr.calling_line .. (i==1 and '' or ', ') .. 'arg' .. i
134 constr.calling_line = '*('..constr.calling_line .. '))'
135 constr.xarg.static = '1'
136 constr.return_type = constr.xarg.scope..'&'
138 if c.destructor then
139 c.destructor.return_type = nil
144 --- Determines, whether classes are children of QObject.
145 -- Fills the 'qobject' field on class if it is child of QObject.
146 function get_qobjects()
147 local function is_qobject(c)
148 if c==nil then return false end
149 if c.qobject then return true end
150 if c.xarg.fullname=='QObject' then
151 c.qobject = true
152 return true
154 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
155 local base = fullnames[b]
156 if is_qobject(base) then
157 --debug(c.xarg.fullname, "is a QObject")
158 c.qobject = true
159 return true
162 return false
164 for c in pairs(classes) do
165 local qobj = is_qobject(c)
171 local should_wrap = function(f)
172 local name = f.xarg.name
173 -- unfixed operator and friend, causes trouble with QDataStream
174 -- if f.xarg.friend and #f.arguments ==2 then return false end
175 -- not an operator - accept
176 if not name:match('^operator') then return true end
177 -- accept supported operators
178 if operators.is_operator(name) then return true end
179 return false
184 function distinguish_methods()
185 for c in pairs(classes) do
186 local construct, destruct, normal = {}, nil, {}
187 local n = c.xarg.name:gsub('%b<>', '')
189 local copy = nil
190 for _, f in ipairs(c) do
191 if n==f.xarg.name then
192 table.insert(construct, f)
193 elseif f.xarg.name:match'~' then
194 destruct = f
195 else
196 if should_wrap(f)
197 and (not f.xarg.member_template_parameters) then
198 table.insert(normal, f)
199 else
200 ignore(f.xarg.fullname, 'operator/template/friend', c.xarg.name)
204 c.constructors = construct
205 c.destructor = destruct
206 c.methods = normal
210 --- Determines, if a class has a public destructor. It also scans the superclasses.
211 -- Sets the 'public_destr' fiield on the class.
212 function fill_public_destr()
213 local function destr_is_public(c)
214 if c.destructor then
215 return c.destructor.xarg.access=='public'
216 else
217 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
218 local base = fullnames[b]
219 if base and not destr_is_public(base) then
220 return false
223 return true
226 for c in pairs(classes) do
227 c.public_destr = destr_is_public(c)
232 function generate_default_copy_constructor(c)
233 if not c.xarg then return end
235 local copy = {
236 [1] = {
237 label = "Argument";
238 xarg = {
239 context = c.xarg.name;
240 id = next_id();
241 name = "p";
242 scope = "";
243 type_base = c.xarg.name;
244 type_constant = "1";
245 type_name = c.xarg.name .. " const&";
246 type_reference = "1";
249 label = "Function";
250 return_type = c.xarg.name;
251 xarg = {
252 access = "public";
253 context = c.xarg.name;
254 fullname = c.xarg.name.."::"..c.xarg.name;
255 id = next_id();
256 inline = "1";
257 member_of = c.xarg.name;
258 member_of_class = c.xarg.name;
259 name = c.xarg.name;
260 scope = c.xarg.name;
261 type_base = c.xarg.name;
262 type_name = c.xarg.name;
265 copy.arguments = {copy[1]}
267 table.insert(c, copy)
268 table.insert(c.constructors, copy)
269 functions[copy] = true
271 return copy
274 -- HACK: do not create copy contructors for classes, that
275 -- contain variables of class '*Private' - they will not compile
276 -- in Qt 4.6
277 local function has_private_fields(c)
278 for _,v in ipairs(c) do
279 if v.label == 'Variable' then
280 if v.xarg.type_base:match('Private') then
281 ignore(c.xarg.fullname, 'cannot create copy constructor', v.xarg.fullname .. ' : ' ..v.xarg.type_base)
282 return true
286 return false
289 function fill_copy_constructor()
290 for c in pairs(classes) do
291 local copy = nil
292 for _, f in ipairs(c.constructors) do
293 if #(f.arguments)==1
294 and f.arguments[1].xarg.type_name==c.xarg.fullname..' const&' then
295 copy = f
296 break
299 c.copy_constructor = copy
301 local function copy_constr_is_public(c)
302 if c.copy_constructor then
303 return (c.copy_constructor.xarg.access=='public')
304 or (c.copy_constructor.xarg.access=='protected')
305 else
306 if has_private_fields(c) then return false end
307 local ret = nil
308 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
309 local base = fullnames[b]
310 if base and not copy_constr_is_public(base) then
311 return false
314 return true
317 for c in pairs(classes) do
318 c.public_constr = copy_constr_is_public(c)
319 if c.public_constr and not c.copy_constructor then
320 c.copy_constructor = generate_default_copy_constructor(c)
325 function fill_implicit_constructor()
326 typesystem.can_convert = {}
327 for c in pairs(classes) do
328 for _,f in ipairs(c) do
329 if f.label:match("^Function") then
330 -- find non-explicit constructor, which has 1 argument of type different
331 -- from class, i.e. an implicit conversion constructor
332 if f.xarg.name == c.xarg.name
333 and #f == 1
334 and (not f.xarg.access or f.xarg.access == "public")
335 and f[1].xarg.type_base ~= c.xarg.name
336 and not f[1].xarg.type_base:match('Private$')
337 and not f.xarg.explicit
338 and not c.abstract
339 then
340 local class_name = c.xarg.cname
341 local from_type = f[1].xarg.type_base
342 typesystem.can_convert[class_name] = typesystem.can_convert[class_name] or { from = {}, class = c }
343 typesystem.can_convert[class_name].from[ from_type ] = f
344 local safe_from = from_type:gsub('[<>*]', '_'):gsub('::', '_LQT_')
351 local function generate_implicit_code(class_name, t)
352 local c = t.class
353 local fullname = c.xarg.fullname
354 local luaname = fullname:gsub('::', '.')
356 local test_header = 'bool lqt_canconvert_' .. class_name .. '(lua_State *L, int n)'
357 local convert_header = 'void* lqt_convert_' .. class_name .. '(lua_State *L, int n)'
359 local test_code = ""
360 local convert_code = ""
361 local tests = {}
363 for _, f in pairs(t.from) do
364 local typ = f[1].xarg.type_name
365 if not typesystem[typ] then
366 ignore(typ, "implicit constructor - unknown type", _)
367 else
368 local test = typesystem[typ].test('n')
369 if not tests[test] then
370 tests[test] = true
371 test_code = test_code..' if ('..test..')\n'
372 test_code = test_code..' return true;\n'
374 local newtype = fullname .. '(arg)'
375 if c.shell then newtype = 'lqt_shell_'..c.xarg.cname..'(L,arg)' end
376 convert_code = convert_code
377 ..' if ('..test..') {\n'
378 ..' '..typ..' arg = '..typesystem[typ].get('n')..';\n'
379 ..' '..fullname..' *ret = new '..newtype..';\n'
380 ..' lqtL_passudata(L, ret, "'..luaname..'*");\n'
381 ..' return ret;\n }\n'
385 test_code = test_code .. ' return false;'
386 convert_code = convert_code..' return NULL;'
388 c.implicit = {
389 headers = { test = test_header, convert = convert_header },
390 test = test_header .. '{\n' .. test_code .. '\n}',
391 convert = convert_header .. '{\n' .. convert_code .. '\n}'
396 function fill_implicit_wrappers()
397 for class_name, t in pairs(typesystem.can_convert) do
398 if not t.class.abstract then
399 generate_implicit_code(class_name, t)
405 local put_class_in_filesystem = lqt.classes.insert
407 function fill_typesystem_with_classes()
408 for c in pairs(classes) do
409 classes[c] = put_class_in_filesystem(c.xarg.fullname)
414 function fill_wrapper_code(f)
415 if f.wrapper_code then return f end
416 local stackn, argn = 1, 1
417 local stack_args, defects = '', 0
418 local has_args = true
419 local wrap, line = ' int oldtop = lua_gettop(L);\n', ''
420 if f.xarg.abstract then
421 ignore(f.xarg.fullname, 'abstract method', f.xarg.member_of_class)
422 return nil
424 if f.xarg.member_of_class and f.xarg.static~='1' then
425 if not typesystem[f.xarg.member_of_class..'*'] then
426 ignore(f.xarg.fullname, 'not a member of wrapped class', f.xarg.member_of_class)
427 return nil
429 stack_args = stack_args .. typesystem[f.xarg.member_of_class..'*'].onstack
430 defects = defects + 7 -- FIXME: arbitrary
431 if f.xarg.constant=='1' then
432 defects = defects + 8 -- FIXME: arbitrary
434 local sget, sn = typesystem[f.xarg.member_of_class..'*'].get(stackn)
435 wrap = wrap .. ' ' .. f.xarg.member_of_class .. '* self = ' .. sget .. ';\n'
436 stackn = stackn + sn
437 wrap = wrap .. [[
438 if (NULL==self) {
439 lua_pushfstring(L, "Instance of %s has already been deleted in:\n", "]]..f.xarg.member_of_class..[[");
440 lqtL_pushtrace(L);
441 lua_concat(L, 2);
442 lua_error(L);
445 --print(sget, sn)
446 if operators.is_operator(f.xarg.name) then
447 line, has_args = operators.call_line(f)
448 if not line then return nil end
449 else
450 line = 'self->'..f.xarg.fullname..'('
452 else
453 line = f.xarg.fullname..'('
455 for i, a in ipairs(f.arguments) do
456 if not typesystem[a.xarg.type_name] then
457 ignore(f.xarg.fullname, 'unkown argument type', a.xarg.type_name)
458 return nil
460 local aget, an, arg_as = typesystem[a.xarg.type_name].get(stackn)
461 stack_args = stack_args .. typesystem[a.xarg.type_name].onstack
462 if typesystem[a.xarg.type_name].defect then defects = defects + typesystem[a.xarg.type_name].defect end
463 wrap = wrap .. ' ' .. argument_name(arg_as or a.xarg.type_name, 'arg'..argn) .. ' = '
464 if a.xarg.default=='1' and an>0 then
465 wrap = wrap .. 'lua_isnoneornil(L, '..stackn..')'
466 for j = stackn+1,stackn+an-1 do
467 wrap = wrap .. ' && lua_isnoneornil(L, '..j..')'
469 local dv = a.xarg.defaultvalue
470 wrap = wrap .. ' ? static_cast< ' .. a.xarg.type_name .. ' >(' .. dv .. ') : '
472 wrap = wrap .. aget .. ';\n'
473 line = line .. (argn==1 and 'arg' or ', arg') .. argn
474 stackn = stackn + an
475 argn = argn + 1
477 if has_args then
478 line = line .. ')'
480 -- FIXME: hack follows for constructors
481 if f.calling_line then line = f.calling_line end
482 if f.return_type then line = f.return_type .. ' ret = ' .. line end
483 wrap = wrap .. ' ' .. line .. ';\n lua_settop(L, oldtop);\n' -- lua_pop(L, '..stackn..');\n'
484 if f.return_type then
485 if not typesystem[f.return_type] then
486 ignore(f.xarg.fullname, 'unknown return type', f.return_type)
487 return nil
489 local rput, rn = typesystem[f.return_type].push'ret'
490 wrap = wrap .. ' luaL_checkstack(L, '..rn..', "cannot grow stack for return value");\n'
491 wrap = wrap .. ' '..rput..';\n return '..rn..';\n'
492 else
493 wrap = wrap .. ' return 0;\n'
495 f.wrapper_code = wrap
496 f.stack_arguments = stack_args
497 f.defects = defects
498 return f
502 function fill_test_code(f)
503 local stackn = 1
504 local test = ''
505 if f.xarg.member_of_class and f.xarg.static~='1' then
506 if not typesystem[f.xarg.member_of_class..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
507 local stest, sn = typesystem[f.xarg.member_of_class..'*'].test(stackn)
508 test = test .. ' && ' .. stest
509 stackn = stackn + sn
511 for i, a in ipairs(f.arguments) do
512 if not typesystem[a.xarg.type_name] then return nil end -- print(a.xarg.type_name) return nil end
513 local atest, an = typesystem[a.xarg.type_name].test(stackn)
514 if a.xarg.default=='1' and an>0 then
515 test = test .. ' && (lqtL_missarg(L, ' .. stackn .. ', ' .. an .. ') || '
516 test = test .. atest .. ')'
517 else
518 test = test .. ' && ' .. atest
520 stackn = stackn + an
522 -- can't make use of default values if I fix number of args
523 test = '(lua_gettop(L)<' .. stackn .. ')' .. test
524 f.test_code = test
525 return f
530 function fill_wrappers()
531 for f in pairs(functions) do
532 local nf = fill_wrapper_code(f)
533 if nf then
534 nf = assert(fill_test_code(nf), nf.xarg.fullname) -- MUST pass
535 else
536 -- failed to generate wrapper
537 functions[f] = nil
542 ---- Output functions
544 function print_wrappers()
545 for c in pairs(classes) do
546 local meta = {}
547 local wrappers = ''
548 for _, f in ipairs(c.methods) do
549 -- FIXME: should we really discard virtual functions?
550 -- if the virtual overload in the shell uses rawget
551 -- on the environment then we can leave these in the
552 -- metatable
553 if f.wrapper_code and not f.ignore then
554 local out = 'static int lqt_bind'..f.xarg.id
555 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
556 if f.xarg.access=='public' then
557 --print_meta(out)
558 wrappers = wrappers .. out .. '\n'
559 meta[f] = f.xarg.name
563 if not c.abstract then
564 for _, f in ipairs(c.constructors) do
565 if f.wrapper_code then
566 local out = 'static int lqt_bind'..f.xarg.id
567 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
568 if f.xarg.access=='public' then
569 --print_meta(out)
570 wrappers = wrappers .. out .. '\n'
571 meta[f] = 'new'
576 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
577 local lua_name = string.gsub(c.xarg.fullname, '::', '.')
578 local out = 'static int lqt_delete'..c.xarg.id..' (lua_State *L) {\n'
579 out = out ..' '..c.xarg.fullname..' *p = static_cast<'
580 ..c.xarg.fullname..'*>(lqtL_toudata(L, 1, "'..lua_name..'*"));\n'
581 if c.public_destr then
582 out = out .. ' if (p) delete p;\n'
584 out = out .. ' lqtL_eraseudata(L, 1, "'..lua_name..'*");\n return 0;\n}\n'
585 --print_meta(out)
586 wrappers = wrappers .. out .. '\n'
587 c.meta = meta
588 c.wrappers = wrappers
593 local print_metatable = function(c)
594 local methods = {}
595 local wrappers = c.wrappers
596 for m, n in pairs(c.meta) do
597 methods[n] = methods[n] or {}
598 table.insert(methods[n], m)
600 for n, l in pairs(methods) do
601 local duplicates = {}
602 for _, f in ipairs(l) do
603 if not f.ignore then
604 local itisnew = true
605 for sa, g in pairs(duplicates) do
606 if sa==f.stack_arguments then
607 --debug("function equal: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
608 if f.defects<g.defects then
609 else
610 ignore(f.xarg.fullname, "duplicate function", f.stack_arguments)
611 itisnew = false
613 elseif string.match(sa, "^"..f.stack_arguments) then -- there is already a version with more arguments
614 --debug("function superseded: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
615 elseif string.match(f.stack_arguments, '^'..sa) then -- there is already a version with less arguments
616 --debug("function superseding: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
619 if itisnew then
620 duplicates[f.stack_arguments] = f
624 --[[
625 local numinitial = 0
626 local numfinal = 0
627 for sa, f in pairs(l) do
628 numinitial = numinitial + 1
630 for sa, f in pairs(duplicates) do
631 numfinal = numfinal + 1
633 if numinitial-numfinal>0 then debug(c.xarg.fullname, "suppressed:", numinitial-numfinal) end
634 --]]
635 methods[n] = duplicates
637 for n, l in pairs(methods) do
638 local name = operators.rename_operator(n)
639 local disp = 'static int lqt_dispatcher_'..name..c.xarg.id..' (lua_State *L) {\n'
640 local testcode = {}
641 for tc, f in pairs(l) do
642 disp = disp..' if ('..f.test_code..') return lqt_bind'..f.xarg.id..'(L);\n'
643 testcode[#testcode+1] = tc
645 -- disp = disp .. ' lua_settop(L, 0);\n'
646 disp = disp .. ' const char * args = lqtL_getarglist(L);\n'
647 disp = disp .. ' lua_pushfstring(L, "%s(%s): incorrect or extra arguments, expecting: %s.", "' ..
648 c.xarg.fullname..'::'..n..'", args, '..string.format("%q", table.concat(testcode, ' or ')) .. ');\n'
649 disp = disp .. ' return lua_error(L);\n}\n'
650 --print_meta(disp)
651 wrappers = wrappers .. disp .. '\n'
653 local metatable = 'static luaL_Reg lqt_metatable'..c.xarg.id..'[] = {\n'
654 for n, l in pairs(methods) do
655 local nn = operators.rename_operator(n)
656 metatable = metatable .. ' { "'..nn..'", lqt_dispatcher_'..nn..c.xarg.id..' },\n'
658 metatable = metatable .. ' { "delete", lqt_delete'..c.xarg.id..' },\n'
659 metatable = metatable .. ' { 0, 0 },\n};\n'
660 --print_meta(metatable)
661 wrappers = wrappers .. metatable .. '\n'
662 local bases = ''
663 for b in string.gmatch(c.xarg.bases_with_attributes or '', '([^;]*);') do
664 if not string.match(b, '^virtual') then
665 b = string.gsub(b, '^[^%s]* ', '')
666 bases = bases .. ' {"'..string.gsub(b,'::','.')..'*", (char*)(void*)static_cast<'..b..'*>(('..c.xarg.fullname..'*)1)-(char*)1},\n'
669 bases = 'static lqt_Base lqt_base'..c.xarg.id..'[] = {\n'..bases..' {NULL, 0}\n};\n'
670 --print_meta(bases)
671 wrappers = wrappers .. bases .. '\n'
672 c.wrappers = wrappers
673 return c
677 function print_metatables()
678 for c in pairs(classes) do
679 print_metatable(c)
684 function print_single_class(c)
685 local n = c.xarg.cname
686 local lua_name = string.gsub(c.xarg.fullname, '::', '.')
687 local cppname = module_name..'_meta_'..n..'.cpp'
688 table.insert(cpp_files, n) -- global cpp_files
689 local fmeta = assert(io.open(module_name.._src..cppname, 'w'))
690 local print_meta = function(...)
691 fmeta:write(...)
692 fmeta:write'\n'
694 print_meta('#include "'..module_name..'_head_'..n..'.hpp'..'"\n\n')
696 if c.implicit then
697 print_meta(c.implicit.test)
698 print_meta(c.implicit.convert)
701 print_meta(c.wrappers)
702 if c.virtual_overloads then
703 print_meta(c.virtual_overloads)
705 print_meta('extern "C" LQT_EXPORT int luaopen_'..n..' (lua_State *L) {')
706 print_meta('\tlqtL_createclass(L, "'
707 ..lua_name..'*", lqt_metatable'
708 ..c.xarg.id..', lqt_base'
709 ..c.xarg.id..');')
711 if c.implicit then
712 print_meta('\tluaL_getmetatable(L, "'..lua_name..'*");')
713 print_meta('\tlua_pushliteral(L, "__test");')
714 print_meta('\tlua_pushlightuserdata(L, (void*)&lqt_canconvert_'..c.xarg.cname..');')
715 print_meta('\tlua_rawset(L, -3);')
716 print_meta('\tlua_pushliteral(L, "__convert");')
717 print_meta('\tlua_pushlightuserdata(L, (void*)&lqt_convert_'..c.xarg.cname..');')
718 print_meta('\tlua_rawset(L, -3);')
719 print_meta('\tlua_pop(L, 1);')
722 print_meta'\treturn 0;'
723 print_meta'}'
724 print_meta''
725 if c.shell and c.qobject then
726 print_meta([[
727 #include <QDebug>
729 QMetaObject lqt_shell_]]..n..[[::staticMetaObject;
731 const QMetaObject *lqt_shell_]]..n..[[::metaObject() const {
732 //int oldtop = lua_gettop(L);
733 lqtL_pushudata(L, this, "]]..c.xarg.fullname..[[*");
734 lua_getfield(L, -1, LQT_OBJMETASTRING);
735 if (lua_isnil(L, -1)) {
736 lua_pop(L, 2);
737 return &]]..c.xarg.fullname..[[::staticMetaObject;
739 lua_getfield(L, -2, LQT_OBJMETADATA);
740 lqtL_touintarray(L);
741 //qDebug() << "copying qmeta object for slots in ]]..c.xarg.fullname..[[";
742 lqt_shell_]]..n..[[::staticMetaObject.d.superdata = &]]..c.xarg.fullname..[[::staticMetaObject;
743 lqt_shell_]]..n..[[::staticMetaObject.d.stringdata = lua_tostring(L, -2);
744 lqt_shell_]]..n..[[::staticMetaObject.d.data = (uint*)lua_touserdata(L, -1);
745 lqt_shell_]]..n..[[::staticMetaObject.d.extradata = 0; // slot_metaobj->d.extradata;
746 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETADATA);
747 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETASTRING);
748 lua_pop(L, 1);
749 //qDebug() << (lua_gettop(L) - oldtop);
750 return &lqt_shell_]]..n..[[::staticMetaObject;
753 int lqt_shell_]]..n..[[::qt_metacall(QMetaObject::Call call, int index, void **args) {
754 //qDebug() << "fake calling!";
755 index = ]]..c.xarg.fullname..[[::qt_metacall(call, index, args);
756 if (index < 0) return index;
757 return lqtL_qt_metacall(L, this, lqtSlotAcceptor_]]..module_name..[[, call, "]]..c.xarg.fullname..[[*", index, args);
761 fmeta:close()
764 function print_merged_build()
765 local path = module_name.._src
766 local mergename = module_name..'_merged_build'
767 local merged = assert(io.open(path..mergename..'.cpp', 'w'))
768 for _, p in ipairs(cpp_files) do
769 merged:write('#include "',module_name,'_head_',p,'.hpp"\n')
771 merged:write('\n')
772 for _, p in ipairs(cpp_files) do
773 merged:write('#include "',module_name,'_meta_',p,'.cpp"\n')
775 local pro_file = assert(io.open(path..mergename..'.pro', 'w'))
777 local print_pro= function(...)
778 pro_file:write(...)
779 pro_file:write'\n'
781 print_pro('TEMPLATE = lib')
782 print_pro('TARGET = '..module_name)
783 print_pro('INCLUDEPATH += .')
784 print_pro('HEADERS += '..module_name..'_slot.hpp')
785 print_pro('SOURCES += ../common/lqt_common.cpp \\')
786 print_pro(' ../common/lqt_qt.cpp \\')
787 print_pro(' '..module_name..'_enum.cpp \\')
788 print_pro(' '..module_name..'_meta.cpp \\')
789 print_pro(' '..module_name..'_slot.cpp \\')
790 print_pro(' '..mergename..'.cpp')
794 function print_class_list()
795 local qobject_present = false
796 local big_picture = {}
797 local type_list_t = {}
798 for c in pairs(classes) do
799 local n = c.xarg.cname
800 if n=='QObject' then qobject_present = true end
801 print_single_class(c)
802 table.insert(big_picture, n)
803 table.insert(type_list_t, 'add_class \''..c.xarg.fullname..'\'\n')
806 local type_list_f = assert(io.open(module_name.._src..module_name..'_types.lua', 'w'))
807 type_list_f:write([[
808 #!/usr/bin/lua
809 local types = (...) or {}
810 assert(lqt.classes.insert, 'module lqt.classes not loaded')
811 local function add_class(class)
812 lqt.classes.insert(class, true)
815 for k, v in ipairs(type_list_t) do
816 type_list_f:write(v)
818 type_list_f:write('return types\n')
819 type_list_f:close()
821 print_merged_build()
822 local fmeta = assert(io.open(module_name.._src..module_name..'_meta.cpp', 'w'))
823 local print_meta = function(...)
824 fmeta:write(...)
825 fmeta:write'\n'
827 print_meta()
828 print_meta('#include "lqt_common.hpp"')
829 print_meta('#include "'..module_name..'_slot.hpp'..'"\n\n')
830 for _, p in ipairs(big_picture) do
831 print_meta('extern "C" LQT_EXPORT int luaopen_'..p..' (lua_State *);')
833 print_meta('void lqt_create_enums_'..module_name..' (lua_State *);')
834 print_meta('extern "C" LQT_EXPORT int luaopen_'..module_name..' (lua_State *L) {')
835 for _, p in ipairs(big_picture) do
836 print_meta('\tluaopen_'..p..'(L);')
838 print_meta('\tlqt_create_enums_'..module_name..'(L);')
839 if qobject_present then
840 print_meta('\tlqtL_qobject_custom(L);')
842 print_meta('\t//lua_pushlightuserdata(L, (void*)&LqtSlotAcceptor::staticMetaObject);')
843 print_meta('\t//lua_setfield(L, LUA_REGISTRYINDEX, LQT_METAOBJECT);')
844 print_meta('\t//lqtL_passudata(L, (void*)(new LqtSlotAcceptor(L)), "QObject*");')
845 print_meta('\t//lua_setfield(L, LUA_REGISTRYINDEX, LQT_METACALLER);')
846 print_meta('\tlqtL_register_super(L);')
847 print_meta('\tlqtSlotAcceptor_'..module_name..' = new LqtSlotAcceptor(L);')
848 print_meta('\treturn 0;\n}')
849 if fmeta then fmeta:close() end
852 ------------------------------------------------------------
854 function preprocess(index)
855 copy_classes(index) -- picks classes if not private and not blacklisted
856 copy_functions(index) -- picks functions and fixes label
857 fix_arguments(index) -- fixes default arguments if they are context-relative
858 fix_functions() -- fixes name and fullname and fills arguments
859 operators.fix_operators(index)
862 function process(index, typesystem, filterfiles)
863 for _, f in ipairs(filterfiles) do
864 classes = loadfile(f)(classes)
867 virtuals.fill_virtuals(classes) -- does that, destructor ("~") excluded
868 distinguish_methods() -- does that
869 fill_public_destr() -- does that: checks if destructor is public
870 fill_copy_constructor() -- does that: checks if copy contructor is public or protected
871 fill_implicit_constructor()
872 fix_methods_wrappers()
873 get_qobjects()
875 fill_typesystem_with_classes()
876 fill_wrappers()
877 virtuals.fill_virtual_overloads(classes) -- does that
878 virtuals.fill_shell_classes(classes) -- does that
879 fill_implicit_wrappers()
881 signalslot.process(functions)
884 function output()
885 virtuals.print_shell_classes(classes) -- does that, and outputs headers
886 virtuals.print_virtual_overloads(classes) -- does that
888 print_wrappers(classes) -- just compiles metatable list
889 print_metatables(classes) -- just collects the wrappers + generates dispatchers
890 print_class_list(classes) -- does that + prints everything related to class
892 signalslot.output()