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 collect_return
= function(f
)
263 local ret_t
= entities
.return_type(f
)
267 return ret_t
.xarg
.type_name
.. ' ret = '
271 local give_back_return
= function(f
)
273 local ret_t
= entities
.return_type(f
)
277 local _d
, _g
, p
, _n
= type_properties(ret_t
)
282 local return_statement
= function(f
)
284 local ret_t
= entities
.return_type(f
)
288 local _d
, _g
, _p
, n
= type_properties(ret_t
)
289 return 'return '..tostring(n
)
293 -- TODO: constructors wait for deciding if shell class is needed
294 local calling_code
= function(f
)
296 local ret
, indent
= '', ' '
299 ret
= ret
..indent
..argument_assert(f
)..';\n'
301 ret
= ret
..get_args(f
, indent
)
303 --if entities.is_constructor(f) then
304 --elseif entities.is_destructor(f) then
310 args = args .. (i > 1 and ', ' or '') .. argument(i)
312 args = '('..args..')';
313 local call_line = f.xarg.fullname .. args .. ';\n'
314 local ret_type = entities.return_type(f)
316 call_line = ret_type.xarg.type_name .. ' ret = ' .. call_line
317 local _d, _g, p, n = type_properties(ret_type)
318 call_line = call_line .. indent .. p'ret' .. '\n'
319 call_line = call_line .. indent .. 'return ' .. tostring(n) .. ';\n'
322 local call_line
= function_static_call(f
)
323 ret
= ret
.. indent
.. collect_return(f
) .. call_line
.. ';\n'
324 local treat_return
= give_back_return(f
)
325 ret
= treat_return
and (ret
..indent
..treat_return
..';\n') or ret
326 ret
= ret
.. indent
.. return_statement(f
) .. ';\n'
339 #include "lqt_common.hpp"
342 #define lqtL_getinteger lua_tointeger
343 #define lqtL_getstring lua_tostring
344 #define lqtL_getnumber lua_tonumber
349 function(f
) return f
.xarg
.name
:match
'^[_%w]*'=='operator' end,
350 function(f
) return f
.xarg
.fullname
:match
'%b<>' end,
351 function(f
) return f
.xarg
.name
:match
'_cast' end,
352 function(f
) return f
.xarg
.fullname
:match
'QInternal' end,
353 function(f
) return f
.xarg
.access
~='public' end,
355 local filter_out
= function(f
)
356 local ret
, msg
, F
= nil, next(FILTERS
, nil)
357 while (not ret
) and F
do
359 msg
, F
= next(FILTERS
, msg
)
364 for _
, v
in pairs(xmlstream
.byid
) do
365 if string.find(v
.label
, 'Function')==1 and (not filter_out(v
)) then
366 local status
, err
= pcall(function_description
, v
)
367 --io[status and 'stdout' or 'stderr']:write((status and '' or v.xarg.fullname..': ')..err..'\n')
369 local s
, e
= pcall(calling_code
, v
)
370 --io[s and 'stdout' or 'stderr']:write((s and ''
371 --or ('error calling '..v.xarg.fullname..': '))..e..(s and '' or '\n'))
373 io
.stdout
:write('extern "C" int bound_function'..v
.xarg
.id
..' (lua_State *L) {\n')
375 io
.stdout
:write('}\n') -- FIXME
380 --io[status and 'stdout' or 'stderr']:write((status and '' or v.xarg.fullname..': ')..err..'\n')
383 --table.foreach(name_list, print)