Implicit conversion constructor implementation
[lqt/mk.git] / generator / virtuals.lua
blobf6254b2547ece12a0e3eb5c4a454d571c6cb1696
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)
6 local byname = {}
7 for c in pairs(classes) do
8 byname[c.xarg.fullname] = c
9 end
10 local function get_virtuals(c)
11 local ret = {}
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
16 end
17 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
24 end
25 end
26 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
31 f.xarg.virtual = '1'
32 local n = string.match(f.xarg.name, '~')or f.xarg.name
33 ret[n] = f
34 end
35 end
36 return ret
37 end
38 for c in pairs(classes) do
39 c.virtuals = get_virtuals(c)
40 end
41 end
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)
49 local ret = ''
50 if v.virtual_overload then return v end
51 -- make return type
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
55 end
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
58 local retget = ''
59 if v.return_type then
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 '
67 end
68 retget = retget .. 'lua_settop(L, oldtop);\n return' .. (v.return_type and ' ret' or '')
69 -- make argument push
70 local pushlines, stack = make_pushlines(v.arguments)
71 if not pushlines then
72 ignore(v.xarg.fullname, 'unknown argument type', stack)
73 return nil, 'argument: '..stack
74 end
75 -- make lua call
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..' ('
79 local fallback = ''
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
84 end
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));'
89 end
90 ret = proto .. [[ {
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)) {
96 lua_insert(L, -3);
97 lua_insert(L, -3);
98 ]] .. pushlines .. [[
99 if (!]]..luacall..[[) {
100 ]]..retget..[[;
101 } else {
102 if (lqtL_is_super(L, lua_gettop(L))) {
103 lua_settop(L, oldtop);
104 ]]..fallback..[[
105 } else
106 lua_error(L);
109 lua_settop(L, oldtop);
110 ]] .. fallback .. '\n}\n'
111 v.virtual_overload = ret
112 v.virtual_proto = string.gsub(proto, ';;', '', 1)
113 return v
118 function fill_virtual_overloads(classes)
119 for c in pairs(classes) do
120 if c.virtuals then
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
126 c.abstract = true
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'
143 local argline = ''
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
186 return c
190 function fill_shell_classes(classes)
191 for c in pairs(classes) do
192 if c.shell then
193 local nc = fill_shell_class(c)
194 if not nc then
195 -- FIXME: useless, but may change
196 ignore(c.xarg.fullname, 'failed to generate shell class')
197 classes[c] = nil
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(...)
210 fhead:write(...)
211 fhead:write'\n'
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, '^[^:]+')..'>')
217 print_head''
218 if c.shell then
219 print_head('#include "'..module_name..'_slot.hpp'..'"\n\n')
220 if c.shell_class then
221 print_head(c.shell_class)
222 else
223 dump(c)
227 print_head('extern "C" LQT_EXPORT int luaopen_'..n..' (lua_State *);')
228 print_head('\n\n#endif // LQT_HEAD_'..n)
229 fhead:close()
231 return classes
234 function print_virtual_overloads(classes)
235 for c in pairs(classes) do
236 if c.shell then
237 local vo = ''
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
247 return classes