added typesystem table
[lqt.git] / new / generator.lua
blobffa2b240db1fd52307afab656bd82301a74c4dd0
1 #!/usr/bin/lua
3 local my = {
4 readfile = function(fn) local f = assert(io.open(fn)) local s = f:read'*a' f:close() return s end
7 local entities = dofile'entities.lua'
8 local elements = entities
9 assert_function = function(f)
10 assert(entities.is_function(f), 'argument is not a function')
11 end
13 local filename = ...
14 local path = string.match(arg[0], '(.*/)[^%/]+') or ''
15 local xmlstream, idindex = dofile(path..'xml.lua')(my.readfile(filename))
16 io.stderr:write'parsed XML\n'
17 local code = xmlstream[1]
19 local decompound = function(n)
20 -- test function pointer
21 local r, a = string.match(n, '(.-) %(%*%) (%b())')
22 if r and a then
23 -- only single arguments are supported
24 return 'function', r, string.match(a, '%(([^,]*)%))')
25 end
26 return nil
27 end
30 local arg_iter = function(f)
31 local i = 0
32 local stackn = 1
33 local onlyargs = 0
34 return function()
35 local a, retn = {}, 0
36 while a and a.label~='Argument' do
37 i = i + 1
38 a = f[i]
39 end
40 retn = stackn
41 onlyargs = onlyargs + 1
42 if a then
43 local d, g, p, n = type_properties(a)
44 stackn = stackn + n
45 end
46 return (a and onlyargs), a, (a and retn), stackn-1
47 end
48 end
50 local base_types = {}
51 assert(loadfile'types.lua')(base_types)
53 while false do
54 local t = {}
55 for _, v in pairs(xmlstream.byid) do if v.xarg.fullname then
56 local o = t[v.xarg.fullname] or {}
57 table.insert(o, v)
58 t[v.xarg.fullname] = o
59 end end
60 get_from_fullname = function(n)
61 local ret = t[n]
62 assert(ret, 'unknown identifier: '..n)
63 return ret
64 end
65 get_unique_fullname = function(n)
66 n = tostring(n)
67 local ret = t[n]
68 assert(ret, 'unknown identifier: '..n)
69 assert(type(ret)=='table' and #ret==1, 'ambiguous identifier: '..n)
70 return ret[1]
71 end
72 --name_list = t
73 end
76 local push_enum = function(fullname)
77 return function(j)
78 return 'lqtL_pushenum(L, '..tostring(j)..', "'..fullname..'");'
79 end
80 end
81 local push_pointer = function(fullname)
82 return function(j)
83 return 'lqtL_pushudata(L, '..tostring(j)..', "' .. fullname .. '*");'
84 end
85 end
86 local push_class = function(fullname)
87 return function(j)
88 return 'lqtL_passudata(L, new '..fullname..'('..tostring(j)..'), "' .. fullname .. '*");'
89 end
90 end
91 local push_constref = function(fullname) -- FIXME: is it correct?
92 return function(j)
93 return 'lqtL_passudata(L, new '..fullname..'('..tostring(j)..'), "' .. fullname .. '*");'
94 end
95 end
96 local push_ref = function(fullname)
97 return function(j)
98 return 'lqtL_passudata(L, &'..tostring(j)..', "' .. fullname .. '*");'
99 end
102 local get_enum = function(fullname)
103 return function(i)
104 return 'static_cast< ' ..
105 fullname .. ' >(lqtL_toenum(L, '..tostring(i)..', "' .. fullname .. '"));'
108 local get_pointer = function(fullname)
109 return function(i)
110 return 'static_cast< ' ..
111 fullname .. ' *>(lqtL_toudata(L, '..tostring(i)..', "' .. fullname .. '*"));'
114 local get_class = function(fullname)
115 return function(i)
116 return '*static_cast< ' ..
117 fullname .. ' *>(lqtL_toudata(L, '..tostring(i)..', "' .. fullname .. '*"));'
120 local get_constref = function(fullname)
121 return function(i)
122 return '*static_cast< ' ..
123 fullname .. ' *>(lqtL_toudata(L, '..tostring(i)..', "' .. fullname .. '*"));'
126 local get_ref = function(fullname)
127 return function(i)
128 return '*static_cast< ' ..
129 fullname .. ' *>(lqtL_toudata(L, '..tostring(i)..', "' .. fullname .. '*"));'
133 type_properties = function(t)
134 local typename = type(t)=='string' and t or t.xarg.type_name
136 if base_types[typename] then
137 local ret = base_types[typename]
138 return ret.desc, ret.get, ret.push, ret.num
141 -- not a base type
142 if type(t)=='string' or t.xarg.type_base==typename then
143 local identifier = get_unique_fullname(typename)
144 local fn = identifier.xarg.fullname
145 if identifier.label=='Enum' then
146 return 'enum;', get_enum(fn), push_enum(fn), 1
147 elseif identifier.label=='Class' then
148 --assert(entities.class_is_copy_constructible(bt))
149 return typename..'*;', get_class(fn), push_class(fn), 1
150 else
151 error('unknown identifier type: '..identifier.label)
153 elseif t.xarg.array or t.xarg.type_name:match'%b[]' then -- FIXME: another hack
154 error'I cannot manipulate arrays'
155 elseif string.match(typename, '%(%*%)') then
156 -- function pointer type
157 -- FIXME: the XML description does not contain this info
158 error'I cannot manipulate function pointers'
159 elseif t.xarg.indirections then
160 if t.xarg.indirections=='1' then
161 local b = get_unique_fullname(t.xarg.type_base)
162 if b.label=='Class' then
163 -- TODO: check if other modifiers are in place?
164 return t.xarg.type_base..'*;',
165 get_pointer(t.xarg.type_base),
166 push_pointer(t.xarg.type_base), 1
167 else
168 error('I cannot manipulate pointers to '..t.xarg.type_base)
171 error'I cannot manipulate double pointers'
172 else
173 -- this is any combination of constant, volatile and reference
174 local ret_get, ret_push = nil, nil
175 if typename==(t.xarg.type_base..' const&') then
176 local bt = get_unique_fullname(t.xarg.type_base)
177 --assert(entities.class_is_copy_constructible(bt))
178 ret_get = get_constref(t.xarg.type_base)
179 ret_push = entities.class_is_copy_constructible(bt) and push_constref(t.xarg.type_base) or nil
180 elseif typename==(t.xarg.type_base..'&') then
181 ret_get = get_ref(t.xarg.type_base)
182 ret_push = push_ref(t.xarg.type_base)
184 assert(ret_get, 'cannot get non-base type '..typename..' from stack')
185 return type_properties(t.xarg.type_base), ret_get, ret_push, 1
189 entities.return_type = function(f)
190 assert_function(f)
191 if entities.is_destructor(f) then
192 return nil
193 elseif entities.is_constructor(f) then
194 -- FIXME: hack follows!
195 assert((f.xarg.type_name==f.xarg.type_base)
196 or (f.xarg.type_name==f.xarg.type_base..'&'), 'return type of constructor is strange')
197 f.xarg.type_name = f.xarg.type_base..'&'
198 f.xarg.reference='1'
199 return f
200 elseif f.xarg.type_name=='' or f.xarg.type_name=='void' then
201 return nil
202 else
203 return f
207 function_description = function(f)
208 assert_function(f)
209 local args_on_stack = '' -- arguments_on_stack(f) -- FIXME: use another method
210 return f.xarg.type_name .. ' ' .. f.xarg.fullname .. ' (' .. args_on_stack .. ')'..
211 (f.xarg.static=='1' and ' [static]' or '')..
212 (f.xarg.virtual=='1' and ' [virtual]' or '')..
213 (entities.is_constructor(f) and ' [constructor]' or '')..
214 (entities.is_destructor(f) and ' [destructor]' or '')..
215 ' [in ' .. tostring(f.xarg.member_of) .. ']'
218 local argument_number = function(f)
219 assert_function(f)
220 local narg, sarg = 0, 0
221 for i, a, s, r in arg_iter(f) do
222 narg = i
223 sarg = r
225 if entities.is_destructor(f) then
226 narg, sarg = 1, 1
227 elseif entities.is_constructor(f) then
228 elseif entities.takes_this_pointer(f) then
229 narg, sarg = narg + 1, sarg + 1
231 return narg, sarg
234 local argument_assert = function(f)
235 assert_function(f)
236 local narg = argument_number(f)
237 return 'luaL_checkany(L, '..tostring(narg)..')'
240 local argument = function(n)
241 return 'arg'..tostring(n)
244 local get_args = function(f, indent)
245 assert_function(f)
246 indent = indent or ' '
247 local ret, shift = '', 0
248 if entities.takes_this_pointer(f) then
249 shift = 1
250 ret = ret .. indent .. f.xarg.member_of_class .. '* self = '
251 ret = ret .. get_pointer(f.xarg.member_of_class)(1) .. ';\n' -- (void)self;\n'
253 for argi, a, stacki in arg_iter(f) do
254 local _d, g, _p, _n = type_properties(a)
255 ret = ret .. indent .. a.xarg.type_name .. ' ' .. argument(argi) .. ' = '
256 ret = ret .. g(stacki + shift) .. ';\n' -- .. '(void) '..argument(argi)..';\n'
258 return ret
261 local arg_list = function(f, pre)
262 assert_function(f)
263 if entities.is_destructor(f) then
264 return '(self)'
265 else
266 local ret = ''
267 for i in arg_iter(f) do
268 ret = ret .. ((i>1 or pre) and ', ' or '') .. argument(i)
270 pre = pre or ''
271 return '('..pre..ret..')'
275 local function_static_call = function(f)
276 assert_function(f)
277 if entities.is_destructor(f) then
278 return 'delete (self)'
279 elseif entities.is_constructor(f) then
280 return '*new lqt_shell_class' .. f.parent.xarg.id .. arg_list(f, 'L')
281 -- f.xarg.fullname..arg_list(f)
282 elseif entities.takes_this_pointer(f) then
283 return 'self->'..f.xarg.fullname..arg_list(f)
284 else
285 return f.xarg.fullname..arg_list(f)
289 local function_shell_call = function(f)
290 assert_function(f)
291 assert(f.xarg.member_of_class, 'not a shell class member')
292 if entities.is_destructor(f) then
293 return 'delete (self)'
294 elseif entities.is_constructor(f) then
295 return '*new lqt_shell_class' .. f.parent.xarg.id .. arg_list(f)
296 -- f.xarg.fullname..arg_list(f)
297 elseif f.xarg.access=='public' then
298 return function_static_call(f)
299 elseif entities.takes_this_pointer(f) then
300 return 'self->'..f.xarg.fullname..arg_list(f)
301 else
302 return f.xarg.fullname..arg_list(f)
306 local collect_return = function(f)
307 assert_function(f)
308 local ret_t = entities.return_type(f)
309 if not ret_t then
310 return ''
311 else
312 return ret_t.xarg.type_name .. ' ret = '
316 local give_back_return = function(f)
317 assert_function(f)
318 local ret_t = entities.return_type(f)
319 if not ret_t then
320 return ''
321 else
322 local _d, _g, p, _n = type_properties(ret_t)
323 return p'ret'
327 local return_statement = function(f)
328 assert_function(f)
329 local ret_t = entities.return_type(f)
330 if not ret_t then
331 return 'return 0'
332 else
333 local _d, _g, _p, n = type_properties(ret_t)
334 return 'return '..tostring(n)
338 -- TODO: constructors wait for deciding if shell class is needed
339 local calling_code = function(f)
340 assert_function(f)
341 local ret, indent = '', ' '
342 local argi = 0
344 ret = ret..indent..argument_assert(f)..';\n'
346 ret = ret..get_args(f, indent)
348 --if entities.is_constructor(f) then
349 --elseif entities.is_destructor(f) then
350 --else
352 --[[
353 local args = ''
354 for i = 1,#f do
355 args = args .. (i > 1 and ', ' or '') .. argument(i)
357 args = '('..args..')';
358 local call_line = f.xarg.fullname .. args .. ';\n'
359 local ret_type = entities.return_type(f)
360 if ret_type then
361 call_line = ret_type.xarg.type_name .. ' ret = ' .. call_line
362 local _d, _g, p, n = type_properties(ret_type)
363 call_line = call_line .. indent .. p'ret' .. '\n'
364 call_line = call_line .. indent .. 'return ' .. tostring(n) .. ';\n'
366 --]]
367 local call_line = function_static_call(f)
368 ret = ret .. indent .. collect_return(f) .. call_line .. ';\n'
369 local treat_return = give_back_return(f)
370 ret = treat_return and (ret..indent..treat_return..';\n') or ret
371 ret = ret .. indent .. return_statement(f) .. ';\n'
373 return ret
377 --[==[io.write[[
378 extern "C" {
379 #include <lua.h>
380 #include <lualib.h>
381 #include <lauxlib.h>
384 #include "lqt_common.hpp"
385 #include <QtGui>
387 #define lqtL_getinteger lua_tointeger
388 #define lqtL_getstring lua_tostring
389 #define lqtL_getnumber lua_tonumber
392 --]==]
394 local CLASS_FILTERS = {
395 function(c) return c.xarg.fullname:match'%b<>' end,
396 function(c) return c.xarg.name:match'_' end,
397 --function(c) return c.xarg.fullname:match'Q.-Data' end,
398 function(c) return c.xarg.class_type=='struct' end,
399 function(c) return c.xarg.fullname=='QVariant::Private::Data' end,
400 function(c) return c.xarg.fullname=='QTextStreamManipulator' end,
402 local FUNCTIONS_FILTERS = {
403 function(f) return not pcall(calling_code, f) end,
404 function(f) return f.xarg.name:match'^[_%w]*'=='operator' end,
405 function(f) return f.xarg.fullname:match'%b<>' end,
406 function(f) return f.xarg.name:match'_' end,
407 function(f) return f.xarg.fullname:match'QInternal' end,
408 function(f) return f.xarg.access~='public' end,
409 function(f) return f.xarg.fullname=='QVariant::canConvert' end,
411 local filter_out = function(f, t)
412 local ret, msg, F = nil, next(t, nil)
413 while (not ret) and F do
414 ret = F(f) and msg
415 msg, F = next(t, msg)
417 return ret
420 local choose_function = function(f1, f2)
421 assert_function(f1)
422 assert_function(f2)
426 local function_proto = function(f)
427 assert_function(f)
428 local larg1, larg2 = '', ''
429 for i, a in arg_iter(f) do
430 if a.xarg.type_name=='void' then
431 larg1, larg2 = '', ''
432 break
434 larg1 = larg1 .. (i>1 and ', ' or '')
435 if string.match(a.xarg.type_name, '%(%*%)') then
436 larg1 = larg1 .. a.xarg.type_name:gsub('%(%*%)', '(*'..argument(i)..')')
437 elseif string.match(a.xarg.type_name, '%[.*%]') then
438 larg1 = larg1 .. a.xarg.type_name:gsub('(%[.*%])', argument(i)..'%1')
439 else
440 larg1 = larg1 .. a.xarg.type_name .. ' ' .. argument(i)
442 larg2 = larg2 .. (i>1 and ', ' or '') .. argument(i)
444 return larg1, larg2
447 local get_virtuals
448 get_virtuals = function(c)
449 assert(entities.is_class(c), 'not a class')
450 local ret, impl = {}, {}
451 for _, f in ipairs(c) do
452 if entities.is_function(f) and f.xarg.virtual=='1'
453 and not string.match(f.xarg.name, '~') then
454 table.insert(ret, f)
455 impl[f.xarg.name] = #ret
458 -- virtual functions in base classes are not included and
459 -- reimplementation are not marked as virtuals
460 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
461 local bvirt = get_virtuals(get_unique_fullname(b))
462 for _, v in ipairs(bvirt) do
463 if not impl[v.xarg.name] then
464 table.insert(ret, v)
465 impl[v.xarg.name] = #ret
469 -- [[
470 -- this wants to return the top-most virtual implementation
471 -- so that it knows to which version it should fallback
472 for _, f in ipairs(c) do
473 if impl[f.xarg.name] and f.xarg.access~='private' then
474 ret[ impl[f.xarg.name] ] = f
477 --]]
478 return ret
481 local virtual_proto = function(f)
482 assert_function(f)
483 local ret = 'virtual '..f.xarg.type_name..' '..f.xarg.name..'('
484 local larg1, larg2 = function_proto(f)
485 ret = ret .. larg1 .. ')'
486 return ret
489 local virtual_body = function(f, n)
490 assert_function(f)
491 local ret = f.xarg.type_name..' '..n..'::'..f.xarg.name..'('
492 local larg1, larg2 = function_proto(f)
493 ret = ret .. larg1 .. [[) {
494 int oldtop = lua_gettop(L);
495 lqtL_pushudata(L, this, "]]..f.parent.xarg.fullname..[[*");
496 lua_getfield(L, -1, "]]..f.xarg.name..[[");
497 lua_insert(L, -2);
498 if (!lua_isnil(L, -2)) {
500 for i, a in arg_iter(f) do
501 local _d, _g, p, _n = type_properties(a)
502 ret = ret .. ' ' .. p(argument(i)) .. ';\n'
504 ret = ret .. [[
505 if (!lua_pcall(L, lua_gettop(L)-oldtop+1, LUA_MULTRET, 0)) {
507 if f.xarg.type_name=='void' then
508 ret = ret .. 'return;\n'
509 else
510 local _d, g, _p, _n = type_properties(f)
511 ret = ret .. g('oldtop+1') .. ';\n'
513 ret = ret .. [[
516 lua_settop(L, oldtop);
518 if f.xarg.abstract then
519 if f.xarg.type_name~='void' then
520 local dc
521 if f.xarg.type_name~=f.xarg.type_base then
522 dc = entities.default_constructor(f)
523 else
524 local st, err = pcall(get_unique_fullname, f.xarg.type_base)
525 dc = entities.default_constructor(st and err or f)
527 if not dc then return nil end
528 ret = ret .. 'return ' .. dc .. ';\n'
529 else
530 ret = ret .. 'return;\n'
532 else
533 if f.type_name~='void' then
534 ret = ret .. 'return this->' .. f.xarg.fullname .. '(' .. larg2 .. ');\n'
535 else
536 ret = ret .. 'this->' .. f.xarg.fullname .. '(' .. larg2 .. ');\n'
539 ret = ret .. '}\n'
540 return ret
543 local examine_class = function(c)
544 assert(entities.is_class(c), 'not a class')
545 local constr, destr = {}, nil
546 for _, f in ipairs(c) do
547 if entities.is_function(f) then
548 if entities.is_constructor(f) then
549 table.insert(constr, f)
550 elseif entities.is_destructor(f) then
551 assert(not destr, 'cannot have more than one destructor!')
552 destr = f
556 --[[
557 local public_f, protected_f, virtual_f, virt_prot_f, abstract_f = {}, {}, {}, {}, {}
558 for _, f in ipairs(c) do
559 if entities.is_function(f) then
560 if f.xarg.abstract=='1' then
561 table.insert(abstract_f, f)
562 elseif f.xarg.virtual=='1' and f.xarg.access=='protected' then
563 table.insert(virt_prot_f, f)
564 elseif f.xarg.virtual=='1' and f.xarg.access=='public' then
565 table.insert(virtual_f, f)
566 elseif f.xarg.virtual~='1' and f.xarg.access=='protected' then
567 table.insert(protected_f, f)
568 elseif f.xarg.virtual~='1' and f.xarg.access=='public' then
569 table.insert(public_f, f)
573 --]]
574 local cname = 'lqt_shell_class'..c.xarg.id
575 local ret = 'class '..cname..' : public '..c.xarg.fullname..' {\npublic:\n'
576 ret = ret .. 'lua_State *L;\n'
577 local onlyprivate = true
578 for _, f in ipairs(constr) do
579 if f.xarg.access~='private' then
580 local st, larg1, larg2 = pcall(function_proto, f)
581 --assert(larg1 and larg2, 'cannot reproduce prototype of function')
582 if st then
583 onlyprivate = false
584 larg1 = (larg1=='') and '' or (', '..larg1)
585 ret = ret .. cname .. '(lua_State *l'..larg1..'):'..c.xarg.fullname..'('
586 ret = ret .. larg2 .. '), L(l) {} // '..f.xarg.id..'\n'
590 if #constr==0 then
591 ret = ret .. cname .. '(lua_State *l):L(l) {} // automatic \n'
592 elseif onlyprivate then
593 error('cannot bind class: '..c.xarg.fullname..': it has only private constructors')
595 ret = ret .. 'virtual ~'..cname..'() { lqtL_unregister(L, this); }\n'
597 local virtuals = get_virtuals(c)
598 local ret2 = ''
599 for _, f in ipairs(virtuals) do
600 local st, bd = pcall(virtual_body, f, cname)
601 if st then
602 ret = ret .. virtual_proto(f) .. ';\n'
603 ret2 = ret2 .. bd .. '\n'
607 ret = ret .. '};\n' .. ret2
608 return ret
611 --[==[ ]=]
612 for _, v in pairs(xmlstream.byid) do
613 --if string.find(v.label, 'Function')==1 and v.xarg.virtual and v.xarg.abstract then io.stderr:write(v.xarg.fullname, '\n') end
614 if string.find(v.label, 'Function')==1 and (not filter_out(v, FUNCTIONS_FILTERS)) then
615 local status, err = pcall(function_description, v)
616 --io[status and 'stdout' or 'stderr']:write((status and '' or v.xarg.fullname..': ')..err..'\n')
617 if true or status then
618 local s, e = pcall(calling_code, v)
619 --io[s and 'stdout' or 'stderr']:write((s and ''
620 --or ('error calling '..v.xarg.fullname..': '))..e..(s and '' or '\n'))
621 if s then
622 io.stdout:write('extern "C" int bound_function'..v.xarg.id..' (lua_State *L) {\n')
623 io.stdout:write(e)
624 io.stdout:write('}\n') -- FIXME
625 else
626 io.stderr:write(e, '\n')
628 else
629 print(err)
631 --io[status and 'stdout' or 'stderr']:write((status and '' or v.xarg.fullname..': ')..err..'\n')
632 elseif false and v.label=='Class' and not filter_out(v, CLASS_FILTERS) then -- do not support templates yet
633 local st, ret = pcall(examine_class, v)
634 if st then print(ret) else io.stderr:write(ret, '\n') end
637 --table.foreach(name_list, print)
638 --]==]
640 local make_function = function(f)
641 local fret, s, e = '', pcall(calling_code, f)
642 if s and not filter_out(f, FUNCTIONS_FILTERS) then
643 fret = fret .. 'static int bound_function'..f.xarg.id..' (lua_State *L) {\n'
644 fret = fret .. e
645 fret = fret .. '}\n'
647 return fret
650 local do_class = function(fn)
651 local c = get_unique_fullname(fn)
652 local ret = ''
653 ret = ret .. examine_class(c)
655 --[[
656 for _, o in pairs(c.byname) do
657 if o.label=='Overloaded' then
658 io.stderr:write('overload: ', o.xarg.name, ' ', #o, '\n')
659 for __, f in pairs(o) do
660 ret = ret .. make_function(f)
662 else
663 ret = ret .. make_function(o)
666 --]]
668 local names = {}
669 for _, f in ipairs(c) do
670 if entities.is_function(f) and not filter_out(f, FUNCTIONS_FILTERS) then
671 local _, argnum = argument_number(f) -- care about arguments on stack
672 names[f.xarg.name] = names[f.xarg.name] or {}
673 names[f.xarg.name][argnum] = names[f.xarg.name][argnum] or {}
674 table.insert(names[f.xarg.name][argnum], f)
678 --[[
679 for n, t in pairs(names) do
680 io.stderr:write(n, ' ', tostring(t), '\n')
681 for a, f in pairs(t) do
682 io.stderr:write(' ', tostring(a), '\n')
683 for _, g in pairs(f) do
684 io.stderr:write(' ', g.xarg.id, '\n')
688 --]]
690 local fcomp = function(f, g)
691 if pcall(calling_code, f) and not pcall(calling_code, g) then
692 elseif entities.takes_this_pointer(g) and not entities.takes_this_pointer(f) then
693 return true
694 elseif argument_number(f) > argument_number(g) then
695 return false
696 elseif argument_number(f) < argument_number(g) then
697 return true
698 else
699 local fa, ga = {}, {}
700 for _, a in arg_iter(f) do
701 table.insert(fa, a)
703 for _, a in arg_iter(g) do
704 table.insert(ga, a)
706 for i = 1, #fa do
707 if base_types[fa[i]] and not base_types[ga[i]] then
708 return true
709 elseif base_types[fa[i]] and base_types[ga[i]] then
710 return false -- TODO: better handling
714 return false
717 io.write(ret)
719 local metatable = {}
720 for name, t in pairs(names) do
721 local call_this_one = nil
722 local fname = 'lqt_bind_'..(tostring(name):match'%~' and 'delete' or 'function')
723 .. '_' .. tostring(name):gsub('%~', '')
724 for k, n in pairs(t) do
725 table.sort(n, fcomp)
726 t[k] = calling_code(n[1]):gsub('\n(.)', '\n %1')
727 call_this_one = call_this_one and (call_this_one .. ' } else ') or ' '
728 call_this_one = call_this_one .. 'if (lua_gettop(L)=='..tostring(k)..') {\n'
729 call_this_one = call_this_one .. t[k]
731 call_this_one = 'static int ' .. fname .. ' (lua_State *L) {\n'
732 .. call_this_one
733 .. ' }\n return luaL_error(L, "wrong number of arguments");\n}\n'
734 print(call_this_one)
735 metatable[name] = fname
738 io.write('static const luaL_Reg metatable_'..c.xarg.name..'[] = {\n')
739 for n, f in pairs(metatable) do
740 io.write( ' { "', n, '", ', f, ' },\n')
742 io.write'};\n'
743 io.write('\n\nextern "C" int lqtL_open_', c.xarg.name, ' (lua_State *L) {\n')
744 io.write(' luaL_register(L, "QObject", metatable_', c.xarg.name, ');\n')
745 io.write(' return 0;\n')
746 io.write('}\n')
750 local copy_functions = function(index)
751 local ret, copied = {}, 0
752 for e in pairs(index) do
753 if e.label:match'^Function'
754 and (e.xarg.name:match'^[_%w]*'=='operator'
755 or e.xarg.fullname:match'%b<>'
756 or e.xarg.name:match'_'
757 or e.xarg.name:match'[xX]11'
758 or e.xarg.fullname:match'QInternal'
759 or e.xarg.access=='private'
760 or e.xarg.fullname=='QVariant::canConvert') then
761 e.label = 'Function'
762 ret[e] = true
763 copied = copied + 1
764 else
765 --removed = removed + (e.label:match'^Function' and 1 or 0)
766 --removed = removed + 1
769 return ret, copied
772 local fix_functions = function(index)
773 for f in pairs(index) do
774 local args = {}
775 for i, a in ipairs(f) do
776 if a.label=='Argument' then
777 table.insert(args, a)
780 f.arguments = args
781 if elements.is_constructor(f) then
782 f.return_type = f.xarg.type_base..'&'
783 elseif elements.is_destructor(f) then
784 f.return_type = nil
785 else
786 f.return_type = f.xarg.type_name
789 return index
792 local copy_enums = function(index)
793 local ret = {}
794 for e in pairs(index) do
795 if e.label=='Enum'
796 and e.xarg.access~='public' then
797 ret[e] = true
800 return ret
803 local fix_enums = function(index)
804 for e in pairs(index) do
805 local values = {}
806 for _, v in ipairs(e) do
807 if v.label=='Enumerators' then
808 values[#values] = v.xarg.name
811 e.values = values
813 return index
816 local copy_classes = function(index)
817 local ret = {}
818 for e in pairs(index) do
819 if e.label=='Class'
820 and e.xarg.access~='public'
821 and not e.xarg.fullname:match'%b<>' then
822 ret[e] = true
825 return ret
828 local fill_virtuals = function(index)
829 local classes = {}
830 for c in pairs(index) do
831 classes[c.xarg.fullname] = c
833 local get_virtuals
834 get_virtuals = function(c)
835 local ret = {}
836 for _, f in ipairs(c) do
837 if f.label=='Function' and f.xarg.virtual=='1' then
838 local n = string.match(f.xarg.name, '~') or f.xarg.name
839 ret[n] = f
842 for b in string.gmatch(c.xarg.bases or '', '([^;]+);') do
843 local base = classes[b]
844 if type(base)=='table' then
845 local bv = get_virtuals(base)
846 for n, f in pairs(bv) do
847 if not ret[n] then ret[n] = f end
851 for _, f in ipairs(c) do
852 if f.label=='Function'
853 and f.xarg.access~='private'
854 and (ret[string.match(f.xarg.name, '~') or f.xarg.name]) then
855 f.xarg.virtual = '1'
856 local n = string.match(f.xarg.name, '~')or f.xarg.name
857 ret[n] = f
860 return ret
862 for c in pairs(index) do
863 c.virtuals = get_virtuals(c)
865 return index
868 local fill_special_methods = function(index, functions)
869 for c in pairs(index) do
870 local construct, destruct = {}, nil
871 local n = c.xarg.name
872 local auto, copy = true, nil
873 for _, f in ipairs(c) do
874 if n==f.xarg.name then
875 auto = false
876 if #f==1 and
877 f[1].xarg.type_name==(n..' const&') then
878 copy = f
881 if functions[f] then
882 if n==f.xarg.name then
883 table.insert(construct, f)
884 elseif f.xarg.name:match'~' then
885 destruct = f
889 construct.auto = auto
890 construct.copy = copy
891 c.constructors = construct
892 c.destructor = destruct
894 return index
897 local fill_typesystem_with_enums = function(enums, types)
898 local ret = {}
899 for e in pairs(enums) do
900 if not types[e.xarg.fullname] then
901 ret[e] = true
902 types[e.xarg.fullname] = {
903 push = function(n)
904 return 'lqtL_pushenum(L, '..n..', "'..e.xarg.fullname..'")', 1
905 end,
906 get = function(n)
907 return 'static_cast<'..e.xarg.fullname..'>'
908 ..'(lqtL_getenum(L, '..n..', "'..e.xarg.fullname..'"))', 1
909 end,
913 return ret
916 local functions = copy_functions(idindex)
917 local functions = fix_functions(functions)
919 local enums = copy_enums(idindex)
920 local enums = fix_enums(enums)
922 local classes = copy_classes(idindex)
923 local classes = fill_virtuals(classes)
924 local classes = fill_special_methods(classes)
926 local ntable = function(t) local ret=0 for _ in pairs(t) do ret=ret+1 end return ret end
928 local typesystem = {}
931 print(ntable(functions))
932 print(ntable(enums))
933 print(ntable(classes))
935 local print_virtuals = function(index)
936 for c in pairs(index) do
937 print(c.xarg.name)
938 for n, f in pairs(c.virtuals) do print(' '..n, f.xarg.fullname) end
942 --print_virtuals(classes)
944 --print(copy_functions(idindex))