restructured source tree
[lqt.git] / generator / generator.lua
blob43a0dceca52d505c25dc6e7589121ff5ee46a7be
1 #!/usr/bin/lua
3 local my = {
4 readfile = function(fn) local f = assert(io.open(fn)) local s = f:read'*a' f:close() return s end
7 local elements = dofile'entities.lua'
8 assert_function = function(f)
9 assert(entities.is_function(f), 'argument is not a function')
10 end
12 local filename = ...
13 local path = string.match(arg[0], '(.*/)[^%/]+') or ''
14 local xmlstream, idindex = dofile(path..'xml.lua')(my.readfile(filename))
15 --local code = xmlstream[1]
17 local debug = function(...)
18 for i = 1, select('#',...) do
19 io.stderr:write((i==1) and '' or '\t', tostring(select(i,...)))
20 end
21 io.stderr:write'\n'
22 end
24 ----------------------------------------------------------------------------------
26 local copy_functions = function(index)
27 local ret, copied = {}, 0
28 for e in pairs(index) do
29 if e.label:match'^Function' then
30 --[[and not (e.xarg.name:match'^[%a]*'=='operator'
31 or e.xarg.fullname:match'%b<>'
32 or e.xarg.name:match'_'
33 or e.xarg.name:match'[xX]11'
34 or e.xarg.fullname:match'QInternal'
35 or e.xarg.access=='private'
36 or e.xarg.access=='protected' -- FIXME
37 or e.xarg.fullname=='QVariant::canConvert') then --]]
38 e.label = 'Function'
39 ret[e] = true
40 copied = copied + 1
41 else
42 --removed = removed + (e.label:match'^Function' and 1 or 0)
43 --removed = removed + 1
44 end
45 end
46 return ret, copied
47 end
49 local fix_functions = function(index, all)
50 local fullnames = {}
51 for e in pairs(all or {}) do
52 if e.xarg.fullname then fullnames[e.xarg.fullname] = true end
53 end
54 for f in pairs(index) 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 if a.xarg.default=='1' and string.match(a.xarg.defaultvalue, '%D') then
62 local dv = a.xarg.defaultvalue
63 if not fullnames[dv] then
64 dv = a.xarg.context..'::'..dv
65 end
66 if fullnames[dv] then
67 a.xarg.defaultvalue = dv
68 else
69 a.xarg.default = nil
70 a.xarg.defaultvalue = nil
71 end
72 end
73 end
74 end
75 f.arguments = args
76 if elements.is_constructor(f) then
77 f.xarg.fullname = '*new '..f.xarg.fullname
78 f.return_type = f.xarg.type_base..'&'
79 f.xarg.static = '1'
80 elseif elements.is_destructor(f) or f.xarg.type_name=='void' then
81 f.return_type = nil
82 else
83 if false and f.xarg.access=='protected' then
84 local shellname = 'lqt_shell_'..string.gsub(f.parent.xarg.fullname, '::', '_LQT_')
85 f.xarg.fullname = shellname..'::'..f.xarg.name
86 if f.xarg.static~='1' then
87 f.xarg.static='1'
88 local newarg = { label='Argument', xarg = {
89 type_name = f.xarg.member_of_class..'*',
90 }, }
91 table.insert(args, newarg, 1)
92 end
93 end
94 f.return_type = f.xarg.type_name
95 end
96 end
97 return index
98 end
100 local copy_enums = function(index)
101 local ret = {}
102 for e in pairs(index) do
103 if e.label=='Enum'
104 and not string.match(e.xarg.fullname, '%b<>')
105 and e.xarg.access~='private' then
106 ret[e] = true
109 return ret
112 local fix_enums = function(index)
113 for e in pairs(index) do
114 local values = {}
115 for _, v in ipairs(e) do
116 if v.label=='Enumerator' then
117 table.insert(values, v)
120 e.values = values
122 return index
125 local copy_classes = function(index)
126 local ret = {}
127 for e in pairs(index) do
128 if e.label=='Class'
129 and e.xarg.access~='private'
130 and not (e.xarg.fullname:match'%b<>'
131 or e.xarg.fullname=='QDebug::Stream'
132 or e.xarg.fullname=='QForeachContainerBase'
133 or e.xarg.fullname=='QByteArray::Data'
134 or e.xarg.fullname=='QVariant::Private::Data'
135 or e.xarg.fullname=='QRegion::QRegionData'
136 or e.xarg.fullname=='QTextStreamManipulator'
137 or e.xarg.fullname=='QString::Data'
138 or e.xarg.fullname=='QThreadStorageData'
139 ) then
140 ret[e] = true
143 return ret
146 local fill_virtuals = function(index)
147 local classes = {}
148 for c in pairs(index) do
149 classes[c.xarg.fullname] = c
151 local get_virtuals
152 get_virtuals = function(c)
153 local ret = {}
154 for _, f in ipairs(c) do
155 if f.label=='Function' and f.xarg.virtual=='1' then
156 local n = string.match(f.xarg.name, '~') or f.xarg.name
157 if n~='~' then ret[n] = f end
160 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
161 local base = classes[b]
162 if type(base)=='table' then
163 local bv = get_virtuals(base)
164 for n, f in pairs(bv) do
165 if not ret[n] then ret[n] = f end
169 for _, f in ipairs(c) do
170 if f.label=='Function'
171 and f.xarg.access~='private'
172 and (ret[string.match(f.xarg.name, '~') or f.xarg.name]) then
173 f.xarg.virtual = '1'
174 local n = string.match(f.xarg.name, '~')or f.xarg.name
175 ret[n] = f
178 return ret
180 for c in pairs(index) do
181 c.virtuals = get_virtuals(c)
182 for _, f in pairs(c.virtuals) do
183 if f.xarg.abstract=='1' then c.abstract=true break end
186 return index
189 local fill_special_methods = function(index)
190 for c in pairs(index) do
191 local construct, destruct, normal = {}, nil, {}
192 local n = c.xarg.name
193 local auto, copy = true, nil
194 for _, f in ipairs(c) do
195 if n==f.xarg.name then
196 auto = false
197 if #(f.arguments or {})==1 and
198 f.arguments[1].xarg.type_name==(c.xarg.fullname..' const&') then
199 copy = f.xarg.access or 'PUBLIC?'
202 if n==f.xarg.name then
203 table.insert(construct, f)
204 elseif f.xarg.name:match'~' then
205 destruct = f
206 else
207 if (not string.match(f.xarg.name, '^operator%W'))
208 and (not f.xarg.member_template_parameters) then
209 table.insert(normal, f)
213 construct.auto = auto
214 construct.copy = (copy==nil and 'auto' or copy) -- FIXME: must try
215 c.constructors = construct
216 c.destructor = destruct and (destruct.xarg.access or 'PUBLIC?') or 'auto'
217 c.methods = normal
219 return index
222 local fill_copy_constructor = function(index)
223 local classes = {}
224 for c in pairs(index) do
225 classes[c.xarg.name] = c
227 local destr
228 destr = function(c)
229 if c.destructor=='auto' then
230 local ret = nil
231 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
232 local base = classes[b]
233 if base and destr(base)=='private' then
234 c.destructor = 'private'
235 return 'private'
239 return c.destructor
241 local copy_constr
242 copy_constr = function(c)
243 if c.constructors.copy=='auto' then
244 local ret = nil
245 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
246 local base = classes[b]
247 if base and copy_constr(base)=='private' then
248 c.constructors.copy = 'private'
249 return 'private'
253 return c.constructors.copy
255 for c in pairs(index) do
256 c.constructors.copy = copy_constr(c)
257 c.destructor = destr(c)
258 --io.stderr:write(c.xarg.fullname, '\t', c.constructors.copy, '\n')
259 --io.stderr:write(c.xarg.fullname, '\t', c.destructor, '\n')
261 return index
264 local fill_typesystem_with_enums = function(enums, types)
265 local ret = {}
266 for e in pairs(enums) do
267 if not types[e.xarg.fullname] then
268 ret[e] = true
269 types[e.xarg.fullname] = {
270 push = function(n)
271 return 'lqtL_pushenum(L, '..n..', "'..e.xarg.fullname..'")', 1
272 end,
273 get = function(n)
274 return 'static_cast<'..e.xarg.fullname..'>'
275 ..'(lqtL_toenum(L, '..n..', "'..e.xarg.fullname..'"))', 1
276 end,
277 test = function(n)
278 return 'lqtL_isenum(L, '..n..', "'..e.xarg.fullname..'")', 1
279 end,
281 else
282 --io.stderr:write(e.xarg.fullname, ': already present\n')
285 return ret
288 local fill_typesystem_with_classes = function(classes, types)
289 local ret = {}
290 for c in pairs(classes) do
291 if not types[c.xarg.fullname] then
292 ret[c] = true
293 types[c.xarg.fullname..'*'] = {
294 -- the argument is a pointer to class
295 push = function(n)
296 return 'lqtL_passudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
297 end,
298 get = function(n)
299 return 'static_cast<'..c.xarg.fullname..'*>'
300 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
301 end,
302 test = function(n)
303 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
304 end,
306 types[c.xarg.fullname..' const*'] = {
307 -- the argument is a pointer to constant class instance
308 push = function(n)
309 return 'lqtL_passudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
310 end,
311 get = function(n)
312 return 'static_cast<'..c.xarg.fullname..'*>'
313 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
314 end,
315 test = function(n)
316 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
317 end,
319 types[c.xarg.fullname..'&'] = {
320 -- the argument is a reference to class
321 push = function(n)
322 return 'lqtL_passudata(L, &'..n..', "'..c.xarg.fullname..'*")', 1
323 end,
324 get = function(n)
325 return '*static_cast<'..c.xarg.fullname..'*>'
326 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
327 end,
328 test = function(n)
329 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
330 end,
332 if c.constructors.copy~='private' then -- and c.destructor~='private' then
333 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
334 types[c.xarg.fullname] = {
335 -- the argument is the class itself
336 push = function(n)
337 return 'lqtL_passudata(L, new '..shellname
338 ..'(L, '..n..'), "'..c.xarg.fullname..'*")', 1
339 end,
340 get = function(n)
341 return '*static_cast<'..c.xarg.fullname..'*>'
342 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
343 end,
344 test = function(n)
345 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
346 end,
348 types[c.xarg.fullname..' const&'] = {
349 -- the argument is a pointer to class
350 push = function(n)
351 return 'lqtL_passudata(L, new '..shellname
352 ..'(L, '..n..'), "'..c.xarg.fullname..'*")', 1
353 end,
354 get = function(n)
355 return '*static_cast<'..c.xarg.fullname..'*>'
356 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
357 end,
358 test = function(n)
359 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
360 end,
362 else
363 --io.stderr:write(c.xarg.fullname, ': no copy constructor\n')
365 else
366 --io.stderr:write(c.xarg.fullname, ': already present\n')
369 return ret
372 local fill_wrapper_code = function(f, types, debug)
373 debug = debug or function()end
374 local stackn, argn = 1, 1
375 local wrap, line = '', ''
376 if f.xarg.member_of_class and f.xarg.static~='1' then
377 if not types[f.xarg.member_of_class..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
378 local sget, sn = types[f.xarg.member_of_class..'*'].get(stackn)
379 wrap = wrap .. ' ' .. f.xarg.member_of_class .. '* self = ' .. sget .. ';\n'
380 stackn = stackn + sn
381 wrap = wrap .. [[
382 if (NULL==self) {
383 lua_pushstring(L, "this pointer is NULL");
384 lua_error(L);
387 --print(sget, sn)
388 line = 'self->'..f.xarg.fullname..'('
389 else
390 line = f.xarg.fullname..'('
392 for i, a in ipairs(f.arguments) do
393 if not types[a.xarg.type_name] then debug(a.xarg.type_name) return nil end -- print(a.xarg.type_name) return nil end
394 local aget, an = types[a.xarg.type_name].get(stackn)
395 wrap = wrap .. ' ' .. a.xarg.type_name .. ' arg' .. tostring(argn) .. ' = '
396 if a.xarg.default=='1' and an>0 then
397 wrap = wrap .. 'lua_isnoneornil(L, '..stackn..')'
398 for j = stackn+1,stackn+an-1 do
399 wrap = wrap .. ' && lua_isnoneornil(L, '..j..')'
401 local dv = a.xarg.defaultvalue
402 wrap = wrap .. ' ? ' .. dv .. ' : '
404 wrap = wrap .. aget .. ';\n'
405 line = line .. (argn==1 and 'arg' or ', arg') .. argn
406 stackn = stackn + an
407 argn = argn + 1
409 line = line .. ')'
410 -- FIXME: hack follows for constructors
411 if f.calling_line then line = f.calling_line end
412 if f.return_type then line = f.return_type .. ' ret = ' .. line end
413 wrap = wrap .. ' ' .. line .. ';\n lua_settop(L, 0);\n' -- lua_pop(L, '..stackn..');\n'
414 if f.return_type then
415 if not types[f.return_type] then return nil end
416 local rput, rn = types[f.return_type].push'ret'
417 wrap = wrap .. ' luaL_checkstack(L, '..rn..', "cannot grow stack for return value");\n'
418 wrap = wrap .. ' '..rput..';\n return '..rn..';\n'
419 else
420 wrap = wrap .. ' return 0;\n'
422 f.wrapper_code = wrap
423 return f
426 local fill_test_code = function(f, types)
427 local stackn = 1
428 local test = ''
429 if f.xarg.member_of_class and f.xarg.static~='1' then
430 if not types[f.xarg.member_of_class..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
431 local stest, sn = types[f.xarg.member_of_class..'*'].test(stackn)
432 test = test .. ' && ' .. stest
433 stackn = stackn + sn
435 for i, a in ipairs(f.arguments) do
436 if not types[a.xarg.type_name] then return nil end -- print(a.xarg.type_name) return nil end
437 local atest, an = types[a.xarg.type_name].test(stackn)
438 if a.xarg.default=='1' and an>0 then
439 test = test .. ' && (lqtL_missarg(L, ' .. stackn .. ', ' .. an .. ') || '
440 test = test .. atest .. ')'
441 else
442 test = test .. ' && ' .. atest
444 stackn = stackn + an
446 -- can't make use of default values if I fix number of args
447 test = '(lua_gettop(L)<' .. stackn .. ')' .. test
448 f.test_code = test
449 return f
452 local fill_wrappers = function(functions, types)
453 local ret = {}
454 for f in pairs(functions) do
455 f = fill_wrapper_code(f, types)
456 if f then
457 f = assert(fill_test_code(f, types), f.xarg.fullname) -- MUST pass
458 ret[f] = true
459 local out = 'extern "C" int lqt_bind'..f.xarg.id..' (lua_State *L) {\n'
460 .. f.wrapper_code .. '}\n'
461 --print(out)
464 return ret
467 local argument_name = function(tn, an)
468 local ret
469 if string.match(tn, '%(%*%)') then
470 ret = string.gsub(tn, '%(%*%)', '(*'..an..')', 1)
471 elseif string.match(tn, '%[.*%]') then
472 ret = string.gsub(tn, '(%[.*%])', an..'%1')
473 else
474 ret = tn .. ' ' .. an
476 return ret
479 local virtual_overload = function(v, types)
480 local ret = ''
481 if v.virtual_overload then return v end
482 -- make return type
483 if v.return_type and not types[v.return_type] then return nil end
484 local rget, rn = '', 0
485 if v.return_type then rget, rn = types[v.return_type].get'oldtop+1' end
486 local retget = (v.return_type and argument_name(v.return_type, 'ret')
487 .. ' = ' .. rget .. ';' or '') .. 'lua_settop(L, oldtop);return'
488 .. (v.return_type and ' ret' or '')
489 -- make argument push
490 local pushlines, stack = '', 0
491 for i, a in ipairs(v.arguments) do
492 if not types[a.xarg.type_name] then return nil end
493 local apush, an = types[a.xarg.type_name].push('arg'..i)
494 pushlines = pushlines .. ' ' .. apush .. ';\n'
495 stack = stack + an
497 -- make lua call
498 local luacall = 'lua_pcall(L, '..stack..', '..rn..', 0)'
499 -- make prototype and fallback
500 local proto = (v.return_type or 'void')..' ;;'..v.xarg.name..' ('
501 local fallback = ''
502 for i, a in ipairs(v.arguments) do
503 proto = proto .. (i>1 and ', ' or '')
504 .. argument_name(a.xarg.type_name, 'arg'..i)
505 fallback = fallback .. (i>1 and ', arg' or 'arg') .. i
507 proto = proto .. ')' .. (v.xarg.constant=='1' and ' const' or '')
508 fallback = (v.return_type and 'return this->' or 'this->')
509 .. v.xarg.fullname .. '(' .. fallback .. ');\n}\n'
510 ret = proto .. [[ {
511 int oldtop = lua_gettop(L);
512 lqtL_pushudata(L, this, "]]..v.xarg.member_of_class..[[*");
513 lua_getfield(L, -1, "]]..v.xarg.name..[[");
514 if (lua_isfunction(L, -1)) {
515 lua_insert(L, -2);
516 ]] .. pushlines .. [[
517 if (]]..luacall..[[) {
518 ]]..retget..[[;
521 lua_settop(L, oldtop);
522 ]] .. fallback
523 v.virtual_overload = ret
524 v.virtual_proto = string.gsub(proto, ';;', '', 1)
525 return v
528 local fill_shell_class = function(c, types)
529 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
530 local shell = 'class ' .. shellname .. ' : public ' .. c.xarg.fullname .. ' {\npublic:\n'
531 shell = shell .. ' lua_State *L;\n'
532 for _, constr in ipairs(c.constructors) do
533 if constr.xarg.access~='private' then
534 local cline = ' '..shellname..' (lua_State *l'
535 local argline = ''
536 for i, a in ipairs(constr.arguments) do
537 cline = cline .. ', ' .. argument_name(a.xarg.type_name, 'arg'..i)
538 argline = argline .. (i>1 and ', arg' or 'arg') .. i
540 cline = cline .. ') : ' .. c.xarg.fullname
541 .. '(' .. argline .. '), L(l) '
542 .. '{ lqtL_register(L, this); }\n'
543 shell = shell .. cline
546 if c.constructors.copy=='auto' then
547 local cline = ' '..shellname..' (lua_State *l, '..c.xarg.fullname..' const& arg1)'
548 cline = cline .. ' : ' .. c.xarg.fullname .. '(arg1), L(l) {}\n'
549 shell = shell .. cline
551 for i, v in pairs(c.virtuals) do
552 if v.xarg.access~='private' then
553 local vret = virtual_overload(v, types)
554 if v.virtual_proto then shell = shell .. ' virtual ' .. v.virtual_proto .. ';\n' end
557 shell = shell .. ' ~'..shellname..'() { lqtL_unregister(L, this); }\n'
558 shell = shell .. '};\n'
559 c.shell_class = shell
560 return c
563 local fill_shell_classes = function(classes, types)
564 local ret = {}
565 for c in pairs(classes) do
566 if c.shell then
567 c = fill_shell_class(c, types)
568 if c then ret [c] = true print(c.shell_class)
569 else
570 io.stderr:write(c.fullname, '\n')
574 return ret
577 local print_virtual_overloads = function(classes, types)
578 for c in pairs(classes) do
579 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
580 for _,v in pairs(c.virtuals) do
581 if v.virtual_overload then
582 print((string.gsub(v.virtual_overload, ';;', shellname..'::', 1)))
586 return classes
589 local print_wrappers = function(index)
590 for c in pairs(index) do
591 local meta = {}
592 for _, f in ipairs(c.methods) do
593 if f.wrapper_code then
594 local out = 'extern "C" int lqt_bind'..f.xarg.id
595 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
596 if f.xarg.access=='public' then
597 print(out)
598 meta[f] = f.xarg.name
602 if c.shell then
603 for _, f in ipairs(c.constructors) do
604 if f.wrapper_code then
605 local out = 'extern "C" int lqt_bind'..f.xarg.id
606 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
607 if f.xarg.access=='public' then
608 print(out)
609 meta[f] = 'new'
613 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
614 local out = 'extern "C" int lqt_delete'..c.xarg.id..' (lua_State *L) {\n'
615 out = out ..' '..c.xarg.fullname..' *p = static_cast<'
616 ..c.xarg.fullname..'*>(lqtL_toudata(L, 1, "'..c.xarg.fullname..'*"));\n'
617 out = out .. ' if (p) delete p;\n return 0;}\n'
618 print(out)
620 c.meta = meta
622 return index
625 local print_metatable = function(c)
626 local methods = {}
627 for m, n in pairs(c.meta) do
628 methods[n] = methods[n] or {}
629 table.insert(methods[n], m)
631 for n, l in pairs(methods) do
632 local disp = 'extern "C" int lqt_dispatcher_'..n..c.xarg.id..' (lua_State *L) {\n'
633 for _, f in ipairs(l) do
634 disp = disp..' if ('..f.test_code..') return lqt_bind'..f.xarg.id..'(L);\n'
636 disp = disp .. ' lua_settop(L, 0);\n'
637 disp = disp .. ' lua_pushstring(L, "incorrect or extra arguments");\n'
638 disp = disp .. ' return lua_error(L);\n}\n'
639 print(disp)
641 local metatable = 'static luaL_Reg lqt_metatable'..c.xarg.id..'[] = {\n'
642 for n, l in pairs(methods) do
643 metatable = metatable .. ' { "'..n..'", lqt_dispatcher_'..n..c.xarg.id..' },\n'
645 if c.shell then
646 metatable = metatable .. ' { "delete", lqt_delete'..c.xarg.id..' },\n'
648 metatable = metatable .. ' { 0, 0 },\n};\n'
649 print(metatable)
650 local bases = ''
651 for b in string.gmatch(c.xarg.bases or '', '([^;]*);') do
652 bases = bases .. '{"' .. b .. '*"}, '
654 bases = 'static lqt_Base lqt_base'..c.xarg.id..'[] = { '..bases..'{NULL} };\n'
655 print(bases)
656 return c
659 local print_metatables = function(classes)
660 for c in pairs(classes) do
661 print_metatable(c)
663 return classes
666 local print_class_list = function(classes)
667 local list = 'static lqt_Class lqt_class_list[] = {\n'
668 for c in pairs(classes) do
669 class = '{ lqt_metatable'..c.xarg.id..', lqt_base'..c.xarg.id..', "'..c.xarg.fullname..'*" },\n'
670 list = list .. ' ' .. class
672 list = list .. ' { 0, 0, 0 },\n};\n'
673 print(list)
674 return classes
677 local fix_methods_wrappers = function(classes)
678 for c in pairs(classes) do
679 -- if class seems abstract but has a shell class
680 -- FIXME: destructor should not matter?
681 if c.abstract and c.destructor~='private' then
682 -- is it really abstract?
683 local a = false
684 for _, f in pairs(c.virtuals) do
685 -- if it is abstract but we cannot overload
686 if f.xarg.abstract=='1' and not f.virtual_overload then a = true break end
688 c.abstract = a
690 -- FIXME: destructor should not matter?
691 c.shell = (not c.abstract) and (c.destructor~='private')
692 for _, constr in ipairs(c.constructors) do
693 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
694 constr.calling_line = '*new '..shellname..'(L'
695 for i=1,#(constr.arguments) do
696 constr.calling_line = constr.calling_line .. ', arg' .. i
698 constr.calling_line = constr.calling_line .. ')'
701 return classes
704 local print_enum_tables = function(enums)
705 for e in pairs(enums) do
706 local table = 'static lqt_Enum lqt_enum'..e.xarg.id..'[] = {\n'
707 --io.stderr:write(e.xarg.fullname, '\t', #e.values, '\n')
708 for _,v in pairs(e.values) do
709 table = table .. ' { "' .. v.xarg.name
710 .. '", static_cast<int>('..v.xarg.fullname..') },\n'
712 table = table .. ' { 0, 0 }\n'
713 table = table .. '};\n'
714 e.enum_table = table
715 print(table)
717 return enums
719 local print_enum_creator = function(enums)
720 local out = 'static lqt_Enumlist lqt_enum_list[] = {\n'
721 for e in pairs(enums) do
722 out = out..' { lqt_enum'..e.xarg.id..', "'..e.xarg.fullname..'" },\n'
724 out = out..' { 0, 0 },\n};\n'
725 out = out .. 'extern "C" int lqt_create_enums (lua_State *L) {\n'
726 out = out .. ' lqtL_createenumlist(L, lqt_enum_list); return 0;\n}\n'
727 print(out)
728 return enums
731 local print_openmodule = function(n)
732 print([[
734 extern "C" int luaopen_]]..n..[[ (lua_State *L) {
735 lqt_create_enums(L);
736 lqtL_createclasses(L, lqt_class_list);
737 return 0;
742 local functions = copy_functions(idindex)
743 local functions = fix_functions(functions, idindex)
745 local enums = copy_enums(idindex)
746 local enums = fix_enums(enums)
748 local classes = copy_classes(idindex)
749 local classes = fill_virtuals(classes)
750 local classes = fill_special_methods(classes)
751 local classes = fill_copy_constructor(classes)
752 local classes = fix_methods_wrappers(classes)
754 local ntable = function(t) local ret=0 for _ in pairs(t) do ret=ret+1 end return ret end
757 local typesystem = {}
759 local ts = dofile('types.lua')
760 setmetatable(typesystem, {
761 __newindex = function(t, k, v)
762 --debug('added type', k)
763 ts[k] = v
764 end,
765 __index = function(t, k)
766 local ret = ts[k]
767 --if not ret then debug("unknown type:", tostring(k), ret) end
768 return ret
769 end,
773 --debug('funcs', ntable(functions))
774 --debug('enums', ntable(enums))
775 --debug('class', ntable(classes))
776 local enums = fill_typesystem_with_enums(enums, typesystem)
777 local classes = fill_typesystem_with_classes(classes, typesystem)
778 local functions = fill_wrappers(functions, typesystem)
779 local classes = fill_shell_classes(classes, typesystem)
780 local classes = print_virtual_overloads(classes, typesystem)
781 local classes = print_wrappers(classes)
782 local enums = print_enum_tables(enums)
783 local enums = print_enum_creator(enums)
784 local classes = print_metatables(classes)
785 local classes = print_class_list(classes)
786 --debug('funcs', ntable(functions))
787 --debug('enums', ntable(enums))
788 --debug('class', ntable(classes))
789 print_openmodule'src'
791 local print_virtuals = function(index)
792 for c in pairs(index) do
793 debug(c.xarg.name)
794 for n, f in pairs(c.virtuals) do debug(' '..n, f.xarg.fullname) end
799 for f in pairs(idindex) do
800 if f.label=='Function' and f.xarg.name=='connect' then
801 --debug(f.xarg.fullname, f.xarg.wrapper_code and 'true' or 'false')
802 local w = fill_wrapper_code(f, typesystem, debug)
803 --debug(w)
804 --print(k, v.get'INDEX')
805 elseif f.label=='Function' and f.xarg.name=='QObject' then
806 --debug('==>', #f.arguments, f.wrapper_code and 'wrapped' or 'gone')
810 --print_virtuals(classes)
812 --print(copy_functions(idindex))