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 return typename
..'*;', get_class(fn
), push_class(fn
), 1
128 error('unknown identifier type: '..identifier
.label
)
130 elseif t
.xarg
.array
or t
.xarg
.type_name
:match
'%b[]' then -- FIXME: another hack
131 error'I cannot manipulate arrays'
132 elseif string.match(typename
, '%(%*%)') then
133 -- function pointer type
134 -- FIXME: the XML description does not contain this info
135 error'I cannot manipulate function pointers'
136 elseif t
.xarg
.indirections
then
137 if t
.xarg
.indirections
=='1' then
138 local b
= get_unique_fullname(t
.xarg
.type_base
)
139 if b
.label
=='Class' then
140 -- TODO: check if other modifiers are in place?
141 return t
.xarg
.type_base
..'*;',
142 get_pointer(t
.xarg
.type_base
),
143 push_pointer(t
.xarg
.type_base
), 1
145 error('I cannot manipulate pointers to '..t
.xarg
.type_base
)
148 error'I cannot manipulate double pointers'
150 -- this is any combination of constant, volatile and reference
151 local ret_get
, ret_push
= nil, nil
152 if typename
==(t
.xarg
.type_base
..' const&') then
153 local bt
= get_unique_fullname(t
.xarg
.type_base
)
154 --assert(entities.class_is_copy_constructible(bt))
155 ret_get
= get_constref(t
.xarg
.type_base
)
156 ret_push
= push_constref(t
.xarg
.type_base
)
157 elseif typename
==(t
.xarg
.type_base
..'&') then
158 ret_get
= get_ref(t
.xarg
.type_base
)
159 ret_push
= push_ref(t
.xarg
.type_base
)
161 assert(ret_get
, 'cannot get non-base type '..typename
..' from stack')
162 return type_properties(t
.xarg
.type_base
), ret_get
, ret_push
, 1
166 entities
.return_type
= function(f
)
168 if entities
.is_destructor(f
) then
170 elseif entities
.is_constructor(f
) then
171 -- FIXME: hack follows!
172 assert(f
.xarg
.type_name
==f
.xarg
.type_base
, 'return type of constructor is strange')
173 f
.xarg
.type_name
= f
.xarg
.type_base
..'&'
176 elseif f
.xarg
.type_name
=='' or f
.xarg
.type_name
=='void' then
183 function_description
= function(f
)
185 local args_on_stack
= '' -- arguments_on_stack(f) -- FIXME: use another method
186 return f
.xarg
.type_name
.. ' ' .. f
.xarg
.fullname
.. ' (' .. args_on_stack
.. ')'..
187 (f
.xarg
.static
=='1' and ' [static]' or '')..
188 (f
.xarg
.virtual
=='1' and ' [virtual]' or '')..
189 (entities
.is_constructor(f
) and ' [constructor]' or '')..
190 (entities
.is_destructor(f
) and ' [destructor]' or '')..
191 ' [in ' .. tostring(f
.xarg
.member_of
) .. ']'
194 local argument_number
= function(f
)
197 if entities
.is_destructor(f
) then
199 elseif entities
.is_constructor(f
) then
200 elseif entities
.takes_this_pointer
then
206 local argument_assert
= function(f
)
208 local narg
= argument_number(f
)
209 return 'luaL_checkany(L, '..tostring(narg
)..')'
212 local argument
= function(n
)
213 return 'arg'..tostring(n
)
216 local get_args
= function(f
, indent
)
218 indent
= indent
or ' '
219 local ret
, argi
, shift
= '', 0, 0
220 if entities
.takes_this_pointer(f
) then
222 ret
= ret
.. indent
.. f
.xarg
.member_of_class
.. '* self = '
223 ret
= ret
.. get_pointer(f
.xarg
.member_of_class
)(1) .. ';\n' -- (void)self;\n'
225 for _
,a
in ipairs(f
) do if a
.label
=='Argument' then
227 local _d
, g
, _p
, _n
= type_properties(a
)
228 ret
= ret
.. indent
.. a
.xarg
.type_name
.. ' '..argument(argi
) .. ' = '
229 ret
= ret
.. g(argi
+ shift
) .. ';\n' -- .. '(void) '..argument(argi)..';\n'
230 else error'element in function is not argument'
235 local arg_list
= function(f
)
237 if entities
.is_destructor(f
) then
242 ret
= ret
.. (i
>1 and ', ' and '') .. argument(i
)
248 local function_static_call
= function(f
)
250 if entities
.is_destructor(f
) then
251 return 'delete (self)'
252 elseif entities
.is_constructor(f
) then
253 return '*new '..f
.xarg
.fullname
..arg_list(f
)
254 elseif entities
.takes_this_pointer(f
) then
255 return 'self->'..f
.xarg
.fullname
..arg_list(f
)
257 return f
.xarg
.fullname
..arg_list(f
)
261 local function_shell_call
= function(f
)
263 assert(f
.xarg
.member_of_class
, 'not a shell class member')
264 if entities
.is_destructor(f
) then
265 return 'delete (self)'
266 elseif entities
.is_constructor(f
) then
267 return '*new '..f
.xarg
.fullname
..arg_list(f
)
268 elseif f
.xarg
.access
=='public' then
269 return function_static_call(f
)
270 elseif entities
.takes_this_pointer(f
) then
271 return 'self->'..f
.xarg
.fullname
..arg_list(f
)
273 return f
.xarg
.fullname
..arg_list(f
)
277 local collect_return
= function(f
)
279 local ret_t
= entities
.return_type(f
)
283 return ret_t
.xarg
.type_name
.. ' ret = '
287 local give_back_return
= function(f
)
289 local ret_t
= entities
.return_type(f
)
293 local _d
, _g
, p
, _n
= type_properties(ret_t
)
298 local return_statement
= function(f
)
300 local ret_t
= entities
.return_type(f
)
304 local _d
, _g
, _p
, n
= type_properties(ret_t
)
305 return 'return '..tostring(n
)
309 -- TODO: constructors wait for deciding if shell class is needed
310 local calling_code
= function(f
)
312 local ret
, indent
= '', ' '
315 ret
= ret
..indent
..argument_assert(f
)..';\n'
317 ret
= ret
..get_args(f
, indent
)
319 --if entities.is_constructor(f) then
320 --elseif entities.is_destructor(f) then
326 args = args .. (i > 1 and ', ' or '') .. argument(i)
328 args = '('..args..')';
329 local call_line = f.xarg.fullname .. args .. ';\n'
330 local ret_type = entities.return_type(f)
332 call_line = ret_type.xarg.type_name .. ' ret = ' .. call_line
333 local _d, _g, p, n = type_properties(ret_type)
334 call_line = call_line .. indent .. p'ret' .. '\n'
335 call_line = call_line .. indent .. 'return ' .. tostring(n) .. ';\n'
338 local call_line
= function_static_call(f
)
339 ret
= ret
.. indent
.. collect_return(f
) .. call_line
.. ';\n'
340 local treat_return
= give_back_return(f
)
341 ret
= treat_return
and (ret
..indent
..treat_return
..';\n') or ret
342 ret
= ret
.. indent
.. return_statement(f
) .. ';\n'
355 #include "lqt_common.hpp"
358 #define lqtL_getinteger lua_tointeger
359 #define lqtL_getstring lua_tostring
360 #define lqtL_getnumber lua_tonumber
364 local CLASS_FILTERS
= {
365 function(c
) return c
.xarg
.fullname
:match
'%b<>' end,
366 function(c
) return c
.xarg
.name
:match
'_' end,
367 --function(c) return c.xarg.fullname:match'Q.-Data' end,
368 function(c
) return c
.xarg
.class_type
=='struct' end,
369 function(c
) return c
.xarg
.fullname
=='QVariant::Private::Data' end,
370 function(c
) return c
.xarg
.fullname
=='QTextStreamManipulator' end,
372 local FUNCTIONS_FILTERS
= {
373 function(f
) return f
.xarg
.name
:match
'^[_%w]*'=='operator' end,
374 function(f
) return f
.xarg
.fullname
:match
'%b<>' end,
375 function(f
) return f
.xarg
.name
:match
'_' end,
376 function(f
) return f
.xarg
.fullname
:match
'QInternal' end,
377 function(f
) return f
.xarg
.access
~='public' end,
379 local filter_out
= function(f
, t
)
380 local ret
, msg
, F
= nil, next(t
, nil)
381 while (not ret
) and F
do
383 msg
, F
= next(t
, msg
)
388 local choose_function
= function(f1
, f2
)
394 local function_proto
= function(f
)
396 local larg1
, larg2
= '', ''
399 if a
.label
~='Argument' then error(a
.label
) end
400 if a
.xarg
.type_name
=='void' then
401 larg1
, larg2
= nil, nil
404 if string.match(a
.xarg
.type_name
, '%(%*%)') then
405 larg1
= larg1
.. ', ' .. a
.xarg
.type_name
:gsub('%(%*%)', '(*'..argument(i
)..')')
406 elseif string.match(a
.xarg
.type_name
, '%[.*%]') then
407 larg1
= larg1
.. ', ' .. a
.xarg
.type_name
:gsub('(%[.*%])', argument(i
)..'%1')
409 larg1
= larg1
.. ', ' .. a
.xarg
.type_name
.. ' ' .. argument(i
)
411 larg2
= larg2
.. (i
>1 and ', ' or '') .. argument(i
)
416 local examine_class
= function(c
)
417 assert(entities
.is_class(c
), 'not a class')
418 local constr
, destr
= {}, nil
419 for _
, f
in ipairs(c
) do
420 if entities
.is_function(f
) then
421 if entities
.is_constructor(f
) then
422 table.insert(constr
, f
)
423 elseif entities
.is_destructor(f
) then
424 assert(not destr
, 'cannot have more than one destructor!')
430 local public_f, protected_f, virtual_f, virt_prot_f, abstract_f = {}, {}, {}, {}, {}
431 for _, f in ipairs(c) do
432 if entities.is_function(f) then
433 if f.xarg.abstract=='1' then
434 table.insert(abstract_f, f)
435 elseif f.xarg.virtual=='1' and f.xarg.access=='protected' then
436 table.insert(virt_prot_f, f)
437 elseif f.xarg.virtual=='1' and f.xarg.access=='public' then
438 table.insert(virtual_f, f)
439 elseif f.xarg.virtual~='1' and f.xarg.access=='protected' then
440 table.insert(protected_f, f)
441 elseif f.xarg.virtual~='1' and f.xarg.access=='public' then
442 table.insert(public_f, f)
447 local cname
= 'lqt_shell_class'..c
.xarg
.id
448 local ret
= 'class '..cname
..' : public '..c
.xarg
.fullname
..' {\npublic:\n'
449 ret
= ret
.. 'lua_State *L;\n'
450 local onlyprivate
= true
451 for _
, f
in ipairs(constr
) do
452 if f
.xarg
.access
~='private' then
453 local oop
= onlyprivate
455 local larg1
, larg2
= function_proto(f
)
456 ret
= ret
.. cname
.. '(lua_State *l'..larg1
..'):'..c
.xarg
.fullname
..'('
457 ret
= ret
.. larg2
.. '), L(l) {} // '..f
.xarg
.id
..'\n'
461 ret
= ret
.. cname
.. '(lua_State *l):L(l) {} // automatic \n'
462 elseif onlyprivate
then
463 error('cannot bind class: '..c
.xarg
.fullname
..': it has only private constructors')
465 ret
= ret
.. 'virtual ~'..cname
..'() { lqtL_unregister(L, this); }\n'
470 for _
, v
in pairs(xmlstream
.byid
) do
471 if false and string.find(v
.label
, 'Function')==1 and (not filter_out(v
, FUNCTIONS_FILTERS
)) then
472 local status
, err
= pcall(function_description
, v
)
473 --io[status and 'stdout' or 'stderr']:write((status and '' or v.xarg.fullname..': ')..err..'\n')
474 if true or status
then
475 local s
, e
= pcall(calling_code
, v
)
476 --io[s and 'stdout' or 'stderr']:write((s and ''
477 --or ('error calling '..v.xarg.fullname..': '))..e..(s and '' or '\n'))
479 io
.stdout
:write('extern "C" int bound_function'..v
.xarg
.id
..' (lua_State *L) {\n')
481 io
.stdout
:write('}\n') -- FIXME
486 --io[status and 'stdout' or 'stderr']:write((status and '' or v.xarg.fullname..': ')..err..'\n')
487 elseif v
.label
=='Class' and not filter_out(v
, CLASS_FILTERS
) then -- do not support templates yet
488 local st
, ret
= pcall(examine_class
, v
)
489 if st
then print(ret
) else io
.stderr
:write(ret
, '\n') end
492 --table.foreach(name_list, print)