fixed typo in comment
[lqt.git] / generator / generator.lua
blobd4dd81d5cf88865870b7a658d3b109df063da6f9
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 distinguish_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 table.insert(construct, f)
284 elseif f.xarg.name:match'~' then
285 destruct = f
286 else
287 if (not string.match(f.xarg.name, '^operator%W'))
288 and (not f.xarg.member_template_parameters) then
289 table.insert(normal, f)
293 c.constructors = construct
294 c.destructor = destruct
295 c.methods = normal
297 return index
300 local fill_public_destr = function(index)
301 local classes = {}
302 for c in pairs(index) do
303 classes[c.xarg.fullname] = c
305 local destr_is_public
306 destr_is_public = function(c)
307 if c.destructor then
308 return c.destructor.xarg.access=='public'
309 else
310 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
311 local base = classes[b]
312 if base and not destr_is_public(base) then
313 return false
316 return true
319 for c in pairs(index) do
320 c.public_destr = destr_is_public(c)
322 return index
325 local fill_copy_constructor = function(index)
326 local classes = {}
327 for c in pairs(index) do
328 classes[c.xarg.name] = c
330 for c in pairs(index) do
331 local copy = nil
332 for _, f in ipairs(c.constructors) do
333 if #(f.arguments)==1
334 and f.arguments[1].xarg.type_name==c.xarg.fullname..' const&' then
335 copy = f
336 break
339 c.copy_constructor = copy
341 local copy_constr_is_public
342 copy_constr_is_public = function(c)
343 if c.copy_constructor then
344 return (c.copy_constructor.xarg.access=='public')
345 or (c.copy_constructor.xarg.access=='protected')
346 else
347 local ret = nil
348 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
349 local base = classes[b]
350 if base and not copy_constr_is_public(base) then
351 return false
354 return true
357 for c in pairs(index) do
358 c.public_constr = copy_constr_is_public(c)
360 return index
363 local fill_typesystem_with_enums = function(enums, types)
364 local ret = {}
365 for e in pairs(enums) do
366 if not types[e.xarg.fullname] then
367 ret[e] = true
368 types[e.xarg.fullname] = {
369 push = function(n)
370 return 'lqtL_pushenum(L, '..n..', "'..e.xarg.fullname..'")', 1
371 end,
372 get = function(n)
373 return 'static_cast<'..e.xarg.fullname..'>'
374 ..'(lqtL_toenum(L, '..n..', "'..e.xarg.fullname..'"))', 1
375 end,
376 test = function(n)
377 return 'lqtL_isenum(L, '..n..', "'..e.xarg.fullname..'")', 1
378 end,
380 else
381 --io.stderr:write(e.xarg.fullname, ': already present\n')
384 return ret
387 local fill_typesystem_with_classes = function(classes, types)
388 local ret = {}
389 for c in pairs(classes) do
390 if not types[c.xarg.fullname] then
391 ret[c] = true
392 types[c.xarg.fullname..'*'] = {
393 -- the argument is a pointer to class
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..' const*'] = {
406 -- the argument is a pointer to constant class instance
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 types[c.xarg.fullname..'&'] = {
419 -- the argument is a reference to class
420 push = function(n)
421 return 'lqtL_passudata(L, &'..n..', "'..c.xarg.fullname..'*")', 1
422 end,
423 get = function(n)
424 return '*static_cast<'..c.xarg.fullname..'*>'
425 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
426 end,
427 test = function(n)
428 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
429 end,
431 if c.public_constr and c.shell then
432 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
433 types[c.xarg.fullname] = {
434 -- the argument is the class itself
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 types[c.xarg.fullname..' const&'] = {
448 -- the argument is a pointer to class
449 push = function(n)
450 return 'lqtL_passudata(L, new '..shellname
451 ..'(L, '..n..'), "'..c.xarg.fullname..'*")', 1
452 end,
453 get = function(n)
454 return '*static_cast<'..c.xarg.fullname..'*>'
455 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
456 end,
457 test = function(n)
458 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
459 end,
464 return ret
467 local fill_wrapper_code = function(f, types)
468 if f.wrapper_code then return f end
469 local stackn, argn = 1, 1
470 local wrap, line = '', ''
471 if f.xarg.member_of_class and f.xarg.static~='1' then
472 if not types[f.xarg.member_of_class..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
473 local sget, sn = types[f.xarg.member_of_class..'*'].get(stackn)
474 wrap = wrap .. ' ' .. f.xarg.member_of_class .. '* self = ' .. sget .. ';\n'
475 stackn = stackn + sn
476 wrap = wrap .. [[
477 if (NULL==self) {
478 lua_pushstring(L, "this pointer is NULL");
479 lua_error(L);
482 --print(sget, sn)
483 line = 'self->'..f.xarg.fullname..'('
484 else
485 line = f.xarg.fullname..'('
487 for i, a in ipairs(f.arguments) do
488 if not types[a.xarg.type_name] then return nil end
489 local aget, an = types[a.xarg.type_name].get(stackn)
490 wrap = wrap .. ' ' .. a.xarg.type_name .. ' arg' .. tostring(argn) .. ' = '
491 if a.xarg.default=='1' and an>0 then
492 wrap = wrap .. 'lua_isnoneornil(L, '..stackn..')'
493 for j = stackn+1,stackn+an-1 do
494 wrap = wrap .. ' && lua_isnoneornil(L, '..j..')'
496 local dv = a.xarg.defaultvalue
497 wrap = wrap .. ' ? static_cast< ' .. a.xarg.type_name .. ' >(' .. dv .. ') : '
499 wrap = wrap .. aget .. ';\n'
500 line = line .. (argn==1 and 'arg' or ', arg') .. argn
501 stackn = stackn + an
502 argn = argn + 1
504 line = line .. ')'
505 -- FIXME: hack follows for constructors
506 if f.calling_line then line = f.calling_line end
507 if f.return_type then line = f.return_type .. ' ret = ' .. line end
508 wrap = wrap .. ' ' .. line .. ';\n lua_settop(L, 0);\n' -- lua_pop(L, '..stackn..');\n'
509 if f.return_type then
510 if not types[f.return_type] then return nil end
511 local rput, rn = types[f.return_type].push'ret'
512 wrap = wrap .. ' luaL_checkstack(L, '..rn..', "cannot grow stack for return value");\n'
513 wrap = wrap .. ' '..rput..';\n return '..rn..';\n'
514 else
515 wrap = wrap .. ' return 0;\n'
517 f.wrapper_code = wrap
518 return f
521 local fill_test_code = function(f, types)
522 local stackn = 1
523 local test = ''
524 if f.xarg.member_of_class and f.xarg.static~='1' then
525 if not types[f.xarg.member_of_class..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
526 local stest, sn = types[f.xarg.member_of_class..'*'].test(stackn)
527 test = test .. ' && ' .. stest
528 stackn = stackn + sn
530 for i, a in ipairs(f.arguments) do
531 if not types[a.xarg.type_name] then return nil end -- print(a.xarg.type_name) return nil end
532 local atest, an = types[a.xarg.type_name].test(stackn)
533 if a.xarg.default=='1' and an>0 then
534 test = test .. ' && (lqtL_missarg(L, ' .. stackn .. ', ' .. an .. ') || '
535 test = test .. atest .. ')'
536 else
537 test = test .. ' && ' .. atest
539 stackn = stackn + an
541 -- can't make use of default values if I fix number of args
542 test = '(lua_gettop(L)<' .. stackn .. ')' .. test
543 f.test_code = test
544 return f
547 local fill_wrappers = function(functions, types)
548 local ret = {}
549 for f in pairs(functions) do
550 f = fill_wrapper_code(f, types)
551 if f then
552 f = assert(fill_test_code(f, types), f.xarg.fullname) -- MUST pass
553 ret[f] = true
554 local out = 'extern "C" int lqt_bind'..f.xarg.id..' (lua_State *L) {\n'
555 .. f.wrapper_code .. '}\n'
556 --print(out)
559 return ret
562 local argument_name = function(tn, an)
563 local ret
564 if string.match(tn, '%(%*%)') then
565 ret = string.gsub(tn, '%(%*%)', '(*'..an..')', 1)
566 elseif string.match(tn, '%[.*%]') then
567 ret = string.gsub(tn, '(%[.*%])', an..'%1')
568 else
569 ret = tn .. ' ' .. an
571 return ret
574 local virtual_overload = function(v, types)
575 local ret = ''
576 if v.virtual_overload then return v end
577 -- make return type
578 if v.return_type and not types[v.return_type] then return nil end
579 local rget, rn = '', 0
580 if v.return_type then rget, rn = types[v.return_type].get'oldtop+1' end
581 local retget = (v.return_type and argument_name(v.return_type, 'ret')
582 .. ' = ' .. rget .. ';' or '') .. 'lua_settop(L, oldtop);return'
583 .. (v.return_type and ' ret' or '')
584 -- make argument push
585 local pushlines, stack = '', 0
586 for i, a in ipairs(v.arguments) do
587 if not types[a.xarg.type_name] then return nil end
588 local apush, an = types[a.xarg.type_name].push('arg'..i)
589 pushlines = pushlines .. ' ' .. apush .. ';\n'
590 stack = stack + an
592 -- make lua call
593 local luacall = 'lua_pcall(L, '..stack..', '..rn..', 0)'
594 -- make prototype and fallback
595 local proto = (v.return_type or 'void')..' ;;'..v.xarg.name..' ('
596 local fallback = ''
597 for i, a in ipairs(v.arguments) do
598 proto = proto .. (i>1 and ', ' or '')
599 .. argument_name(a.xarg.type_name, 'arg'..i)
600 fallback = fallback .. (i>1 and ', arg' or 'arg') .. i
602 proto = proto .. ')' .. (v.xarg.constant=='1' and ' const' or '')
603 fallback = (v.return_type and 'return this->' or 'this->')
604 .. v.xarg.fullname .. '(' .. fallback .. ');\n}\n'
605 ret = proto .. [[ {
606 int oldtop = lua_gettop(L);
607 lqtL_pushudata(L, this, "]]..v.xarg.member_of_class..[[*");
608 lua_getfield(L, -1, "]]..v.xarg.name..[[");
609 if (lua_isfunction(L, -1)) {
610 lua_insert(L, -2);
611 ]] .. pushlines .. [[
612 if (]]..luacall..[[) {
613 ]]..retget..[[;
616 lua_settop(L, oldtop);
617 ]] .. fallback
618 v.virtual_overload = ret
619 v.virtual_proto = string.gsub(proto, ';;', '', 1)
620 return v
623 local fill_shell_class = function(c, types)
624 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
625 local shell = 'class ' .. shellname .. ' : public ' .. c.xarg.fullname .. ' {\npublic:\n'
626 shell = shell .. ' lua_State *L;\n'
627 for _, constr in ipairs(c.constructors) do
628 if constr.xarg.access~='private' then
629 local cline = ' '..shellname..' (lua_State *l'
630 local argline = ''
631 for i, a in ipairs(constr.arguments) do
632 cline = cline .. ', ' .. argument_name(a.xarg.type_name, 'arg'..i)
633 argline = argline .. (i>1 and ', arg' or 'arg') .. i
635 cline = cline .. ') : ' .. c.xarg.fullname
636 .. '(' .. argline .. '), L(l) '
637 .. '{ lqtL_register(L, this); }\n'
638 shell = shell .. cline
641 if c.copy_constructor==nil and c.public_constr then
642 local cline = ' '..shellname..' (lua_State *l, '..c.xarg.fullname..' const& arg1)'
643 cline = cline .. ' : ' .. c.xarg.fullname .. '(arg1), L(l) {}\n'
644 shell = shell .. cline
646 for i, v in pairs(c.virtuals) do
647 if v.xarg.access~='private' then
648 local vret = virtual_overload(v, types)
649 if v.virtual_proto then shell = shell .. ' virtual ' .. v.virtual_proto .. ';\n' end
652 shell = shell .. ' ~'..shellname..'() { lqtL_unregister(L, this); }\n'
653 shell = shell .. '};\n'
654 c.shell_class = shell
655 return c
658 local fill_shell_classes = function(classes, types)
659 local ret = {}
660 for c in pairs(classes) do
661 if c.shell then
662 c = fill_shell_class(c, types)
663 if c then ret[c] = true else error(c.xarg.fullname) end
666 return ret
669 local print_shell_classes = function(classes)
670 for c in pairs(classes) do
671 if c.shell then
672 if c then
673 hpp(c.shell_class)
674 else
675 --io.stderr:write(c.fullname, '\n')
679 return classes
682 local print_virtual_overloads = function(classes)
683 for c in pairs(classes) do
684 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
685 for _,v in pairs(c.virtuals) do
686 if v.virtual_overload then
687 cpp((string.gsub(v.virtual_overload, ';;', shellname..'::', 1)))
691 return classes
694 local print_wrappers = function(index)
695 for c in pairs(index) do
696 local meta = {}
697 for _, f in ipairs(c.methods) 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] = f.xarg.name
707 if c.shell then
708 for _, f in ipairs(c.constructors) do
709 if f.wrapper_code then
710 local out = 'extern "C" int lqt_bind'..f.xarg.id
711 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
712 if f.xarg.access=='public' then
713 cpp(out)
714 meta[f] = 'new'
718 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
719 local out = 'extern "C" int lqt_delete'..c.xarg.id..' (lua_State *L) {\n'
720 out = out ..' '..c.xarg.fullname..' *p = static_cast<'
721 ..c.xarg.fullname..'*>(lqtL_toudata(L, 1, "'..c.xarg.fullname..'*"));\n'
722 out = out .. ' if (p) delete p;\n return 0;\n}\n'
723 cpp(out)
725 c.meta = meta
727 return index
730 local print_metatable = function(c)
731 local methods = {}
732 for m, n in pairs(c.meta) do
733 methods[n] = methods[n] or {}
734 table.insert(methods[n], m)
736 for n, l in pairs(methods) do
737 local disp = 'extern "C" int lqt_dispatcher_'..n..c.xarg.id..' (lua_State *L) {\n'
738 for _, f in ipairs(l) do
739 disp = disp..' if ('..f.test_code..') return lqt_bind'..f.xarg.id..'(L);\n'
741 disp = disp .. ' lua_settop(L, 0);\n'
742 disp = disp .. ' lua_pushstring(L, "incorrect or extra arguments");\n'
743 disp = disp .. ' return lua_error(L);\n}\n'
744 cpp(disp)
746 local metatable = 'static luaL_Reg lqt_metatable'..c.xarg.id..'[] = {\n'
747 for n, l in pairs(methods) do
748 metatable = metatable .. ' { "'..n..'", lqt_dispatcher_'..n..c.xarg.id..' },\n'
750 if c.shell then
751 metatable = metatable .. ' { "delete", lqt_delete'..c.xarg.id..' },\n'
753 metatable = metatable .. ' { 0, 0 },\n};\n'
754 cpp(metatable)
755 local bases = ''
756 for b in string.gmatch(c.xarg.bases or '', '([^;]*);') do
757 bases = bases .. '{"' .. b .. '*"}, '
759 bases = 'static lqt_Base lqt_base'..c.xarg.id..'[] = { '..bases..'{NULL} };\n'
760 cpp(bases)
761 return c
764 local print_metatables = function(classes)
765 for c in pairs(classes) do
766 print_metatable(c)
768 return classes
771 local print_class_list = function(classes)
772 local list = 'static lqt_Class lqt_class_list[] = {\n'
773 for c in pairs(classes) do
774 class = '{ lqt_metatable'..c.xarg.id..', lqt_base'..c.xarg.id..', "'..c.xarg.fullname..'*" },\n'
775 list = list .. ' ' .. class
777 list = list .. ' { 0, 0, 0 },\n};\n'
778 cpp(list)
779 return classes
782 local fix_methods_wrappers = function(classes)
783 for c in pairs(classes) do
784 -- if class seems abstract but has a shell class
785 if c.abstract then
786 -- is it really abstract?
787 local a = false
788 for _, f in pairs(c.virtuals) do
789 -- if it is abstract but we cannot overload
790 -- FIXME: this always fails: f.virtual_overload is not filled yet
791 -- maybe this check must be moved later:
792 -- we don't use shell class to move instances to Lua
793 -- but we want to instantiate if we can wrap all virtuals...
794 if f.xarg.abstract=='1' and not f.virtual_overload then a = true break end
796 c.abstract = a
798 c.shell = (not c.abstract) and c.public_destr
799 for _, constr in ipairs(c.constructors) do
800 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
801 constr.calling_line = '*new '..shellname..'(L'
802 for i=1,#(constr.arguments) do
803 constr.calling_line = constr.calling_line .. ', arg' .. i
805 constr.calling_line = constr.calling_line .. ')'
808 return classes
811 local print_enum_tables = function(enums)
812 for e in pairs(enums) do
813 local table = 'static lqt_Enum lqt_enum'..e.xarg.id..'[] = {\n'
814 --io.stderr:write(e.xarg.fullname, '\t', #e.values, '\n')
815 for _,v in pairs(e.values) do
816 table = table .. ' { "' .. v.xarg.name
817 .. '", static_cast<int>('..v.xarg.fullname..') },\n'
819 table = table .. ' { 0, 0 }\n'
820 table = table .. '};\n'
821 e.enum_table = table
822 cpp(table)
824 return enums
826 local print_enum_creator = function(enums)
827 local out = 'static lqt_Enumlist lqt_enum_list[] = {\n'
828 for e in pairs(enums) do
829 out = out..' { lqt_enum'..e.xarg.id..', "'..e.xarg.fullname..'" },\n'
831 out = out..' { 0, 0 },\n};\n'
832 out = out .. 'extern "C" int lqt_create_enums (lua_State *L) {\n'
833 out = out .. ' lqtL_createenumlist(L, lqt_enum_list); return 0;\n}\n'
834 cpp(out)
835 return enums
838 local print_openmodule = function(n)
839 cpp([[
841 extern "C" int luaopen_]]..n..[[ (lua_State *L) {
842 lqt_create_enums(L);
843 lqtL_createclasses(L, lqt_class_list);
844 return 0;
849 --------------------------------------------------------------------------------------
851 local typesystem = {}
853 local ts = {}
854 for i, ft in ipairs(typefiles) do
855 ts = dofile(ft)
857 setmetatable(typesystem, {
858 __newindex = function(t, k, v)
859 --debug('added type', k)
860 ts[k] = v
861 end,
862 __index = function(t, k)
863 local ret = ts[k]
864 --if not ret then debug("unknown type:", tostring(k), ret) end
865 return ret
866 end,
870 fix_arguments(idindex) -- fixes default arguments if they are context-relative
871 local functions = copy_functions(idindex) -- picks functions and fixes label
872 local functions = fix_functions(functions) -- fixes name and fullname and fills arguments
874 local enums = copy_enums(idindex) -- picks enums if public
875 local enums = fill_enums(enums) -- fills field "values"
877 local classes = copy_classes(idindex) -- picks classes if not private and not blacklisted
878 local classes = fill_virtuals(classes) -- does that, destructor ("~") excluded
879 local classes = distinguish_methods(classes) -- does that
880 local classes = fill_public_destr(classes) -- does that: checks if destructor is public
881 local classes = fill_copy_constructor(classes) -- does that: checks if copy contructor is public or protected
882 local classes = fix_methods_wrappers(classes)
884 local enums = fill_typesystem_with_enums(enums, typesystem) -- does that
885 local classes = fill_typesystem_with_classes(classes, typesystem)
886 local functions = fill_wrappers(functions, typesystem)
887 local classes = fill_shell_classes(classes, typesystem)
889 ------------- BEGIN OUTPUT
892 hpp('#ifndef LQT_BIND_'..module_name)
893 hpp('#define LQT_BIND_'..module_name)
894 hpp()
895 hpp()
896 for _, i in ipairs(output_includes) do
897 hpp('#include '..i)
899 hpp()
901 cpp('#include "'..tostring(hppname)..'"')
902 cpp()
903 cpp()
905 local classes = print_shell_classes(classes) -- does that
906 local classes = print_virtual_overloads(classes, typesystem) -- does that
907 local classes = print_wrappers(classes) -- does that + FIXME: checks if has shell for constr/destr and compiles metatable list
908 local enums = print_enum_tables(enums) -- does that
909 local enums = print_enum_creator(enums) -- does that + print enum list
910 local classes = print_metatables(classes) -- does that + print dispatchers
911 local classes = print_class_list(classes) -- does that
913 print_openmodule(module_name) -- does that
915 hpp('#endif // LQT_BIND_'..module_name)