better error message when illegal arguments are provided
[lqt/mk.git] / generator / classes.lua
blob1ffc547f4372786098bc4ae91bb571b110283b6d
1 require 'virtuals'
2 require 'templates'
3 require 'operators'
4 require 'signalslot'
6 module('classes', package.seeall)
8 local functions = {}
9 local classes = {}
10 local cpp_files = {}
12 --- Copies functions from the index.
13 function copy_functions(index)
14 for e in pairs(index) do
15 if e.label:match'^Function' then
16 e.label = 'Function'
17 functions[e] = true
18 end
19 end
20 end
23 function fix_arguments(index)
24 for a in pairs(index) do
25 if a.label=='Argument'
26 and a.xarg.default=='1'
27 and (not string.match(a.xarg.defaultvalue, '^[-+]?%d+%.?%d*[L]?$'))
28 and (not string.match(a.xarg.defaultvalue, '^".*"$'))
29 and a.xarg.defaultvalue~='true'
30 and a.xarg.defaultvalue~='false'
31 and (not string.match(a.xarg.defaultvalue, '^0[xX]%d+$')) then
32 local dv, call = string.match(a.xarg.defaultvalue, '(.-)(%(%))')
33 dv = dv or a.xarg.defaultvalue
34 call = call or ''
35 local context = a.xarg.context
36 while not fullnames[context..'::'..dv] and context~='' do
37 context = string.match(context, '^(.*)::') or ''
38 end
39 if fullnames[context..'::'..dv] then
40 a.xarg.defaultvalue = context..'::'..dv..call
41 elseif fullnames[dv] then
42 a.xarg.defaultvalue = dv..call
43 else
44 a.xarg.default = nil
45 a.xarg.defaultvalue = nil
46 end
47 end
48 end
49 end
52 --- Removes unneeded 'void' parameters and return values.
53 function fix_functions()
54 for f in pairs(functions) do
55 local args = {}
56 for i, a in ipairs(f) do
57 -- avoid bogus 'void' arguments
58 if a.xarg.type_name=='void' and i==1 and f[2]==nil then break end
59 if a.label=='Argument' then
60 table.insert(args, a)
61 end
62 end
63 f.arguments = args
64 f.return_type = f.xarg.type_name
65 if f.xarg.type_name=='void' then
66 f.return_type = nil
67 end
68 end
69 end
71 --- Determines, if a class is public.
72 function class_is_public(c)
73 repeat
74 if c.xarg.access~='public' then return false end
75 if c.xarg.member_of_class then
76 local p = fullnames[c.xarg.member_of_class]
77 assert(p, 'member_of_class should exist')
78 assert(p.label=='Class', 'member_of_class should be a class')
79 c = fullnames[c.xarg.member_of_class]
80 else
81 return true
82 end
83 until true
84 end
86 --- Selects public classes from the index, and creates templated instances
87 -- where appropriate.
88 function copy_classes(index)
89 for e in pairs(index) do
90 if e.label=='Class' then
91 e.xarg.safename = e.xarg.fullname
92 if class_is_public(e)
93 and not e.xarg.fullname:match'%b<>' then
94 classes[e] = true
95 elseif not e.xarg.fullname:match'%b<>' then
96 ignore(e.xarg.fullname, 'not public')
97 else
98 if templates.should_copy(e) then
99 templates.create(e, classes)
104 templates.finish(index)
107 function fix_methods_wrappers()
108 for c in pairs(classes) do
109 c.shell = c.public_destr
110 c.shell = c.shell and (next(c.virtuals)~=nil)
111 for _, constr in ipairs(c.constructors) do
112 if c.shell then
113 local shellname = 'lqt_shell_'..string.gsub(c.xarg.safename, '::', '_LQT_')
114 constr.calling_line = 'new '..shellname..'(L'
115 if #(constr.arguments)>0 then constr.calling_line = constr.calling_line .. ', ' end
116 else
117 local shellname = c.xarg.fullname
118 constr.calling_line = 'new '..shellname..'('
120 for i=1,#(constr.arguments) do
121 constr.calling_line = constr.calling_line .. (i==1 and '' or ', ') .. 'arg' .. i
123 constr.calling_line = '*('..constr.calling_line .. '))'
124 constr.xarg.static = '1'
125 constr.return_type = constr.xarg.scope..'&'
127 if c.destructor then
128 c.destructor.return_type = nil
133 --- Determines, whether classes are children of QObject.
134 -- Fills the 'qobject' field on class if it is child of QObject.
135 function get_qobjects()
136 local function is_qobject(c)
137 if c==nil then return false end
138 if c.qobject then return true end
139 if c.xarg.fullname=='QObject' then
140 c.qobject = true
141 return true
143 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
144 local base = fullnames[b]
145 if is_qobject(base) then
146 --debug(c.xarg.fullname, "is a QObject")
147 c.qobject = true
148 return true
151 return false
153 for c in pairs(classes) do
154 local qobj = is_qobject(c)
160 local should_wrap = function(f)
161 local name = f.xarg.name
162 -- unfixed operator and friend, causes trouble with QDataStream
163 if f.xarg.friend and #f.arguments ==2 then return false end
164 -- not an operator - accept
165 if not name:match('^operator') then return true end
166 -- accept supported operators
167 if operators.is_operator(name)then return true end
168 return false
173 function distinguish_methods()
174 for c in pairs(classes) do
175 local construct, destruct, normal = {}, nil, {}
176 local n = c.xarg.name:gsub('%b<>', '')
178 local copy = nil
179 for _, f in ipairs(c) do
180 if n==f.xarg.name then
181 table.insert(construct, f)
182 elseif f.xarg.name:match'~' then
183 destruct = f
184 else
185 if should_wrap(f)
186 and (not f.xarg.member_template_parameters) then
187 table.insert(normal, f)
188 else
189 ignore(f.xarg.fullname, 'operator/template/friend', c.xarg.name)
193 c.constructors = construct
194 c.destructor = destruct
195 c.methods = normal
199 --- Determines, if a class has a public destructor. It also scans the superclasses.
200 -- Sets the 'public_destr' fiield on the class.
201 function fill_public_destr()
202 local function destr_is_public(c)
203 if c.destructor then
204 return c.destructor.xarg.access=='public'
205 else
206 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
207 local base = fullnames[b]
208 if base and not destr_is_public(base) then
209 return false
212 return true
215 for c in pairs(classes) do
216 c.public_destr = destr_is_public(c)
221 function generate_default_copy_constructor(c)
222 if not c.xarg then return end
224 local copy = {
225 [1] = {
226 label = "Argument";
227 xarg = {
228 context = c.xarg.name;
229 id = next_id();
230 name = "p";
231 scope = "";
232 type_base = c.xarg.name;
233 type_constant = "1";
234 type_name = c.xarg.name .. " const&";
235 type_reference = "1";
238 label = "Function";
239 return_type = c.xarg.name;
240 xarg = {
241 access = "public";
242 context = c.xarg.name;
243 fullname = c.xarg.name.."::"..c.xarg.name;
244 id = next_id();
245 inline = "1";
246 member_of = c.xarg.name;
247 member_of_class = c.xarg.name;
248 name = c.xarg.name;
249 scope = c.xarg.name;
250 type_base = c.xarg.name;
251 type_name = c.xarg.name;
254 copy.arguments = {copy[1]}
256 table.insert(c, copy)
257 table.insert(c.constructors, copy)
258 functions[copy] = true
260 return copy
263 -- HACK: do not create copy contructors for classes, that
264 -- contain variables of class '*Private' - they will not compile
265 -- in Qt 4.6
266 local function has_private_fields(c)
267 for _,v in ipairs(c) do
268 if v.label == 'Variable' then
269 if v.xarg.type_base:match('Private') then
270 ignore(c.xarg.fullname, 'cannot create copy constructor', v.xarg.fullname .. ' : ' ..v.xarg.type_base)
271 return true
275 return false
278 function fill_copy_constructor()
279 for c in pairs(classes) do
280 local copy = nil
281 for _, f in ipairs(c.constructors) do
282 if #(f.arguments)==1
283 and f.arguments[1].xarg.type_name==c.xarg.fullname..' const&' then
284 copy = f
285 break
288 c.copy_constructor = copy
290 local function copy_constr_is_public(c)
291 if c.copy_constructor then
292 return (c.copy_constructor.xarg.access=='public')
293 or (c.copy_constructor.xarg.access=='protected')
294 else
295 if has_private_fields(c) then return false end
296 local ret = nil
297 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
298 local base = fullnames[b]
299 if base and not copy_constr_is_public(base) then
300 return false
303 return true
306 for c in pairs(classes) do
307 c.public_constr = copy_constr_is_public(c)
308 if c.public_constr and not c.copy_constructor then
309 c.copy_constructor = generate_default_copy_constructor(c)
315 local put_class_in_filesystem = lqt.classes.insert
317 function fill_typesystem_with_classes(types)
318 for c in pairs(classes) do
319 classes[c] = put_class_in_filesystem(c.xarg.fullname, types) --, true)
324 function fill_wrapper_code(f, types)
325 if f.wrapper_code then return f end
326 local stackn, argn = 1, 1
327 local stack_args, defects = '', 0
328 local wrap, line = ' int oldtop = lua_gettop(L);\n', ''
329 if f.xarg.abstract then
330 ignore(f.xarg.fullname, 'abstract method', f.xarg.member_of_class)
331 return nil
333 if f.xarg.member_of_class and f.xarg.static~='1' then
334 if not types[f.xarg.member_of_class..'*'] then
335 ignore(f.xarg.fullname, 'not a member of wrapped class', f.xarg.member_of_class)
336 return nil
338 stack_args = stack_args .. types[f.xarg.member_of_class..'*'].onstack
339 defects = defects + 7 -- FIXME: arbitrary
340 if f.xarg.constant=='1' then
341 defects = defects + 8 -- FIXME: arbitrary
343 local sget, sn = types[f.xarg.member_of_class..'*'].get(stackn)
344 wrap = wrap .. ' ' .. f.xarg.member_of_class .. '* self = ' .. sget .. ';\n'
345 stackn = stackn + sn
346 wrap = wrap .. [[
347 if (NULL==self) {
348 lua_pushfstring(L, "Instance of %s has already been deleted in:\n", "]]..f.xarg.member_of_class..[[");
349 lqtL_pushtrace(L);
350 lua_concat(L, 2);
351 lua_error(L);
354 --print(sget, sn)
355 if operators.is_operator(f.xarg.name) then
356 local op = operators.get_operator(f.xarg.name)
357 if op == "*" and #f.arguments == 0 then
358 ignore(f.xarg.fullname, "pointer dereference operator", f.xarg.member_of_class)
359 return nil
360 elseif op == '++' or op == '--' then
361 -- the ++ and -- operators don't line () at the end, like: *self ++()
362 if f.arguments[1] then
363 line = op..' *self'
364 f.arguments[1] = nil
365 else
366 line = '*self '..op
368 else
369 line = '*self '..op..'('
371 else
372 line = 'self->'..f.xarg.fullname..'('
374 else
375 line = f.xarg.fullname..'('
377 for i, a in ipairs(f.arguments) do
378 if not types[a.xarg.type_name] then
379 ignore(f.xarg.fullname, 'unkown argument type', a.xarg.type_name)
380 return nil
382 local aget, an, arg_as = types[a.xarg.type_name].get(stackn)
383 stack_args = stack_args .. types[a.xarg.type_name].onstack
384 if types[a.xarg.type_name].defect then defects = defects + types[a.xarg.type_name].defect end
385 wrap = wrap .. ' ' .. argument_name(arg_as or a.xarg.type_name, 'arg'..argn) .. ' = '
386 if a.xarg.default=='1' and an>0 then
387 wrap = wrap .. 'lua_isnoneornil(L, '..stackn..')'
388 for j = stackn+1,stackn+an-1 do
389 wrap = wrap .. ' && lua_isnoneornil(L, '..j..')'
391 local dv = a.xarg.defaultvalue
392 wrap = wrap .. ' ? static_cast< ' .. a.xarg.type_name .. ' >(' .. dv .. ') : '
394 wrap = wrap .. aget .. ';\n'
395 line = line .. (argn==1 and 'arg' or ', arg') .. argn
396 stackn = stackn + an
397 argn = argn + 1
399 if not f.xarg.name:match('%+%+') and not f.xarg.name:match('%-%-') then
400 line = line .. ')'
402 -- FIXME: hack follows for constructors
403 if f.calling_line then line = f.calling_line end
404 if f.return_type then line = f.return_type .. ' ret = ' .. line end
405 wrap = wrap .. ' ' .. line .. ';\n lua_settop(L, oldtop);\n' -- lua_pop(L, '..stackn..');\n'
406 if f.return_type then
407 if not types[f.return_type] then
408 ignore(f.xarg.fullname, 'unknown return type', f.return_type)
409 return nil
411 local rput, rn = types[f.return_type].push'ret'
412 wrap = wrap .. ' luaL_checkstack(L, '..rn..', "cannot grow stack for return value");\n'
413 wrap = wrap .. ' '..rput..';\n return '..rn..';\n'
414 else
415 wrap = wrap .. ' return 0;\n'
417 f.wrapper_code = wrap
418 f.stack_arguments = stack_args
419 f.defects = defects
420 return f
424 function fill_test_code(f, types)
425 local stackn = 1
426 local test = ''
427 if f.xarg.member_of_class and f.xarg.static~='1' then
428 if not types[f.xarg.member_of_class..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
429 local stest, sn = types[f.xarg.member_of_class..'*'].test(stackn)
430 test = test .. ' && ' .. stest
431 stackn = stackn + sn
433 for i, a in ipairs(f.arguments) do
434 if not types[a.xarg.type_name] then return nil end -- print(a.xarg.type_name) return nil end
435 local atest, an = types[a.xarg.type_name].test(stackn)
436 if a.xarg.default=='1' and an>0 then
437 test = test .. ' && (lqtL_missarg(L, ' .. stackn .. ', ' .. an .. ') || '
438 test = test .. atest .. ')'
439 else
440 test = test .. ' && ' .. atest
442 stackn = stackn + an
444 -- can't make use of default values if I fix number of args
445 test = '(lua_gettop(L)<' .. stackn .. ')' .. test
446 f.test_code = test
447 return f
452 function fill_wrappers(types)
453 for f in pairs(functions) do
454 local nf = fill_wrapper_code(f, types)
455 if nf then
456 nf = assert(fill_test_code(nf, types), nf.xarg.fullname) -- MUST pass
457 else
458 -- failed to generate wrapper
459 functions[f] = nil
464 ---- Output functions
466 function print_wrappers()
467 for c in pairs(classes) do
468 local meta = {}
469 local wrappers = ''
470 for _, f in ipairs(c.methods) do
471 -- FIXME: should we really discard virtual functions?
472 -- if the virtual overload in the shell uses rawget
473 -- on the environment then we can leave these in the
474 -- metatable
475 if f.wrapper_code then
476 local out = 'static int lqt_bind'..f.xarg.id
477 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
478 if f.xarg.access=='public' then
479 --print_meta(out)
480 wrappers = wrappers .. out .. '\n'
481 meta[f] = f.xarg.name
485 if not c.abstract then
486 for _, f in ipairs(c.constructors) do
487 if f.wrapper_code then
488 local out = 'static int lqt_bind'..f.xarg.id
489 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
490 if f.xarg.access=='public' then
491 --print_meta(out)
492 wrappers = wrappers .. out .. '\n'
493 meta[f] = 'new'
498 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
499 local lua_name = string.gsub(c.xarg.fullname, '::', '.')
500 local out = 'static int lqt_delete'..c.xarg.id..' (lua_State *L) {\n'
501 out = out ..' '..c.xarg.fullname..' *p = static_cast<'
502 ..c.xarg.fullname..'*>(lqtL_toudata(L, 1, "'..lua_name..'*"));\n'
503 if c.public_destr then
504 out = out .. ' if (p) delete p;\n'
506 out = out .. ' lqtL_eraseudata(L, 1, "'..lua_name..'*");\n return 0;\n}\n'
507 --print_meta(out)
508 wrappers = wrappers .. out .. '\n'
509 c.meta = meta
510 c.wrappers = wrappers
515 local print_metatable = function(c)
516 local methods = {}
517 local wrappers = c.wrappers
518 for m, n in pairs(c.meta) do
519 methods[n] = methods[n] or {}
520 table.insert(methods[n], m)
522 for n, l in pairs(methods) do
523 local duplicates = {}
524 for _, f in ipairs(l) do
525 local itisnew = true
526 for sa, g in pairs(duplicates) do
527 if sa==f.stack_arguments then
528 --debug("function equal: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
529 if f.defects<g.defects then
530 else
531 ignore(f.xarg.fullname, "duplicate function", f.stack_arguments)
532 itisnew = false
534 elseif string.match(sa, "^"..f.stack_arguments) then -- there is already a version with more arguments
535 --debug("function superseded: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
536 elseif string.match(f.stack_arguments, '^'..sa) then -- there is already a version with less arguments
537 --debug("function superseding: ", f.xarg.fullname, f.stack_arguments, sa, f.defects, g.defects)
540 if itisnew then
541 duplicates[f.stack_arguments] = f
544 --[[
545 local numinitial = 0
546 local numfinal = 0
547 for sa, f in pairs(l) do
548 numinitial = numinitial + 1
550 for sa, f in pairs(duplicates) do
551 numfinal = numfinal + 1
553 if numinitial-numfinal>0 then debug(c.xarg.fullname, "suppressed:", numinitial-numfinal) end
554 --]]
555 methods[n] = duplicates
557 for n, l in pairs(methods) do
558 local name = operators.rename_operator(n)
559 local disp = 'static int lqt_dispatcher_'..name..c.xarg.id..' (lua_State *L) {\n'
560 local testcode = {}
561 for tc, f in pairs(l) do
562 disp = disp..' if ('..f.test_code..') return lqt_bind'..f.xarg.id..'(L);\n'
563 testcode[#testcode+1] = tc
565 -- disp = disp .. ' lua_settop(L, 0);\n'
566 disp = disp .. ' const char * args = lqtL_getarglist(L);\n'
567 disp = disp .. ' lua_pushfstring(L, "%s(%s): incorrect or extra arguments, expecting: %s.", "' ..
568 c.xarg.fullname..'::'..n..'", args, '..string.format("%q", table.concat(testcode, ' or ')) .. ');\n'
569 disp = disp .. ' return lua_error(L);\n}\n'
570 --print_meta(disp)
571 wrappers = wrappers .. disp .. '\n'
573 local metatable = 'static luaL_Reg lqt_metatable'..c.xarg.id..'[] = {\n'
574 for n, l in pairs(methods) do
575 local nn = operators.rename_operator(n)
576 metatable = metatable .. ' { "'..nn..'", lqt_dispatcher_'..nn..c.xarg.id..' },\n'
578 metatable = metatable .. ' { "delete", lqt_delete'..c.xarg.id..' },\n'
579 metatable = metatable .. ' { 0, 0 },\n};\n'
580 --print_meta(metatable)
581 wrappers = wrappers .. metatable .. '\n'
582 local bases = ''
583 for b in string.gmatch(c.xarg.bases_with_attributes or '', '([^;]*);') do
584 if not string.match(b, '^virtual') then
585 b = string.gsub(b, '^[^%s]* ', '')
586 bases = bases .. ' {"'..string.gsub(b,'::','.')..'*", (char*)(void*)static_cast<'..b..'*>(('..c.xarg.fullname..'*)1)-(char*)1},\n'
589 bases = 'static lqt_Base lqt_base'..c.xarg.id..'[] = {\n'..bases..' {NULL, 0}\n};\n'
590 --print_meta(bases)
591 wrappers = wrappers .. bases .. '\n'
592 c.wrappers = wrappers
593 return c
597 function print_metatables()
598 for c in pairs(classes) do
599 print_metatable(c)
604 function print_single_class(c)
605 local n = string.gsub(c.xarg.safename, '::', '_LQT_')
606 local lua_name = string.gsub(c.xarg.fullname, '::', '.')
607 local cppname = module_name..'_meta_'..n..'.cpp'
608 table.insert(cpp_files, cppname) -- global cpp_files
609 local fmeta = assert(io.open(module_name.._src..cppname, 'w'))
610 local print_meta = function(...)
611 fmeta:write(...)
612 fmeta:write'\n'
614 print_meta('#include "'..module_name..'_head_'..n..'.hpp'..'"\n\n')
615 print_meta(c.wrappers)
616 if c.virtual_overloads then
617 print_meta(c.virtual_overloads)
619 print_meta('extern "C" LQT_EXPORT int luaopen_'..n..' (lua_State *L) {')
620 print_meta('\tlqtL_createclass(L, "'
621 ..lua_name..'*", lqt_metatable'
622 ..c.xarg.id..', lqt_base'
623 ..c.xarg.id..');')
624 print_meta'\treturn 0;'
625 print_meta'}'
626 print_meta''
627 if c.shell and c.qobject then
628 print_meta([[
629 #include <QDebug>
631 QMetaObject lqt_shell_]]..n..[[::staticMetaObject;
633 const QMetaObject *lqt_shell_]]..n..[[::metaObject() const {
634 //int oldtop = lua_gettop(L);
635 lqtL_pushudata(L, this, "]]..c.xarg.fullname..[[*");
636 lua_getfield(L, -1, LQT_OBJMETASTRING);
637 if (lua_isnil(L, -1)) {
638 lua_pop(L, 2);
639 return &]]..c.xarg.fullname..[[::staticMetaObject;
641 lua_getfield(L, -2, LQT_OBJMETADATA);
642 lqtL_touintarray(L);
643 //qDebug() << "copying qmeta object for slots in ]]..c.xarg.fullname..[[";
644 lqt_shell_]]..n..[[::staticMetaObject.d.superdata = &]]..c.xarg.fullname..[[::staticMetaObject;
645 lqt_shell_]]..n..[[::staticMetaObject.d.stringdata = lua_tostring(L, -2);
646 lqt_shell_]]..n..[[::staticMetaObject.d.data = (uint*)lua_touserdata(L, -1);
647 lqt_shell_]]..n..[[::staticMetaObject.d.extradata = 0; // slot_metaobj->d.extradata;
648 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETADATA);
649 lua_setfield(L, LUA_REGISTRYINDEX, LQT_OBJMETASTRING);
650 lua_pop(L, 1);
651 //qDebug() << (lua_gettop(L) - oldtop);
652 return &lqt_shell_]]..n..[[::staticMetaObject;
655 int lqt_shell_]]..n..[[::qt_metacall(QMetaObject::Call call, int index, void **args) {
656 //qDebug() << "fake calling!";
657 index = ]]..c.xarg.fullname..[[::qt_metacall(call, index, args);
658 if (index < 0) return index;
659 return lqtL_qt_metacall(L, this, lqtSlotAcceptor_]]..module_name..[[, call, "]]..c.xarg.fullname..[[*", index, args);
663 fmeta:close()
666 function print_merged_build()
667 local path = module_name.._src
668 local mergename = module_name..'_merged_build'
669 local merged = assert(io.open(path..mergename..'.cpp', 'w'))
670 for _, p in ipairs(cpp_files) do
671 merged:write('#include "'..p..'"\n')
673 local pro_file = assert(io.open(path..mergename..'.pro', 'w'))
675 local print_pro= function(...)
676 pro_file:write(...)
677 pro_file:write'\n'
679 print_pro('TEMPLATE = lib')
680 print_pro('TARGET = '..module_name)
681 print_pro('INCLUDEPATH += .')
682 print_pro('HEADERS += '..module_name..'_slot.hpp')
683 print_pro('SOURCES += ../common/lqt_common.cpp \\')
684 print_pro(' ../common/lqt_qt.cpp \\')
685 print_pro(' '..module_name..'_enum.cpp \\')
686 print_pro(' '..module_name..'_meta.cpp \\')
687 print_pro(' '..module_name..'_slot.cpp \\')
688 print_pro(' '..mergename..'.cpp')
692 function print_class_list()
693 local qobject_present = false
694 local big_picture = {}
695 local type_list_t = {}
696 for c in pairs(classes) do
697 local n = string.gsub(c.xarg.safename, '::', '_LQT_')
698 if n=='QObject' then qobject_present = true end
699 print_single_class(c)
700 table.insert(big_picture, 'luaopen_'..n)
701 table.insert(type_list_t, 'add_class(\''..c.xarg.fullname..'\', types)\n')
704 local type_list_f = assert(io.open(module_name.._src..module_name..'_types.lua', 'w'))
705 type_list_f:write([[
706 #!/usr/bin/lua
707 local types = (...) or {}
708 local add_class = lqt.classes.insert or error('module lqt.classes not loaded')
710 for k, v in ipairs(type_list_t) do
711 type_list_f:write(v)
713 type_list_f:write('return types\n')
714 type_list_f:close()
716 print_merged_build()
717 local fmeta = assert(io.open(module_name.._src..module_name..'_meta.cpp', 'w'))
718 local print_meta = function(...)
719 fmeta:write(...)
720 fmeta:write'\n'
722 print_meta()
723 print_meta('#include "lqt_common.hpp"')
724 print_meta('#include "'..module_name..'_slot.hpp'..'"\n\n')
725 for _, p in ipairs(big_picture) do
726 print_meta('extern "C" LQT_EXPORT int '..p..' (lua_State *);')
728 print_meta('void lqt_create_enums_'..module_name..' (lua_State *);')
729 print_meta('extern "C" LQT_EXPORT int luaopen_'..module_name..' (lua_State *L) {')
730 for _, p in ipairs(big_picture) do
731 print_meta('\t'..p..'(L);')
733 print_meta('\tlqt_create_enums_'..module_name..'(L);')
734 if qobject_present then
735 print_meta('\tlqtL_qobject_custom(L);')
737 print_meta('\t//lua_pushlightuserdata(L, (void*)&LqtSlotAcceptor::staticMetaObject);')
738 print_meta('\t//lua_setfield(L, LUA_REGISTRYINDEX, LQT_METAOBJECT);')
739 print_meta('\t//lqtL_passudata(L, (void*)(new LqtSlotAcceptor(L)), "QObject*");')
740 print_meta('\t//lua_setfield(L, LUA_REGISTRYINDEX, LQT_METACALLER);')
741 print_meta('\tlqtL_register_super(L);')
742 print_meta('\tlqtSlotAcceptor_'..module_name..' = new LqtSlotAcceptor(L);')
743 print_meta('\treturn 0;\n}')
744 if fmeta then fmeta:close() end
747 ------------------------------------------------------------
749 function preprocess(index)
750 copy_classes(index) -- picks classes if not private and not blacklisted
751 copy_functions(index) -- picks functions and fixes label
752 fix_arguments(index) -- fixes default arguments if they are context-relative
753 fix_functions() -- fixes name and fullname and fills arguments
754 operators.fix_operators(index)
757 function process(index, typesystem, filterfiles)
758 for _, f in ipairs(filterfiles) do
759 classes = loadfile(f)(classes)
762 virtuals.fill_virtuals(classes) -- does that, destructor ("~") excluded
763 distinguish_methods() -- does that
764 fill_public_destr() -- does that: checks if destructor is public
765 fill_copy_constructor() -- does that: checks if copy contructor is public or protected
766 fix_methods_wrappers()
767 get_qobjects()
769 fill_typesystem_with_classes(typesystem)
770 fill_wrappers(typesystem)
771 virtuals.fill_virtual_overloads(classes, typesystem) -- does that
772 virtuals.fill_shell_classes(classes, typesystem) -- does that
774 signalslot.process(functions, typesystem)
777 function output()
778 virtuals.print_shell_classes(classes) -- does that
779 virtuals.print_virtual_overloads(classes) -- does that
780 print_wrappers(classes) -- just compiles metatable list
781 print_metatables(classes) -- just collects the wrappers + generates dispatchers
782 print_class_list(classes) -- does that + prints everything related to class
784 signalslot.output()