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
, '%(([^,]*)%))')
29 assert(loadfile
'types.lua')(base_types
)
33 for _
, v
in pairs(xmlstream
.byid
) do if v
.xarg
.fullname
then
34 local o
= t
[v
.xarg
.fullname
] or {}
36 t
[v
.xarg
.fullname
] = o
38 get_from_fullname
= function(n
)
40 assert(ret
, 'unknown identifier: '..n
)
43 get_unique_fullname
= function(n
)
46 assert(ret
, 'unknown identifier: '..n
)
47 assert(type(ret
)=='table' and #ret
==1, 'ambiguous identifier: '..n
)
54 local push_enum
= function(fullname
)
56 return 'lqtL_pushenum(L, '..tostring(j
)..', "'..fullname
..'");'
59 local push_pointer
= function(fullname
)
61 return 'lqtL_pushudata(L, '..tostring(j
)..', "' .. fullname
.. '*");'
64 local push_class
= function(fullname
)
66 return 'lqtL_passudata(L, new '..fullname
..'('..tostring(j
)..'), "' .. fullname
.. '*");'
69 local push_constref
= function(fullname
) -- FIXME: is it correct?
71 return 'lqtL_passudata(L, new '..fullname
..'('..tostring(j
)..'), "' .. fullname
.. '*");'
74 local push_ref
= function(fullname
)
76 return 'lqtL_passudata(L, &'..tostring(j
)..', "' .. fullname
.. '*");'
80 local get_enum
= function(fullname
)
82 return 'static_cast< ' ..
83 fullname
.. ' >(lqtL_toenum(L, '..tostring(i
)..', "' .. fullname
.. '"));'
86 local get_pointer
= function(fullname
)
88 return 'static_cast< ' ..
89 fullname
.. ' *>(lqtL_toudata(L, '..tostring(i
)..', "' .. fullname
.. '*"));'
92 local get_class
= function(fullname
)
94 return '*static_cast< ' ..
95 fullname
.. ' *>(lqtL_toudata(L, '..tostring(i
)..', "' .. fullname
.. '*"));'
98 local get_constref
= function(fullname
)
100 return '*static_cast< ' ..
101 fullname
.. ' *>(lqtL_toudata(L, '..tostring(i
)..', "' .. fullname
.. '*"));'
104 local get_ref
= function(fullname
)
106 return '*static_cast< ' ..
107 fullname
.. ' *>(lqtL_toudata(L, '..tostring(i
)..', "' .. fullname
.. '*"));'
111 type_properties
= function(t
)
112 local typename
= type(t
)=='string' and t
or t
.xarg
.type_name
114 if base_types
[typename
] then
115 local ret
= base_types
[typename
]
116 return ret
.desc
, ret
.get
, ret
.push
, ret
.num
120 if type(t
)=='string' or t
.xarg
.type_base
==typename
then
121 local identifier
= get_unique_fullname(typename
)
122 local fn
= identifier
.xarg
.fullname
123 if identifier
.label
=='Enum' then
124 return 'string;', get_enum(fn
), push_enum(fn
), 1
125 elseif identifier
.label
=='Class' then
126 --assert(entities.class_is_copy_constructible(bt))
127 return typename
..'*;', get_class(fn
), push_class(fn
), 1
129 error('unknown identifier type: '..identifier
.label
)
131 elseif t
.xarg
.array
or t
.xarg
.type_name
:match
'%b[]' then -- FIXME: another hack
132 error'I cannot manipulate arrays'
133 elseif string.match(typename
, '%(%*%)') then
134 -- function pointer type
135 -- FIXME: the XML description does not contain this info
136 error'I cannot manipulate function pointers'
137 elseif t
.xarg
.indirections
then
138 if t
.xarg
.indirections
=='1' then
139 local b
= get_unique_fullname(t
.xarg
.type_base
)
140 if b
.label
=='Class' then
141 -- TODO: check if other modifiers are in place?
142 return t
.xarg
.type_base
..'*;',
143 get_pointer(t
.xarg
.type_base
),
144 push_pointer(t
.xarg
.type_base
), 1
146 error('I cannot manipulate pointers to '..t
.xarg
.type_base
)
149 error'I cannot manipulate double pointers'
151 -- this is any combination of constant, volatile and reference
152 local ret_get
, ret_push
= nil, nil
153 if typename
==(t
.xarg
.type_base
..' const&') then
154 local bt
= get_unique_fullname(t
.xarg
.type_base
)
155 --assert(entities.class_is_copy_constructible(bt))
156 ret_get
= get_constref(t
.xarg
.type_base
)
157 ret_push
= entities
.class_is_copy_constructible(bt
) and push_constref(t
.xarg
.type_base
) or nil
158 elseif typename
==(t
.xarg
.type_base
..'&') then
159 ret_get
= get_ref(t
.xarg
.type_base
)
160 ret_push
= push_ref(t
.xarg
.type_base
)
162 assert(ret_get
, 'cannot get non-base type '..typename
..' from stack')
163 return type_properties(t
.xarg
.type_base
), ret_get
, ret_push
, 1
167 entities
.return_type
= function(f
)
169 if entities
.is_destructor(f
) then
171 elseif entities
.is_constructor(f
) then
172 -- FIXME: hack follows!
173 assert(f
.xarg
.type_name
==f
.xarg
.type_base
, 'return type of constructor is strange')
174 f
.xarg
.type_name
= f
.xarg
.type_base
..'&'
177 elseif f
.xarg
.type_name
=='' or f
.xarg
.type_name
=='void' then
184 function_description
= function(f
)
186 local args_on_stack
= '' -- arguments_on_stack(f) -- FIXME: use another method
187 return f
.xarg
.type_name
.. ' ' .. f
.xarg
.fullname
.. ' (' .. args_on_stack
.. ')'..
188 (f
.xarg
.static
=='1' and ' [static]' or '')..
189 (f
.xarg
.virtual
=='1' and ' [virtual]' or '')..
190 (entities
.is_constructor(f
) and ' [constructor]' or '')..
191 (entities
.is_destructor(f
) and ' [destructor]' or '')..
192 ' [in ' .. tostring(f
.xarg
.member_of
) .. ']'
195 local argument_number
= function(f
)
198 if entities
.is_destructor(f
) then
200 elseif entities
.is_constructor(f
) then
201 elseif entities
.takes_this_pointer
then
207 local argument_assert
= function(f
)
209 local narg
= argument_number(f
)
210 return 'luaL_checkany(L, '..tostring(narg
)..')'
213 local argument
= function(n
)
214 return 'arg'..tostring(n
)
217 local get_args
= function(f
, indent
)
219 indent
= indent
or ' '
220 local ret
, argi
, shift
= '', 0, 0
221 if entities
.takes_this_pointer(f
) then
223 ret
= ret
.. indent
.. f
.xarg
.member_of_class
.. '* self = '
224 ret
= ret
.. get_pointer(f
.xarg
.member_of_class
)(1) .. ';\n' -- (void)self;\n'
226 for _
,a
in ipairs(f
) do if a
.label
=='Argument' then
228 local _d
, g
, _p
, _n
= type_properties(a
)
229 ret
= ret
.. indent
.. a
.xarg
.type_name
.. ' '..argument(argi
) .. ' = '
230 ret
= ret
.. g(argi
+ shift
) .. ';\n' -- .. '(void) '..argument(argi)..';\n'
231 else error'element in function is not argument'
236 local arg_list
= function(f
)
238 if entities
.is_destructor(f
) then
243 ret
= ret
.. (i
>1 and ', ' and '') .. argument(i
)
249 local function_static_call
= function(f
)
251 if entities
.is_destructor(f
) then
252 return 'delete (self)'
253 elseif entities
.is_constructor(f
) then
254 return '*new '..f
.xarg
.fullname
..arg_list(f
)
255 elseif entities
.takes_this_pointer(f
) then
256 return 'self->'..f
.xarg
.fullname
..arg_list(f
)
258 return f
.xarg
.fullname
..arg_list(f
)
262 local function_shell_call
= function(f
)
264 assert(f
.xarg
.member_of_class
, 'not a shell class member')
265 if entities
.is_destructor(f
) then
266 return 'delete (self)'
267 elseif entities
.is_constructor(f
) then
268 return '*new '..f
.xarg
.fullname
..arg_list(f
)
269 elseif f
.xarg
.access
=='public' then
270 return function_static_call(f
)
271 elseif entities
.takes_this_pointer(f
) then
272 return 'self->'..f
.xarg
.fullname
..arg_list(f
)
274 return f
.xarg
.fullname
..arg_list(f
)
278 local collect_return
= function(f
)
280 local ret_t
= entities
.return_type(f
)
284 return ret_t
.xarg
.type_name
.. ' ret = '
288 local give_back_return
= function(f
)
290 local ret_t
= entities
.return_type(f
)
294 local _d
, _g
, p
, _n
= type_properties(ret_t
)
299 local return_statement
= function(f
)
301 local ret_t
= entities
.return_type(f
)
305 local _d
, _g
, _p
, n
= type_properties(ret_t
)
306 return 'return '..tostring(n
)
310 -- TODO: constructors wait for deciding if shell class is needed
311 local calling_code
= function(f
)
313 local ret
, indent
= '', ' '
316 ret
= ret
..indent
..argument_assert(f
)..';\n'
318 ret
= ret
..get_args(f
, indent
)
320 --if entities.is_constructor(f) then
321 --elseif entities.is_destructor(f) then
327 args = args .. (i > 1 and ', ' or '') .. argument(i)
329 args = '('..args..')';
330 local call_line = f.xarg.fullname .. args .. ';\n'
331 local ret_type = entities.return_type(f)
333 call_line = ret_type.xarg.type_name .. ' ret = ' .. call_line
334 local _d, _g, p, n = type_properties(ret_type)
335 call_line = call_line .. indent .. p'ret' .. '\n'
336 call_line = call_line .. indent .. 'return ' .. tostring(n) .. ';\n'
339 local call_line
= function_static_call(f
)
340 ret
= ret
.. indent
.. collect_return(f
) .. call_line
.. ';\n'
341 local treat_return
= give_back_return(f
)
342 ret
= treat_return
and (ret
..indent
..treat_return
..';\n') or ret
343 ret
= ret
.. indent
.. return_statement(f
) .. ';\n'
356 #include "lqt_common.hpp"
359 #define lqtL_getinteger lua_tointeger
360 #define lqtL_getstring lua_tostring
361 #define lqtL_getnumber lua_tonumber
365 local CLASS_FILTERS
= {
366 function(c
) return c
.xarg
.fullname
:match
'%b<>' end,
367 function(c
) return c
.xarg
.name
:match
'_' end,
368 --function(c) return c.xarg.fullname:match'Q.-Data' end,
369 function(c
) return c
.xarg
.class_type
=='struct' end,
370 function(c
) return c
.xarg
.fullname
=='QVariant::Private::Data' end,
371 function(c
) return c
.xarg
.fullname
=='QTextStreamManipulator' end,
373 local FUNCTIONS_FILTERS
= {
374 function(f
) return f
.xarg
.name
:match
'^[_%w]*'=='operator' end,
375 function(f
) return f
.xarg
.fullname
:match
'%b<>' end,
376 function(f
) return f
.xarg
.name
:match
'_' end,
377 function(f
) return f
.xarg
.fullname
:match
'QInternal' end,
378 function(f
) return f
.xarg
.access
~='public' end,
380 local filter_out
= function(f
, t
)
381 local ret
, msg
, F
= nil, next(t
, nil)
382 while (not ret
) and F
do
384 msg
, F
= next(t
, msg
)
389 local choose_function
= function(f1
, f2
)
395 local function_proto
= function(f
)
397 local larg1
, larg2
= '', ''
400 if a
.label
~='Argument' then error(a
.label
) end
401 if a
.xarg
.type_name
=='void' then
402 larg1
, larg2
= nil, nil
405 larg1
= larg1
.. (i
>1 and ', ' or '')
406 if string.match(a
.xarg
.type_name
, '%(%*%)') then
407 larg1
= larg1
.. a
.xarg
.type_name
:gsub('%(%*%)', '(*'..argument(i
)..')')
408 elseif string.match(a
.xarg
.type_name
, '%[.*%]') then
409 larg1
= larg1
.. a
.xarg
.type_name
:gsub('(%[.*%])', argument(i
)..'%1')
411 larg1
= larg1
.. a
.xarg
.type_name
.. ' ' .. argument(i
)
413 larg2
= larg2
.. (i
>1 and ', ' or '') .. argument(i
)
419 get_virtuals
= function(c
)
420 assert(entities
.is_class(c
), 'not a class')
421 local ret
, impl
= {}, {}
422 for _
, f
in ipairs(c
) do
423 if entities
.is_function(f
) and f
.xarg
.virtual
=='1'
424 and not string.match(f
.xarg
.name
, '~') then
426 impl
[f
.xarg
.name
] = #ret
429 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
430 local bvirt
= get_virtuals(get_unique_fullname(b
))
431 for _
, v
in ipairs(bvirt
) do
432 if not impl
[v
.xarg
.name
] then
434 impl
[v
.xarg
.name
] = #ret
439 for _
, f
in ipairs(c
) do
440 if impl
[f
.xarg
.name
] and f
.xarg
.access
~='private' then
441 ret
[ impl
[f
.xarg
.name
] ] = f
448 local virtual_proto
= function(f
)
450 local ret
= 'virtual '..f
.xarg
.type_name
..' '..f
.xarg
.name
..'('
451 local larg1
, larg2
= function_proto(f
)
452 ret
= ret
.. larg1
.. ')'
456 local virtual_body
= function(f
, n
)
458 local ret
= f
.xarg
.type_name
..' '..n
..'::'..f
.xarg
.name
..'('
459 local larg1
, larg2
= function_proto(f
)
460 ret
= ret
.. larg1
.. [[) {
461 int oldtop = lua_gettop(L);
462 lqtL_pushudata(L, this, "]]..f
.parent
.xarg
.fullname
..[[*");
463 lua_getfield(L, -1, "]]..f
.xarg
.name
..[[");
465 if (!lua_isnil(L, -2)) {
467 for i
, a
in ipairs(f
) do
468 local _d
, _g
, p
, _n
= type_properties(a
)
469 ret
= ret
.. ' ' .. p(argument(i
)) .. ';\n'
472 if (!lua_pcall(L, lua_gettop(L)-oldtop+1, LUA_MULTRET, 0)) {
474 if f
.xarg
.type_name
=='void' then
475 ret
= ret
.. 'return;'
477 local _d
, g
, _p
, _n
= type_properties(f
)
478 ret
= ret
.. g('oldtop+1') .. ';\n'
483 lua_settop(L, oldtop);
485 if f
.xarg
.abstract
then
486 if f
.xarg
.type_name
~='void' then
488 if f
.xarg
.type_name
~=f
.xarg
.type_base
then
489 dc
= entities
.default_constructor(f
)
491 local st
, err
= pcall(get_unique_fullname
, f
.xarg
.type_base
)
492 dc
= entities
.default_constructor(st
and err
or f
)
494 if not dc
then return nil end
495 ret
= ret
.. 'return ' .. dc
.. ';\n'
497 ret
= ret
.. 'return;\n'
500 if f
.type_name
~='void' then
501 ret
= ret
.. 'return this->' .. f
.xarg
.fullname
.. '(' .. larg2
.. ');\n'
503 ret
= ret
.. 'this->' .. f
.xarg
.fullname
.. '(' .. larg2
.. ');\n'
510 local examine_class
= function(c
)
511 assert(entities
.is_class(c
), 'not a class')
512 local constr
, destr
= {}, nil
513 for _
, f
in ipairs(c
) do
514 if entities
.is_function(f
) then
515 if entities
.is_constructor(f
) then
516 table.insert(constr
, f
)
517 elseif entities
.is_destructor(f
) then
518 assert(not destr
, 'cannot have more than one destructor!')
524 local public_f, protected_f, virtual_f, virt_prot_f, abstract_f = {}, {}, {}, {}, {}
525 for _, f in ipairs(c) do
526 if entities.is_function(f) then
527 if f.xarg.abstract=='1' then
528 table.insert(abstract_f, f)
529 elseif f.xarg.virtual=='1' and f.xarg.access=='protected' then
530 table.insert(virt_prot_f, f)
531 elseif f.xarg.virtual=='1' and f.xarg.access=='public' then
532 table.insert(virtual_f, f)
533 elseif f.xarg.virtual~='1' and f.xarg.access=='protected' then
534 table.insert(protected_f, f)
535 elseif f.xarg.virtual~='1' and f.xarg.access=='public' then
536 table.insert(public_f, f)
541 local cname
= 'lqt_shell_class'..c
.xarg
.id
542 local ret
= 'class '..cname
..' : public '..c
.xarg
.fullname
..' {\npublic:\n'
543 ret
= ret
.. 'lua_State *L;\n'
544 local onlyprivate
= true
545 for _
, f
in ipairs(constr
) do
546 if f
.xarg
.access
~='private' then
548 local larg1
, larg2
= function_proto(f
)
549 assert(larg1
and larg2
, 'cannot reproduce prototype of function')
550 larg1
= (larg1
=='') and '' or (', '..larg1
)
551 ret
= ret
.. cname
.. '(lua_State *l'..larg1
..'):'..c
.xarg
.fullname
..'('
552 ret
= ret
.. larg2
.. '), L(l) {} // '..f
.xarg
.id
..'\n'
556 ret
= ret
.. cname
.. '(lua_State *l):L(l) {} // automatic \n'
557 elseif onlyprivate
then
558 error('cannot bind class: '..c
.xarg
.fullname
..': it has only private constructors')
560 ret
= ret
.. 'virtual ~'..cname
..'() { lqtL_unregister(L, this); }\n'
562 local virtuals
= get_virtuals(c
)
564 for _
, f
in ipairs(virtuals
) do
565 local st
, bd
= pcall(virtual_body
, f
, cname
)
567 ret
= ret
.. virtual_proto(f
) .. ';\n'
568 ret2
= ret2
.. bd
.. '\n'
572 ret
= ret
.. '};\n' .. ret2
576 for _
, v
in pairs(xmlstream
.byid
) do
577 --if string.find(v.label, 'Function')==1 and v.xarg.virtual and v.xarg.abstract then io.stderr:write(v.xarg.fullname, '\n') end
578 if false and string.find(v
.label
, 'Function')==1 and (not filter_out(v
, FUNCTIONS_FILTERS
)) then
579 local status
, err
= pcall(function_description
, v
)
580 --io[status and 'stdout' or 'stderr']:write((status and '' or v.xarg.fullname..': ')..err..'\n')
581 if true or status
then
582 local s
, e
= pcall(calling_code
, v
)
583 --io[s and 'stdout' or 'stderr']:write((s and ''
584 --or ('error calling '..v.xarg.fullname..': '))..e..(s and '' or '\n'))
586 io
.stdout
:write('extern "C" int bound_function'..v
.xarg
.id
..' (lua_State *L) {\n')
588 io
.stdout
:write('}\n') -- FIXME
593 --io[status and 'stdout' or 'stderr']:write((status and '' or v.xarg.fullname..': ')..err..'\n')
594 elseif v
.label
=='Class' and not filter_out(v
, CLASS_FILTERS
) then -- do not support templates yet
595 local st
, ret
= pcall(examine_class
, v
)
596 if st
then print(ret
) else io
.stderr
:write(ret
, '\n') end
599 --table.foreach(name_list, print)