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 assert_function
= function(f
)
9 assert(entities
.is_function(f
), 'argument is not a function')
13 local path
= string.match(arg
[0], '(.*/)[^%/]+') or ''
14 local xmlstream
= dofile(path
..'xml.lua')(my
.readfile(filename
))
15 local code
= xmlstream
[1]
17 local decompound
= function(n
)
18 -- test function pointer
19 local r
, a
= string.match(n
, '(.-) %(%*%) (%b())')
21 -- only single arguments are supported
22 return 'function', r
, string.match(a
, '%(([^,]*)%))')
28 local arg_iter
= function(f
)
34 while a
and a
.label
~='Argument' do
39 onlyargs
= onlyargs
+ 1
41 local d
, g
, p
, n
= type_properties(a
)
44 return (a
and onlyargs
), a
, (a
and retn
)
49 assert(loadfile
'types.lua')(base_types
)
53 for _
, v
in pairs(xmlstream
.byid
) do if v
.xarg
.fullname
then
54 local o
= t
[v
.xarg
.fullname
] or {}
56 t
[v
.xarg
.fullname
] = o
58 get_from_fullname
= function(n
)
60 assert(ret
, 'unknown identifier: '..n
)
63 get_unique_fullname
= function(n
)
66 assert(ret
, 'unknown identifier: '..n
)
67 assert(type(ret
)=='table' and #ret
==1, 'ambiguous identifier: '..n
)
74 local push_enum
= function(fullname
)
76 return 'lqtL_pushenum(L, '..tostring(j
)..', "'..fullname
..'");'
79 local push_pointer
= function(fullname
)
81 return 'lqtL_pushudata(L, '..tostring(j
)..', "' .. fullname
.. '*");'
84 local push_class
= function(fullname
)
86 return 'lqtL_passudata(L, new '..fullname
..'('..tostring(j
)..'), "' .. fullname
.. '*");'
89 local push_constref
= function(fullname
) -- FIXME: is it correct?
91 return 'lqtL_passudata(L, new '..fullname
..'('..tostring(j
)..'), "' .. fullname
.. '*");'
94 local push_ref
= function(fullname
)
96 return 'lqtL_passudata(L, &'..tostring(j
)..', "' .. fullname
.. '*");'
100 local get_enum
= function(fullname
)
102 return 'static_cast< ' ..
103 fullname
.. ' >(lqtL_toenum(L, '..tostring(i
)..', "' .. fullname
.. '"));'
106 local get_pointer
= function(fullname
)
108 return 'static_cast< ' ..
109 fullname
.. ' *>(lqtL_toudata(L, '..tostring(i
)..', "' .. fullname
.. '*"));'
112 local get_class
= function(fullname
)
114 return '*static_cast< ' ..
115 fullname
.. ' *>(lqtL_toudata(L, '..tostring(i
)..', "' .. fullname
.. '*"));'
118 local get_constref
= function(fullname
)
120 return '*static_cast< ' ..
121 fullname
.. ' *>(lqtL_toudata(L, '..tostring(i
)..', "' .. fullname
.. '*"));'
124 local get_ref
= function(fullname
)
126 return '*static_cast< ' ..
127 fullname
.. ' *>(lqtL_toudata(L, '..tostring(i
)..', "' .. fullname
.. '*"));'
131 type_properties
= function(t
)
132 local typename
= type(t
)=='string' and t
or t
.xarg
.type_name
134 if base_types
[typename
] then
135 local ret
= base_types
[typename
]
136 return ret
.desc
, ret
.get
, ret
.push
, ret
.num
140 if type(t
)=='string' or t
.xarg
.type_base
==typename
then
141 local identifier
= get_unique_fullname(typename
)
142 local fn
= identifier
.xarg
.fullname
143 if identifier
.label
=='Enum' then
144 return 'string;', get_enum(fn
), push_enum(fn
), 1
145 elseif identifier
.label
=='Class' then
146 --assert(entities.class_is_copy_constructible(bt))
147 return typename
..'*;', get_class(fn
), push_class(fn
), 1
149 error('unknown identifier type: '..identifier
.label
)
151 elseif t
.xarg
.array
or t
.xarg
.type_name
:match
'%b[]' then -- FIXME: another hack
152 error'I cannot manipulate arrays'
153 elseif string.match(typename
, '%(%*%)') then
154 -- function pointer type
155 -- FIXME: the XML description does not contain this info
156 error'I cannot manipulate function pointers'
157 elseif t
.xarg
.indirections
then
158 if t
.xarg
.indirections
=='1' then
159 local b
= get_unique_fullname(t
.xarg
.type_base
)
160 if b
.label
=='Class' then
161 -- TODO: check if other modifiers are in place?
162 return t
.xarg
.type_base
..'*;',
163 get_pointer(t
.xarg
.type_base
),
164 push_pointer(t
.xarg
.type_base
), 1
166 error('I cannot manipulate pointers to '..t
.xarg
.type_base
)
169 error'I cannot manipulate double pointers'
171 -- this is any combination of constant, volatile and reference
172 local ret_get
, ret_push
= nil, nil
173 if typename
==(t
.xarg
.type_base
..' const&') then
174 local bt
= get_unique_fullname(t
.xarg
.type_base
)
175 --assert(entities.class_is_copy_constructible(bt))
176 ret_get
= get_constref(t
.xarg
.type_base
)
177 ret_push
= entities
.class_is_copy_constructible(bt
) and push_constref(t
.xarg
.type_base
) or nil
178 elseif typename
==(t
.xarg
.type_base
..'&') then
179 ret_get
= get_ref(t
.xarg
.type_base
)
180 ret_push
= push_ref(t
.xarg
.type_base
)
182 assert(ret_get
, 'cannot get non-base type '..typename
..' from stack')
183 return type_properties(t
.xarg
.type_base
), ret_get
, ret_push
, 1
187 entities
.return_type
= function(f
)
189 if entities
.is_destructor(f
) then
191 elseif entities
.is_constructor(f
) then
192 -- FIXME: hack follows!
193 assert((f
.xarg
.type_name
==f
.xarg
.type_base
)
194 or (f
.xarg
.type_name
==f
.xarg
.type_base
..'&'), 'return type of constructor is strange')
195 f
.xarg
.type_name
= f
.xarg
.type_base
..'&'
198 elseif f
.xarg
.type_name
=='' or f
.xarg
.type_name
=='void' then
205 function_description
= function(f
)
207 local args_on_stack
= '' -- arguments_on_stack(f) -- FIXME: use another method
208 return f
.xarg
.type_name
.. ' ' .. f
.xarg
.fullname
.. ' (' .. args_on_stack
.. ')'..
209 (f
.xarg
.static
=='1' and ' [static]' or '')..
210 (f
.xarg
.virtual
=='1' and ' [virtual]' or '')..
211 (entities
.is_constructor(f
) and ' [constructor]' or '')..
212 (entities
.is_destructor(f
) and ' [destructor]' or '')..
213 ' [in ' .. tostring(f
.xarg
.member_of
) .. ']'
216 local argument_number
= function(f
)
219 if entities
.is_destructor(f
) then
221 elseif entities
.is_constructor(f
) then
222 elseif entities
.takes_this_pointer
then
228 local argument_assert
= function(f
)
230 local narg
= argument_number(f
)
231 return 'luaL_checkany(L, '..tostring(narg
)..')'
234 local argument
= function(n
)
235 return 'arg'..tostring(n
)
238 local get_args
= function(f
, indent
)
240 indent
= indent
or ' '
241 local ret
, shift
= '', 0
242 if entities
.takes_this_pointer(f
) then
244 ret
= ret
.. indent
.. f
.xarg
.member_of_class
.. '* self = '
245 ret
= ret
.. get_pointer(f
.xarg
.member_of_class
)(1) .. ';\n' -- (void)self;\n'
247 for argi
, a
, stacki
in arg_iter(f
) do
248 local _d
, g
, _p
, _n
= type_properties(a
)
249 ret
= ret
.. indent
.. a
.xarg
.type_name
.. ' ' .. argument(argi
) .. ' = '
250 ret
= ret
.. g(stacki
+ shift
) .. ';\n' -- .. '(void) '..argument(argi)..';\n'
255 local arg_list
= function(f
, pre
)
257 if entities
.is_destructor(f
) then
261 for i
in arg_iter(f
) do
262 ret
= ret
.. ((i
>1 or pre
) and ', ' or '') .. argument(i
)
265 return '('..pre
..ret
..')'
269 local function_static_call
= function(f
)
271 if entities
.is_destructor(f
) then
272 return 'delete (self)'
273 elseif entities
.is_constructor(f
) then
274 return '*new lqt_shell_class' .. f
.parent
.xarg
.id
.. arg_list(f
, 'L')
275 -- f.xarg.fullname..arg_list(f)
276 elseif entities
.takes_this_pointer(f
) then
277 return 'self->'..f
.xarg
.fullname
..arg_list(f
)
279 return f
.xarg
.fullname
..arg_list(f
)
283 local function_shell_call
= function(f
)
285 assert(f
.xarg
.member_of_class
, 'not a shell class member')
286 if entities
.is_destructor(f
) then
287 return 'delete (self)'
288 elseif entities
.is_constructor(f
) then
289 return '*new lqt_shell_class' .. f
.parent
.xarg
.id
.. arg_list(f
)
290 -- f.xarg.fullname..arg_list(f)
291 elseif f
.xarg
.access
=='public' then
292 return function_static_call(f
)
293 elseif entities
.takes_this_pointer(f
) then
294 return 'self->'..f
.xarg
.fullname
..arg_list(f
)
296 return f
.xarg
.fullname
..arg_list(f
)
300 local collect_return
= function(f
)
302 local ret_t
= entities
.return_type(f
)
306 return ret_t
.xarg
.type_name
.. ' ret = '
310 local give_back_return
= function(f
)
312 local ret_t
= entities
.return_type(f
)
316 local _d
, _g
, p
, _n
= type_properties(ret_t
)
321 local return_statement
= function(f
)
323 local ret_t
= entities
.return_type(f
)
327 local _d
, _g
, _p
, n
= type_properties(ret_t
)
328 return 'return '..tostring(n
)
332 -- TODO: constructors wait for deciding if shell class is needed
333 local calling_code
= function(f
)
335 local ret
, indent
= '', ' '
338 ret
= ret
..indent
..argument_assert(f
)..';\n'
340 ret
= ret
..get_args(f
, indent
)
342 --if entities.is_constructor(f) then
343 --elseif entities.is_destructor(f) then
349 args = args .. (i > 1 and ', ' or '') .. argument(i)
351 args = '('..args..')';
352 local call_line = f.xarg.fullname .. args .. ';\n'
353 local ret_type = entities.return_type(f)
355 call_line = ret_type.xarg.type_name .. ' ret = ' .. call_line
356 local _d, _g, p, n = type_properties(ret_type)
357 call_line = call_line .. indent .. p'ret' .. '\n'
358 call_line = call_line .. indent .. 'return ' .. tostring(n) .. ';\n'
361 local call_line
= function_static_call(f
)
362 ret
= ret
.. indent
.. collect_return(f
) .. call_line
.. ';\n'
363 local treat_return
= give_back_return(f
)
364 ret
= treat_return
and (ret
..indent
..treat_return
..';\n') or ret
365 ret
= ret
.. indent
.. return_statement(f
) .. ';\n'
378 #include "lqt_common.hpp"
381 #define lqtL_getinteger lua_tointeger
382 #define lqtL_getstring lua_tostring
383 #define lqtL_getnumber lua_tonumber
387 local CLASS_FILTERS
= {
388 function(c
) return c
.xarg
.fullname
:match
'%b<>' end,
389 function(c
) return c
.xarg
.name
:match
'_' end,
390 --function(c) return c.xarg.fullname:match'Q.-Data' end,
391 function(c
) return c
.xarg
.class_type
=='struct' end,
392 function(c
) return c
.xarg
.fullname
=='QVariant::Private::Data' end,
393 function(c
) return c
.xarg
.fullname
=='QTextStreamManipulator' end,
395 local FUNCTIONS_FILTERS
= {
396 function(f
) return f
.xarg
.name
:match
'^[_%w]*'=='operator' end,
397 function(f
) return f
.xarg
.fullname
:match
'%b<>' end,
398 function(f
) return f
.xarg
.name
:match
'_' end,
399 function(f
) return f
.xarg
.fullname
:match
'QInternal' end,
400 function(f
) return f
.xarg
.access
~='public' end,
401 function(f
) return f
.xarg
.fullname
=='QVariant::canConvert' end,
403 local filter_out
= function(f
, t
)
404 local ret
, msg
, F
= nil, next(t
, nil)
405 while (not ret
) and F
do
407 msg
, F
= next(t
, msg
)
412 local choose_function
= function(f1
, f2
)
418 local function_proto
= function(f
)
420 local larg1
, larg2
= '', ''
421 for i
, a
in arg_iter(f
) do
422 if a
.xarg
.type_name
=='void' then
423 larg1
, larg2
= '', ''
426 larg1
= larg1
.. (i
>1 and ', ' or '')
427 if string.match(a
.xarg
.type_name
, '%(%*%)') then
428 larg1
= larg1
.. a
.xarg
.type_name
:gsub('%(%*%)', '(*'..argument(i
)..')')
429 elseif string.match(a
.xarg
.type_name
, '%[.*%]') then
430 larg1
= larg1
.. a
.xarg
.type_name
:gsub('(%[.*%])', argument(i
)..'%1')
432 larg1
= larg1
.. a
.xarg
.type_name
.. ' ' .. argument(i
)
434 larg2
= larg2
.. (i
>1 and ', ' or '') .. argument(i
)
440 get_virtuals
= function(c
)
441 assert(entities
.is_class(c
), 'not a class')
442 local ret
, impl
= {}, {}
443 for _
, f
in ipairs(c
) do
444 if entities
.is_function(f
) and f
.xarg
.virtual
=='1'
445 and not string.match(f
.xarg
.name
, '~') then
447 impl
[f
.xarg
.name
] = #ret
450 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
451 local bvirt
= get_virtuals(get_unique_fullname(b
))
452 for _
, v
in ipairs(bvirt
) do
453 if not impl
[v
.xarg
.name
] then
455 impl
[v
.xarg
.name
] = #ret
460 for _
, f
in ipairs(c
) do
461 if impl
[f
.xarg
.name
] and f
.xarg
.access
~='private' then
462 ret
[ impl
[f
.xarg
.name
] ] = f
469 local virtual_proto
= function(f
)
471 local ret
= 'virtual '..f
.xarg
.type_name
..' '..f
.xarg
.name
..'('
472 local larg1
, larg2
= function_proto(f
)
473 ret
= ret
.. larg1
.. ')'
477 local virtual_body
= function(f
, n
)
479 local ret
= f
.xarg
.type_name
..' '..n
..'::'..f
.xarg
.name
..'('
480 local larg1
, larg2
= function_proto(f
)
481 ret
= ret
.. larg1
.. [[) {
482 int oldtop = lua_gettop(L);
483 lqtL_pushudata(L, this, "]]..f
.parent
.xarg
.fullname
..[[*");
484 lua_getfield(L, -1, "]]..f
.xarg
.name
..[[");
486 if (!lua_isnil(L, -2)) {
488 for i
, a
in arg_iter(f
) do
489 local _d
, _g
, p
, _n
= type_properties(a
)
490 ret
= ret
.. ' ' .. p(argument(i
)) .. ';\n'
493 if (!lua_pcall(L, lua_gettop(L)-oldtop+1, LUA_MULTRET, 0)) {
495 if f
.xarg
.type_name
=='void' then
496 ret
= ret
.. 'return;\n'
498 local _d
, g
, _p
, _n
= type_properties(f
)
499 ret
= ret
.. g('oldtop+1') .. ';\n'
504 lua_settop(L, oldtop);
506 if f
.xarg
.abstract
then
507 if f
.xarg
.type_name
~='void' then
509 if f
.xarg
.type_name
~=f
.xarg
.type_base
then
510 dc
= entities
.default_constructor(f
)
512 local st
, err
= pcall(get_unique_fullname
, f
.xarg
.type_base
)
513 dc
= entities
.default_constructor(st
and err
or f
)
515 if not dc
then return nil end
516 ret
= ret
.. 'return ' .. dc
.. ';\n'
518 ret
= ret
.. 'return;\n'
521 if f
.type_name
~='void' then
522 ret
= ret
.. 'return this->' .. f
.xarg
.fullname
.. '(' .. larg2
.. ');\n'
524 ret
= ret
.. 'this->' .. f
.xarg
.fullname
.. '(' .. larg2
.. ');\n'
531 local examine_class
= function(c
)
532 assert(entities
.is_class(c
), 'not a class')
533 local constr
, destr
= {}, nil
534 for _
, f
in ipairs(c
) do
535 if entities
.is_function(f
) then
536 if entities
.is_constructor(f
) then
537 table.insert(constr
, f
)
538 elseif entities
.is_destructor(f
) then
539 assert(not destr
, 'cannot have more than one destructor!')
545 local public_f, protected_f, virtual_f, virt_prot_f, abstract_f = {}, {}, {}, {}, {}
546 for _, f in ipairs(c) do
547 if entities.is_function(f) then
548 if f.xarg.abstract=='1' then
549 table.insert(abstract_f, f)
550 elseif f.xarg.virtual=='1' and f.xarg.access=='protected' then
551 table.insert(virt_prot_f, f)
552 elseif f.xarg.virtual=='1' and f.xarg.access=='public' then
553 table.insert(virtual_f, f)
554 elseif f.xarg.virtual~='1' and f.xarg.access=='protected' then
555 table.insert(protected_f, f)
556 elseif f.xarg.virtual~='1' and f.xarg.access=='public' then
557 table.insert(public_f, f)
562 local cname
= 'lqt_shell_class'..c
.xarg
.id
563 local ret
= 'class '..cname
..' : public '..c
.xarg
.fullname
..' {\npublic:\n'
564 ret
= ret
.. 'lua_State *L;\n'
565 local onlyprivate
= true
566 for _
, f
in ipairs(constr
) do
567 if f
.xarg
.access
~='private' then
568 local st
, larg1
, larg2
= pcall(function_proto
, f
)
569 --assert(larg1 and larg2, 'cannot reproduce prototype of function')
572 larg1
= (larg1
=='') and '' or (', '..larg1
)
573 ret
= ret
.. cname
.. '(lua_State *l'..larg1
..'):'..c
.xarg
.fullname
..'('
574 ret
= ret
.. larg2
.. '), L(l) {} // '..f
.xarg
.id
..'\n'
579 ret
= ret
.. cname
.. '(lua_State *l):L(l) {} // automatic \n'
580 elseif onlyprivate
then
581 error('cannot bind class: '..c
.xarg
.fullname
..': it has only private constructors')
583 ret
= ret
.. 'virtual ~'..cname
..'() { lqtL_unregister(L, this); }\n'
585 local virtuals
= get_virtuals(c
)
587 for _
, f
in ipairs(virtuals
) do
588 local st
, bd
= pcall(virtual_body
, f
, cname
)
590 ret
= ret
.. virtual_proto(f
) .. ';\n'
591 ret2
= ret2
.. bd
.. '\n'
595 ret
= ret
.. '};\n' .. ret2
600 for _
, v
in pairs(xmlstream
.byid
) do
601 --if string.find(v.label, 'Function')==1 and v.xarg.virtual and v.xarg.abstract then io.stderr:write(v.xarg.fullname, '\n') end
602 if string.find(v
.label
, 'Function')==1 and (not filter_out(v
, FUNCTIONS_FILTERS
)) then
603 local status
, err
= pcall(function_description
, v
)
604 --io[status and 'stdout' or 'stderr']:write((status and '' or v.xarg.fullname..': ')..err..'\n')
605 if true or status
then
606 local s
, e
= pcall(calling_code
, v
)
607 --io[s and 'stdout' or 'stderr']:write((s and ''
608 --or ('error calling '..v.xarg.fullname..': '))..e..(s and '' or '\n'))
610 io
.stdout
:write('extern "C" int bound_function'..v
.xarg
.id
..' (lua_State *L) {\n')
612 io
.stdout
:write('}\n') -- FIXME
614 io
.stderr
:write(e
, '\n')
619 --io[status and 'stdout' or 'stderr']:write((status and '' or v.xarg.fullname..': ')..err..'\n')
620 elseif false and v
.label
=='Class' and not filter_out(v
, CLASS_FILTERS
) then -- do not support templates yet
621 local st
, ret
= pcall(examine_class
, v
)
622 if st
then print(ret
) else io
.stderr
:write(ret
, '\n') end
625 --table.foreach(name_list, print)
629 local do_class
= function(fn
)
630 local c
= get_unique_fullname(fn
)
632 ret
= ret
.. examine_class(c
)
634 for _
, f
in pairs(c
) do
635 local fret
, s
, e
= '', pcall(calling_code
, f
)
636 if s
and not filter_out(f
, FUNCTIONS_FILTERS
) then
637 fret
= fret
.. 'extern "C" int bound_function'..f
.xarg
.id
..' (lua_State *L) {\n'