1 module('virtuals', package
.seeall
)
3 --- Retrieves the virtual method for each class. Also retrieves the virtual
4 -- methods for all superclasses.
5 function fill_virtuals(classes
)
7 for c
in pairs(classes
) do
8 byname
[c
.xarg
.fullname
] = c
10 local function get_virtuals(c
, includePrivate
)
12 for _
, f
in ipairs(c
) do
13 if f
.label
=='Function' and f
.xarg
.virtual
~= '1' then
14 methods
[f
.xarg
.name
] = f
19 local function add_overload(name
, func
)
23 -- add virtual methods declared in the class
24 for _
, f
in ipairs(c
) do
25 if f
.label
=='Function' and f
.xarg
.virtual
=='1' then
26 local n
= string.match(f
.xarg
.name
, '~') or f
.xarg
.name
27 if n
~='~' and n
~='metaObject' then
33 -- find virtual methods in base classes
34 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
35 local base
= byname
[b
]
36 if type(base
)=='table' then
37 local bv
= get_virtuals(base
, true)
38 for n
, f
in pairs(bv
) do
39 -- print('found', n, 'in', b, 'for', c.xarg.name, 'have', not not ret[n])
42 -- print('has', n, 'which is not marked virtual')
43 methods
[n
].xarg
.virtual
= '1'
44 add_overload(n
, methods
[n
])
46 -- print('does not have', n)
54 -- mark methods in class not explicitly marked as virtual, as C++
55 -- does not require that overriden methods are marked virtual
56 for _
, f
in ipairs(c
) do
57 local n
= string.match(f
.xarg
.name
, '~') or f
.xarg
.name
58 if f
.label
=='Function'
59 and (includePrivate
or f
.xarg
.access
~='private')
62 -- print('adding', c.xarg.name, n)
68 local virtual_index
= 0
69 for n
, f
in pairs(ret
) do
70 virtual_index
= virtual_index
+ 1
71 f
.virtual_index
= virtual_index
74 return ret
, virtual_index
76 for c
in pairs(classes
) do
77 c
.virtuals
, c
.nvirtuals
= get_virtuals(c
)
82 --- Generates a virtual overload for function 'v'.
83 -- Returns nil if a parameter or return type is of unknown/ignored type. Normal
84 -- virtual methods call original virtual method if no corresponding Lua function is
85 -- found, pure virtual (abstract) methods throw Lua error.
86 function virtual_overload(v
)
87 if v
.virtual_overload
then return v
end
89 if v
.return_type
and not typesystem
[v
.return_type
] then
90 ignore(v
.xarg
.fullname
, 'unknown return type', v
.return_type
)
91 return nil, 'return: '..v
.return_type
94 local rget
, rn
, ret_as
= '', 0
95 if v
.return_type
then rget
, rn
, ret_as
= typesystem
[v
.return_type
].get
'oldtop+2' end
98 local atest
, an
= typesystem
[v
.return_type
].test('oldtop+2')
99 retget
= [[if (!(]]..atest
..[[)) {
100 luaL_error(L, "Unexpected virtual method return type: %s; expecting %s\nin: %s",
101 luaL_typename(L,oldtop+2), "]]..v
.return_type
..[[", lqtL_source(L,oldtop+1));
104 retget
= retget
.. argument_name(ret_as
or v
.return_type
, 'ret') .. ' = ' .. rget
.. ';\n '
106 retget
= retget
.. 'lua_settop(L, oldtop);\n return' .. (v
.return_type
and ' ret' or '')
107 -- make argument push
108 local pushlines
, stack
= make_pushlines(v
.arguments
)
109 if not pushlines
then
110 ignore(v
.xarg
.fullname
, 'unknown argument type', stack
)
111 return nil, 'argument: '..stack
114 local luacall
= 'lqtL_pcall(L, '..(stack
+1)..', '..rn
..', 0)'
115 -- make prototype and fallback
116 local proto
= (v
.return_type
or 'void')..' ;;'..v
.xarg
.name
..' ('
118 for i
, a
in ipairs(v
.arguments
) do
119 proto
= proto
.. (i
>1 and ', ' or '')
120 .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
121 fallback
= fallback
.. (i
>1 and ', arg' or 'arg') .. i
123 proto
= proto
.. ')' .. (v
.xarg
.constant
=='1' and ' const' or '')
124 fallback
= (v
.return_type
and 'return this->' or 'this->') .. v
.xarg
.fullname
.. '(' .. fallback
.. ');' ..
125 (v
.return_type
and '' or ' return;')
126 if v
.xarg
.abstract
then
127 fallback
= 'luaL_error(L, "Abstract method %s for %s not implemented! In %s", "' .. v
.xarg
.name
.. '", lqtL_source(L,oldtop+1));'
129 ret
= proto
.. ' {\n'
130 ret
= ret
.. ' int oldtop = lua_gettop(L);\n'
131 if VERBOSE_BUILD
then
132 ret
= ret
.. ' printf("[%lx; %p] virtual %s :: %s (%d) => %d\\n", ' ..
133 'QThread::currentThreadId(), this, ' ..
134 '"'..v
.xarg
.member_of_class
.. '", ' ..
135 '"'..v
.xarg
.name
..'", '..
136 v
.virtual_index
.. ', '..
137 '(int)(bool)hasOverride[' .. v
.virtual_index
.. ']'..
140 ret
= ret
.. ' if (!hasOverride[' .. v
.virtual_index
.. ']) { \n'
141 ret
= ret
.. ' ' .. fallback
.. '\n }\n'
143 lqtL_pushudata(L, this, "]]..string.gsub(v
.xarg
.member_of_class
, '::', '.')..[[*");
144 lqtL_getoverload(L, -1, "]]..v
.xarg
.name
..[[");
145 lua_pushvalue(L, -1); // copy of function
146 if (lua_isfunction(L, -1)) {
149 ]] .. pushlines
.. [[
150 if (!]]..luacall
..[[) {
153 if (lqtL_is_super(L, lua_gettop(L))) {
154 lua_settop(L, oldtop);
160 lua_settop(L, oldtop);
165 v
.virtual_overload
= ret
166 v
.virtual_proto
= string.gsub(proto
, ';;', '', 1)
172 function fill_virtual_overloads(classes
)
173 for c
in pairs(classes
) do
175 for i
, v
in pairs(c
.virtuals
) do
176 if v
.xarg
.access
~='private' then
177 local vret
, err
= virtual_overload(v
)
178 if not vret
and v
.xarg
.abstract
then
179 -- cannot create instance without implementation of an abstract method
190 function fill_shell_class(c
)
191 local shellname
= 'lqt_shell_'..c
.xarg
.cname
192 local shell
= 'class LQT_EXPORT ' .. shellname
.. ' : public ' .. c
.xarg
.fullname
.. ' {\n'
193 shell
= shell
.. ' lua_State *L;\n'
194 shell
= shell
.. ' QBitArray hasOverride;\n'
195 shell
= shell
.. 'public:\n'
196 shell
= shell
.. ' static int lqtAddOverride(lua_State *L);\n'
197 for _
, constr
in ipairs(c
.constructors
) do
198 if constr
.xarg
.access
~='private' then
199 local cline
= ' '..shellname
..' (lua_State *l'
201 for i
, a
in ipairs(constr
.arguments
) do
202 cline
= cline
.. ', ' .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
203 argline
= argline
.. (i
>1 and ', arg' or 'arg') .. i
205 cline
= cline
.. ') : ' .. c
.xarg
.fullname
206 .. '(' .. argline
.. '), L(l), hasOverride(' .. c
.nvirtuals
.. ') '
207 .. '{\n lqtL_register(L, this);\n'
208 if c
.protected_enums
then
209 cline
= cline
.. ' registerEnums();\n'
211 cline
= cline
.. ' }\n'
212 shell
= shell
.. cline
215 if c
.copy_constructor
==nil and c
.public_constr
then
216 local cline
= ' '..shellname
..' (lua_State *l, '..c
.xarg
.fullname
..' const& arg1)'
217 cline
= cline
.. ' : ' .. c
.xarg
.fullname
.. '(arg1), L(l) {}\n'
218 shell
= shell
.. cline
220 for i
, v
in pairs(c
.virtuals
) do
221 if v
.xarg
.access
~='private' then
222 if v
.virtual_proto
then shell
= shell
.. ' virtual ' .. v
.virtual_proto
.. ';\n' end
225 shell
= shell
.. ' ~'..shellname
..'() { lqtL_unregister(L, this); }\n'
226 if c
.shell
and c
.qobject
then
227 shell
= shell
.. ' static QMetaObject staticMetaObject;\n'
228 shell
= shell
.. ' virtual const QMetaObject *metaObject() const;\n'
229 shell
= shell
.. ' virtual int qt_metacall(QMetaObject::Call, int, void **);\n'
230 shell
= shell
.. 'private:\n'
231 shell
= shell
.. ' Q_DISABLE_COPY('..shellname
..');\n'
233 if c
.protected_enums
then
234 shell
= shell
.. ' void registerEnums() {\n'
235 for _
,e
in ipairs(c
.protected_enums
) do
236 shell
= shell
.. e
.enum_table
237 shell
= shell
.. ' lqtL_createenum(L, lqt_enum'..e
.xarg
.id
..', "'..string.gsub(e
.xarg
.fullname
, "::", ".")..'");\n'
239 shell
= shell
.. ' }\n'
241 shell
= shell
.. '};\n'
242 c
.shell_class
= shell
247 function fill_shell_classes(classes
)
248 for c
in pairs(classes
) do
250 local nc
= fill_shell_class(c
)
252 -- FIXME: useless, but may change
253 ignore(c
.xarg
.fullname
, 'failed to generate shell class')
260 ----------------------------------------------------------------------
262 function print_shell_classes(classes
)
263 for c
in pairs(classes
) do
264 local n
= c
.xarg
.cname
265 local fhead
= assert(io
.open(module_name
.._src
..module_name
..'_head_'..n
..'.hpp', 'w'))
266 local print_head
= function(...)
270 print_head('#ifndef LQT_HEAD_'..n
)
271 print_head('#define LQT_HEAD_'..n
)
272 print_head(output_includes
)
273 --print_head('#include <'..string.match(c.xarg.fullname, '^[^:]+')..'>')
276 print_head('#include "'..module_name
..'_slot.hpp'..'"\n\n')
277 if c
.shell_class
then
278 print_head(c
.shell_class
)
284 print_head('extern "C" LQT_EXPORT int luaopen_'..n
..' (lua_State *);')
285 print_head('\n\n#endif // LQT_HEAD_'..n
)
291 function print_virtual_overloads(classes
)
292 for c
in pairs(classes
) do
295 local shellname
= 'lqt_shell_'..c
.xarg
.cname
296 for _
,v
in pairs(c
.virtuals
) do
297 if v
.virtual_overload
then
298 vo
= vo
.. string.gsub(v
.virtual_overload
, ';;', shellname
..'::', 1)
301 c
.virtual_overloads
= vo
307 function sort_by_index(c
)
309 for name
, virt
in pairs(c
.virtuals
) do
310 res
[virt
.virtual_index
] = virt