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 local virtual_index
= 0
13 local function add_overload(name
, func
)
14 virtual_index
= virtual_index
+ 1
15 func
.virtual_index
= virtual_index
19 -- add virtual methods declared in the class
20 for _
, f
in ipairs(c
) do
21 if f
.label
=='Function' and f
.xarg
.virtual
=='1' then
22 local n
= string.match(f
.xarg
.name
, '~') or f
.xarg
.name
23 if n
~='~' and n
~='metaObject' then
29 -- find virtual methods in base classes
30 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
31 local base
= byname
[b
]
32 if type(base
)=='table' then
33 local bv
= get_virtuals(base
, true)
34 for n
, f
in pairs(bv
) do
35 if not ret
[n
] then add_overload(n
, f
) end
40 -- mark methods in class not explicitly marked as virtual, as C++
41 -- does not require that overriden methods are marked virtual
42 for _
, f
in ipairs(c
) do
43 local n
= string.match(f
.xarg
.name
, '~') or f
.xarg
.name
44 if f
.label
=='Function'
45 and (includePrivate
or f
.xarg
.access
~='private')
51 return ret
, virtual_index
53 for c
in pairs(classes
) do
54 c
.virtuals
, c
.nvirtuals
= get_virtuals(c
)
59 --- Generates a virtual overload for function 'v'.
60 -- Returns nil if a parameter or return type is of unknown/ignored type. Normal
61 -- virtual methods call original virtual method if no corresponding Lua function is
62 -- found, pure virtual (abstract) methods throw Lua error.
63 function virtual_overload(v
)
65 if v
.virtual_overload
then return v
end
67 if v
.return_type
and not typesystem
[v
.return_type
] then
68 ignore(v
.xarg
.fullname
, 'unknown return type', v
.return_type
)
69 return nil, 'return: '..v
.return_type
71 local rget
, rn
, ret_as
= '', 0
72 if v
.return_type
then rget
, rn
, ret_as
= typesystem
[v
.return_type
].get
'oldtop+2' end
75 local atest
, an
= typesystem
[v
.return_type
].test('oldtop+2')
76 retget
= [[if (!(]]..atest
..[[)) {
77 luaL_error(L, "Unexpected virtual method return type: %s; expecting %s\nin: %s",
78 luaL_typename(L,oldtop+2), "]]..v
.return_type
..[[", lqtL_source(L,oldtop+1));
81 retget
= retget
.. argument_name(ret_as
or v
.return_type
, 'ret') .. ' = ' .. rget
.. ';\n '
83 retget
= retget
.. 'lua_settop(L, oldtop);\n return' .. (v
.return_type
and ' ret' or '')
85 local pushlines
, stack
= make_pushlines(v
.arguments
)
87 ignore(v
.xarg
.fullname
, 'unknown argument type', stack
)
88 return nil, 'argument: '..stack
91 local luacall
= 'lqtL_pcall(L, '..(stack
+1)..', '..rn
..', 0)'
92 -- make prototype and fallback
93 local proto
= (v
.return_type
or 'void')..' ;;'..v
.xarg
.name
..' ('
95 for i
, a
in ipairs(v
.arguments
) do
96 proto
= proto
.. (i
>1 and ', ' or '')
97 .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
98 fallback
= fallback
.. (i
>1 and ', arg' or 'arg') .. i
100 proto
= proto
.. ')' .. (v
.xarg
.constant
=='1' and ' const' or '')
101 fallback
= (v
.return_type
and 'return this->' or 'this->') .. v
.xarg
.fullname
.. '(' .. fallback
.. ');' ..
102 (v
.return_type
and '' or ' return;')
103 if v
.xarg
.abstract
then
104 fallback
= 'luaL_error(L, "Abstract method %s not implemented! In %s", "' .. v
.xarg
.name
.. '", lqtL_source(L,oldtop+1));'
106 ret
= proto
.. ' {\n'
107 ret
= ret
.. ' int oldtop = lua_gettop(L);\n'
108 ret
= ret
.. ' printf("Checking for override idx: %d name: %s class: %s value: %d in thread: %lx\\n", ' ..
109 v
.virtual_index
.. ', "'..v
.xarg
.name
..'", "'.. v
.xarg
.member_of_class
.. '", ' ..
110 '(int)(bool)hasOverride[' .. v
.virtual_index
.. '], QThread::currentThreadId());\n'
111 ret
= ret
.. ' if (!hasOverride[' .. v
.virtual_index
.. ']) { \n'
112 ret
= ret
.. ' ' .. fallback
.. '\n }\n'
114 lqtL_pushudata(L, this, "]]..string.gsub(v
.xarg
.member_of_class
, '::', '.')..[[*");
115 lqtL_getoverload(L, -1, "]]..v
.xarg
.name
..[[");
116 lua_pushvalue(L, -1); // copy of function
117 if (lua_isfunction(L, -1)) {
120 ]] .. pushlines
.. [[
121 if (!]]..luacall
..[[) {
124 if (lqtL_is_super(L, lua_gettop(L))) {
125 lua_settop(L, oldtop);
131 lua_settop(L, oldtop);
136 v
.virtual_overload
= ret
137 v
.virtual_proto
= string.gsub(proto
, ';;', '', 1)
143 function fill_virtual_overloads(classes
)
144 for c
in pairs(classes
) do
146 for i
, v
in pairs(c
.virtuals
) do
147 if v
.xarg
.access
~='private' then
148 local vret
, err
= virtual_overload(v
)
149 if not vret
and v
.xarg
.abstract
then
150 -- cannot create instance without implementation of an abstract method
161 function fill_shell_class(c
)
162 local shellname
= 'lqt_shell_'..c
.xarg
.cname
163 local shell
= 'class LQT_EXPORT ' .. shellname
.. ' : public ' .. c
.xarg
.fullname
.. ' {\n'
164 shell
= shell
.. ' lua_State *L;\n'
165 shell
= shell
.. ' QBitArray hasOverride;\n'
166 shell
= shell
.. 'public:\n'
167 shell
= shell
.. ' static int lqtAddOverride(lua_State *L);\n'
168 for _
, constr
in ipairs(c
.constructors
) do
169 if constr
.xarg
.access
~='private' then
170 local cline
= ' '..shellname
..' (lua_State *l'
172 for i
, a
in ipairs(constr
.arguments
) do
173 cline
= cline
.. ', ' .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
174 argline
= argline
.. (i
>1 and ', arg' or 'arg') .. i
176 cline
= cline
.. ') : ' .. c
.xarg
.fullname
177 .. '(' .. argline
.. '), L(l), hasOverride(' .. c
.nvirtuals
.. ') '
178 .. '{\n lqtL_register(L, this);\n'
179 if c
.protected_enums
then
180 cline
= cline
.. ' registerEnums();\n'
182 cline
= cline
.. ' }\n'
183 shell
= shell
.. cline
186 if c
.copy_constructor
==nil and c
.public_constr
then
187 local cline
= ' '..shellname
..' (lua_State *l, '..c
.xarg
.fullname
..' const& arg1)'
188 cline
= cline
.. ' : ' .. c
.xarg
.fullname
.. '(arg1), L(l) {}\n'
189 shell
= shell
.. cline
191 for i
, v
in pairs(c
.virtuals
) do
192 if v
.xarg
.access
~='private' then
193 if v
.virtual_proto
then shell
= shell
.. ' virtual ' .. v
.virtual_proto
.. ';\n' end
196 shell
= shell
.. ' ~'..shellname
..'() { lqtL_unregister(L, this); }\n'
197 if c
.shell
and c
.qobject
then
198 shell
= shell
.. ' static QMetaObject staticMetaObject;\n'
199 shell
= shell
.. ' virtual const QMetaObject *metaObject() const;\n'
200 shell
= shell
.. ' virtual int qt_metacall(QMetaObject::Call, int, void **);\n'
201 shell
= shell
.. 'private:\n'
202 shell
= shell
.. ' Q_DISABLE_COPY('..shellname
..');\n'
204 if c
.protected_enums
then
205 shell
= shell
.. ' void registerEnums() {\n'
206 for _
,e
in ipairs(c
.protected_enums
) do
207 shell
= shell
.. e
.enum_table
208 shell
= shell
.. ' lqtL_createenum(L, lqt_enum'..e
.xarg
.id
..', "'..string.gsub(e
.xarg
.fullname
, "::", ".")..'");\n'
210 shell
= shell
.. ' }\n'
212 shell
= shell
.. '};\n'
213 c
.shell_class
= shell
218 function fill_shell_classes(classes
)
219 for c
in pairs(classes
) do
221 local nc
= fill_shell_class(c
)
223 -- FIXME: useless, but may change
224 ignore(c
.xarg
.fullname
, 'failed to generate shell class')
231 ----------------------------------------------------------------------
233 function print_shell_classes(classes
)
234 for c
in pairs(classes
) do
235 local n
= c
.xarg
.cname
236 local fhead
= assert(io
.open(module_name
.._src
..module_name
..'_head_'..n
..'.hpp', 'w'))
237 local print_head
= function(...)
241 print_head('#ifndef LQT_HEAD_'..n
)
242 print_head('#define LQT_HEAD_'..n
)
243 print_head(output_includes
)
244 --print_head('#include <'..string.match(c.xarg.fullname, '^[^:]+')..'>')
247 print_head('#include "'..module_name
..'_slot.hpp'..'"\n\n')
248 if c
.shell_class
then
249 print_head(c
.shell_class
)
255 print_head('extern "C" LQT_EXPORT int luaopen_'..n
..' (lua_State *);')
256 print_head('\n\n#endif // LQT_HEAD_'..n
)
262 function print_virtual_overloads(classes
)
263 for c
in pairs(classes
) do
266 local shellname
= 'lqt_shell_'..c
.xarg
.cname
267 for _
,v
in pairs(c
.virtuals
) do
268 if v
.virtual_overload
then
269 vo
= vo
.. string.gsub(v
.virtual_overload
, ';;', shellname
..'::', 1)
272 c
.virtual_overloads
= vo
278 function sort_by_index(c
)
280 for name
, virt
in pairs(c
.virtuals
) do
281 res
[virt
.virtual_index
] = virt