added the possibility that type.get specifies storage type
[lqt.git] / generator / generator.lua
blob86130af8304d79d12c56f8a4cd54049bcbfc77ee
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_meta = fprint(assert(io.open(module_name..'_src/'..module_name..'_meta.cpp', 'w')))
83 local print_enum = fprint(assert(io.open(module_name..'_src/'..module_name..'_enum.cpp', 'w')))
84 local print_virt = fprint(assert(io.open(module_name..'_src/'..module_name..'_virt.cpp', 'w')))
86 local xmlstream, idindex = dofile(path..'xml.lua')(readfile(filename))
88 ----------------------------------------------------------------------------------
90 local copy_functions = function(index)
91 local ret = {}
92 for e in pairs(index) do
93 if e.label:match'^Function' then
94 e.label = 'Function'
95 ret[e] = true
96 end
97 end
98 return ret
99 end
102 local fix_arguments = function(all)
103 local fullnames = {}
104 for e in pairs(all or {}) do
105 if e.xarg.fullname then fullnames[e.xarg.fullname] = true end
107 for a in pairs(all) do
108 if a.label=='Argument'
109 and a.xarg.default=='1'
110 and string.match(a.xarg.defaultvalue, '%D') then
111 local dv = a.xarg.defaultvalue
112 if not fullnames[dv] then
113 dv = a.xarg.context..'::'..dv
115 if fullnames[dv] then
116 a.xarg.defaultvalue = dv
117 else
118 a.xarg.default = nil
119 a.xarg.defaultvalue = nil
123 return all
126 local fix_functions = function(index)
127 for f in pairs(index) do
128 local args = {}
129 for i, a in ipairs(f) do
130 -- avoid bogus 'void' arguments
131 if a.xarg.type_name=='void' and i==1 and f[2]==nil then break end
132 if a.label=='Argument' then
133 table.insert(args, a)
136 f.arguments = args
137 f.return_type = f.xarg.type_name
138 if f.xarg.type_name=='void' then
139 f.return_type = nil
142 return index
145 local copy_enums = function(index)
146 local ret = {}
147 for e in pairs(index) do
148 if e.label=='Enum'
149 and not string.match(e.xarg.fullname, '%b<>')
150 and e.xarg.access=='public' then
151 ret[e] = true
154 return ret
157 local fill_enums = function(index)
158 for e in pairs(index) do
159 local values = {}
160 for _, v in ipairs(e) do
161 if v.label=='Enumerator' then
162 table.insert(values, v)
165 e.values = values
167 return index
170 local copy_classes = function(index)
171 local ret = {}
172 for e in pairs(index) do
173 if e.label=='Class'
174 and e.xarg.access~='private'
175 and not (e.xarg.fullname:match'%b<>'
176 or e.xarg.fullname=='QDebug::Stream'
177 or e.xarg.fullname=='QForeachContainerBase'
178 or e.xarg.fullname=='QByteArray::Data'
179 or e.xarg.fullname=='QVariant::Private::Data'
180 or e.xarg.fullname=='QRegion::QRegionData'
181 or e.xarg.fullname=='QTextStreamManipulator'
182 or e.xarg.fullname=='QString::Data'
183 or e.xarg.fullname=='QThreadStorageData'
184 ) then
185 ret[e] = true
188 return ret
191 local fill_virtuals = function(index)
192 local classes = {}
193 for c in pairs(index) do
194 classes[c.xarg.fullname] = c
196 local get_virtuals
197 get_virtuals = function(c)
198 local ret = {}
199 for _, f in ipairs(c) do
200 if f.label=='Function' and f.xarg.virtual=='1' then
201 local n = string.match(f.xarg.name, '~') or f.xarg.name
202 if n~='~' then ret[n] = f end
205 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
206 local base = classes[b]
207 if type(base)=='table' then
208 local bv = get_virtuals(base)
209 for n, f in pairs(bv) do
210 if not ret[n] then ret[n] = f end
214 for _, f in ipairs(c) do
215 if f.label=='Function'
216 and f.xarg.access~='private'
217 and (ret[string.match(f.xarg.name, '~') or f.xarg.name]) then
218 f.xarg.virtual = '1'
219 local n = string.match(f.xarg.name, '~')or f.xarg.name
220 ret[n] = f
223 return ret
225 for c in pairs(index) do
226 c.virtuals = get_virtuals(c)
227 for _, f in pairs(c.virtuals) do
228 if f.xarg.abstract=='1' then c.abstract=true break end
231 return index
234 local distinguish_methods = function(index)
235 for c in pairs(index) do
236 local construct, destruct, normal = {}, nil, {}
237 local n = c.xarg.name
238 local copy = nil
239 for _, f in ipairs(c) do
240 if n==f.xarg.name then
241 table.insert(construct, f)
242 elseif f.xarg.name:match'~' then
243 destruct = f
244 else
245 if (not string.match(f.xarg.name, '^operator%W'))
246 and (not f.xarg.member_template_parameters) then
247 table.insert(normal, f)
251 c.constructors = construct
252 c.destructor = destruct
253 c.methods = normal
255 return index
258 local fill_public_destr = function(index)
259 local classes = {}
260 for c in pairs(index) do
261 classes[c.xarg.fullname] = c
263 local destr_is_public
264 destr_is_public = function(c)
265 if c.destructor then
266 return c.destructor.xarg.access=='public'
267 else
268 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
269 local base = classes[b]
270 if base and not destr_is_public(base) then
271 return false
274 return true
277 for c in pairs(index) do
278 c.public_destr = destr_is_public(c)
280 return index
283 local fill_copy_constructor = function(index)
284 local classes = {}
285 for c in pairs(index) do
286 classes[c.xarg.name] = c
288 for c in pairs(index) do
289 local copy = nil
290 for _, f in ipairs(c.constructors) do
291 if #(f.arguments)==1
292 and f.arguments[1].xarg.type_name==c.xarg.fullname..' const&' then
293 copy = f
294 break
297 c.copy_constructor = copy
299 local copy_constr_is_public
300 copy_constr_is_public = function(c)
301 if c.copy_constructor then
302 return (c.copy_constructor.xarg.access=='public')
303 or (c.copy_constructor.xarg.access=='protected')
304 else
305 local ret = nil
306 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
307 local base = classes[b]
308 if base and not copy_constr_is_public(base) then
309 return false
312 return true
315 for c in pairs(index) do
316 c.public_constr = copy_constr_is_public(c)
318 return index
321 local fill_typesystem_with_enums = function(enums, types)
322 local ret = {}
323 for e in pairs(enums) do
324 if not types[e.xarg.fullname] then
325 ret[e] = true
326 types[e.xarg.fullname] = {
327 push = function(n)
328 return 'lqtL_pushenum(L, '..n..', "'..e.xarg.fullname..'")', 1
329 end,
330 get = function(n)
331 return 'static_cast<'..e.xarg.fullname..'>'
332 ..'(lqtL_toenum(L, '..n..', "'..e.xarg.fullname..'"))', 1
333 end,
334 test = function(n)
335 return 'lqtL_isenum(L, '..n..', "'..e.xarg.fullname..'")', 1
336 end,
338 else
339 --io.stderr:write(e.xarg.fullname, ': already present\n')
342 return ret
345 local fill_typesystem_with_classes = function(classes, types)
346 local ret = {}
347 for c in pairs(classes) do
348 if not types[c.xarg.fullname] then
349 ret[c] = true
350 types[c.xarg.fullname..'*'] = {
351 -- the argument is a pointer to class
352 push = function(n)
353 return 'lqtL_passudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
354 end,
355 get = function(n)
356 return 'static_cast<'..c.xarg.fullname..'*>'
357 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
358 end,
359 test = function(n)
360 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
361 end,
363 types[c.xarg.fullname..' const*'] = {
364 -- the argument is a pointer to constant class instance
365 push = function(n)
366 return 'lqtL_passudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
367 end,
368 get = function(n)
369 return 'static_cast<'..c.xarg.fullname..'*>'
370 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
371 end,
372 test = function(n)
373 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
374 end,
376 types[c.xarg.fullname..'&'] = {
377 -- the argument is a reference to class
378 push = function(n)
379 return 'lqtL_passudata(L, &'..n..', "'..c.xarg.fullname..'*")', 1
380 end,
381 get = function(n)
382 return '*static_cast<'..c.xarg.fullname..'*>'
383 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
384 end,
385 test = function(n)
386 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
387 end,
389 if c.public_constr and c.shell then
390 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
391 types[c.xarg.fullname] = {
392 -- the argument is the class itself
393 push = function(n)
394 return 'lqtL_passudata(L, new '..shellname
395 ..'(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 class
407 push = function(n)
408 return 'lqtL_passudata(L, new '..shellname
409 ..'(L, '..n..'), "'..c.xarg.fullname..'*")', 1
410 end,
411 get = function(n)
412 return '*static_cast<'..c.xarg.fullname..'*>'
413 ..'(lqtL_toudata(L, '..n..', "'..c.xarg.fullname..'*"))', 1
414 end,
415 test = function(n)
416 return 'lqtL_isudata(L, '..n..', "'..c.xarg.fullname..'*")', 1
417 end,
422 return ret
425 local argument_name = function(tn, an)
426 local ret
427 if string.match(tn, '%(%*%)') then
428 ret = string.gsub(tn, '%(%*%)', '(*'..an..')', 1)
429 elseif string.match(tn, '%[.*%]') then
430 ret = string.gsub(tn, '(%[.*%])', an..'%1')
431 else
432 ret = tn .. ' ' .. an
434 return ret
437 local fill_wrapper_code = function(f, types)
438 if f.wrapper_code then return f end
439 local stackn, argn = 1, 1
440 local wrap, line = ' int oldtop = lua_gettop(L);\n', ''
441 if f.xarg.abstract then return nil end
442 if f.xarg.member_of_class and f.xarg.static~='1' then
443 if not types[f.xarg.member_of_class..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
444 local sget, sn = types[f.xarg.member_of_class..'*'].get(stackn)
445 wrap = wrap .. ' ' .. f.xarg.member_of_class .. '* self = ' .. sget .. ';\n'
446 stackn = stackn + sn
447 wrap = wrap .. [[
448 if (NULL==self) {
449 lua_pushstring(L, "this pointer is NULL");
450 lua_error(L);
453 --print(sget, sn)
454 line = 'self->'..f.xarg.fullname..'('
455 else
456 line = f.xarg.fullname..'('
458 for i, a in ipairs(f.arguments) do
459 if not types[a.xarg.type_name] then return nil end
460 local aget, an, arg_as = types[a.xarg.type_name].get(stackn)
461 wrap = wrap .. ' ' .. argument_name(arg_as or a.xarg.type_name, 'arg'..argn) .. ' = '
462 if a.xarg.default=='1' and an>0 then
463 wrap = wrap .. 'lua_isnoneornil(L, '..stackn..')'
464 for j = stackn+1,stackn+an-1 do
465 wrap = wrap .. ' && lua_isnoneornil(L, '..j..')'
467 local dv = a.xarg.defaultvalue
468 wrap = wrap .. ' ? static_cast< ' .. a.xarg.type_name .. ' >(' .. dv .. ') : '
470 wrap = wrap .. aget .. ';\n'
471 line = line .. (argn==1 and 'arg' or ', arg') .. argn
472 stackn = stackn + an
473 argn = argn + 1
475 line = line .. ')'
476 -- FIXME: hack follows for constructors
477 if f.calling_line then line = f.calling_line end
478 if f.return_type then line = f.return_type .. ' ret = ' .. line end
479 wrap = wrap .. ' ' .. line .. ';\n lua_settop(L, oldtop);\n' -- lua_pop(L, '..stackn..');\n'
480 if f.return_type then
481 if not types[f.return_type] then return nil end
482 local rput, rn = types[f.return_type].push'ret'
483 wrap = wrap .. ' luaL_checkstack(L, '..rn..', "cannot grow stack for return value");\n'
484 wrap = wrap .. ' '..rput..';\n return '..rn..';\n'
485 else
486 wrap = wrap .. ' return 0;\n'
488 f.wrapper_code = wrap
489 return f
492 local fill_test_code = function(f, types)
493 local stackn = 1
494 local test = ''
495 if f.xarg.member_of_class and f.xarg.static~='1' then
496 if not types[f.xarg.member_of_class..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
497 local stest, sn = types[f.xarg.member_of_class..'*'].test(stackn)
498 test = test .. ' && ' .. stest
499 stackn = stackn + sn
501 for i, a in ipairs(f.arguments) do
502 if not types[a.xarg.type_name] then return nil end -- print(a.xarg.type_name) return nil end
503 local atest, an = types[a.xarg.type_name].test(stackn)
504 if a.xarg.default=='1' and an>0 then
505 test = test .. ' && (lqtL_missarg(L, ' .. stackn .. ', ' .. an .. ') || '
506 test = test .. atest .. ')'
507 else
508 test = test .. ' && ' .. atest
510 stackn = stackn + an
512 -- can't make use of default values if I fix number of args
513 test = '(lua_gettop(L)<' .. stackn .. ')' .. test
514 f.test_code = test
515 return f
518 local fill_wrappers = function(functions, types)
519 local ret = {}
520 for f in pairs(functions) do
521 f = fill_wrapper_code(f, types)
522 if f then
523 f = assert(fill_test_code(f, types), f.xarg.fullname) -- MUST pass
524 ret[f] = true
525 local out = 'extern "C" int lqt_bind'..f.xarg.id..' (lua_State *L) {\n'
526 .. f.wrapper_code .. '}\n'
527 --print(out)
530 return ret
533 local virtual_overload = function(v, types)
534 local ret = ''
535 if v.virtual_overload then return v end
536 -- make return type
537 if v.return_type and not types[v.return_type] then return nil end
538 local rget, rn = '', 0
539 if v.return_type then rget, rn, ret_as = types[v.return_type].get'oldtop+1' end
540 local retget = (v.return_type and argument_name(ret_as or v.return_type, 'ret')
541 .. ' = ' .. rget .. ';' or '') .. 'lua_settop(L, oldtop);return'
542 .. (v.return_type and ' ret' or '')
543 -- make argument push
544 local pushlines, stack = '', 0
545 for i, a in ipairs(v.arguments) do
546 if not types[a.xarg.type_name] then return nil end
547 local apush, an = types[a.xarg.type_name].push('arg'..i)
548 pushlines = pushlines .. ' ' .. apush .. ';\n'
549 stack = stack + an
551 -- make lua call
552 local luacall = 'lua_pcall(L, '..(stack+1)..', '..rn..', 0)'
553 -- make prototype and fallback
554 local proto = (v.return_type or 'void')..' ;;'..v.xarg.name..' ('
555 local fallback = ''
556 for i, a in ipairs(v.arguments) do
557 proto = proto .. (i>1 and ', ' or '')
558 .. argument_name(a.xarg.type_name, 'arg'..i)
559 fallback = fallback .. (i>1 and ', arg' or 'arg') .. i
561 proto = proto .. ')' .. (v.xarg.constant=='1' and ' const' or '')
562 fallback = (v.return_type and 'return this->' or 'this->')
563 .. v.xarg.fullname .. '(' .. fallback .. ');\n}\n'
564 ret = proto .. [[ {
565 int oldtop = lua_gettop(L);
566 lqtL_pushudata(L, this, "]]..v.xarg.member_of_class..[[*");
567 lua_getfield(L, -1, "]]..v.xarg.name..[[");
568 if (lua_isfunction(L, -1)) {
569 lua_insert(L, -2);
570 ]] .. pushlines .. [[
571 if (!]]..luacall..[[) {
572 ]]..retget..[[;
575 lua_settop(L, oldtop);
576 ]] .. fallback
577 v.virtual_overload = ret
578 v.virtual_proto = string.gsub(proto, ';;', '', 1)
579 return v
582 local fill_shell_class = function(c, types)
583 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
584 local shell = 'class ' .. shellname .. ' : public ' .. c.xarg.fullname .. ' {\npublic:\n'
585 shell = shell .. ' lua_State *L;\n'
586 for _, constr in ipairs(c.constructors) do
587 if constr.xarg.access~='private' then
588 local cline = ' '..shellname..' (lua_State *l'
589 local argline = ''
590 for i, a in ipairs(constr.arguments) do
591 cline = cline .. ', ' .. argument_name(a.xarg.type_name, 'arg'..i)
592 argline = argline .. (i>1 and ', arg' or 'arg') .. i
594 cline = cline .. ') : ' .. c.xarg.fullname
595 .. '(' .. argline .. '), L(l) '
596 .. '{ lqtL_register(L, this); }\n'
597 shell = shell .. cline
600 if c.copy_constructor==nil and c.public_constr then
601 local cline = ' '..shellname..' (lua_State *l, '..c.xarg.fullname..' const& arg1)'
602 cline = cline .. ' : ' .. c.xarg.fullname .. '(arg1), L(l) {}\n'
603 shell = shell .. cline
605 for i, v in pairs(c.virtuals) do
606 if v.xarg.access~='private' then
607 if v.virtual_proto then shell = shell .. ' virtual ' .. v.virtual_proto .. ';\n' end
610 shell = shell .. ' ~'..shellname..'() { lqtL_unregister(L, this); }\n'
611 shell = shell .. '};\n'
612 c.shell_class = shell
613 return c
616 local fill_virtual_overloads = function(classes, types)
617 for c in pairs(classes) do
618 for i, v in pairs(c.virtuals) do
619 if v.xarg.access~='private' then
620 local vret = virtual_overload(v, types)
624 return classes
627 local fill_shell_classes = function(classes, types)
628 local ret = {}
629 for c in pairs(classes) do
630 if c.shell then
631 c = fill_shell_class(c, types)
632 if c then ret[c] = true end
634 ret[c] = true
636 return ret
639 local print_shell_classes = function(classes)
640 for c in pairs(classes) do
641 if c.shell then
642 if c then
643 print_head(c.shell_class)
644 else
645 --io.stderr:write(c.fullname, '\n')
649 return classes
652 local print_virtual_overloads = function(classes)
653 for c in pairs(classes) do
654 if c.shell then
655 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
656 for _,v in pairs(c.virtuals) do
657 if v.virtual_overload then
658 print_virt((string.gsub(v.virtual_overload, ';;', shellname..'::', 1)))
663 return classes
666 local print_wrappers = function(index)
667 for c in pairs(index) do
668 local meta = {}
669 for _, f in ipairs(c.methods) do
670 if f.wrapper_code then
671 local out = 'extern "C" int lqt_bind'..f.xarg.id
672 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
673 if f.xarg.access=='public' then
674 print_meta(out)
675 meta[f] = f.xarg.name
679 if c.shell then
680 for _, f in ipairs(c.constructors) do
681 if f.wrapper_code then
682 local out = 'extern "C" int lqt_bind'..f.xarg.id
683 ..' (lua_State *L) {\n'.. f.wrapper_code .. '}\n'
684 if f.xarg.access=='public' then
685 print_meta(out)
686 meta[f] = 'new'
690 --local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
691 local out = 'extern "C" int lqt_delete'..c.xarg.id..' (lua_State *L) {\n'
692 out = out ..' '..c.xarg.fullname..' *p = static_cast<'
693 ..c.xarg.fullname..'*>(lqtL_toudata(L, 1, "'..c.xarg.fullname..'*"));\n'
694 out = out .. ' if (p) delete p;\n return 0;\n}\n'
695 print_meta(out)
697 c.meta = meta
699 return index
702 local print_metatable = function(c)
703 local methods = {}
704 for m, n in pairs(c.meta) do
705 methods[n] = methods[n] or {}
706 table.insert(methods[n], m)
708 for n, l in pairs(methods) do
709 local disp = 'extern "C" int lqt_dispatcher_'..n..c.xarg.id..' (lua_State *L) {\n'
710 for _, f in ipairs(l) do
711 disp = disp..' if ('..f.test_code..') return lqt_bind'..f.xarg.id..'(L);\n'
713 disp = disp .. ' lua_settop(L, 0);\n'
714 disp = disp .. ' lua_pushstring(L, "incorrect or extra arguments");\n'
715 disp = disp .. ' return lua_error(L);\n}\n'
716 print_meta(disp)
718 local metatable = 'static luaL_Reg lqt_metatable'..c.xarg.id..'[] = {\n'
719 for n, l in pairs(methods) do
720 metatable = metatable .. ' { "'..n..'", lqt_dispatcher_'..n..c.xarg.id..' },\n'
722 if c.shell then
723 metatable = metatable .. ' { "delete", lqt_delete'..c.xarg.id..' },\n'
725 metatable = metatable .. ' { 0, 0 },\n};\n'
726 print_meta(metatable)
727 local bases = ''
728 for b in string.gmatch(c.xarg.bases or '', '([^;]*);') do
729 bases = bases .. '{"' .. b .. '*"}, '
731 bases = 'static lqt_Base lqt_base'..c.xarg.id..'[] = { '..bases..'{NULL} };\n'
732 print_meta(bases)
733 return c
736 local print_metatables = function(classes)
737 for c in pairs(classes) do
738 print_metatable(c)
740 return classes
743 local print_class_list = function(classes)
744 local list = 'static lqt_Class lqt_class_list[] = {\n'
745 for c in pairs(classes) do
746 class = '{ lqt_metatable'..c.xarg.id..', lqt_base'..c.xarg.id..', "'..c.xarg.fullname..'*" },\n'
747 list = list .. ' ' .. class
749 list = list .. ' { 0, 0, 0 },\n};\n'
750 print_meta(list)
751 return classes
754 local fix_methods_wrappers = function(classes)
755 for c in pairs(classes) do
756 -- if class seems abstract but has a shell class
757 if c.abstract then
758 -- is it really abstract?
759 local a = false
760 for _, f in pairs(c.virtuals) do
761 -- if it is abstract but we cannot overload
762 -- FIXME: this always fails: f.virtual_overload is not filled yet
763 -- maybe this check must be moved later:
764 -- we don't use shell class to move instances to Lua
765 -- but we want to instantiate if we can wrap all virtuals...
766 if f.xarg.abstract=='1' and not f.virtual_overload then a = true break end
768 c.abstract = a
770 c.shell = (not c.abstract) and c.public_destr
771 for _, constr in ipairs(c.constructors) do
772 local shellname = 'lqt_shell_'..string.gsub(c.xarg.fullname, '::', '_LQT_')
773 constr.calling_line = '*new '..shellname..'(L'
774 for i=1,#(constr.arguments) do
775 constr.calling_line = constr.calling_line .. ', arg' .. i
777 constr.calling_line = constr.calling_line .. ')'
778 constr.xarg.static = '1'
779 constr.return_type = constr.xarg.type_base..'&'
781 if c.destructor then
782 c.destructor.return_type = nil
785 return classes
788 local print_enum_tables = function(enums)
789 for e in pairs(enums) do
790 local table = 'static lqt_Enum lqt_enum'..e.xarg.id..'[] = {\n'
791 --io.stderr:write(e.xarg.fullname, '\t', #e.values, '\n')
792 for _,v in pairs(e.values) do
793 table = table .. ' { "' .. v.xarg.name
794 .. '", static_cast<int>('..v.xarg.fullname..') },\n'
796 table = table .. ' { 0, 0 }\n'
797 table = table .. '};\n'
798 e.enum_table = table
799 print_enum(table)
801 return enums
803 local print_enum_creator = function(enums, n)
804 local out = 'static lqt_Enumlist lqt_enum_list[] = {\n'
805 for e in pairs(enums) do
806 out = out..' { lqt_enum'..e.xarg.id..', "'..e.xarg.fullname..'" },\n'
808 out = out..' { 0, 0 },\n};\n'
809 out = out .. 'void lqt_create_enums_'..n..' (lua_State *L) {\n'
810 out = out .. ' lqtL_createenumlist(L, lqt_enum_list); return;\n}\n'
811 print_enum(out)
812 return enums
815 local print_openmodule = function(n)
816 print_meta([[
818 void lqt_create_enums_]]..n..[[(lua_State*);
820 extern "C" int luaopen_]]..n..[[ (lua_State *L) {
821 lqt_create_enums_]]..n..[[(L);
822 lqtL_createclasses(L, lqt_class_list);
823 return 0;
828 --------------------------------------------------------------------------------------
830 local typesystem = {}
832 local ts = {}
833 for i, ft in ipairs(typefiles) do
834 ts = loadfile(ft)(ts)
836 setmetatable(typesystem, {
837 __newindex = function(t, k, v)
838 --debug('added type', k)
839 ts[k] = v
840 end,
841 __index = function(t, k)
842 local ret = ts[k]
843 --if not ret then debug("unknown type:", tostring(k), ret) end
844 return ret
845 end,
849 fix_arguments(idindex) -- fixes default arguments if they are context-relative
850 local functions = copy_functions(idindex) -- picks functions and fixes label
851 local functions = fix_functions(functions) -- fixes name and fullname and fills arguments
853 local enums = copy_enums(idindex) -- picks enums if public
854 local enums = fill_enums(enums) -- fills field "values"
856 local classes = copy_classes(idindex) -- picks classes if not private and not blacklisted
857 local classes = fill_virtuals(classes) -- does that, destructor ("~") excluded
858 local classes = distinguish_methods(classes) -- does that
859 local classes = fill_public_destr(classes) -- does that: checks if destructor is public
860 local classes = fill_copy_constructor(classes) -- does that: checks if copy contructor is public or protected
861 local classes = fix_methods_wrappers(classes)
863 for _, f in ipairs(filterfiles) do
864 classes, enums = loadfile(f)(classes, enums)
867 local enums = fill_typesystem_with_enums(enums, typesystem) -- does that
868 local classes = fill_typesystem_with_classes(classes, typesystem)
870 local functions = fill_wrappers(functions, typesystem)
871 local classes = fill_virtual_overloads(classes, typesystem) -- does that
872 local classes = fill_shell_classes(classes, typesystem) -- does that
874 ------------- BEGIN OUTPUT
877 print_head('#ifndef LQT_BIND_'..module_name)
878 print_head('#define LQT_BIND_'..module_name)
879 print_head()
880 print_head()
881 for _, i in ipairs(output_includes) do
882 print_head('#include '..i)
884 print_head()
886 print_enum('#include "'..module_name..'_head.hpp'..'"\n\n')
887 print_meta('#include "'..module_name..'_head.hpp'..'"\n\n')
888 print_virt('#include "'..module_name..'_head.hpp'..'"\n\n')
890 local classes = print_shell_classes(classes) -- does that
891 local classes = print_virtual_overloads(classes, typesystem) -- does that
892 local classes = print_wrappers(classes) -- does that + compiles metatable list
893 local enums = print_enum_tables(enums) -- does that
894 local enums = print_enum_creator(enums, module_name) -- does that + print enum list
895 local classes = print_metatables(classes) -- does that + print dispatchers
896 local classes = print_class_list(classes) -- does that
898 print_openmodule(module_name) -- does that
900 print_head('#endif // LQT_BIND_'..module_name)