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
)
12 for _
, f
in ipairs(c
) do
13 if f
.label
=='Function' and f
.xarg
.virtual
=='1' then
14 local n
= string.match(f
.xarg
.name
, '~') or f
.xarg
.name
15 if n
~='~' and n
~='metaObject' then ret
[n
] = f
end
18 for b
in string.gmatch(c
.xarg
.bases
or '', '([^;]+);') do
19 local base
= byname
[b
]
20 if type(base
)=='table' then
21 local bv
= get_virtuals(base
)
22 for n
, f
in pairs(bv
) do
23 if not ret
[n
] then ret
[n
] = f
end
27 for _
, f
in ipairs(c
) do
28 if f
.label
=='Function'
29 and f
.xarg
.access
~='private'
30 and (ret
[string.match(f
.xarg
.name
, '~') or f
.xarg
.name
]) then
32 local n
= string.match(f
.xarg
.name
, '~')or f
.xarg
.name
38 for c
in pairs(classes
) do
39 c
.virtuals
= get_virtuals(c
)
44 --- Generates a virtual overload for function 'v'.
45 -- Returns nil if a parameter or return type is of unknown/ignored type. Normal
46 -- virtual methods call original virtual method if no corresponding Lua function is
47 -- found, pure virtual (abstract) methods throw Lua error.
48 function virtual_overload(v
)
50 if v
.virtual_overload
then return v
end
52 if v
.return_type
and not typesystem
[v
.return_type
] then
53 ignore(v
.xarg
.fullname
, 'unknown return type', v
.return_type
)
54 return nil, 'return: '..v
.return_type
56 local rget
, rn
, ret_as
= '', 0
57 if v
.return_type
then rget
, rn
, ret_as
= typesystem
[v
.return_type
].get
'oldtop+2' end
60 local atest
, an
= typesystem
[v
.return_type
].test('oldtop+2')
61 retget
= [[if (!(]]..atest
..[[)) {
62 luaL_error(L, "Unexpected virtual method return type: %s; expecting %s\nin: %s",
63 luaL_typename(L,oldtop+2), "]]..v
.return_type
..[[", lqtL_source(L,oldtop+1));
66 retget
= retget
.. argument_name(ret_as
or v
.return_type
, 'ret') .. ' = ' .. rget
.. ';\n '
68 retget
= retget
.. 'lua_settop(L, oldtop);\n return' .. (v
.return_type
and ' ret' or '')
70 local pushlines
, stack
= make_pushlines(v
.arguments
)
72 ignore(v
.xarg
.fullname
, 'unknown argument type', stack
)
73 return nil, 'argument: '..stack
76 local luacall
= 'lqtL_pcall(L, '..(stack
+1)..', '..rn
..', 0)'
77 -- make prototype and fallback
78 local proto
= (v
.return_type
or 'void')..' ;;'..v
.xarg
.name
..' ('
80 for i
, a
in ipairs(v
.arguments
) do
81 proto
= proto
.. (i
>1 and ', ' or '')
82 .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
83 fallback
= fallback
.. (i
>1 and ', arg' or 'arg') .. i
85 proto
= proto
.. ')' .. (v
.xarg
.constant
=='1' and ' const' or '')
86 fallback
= (v
.return_type
and 'return this->' or 'this->') .. v
.xarg
.fullname
.. '(' .. fallback
.. ');'
87 if v
.xarg
.abstract
then
88 fallback
= 'luaL_error(L, "Abstract method %s not implemented! In %s", "' .. v
.xarg
.name
.. '", lqtL_source(L,oldtop+1));'
91 int oldtop = lua_gettop(L);
92 lqtL_pushudata(L, this, "]]..string.gsub(v
.xarg
.member_of_class
, '::', '.')..[[*");
93 lqtL_getoverload(L, -1, "]]..v
.xarg
.name
..[[");
94 lua_pushvalue(L, -1); // copy of function
95 if (lua_isfunction(L, -1)) {
99 if (!]]..luacall
..[[) {
102 if (lqtL_is_super(L, lua_gettop(L))) {
103 lua_settop(L, oldtop);
109 lua_settop(L, oldtop);
110 ]] .. fallback
.. '\n}\n'
111 v
.virtual_overload
= ret
112 v
.virtual_proto
= string.gsub(proto
, ';;', '', 1)
118 function fill_virtual_overloads(classes
)
119 for c
in pairs(classes
) do
121 for i
, v
in pairs(c
.virtuals
) do
122 if v
.xarg
.access
~='private' then
123 local vret
, err
= virtual_overload(v
)
124 if not vret
and v
.xarg
.abstract
then
125 -- cannot create instance without implementation of an abstract method
136 function fill_shell_class(c
)
137 local shellname
= 'lqt_shell_'..c
.xarg
.cname
138 local shell
= 'class LQT_EXPORT ' .. shellname
.. ' : public ' .. c
.xarg
.fullname
.. ' {\npublic:\n'
139 shell
= shell
.. ' lua_State *L;\n'
140 for _
, constr
in ipairs(c
.constructors
) do
141 if constr
.xarg
.access
~='private' then
142 local cline
= ' '..shellname
..' (lua_State *l'
144 for i
, a
in ipairs(constr
.arguments
) do
145 cline
= cline
.. ', ' .. argument_name(a
.xarg
.type_name
, 'arg'..i
)
146 argline
= argline
.. (i
>1 and ', arg' or 'arg') .. i
148 cline
= cline
.. ') : ' .. c
.xarg
.fullname
149 .. '(' .. argline
.. '), L(l) '
150 .. '{\n lqtL_register(L, this);\n'
151 if c
.protected_enums
then
152 cline
= cline
.. ' registerEnums();\n'
154 cline
= cline
.. ' }\n'
155 shell
= shell
.. cline
158 if c
.copy_constructor
==nil and c
.public_constr
then
159 local cline
= ' '..shellname
..' (lua_State *l, '..c
.xarg
.fullname
..' const& arg1)'
160 cline
= cline
.. ' : ' .. c
.xarg
.fullname
.. '(arg1), L(l) {}\n'
161 shell
= shell
.. cline
163 for i
, v
in pairs(c
.virtuals
) do
164 if v
.xarg
.access
~='private' then
165 if v
.virtual_proto
then shell
= shell
.. ' virtual ' .. v
.virtual_proto
.. ';\n' end
168 shell
= shell
.. ' ~'..shellname
..'() { lqtL_unregister(L, this); }\n'
169 if c
.shell
and c
.qobject
then
170 shell
= shell
.. ' static QMetaObject staticMetaObject;\n'
171 shell
= shell
.. ' virtual const QMetaObject *metaObject() const;\n'
172 shell
= shell
.. ' virtual int qt_metacall(QMetaObject::Call, int, void **);\n'
173 shell
= shell
.. 'private:\n'
174 shell
= shell
.. ' Q_DISABLE_COPY('..shellname
..');\n'
176 if c
.protected_enums
then
177 shell
= shell
.. ' void registerEnums() {\n'
178 for _
,e
in ipairs(c
.protected_enums
) do
179 shell
= shell
.. e
.enum_table
180 shell
= shell
.. ' lqtL_createenum(L, lqt_enum'..e
.xarg
.id
..', "'..string.gsub(e
.xarg
.fullname
, "::", ".")..'");\n'
182 shell
= shell
.. ' }\n'
184 shell
= shell
.. '};\n'
185 c
.shell_class
= shell
190 function fill_shell_classes(classes
)
191 for c
in pairs(classes
) do
193 local nc
= fill_shell_class(c
)
195 -- FIXME: useless, but may change
196 ignore(c
.xarg
.fullname
, 'failed to generate shell class')
203 ----------------------------------------------------------------------
205 function print_shell_classes(classes
)
206 for c
in pairs(classes
) do
207 local n
= c
.xarg
.cname
208 local fhead
= assert(io
.open(module_name
.._src
..module_name
..'_head_'..n
..'.hpp', 'w'))
209 local print_head
= function(...)
213 print_head('#ifndef LQT_HEAD_'..n
)
214 print_head('#define LQT_HEAD_'..n
)
215 print_head(output_includes
)
216 --print_head('#include <'..string.match(c.xarg.fullname, '^[^:]+')..'>')
219 print_head('#include "'..module_name
..'_slot.hpp'..'"\n\n')
220 if c
.shell_class
then
221 print_head(c
.shell_class
)
227 print_head('extern "C" LQT_EXPORT int luaopen_'..n
..' (lua_State *);')
228 print_head('\n\n#endif // LQT_HEAD_'..n
)
234 function print_virtual_overloads(classes
)
235 for c
in pairs(classes
) do
238 local shellname
= 'lqt_shell_'..c
.xarg
.cname
239 for _
,v
in pairs(c
.virtuals
) do
240 if v
.virtual_overload
then
241 vo
= vo
.. string.gsub(v
.virtual_overload
, ';;', shellname
..'::', 1)
244 c
.virtual_overloads
= vo