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')
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 ----------------------------------------------------------------------------------
21 local copy_functions
= function(index
)
22 local ret
, copied
= {}, 0
23 for e
in pairs(index
) do
24 if e
.label
:match
'^Function' then
25 --[[and not (e.xarg.name:match'^[%a]*'=='operator'
26 or e.xarg.fullname:match'%b<>'
27 or e.xarg.name:match'_'
28 or e.xarg.name:match'[xX]11'
29 or e.xarg.fullname:match'QInternal'
30 or e.xarg.access=='private'
31 or e.xarg.access=='protected' -- FIXME
32 or e.xarg.fullname=='QVariant::canConvert') then --]]
37 --removed = removed + (e.label:match'^Function' and 1 or 0)
38 --removed = removed + 1
44 local fix_functions
= function(index
)
45 for f
in pairs(index
) do
47 for i
, a
in ipairs(f
) do
48 -- avoid bogus 'void' arguments
49 if a
.xarg
.type_name
=='void' and i
==1 and f
[2]==nil then break end
50 if a
.label
=='Argument' then
55 if elements
.is_constructor(f
) then
56 f
.xarg
.fullname
= '*new '..f
.xarg
.fullname
57 f
.return_type
= f
.xarg
.type_base
..'&'
59 elseif elements
.is_destructor(f
) or f
.xarg
.type_name
=='void' then
62 if false and f
.xarg
.access
=='protected' then
63 local shellname
= 'lqt_shell_'..string.gsub(f
.parent
.xarg
.fullname
, '::', '_LQT_')
64 f
.xarg
.fullname
= shellname
..'::'..f
.xarg
.name
65 if f
.xarg
.static
~='1' then
67 local newarg
= { label
='Argument', xarg
= {
68 type_name
= f
.xarg
.member_of_class
..'*',
70 table.insert(args
, newarg
, 1)
73 f
.return_type
= f
.xarg
.type_name
79 local copy_enums
= function(index
)
81 for e
in pairs(index
) do
83 and e
.xarg
.access
~='public' then
90 local fix_enums
= function(index
)
91 for e
in pairs(index
) do
93 for _
, v
in ipairs(e
) do
94 if v
.label
=='Enumerators' then
95 values
[#values
] = v
.xarg
.name
103 local copy_classes
= function(index
)
105 for e
in pairs(index
) do
107 and e
.xarg
.access
~='private'
108 and not (e
.xarg
.fullname
:match
'%b<>'
109 or e
.xarg
.fullname
=='QDebug::Stream'
110 or e
.xarg
.fullname
=='QForeachContainerBase'
111 or e
.xarg
.fullname
=='QByteArray::Data'
112 or e
.xarg
.fullname
=='QVariant::Private::Data'
113 or e
.xarg
.fullname
=='QRegion::QRegionData'
114 or e
.xarg
.fullname
=='QTextStreamManipulator'
115 or e
.xarg
.fullname
=='QString::Data'
116 or e
.xarg
.fullname
=='QThreadStorageData'
124 local fill_virtuals
= function(index
)
126 for c
in pairs(index
) do
127 classes
[c
.xarg
.fullname
] = c
130 get_virtuals
= function(c
)
132 for _
, f
in ipairs(c
) do
133 if f
.label
=='Function' and f
.xarg
.virtual
=='1' then
134 local n
= string.match(f
.xarg
.name
, '~') or f
.xarg
.name
135 if n
~='~' then ret
[n
] = f
end
138 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
139 local base
= classes
[b
]
140 if type(base
)=='table' then
141 local bv
= get_virtuals(base
)
142 for n
, f
in pairs(bv
) do
143 if not ret
[n
] then ret
[n
] = f
end
147 for _
, f
in ipairs(c
) do
148 if f
.label
=='Function'
149 and f
.xarg
.access
~='private'
150 and (ret
[string.match(f
.xarg
.name
, '~') or f
.xarg
.name
]) then
152 local n
= string.match(f
.xarg
.name
, '~')or f
.xarg
.name
158 for c
in pairs(index
) do
159 c
.virtuals
= get_virtuals(c
)
160 for _
, f
in pairs(c
.virtuals
) do
161 if f
.xarg
.abstract
=='1' then c
.abstract
=true break end
167 local fill_special_methods
= function(index
)
168 for c
in pairs(index
) do
169 local construct
, destruct
, normal
= {}, nil, {}
170 local n
= c
.xarg
.name
171 local auto
, copy
= true, nil
172 for _
, f
in ipairs(c
) do
173 if n
==f
.xarg
.name
then
175 if #(f
.arguments
or {})==1 and
176 f
.arguments
[1].xarg
.type_name
==(c
.xarg
.fullname
..' const&') then
177 copy
= f
.xarg
.access
or 'PUBLIC?'
180 if n
==f
.xarg
.name
then
181 table.insert(construct
, f
)
182 elseif f
.xarg
.name
:match
'~' then
185 if (not string.match(f
.xarg
.name
, '^operator%W'))
186 and (not f
.xarg
.member_template_parameters
) then
187 table.insert(normal
, f
)
191 construct
.auto
= auto
192 construct
.copy
= (copy
==nil and 'auto' or copy
) -- FIXME: must try
193 c
.constructors
= construct
194 c
.destructor
= destruct
and (destruct
.xarg
.access
or 'PUBLIC?') or 'auto'
200 local fill_copy_constructor
= function(index
)
202 for c
in pairs(index
) do
203 classes
[c
.xarg
.name
] = c
207 if c
.destructor
=='auto' then
209 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
210 local base
= classes
[b
]
211 if base
and destr(base
)=='private' then
212 c
.destructor
= 'private'
220 copy_constr
= function(c
)
221 if c
.constructors
.copy
=='auto' then
223 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
224 local base
= classes
[b
]
225 if base
and copy_constr(base
)=='private' then
226 c
.constructors
.copy
= 'private'
231 return c
.constructors
.copy
233 for c
in pairs(index
) do
234 c
.constructors
.copy
= copy_constr(c
)
235 c
.destructor
= destr(c
)
236 --io.stderr:write(c.xarg.fullname, '\t', c.constructors.copy, '\n')
237 --io.stderr:write(c.xarg.fullname, '\t', c.destructor, '\n')
242 local fill_typesystem_with_enums
= function(enums
, types
)
244 for e
in pairs(enums
) do
245 if not types
[e
.xarg
.fullname
] then
247 types
[e
.xarg
.fullname
] = {
249 return 'lqtL_pushenum(L, '..n
..', "'..e
.xarg
.fullname
..'")', 1
252 return 'static_cast<'..e
.xarg
.fullname
..'>'
253 ..'(lqtL_toenum(L, '..n
..', "'..e
.xarg
.fullname
..'"))', 1
257 --io.stderr:write(e.xarg.fullname, ': already present\n')
263 local fill_typesystem_with_classes
= function(classes
, types
)
265 for c
in pairs(classes
) do
266 if not types
[c
.xarg
.fullname
] then
268 types
[c
.xarg
.fullname
..'*'] = {
269 -- the argument is a pointer to class
271 return 'lqtL_passudata(L, '..n
..', "'..c
.xarg
.fullname
..'*")', 1
274 return 'static_cast<'..c
.xarg
.fullname
..'*>'
275 ..'(lqtL_toudata(L, '..n
..', "'..c
.xarg
.fullname
..'*"))', 1
278 types
[c
.xarg
.fullname
..'&'] = {
279 -- the argument is a reference to class
281 return 'lqtL_passudata(L, &'..n
..', "'..c
.xarg
.fullname
..'*")', 1
284 return '*static_cast<'..c
.xarg
.fullname
..'*>'
285 ..'(lqtL_toudata(L, '..n
..', "'..c
.xarg
.fullname
..'*"))', 1
288 if c
.constructors
.copy
~='private' then -- and c.destructor~='private' then
289 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
290 types
[c
.xarg
.fullname
] = {
291 -- the argument is the class itself
293 return 'lqtL_passudata(L, new '..shellname
294 ..'(L, '..n
..'), "'..c
.xarg
.fullname
..'*")', 1
297 return '*static_cast<'..c
.xarg
.fullname
..'*>'
298 ..'(lqtL_toudata(L, '..n
..', "'..c
.xarg
.fullname
..'*"))', 1
301 types
[c
.xarg
.fullname
..' const&'] = {
302 -- the argument is a pointer to class
304 return 'lqtL_passudata(L, new '..shellname
305 ..'(L, '..n
..'), "'..c
.xarg
.fullname
..'*")', 1
308 return '*static_cast<'..c
.xarg
.fullname
..'*>'
309 ..'(lqtL_toudata(L, '..n
..', "'..c
.xarg
.fullname
..'*"))', 1
313 io
.stderr
:write(c
.xarg
.fullname
, ': no copy constructor\n')
316 io
.stderr
:write(c
.xarg
.fullname
, ': already present\n')
322 local fill_wrapper_code
= function(f
, types
)
323 local stackn
, argn
= 1, 1
324 local wrap
, line
= '', ''
325 if f
.xarg
.member_of_class
and f
.xarg
.static
~='1' then
326 if not types
[f
.xarg
.member_of_class
..'*'] then return nil end -- print(f.xarg.member_of_class) return nil end
327 local sget
, sn
= types
[f
.xarg
.member_of_class
..'*'].get(stackn
)
328 wrap
= wrap
.. ' ' .. f
.xarg
.member_of_class
.. '* self = ' .. sget
.. ';\n'
332 lua_pushstring(L, "this pointer is NULL");
337 line
= 'self->'..f
.xarg
.fullname
..'('
339 line
= f
.xarg
.fullname
..'('
341 for i
, a
in ipairs(f
.arguments
) do
342 if not types
[a
.xarg
.type_name
] then return nil end -- print(a.xarg.type_name) return nil end
343 local aget
, an
= types
[a
.xarg
.type_name
].get(stackn
)
344 wrap
= wrap
.. ' ' .. a
.xarg
.type_name
.. ' arg' .. tostring(argn
) .. ' = '
345 wrap
= wrap
.. aget
.. ';\n'
346 line
= line
.. (argn
==1 and 'arg' or ', arg') .. argn
351 -- FIXME: hack follows for constructors
352 if f
.calling_line
then line
= f
.calling_line
end
353 if f
.return_type
then line
= f
.return_type
.. ' ret = ' .. line
end
354 wrap
= wrap
.. ' ' .. line
.. ';\n lua_settop(L, 0);\n' -- lua_pop(L, '..stackn..');\n'
355 if f
.return_type
then
356 if not types
[f
.return_type
] then return nil end
357 local rput
, rn
= types
[f
.return_type
].push
'ret'
358 wrap
= wrap
.. ' luaL_checkstack(L, '..rn
..', "cannot grow stack for return value");\n'
359 wrap
= wrap
.. ' '..rput
..';\n return '..rn
..';\n'
361 wrap
= wrap
.. ' return 0;\n'
363 f
.wrapper_code
= wrap
367 local fill_wrappers
= function(functions
, types
)
369 for f
in pairs(functions
) do
370 f
= fill_wrapper_code(f
, types
)
373 local out
= 'extern "C" int lqt_bind'..f
.xarg
.id
..' (lua_State *L) {\n'
374 .. f
.wrapper_code
.. '}\n'
381 local argument_name
= function(tn
, an
)
383 if string.match(tn
, '%(%*%)') then
384 ret
= string.gsub(tn
, '%(%*%)', '(*'..an
..')', 1)
385 elseif string.match(tn
, '%[.*%]') then
386 ret
= string.gsub(tn
, '(%[.*%])', an
..'%1')
388 ret
= tn
.. ' ' .. an
393 local virtual_overload
= function(v
, types
)
395 if v
.virtual_overload
then return v
end
397 if v
.return_type
and not types
[v
.return_type
] then return nil end
398 local rget
, rn
= '', 0
399 if v
.return_type
then rget
, rn
= types
[v
.return_type
].get
'oldtop+1' end
400 local retget
= (v
.return_type
and argument_name(v
.return_type
, 'ret')
401 .. ' = ' .. rget
.. ';' or '') .. 'lua_settop(L, oldtop);return'
402 .. (v
.return_type
and ' ret' or '')
403 -- make argument push
404 local pushlines
, stack
= '', 0
405 for i
, a
in ipairs(v
.arguments
) do
406 if not types
[a
.xarg
.type_name
] then return nil end
407 local apush
, an
= types
[a
.xarg
.type_name
].push('arg'..i
)
408 pushlines
= pushlines
.. ' ' .. apush
.. ';\n'
412 local luacall
= 'lua_pcall(L, '..stack
..', '..rn
..', 0)'
413 -- make prototype and fallback
414 local proto
= (v
.return_type
or 'void')..' ;;'..v
.xarg
.name
..' ('
416 for i
, a
in ipairs(v
.arguments
) do
417 proto
= proto
.. (i
>1 and ', ' or '')
418 .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
419 fallback
= fallback
.. (i
>1 and ', arg' or 'arg') .. i
421 proto
= proto
.. ')' .. (v
.xarg
.constant
=='1' and ' const' or '')
422 fallback
= (v
.return_type
and 'return this->' or 'this->')
423 .. v
.xarg
.fullname
.. '(' .. fallback
.. ');\n}\n'
425 int oldtop = lua_gettop(L);
426 lqtL_pushudata(L, this, "]]..v
.xarg
.member_of_class
..[[*");
427 lua_getfield(L, -1, "]]..v
.xarg
.name
..[[");
428 if (lua_isfunction(L, -1)) {
430 ]] .. pushlines
.. [[
431 if (]]..luacall
..[[) {
435 lua_settop(L, oldtop);
437 v
.virtual_overload
= ret
438 v
.virtual_proto
= string.gsub(proto
, ';;', '', 1)
442 local fill_shell_class
= function(c
, types
)
443 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
444 local shell
= 'class ' .. shellname
.. ' : public ' .. c
.xarg
.fullname
.. ' {\npublic:\n'
445 shell
= shell
.. ' lua_State *L;\n'
446 for _
, constr
in ipairs(c
.constructors
) do
447 if constr
.xarg
.access
~='private' then
448 local cline
= ' '..shellname
..' (lua_State *l'
450 for i
, a
in ipairs(constr
.arguments
) do
451 cline
= cline
.. ', ' .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
452 argline
= argline
.. (i
>1 and ', arg' or 'arg') .. i
454 cline
= cline
.. ') : ' .. c
.xarg
.fullname
.. '(' .. argline
.. '), L(l) {}\n'
455 shell
= shell
.. cline
458 if c
.constructors
.copy
=='auto' then
459 local cline
= ' '..shellname
..' (lua_State *l, '..c
.xarg
.fullname
..' const& arg1)'
460 cline
= cline
.. ' : ' .. c
.xarg
.fullname
.. '(arg1), L(l) {}\n'
461 shell
= shell
.. cline
463 for i
, v
in pairs(c
.virtuals
) do
464 if v
.xarg
.access
~='private' then
465 local vret
= virtual_overload(v
, types
)
466 if v
.virtual_proto
then shell
= shell
.. ' virtual ' .. v
.virtual_proto
.. ';\n' end
469 shell
= shell
.. '};\n'
470 c
.shell_class
= shell
474 local fill_shell_classes
= function(classes
, types
)
476 for c
in pairs(classes
) do
478 c
= fill_shell_class(c
, types
)
479 if c
then ret
[c
] = true print(c
.shell_class
)
481 io
.stderr
:write(c
.fullname
, '\n')
488 local print_virtual_overloads
= function(classes
, types
)
489 for c
in pairs(classes
) do
490 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
491 for _
,v
in pairs(c
.virtuals
) do
492 if v
.virtual_overload
then
493 print((string.gsub(v
.virtual_overload
, ';;', shellname
..'::', 1)))
500 local print_wrappers
= function(index
)
501 for c
in pairs(index
) do
503 for _
, f
in ipairs(c
.methods
) do
504 if f
.wrapper_code
then
505 local out
= 'extern "C" int lqt_bind'..f
.xarg
.id
506 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
507 if f
.xarg
.access
=='public' then print(out
) end
508 meta
[f
.xarg
.id
] = f
.xarg
.name
512 for _
, f
in ipairs(c
.constructors
) do
513 if f
.wrapper_code
then
514 local out
= 'extern "C" int lqt_bind'..f
.xarg
.id
515 ..' (lua_State *L) {\n'.. f
.wrapper_code
.. '}\n'
516 if f
.xarg
.access
=='public' then print(out
) end
517 meta
[f
.xarg
.id
] = 'new'
525 local fix_methods_wrappers
= function(classes
)
526 for c
in pairs(classes
) do
527 -- if class seems abstract but has a shell class
528 if c
.abstract
and c
.destructor
~='private' then
529 -- is it really abstract?
531 for _
, f
in pairs(c
.virtuals
) do
532 -- if it is abstract but we cannot overload
533 if f
.xarg
.abstract
=='1' and not f
.virtual_overload
then a
= true break end
537 c
.shell
= (not c
.abstract
) and (c
.destructor
~='private')
538 for _
, constr
in ipairs(c
.constructors
) do
539 local shellname
= 'lqt_shell_'..string.gsub(c
.xarg
.fullname
, '::', '_LQT_')
540 constr
.calling_line
= '*new '..shellname
..'(L'
541 for i
=1,#(constr
.arguments
) do
542 constr
.calling_line
= constr
.calling_line
.. ', arg' .. i
544 constr
.calling_line
= constr
.calling_line
.. ')'
550 local functions
= copy_functions(idindex
)
551 local functions
= fix_functions(functions
)
553 local enums
= copy_enums(idindex
)
554 local enums
= fix_enums(enums
)
556 local classes
= copy_classes(idindex
)
557 local classes
= fill_virtuals(classes
)
558 local classes
= fill_special_methods(classes
)
559 local classes
= fill_copy_constructor(classes
)
560 local classes
= fix_methods_wrappers(classes
)
562 local ntable
= function(t
) local ret
=0 for _
in pairs(t
) do ret
=ret
+1 end return ret
end
564 local typesystem
= dofile'types.lua'
566 local debug
= function(...)
567 for i
= 1, select('#',...) do
568 io
.stderr
:write((i
==1) and '' or '\t', (select(i
,...)))
572 debug('funcs', ntable(functions
))
573 debug('enums', ntable(enums
))
574 debug('class', ntable(classes
))
575 local enums
= fill_typesystem_with_enums(enums
, typesystem
)
576 local classes
= fill_typesystem_with_classes(classes
, typesystem
)
577 local functions
= fill_wrappers(functions
, typesystem
)
578 local classes
= fill_shell_classes(classes
, typesystem
)
579 local classes
= print_virtual_overloads(classes
, typesystem
)
580 local classes
= print_wrappers(classes
)
581 debug('funcs', ntable(functions
))
582 debug('enums', ntable(enums
))
583 debug('class', ntable(classes
))
585 local print_virtuals
= function(index
)
586 for c
in pairs(index
) do
588 for n
, f
in pairs(c
.virtuals
) do debug(' '..n
, f
.xarg
.fullname
) end
593 for k
,v
in pairs(typesystem
) do
594 --print(k, v.get'INDEX')
597 --print_virtuals(classes)
599 --print(copy_functions(idindex))