various fixes
[lqt.git] / binder.lua
blobafb305460995780ddf796abe58a6d56d50fa8e97
1 #!/usr/bin/lua
3 --[[
5 Copyright (c) 2007-2008 Mauro Iazzi
7 Permission is hereby granted, free of charge, to any person
8 obtaining a copy of this software and associated documentation
9 files (the "Software"), to deal in the Software without
10 restriction, including without limitation the rights to use,
11 copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the
13 Software is furnished to do so, subject to the following
14 conditions:
16 The above copyright notice and this permission notice shall be
17 included in all copies or substantial portions of the Software.
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 OTHER DEALINGS IN THE SOFTWARE.
28 --]]
30 local binder = {}
31 local B = nil
33 -- a string devised to not compile. should not make into code. never.
34 binder.ERRORSTRING = '<<>>'
35 binder.WRAPCALL = '__LuaWrapCall__'
36 binder.debug_type = function(el) return (type(el)=='table'and (el.tag .. ' ' .. el.attr.id) or el) end
38 function binder:init(filename)
39 --require 'lxp'
40 --require 'lxp.lom'
42 if not self.tree then
43 local xmlf = io.open(filename, 'r')
44 local xmls = xmlf:read('*a')
45 xmlf:close()
46 --self.tree = lxp.lom.parse(xmls)
47 xml.id = {}
48 self.tree = xml:collect(xmls)
49 end
51 self.ids = xml.id
52 self.type_names = {}
53 self.types_to_stack = {
54 ['char * *'] = function(i) return 'lqtL_pusharguments(L, ' .. tostring(i) .. ')' end,
55 ['const char * *'] = function(i) return 'lqtL_pusharguments(L, ' .. tostring(i) .. ')' end,
56 ['const char *'] = function(i) return 'lua_pushstring(L, ' .. tostring(i) .. ')' end,
57 ['short int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
58 ['unsigned short int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
59 ['short unsigned int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
60 ['int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
61 ['unsigned int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
62 ['long int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
63 ['unsigned long int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
64 ['long unsigned int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
65 ['long long int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
66 ['unsigned long long int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
67 ['float'] = function(i) return 'lua_pushnumber(L, ' .. tostring(i) .. ')' end,
68 ['double'] = function(i) return 'lua_pushnumber(L, ' .. tostring(i) .. ')' end,
69 ['bool'] = function(i) return 'lua_pushboolean(L, ' .. tostring(i) .. ')' end,
70 ['void *'] = function(i) return 'lua_pushlightuserdata(L, ' .. tostring(i) .. ')' end,
71 ['void * *'] = function(i) return 'lua_pushlightuserdata(L, ' .. tostring(i) .. ')' end,
73 self.types_from_stack = {
74 ['int&'] = function(i) return 'lqtL_tointref(L, ' .. tostring(i) .. ')' end,
75 ['char * *'] = function(i) return 'lqtL_toarguments(L, ' .. tostring(i) .. ')' end,
76 ['const char * *'] = function(i) return 'lqtL_toarguments(L, ' .. tostring(i) .. ')' end,
77 ['const char *'] = function(i) return 'lua_tostring(L, ' .. tostring(i) .. ')' end,
78 ['short int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
79 ['unsigned short int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
80 ['short unsigned int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
81 ['int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
82 ['unsigned int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
83 ['long int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
84 ['unsigned long int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
85 ['long unsigned int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
86 ['long long int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
87 ['unsigned long long int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
88 ['float'] = function(i) return 'lua_tonumber(L, ' .. tostring(i) .. ')' end,
89 ['double'] = function(i) return 'lua_tonumber(L, ' .. tostring(i) .. ')' end,
90 ['bool'] = function(i) return '(bool)lua_toboolean(L, ' .. tostring(i) .. ')' end,
91 ['void *'] = function(i) return 'lua_touserdata(L, ' .. tostring(i) .. ')' end,
92 ['void * *'] = function(i) return 'static_cast<void **>(lua_touserdata(L, ' .. tostring(i) .. '))' end,
94 self.types_test = {
95 ['char * *'] = function(i) return 'lqtL_testarguments(L, ' .. tostring(i) .. ')' end,
96 ['const char * *'] = function(i) return 'lqtL_testarguments(L, ' .. tostring(i) .. ')' end,
97 ['const char *'] = function(i) return '(lua_type(L, ' .. tostring(i) .. ')==LUA_TSTRING)' end,
98 ['short int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
99 ['unsigned short int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
100 ['short unsigned int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
101 ['int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
102 ['unsigned int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
103 ['long int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
104 ['unsigned long int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
105 ['long unsigned int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
106 ['long long int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
107 ['unsigned long long int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
108 ['float'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
109 ['double'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
110 ['bool'] = function(i) return 'lua_isboolean(L, ' .. tostring(i) .. ')' end,
111 ['void *'] = function(i) return 'lua_isuserdata(L, ' .. tostring(i) .. ')' end,
112 ['void * *'] = function(i) return 'lua_isuserdata(L, ' .. tostring(i) .. ')' end,
114 -- self.conditions = {}
116 return self.tree
119 function binder.wrapclass(n)
120 return 'LuaBinder< '..n..' >'
123 function binder.lua_proto(s)
124 return 'int '..s..' (lua_State *L)'
127 function binder.fake_pointer (id)
128 return { tag='PointerType', attr={ type=id } }
131 function binder:find(f, t)
132 t = t or self.tree
133 if type(t)~='table' then return nil end;
134 if f(t) then return t end
135 local ret = nil
136 for k,v in pairs(t) do
137 ret = ret or self:find(f, v)
138 if ret then break end
139 end;
140 return ret;
143 function binder.name_search (n)
144 return function (t)
145 return (type(t)=='table') and (type(t.attr)=='table') and (t.attr.name==n)
149 function binder.id_search (i)
150 return function (t)
151 return (type(t)=='table') and (type(t.attr)=='table') and (t.attr.id==i) -- or ((type(i)=='table') and i[t.attr.id])
155 function binder.tag_search (n)
156 return function (t)
157 return (type(t)=='table') and (t.tag==n) -- or ((type(i)==table) and i[t.attr.id])
161 function binder.pointer_search(id)
162 return function (t)
163 return (type(t)=='table') and (t.tag=='PointerType') and (type(t.attr)=='table') and (t.attr.type==id)
167 function binder:find_name (n)
168 if not self.names then self.names = {} end
169 if not self.names[n] then
170 self.names[n] = self:find(self.name_search(n))
172 return self.names[n]
175 function binder:find_id (n)
176 if not self.ids then self.ids = {} end
177 if not self.ids[n] then
178 self.ids[n] = self:find(self.id_search(n))
180 return self.ids[n]
183 function binder:find_pointer (n)
184 if not self.pointers then self.pointers = {} end
185 if not self.pointers[n] then
186 self.pointers[n] = self:find(self.pointer_search(n.attr.id))
188 return self.pointers[n]
191 function binder:context_name(el)
192 if type(el.attr)~='table' then return '' end
193 if type(el.attr.context)~='string' then return '' end
195 local context_el = self:find_id(el.attr.context)
197 if not context_el then return '' end
199 local context = (context_el.attr.name=='::') and '' or (context_el.attr.name..'::')
200 return context
203 function binder:type_name(el)
204 -- print('getting name of', el, el.tag)
206 self.type_names = self.type_names or {}
207 local t = self.type_names
209 if t[el] then return t[el] end
211 if el.tag == 'FundamentalType' then
212 t[el] = el.attr.name
213 elseif (el.tag == 'Class') or (el.tag == 'Struct') or (el.tag=='Union') then
214 t[el] = self:context_name(el) .. el.attr.name
215 elseif el.tag == 'Typedef' then
216 t[el] = self:type_name(self:find_id(el.attr.type))
217 elseif el.tag == 'PointerType' then
218 t[el] = self:type_name(self:find_id(el.attr.type)) .. ' *'
219 elseif el.tag == 'ReferenceType' then
220 t[el] = self:type_name(self:find_id(el.attr.type)) .. '&'
221 elseif el.tag == 'CvQualifiedType' then
222 t[el] = ( (el.attr.volatile=='1') and 'volatile ' or '' )
223 .. ( (el.attr.const=='1') and 'const ' or '' )
224 .. self:type_name(self:find_id(el.attr.type))
225 elseif el.tag == 'Enumeration' then
226 t[el] = self:context_name(el) .. el.attr.name
227 else
228 error('cannot determine type name: ' .. self.debug_type(el))
230 return t[el]
233 function binder.wrapcall(m, overload, n)
234 if m.tag=='Method' then
235 return binder.WRAPCALL..m.attr.name..(overload and '__OverloadedVersion'..tostring(n) or '')
236 elseif m.tag=='Constructor' then
237 return binder.WRAPCALL..m.attr.name..'__new'..(overload and '__OverloadedVersion'..tostring(n) or '')
238 elseif m.tag=='Destructor' then
239 -- cannot be overloaded, true?
240 return binder.WRAPCALL..m.attr.name..'__delete'..(overload and '__OverloadedVersion'..tostring(n) or '')
242 return false
245 function binder.arguments_of(f)
246 local ret = {}
247 for argi = 1, table.maxn(f) do
248 if (type(f[argi])=='table') and (f[argi].tag=='Argument') then
249 table.insert(ret, f[argi])
252 return ret
256 function binder:base_type(el)
257 local ret = self:find_id(el.attr.type)
258 while (ret.tag=='Typedef') or (ret.tag=='CvQualifiedType') do
259 ret = self:find_id(ret.attr.type)
261 return ret
264 function binder:type_from_stack(el)
265 local t = self.types_from_stack
266 if t[el] then return t[el] end
268 local name = self:type_name(el)
269 if t[name] then
270 t[el] = t[name]
271 return t[el]
274 if (el.tag=='Class') or (el.tag=='Struct') or (el.tag=='Union') then
275 t[el] = function(i) return '**static_cast<'..name..'**>(lqtL_checkudata(L, '..tostring(i)..', "' ..name.. '*"))' end
276 elseif (el.tag=='CvQualifiedType') then
277 t[el] = self:type_from_stack(self:find_id(el.attr.type))
278 elseif (el.tag=='ReferenceType') then
279 t[el] = self:type_from_stack(self:find_id(el.attr.type))
280 elseif (el.tag=='Typedef') then
281 t[el] = self:type_from_stack(self:find_id(el.attr.type))
282 elseif (el.tag=='Enumeration') then
283 t[el] = function (i) return 'static_cast<'..name..'>(lqtL_toenum(L, '..tostring(i)..', "'..name..'"))' end
284 elseif (el.tag=='PointerType') then
285 local b = self:base_type(el)
286 local base_t = self:type_from_stack(b)
287 t[el] = (type(base_t)=='function') and function (i)
288 local base = base_t(i)
289 local c = string.sub(base, 1, 1)
290 if (c=='*') then
291 return string.sub(base, 2)
292 else
293 return 'static_cast<'..name..'>(lua_touserdata(L, '..tostring(i)..'))'
295 end or function (i) return '0' end
296 elseif (el.tag=='FunctionType') then -- FIXME
299 if t[el]==nil then
300 error('cannot deternime how to retrieve type: '.. ((type(el)=='table') and (el.tag..' '..el.attr.id) or el))
302 return t[el]
306 function binder:type_to_stack(el)
307 local t = self.types_to_stack
309 if t[el] then return t[el] end
311 local name = self:type_name(el)
312 -- print (el.tag, '|'..name..'|', rawget(t,el) or '<>')
314 if t[name] then
315 t[el] = t[name]
316 return t[el]
319 if (el.tag=='Class') or (el.tag=='Struct') or (el.tag=='Union') then
320 -- FIXME: force deep copy if possible
321 t[el] = function(i) return 'lqtL_passudata(L, new '..name..'('..tostring(i)..'), "'..name..'*")' end
322 elseif (el.tag=='CvQualifiedType') then -- FIXED? FIXME: this is just a mess
323 local base_t = self:base_type(el)
324 local non_cv = self:type_to_stack(base_t)
325 --if (base_t.tag=='Class') or (base_t.tag=='Struct') or (base_t.tag=='Union') then else end
326 t[el] = non_cv
327 elseif (el.tag=='ReferenceType') then
328 local base_t = self:base_type(el)
329 if (base_t.tag=='Class') or (base_t.tag=='Struct') or (base_t.tag=='Union') then
330 t[el] = function(i) return 'lqtL_pushudata(L, &('..tostring(i)..'), "'..self:type_name(base_t)..'*")' end
331 else
332 t[el] = self:type_to_stack(self:find_id(el.attr.type))
334 elseif (el.tag=='Typedef') then
335 t[el] = self:type_to_stack(self:find_id(el.attr.type))
336 elseif (el.tag=='Enumeration') then
337 t[el] = function (i) return 'lqtL_pushenum(L, '..tostring(i)..', "'..name..'")' end
338 elseif (el.tag=='PointerType') then
339 local base_t = self:base_type(el)
340 t[el] = function(i) return 'lqtL_pushudata(L, '..tostring(i)..', "'..self:type_name(base_t)..'*")' end
343 -- print (el.tag, el, rawget(t,el) or '<>')
344 if t[el]==nil then
345 error('cannot deternime how to push on stack type: '.. self.debug_type(el))
347 return t[el]
352 function binder:type_test(el)
353 local t = self.types_test
355 if t[el] then return t[el] end
357 local name = self:type_name(el)
359 if t[name] then
360 t[el] = t[name]
361 return t[el]
364 if (el.tag=='Class') or (el.tag=='Struct') or (el.tag=='Union') then
365 t[el] = function(i) return 'lqtL_testudata(L, ' .. tostring(i) .. ', "' .. name .. '*")' end
366 elseif (el.tag=='CvQualifiedType') then
367 t[el] = self:type_test(self:find_id(el.attr.type))
368 elseif (el.tag=='ReferenceType') then
369 t[el] = self:type_test(self:find_id(el.attr.type))
370 elseif (el.tag=='Typedef') then
371 t[el] = self:type_test(self:find_id(el.attr.type))
372 elseif (el.tag=='Enumeration') then
373 t[el] = function (i) return 'lqtL_isenum(L, '..tostring(i)..', "'..name..'")' end
374 elseif (el.tag=='PointerType') then
375 t[el] = self:type_test(self:find_id(el.attr.type)) or function() return '(true)' end
376 elseif (el.tag=='FunctionType') then -- FIXME
379 -- print (el.tag, el, rawget(t,el) or '<>')
380 if t[el]==nil then
381 error('cannot deternime how to test type: '.. self.debug_type(el))
383 return t[el]
387 function binder:function_body(f)
388 if f.attr.pure_virtual=='1' then error'cannot call pure vitual functions' end
389 -- FIXME could be more precise... problem is copy constructor of QObject if private
390 if f.tag=='Constructor' and f.attr.artificial=='1' then
391 error'refuse to bind implicitly defined constructors'
394 local body = '{\n'
395 local has_this = 0
396 --local base_class = nil
397 local args = self.arguments_of(f)
398 local funcname = self:context_name(f) .. f.attr.name
399 local ret_type = nil
400 local pointer_to_class = self.fake_pointer(f.attr.context)
402 --if f.attr.context then base_class = self:find_id(f.attr.context) end
403 --if base_class and ((base_class.tag=='Class') or (base_class.tag=='Struct')) then
404 --pointer_base = self:find(self.pointer_search(f.attr.context))
405 --end
407 -- NEEDS THIS POINTER?
408 if ( (f.tag=='Method') and (f.attr.static~='1') ) or (f.tag == 'Destructor') then
409 local pointer_base = pointer_to_class
410 body = body .. ' ' .. self:type_name(pointer_base) .. '& __lua__obj = '
411 .. self:type_from_stack(pointer_base)(1) .. ';\n';
412 ---[==[
413 body = body .. [[
414 if (__lua__obj==0) {
415 lua_pushstring(L, "trying to reference deleted pointer");
416 lua_error(L);
417 return 0;
420 --]==]
421 has_this = 1
424 -- GETTING ARGUMENTS
425 for argi = 1, table.maxn(args) do
426 local arg = args[argi]
427 local argname = 'arg' .. tostring(argi)
429 local argt = self:find_id(arg.attr.type)
430 local argtype = self:type_name(argt)
431 local def = arg.attr.default
433 if def and string.match(string.sub(def, 1, 1), '[%l%u]') then
434 def = self:context_name(argt)..def
435 elseif def then
436 def = 'static_cast< ' .. argtype .. ' >(' .. def .. ')'
439 --print ('getting arg type', argtype, arg.attr.type)
441 body = body .. ' ' .. argtype .. ' ' .. argname .. ' = '
442 .. (def and (self:type_test(argt)(argi+has_this) .. '?') or '')
443 .. self:type_from_stack(argt)(argi+has_this)
444 body = body .. (def and (':' .. tostring(def)) or '') .. ';\n' -- '// default = '..tostring(def)..'\n'
446 body = body .. ' '
448 if f.tag=='Constructor' then
449 --[[
450 local my_class = self:find_id(f.attr.context)
451 if my_class.attr.abstract='1' then error'cannot construct abstract class' end
452 --]]
453 ret_type = pointer_to_class
454 funcname = 'new ' .. self.wrapclass(f.attr.name)
456 -- ret_type = self:find_id(f.attr.context) -- wrong?
457 -- body = body .. self:type_name(ret_type) .. ' * ret = new '
458 -- print (self:type_name(ret_type))
459 elseif f.tag=='Destructor' then
460 -- TREATED AS SPECIAL CASE
461 body = body .. 'delete __lua__obj;\n'
462 body = body .. ' __lua__obj = 0;\n';
463 body = body .. ' return 0;\n}\n'
464 return body
465 else
466 ret_type = self:find_id(f.attr.returns)
469 -- GET RETURN TYPE
470 if ret_type.attr.name=='void' then
471 ret_type = nil
472 else
473 body = body .. self:type_name(ret_type) .. ' ret = '
476 -- CALL FUNCTION
477 if has_this==1 then
478 body = body .. '__lua__obj->' .. funcname .. '('
479 else
480 body = body .. funcname .. '('
483 -- IF OVERRIDING CONSTRUCTOR ADD STATE POINTER
484 if f.tag=='Constructor' then
485 body = body .. 'L' .. ((table.maxn(args) > 0) and ', ' or '')
488 -- ADD ARGS TO FUNCTION CALL
489 if table.maxn(args) > 0 then body = body .. 'arg1' end
490 for argi = 2, table.maxn(args) do
491 body = body .. ', arg' .. tostring(argi)
494 body = body .. ');\n'
496 -- HANDLE RETURN VALUE
497 if f.tag=='Constructor' then
498 body = body .. ' lqtL_passudata(L, ret, "'..f.attr.name..'*");\n'
499 body = body .. ' return 1;\n}\n'
500 elseif ret_type then
501 -- print('pushing', binder:type_name(ret_type))
502 local ret_to_stack = self:type_to_stack(ret_type)'ret'
503 body = body .. ' ' .. ret_to_stack .. ';\n'
504 body = body .. ' return 1;\n}\n'
505 else
506 body = body .. ' return 0;\n}\n'
509 return body
512 function binder:function_test(p, score)
513 local ret = ''
514 local isstatic = 0
516 ret = ret .. ' ' .. score .. ' = 0;\n'
518 if p.attr.static~='1' and p.tag=='Method' then
519 ret = ret .. ' ' .. score .. ' += ' .. self:type_test( self.fake_pointer(p.attr.context) )(1)
520 .. '?premium:-premium*premium;\n'
521 isstatic = 1
524 local args = self.arguments_of(p)
526 for argi = 1, table.maxn(args) do
527 local arg = args[argi]
528 --print ( 'ARGUMENT TEST', argi)
529 local argname = 'arg' .. tostring(argi)
530 if (type(arg)=='table') and (arg.tag=='Argument') then
531 ret = ret .. ' if (' .. self:type_test( self:find_id(arg.attr.type) )(argi+isstatic) .. ') {\n'
532 ret = ret .. ' ' .. score .. ' += premium;\n'
533 ret = ret .. ' } else if (' .. tostring(arg.attr.default and true or false) .. ') {\n'
534 ret = ret .. ' ' .. score .. ' += premium-1; // '..tostring(arg, arg.attr.default)..';\n'
535 ret = ret .. ' } else {\n'
536 ret = ret .. ' ' .. score .. ' -= premium*premium;\n'
537 ret = ret .. ' }\n'
539 -- ret = ret .. ' ' .. score .. ' += ' .. type_on_stack_test( find_id(arg.attr.type) , argi+isstatic )
540 -- .. '?' .. tostring(premium) .. ':-' .. tostring(premium) .. '*' .. tostring(premium) .. ';\n'
544 return ret
547 function binder:get_members (c)
548 if not self.members then self.members = {} end
549 if not self.members[c] then
550 local ret = { functions={}, enumerations={}, classes={}, methods={}, constructors={}, virtuals={} }
551 for s in string.gmatch(c.attr.members, '(_%d+) ') do
552 local m = self:find_id(s)
553 local n = m.attr.name
554 print("member of", c.attr.name , "found:", s, "name:", n)
556 local filtered, motive = false, ''
557 if self.filter then
558 filtered, motive = self.filter(m)
561 if filtered then
562 print('Filtered member: '..n..' for '..(motive or 'no apparent reason.'))
563 elseif m.tag=='Enumeration' then
564 table.insert(ret.enumerations, m)
565 elseif m.tag=='Function' then
566 ret.functions[n] = ret.functions[n] or {}
567 table.insert(ret.functions[n], m)
568 elseif m.tag=='Method' and (m.attr.access=='public') then
569 ret.methods[n] = ret.methods[n] or {}
570 table.insert(ret.methods[n], m)
571 elseif m.tag=='Constructor' and (m.attr.access=='public') then
572 table.insert(ret.constructors, m)
573 elseif m.tag=='Destructor' then
574 ret.destructor = m
575 elseif m.tag=='Class' or m.tag=='Struct' then
576 table.insert(ret.classes, m)
579 if (m.attr.virtual=='1') and (m.tag~='Constructor') and (m.tag~='Destructor') and not filtered then
580 table.insert(ret.virtuals, m)
582 --[[
583 local n = n..' < < of type > > '.. m.tag ..' < < with access > > ' .. m.attr.access
584 ret.cache[n] = ret.cache[n] or {}
585 table.insert(ret.cache[n], m)
588 self.members[c] = ret
590 return self.members[c]
593 function binder:code_function (f)
594 local body, test = {}, {}
596 for i, m in ipairs(f) do
597 local fname = self.wrapcall(m, overloaded, j)
599 if not fname then error'this shout *NOT* happen!' end
600 local st, err
602 st, err = pcall(self.function_body, self, m)
603 if st then
604 body[i] = err
605 else
606 print(err)
607 body[i] = nil
610 st, err = pcall(self.function_test, self, m, 'score['..i..']')
611 if st then
612 test[i] = err
613 else
614 print(err)
615 test[i] = nil
618 --body[i] = self:function_body(m)
619 --test[i] = self:function_test(m, 'score['..i..']')
622 return body, test
625 function binder:begin_dispatch(n, m)
626 return self.lua_proto(n) .. ' {\n int score[' .. (m+1)
627 ..'];\n const int premium = 11+lua_gettop(L);\n'
630 function binder:choose_dispatch(m)
631 return [[
632 int best = 1;
633 for (int i=1;i<=]]..m..[[;i++) {
634 if (score[best] < score[i]) { best = i; }
636 switch (best) {
640 function binder:solve_overload (f, n, c)
641 local proto, def = '', ''
642 local body, test = self:code_function(f)
644 local number = 0
645 for i = 1,table.maxn(f) do if (type(body[i])=='string') and (type(test[i])=='string') then number = number + 1 end end
647 if number>1 then
648 local fulltest = self:begin_dispatch(c..n, table.maxn(f))
650 for i = 1,table.maxn(f) do
651 local fullname = n..'__OverloadedVersion__'..i
652 if (type(body[i])=='string') and (type(test[i])=='string') then
653 proto = proto .. ' static '..self.lua_proto(fullname)..';\n'
654 def = def .. self.lua_proto(c..fullname)..' '..body[i]
655 fulltest = fulltest .. test[i]
659 fulltest = fulltest .. self:choose_dispatch(table.maxn(f))
661 for i = 1,table.maxn(f) do
662 if (type(body[i])=='string') and (type(test[i])=='string') then
663 local fullname = n..'__OverloadedVersion__'..i
664 fulltest = fulltest .. ' case ' .. i .. ': return ' .. fullname ..'(L); break;\n'
668 -- TODO: move to a function?
669 -- TODO: trigger an error
670 fulltest = fulltest .. [[
672 lua_pushstring(L, "no overload of function ]].. n ..[[ matching arguments");
673 lua_error(L);
674 return 0;
678 proto = proto .. ' static '..self.lua_proto(n)..';\n'
679 def = def .. fulltest
680 elseif number==1 then
681 proto, def = nil, nil
682 for i, v in ipairs(body) do
683 proto = ' static '..self.lua_proto(n)..';\n'
684 def = self.lua_proto(c..n)..' '..v
686 else
687 proto, def = nil, nil
690 return proto, def
693 function binder:enum_push_body(id, c)
694 local enum = (type(id)=='string') and self:find_id(id) or id
695 local e_static = (self:find_id(enum.attr.context).tag == 'Class') and 'static ' or ''
696 local e_context = self:context_name(enum)
697 local e_name = 'lqt_pushenum_' .. enum.attr.name
698 local e_proto, e_def = '', ''
700 e_proto = e_proto .. ' ' .. e_static .. self.lua_proto(e_name) .. ';\n'
701 e_def = e_def .. self.lua_proto(c .. e_name) .. ' '
702 e_def = e_def .. '{\n'
703 e_def = e_def .. ' int enum_table = 0;\n'
704 e_def = e_def .. ' lua_getfield(L, LUA_REGISTRYINDEX, LQT_ENUMS);\n'
705 e_def = e_def .. ' if (!lua_istable(L, -1)) {\n'
706 e_def = e_def .. ' lua_pop(L, 1);\n'
707 e_def = e_def .. ' lua_newtable(L);\n'
708 e_def = e_def .. ' lua_pushvalue(L, -1);\n'
709 e_def = e_def .. ' lua_setfield(L, LUA_REGISTRYINDEX, LQT_ENUMS);\n'
710 e_def = e_def .. ' }\n'
712 e_def = e_def .. ' lua_newtable(L);\n'
713 e_def = e_def .. ' enum_table = lua_gettop(L);\n'
714 for i, e in ipairs(enum) do
715 if (type(e)=='table') and (e.tag=='EnumValue') then
716 e_def = e_def .. ' lua_pushstring(L, "' .. e.attr.name .. '");\n'
717 e_def = e_def .. ' lua_rawseti(L, enum_table, ' .. e.attr.init .. ');\n'
718 e_def = e_def .. ' lua_pushinteger(L, ' .. e.attr.init .. ');\n'
719 e_def = e_def .. ' lua_setfield(L, enum_table, "' .. e.attr.name .. '");\n'
722 e_def = e_def .. ' lua_pushvalue(L, -1);\n'
723 e_def = e_def .. ' lua_setfield(L, -3, "' .. e_context .. enum.attr.name .. '");\n'
724 e_def = e_def .. ' lua_remove(L, -2);\n'
725 e_def = e_def .. ' return 1;\n'
726 e_def = e_def .. '}\n'
727 --print (e_def)
728 return e_proto, e_def, e_name
731 function binder:mangled (f)
732 local args = self:arguments_of(f)
733 local k = f.attr.name..'('
734 for i = 1, table.maxn(args) do
735 k = k..', '..self:type_name(args.attr.type)
737 k = k..')'
738 return k
741 function binder:get_virtuals (c)
742 local c_v = self:get_members(c).virtuals
743 local mang_virtuals = {}
745 for n, f in pairs(c_v) do
746 if f.attr.virtual=='1' then
747 local k = self:mangled(f)
748 mang_virtuals[k] = mang_virtuals[k] or f
753 for s in string.gmatch(c.attr.bases or '', '(_%d+) ') do
754 local my_base = self:find_id(s)
755 local my_virtual = self:get_virtuals(my_base)
756 for k, f in pairs(my_virtual) do
757 mang_virtuals[k] = mang_virtuals[k] or f
761 return mang_virtuals
764 function binder:proto_preamble (n, ...)
765 -- FIXME: this is only Qt (the inclusion by name of class)
766 -- FIXED?
767 i = i or n
768 local ret = [[
769 #include "lqt_common.hpp"
771 for n = 1,select('#', ...) do
772 local i = select(n, ...)
773 ret = ret .. '#include <'..i..'>\n'
776 -- FIXME handle namespaces
777 ret = ret .. [[
779 template <> class ]] .. self.wrapclass(n) .. [[ : public ]] .. n .. [[ {
780 private:
781 lua_State *L;
782 public:
784 return ret
787 function binder:proto_ending (n)
788 return [[
794 function binder:copy_constructor(c)
795 if c.tag=='Constructor' and c.attr.artificial=='1' then
796 return ''
798 local constr = ' '
799 local args = self.arguments_of(c)
800 constr = constr .. self.wrapclass(c.attr.name) .. ' (lua_State *l'
801 for argi = 1, table.maxn(args) do
802 local argt = self:find_id(args[argi].attr.type)
803 local argtype = self:type_name(argt)
804 constr = constr .. ', ' .. argtype .. ' arg'..tostring(argi)
806 constr = constr .. '):'..c.attr.name..'('
807 for argi = 1, table.maxn(args) do
808 constr = constr .. ((argi>1) and ', ' or '') .. 'arg'..tostring(argi)
810 constr = constr .. '), L(l) {}\n'
811 return constr, nil
814 function binder.meta_constr_proto (n) return 'extern "C" int luaopen_'..n..' (lua_State *L);\n' end
815 function binder.meta_constr_preamble (n)
816 return [[
817 int luaopen_]]..n..[[ (lua_State *L) {
818 if (luaL_newmetatable(L, "]]..n..[[*")) {
821 function binder.meta_constr_method (n, c)
822 c = c or ''
823 return ' lua_pushcfunction(L, '..c..n..');\n lua_setfield(L, -2, "'..n..'");\n'
825 function binder.meta_constr_ending (n)
826 return [[
827 lua_pushcfunction(L, lqtL_newindex);
828 lua_setfield(L, -2, "__newindex");
829 lua_pushcfunction(L, lqtL_index);
830 lua_setfield(L, -2, "__index");
831 lua_pushcfunction(L, lqtL_gc);
832 lua_setfield(L, -2, "__gc");
833 lua_pushstring(L, "]]..n..[[");
834 lua_setfield(L, -2, "__qtype");
835 lua_setglobal(L, "]]..n..[[");
836 } else {
837 lua_pop(L, 1);
839 return 0;
844 function binder:virtual_overload (f, c, id)
845 --if f.attr.access~='public' then error'only public virtual function are exported' end
846 if f.attr.access=='private' then error'private virtual function are not exported' end
848 c = c or ''
849 local args = self.arguments_of(f)
850 local ret_t = f.attr.returns and self:find_id(f.attr.returns)
851 local ret_n = ret_t and self:type_name(ret_t) or 'void'
852 local fh, fb = ' ', ''
853 fh = fh .. ret_n .. ' ' .. f.attr.name .. ' ('
854 fb = fb .. ret_n .. ' ' .. c .. f.attr.name .. ' ('
856 -- GETTING ARGUMENTS
857 for argi = 1, table.maxn(args) do
858 local arg = args[argi]
859 local argname = 'arg' .. tostring(argi)
861 local argt = self:find_id(arg.attr.type)
862 local argtype = self:type_name(argt)
863 local def = arg.attr.default or nil
865 def = def and (self:context_name(argt)..def)
867 --print ('signing arg type', argtype)
869 if argi>1 then fh = fh .. ', ' fb = fb .. ', ' end
870 fh = fh .. argtype .. ' ' .. argname .. (def and (' = '..def) or '')
871 fb = fb .. argtype .. ' ' .. argname
874 fh = fh .. ')' .. (f.attr.const and ' const' or '') .. ';\n'
876 if f.attr.access~='public' then
877 fh = f.attr.access .. ':\n' .. fh .. 'public:\n'
880 fb = fb .. ')' .. (f.attr.const and ' const' or '') .. ' {\n'
881 fb = fb .. ' bool absorbed = false;\n int oldtop = lua_gettop(L);\n'
883 local context = self:context_name(f)
884 local pointer_to_class = self.fake_pointer ( id or f.attr.context )
885 local push_this = self:type_to_stack(pointer_to_class)'this'
886 --fb = fb .. ' ' .. push_this .. ';\n'
887 --fb = fb .. ' lua_getfield(L, -1, "'..(f.attr.name)..'");\n lua_insert(L, -2);\n'
888 ---[=[
889 fb = fb .. ' ' .. push_this .. [[;
890 if (lua_getmetatable(L, -1)) {
891 lua_getfield(L, -1, "]]..(f.attr.name)..[[");
892 lua_remove(L, -2);
893 } else {
894 lua_pushnil(L);
896 lua_insert(L, -2);
898 --]=]
901 for argi = 1, table.maxn(args) do
902 local arg = args[argi]
903 local argname = 'arg' .. tostring(argi)
905 local argt = self:find_id(arg.attr.type)
906 local argtype = self:type_name(argt)
907 local def = arg.attr.default
909 def = def and (self:context_name(argt)..def)
911 local to_stack = self:type_to_stack(argt)(argname)
912 --to_stack = (type(to_stack)=='string') and to_stack or table.concat(to_stack, '\n ')
913 fb = fb .. ' ' .. to_stack .. ';\n'
916 local sig = '(' .. (args[1] and 'arg1' or '')
917 for argi = 2, table.maxn(args) do
918 sig = sig .. ', arg' .. argi
920 sig = sig .. ')'
922 fb = fb .. [[
923 if (lua_isfunction(L, -]]..table.maxn(args)..[[-2)) {
924 lua_pcall(L, ]] .. table.maxn(args) .. [[+1, 2, 0);
925 absorbed = (bool)lua_toboolean(L, -1) || (bool)lua_toboolean(L, -2);
926 lua_pop(L, 1);
928 if (!absorbed) {
929 lua_settop(L, oldtop);
930 ]] .. (f.attr.pure_virtual~='1' and (((ret_n~='void') and 'return ' or '')..'this->'..context..f.attr.name..sig..';\n') or '') .. [[
933 -- fb = fb .. ' if (!lua_isnil)' -- TODO: check?
934 if ret_n~='void' then
935 fb = fb .. ' ' .. ret_n .. ' ret = ' .. self:type_from_stack(ret_t)(-1) .. ';\n'
936 fb = fb .. ' lua_settop(L, oldtop);\n'
937 fb = fb .. ' return ret;\n'
938 else
939 fb = fb .. ' lua_settop(L, oldtop);\n'
941 fb = fb .. '}\n'
943 return fh, fb
946 function binder:virtual_destructor (f, c)
947 c = c or ''
948 local lname = self.wrapclass(f.attr.name)
949 local pclass = self.fake_pointer(f.attr.context)
950 local push_this = self:type_to_stack(pclass)'this'
951 return [[
952 ~]]..lname..[[ ();
953 ]],
954 c .. [[
955 ~]]..lname..[[ () {
956 int oldtop = lua_gettop(L);
957 ]] .. push_this .. [[;
958 lua_getfield(L, -1, "~]]..f.attr.name..[[");
960 if (lua_isfunction(L, -1)) {
961 lua_insert(L, -2);
962 lua_pcall(L, 1, 1, 0);
963 } else {
965 lua_settop(L, oldtop);
971 function binder:make_namespace(tname, include_file, ...)
972 local bind_file = 'lqt_bind_'..include_file..'.hpp'
973 if string.match(include_file, '(%.[hH]([pP]?)%2)$') then
974 bind_file = 'lqt_bind_'..include_file
977 local my_class = self:find_id(tname) or self:find_name(tname)
978 ---- FIXME handle namespaces
979 local my_context = self.wrapclass(tname)..'::'
981 local my = self:get_members(my_class)
983 local my_enums = nil
984 my.virtuals = self:get_virtuals(my_class)
986 print 'writing preambles'
988 local fullproto = self:proto_preamble(tname, include_file, ...)
989 local fulldef = '#include "'..bind_file..'"\n\n'
990 local metatable_constructor = self.meta_constr_preamble(tname)
992 print 'binding each member'
994 local my_members = {}
995 table.foreach(my.methods, function(k, v) my_members[k] = v end)
996 my_members.new = my.constructors
997 my_members.delete = { my.destructor }
998 for n, l in pairs(my_members) do
999 local fname = self.WRAPCALL..n
1000 local proto, def = self:solve_overload(l, fname, my_context)
1001 if (proto and def) then
1002 fullproto = fullproto .. proto
1003 fulldef = fulldef .. def
1004 metatable_constructor = metatable_constructor .. self.meta_constr_method (n, my_context..self.WRAPCALL)
1008 print'binding virtual methods'
1010 for s, f in pairs(my.virtuals) do
1011 print ('virtual', s)
1012 local ret, h, c = pcall(self.virtual_overload, self, f, my_context, my_class.attr.id)
1013 if ret then
1014 fullproto, fulldef = fullproto..h, fulldef..c
1015 else
1016 print(h)
1020 print'overriding virtual destructor'
1021 if my.destructor and my.destructor.attr.virtual == '1' then
1022 local h, c = self:virtual_destructor(my.destructor, my_context)
1023 fullproto, fulldef = fullproto..h, fulldef..c
1026 print'creating enum translation tables'
1027 for k, e in pairs(my.enumerations) do
1028 local e_p, e_d, e_n = self:enum_push_body(e, my_context)
1029 fulldef = fulldef .. e_d
1030 fullproto = fullproto .. e_p
1031 metatable_constructor = metatable_constructor .. ' ' .. my_context .. e_n .. '(L);\n lua_setfield(L, -2, "'..e.attr.name..'");\n'
1034 print'copying constructors'
1035 for i, v in ipairs(my.constructors) do
1036 fullproto = fullproto..self:copy_constructor(v)
1038 fullproto = fullproto .. self:proto_ending(tname) .. self.meta_constr_proto (tname)
1040 print'specifying bases'
1041 metatable_constructor = metatable_constructor .. ' lua_newtable(L);\n'
1042 local deep_bases = {}
1043 for s in string.gmatch(my_class.attr.bases or '', '(_%d+) ') do
1044 local base = self:find_id(s)
1045 local bname = self:type_name(base)
1046 metatable_constructor = metatable_constructor .. [[
1047 lua_pushboolean(L, 1);
1048 lua_setfield(L, -2, "]]..bname..[[*");
1050 deep_bases = self.set_union(deep_bases, self:tree_of_bases(base))
1052 for n in pairs(deep_bases) do
1053 metatable_constructor = metatable_constructor .. [[
1054 lua_pushboolean(L, 0);
1055 lua_setfield(L, -2, "]]..n..[[*");
1058 metatable_constructor = metatable_constructor .. ' lua_setfield(L, -2, "__base");\n'
1061 print'finalizing code'
1062 metatable_constructor = metatable_constructor .. self.meta_constr_ending (tname)
1063 fulldef = fulldef .. metatable_constructor
1065 return fullproto, fulldef
1068 function binder.set_union(...)
1069 local ret = {}
1070 for _, s in ipairs{...} do
1071 for v, t in pairs(s) do
1072 if t==true then ret[v] = true end
1075 return ret
1078 function binder:tree_of_bases(c)
1079 local ret = {}
1080 for s in string.gmatch(c.attr.bases or '', '(_%d+) ') do
1081 local b = self:find_id(s)
1082 ret[b.attr.name] = true
1083 local bb = self:tree_of_bases(b)
1084 ret = self.set_union(ret, bb)
1086 return ret
1090 return binder