removed unused variable
[lqt.git] / generator / generator.lua
blob83cd58677b3db8d2a6798cec5bc11a8bee23f854
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 output_includes = {
38 '"lqt_common.hpp"',
42 local i = 1
43 while select(i, ...) do
44 local argi = select(i, ...)
45 if argi=='-n' then
46 i = i + 1
47 module_name = select(i, ...)
48 elseif argi=='-d' then
49 i = i + 1
50 dirname = select(i, ...)
51 elseif argi=='-i' then
52 i = i + 1
53 table.insert(output_includes, (select(i, ...)))
54 elseif argi=='-t' then
55 i = i + 1
56 table.insert(typefiles, (select(i, ...)))
57 elseif argi=='-h' then
58 i = i + 1
59 hppname = select(i, ...)
60 elseif argi=='-c' then
61 i = i + 1
62 cppname = select(i, ...)
63 elseif argi=='-o' then
64 i = i + 1
65 local name = select(i, ...)
66 cppname = name..'.cpp'
67 hppname = name..'.hpp'
68 else
69 filename = filename and error'duplicate filename' or argi
70 end
71 i = i + 1
72 end
73 dirname = dirname or ''
74 end
76 local readfile = function(fn)
77 local f = assert(io.open(fn))
78 local s = f:read'*a'
79 f:close()
80 return s
81 end
83 local fprint = function(f)
84 return function(...)
85 for i = 1, select('#',...) do
86 f:write((i==1) and '' or '\t', tostring(select(i,...)))
87 end
88 f:write'\n'
89 end
90 end
92 local debug = fprint(io.stderr)
93 local cpp, hpp = nil, nil
94 if cppname then
95 local cppfile = assert(io.open(dirname .. cppname, 'w'))
96 cpp = fprint(cppfile)
97 else
98 cpp = print
99 end
100 if hppname then
101 local hppfile = assert(io.open(dirname .. hppname, 'w'))
102 hpp = fprint(hppfile)
103 else
104 hpp = print
107 local xmlstream, idindex = dofile(path..'xml.lua')(readfile(filename))
109 ----------------------------------------------------------------------------------
111 local copy_functions = function(index)
112 local ret = {}
113 for e in pairs(index) do
114 if e.label:match'^Function' then
115 e.label = 'Function'
116 ret[e] = true
119 return ret
123 local fix_arguments = function(all)
124 local fullnames = {}
125 for e in pairs(all or {}) do
126 if e.xarg.fullname then fullnames[e.xarg.fullname] = true end
128 for a in pairs(all) do
129 if a.label=='Argument'
130 and a.xarg.default=='1'
131 and string.match(a.xarg.defaultvalue, '%D') then
132 local dv = a.xarg.defaultvalue
133 if not fullnames[dv] then
134 dv = a.xarg.context..'::'..dv
136 if fullnames[dv] then
137 a.xarg.defaultvalue = dv
138 else
139 a.xarg.default = nil
140 a.xarg.defaultvalue = nil
144 return all
147 local fix_functions = function(index)
148 for f in pairs(index) do
149 local args = {}
150 for i, a in ipairs(f) do
151 -- avoid bogus 'void' arguments
152 if a.xarg.type_name=='void' and i==1 and f[2]==nil then break end
153 if a.label=='Argument' then
154 table.insert(args, a)
157 f.arguments = args
158 local is_constructor = function(f)
159 return (f.xarg.member_of_class and f.xarg.member_of_class~=''
160 and f.xarg.fullname==(f.xarg.member_of_class..'::'..f.xarg.name) -- this should be always true
161 and string.match(f.xarg.member_of_class, f.xarg.name..'$'))
163 if is_constructor(f) then
164 f.xarg.fullname = '*new '..f.xarg.fullname
165 f.return_type = f.xarg.type_base..'&'
166 f.xarg.static = '1'
167 elseif string.match(f.xarg.name, '~') or f.xarg.type_name=='void' then
168 f.return_type = nil
169 else
170 if false and f.xarg.access=='protected' then
171 local shellname = 'lqt_shell_'..string.gsub(f.parent.xarg.fullname, '::', '_LQT_')
172 f.xarg.fullname = shellname..'::'..f.xarg.name
173 if f.xarg.static~='1' then
174 f.xarg.static='1'
175 local newarg = { label='Argument', xarg = {
176 type_name = f.xarg.member_of_class..'*',
177 }, }
178 table.insert(args, newarg, 1)
181 f.return_type = f.xarg.type_name
184 return index
187 local copy_enums = function(index)
188 local ret = {}
189 for e in pairs(index) do
190 if e.label=='Enum'
191 and not string.match(e.xarg.fullname, '%b<>')
192 and e.xarg.access=='public' then
193 ret[e] = true
196 return ret
199 local fill_enums = function(index)
200 for e in pairs(index) do
201 local values = {}
202 for _, v in ipairs(e) do
203 if v.label=='Enumerator' then
204 table.insert(values, v)
207 e.values = values
209 return index
212 local copy_classes = function(index)
213 local ret = {}
214 for e in pairs(index) do
215 if e.label=='Class'
216 and e.xarg.access~='private'
217 and not (e.xarg.fullname:match'%b<>'
218 or e.xarg.fullname=='QDebug::Stream'
219 or e.xarg.fullname=='QForeachContainerBase'
220 or e.xarg.fullname=='QByteArray::Data'
221 or e.xarg.fullname=='QVariant::Private::Data'
222 or e.xarg.fullname=='QRegion::QRegionData'
223 or e.xarg.fullname=='QTextStreamManipulator'
224 or e.xarg.fullname=='QString::Data'
225 or e.xarg.fullname=='QThreadStorageData'
226 ) then
227 ret[e] = true
230 return ret
233 local fill_virtuals = function(index)
234 local classes = {}
235 for c in pairs(index) do
236 classes[c.xarg.fullname] = c
238 local get_virtuals
239 get_virtuals = function(c)
240 local ret = {}
241 for _, f in ipairs(c) do
242 if f.label=='Function' and f.xarg.virtual=='1' then
243 local n = string.match(f.xarg.name, '~') or f.xarg.name
244 if n~='~' then ret[n] = f end
247 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
248 local base = classes[b]
249 if type(base)=='table' then
250 local bv = get_virtuals(base)
251 for n, f in pairs(bv) do
252 if not ret[n] then ret[n] = f end
256 for _, f in ipairs(c) do
257 if f.label=='Function'
258 and f.xarg.access~='private'
259 and (ret[string.match(f.xarg.name, '~') or f.xarg.name]) then
260 f.xarg.virtual = '1'
261 local n = string.match(f.xarg.name, '~')or f.xarg.name
262 ret[n] = f
265 return ret
267 for c in pairs(index) do
268 c.virtuals = get_virtuals(c)
269 for _, f in pairs(c.virtuals) do
270 if f.xarg.abstract=='1' then c.abstract=true break end
273 return index
276 local fill_special_methods = function(index)
277 for c in pairs(index) do
278 local construct, destruct, normal = {}, nil, {}
279 local n = c.xarg.name
280 local copy = nil
281 for _, f in ipairs(c) do
282 if n==f.xarg.name then
283 if #(f.arguments or {})==1 and
284 f.arguments[1].xarg.type_name==(c.xarg.fullname..' const&') then
285 copy = f.xarg.access or 'PUBLIC?'
288 if n==f.xarg.name then
289 table.insert(construct, f)
290 elseif f.xarg.name:match'~' then
291 destruct = f
292 else
293 if (not string.match(f.xarg.name, '^operator%W'))
294 and (not f.xarg.member_template_parameters) then
295 table.insert(normal, f)
299 construct.copy = (copy==nil and 'auto' or copy) -- FIXME: must try
300 c.constructors = construct
301 c.destructor = destruct and (destruct.xarg.access or 'PUBLIC?') or 'auto'
302 c.methods = normal
304 return index
307 local fill_copy_constructor = function(index)
308 local classes = {}
309 for c in pairs(index) do
310 classes[c.xarg.name] = c
312 local destr
313 destr = function(c)
314 if c.destructor=='auto' then
315 local ret = nil
316 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
317 local base = classes[b]
318 if base and destr(base)=='private' then
319 c.destructor = 'private'
320 return 'private'
324 return c.destructor
326 local copy_constr
327 copy_constr = function(c)
328 if c.constructors.copy=='auto' then
329 local ret = nil
330 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
331 local base = classes[b]
332 if base and copy_constr(base)=='private' then
333 c.constructors.copy = 'private'
334 return 'private'
338 return c.constructors.copy
340 for c in pairs(index) do
341 c.constructors.copy = copy_constr(c)
342 c.destructor = destr(c)
343 --io.stderr:write(c.xarg.fullname, '\t', c.constructors.copy, '\n')
344 --io.stderr:write(c.xarg.fullname, '\t', c.destructor, '\n')
346 return index
349 local fill_typesystem_with_enums = function(enums, types)
350 local ret = {}
351 for e in pairs(enums) do
352 if not types[e.xarg.fullname] then
353 ret[e] = true
354 types[e.xarg.fullname] = {
355 push = function(n)
356 return 'lqtL_pushenum(L, '..n..', "'..e.xarg.fullname..'")', 1
357 end,
358 get = function(n)
359 return 'static_cast<'..e.xarg.fullname..'>'
360 ..'(lqtL_toenum(L, '..n..', "'..e.xarg.fullname..'"))', 1
361 end,
362 test = function(n)
363 return 'lqtL_isenum(L, '..n..', "'..e.xarg.fullname..'")', 1
364 end,
366 else
367 --io.stderr:write(e.xarg.fullname, ': already present\n')
370 return ret
373 local fill_typesystem_with_classes = function(classes, types)
374 local ret = {}
375 for c in pairs(classes) do
376 if not types[c.xarg.fullname] then
377 ret[c] = true
378 types[c.xarg.fullname..'*'] = {
379 -- the argument is a pointer to class
380 push = function(n)
381 return 'lqtL_passudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
382 end,
383 get = function(n)
384 return 'static_cast<'..c.xarg.fullname..'*>'
385 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
386 end,
387 test = function(n)
388 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
389 end,
391 types[c.xarg.fullname..' const*'] = {
392 -- the argument is a pointer to constant class instance
393 push = function(n)
394 return 'lqtL_passudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
395 end,
396 get = function(n)
397 return 'static_cast<'..c.xarg.fullname..'*>'
398 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
399 end,
400 test = function(n)
401 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
402 end,
404 types[c.xarg.fullname..'&'] = {
405 -- the argument is a reference to class
406 push = function(n)
407 return 'lqtL_passudata(L, &'..n..', "'..c.xarg.fullname..'*")', 1
408 end,
409 get = function(n)
410 return '*static_cast<'..c.xarg.fullname..'*>'
411 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
412 end,
413 test = function(n)
414 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
415 end,
417 if c.constructors.copy~='private' then -- and c.destructor~='private' then
418 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
419 types[c.xarg.fullname] = {
420 -- the argument is the class itself
421 push = function(n)
422 return 'lqtL_passudata(L, new '..shellname
423 ..'(L, '..n..'), "'..c.xarg.fullname..'*")', 1
424 end,
425 get = function(n)
426 return '*static_cast<'..c.xarg.fullname..'*>'
427 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
428 end,
429 test = function(n)
430 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
431 end,
433 types[c.xarg.fullname..' const&'] = {
434 -- the argument is a pointer to class
435 push = function(n)
436 return 'lqtL_passudata(L, new '..shellname
437 ..'(L, '..n..'), "'..c.xarg.fullname..'*")', 1
438 end,
439 get = function(n)
440 return '*static_cast<'..c.xarg.fullname..'*>'
441 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
442 end,
443 test = function(n)
444 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
445 end,
447 else
448 --io.stderr:write(c.xarg.fullname, ': no copy constructor\n')
450 else
451 --io.stderr:write(c.xarg.fullname, ': already present\n')
454 return ret
457 local fill_wrapper_code = function(f, types)
458 local stackn, argn = 1, 1
459 local wrap, line = '', ''
460 if f.xarg.member_of_class and f.xarg.static~='1' then
461 if not types[f.xarg.member_of_class..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
462 local sget, sn = types[f.xarg.member_of_class..'*'].get(stackn)
463 wrap = wrap .. ' ' .. f.xarg.member_of_class .. '* self = ' .. sget .. ';\n'
464 stackn = stackn + sn
465 wrap = wrap .. [[
466 if (NULL==self) {
467 lua_pushstring(L, "this pointer is NULL");
468 lua_error(L);
471 --print(sget, sn)
472 line = 'self->'..f.xarg.fullname..'('
473 else
474 line = f.xarg.fullname..'('
476 for i, a in ipairs(f.arguments) do
477 if not types[a.xarg.type_name] then return nil end
478 local aget, an = types[a.xarg.type_name].get(stackn)
479 wrap = wrap .. ' ' .. a.xarg.type_name .. ' arg' .. tostring(argn) .. ' = '
480 if a.xarg.default=='1' and an>0 then
481 wrap = wrap .. 'lua_isnoneornil(L, '..stackn..')'
482 for j = stackn+1,stackn+an-1 do
483 wrap = wrap .. ' && lua_isnoneornil(L, '..j..')'
485 local dv = a.xarg.defaultvalue
486 wrap = wrap .. ' ? static_cast< ' .. a.xarg.type_name .. ' >(' .. dv .. ') : '
488 wrap = wrap .. aget .. ';\n'
489 line = line .. (argn==1 and 'arg' or ', arg') .. argn
490 stackn = stackn + an
491 argn = argn + 1
493 line = line .. ')'
494 -- FIXME: hack follows for constructors
495 if f.calling_line then line = f.calling_line end
496 if f.return_type then line = f.return_type .. ' ret = ' .. line end
497 wrap = wrap .. ' ' .. line .. ';\n lua_settop(L, 0);\n' -- lua_pop(L, '..stackn..');\n'
498 if f.return_type then
499 if not types[f.return_type] then return nil end
500 local rput, rn = types[f.return_type].push'ret'
501 wrap = wrap .. ' luaL_checkstack(L, '..rn..', "cannot grow stack for return value");\n'
502 wrap = wrap .. ' '..rput..';\n return '..rn..';\n'
503 else
504 wrap = wrap .. ' return 0;\n'
506 f.wrapper_code = wrap
507 return f
510 local fill_test_code = function(f, types)
511 local stackn = 1
512 local test = ''
513 if f.xarg.member_of_class and f.xarg.static~='1' then
514 if not types[f.xarg.member_of_class..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
515 local stest, sn = types[f.xarg.member_of_class..'*'].test(stackn)
516 test = test .. ' && ' .. stest
517 stackn = stackn + sn
519 for i, a in ipairs(f.arguments) do
520 if not types[a.xarg.type_name] then return nil end -- print(a.xarg.type_name) return nil end
521 local atest, an = types[a.xarg.type_name].test(stackn)
522 if a.xarg.default=='1' and an>0 then
523 test = test .. ' && (lqtL_missarg(L, ' .. stackn .. ', ' .. an .. ') || '
524 test = test .. atest .. ')'
525 else
526 test = test .. ' && ' .. atest
528 stackn = stackn + an
530 -- can't make use of default values if I fix number of args
531 test = '(lua_gettop(L)<' .. stackn .. ')' .. test
532 f.test_code = test
533 return f
536 local fill_wrappers = function(functions, types)
537 local ret = {}
538 for f in pairs(functions) do
539 f = fill_wrapper_code(f, types)
540 if f then
541 f = assert(fill_test_code(f, types), f.xarg.fullname) -- MUST pass
542 ret[f] = true
543 local out = 'extern "C" int lqt_bind'..f.xarg.id..' (lua_State *L) {\n'
544 .. f.wrapper_code .. '}\n'
545 --print(out)
548 return ret
551 local argument_name = function(tn, an)
552 local ret
553 if string.match(tn, '%(%*%)') then
554 ret = string.gsub(tn, '%(%*%)', '(*'..an..')', 1)
555 elseif string.match(tn, '%[.*%]') then
556 ret = string.gsub(tn, '(%[.*%])', an..'%1')
557 else
558 ret = tn .. ' ' .. an
560 return ret
563 local virtual_overload = function(v, types)
564 local ret = ''
565 if v.virtual_overload then return v end
566 -- make return type
567 if v.return_type and not types[v.return_type] then return nil end
568 local rget, rn = '', 0
569 if v.return_type then rget, rn = types[v.return_type].get'oldtop+1' end
570 local retget = (v.return_type and argument_name(v.return_type, 'ret')
571 .. ' = ' .. rget .. ';' or '') .. 'lua_settop(L, oldtop);return'
572 .. (v.return_type and ' ret' or '')
573 -- make argument push
574 local pushlines, stack = '', 0
575 for i, a in ipairs(v.arguments) do
576 if not types[a.xarg.type_name] then return nil end
577 local apush, an = types[a.xarg.type_name].push('arg'..i)
578 pushlines = pushlines .. ' ' .. apush .. ';\n'
579 stack = stack + an
581 -- make lua call
582 local luacall = 'lua_pcall(L, '..stack..', '..rn..', 0)'
583 -- make prototype and fallback
584 local proto = (v.return_type or 'void')..' ;;'..v.xarg.name..' ('
585 local fallback = ''
586 for i, a in ipairs(v.arguments) do
587 proto = proto .. (i>1 and ', ' or '')
588 .. argument_name(a.xarg.type_name, 'arg'..i)
589 fallback = fallback .. (i>1 and ', arg' or 'arg') .. i
591 proto = proto .. ')' .. (v.xarg.constant=='1' and ' const' or '')
592 fallback = (v.return_type and 'return this->' or 'this->')
593 .. v.xarg.fullname .. '(' .. fallback .. ');\n}\n'
594 ret = proto .. [[ {
595 int oldtop = lua_gettop(L);
596 lqtL_pushudata(L, this, "]]..v.xarg.member_of_class..[[*");
597 lua_getfield(L, -1, "]]..v.xarg.name..[[");
598 if (lua_isfunction(L, -1)) {
599 lua_insert(L, -2);
600 ]] .. pushlines .. [[
601 if (]]..luacall..[[) {
602 ]]..retget..[[;
605 lua_settop(L, oldtop);
606 ]] .. fallback
607 v.virtual_overload = ret
608 v.virtual_proto = string.gsub(proto, ';;', '', 1)
609 return v
612 local fill_shell_class = function(c, types)
613 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
614 local shell = 'class ' .. shellname .. ' : public ' .. c.xarg.fullname .. ' {\npublic:\n'
615 shell = shell .. ' lua_State *L;\n'
616 for _, constr in ipairs(c.constructors) do
617 if constr.xarg.access~='private' then
618 local cline = ' '..shellname..' (lua_State *l'
619 local argline = ''
620 for i, a in ipairs(constr.arguments) do
621 cline = cline .. ', ' .. argument_name(a.xarg.type_name, 'arg'..i)
622 argline = argline .. (i>1 and ', arg' or 'arg') .. i
624 cline = cline .. ') : ' .. c.xarg.fullname
625 .. '(' .. argline .. '), L(l) '
626 .. '{ lqtL_register(L, this); }\n'
627 shell = shell .. cline
630 if c.constructors.copy=='auto' then
631 local cline = ' '..shellname..' (lua_State *l, '..c.xarg.fullname..' const& arg1)'
632 cline = cline .. ' : ' .. c.xarg.fullname .. '(arg1), L(l) {}\n'
633 shell = shell .. cline
635 for i, v in pairs(c.virtuals) do
636 if v.xarg.access~='private' then
637 local vret = virtual_overload(v, types)
638 if v.virtual_proto then shell = shell .. ' virtual ' .. v.virtual_proto .. ';\n' end
641 shell = shell .. ' ~'..shellname..'() { lqtL_unregister(L, this); }\n'
642 shell = shell .. '};\n'
643 c.shell_class = shell
644 return c
647 local fill_shell_classes = function(classes, types)
648 local ret = {}
649 for c in pairs(classes) do
650 if c.shell then
651 c = fill_shell_class(c, types)
652 if c then ret[c] = true else error(c.xarg.fullname) end
655 return ret
658 local print_shell_classes = function(classes)
659 for c in pairs(classes) do
660 if c.shell then
661 if c then
662 hpp(c.shell_class)
663 else
664 --io.stderr:write(c.fullname, '\n')
668 return classes
671 local print_virtual_overloads = function(classes)
672 for c in pairs(classes) do
673 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
674 for _,v in pairs(c.virtuals) do
675 if v.virtual_overload then
676 cpp((string.gsub(v.virtual_overload, ';;', shellname..'::', 1)))
680 return classes
683 local print_wrappers = function(index)
684 for c in pairs(index) do
685 local meta = {}
686 for _, f in ipairs(c.methods) do
687 if f.wrapper_code then
688 local out = 'extern "C" int lqt_bind'..f.xarg.id
689 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
690 if f.xarg.access=='public' then
691 cpp(out)
692 meta[f] = f.xarg.name
696 if c.shell then
697 for _, f in ipairs(c.constructors) do
698 if f.wrapper_code then
699 local out = 'extern "C" int lqt_bind'..f.xarg.id
700 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
701 if f.xarg.access=='public' then
702 cpp(out)
703 meta[f] = 'new'
707 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
708 local out = 'extern "C" int lqt_delete'..c.xarg.id..' (lua_State *L) {\n'
709 out = out ..' '..c.xarg.fullname..' *p = static_cast<'
710 ..c.xarg.fullname..'*>(lqtL_toudata(L, 1, "'..c.xarg.fullname..'*"));\n'
711 out = out .. ' if (p) delete p;\n return 0;\n}\n'
712 cpp(out)
714 c.meta = meta
716 return index
719 local print_metatable = function(c)
720 local methods = {}
721 for m, n in pairs(c.meta) do
722 methods[n] = methods[n] or {}
723 table.insert(methods[n], m)
725 for n, l in pairs(methods) do
726 local disp = 'extern "C" int lqt_dispatcher_'..n..c.xarg.id..' (lua_State *L) {\n'
727 for _, f in ipairs(l) do
728 disp = disp..' if ('..f.test_code..') return lqt_bind'..f.xarg.id..'(L);\n'
730 disp = disp .. ' lua_settop(L, 0);\n'
731 disp = disp .. ' lua_pushstring(L, "incorrect or extra arguments");\n'
732 disp = disp .. ' return lua_error(L);\n}\n'
733 cpp(disp)
735 local metatable = 'static luaL_Reg lqt_metatable'..c.xarg.id..'[] = {\n'
736 for n, l in pairs(methods) do
737 metatable = metatable .. ' { "'..n..'", lqt_dispatcher_'..n..c.xarg.id..' },\n'
739 if c.shell then
740 metatable = metatable .. ' { "delete", lqt_delete'..c.xarg.id..' },\n'
742 metatable = metatable .. ' { 0, 0 },\n};\n'
743 cpp(metatable)
744 local bases = ''
745 for b in string.gmatch(c.xarg.bases or '', '([^;]*);') do
746 bases = bases .. '{"' .. b .. '*"}, '
748 bases = 'static lqt_Base lqt_base'..c.xarg.id..'[] = { '..bases..'{NULL} };\n'
749 cpp(bases)
750 return c
753 local print_metatables = function(classes)
754 for c in pairs(classes) do
755 print_metatable(c)
757 return classes
760 local print_class_list = function(classes)
761 local list = 'static lqt_Class lqt_class_list[] = {\n'
762 for c in pairs(classes) do
763 class = '{ lqt_metatable'..c.xarg.id..', lqt_base'..c.xarg.id..', "'..c.xarg.fullname..'*" },\n'
764 list = list .. ' ' .. class
766 list = list .. ' { 0, 0, 0 },\n};\n'
767 cpp(list)
768 return classes
771 local fix_methods_wrappers = function(classes)
772 for c in pairs(classes) do
773 -- if class seems abstract but has a shell class
774 -- FIXME: destructor should not matter?
775 if c.abstract and c.destructor~='private' then
776 -- is it really abstract?
777 local a = false
778 for _, f in pairs(c.virtuals) do
779 -- if it is abstract but we cannot overload
780 if f.xarg.abstract=='1' and not f.virtual_overload then a = true break end
782 c.abstract = a
784 -- FIXME: destructor should not matter?
785 c.shell = (not c.abstract) and (c.destructor~='private')
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 .. ')'
795 return classes
798 local print_enum_tables = function(enums)
799 for e in pairs(enums) do
800 local table = 'static lqt_Enum lqt_enum'..e.xarg.id..'[] = {\n'
801 --io.stderr:write(e.xarg.fullname, '\t', #e.values, '\n')
802 for _,v in pairs(e.values) do
803 table = table .. ' { "' .. v.xarg.name
804 .. '", static_cast<int>('..v.xarg.fullname..') },\n'
806 table = table .. ' { 0, 0 }\n'
807 table = table .. '};\n'
808 e.enum_table = table
809 cpp(table)
811 return enums
813 local print_enum_creator = function(enums)
814 local out = 'static lqt_Enumlist lqt_enum_list[] = {\n'
815 for e in pairs(enums) do
816 out = out..' { lqt_enum'..e.xarg.id..', "'..e.xarg.fullname..'" },\n'
818 out = out..' { 0, 0 },\n};\n'
819 out = out .. 'extern "C" int lqt_create_enums (lua_State *L) {\n'
820 out = out .. ' lqtL_createenumlist(L, lqt_enum_list); return 0;\n}\n'
821 cpp(out)
822 return enums
825 local print_openmodule = function(n)
826 cpp([[
828 extern "C" int luaopen_]]..n..[[ (lua_State *L) {
829 lqt_create_enums(L);
830 lqtL_createclasses(L, lqt_class_list);
831 return 0;
836 --------------------------------------------------------------------------------------
838 local typesystem = {}
840 local ts = {}
841 for i, ft in ipairs(typefiles) do
842 ts = dofile(ft)
844 setmetatable(typesystem, {
845 __newindex = function(t, k, v)
846 --debug('added type', k)
847 ts[k] = v
848 end,
849 __index = function(t, k)
850 local ret = ts[k]
851 --if not ret then debug("unknown type:", tostring(k), ret) end
852 return ret
853 end,
857 fix_arguments(idindex) -- fixes default arguments if they are context-relative
858 local functions = copy_functions(idindex) -- pics functions and fixes label
859 local functions = fix_functions(functions) -- fixes name and fullname and fills arguments
861 local enums = copy_enums(idindex) -- picks enums if public
862 local enums = fill_enums(enums) -- fills field "values"
864 local classes = copy_classes(idindex) -- picks classes if not private and not blacklisted
865 local classes = fill_virtuals(classes) -- does that, destructor ("~") excluded
866 local classes = fill_special_methods(classes)
867 local classes = fill_copy_constructor(classes)
868 local classes = fix_methods_wrappers(classes)
870 local enums = fill_typesystem_with_enums(enums, typesystem) -- does that
871 local classes = fill_typesystem_with_classes(classes, typesystem)
872 local functions = fill_wrappers(functions, typesystem)
873 local classes = fill_shell_classes(classes, typesystem)
875 ------------- BEGIN OUTPUT
878 hpp('#ifndef LQT_BIND_'..module_name)
879 hpp('#define LQT_BIND_'..module_name)
880 hpp()
881 hpp()
882 for _, i in ipairs(output_includes) do
883 hpp('#include '..i)
885 hpp()
887 cpp('#include "'..tostring(hppname)..'"')
888 cpp()
889 cpp()
891 local classes = print_shell_classes(classes) -- does that
892 local classes = print_virtual_overloads(classes, typesystem) -- does that
893 local classes = print_wrappers(classes) -- does that + FIXME: checks if has shell for constr/destr and compiles metatable list
894 local enums = print_enum_tables(enums) -- does that
895 local enums = print_enum_creator(enums) -- does that + print enum list
896 local classes = print_metatables(classes) -- does that + print dispatchers
897 local classes = print_class_list(classes) -- does that
899 print_openmodule(module_name) -- does that
901 hpp('#endif // LQT_BIND_'..module_name)