binding functions are static
[lqt.git] / generator / generator.lua
blob1a8a35ced4c30accc0957484183f2599630653dc
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 dirname = nil
33 local module_name = nil
34 local typefiles = {}
35 local filterfiles = {}
36 local output_includes = {
37 '"lqt_common.hpp"',
41 local i = 1
42 while select(i, ...) do
43 local argi = select(i, ...)
44 if argi=='-n' then
45 i = i + 1
46 module_name = select(i, ...)
47 elseif argi=='-i' then
48 i = i + 1
49 table.insert(output_includes, (select(i, ...)))
50 elseif argi=='-t' then
51 i = i + 1
52 table.insert(typefiles, (select(i, ...)))
53 elseif argi=='-f' then
54 i = i + 1
55 table.insert(filterfiles, (select(i, ...)))
56 else
57 filename = filename and error'duplicate filename' or argi
58 end
59 i = i + 1
60 end
61 end
63 local readfile = function(fn)
64 local f = assert(io.open(fn))
65 local s = f:read'*a'
66 f:close()
67 return s
68 end
70 local fprint = function(f)
71 return function(...)
72 for i = 1, select('#',...) do
73 f:write((i==1) and '' or '\t', tostring(select(i,...)))
74 end
75 f:write'\n'
76 f:flush()
77 end
78 end
80 local debug = fprint(io.stderr)
81 local print_head = fprint(assert(io.open(module_name..'_src/'..module_name..'_head.hpp', 'w')))
82 local print_enum = fprint(assert(io.open(module_name..'_src/'..module_name..'_enum.cpp', 'w')))
83 local print_virt = fprint(assert(io.open(module_name..'_src/'..module_name..'_virt.cpp', 'w')))
84 local print_type = fprint(assert(io.open(module_name..'_src/'..module_name..'_type.lua', 'w')))
86 local meta_printer
88 local n = 0
89 meta_printer = function()
90 n = n + 1
91 local f = assert(io.open(module_name..'_src/'..module_name..'_meta_'..n..'.cpp', 'w'))
92 f:write('#include "'..module_name..'_head.hpp'..'"\n\n\n')
93 return function(s)
94 if s==nil then
95 f:close()
96 return 0
97 else
98 s = tostring(s)
99 f:write(s, '\n')
100 f:flush()
101 return #s
103 end, n
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 f.return_type = f.xarg.type_name
159 if f.xarg.type_name=='void' then
160 f.return_type = nil
163 return index
166 local copy_enums = function(index)
167 local ret = {}
168 for e in pairs(index) do
169 if e.label=='Enum'
170 and not string.match(e.xarg.fullname, '%b<>')
171 and e.xarg.access=='public' then
172 ret[e] = true
175 return ret
178 local fill_enums = function(index)
179 for e in pairs(index) do
180 local values = {}
181 for _, v in ipairs(e) do
182 if v.label=='Enumerator' then
183 table.insert(values, v)
186 e.values = values
188 return index
191 local copy_classes = function(index)
192 local ret = {}
193 for e in pairs(index) do
194 if e.label=='Class'
195 and e.xarg.access~='private'
196 and not (e.xarg.fullname:match'%b<>'
197 or e.xarg.fullname=='QDebug::Stream'
198 or e.xarg.fullname=='QForeachContainerBase'
199 or e.xarg.fullname=='QByteArray::Data'
200 or e.xarg.fullname=='QVariant::Private::Data'
201 or e.xarg.fullname=='QRegion::QRegionData'
202 or e.xarg.fullname=='QTextStreamManipulator'
203 or e.xarg.fullname=='QString::Data'
204 or e.xarg.fullname=='QThreadStorageData'
205 ) then
206 ret[e] = true
209 return ret
212 local fill_virtuals = function(index)
213 local classes = {}
214 for c in pairs(index) do
215 classes[c.xarg.fullname] = c
217 local get_virtuals
218 get_virtuals = function(c)
219 local ret = {}
220 for _, f in ipairs(c) do
221 if f.label=='Function' and f.xarg.virtual=='1' then
222 local n = string.match(f.xarg.name, '~') or f.xarg.name
223 if n~='~' then ret[n] = f end
226 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
227 local base = classes[b]
228 if type(base)=='table' then
229 local bv = get_virtuals(base)
230 for n, f in pairs(bv) do
231 if not ret[n] then ret[n] = f end
235 for _, f in ipairs(c) do
236 if f.label=='Function'
237 and f.xarg.access~='private'
238 and (ret[string.match(f.xarg.name, '~') or f.xarg.name]) then
239 f.xarg.virtual = '1'
240 local n = string.match(f.xarg.name, '~')or f.xarg.name
241 ret[n] = f
244 return ret
246 for c in pairs(index) do
247 c.virtuals = get_virtuals(c)
248 for _, f in pairs(c.virtuals) do
249 if f.xarg.abstract=='1' then c.abstract=true break end
252 return index
255 local distinguish_methods = function(index)
256 for c in pairs(index) do
257 local construct, destruct, normal = {}, nil, {}
258 local n = c.xarg.name
259 local copy = nil
260 for _, f in ipairs(c) do
261 if n==f.xarg.name then
262 table.insert(construct, f)
263 elseif f.xarg.name:match'~' then
264 destruct = f
265 else
266 if (not string.match(f.xarg.name, '^operator%W'))
267 and (not f.xarg.member_template_parameters) then
268 table.insert(normal, f)
272 c.constructors = construct
273 c.destructor = destruct
274 c.methods = normal
276 return index
279 local fill_public_destr = function(index)
280 local classes = {}
281 for c in pairs(index) do
282 classes[c.xarg.fullname] = c
284 local destr_is_public
285 destr_is_public = function(c)
286 if c.destructor then
287 return c.destructor.xarg.access=='public'
288 else
289 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
290 local base = classes[b]
291 if base and not destr_is_public(base) then
292 return false
295 return true
298 for c in pairs(index) do
299 c.public_destr = destr_is_public(c)
301 return index
304 local fill_copy_constructor = function(index)
305 local classes = {}
306 for c in pairs(index) do
307 classes[c.xarg.name] = c
309 for c in pairs(index) do
310 local copy = nil
311 for _, f in ipairs(c.constructors) do
312 if #(f.arguments)==1
313 and f.arguments[1].xarg.type_name==c.xarg.fullname..' const&' then
314 copy = f
315 break
318 c.copy_constructor = copy
320 local copy_constr_is_public
321 copy_constr_is_public = function(c)
322 if c.copy_constructor then
323 return (c.copy_constructor.xarg.access=='public')
324 or (c.copy_constructor.xarg.access=='protected')
325 else
326 local ret = nil
327 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
328 local base = classes[b]
329 if base and not copy_constr_is_public(base) then
330 return false
333 return true
336 for c in pairs(index) do
337 c.public_constr = copy_constr_is_public(c)
339 return index
342 local typesystem_enum_filler = function(enums)
343 local ret = {}
344 for e in pairs(enums) do
345 local en = e.xarg.fullname
346 table.insert(ret, [[
347 types[']]..en..[['] = {
348 push = function(n)
349 return 'lqtL_pushenum(L, '..n..', "]]..en..[[")', 1
350 end,
351 get = function(n)
352 return 'static_cast<]]..en..[[>'
353 ..'(lqtL_toenum(L, '..n..', "]]..en..[["))', 1
354 end,
355 test = function(n)
356 return 'lqtL_isenum(L, '..n..', "]]..en..[[")', 1
357 end,
361 return ret
364 local fill_typesystem_with_enums = function(enums, types)
365 local etype = function(en)
366 return {
367 push = function(n)
368 return 'lqtL_pushenum(L, '..n..', "'..en..'")', 1
369 end,
370 get = function(n)
371 return 'static_cast<'..en..'>'
372 ..'(lqtL_toenum(L, '..n..', "'..en..'"))', 1
373 end,
374 test = function(n)
375 return 'lqtL_isenum(L, '..n..', "'..en..'")', 1
376 end,
379 local ret = {}
380 for e in pairs(enums) do
381 if types[e.xarg.fullname]==nil then
382 ret[e] = true
383 types[e.xarg.fullname] = etype(e.xarg.fullname)
384 else
385 --io.stderr:write(e.xarg.fullname, ': already present\n')
388 return ret
391 local typesystem_class_filler = function(classes)
392 local pointer_t = function(fn)
393 return [[
394 types[']]..fn..[[*'] = {
395 -- the argument is a pointer to class
396 push = function(n)
397 return 'lqtL_passudata(L, '..n..', "]]..fn..[[*")', 1
398 end,
399 get = function(n)
400 return 'static_cast<]]..fn..[[*>'
401 ..'(lqtL_toudata(L, '..n..', "]]..fn..[[*"))', 1
402 end,
403 test = function(n)
404 return 'lqtL_isudata(L, '..n..', "]]..fn..[[*")', 1
405 end,
409 local pointer_const_t = function(fn)
410 return [[
411 types[']]..fn..[[ const*'] = {
412 -- the argument is a pointer to constant class
413 push = function(n)
414 return 'lqtL_passudata(L, '..n..', "]]..fn..[[*")', 1
415 end,
416 get = function(n)
417 return 'static_cast<]]..fn..[[*>'
418 ..'(lqtL_toudata(L, '..n..', "]]..fn..[[*"))', 1
419 end,
420 test = function(n)
421 return 'lqtL_isudata(L, '..n..', "]]..fn..[[*")', 1
422 end,
426 local ref_t = function(fn)
427 return [[
428 types[']]..fn..[[&'] = {
429 -- the argument is a reference to class
430 push = function(n)
431 return 'lqtL_passudata(L, &'..n..', "]]..fn..[[*")', 1
432 end,
433 get = function(n)
434 return '*static_cast<]]..fn..[[*>'
435 ..'(lqtL_toudata(L, '..n..', "]]..fn..[[*"))', 1
436 end,
437 test = function(n)
438 return 'lqtL_isudata(L, '..n..', "]]..fn..[[*")', 1
439 end,
443 local instance_t = function(fn, sn)
444 return [[
445 types[']]..fn..[['] = {
446 -- the argument is a instance of class
447 push = function(n)
448 return 'lqtL_passudata(L, new ]]..sn
449 ..[[(L, '..n..'), "]]..fn..[[*")', 1
450 end,
451 get = function(n)
452 return '*static_cast<]]..fn..[[*>'
453 ..'(lqtL_toudata(L, '..n..', "]]..fn..[[*"))', 1
454 end,
455 test = function(n)
456 return 'lqtL_isudata(L, '..n..', "]]..fn..[[*")', 1
457 end,
461 local const_ref_t = function(fn, sn)
462 return [[
463 types[']]..fn..[[ const&'] = {
464 -- the argument is a constant ref to class
465 push = function(n)
466 return 'lqtL_passudata(L, new ]]..sn
467 ..[[(L, '..n..'), "]]..fn..[[*")', 1
468 end,
469 get = function(n)
470 return '*static_cast<]]..fn..[[*>'
471 ..'(lqtL_toudata(L, '..n..', "]]..fn..[[*"))', 1
472 end,
473 test = function(n)
474 return 'lqtL_isudata(L, '..n..', "]]..fn..[[*")', 1
475 end,
479 local ret = {}
480 for c in pairs(classes) do
481 local ctype = ''
482 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
483 ctype = ctype .. pointer_t(c.xarg.fullname)
484 ctype = ctype .. pointer_const_t(c.xarg.fullname)
485 ctype = ctype .. ref_t(c.xarg.fullname)
486 if c.public_constr and c.shell then
487 ctype = ctype .. instance_t(c.xarg.fullname, shellname)
488 ctype = ctype .. const_ref_t(c.xarg.fullname, shellname)
489 else
490 ctype = ctype .. 'types["'..c.xarg.fullname..'"] = false\n'
492 table.insert(ret, ctype)
494 return ret
497 local fill_typesystem_with_classes = function(classes, types)
498 local pointer_t = function(fn)
499 return {
500 -- the argument is a pointer to class
501 push = function(n)
502 return 'lqtL_passudata(L, '..n..', "'..fn..'*")', 1
503 end,
504 get = function(n)
505 return 'static_cast<'..fn..'*>'
506 ..'(lqtL_toudata(L, '..n..', "'..fn..'*"))', 1
507 end,
508 test = function(n)
509 return 'lqtL_isudata(L, '..n..', "'..fn..'*")', 1
510 end,
513 local pointer_const_t = function(fn)
514 return {
515 -- the argument is a pointer to constant class instance
516 push = function(n)
517 return 'lqtL_passudata(L, '..n..', "'..fn..'*")', 1
518 end,
519 get = function(n)
520 return 'static_cast<'..fn..'*>'
521 ..'(lqtL_toudata(L, '..n..', "'..fn..'*"))', 1
522 end,
523 test = function(n)
524 return 'lqtL_isudata(L, '..n..', "'..fn..'*")', 1
525 end,
528 local ref_t = function(fn)
529 return {
530 -- the argument is a reference to class
531 push = function(n)
532 return 'lqtL_passudata(L, &'..n..', "'..fn..'*")', 1
533 end,
534 get = function(n)
535 return '*static_cast<'..fn..'*>'
536 ..'(lqtL_toudata(L, '..n..', "'..fn..'*"))', 1
537 end,
538 test = function(n)
539 return 'lqtL_isudata(L, '..n..', "'..fn..'*")', 1
540 end,
543 local instance_t = function(fn, sn)
544 return {
545 -- the argument is the class itself
546 push = function(n)
547 return 'lqtL_passudata(L, new '..sn
548 ..'(L, '..n..'), "'..fn..'*")', 1
549 end,
550 get = function(n)
551 return '*static_cast<'..fn..'*>'
552 ..'(lqtL_toudata(L, '..n..', "'..fn..'*"))', 1
553 end,
554 test = function(n)
555 return 'lqtL_isudata(L, '..n..', "'..fn..'*")', 1
556 end,
559 local const_ref_t = function(fn, sn)
560 return {
561 -- the argument is a pointer to class
562 push = function(n)
563 return 'lqtL_passudata(L, new '..sn
564 ..'(L, '..n..'), "'..fn..'*")', 1
565 end,
566 get = function(n)
567 return '*static_cast<'..fn..'*>'
568 ..'(lqtL_toudata(L, '..n..', "'..fn..'*"))', 1
569 end,
570 test = function(n)
571 return 'lqtL_isudata(L, '..n..', "'..fn..'*")', 1
572 end,
575 local ret = {}
576 for c in pairs(classes) do
577 if types[c.xarg.fullname]==nil then
578 ret[c] = true
579 types[c.xarg.fullname..'*'] = pointer_t(c.xarg.fullname)
580 types[c.xarg.fullname..' const*'] = pointer_const_t(c.xarg.fullname)
581 types[c.xarg.fullname..'&'] = ref_t(c.xarg.fullname)
582 if c.public_constr and c.shell then
583 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
584 types[c.xarg.fullname] = instance_t(c.xarg.fullname, shellname)
585 types[c.xarg.fullname..' const&'] = const_ref_t(c.xarg.fullname, shellname)
589 return ret
592 local argument_name = function(tn, an)
593 local ret
594 if string.match(tn, '%(%*%)') then
595 ret = string.gsub(tn, '%(%*%)', '(*'..an..')', 1)
596 elseif string.match(tn, '%[.*%]') then
597 ret = string.gsub(tn, '(%[.*%])', an..'%1')
598 else
599 ret = tn .. ' ' .. an
601 return ret
604 local fill_wrapper_code = function(f, types)
605 if f.wrapper_code then return f end
606 local stackn, argn = 1, 1
607 local wrap, line = ' int oldtop = lua_gettop(L);\n', ''
608 if f.xarg.abstract then return nil end
609 if f.xarg.member_of_class and f.xarg.static~='1' then
610 if not types[f.xarg.member_of_class..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
611 local sget, sn = types[f.xarg.member_of_class..'*'].get(stackn)
612 wrap = wrap .. ' ' .. f.xarg.member_of_class .. '* self = ' .. sget .. ';\n'
613 stackn = stackn + sn
614 wrap = wrap .. [[
615 if (NULL==self) {
616 lua_pushstring(L, "this pointer is NULL");
617 lua_error(L);
620 --print(sget, sn)
621 line = 'self->'..f.xarg.fullname..'('
622 else
623 line = f.xarg.fullname..'('
625 for i, a in ipairs(f.arguments) do
626 if not types[a.xarg.type_name] then return nil end
627 local aget, an, arg_as = types[a.xarg.type_name].get(stackn)
628 wrap = wrap .. ' ' .. argument_name(arg_as or a.xarg.type_name, 'arg'..argn) .. ' = '
629 if a.xarg.default=='1' and an>0 then
630 wrap = wrap .. 'lua_isnoneornil(L, '..stackn..')'
631 for j = stackn+1,stackn+an-1 do
632 wrap = wrap .. ' && lua_isnoneornil(L, '..j..')'
634 local dv = a.xarg.defaultvalue
635 wrap = wrap .. ' ? static_cast< ' .. a.xarg.type_name .. ' >(' .. dv .. ') : '
637 wrap = wrap .. aget .. ';\n'
638 line = line .. (argn==1 and 'arg' or ', arg') .. argn
639 stackn = stackn + an
640 argn = argn + 1
642 line = line .. ')'
643 -- FIXME: hack follows for constructors
644 if f.calling_line then line = f.calling_line end
645 if f.return_type then line = f.return_type .. ' ret = ' .. line end
646 wrap = wrap .. ' ' .. line .. ';\n lua_settop(L, oldtop);\n' -- lua_pop(L, '..stackn..');\n'
647 if f.return_type then
648 if not types[f.return_type] then return nil end
649 local rput, rn = types[f.return_type].push'ret'
650 wrap = wrap .. ' luaL_checkstack(L, '..rn..', "cannot grow stack for return value");\n'
651 wrap = wrap .. ' '..rput..';\n return '..rn..';\n'
652 else
653 wrap = wrap .. ' return 0;\n'
655 f.wrapper_code = wrap
656 return f
659 local fill_test_code = function(f, types)
660 local stackn = 1
661 local test = ''
662 if f.xarg.member_of_class and f.xarg.static~='1' then
663 if not types[f.xarg.member_of_class..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
664 local stest, sn = types[f.xarg.member_of_class..'*'].test(stackn)
665 test = test .. ' && ' .. stest
666 stackn = stackn + sn
668 for i, a in ipairs(f.arguments) do
669 if not types[a.xarg.type_name] then return nil end -- print(a.xarg.type_name) return nil end
670 local atest, an = types[a.xarg.type_name].test(stackn)
671 if a.xarg.default=='1' and an>0 then
672 test = test .. ' && (lqtL_missarg(L, ' .. stackn .. ', ' .. an .. ') || '
673 test = test .. atest .. ')'
674 else
675 test = test .. ' && ' .. atest
677 stackn = stackn + an
679 -- can't make use of default values if I fix number of args
680 test = '(lua_gettop(L)<' .. stackn .. ')' .. test
681 f.test_code = test
682 return f
685 local fill_wrappers = function(functions, types)
686 local ret = {}
687 for f in pairs(functions) do
688 f = fill_wrapper_code(f, types)
689 if f then
690 f = assert(fill_test_code(f, types), f.xarg.fullname) -- MUST pass
691 ret[f] = true
692 --local out = 'extern "C" int lqt_bind'..f.xarg.id..' (lua_State *L) {\n'
693 --.. f.wrapper_code .. '}\n'
694 --print(out)
697 return ret
700 local virtual_overload = function(v, types)
701 local ret = ''
702 if v.virtual_overload then return v end
703 -- make return type
704 if v.return_type and not types[v.return_type] then return nil end
705 local rget, rn = '', 0
706 if v.return_type then rget, rn, ret_as = types[v.return_type].get'oldtop+1' end
707 local retget = (v.return_type and argument_name(ret_as or v.return_type, 'ret')
708 .. ' = ' .. rget .. ';' or '') .. 'lua_settop(L, oldtop);return'
709 .. (v.return_type and ' ret' or '')
710 -- make argument push
711 local pushlines, stack = '', 0
712 for i, a in ipairs(v.arguments) do
713 if not types[a.xarg.type_name] then return nil end
714 local apush, an = types[a.xarg.type_name].push('arg'..i)
715 pushlines = pushlines .. ' ' .. apush .. ';\n'
716 stack = stack + an
718 -- make lua call
719 local luacall = 'lua_pcall(L, '..(stack+1)..', '..rn..', 0)'
720 -- make prototype and fallback
721 local proto = (v.return_type or 'void')..' ;;'..v.xarg.name..' ('
722 local fallback = ''
723 for i, a in ipairs(v.arguments) do
724 proto = proto .. (i>1 and ', ' or '')
725 .. argument_name(a.xarg.type_name, 'arg'..i)
726 fallback = fallback .. (i>1 and ', arg' or 'arg') .. i
728 proto = proto .. ')' .. (v.xarg.constant=='1' and ' const' or '')
729 fallback = (v.return_type and 'return this->' or 'this->')
730 .. v.xarg.fullname .. '(' .. fallback .. ');\n}\n'
731 ret = proto .. [[ {
732 int oldtop = lua_gettop(L);
733 lqtL_pushudata(L, this, "]]..v.xarg.member_of_class..[[*");
734 lua_getfield(L, -1, "]]..v.xarg.name..[[");
735 if (lua_isfunction(L, -1)) {
736 lua_insert(L, -2);
737 ]] .. pushlines .. [[
738 if (!]]..luacall..[[) {
739 ]]..retget..[[;
742 lua_settop(L, oldtop);
743 ]] .. fallback
744 v.virtual_overload = ret
745 v.virtual_proto = string.gsub(proto, ';;', '', 1)
746 return v
749 local fill_shell_class = function(c, types)
750 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
751 local shell = 'class ' .. shellname .. ' : public ' .. c.xarg.fullname .. ' {\npublic:\n'
752 shell = shell .. ' lua_State *L;\n'
753 for _, constr in ipairs(c.constructors) do
754 if constr.xarg.access~='private' then
755 local cline = ' '..shellname..' (lua_State *l'
756 local argline = ''
757 for i, a in ipairs(constr.arguments) do
758 cline = cline .. ', ' .. argument_name(a.xarg.type_name, 'arg'..i)
759 argline = argline .. (i>1 and ', arg' or 'arg') .. i
761 cline = cline .. ') : ' .. c.xarg.fullname
762 .. '(' .. argline .. '), L(l) '
763 .. '{ lqtL_register(L, this); }\n'
764 shell = shell .. cline
767 if c.copy_constructor==nil and c.public_constr then
768 local cline = ' '..shellname..' (lua_State *l, '..c.xarg.fullname..' const& arg1)'
769 cline = cline .. ' : ' .. c.xarg.fullname .. '(arg1), L(l) {}\n'
770 shell = shell .. cline
772 for i, v in pairs(c.virtuals) do
773 if v.xarg.access~='private' then
774 if v.virtual_proto then shell = shell .. ' virtual ' .. v.virtual_proto .. ';\n' end
777 shell = shell .. ' ~'..shellname..'() { lqtL_unregister(L, this); }\n'
778 shell = shell .. '};\n'
779 c.shell_class = shell
780 return c
783 local fill_virtual_overloads = function(classes, types)
784 for c in pairs(classes) do
785 for i, v in pairs(c.virtuals) do
786 if v.xarg.access~='private' then
787 local vret = virtual_overload(v, types)
791 return classes
794 local fill_shell_classes = function(classes, types)
795 local ret = {}
796 for c in pairs(classes) do
797 if c.shell then
798 c = fill_shell_class(c, types)
799 if c then ret[c] = true end
801 ret[c] = true
803 return ret
806 local print_shell_classes = function(classes)
807 for c in pairs(classes) do
808 if c.shell then
809 if c then
810 print_head(c.shell_class)
811 else
812 --io.stderr:write(c.fullname, '\n')
816 return classes
819 local print_virtual_overloads = function(classes)
820 for c in pairs(classes) do
821 if c.shell then
822 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
823 for _,v in pairs(c.virtuals) do
824 if v.virtual_overload then
825 print_virt((string.gsub(v.virtual_overload, ';;', shellname..'::', 1)))
830 return classes
833 local print_wrappers = function(index)
834 for c in pairs(index) do
835 local meta = {}
836 local wrappers = ''
837 for _, f in ipairs(c.methods) do
838 if f.wrapper_code then
839 local out = 'static int lqt_bind'..f.xarg.id
840 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
841 if f.xarg.access=='public' then
842 --print_meta(out)
843 wrappers = wrappers .. out .. '\n'
844 meta[f] = f.xarg.name
848 if c.shell then
849 for _, f in ipairs(c.constructors) do
850 if f.wrapper_code then
851 local out = 'static int lqt_bind'..f.xarg.id
852 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
853 if f.xarg.access=='public' then
854 --print_meta(out)
855 wrappers = wrappers .. out .. '\n'
856 meta[f] = 'new'
860 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
861 local out = 'static int lqt_delete'..c.xarg.id..' (lua_State *L) {\n'
862 out = out ..' '..c.xarg.fullname..' *p = static_cast<'
863 ..c.xarg.fullname..'*>(lqtL_toudata(L, 1, "'..c.xarg.fullname..'*"));\n'
864 out = out .. ' if (p) delete p;\n return 0;\n}\n'
865 --print_meta(out)
866 wrappers = wrappers .. out .. '\n'
868 c.meta = meta
869 c.wrappers = wrappers
871 return index
874 local print_metatable = function(c)
875 local methods = {}
876 local wrappers = c.wrappers
877 for m, n in pairs(c.meta) do
878 methods[n] = methods[n] or {}
879 table.insert(methods[n], m)
881 for n, l in pairs(methods) do
882 local disp = 'static int lqt_dispatcher_'..n..c.xarg.id..' (lua_State *L) {\n'
883 for _, f in ipairs(l) do
884 disp = disp..' if ('..f.test_code..') return lqt_bind'..f.xarg.id..'(L);\n'
886 disp = disp .. ' lua_settop(L, 0);\n'
887 disp = disp .. ' lua_pushstring(L, "incorrect or extra arguments");\n'
888 disp = disp .. ' return lua_error(L);\n}\n'
889 --print_meta(disp)
890 wrappers = wrappers .. disp .. '\n'
892 local metatable = 'static luaL_Reg lqt_metatable'..c.xarg.id..'[] = {\n'
893 for n, l in pairs(methods) do
894 metatable = metatable .. ' { "'..n..'", lqt_dispatcher_'..n..c.xarg.id..' },\n'
896 if c.shell then
897 metatable = metatable .. ' { "delete", lqt_delete'..c.xarg.id..' },\n'
899 metatable = metatable .. ' { 0, 0 },\n};\n'
900 --print_meta(metatable)
901 wrappers = wrappers .. metatable .. '\n'
902 local bases = ''
903 for b in string.gmatch(c.xarg.bases or '', '([^;]*);') do
904 bases = bases .. '{"' .. b .. '*"}, '
906 bases = 'static lqt_Base lqt_base'..c.xarg.id..'[] = { '..bases..'{NULL} };\n'
907 --print_meta(bases)
908 wrappers = wrappers .. bases .. '\n'
909 c.wrappers = wrappers
910 return c
913 local print_metatables = function(classes)
914 for c in pairs(classes) do
915 print_metatable(c)
917 return classes
920 local print_class_list = function(classes)
921 local print_meta, n, lines, list
922 local begin = function()
923 print_meta, n = meta_printer()
924 lines = 0
925 list = 'static lqt_Class lqt_class_list_'..n..'[] = {\n'
927 local finish = function()
928 list = list .. ' { 0, 0, 0 },\n};\n'
929 .. 'void lqtopen_meta_'..n..' (lua_State *L) {\n'
930 .. ' lqtL_createclasses(L, lqt_class_list_'..n..');\n}'
932 -- begin
933 begin()
934 for c in pairs(classes) do
935 class = '{ lqt_metatable'..c.xarg.id..', lqt_base'..c.xarg.id..', "'..c.xarg.fullname..'*" },\n'
936 list = list .. ' ' .. class
937 lines = lines + print_meta(c.wrappers)
938 if lines > 100000 then
939 finish()
940 print_meta(list)
941 begin()
944 finish()
945 print_meta(list)
946 for i = 1, n do
947 print_meta('void lqtopen_meta_'..i..'(lua_State *);\n')
949 print_meta([[
951 void lqt_create_enums_]]..module_name..[[(lua_State*);
953 extern "C" int luaopen_]]..module_name..[[ (lua_State *L) {
954 lqt_create_enums_]]..module_name..[[(L);]])
955 for i = 1, n do
956 print_meta(' lqtopen_meta_'..i..'(L);')
958 print_meta(' return 0;\n}\n')
959 return classes
962 local fix_methods_wrappers = function(classes)
963 for c in pairs(classes) do
964 -- if class seems abstract but has a shell class
965 if c.abstract then
966 -- is it really abstract?
967 local a = false
968 for _, f in pairs(c.virtuals) do
969 -- if it is abstract but we cannot overload
970 -- FIXME: this always fails: f.virtual_overload is not filled yet
971 -- maybe this check must be moved later:
972 -- we don't use shell class to move instances to Lua
973 -- but we want to instantiate if we can wrap all virtuals...
974 if f.xarg.abstract=='1' and not f.virtual_overload then a = true break end
976 c.abstract = a
978 c.shell = (not c.abstract) and c.public_destr
979 for _, constr in ipairs(c.constructors) do
980 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
981 constr.calling_line = '*new '..shellname..'(L'
982 for i=1,#(constr.arguments) do
983 constr.calling_line = constr.calling_line .. ', arg' .. i
985 constr.calling_line = constr.calling_line .. ')'
986 constr.xarg.static = '1'
987 constr.return_type = constr.xarg.type_base..'&'
989 if c.destructor then
990 c.destructor.return_type = nil
993 return classes
996 local print_enum_tables = function(enums)
997 for e in pairs(enums) do
998 local table = 'static lqt_Enum lqt_enum'..e.xarg.id..'[] = {\n'
999 --io.stderr:write(e.xarg.fullname, '\t', #e.values, '\n')
1000 for _,v in pairs(e.values) do
1001 table = table .. ' { "' .. v.xarg.name
1002 .. '", static_cast<int>('..v.xarg.fullname..') },\n'
1004 table = table .. ' { 0, 0 }\n'
1005 table = table .. '};\n'
1006 e.enum_table = table
1007 print_enum(table)
1009 return enums
1011 local print_enum_creator = function(enums, n)
1012 local out = 'static lqt_Enumlist lqt_enum_list[] = {\n'
1013 for e in pairs(enums) do
1014 out = out..' { lqt_enum'..e.xarg.id..', "'..e.xarg.fullname..'" },\n'
1016 out = out..' { 0, 0 },\n};\n'
1017 out = out .. 'void lqt_create_enums_'..n..' (lua_State *L) {\n'
1018 out = out .. ' lqtL_createenumlist(L, lqt_enum_list); return;\n}\n'
1019 print_enum(out)
1020 return enums
1023 --------------------------------------------------------------------------------------
1025 local typesystem = {}
1027 local ts = {}
1028 for i, ft in ipairs(typefiles) do
1029 ts = loadfile(ft)(ts)
1031 setmetatable(typesystem, {
1032 __newindex = function(t, k, v)
1033 --debug('added type', k)
1034 ts[k] = v
1035 end,
1036 __index = function(t, k)
1037 local ret = ts[k]
1038 --if not ret then debug("unknown type:", tostring(k), ret) end
1039 return ret
1040 end,
1044 fix_arguments(idindex) -- fixes default arguments if they are context-relative
1045 local functions = copy_functions(idindex) -- picks functions and fixes label
1046 local functions = fix_functions(functions) -- fixes name and fullname and fills arguments
1048 local enums = copy_enums(idindex) -- picks enums if public
1049 local enums = fill_enums(enums) -- fills field "values"
1051 local classes = copy_classes(idindex) -- picks classes if not private and not blacklisted
1052 local classes = fill_virtuals(classes) -- does that, destructor ("~") excluded
1053 local classes = distinguish_methods(classes) -- does that
1054 local classes = fill_public_destr(classes) -- does that: checks if destructor is public
1055 local classes = fill_copy_constructor(classes) -- does that: checks if copy contructor is public or protected
1056 local classes = fix_methods_wrappers(classes)
1058 for _, f in ipairs(filterfiles) do
1059 classes, enums = loadfile(f)(classes, enums)
1062 local enums = fill_typesystem_with_enums(enums, typesystem) -- does that
1063 local classes = fill_typesystem_with_classes(classes, typesystem)
1065 local functions = fill_wrappers(functions, typesystem)
1066 local classes = fill_virtual_overloads(classes, typesystem) -- does that
1067 local classes = fill_shell_classes(classes, typesystem) -- does that
1070 ------------- BEGIN OUTPUT
1073 print_head('#ifndef LQT_BIND_'..module_name)
1074 print_head('#define LQT_BIND_'..module_name)
1075 print_head()
1076 print_head()
1077 for _, i in ipairs(output_includes) do
1078 print_head('#include '..i)
1080 print_head()
1082 print_enum('#include "'..module_name..'_head.hpp'..'"\n\n')
1083 print_virt('#include "'..module_name..'_head.hpp'..'"\n\n')
1085 print_type'local types = ... or {}\n'
1086 for i, v in ipairs(typesystem_enum_filler(enums)) do
1087 print_type(v)
1089 for i, v in ipairs(typesystem_class_filler(classes)) do
1090 print_type(v)
1092 print_type'return types\n'
1094 local classes = print_shell_classes(classes) -- does that
1095 local classes = print_virtual_overloads(classes, typesystem) -- does that
1096 local enums = print_enum_tables(enums) -- does that
1097 local enums = print_enum_creator(enums, module_name) -- does that + print enum list
1098 local classes = print_wrappers(classes) -- does that + compiles metatable list
1099 local classes = print_metatables(classes) -- does that + print dispatchers
1100 local classes = print_class_list(classes) -- does that
1102 --print_openmodule(module_name) -- does that
1104 print_head('#endif // LQT_BIND_'..module_name)