added a filter that eliminates Qt internal classes
[lqt.git] / generator / generator.lua
blob88fba7535b171021fb97c5733e744ed5c73fce85
1 #!/usr/bin/lua
3 --[[
5 Copyright (c) 2007-2008 Mauro Iazzi
7 Permission is hereby granted, free of charge, to any person
8 obtaining a copy of this software and associated documentation
9 files (the "Software"), to deal in the Software without
10 restriction, including without limitation the rights to use,
11 copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the
13 Software is furnished to do so, subject to the following
14 conditions:
16 The above copyright notice and this permission notice shall be
17 included in all copies or substantial portions of the Software.
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 OTHER DEALINGS IN THE SOFTWARE.
28 --]]
30 local path = string.match(arg[0], '(.*/)[^%/]+') or ''
31 local filename = nil
32 local cppname = nil
33 local hppname = nil
34 local dirname = nil
35 local module_name = nil
36 local typefiles = {}
37 local filterfiles = {}
38 local output_includes = {
39 '"lqt_common.hpp"',
43 local i = 1
44 while select(i, ...) do
45 local argi = select(i, ...)
46 if argi=='-n' then
47 i = i + 1
48 module_name = select(i, ...)
49 elseif argi=='-d' then
50 i = i + 1
51 dirname = select(i, ...)
52 if dirname~='' and not string.match(dirname, '/$') then
53 dirname = dirname .. '/'
54 end
55 elseif argi=='-i' then
56 i = i + 1
57 table.insert(output_includes, (select(i, ...)))
58 elseif argi=='-t' then
59 i = i + 1
60 table.insert(typefiles, (select(i, ...)))
61 elseif argi=='-f' then
62 i = i + 1
63 table.insert(filterfiles, (select(i, ...)))
64 elseif argi=='-h' then
65 i = i + 1
66 hppname = select(i, ...)
67 elseif argi=='-c' then
68 i = i + 1
69 cppname = select(i, ...)
70 elseif argi=='-o' then
71 i = i + 1
72 local name = select(i, ...)
73 cppname = name..'.cpp'
74 hppname = name..'.hpp'
75 else
76 filename = filename and error'duplicate filename' or argi
77 end
78 i = i + 1
79 end
80 dirname = dirname or ''
81 end
83 local readfile = function(fn)
84 local f = assert(io.open(fn))
85 local s = f:read'*a'
86 f:close()
87 return s
88 end
90 local fprint = function(f)
91 return function(...)
92 for i = 1, select('#',...) do
93 f:write((i==1) and '' or '\t', tostring(select(i,...)))
94 end
95 f:write'\n'
96 f:flush()
97 end
98 end
100 local debug = fprint(io.stderr)
101 local cpp, hpp = nil, nil
102 if cppname then
103 local cppfile = assert(io.open(dirname .. cppname, 'w'))
104 cpp = fprint(cppfile)
105 else
106 cpp = print
108 if hppname then
109 local hppfile = assert(io.open(dirname .. hppname, 'w'))
110 hpp = fprint(hppfile)
111 else
112 hpp = print
115 local xmlstream, idindex = dofile(path..'xml.lua')(readfile(filename))
117 ----------------------------------------------------------------------------------
119 local copy_functions = function(index)
120 local ret = {}
121 for e in pairs(index) do
122 if e.label:match'^Function' then
123 e.label = 'Function'
124 ret[e] = true
127 return ret
131 local fix_arguments = function(all)
132 local fullnames = {}
133 for e in pairs(all or {}) do
134 if e.xarg.fullname then fullnames[e.xarg.fullname] = true end
136 for a in pairs(all) do
137 if a.label=='Argument'
138 and a.xarg.default=='1'
139 and string.match(a.xarg.defaultvalue, '%D') then
140 local dv = a.xarg.defaultvalue
141 if not fullnames[dv] then
142 dv = a.xarg.context..'::'..dv
144 if fullnames[dv] then
145 a.xarg.defaultvalue = dv
146 else
147 a.xarg.default = nil
148 a.xarg.defaultvalue = nil
152 return all
155 local fix_functions = function(index)
156 for f in pairs(index) do
157 local args = {}
158 for i, a in ipairs(f) do
159 -- avoid bogus 'void' arguments
160 if a.xarg.type_name=='void' and i==1 and f[2]==nil then break end
161 if a.label=='Argument' then
162 table.insert(args, a)
165 f.arguments = args
166 f.return_type = f.xarg.type_name
167 if f.xarg.type_name=='void' then
168 f.return_type = nil
171 return index
174 local copy_enums = function(index)
175 local ret = {}
176 for e in pairs(index) do
177 if e.label=='Enum'
178 and not string.match(e.xarg.fullname, '%b<>')
179 and e.xarg.access=='public' then
180 ret[e] = true
183 return ret
186 local fill_enums = function(index)
187 for e in pairs(index) do
188 local values = {}
189 for _, v in ipairs(e) do
190 if v.label=='Enumerator' then
191 table.insert(values, v)
194 e.values = values
196 return index
199 local copy_classes = function(index)
200 local ret = {}
201 for e in pairs(index) do
202 if e.label=='Class'
203 and e.xarg.access~='private'
204 and not (e.xarg.fullname:match'%b<>'
205 or e.xarg.fullname=='QDebug::Stream'
206 or e.xarg.fullname=='QForeachContainerBase'
207 or e.xarg.fullname=='QByteArray::Data'
208 or e.xarg.fullname=='QVariant::Private::Data'
209 or e.xarg.fullname=='QRegion::QRegionData'
210 or e.xarg.fullname=='QTextStreamManipulator'
211 or e.xarg.fullname=='QString::Data'
212 or e.xarg.fullname=='QThreadStorageData'
213 ) then
214 ret[e] = true
217 return ret
220 local fill_virtuals = function(index)
221 local classes = {}
222 for c in pairs(index) do
223 classes[c.xarg.fullname] = c
225 local get_virtuals
226 get_virtuals = function(c)
227 local ret = {}
228 for _, f in ipairs(c) do
229 if f.label=='Function' and f.xarg.virtual=='1' then
230 local n = string.match(f.xarg.name, '~') or f.xarg.name
231 if n~='~' then ret[n] = f end
234 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
235 local base = classes[b]
236 if type(base)=='table' then
237 local bv = get_virtuals(base)
238 for n, f in pairs(bv) do
239 if not ret[n] then ret[n] = f end
243 for _, f in ipairs(c) do
244 if f.label=='Function'
245 and f.xarg.access~='private'
246 and (ret[string.match(f.xarg.name, '~') or f.xarg.name]) then
247 f.xarg.virtual = '1'
248 local n = string.match(f.xarg.name, '~')or f.xarg.name
249 ret[n] = f
252 return ret
254 for c in pairs(index) do
255 c.virtuals = get_virtuals(c)
256 for _, f in pairs(c.virtuals) do
257 if f.xarg.abstract=='1' then c.abstract=true break end
260 return index
263 local distinguish_methods = function(index)
264 for c in pairs(index) do
265 local construct, destruct, normal = {}, nil, {}
266 local n = c.xarg.name
267 local copy = nil
268 for _, f in ipairs(c) do
269 if n==f.xarg.name then
270 table.insert(construct, f)
271 elseif f.xarg.name:match'~' then
272 destruct = f
273 else
274 if (not string.match(f.xarg.name, '^operator%W'))
275 and (not f.xarg.member_template_parameters) then
276 table.insert(normal, f)
280 c.constructors = construct
281 c.destructor = destruct
282 c.methods = normal
284 return index
287 local fill_public_destr = function(index)
288 local classes = {}
289 for c in pairs(index) do
290 classes[c.xarg.fullname] = c
292 local destr_is_public
293 destr_is_public = function(c)
294 if c.destructor then
295 return c.destructor.xarg.access=='public'
296 else
297 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
298 local base = classes[b]
299 if base and not destr_is_public(base) then
300 return false
303 return true
306 for c in pairs(index) do
307 c.public_destr = destr_is_public(c)
309 return index
312 local fill_copy_constructor = function(index)
313 local classes = {}
314 for c in pairs(index) do
315 classes[c.xarg.name] = c
317 for c in pairs(index) do
318 local copy = nil
319 for _, f in ipairs(c.constructors) do
320 if #(f.arguments)==1
321 and f.arguments[1].xarg.type_name==c.xarg.fullname..' const&' then
322 copy = f
323 break
326 c.copy_constructor = copy
328 local copy_constr_is_public
329 copy_constr_is_public = function(c)
330 if c.copy_constructor then
331 return (c.copy_constructor.xarg.access=='public')
332 or (c.copy_constructor.xarg.access=='protected')
333 else
334 local ret = nil
335 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
336 local base = classes[b]
337 if base and not copy_constr_is_public(base) then
338 return false
341 return true
344 for c in pairs(index) do
345 c.public_constr = copy_constr_is_public(c)
347 return index
350 local fill_typesystem_with_enums = function(enums, types)
351 local ret = {}
352 for e in pairs(enums) do
353 if not types[e.xarg.fullname] then
354 ret[e] = true
355 types[e.xarg.fullname] = {
356 push = function(n)
357 return 'lqtL_pushenum(L, '..n..', "'..e.xarg.fullname..'")', 1
358 end,
359 get = function(n)
360 return 'static_cast<'..e.xarg.fullname..'>'
361 ..'(lqtL_toenum(L, '..n..', "'..e.xarg.fullname..'"))', 1
362 end,
363 test = function(n)
364 return 'lqtL_isenum(L, '..n..', "'..e.xarg.fullname..'")', 1
365 end,
367 else
368 --io.stderr:write(e.xarg.fullname, ': already present\n')
371 return ret
374 local fill_typesystem_with_classes = function(classes, types)
375 local ret = {}
376 for c in pairs(classes) do
377 if not types[c.xarg.fullname] then
378 ret[c] = true
379 types[c.xarg.fullname..'*'] = {
380 -- the argument is a pointer to class
381 push = function(n)
382 return 'lqtL_passudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
383 end,
384 get = function(n)
385 return 'static_cast<'..c.xarg.fullname..'*>'
386 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
387 end,
388 test = function(n)
389 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
390 end,
392 types[c.xarg.fullname..' const*'] = {
393 -- the argument is a pointer to constant class instance
394 push = function(n)
395 return 'lqtL_passudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
396 end,
397 get = function(n)
398 return 'static_cast<'..c.xarg.fullname..'*>'
399 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
400 end,
401 test = function(n)
402 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
403 end,
405 types[c.xarg.fullname..'&'] = {
406 -- the argument is a reference to class
407 push = function(n)
408 return 'lqtL_passudata(L, &'..n..', "'..c.xarg.fullname..'*")', 1
409 end,
410 get = function(n)
411 return '*static_cast<'..c.xarg.fullname..'*>'
412 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
413 end,
414 test = function(n)
415 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
416 end,
418 if c.public_constr and c.shell then
419 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
420 types[c.xarg.fullname] = {
421 -- the argument is the class itself
422 push = function(n)
423 return 'lqtL_passudata(L, new '..shellname
424 ..'(L, '..n..'), "'..c.xarg.fullname..'*")', 1
425 end,
426 get = function(n)
427 return '*static_cast<'..c.xarg.fullname..'*>'
428 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
429 end,
430 test = function(n)
431 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
432 end,
434 types[c.xarg.fullname..' const&'] = {
435 -- the argument is a pointer to class
436 push = function(n)
437 return 'lqtL_passudata(L, new '..shellname
438 ..'(L, '..n..'), "'..c.xarg.fullname..'*")', 1
439 end,
440 get = function(n)
441 return '*static_cast<'..c.xarg.fullname..'*>'
442 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
443 end,
444 test = function(n)
445 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
446 end,
451 return ret
454 local fill_wrapper_code = function(f, types)
455 if f.wrapper_code then return f end
456 local stackn, argn = 1, 1
457 local wrap, line = '', ''
458 if f.xarg.member_of_class and f.xarg.static~='1' then
459 if not types[f.xarg.member_of_class..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
460 local sget, sn = types[f.xarg.member_of_class..'*'].get(stackn)
461 wrap = wrap .. ' ' .. f.xarg.member_of_class .. '* self = ' .. sget .. ';\n'
462 stackn = stackn + sn
463 wrap = wrap .. [[
464 if (NULL==self) {
465 lua_pushstring(L, "this pointer is NULL");
466 lua_error(L);
469 --print(sget, sn)
470 line = 'self->'..f.xarg.fullname..'('
471 else
472 line = f.xarg.fullname..'('
474 for i, a in ipairs(f.arguments) do
475 if not types[a.xarg.type_name] then return nil end
476 local aget, an = types[a.xarg.type_name].get(stackn)
477 wrap = wrap .. ' ' .. a.xarg.type_name .. ' arg' .. tostring(argn) .. ' = '
478 if a.xarg.default=='1' and an>0 then
479 wrap = wrap .. 'lua_isnoneornil(L, '..stackn..')'
480 for j = stackn+1,stackn+an-1 do
481 wrap = wrap .. ' && lua_isnoneornil(L, '..j..')'
483 local dv = a.xarg.defaultvalue
484 wrap = wrap .. ' ? static_cast< ' .. a.xarg.type_name .. ' >(' .. dv .. ') : '
486 wrap = wrap .. aget .. ';\n'
487 line = line .. (argn==1 and 'arg' or ', arg') .. argn
488 stackn = stackn + an
489 argn = argn + 1
491 line = line .. ')'
492 -- FIXME: hack follows for constructors
493 if f.calling_line then line = f.calling_line end
494 if f.return_type then line = f.return_type .. ' ret = ' .. line end
495 wrap = wrap .. ' ' .. line .. ';\n lua_settop(L, 0);\n' -- lua_pop(L, '..stackn..');\n'
496 if f.return_type then
497 if not types[f.return_type] then return nil end
498 local rput, rn = types[f.return_type].push'ret'
499 wrap = wrap .. ' luaL_checkstack(L, '..rn..', "cannot grow stack for return value");\n'
500 wrap = wrap .. ' '..rput..';\n return '..rn..';\n'
501 else
502 wrap = wrap .. ' return 0;\n'
504 f.wrapper_code = wrap
505 return f
508 local fill_test_code = function(f, types)
509 local stackn = 1
510 local test = ''
511 if f.xarg.member_of_class and f.xarg.static~='1' then
512 if not types[f.xarg.member_of_class..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
513 local stest, sn = types[f.xarg.member_of_class..'*'].test(stackn)
514 test = test .. ' && ' .. stest
515 stackn = stackn + sn
517 for i, a in ipairs(f.arguments) do
518 if not types[a.xarg.type_name] then return nil end -- print(a.xarg.type_name) return nil end
519 local atest, an = types[a.xarg.type_name].test(stackn)
520 if a.xarg.default=='1' and an>0 then
521 test = test .. ' && (lqtL_missarg(L, ' .. stackn .. ', ' .. an .. ') || '
522 test = test .. atest .. ')'
523 else
524 test = test .. ' && ' .. atest
526 stackn = stackn + an
528 -- can't make use of default values if I fix number of args
529 test = '(lua_gettop(L)<' .. stackn .. ')' .. test
530 f.test_code = test
531 return f
534 local fill_wrappers = function(functions, types)
535 local ret = {}
536 for f in pairs(functions) do
537 f = fill_wrapper_code(f, types)
538 if f then
539 f = assert(fill_test_code(f, types), f.xarg.fullname) -- MUST pass
540 ret[f] = true
541 local out = 'extern "C" int lqt_bind'..f.xarg.id..' (lua_State *L) {\n'
542 .. f.wrapper_code .. '}\n'
543 --print(out)
546 return ret
549 local argument_name = function(tn, an)
550 local ret
551 if string.match(tn, '%(%*%)') then
552 ret = string.gsub(tn, '%(%*%)', '(*'..an..')', 1)
553 elseif string.match(tn, '%[.*%]') then
554 ret = string.gsub(tn, '(%[.*%])', an..'%1')
555 else
556 ret = tn .. ' ' .. an
558 return ret
561 local virtual_overload = function(v, types)
562 local ret = ''
563 if v.virtual_overload then return v end
564 -- make return type
565 if v.return_type and not types[v.return_type] then return nil end
566 local rget, rn = '', 0
567 if v.return_type then rget, rn = types[v.return_type].get'oldtop+1' end
568 local retget = (v.return_type and argument_name(v.return_type, 'ret')
569 .. ' = ' .. rget .. ';' or '') .. 'lua_settop(L, oldtop);return'
570 .. (v.return_type and ' ret' or '')
571 -- make argument push
572 local pushlines, stack = '', 0
573 for i, a in ipairs(v.arguments) do
574 if not types[a.xarg.type_name] then return nil end
575 local apush, an = types[a.xarg.type_name].push('arg'..i)
576 pushlines = pushlines .. ' ' .. apush .. ';\n'
577 stack = stack + an
579 -- make lua call
580 local luacall = 'lua_pcall(L, '..stack..', '..rn..', 0)'
581 -- make prototype and fallback
582 local proto = (v.return_type or 'void')..' ;;'..v.xarg.name..' ('
583 local fallback = ''
584 for i, a in ipairs(v.arguments) do
585 proto = proto .. (i>1 and ', ' or '')
586 .. argument_name(a.xarg.type_name, 'arg'..i)
587 fallback = fallback .. (i>1 and ', arg' or 'arg') .. i
589 proto = proto .. ')' .. (v.xarg.constant=='1' and ' const' or '')
590 fallback = (v.return_type and 'return this->' or 'this->')
591 .. v.xarg.fullname .. '(' .. fallback .. ');\n}\n'
592 ret = proto .. [[ {
593 int oldtop = lua_gettop(L);
594 lqtL_pushudata(L, this, "]]..v.xarg.member_of_class..[[*");
595 lua_getfield(L, -1, "]]..v.xarg.name..[[");
596 if (lua_isfunction(L, -1)) {
597 lua_insert(L, -2);
598 ]] .. pushlines .. [[
599 if (]]..luacall..[[) {
600 ]]..retget..[[;
603 lua_settop(L, oldtop);
604 ]] .. fallback
605 v.virtual_overload = ret
606 v.virtual_proto = string.gsub(proto, ';;', '', 1)
607 return v
610 local fill_shell_class = function(c, types)
611 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
612 local shell = 'class ' .. shellname .. ' : public ' .. c.xarg.fullname .. ' {\npublic:\n'
613 shell = shell .. ' lua_State *L;\n'
614 for _, constr in ipairs(c.constructors) do
615 if constr.xarg.access~='private' then
616 local cline = ' '..shellname..' (lua_State *l'
617 local argline = ''
618 for i, a in ipairs(constr.arguments) do
619 cline = cline .. ', ' .. argument_name(a.xarg.type_name, 'arg'..i)
620 argline = argline .. (i>1 and ', arg' or 'arg') .. i
622 cline = cline .. ') : ' .. c.xarg.fullname
623 .. '(' .. argline .. '), L(l) '
624 .. '{ lqtL_register(L, this); }\n'
625 shell = shell .. cline
628 if c.copy_constructor==nil and c.public_constr then
629 local cline = ' '..shellname..' (lua_State *l, '..c.xarg.fullname..' const& arg1)'
630 cline = cline .. ' : ' .. c.xarg.fullname .. '(arg1), L(l) {}\n'
631 shell = shell .. cline
633 for i, v in pairs(c.virtuals) do
634 if v.xarg.access~='private' then
635 local vret = virtual_overload(v, types)
636 if v.virtual_proto then shell = shell .. ' virtual ' .. v.virtual_proto .. ';\n' end
639 shell = shell .. ' ~'..shellname..'() { lqtL_unregister(L, this); }\n'
640 shell = shell .. '};\n'
641 c.shell_class = shell
642 return c
645 local fill_shell_classes = function(classes, types)
646 local ret = {}
647 for c in pairs(classes) do
648 if c.shell then
649 c = fill_shell_class(c, types)
650 if c then ret[c] = true else error(c.xarg.fullname) end
653 return ret
656 local print_shell_classes = function(classes)
657 for c in pairs(classes) do
658 if c.shell then
659 if c then
660 hpp(c.shell_class)
661 else
662 --io.stderr:write(c.fullname, '\n')
666 return classes
669 local print_virtual_overloads = function(classes)
670 for c in pairs(classes) do
671 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
672 for _,v in pairs(c.virtuals) do
673 if v.virtual_overload then
674 cpp((string.gsub(v.virtual_overload, ';;', shellname..'::', 1)))
678 return classes
681 local print_wrappers = function(index)
682 for c in pairs(index) do
683 local meta = {}
684 for _, f in ipairs(c.methods) do
685 if f.wrapper_code then
686 local out = 'extern "C" int lqt_bind'..f.xarg.id
687 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
688 if f.xarg.access=='public' then
689 cpp(out)
690 meta[f] = f.xarg.name
694 if c.shell then
695 for _, f in ipairs(c.constructors) do
696 if f.wrapper_code then
697 local out = 'extern "C" int lqt_bind'..f.xarg.id
698 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
699 if f.xarg.access=='public' then
700 cpp(out)
701 meta[f] = 'new'
705 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
706 local out = 'extern "C" int lqt_delete'..c.xarg.id..' (lua_State *L) {\n'
707 out = out ..' '..c.xarg.fullname..' *p = static_cast<'
708 ..c.xarg.fullname..'*>(lqtL_toudata(L, 1, "'..c.xarg.fullname..'*"));\n'
709 out = out .. ' if (p) delete p;\n return 0;\n}\n'
710 cpp(out)
712 c.meta = meta
714 return index
717 local print_metatable = function(c)
718 local methods = {}
719 for m, n in pairs(c.meta) do
720 methods[n] = methods[n] or {}
721 table.insert(methods[n], m)
723 for n, l in pairs(methods) do
724 local disp = 'extern "C" int lqt_dispatcher_'..n..c.xarg.id..' (lua_State *L) {\n'
725 for _, f in ipairs(l) do
726 disp = disp..' if ('..f.test_code..') return lqt_bind'..f.xarg.id..'(L);\n'
728 disp = disp .. ' lua_settop(L, 0);\n'
729 disp = disp .. ' lua_pushstring(L, "incorrect or extra arguments");\n'
730 disp = disp .. ' return lua_error(L);\n}\n'
731 cpp(disp)
733 local metatable = 'static luaL_Reg lqt_metatable'..c.xarg.id..'[] = {\n'
734 for n, l in pairs(methods) do
735 metatable = metatable .. ' { "'..n..'", lqt_dispatcher_'..n..c.xarg.id..' },\n'
737 if c.shell then
738 metatable = metatable .. ' { "delete", lqt_delete'..c.xarg.id..' },\n'
740 metatable = metatable .. ' { 0, 0 },\n};\n'
741 cpp(metatable)
742 local bases = ''
743 for b in string.gmatch(c.xarg.bases or '', '([^;]*);') do
744 bases = bases .. '{"' .. b .. '*"}, '
746 bases = 'static lqt_Base lqt_base'..c.xarg.id..'[] = { '..bases..'{NULL} };\n'
747 cpp(bases)
748 return c
751 local print_metatables = function(classes)
752 for c in pairs(classes) do
753 print_metatable(c)
755 return classes
758 local print_class_list = function(classes)
759 local list = 'static lqt_Class lqt_class_list[] = {\n'
760 for c in pairs(classes) do
761 class = '{ lqt_metatable'..c.xarg.id..', lqt_base'..c.xarg.id..', "'..c.xarg.fullname..'*" },\n'
762 list = list .. ' ' .. class
764 list = list .. ' { 0, 0, 0 },\n};\n'
765 cpp(list)
766 return classes
769 local fix_methods_wrappers = function(classes)
770 for c in pairs(classes) do
771 -- if class seems abstract but has a shell class
772 if c.abstract then
773 -- is it really abstract?
774 local a = false
775 for _, f in pairs(c.virtuals) do
776 -- if it is abstract but we cannot overload
777 -- FIXME: this always fails: f.virtual_overload is not filled yet
778 -- maybe this check must be moved later:
779 -- we don't use shell class to move instances to Lua
780 -- but we want to instantiate if we can wrap all virtuals...
781 if f.xarg.abstract=='1' and not f.virtual_overload then a = true break end
783 c.abstract = a
785 c.shell = (not c.abstract) and c.public_destr
786 for _, constr in ipairs(c.constructors) do
787 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
788 constr.calling_line = '*new '..shellname..'(L'
789 for i=1,#(constr.arguments) do
790 constr.calling_line = constr.calling_line .. ', arg' .. i
792 constr.calling_line = constr.calling_line .. ')'
793 constr.xarg.static = '1'
794 constr.return_type = constr.xarg.type_base..'&'
796 if c.destructor then
797 c.destructor.return_type = nil
800 return classes
803 local print_enum_tables = function(enums)
804 for e in pairs(enums) do
805 local table = 'static lqt_Enum lqt_enum'..e.xarg.id..'[] = {\n'
806 --io.stderr:write(e.xarg.fullname, '\t', #e.values, '\n')
807 for _,v in pairs(e.values) do
808 table = table .. ' { "' .. v.xarg.name
809 .. '", static_cast<int>('..v.xarg.fullname..') },\n'
811 table = table .. ' { 0, 0 }\n'
812 table = table .. '};\n'
813 e.enum_table = table
814 cpp(table)
816 return enums
818 local print_enum_creator = function(enums)
819 local out = 'static lqt_Enumlist lqt_enum_list[] = {\n'
820 for e in pairs(enums) do
821 out = out..' { lqt_enum'..e.xarg.id..', "'..e.xarg.fullname..'" },\n'
823 out = out..' { 0, 0 },\n};\n'
824 out = out .. 'extern "C" int lqt_create_enums (lua_State *L) {\n'
825 out = out .. ' lqtL_createenumlist(L, lqt_enum_list); return 0;\n}\n'
826 cpp(out)
827 return enums
830 local print_openmodule = function(n)
831 cpp([[
833 extern "C" int luaopen_]]..n..[[ (lua_State *L) {
834 lqt_create_enums(L);
835 lqtL_createclasses(L, lqt_class_list);
836 return 0;
841 --------------------------------------------------------------------------------------
843 local typesystem = {}
845 local ts = {}
846 for i, ft in ipairs(typefiles) do
847 ts = loadfile(ft)(ts)
849 setmetatable(typesystem, {
850 __newindex = function(t, k, v)
851 --debug('added type', k)
852 ts[k] = v
853 end,
854 __index = function(t, k)
855 local ret = ts[k]
856 --if not ret then debug("unknown type:", tostring(k), ret) end
857 return ret
858 end,
862 fix_arguments(idindex) -- fixes default arguments if they are context-relative
863 local functions = copy_functions(idindex) -- picks functions and fixes label
864 local functions = fix_functions(functions) -- fixes name and fullname and fills arguments
866 local enums = copy_enums(idindex) -- picks enums if public
867 local enums = fill_enums(enums) -- fills field "values"
869 local classes = copy_classes(idindex) -- picks classes if not private and not blacklisted
870 local classes = fill_virtuals(classes) -- does that, destructor ("~") excluded
871 local classes = distinguish_methods(classes) -- does that
872 local classes = fill_public_destr(classes) -- does that: checks if destructor is public
873 local classes = fill_copy_constructor(classes) -- does that: checks if copy contructor is public or protected
874 local classes = fix_methods_wrappers(classes)
876 for _, f in ipairs(filterfiles) do
877 classes, enums = loadfile(f)(classes, enums)
880 local enums = fill_typesystem_with_enums(enums, typesystem) -- does that
881 local classes = fill_typesystem_with_classes(classes, typesystem)
883 local functions = fill_wrappers(functions, typesystem)
884 local classes = fill_shell_classes(classes, typesystem) -- does that, also only selects those with a shell class
886 ------------- BEGIN OUTPUT
889 hpp('#ifndef LQT_BIND_'..module_name)
890 hpp('#define LQT_BIND_'..module_name)
891 hpp()
892 hpp()
893 for _, i in ipairs(output_includes) do
894 hpp('#include '..i)
896 hpp()
898 cpp('#include "'..tostring(hppname)..'"')
899 cpp()
900 cpp()
902 local classes = print_shell_classes(classes) -- does that
903 local classes = print_virtual_overloads(classes, typesystem) -- does that
904 local classes = print_wrappers(classes) -- does that + FIXME: checks if has shell for constr/destr and compiles metatable list
905 local enums = print_enum_tables(enums) -- does that
906 local enums = print_enum_creator(enums) -- does that + print enum list
907 local classes = print_metatables(classes) -- does that + print dispatchers
908 local classes = print_class_list(classes) -- does that
910 print_openmodule(module_name) -- does that
912 hpp('#endif // LQT_BIND_'..module_name)