Added Qt specific includes to make more bindings compile cleanly from the start
[lqt.git] / binder.lua
blobc1e77937f8fbbe6b9ba05255b1a1a98952ce8dd2
1 #!/usr/bin/lua
3 local binder = {}
4 local B = nil
6 -- a string devised to not compile. should not make into code. never.
7 binder.ERRORSTRING = '<<>>'
8 binder.WRAPCALL = '__LuaWrapCall__'
9 binder.debug_type = function(el) return (type(el)=='table'and (el.tag .. ' ' .. el.attr.id) or el) end
11 function binder:init(filename)
12 --require 'lxp'
13 --require 'lxp.lom'
15 if not self.tree then
16 local xmlf = io.open(filename, 'r')
17 local xmls = xmlf:read('*a')
18 xmlf:close()
19 --self.tree = lxp.lom.parse(xmls)
20 xml.id = {}
21 self.tree = xml:collect(xmls)
22 end
24 self.ids = xml.id
25 self.type_names = {}
26 self.types_to_stack = {
27 ['char * *'] = function(i) return 'lqtL_pusharguments(L, ' .. tostring(i) .. ')' end,
28 ['const char * *'] = function(i) return 'lqtL_pusharguments(L, ' .. tostring(i) .. ')' end,
29 ['const char *'] = function(i) return 'lua_pushstring(L, ' .. tostring(i) .. ')' end,
30 ['short int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
31 ['unsigned short int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
32 ['short unsigned int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
33 ['int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
34 ['unsigned int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
35 ['long int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
36 ['unsigned long int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
37 ['long unsigned int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
38 ['long long int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
39 ['unsigned long long int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
40 ['float'] = function(i) return 'lua_pushnumber(L, ' .. tostring(i) .. ')' end,
41 ['double'] = function(i) return 'lua_pushnumber(L, ' .. tostring(i) .. ')' end,
42 ['bool'] = function(i) return 'lua_pushboolean(L, ' .. tostring(i) .. ')' end,
43 ['void *'] = function(i) return 'lua_pushlightuserdata(L, ' .. tostring(i) .. ')' end,
44 ['void * *'] = function(i) return 'lua_pushlightuserdata(L, ' .. tostring(i) .. ')' end,
46 self.types_from_stack = {
47 ['int&'] = function(i) return 'lqtL_tointref(L, ' .. tostring(i) .. ')' end,
48 ['char * *'] = function(i) return 'lqtL_toarguments(L, ' .. tostring(i) .. ')' end,
49 ['const char * *'] = function(i) return 'lqtL_toarguments(L, ' .. tostring(i) .. ')' end,
50 ['const char *'] = function(i) return 'lua_tostring(L, ' .. tostring(i) .. ')' end,
51 ['short int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
52 ['unsigned short int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
53 ['short unsigned int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
54 ['int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
55 ['unsigned int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
56 ['long int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
57 ['unsigned long int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
58 ['long unsigned int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
59 ['long long int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
60 ['unsigned long long int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
61 ['float'] = function(i) return 'lua_tonumber(L, ' .. tostring(i) .. ')' end,
62 ['double'] = function(i) return 'lua_tonumber(L, ' .. tostring(i) .. ')' end,
63 ['bool'] = function(i) return '(bool)lua_toboolean(L, ' .. tostring(i) .. ')' end,
64 ['void *'] = function(i) return 'lua_touserdata(L, ' .. tostring(i) .. ')' end,
65 ['void * *'] = function(i) return 'static_cast<void **>(lua_touserdata(L, ' .. tostring(i) .. '))' end,
67 self.types_test = {
68 ['char * *'] = function(i) return 'lqtL_testarguments(L, ' .. tostring(i) .. ')' end,
69 ['const char * *'] = function(i) return 'lqtL_testarguments(L, ' .. tostring(i) .. ')' end,
70 ['const char *'] = function(i) return '(lua_type(L, ' .. tostring(i) .. ')==LUA_TSTRING)' end,
71 ['short int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
72 ['unsigned short int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
73 ['short unsigned int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
74 ['int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
75 ['unsigned int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
76 ['long int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
77 ['unsigned long int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
78 ['long unsigned int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
79 ['long long int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
80 ['unsigned long long int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
81 ['float'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
82 ['double'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
83 ['bool'] = function(i) return 'lua_isboolean(L, ' .. tostring(i) .. ')' end,
84 ['void *'] = function(i) return 'lua_isuserdata(L, ' .. tostring(i) .. ')' end,
85 ['void * *'] = function(i) return 'lua_isuserdata(L, ' .. tostring(i) .. ')' end,
87 -- self.conditions = {}
89 return self.tree
90 end
92 function binder.wrapclass(n)
93 return 'LuaBinder< '..n..' >'
94 end
96 function binder.lua_proto(s)
97 return 'int '..s..' (lua_State *L)'
98 end
100 function binder.fake_pointer (id)
101 return { tag='PointerType', attr={ type=id } }
104 function binder:find(f, t)
105 t = t or self.tree
106 if type(t)~='table' then return nil end;
107 if f(t) then return t end
108 local ret = nil
109 for k,v in pairs(t) do
110 ret = ret or self:find(f, v)
111 if ret then break end
112 end;
113 return ret;
116 function binder.name_search (n)
117 return function (t)
118 return (type(t)=='table') and (type(t.attr)=='table') and (t.attr.name==n)
122 function binder.id_search (i)
123 return function (t)
124 return (type(t)=='table') and (type(t.attr)=='table') and (t.attr.id==i) -- or ((type(i)=='table') and i[t.attr.id])
128 function binder.tag_search (n)
129 return function (t)
130 return (type(t)=='table') and (t.tag==n) -- or ((type(i)==table) and i[t.attr.id])
134 function binder.pointer_search(id)
135 return function (t)
136 return (type(t)=='table') and (t.tag=='PointerType') and (type(t.attr)=='table') and (t.attr.type==id)
140 function binder:find_name (n)
141 if not self.names then self.names = {} end
142 if not self.names[n] then
143 self.names[n] = self:find(self.name_search(n))
145 return self.names[n]
148 function binder:find_id (n)
149 if not self.ids then self.ids = {} end
150 if not self.ids[n] then
151 self.ids[n] = self:find(self.id_search(n))
153 return self.ids[n]
156 function binder:find_pointer (n)
157 if not self.pointers then self.pointers = {} end
158 if not self.pointers[n] then
159 self.pointers[n] = self:find(self.pointer_search(n.attr.id))
161 return self.pointers[n]
164 function binder:context_name(el)
165 if type(el.attr)~='table' then return '' end
166 if type(el.attr.context)~='string' then return '' end
168 local context_el = self:find_id(el.attr.context)
170 if not context_el then return '' end
172 local context = (context_el.attr.name=='::') and '' or (context_el.attr.name..'::')
173 return context
176 function binder:type_name(el)
177 -- print('getting name of', el, el.tag)
179 self.type_names = self.type_names or {}
180 local t = self.type_names
182 if t[el] then return t[el] end
184 if el.tag == 'FundamentalType' then
185 t[el] = el.attr.name
186 elseif (el.tag == 'Class') or (el.tag == 'Struct') or (el.tag=='Union') then
187 t[el] = self:context_name(el) .. el.attr.name
188 elseif el.tag == 'Typedef' then
189 t[el] = self:type_name(self:find_id(el.attr.type))
190 elseif el.tag == 'PointerType' then
191 t[el] = self:type_name(self:find_id(el.attr.type)) .. ' *'
192 elseif el.tag == 'ReferenceType' then
193 t[el] = self:type_name(self:find_id(el.attr.type)) .. '&'
194 elseif el.tag == 'CvQualifiedType' then
195 t[el] = ( (el.attr.volatile=='1') and 'volatile ' or '' )
196 .. ( (el.attr.const=='1') and 'const ' or '' )
197 .. self:type_name(self:find_id(el.attr.type))
198 elseif el.tag == 'Enumeration' then
199 t[el] = self:context_name(el) .. el.attr.name
200 else
201 error('cannot determine type name: ' .. self.debug_type(el))
203 return t[el]
206 function binder.wrapcall(m, overload, n)
207 if m.tag=='Method' then
208 return binder.WRAPCALL..m.attr.name..(overload and '__OverloadedVersion'..tostring(n) or '')
209 elseif m.tag=='Constructor' then
210 return binder.WRAPCALL..m.attr.name..'__new'..(overload and '__OverloadedVersion'..tostring(n) or '')
211 elseif m.tag=='Destructor' then
212 -- cannot be overloaded, true?
213 return binder.WRAPCALL..m.attr.name..'__delete'..(overload and '__OverloadedVersion'..tostring(n) or '')
215 return false
218 function binder.arguments_of(f)
219 local ret = {}
220 for argi = 1, table.maxn(f) do
221 if (type(f[argi])=='table') and (f[argi].tag=='Argument') then
222 table.insert(ret, f[argi])
225 return ret
229 function binder:base_type(el)
230 local ret = self:find_id(el.attr.type)
231 while (ret.tag=='Typedef') or (ret.tag=='CvQualifiedType') do
232 ret = self:find_id(ret.attr.type)
234 return ret
237 function binder:type_from_stack(el)
238 local t = self.types_from_stack
239 if t[el] then return t[el] end
241 local name = self:type_name(el)
242 if t[name] then
243 t[el] = t[name]
244 return t[el]
247 if (el.tag=='Class') or (el.tag=='Struct') or (el.tag=='Union') then
248 t[el] = function(i) return '**static_cast<'..name..'**>(lqtL_checkudata(L, '..tostring(i)..', "' ..name.. '*"))' end
249 elseif (el.tag=='CvQualifiedType') then
250 t[el] = self:type_from_stack(self:find_id(el.attr.type))
251 elseif (el.tag=='ReferenceType') then
252 t[el] = self:type_from_stack(self:find_id(el.attr.type))
253 elseif (el.tag=='Typedef') then
254 t[el] = self:type_from_stack(self:find_id(el.attr.type))
255 elseif (el.tag=='Enumeration') then
256 t[el] = function (i) return 'static_cast<'..name..'>(lqtL_toenum(L, '..tostring(i)..', "'..name..'"))' end
257 elseif (el.tag=='PointerType') then
258 local b = self:base_type(el)
259 local base_t = self:type_from_stack(b)
260 t[el] = (type(base_t)=='function') and function (i)
261 local base = base_t(i)
262 local c = string.sub(base, 1, 1)
263 if (c=='*') then
264 return string.sub(base, 2)
265 else
266 return 'static_cast<'..name..'>(lua_touserdata(L, '..tostring(i)..'))'
268 end or function (i) return '0' end
269 elseif (el.tag=='FunctionType') then -- FIXME
272 if t[el]==nil then
273 error('cannot deternime how to retrieve type: '.. ((type(el)=='table') and (el.tag..' '..el.attr.id) or el))
275 return t[el]
279 function binder:type_to_stack(el)
280 local t = self.types_to_stack
282 if t[el] then return t[el] end
284 local name = self:type_name(el)
285 -- print (el.tag, '|'..name..'|', rawget(t,el) or '<>')
287 if t[name] then
288 t[el] = t[name]
289 return t[el]
292 if (el.tag=='Class') or (el.tag=='Struct') or (el.tag=='Union') then
293 -- FIXME: force deep copy if possible
294 t[el] = function(i) return 'lqtL_passudata(L, new '..name..'('..tostring(i)..'), "'..name..'*")' end
295 elseif (el.tag=='CvQualifiedType') then -- FIXED? FIXME: this is just a mess
296 local base_t = self:base_type(el)
297 local non_cv = self:type_to_stack(base_t)
298 --if (base_t.tag=='Class') or (base_t.tag=='Struct') or (base_t.tag=='Union') then else end
299 t[el] = non_cv
300 elseif (el.tag=='ReferenceType') then
301 local base_t = self:base_type(el)
302 if (base_t.tag=='Class') or (base_t.tag=='Struct') or (base_t.tag=='Union') then
303 t[el] = function(i) return 'lqtL_pushudata(L, &('..tostring(i)..'), "'..self:type_name(base_t)..'*")' end
304 else
305 t[el] = self:type_to_stack(self:find_id(el.attr.type))
307 elseif (el.tag=='Typedef') then
308 t[el] = self:type_to_stack(self:find_id(el.attr.type))
309 elseif (el.tag=='Enumeration') then
310 t[el] = function (i) return 'lqtL_pushenum(L, '..tostring(i)..', "'..name..'")' end
311 elseif (el.tag=='PointerType') then
312 local base_t = self:base_type(el)
313 t[el] = function(i) return 'lqtL_pushudata(L, '..tostring(i)..', "'..self:type_name(base_t)..'*")' end
316 -- print (el.tag, el, rawget(t,el) or '<>')
317 if t[el]==nil then
318 error('cannot deternime how to push on stack type: '.. self.debug_type(el))
320 return t[el]
325 function binder:type_test(el)
326 local t = self.types_test
328 if t[el] then return t[el] end
330 local name = self:type_name(el)
332 if t[name] then
333 t[el] = t[name]
334 return t[el]
337 if (el.tag=='Class') or (el.tag=='Struct') or (el.tag=='Union') then
338 t[el] = function(i) return 'lqtL_testudata(L, ' .. tostring(i) .. ', "' .. name .. '*")' end
339 elseif (el.tag=='CvQualifiedType') then
340 t[el] = self:type_test(self:find_id(el.attr.type))
341 elseif (el.tag=='ReferenceType') then
342 t[el] = self:type_test(self:find_id(el.attr.type))
343 elseif (el.tag=='Typedef') then
344 t[el] = self:type_test(self:find_id(el.attr.type))
345 elseif (el.tag=='Enumeration') then
346 t[el] = function (i) return 'lqtL_isenum(L, '..tostring(i)..', "'..name..'")' end
347 elseif (el.tag=='PointerType') then
348 t[el] = self:type_test(self:find_id(el.attr.type)) or function() return '(true)' end
349 elseif (el.tag=='FunctionType') then -- FIXME
352 -- print (el.tag, el, rawget(t,el) or '<>')
353 if t[el]==nil then
354 error('cannot deternime how to test type: '.. self.debug_type(el))
356 return t[el]
360 function binder:function_body(f)
361 if f.attr.pure_virtual=='1' then error'cannot call pure vitual functions' end
363 local body = '{\n'
364 local has_this = 0
365 --local base_class = nil
366 local args = self.arguments_of(f)
367 local funcname = self:context_name(f) .. f.attr.name
368 local ret_type = nil
369 local pointer_to_class = self.fake_pointer(f.attr.context)
371 --if f.attr.context then base_class = self:find_id(f.attr.context) end
372 --if base_class and ((base_class.tag=='Class') or (base_class.tag=='Struct')) then
373 --pointer_base = self:find(self.pointer_search(f.attr.context))
374 --end
376 -- NEEDS THIS POINTER?
377 if ( (f.tag=='Method') and (f.attr.static~='1') ) or (f.tag == 'Destructor') then
378 local pointer_base = pointer_to_class
379 body = body .. ' ' .. self:type_name(pointer_base) .. '& __lua__obj = '
380 .. self:type_from_stack(pointer_base)(1) .. ';\n';
381 ---[==[
382 body = body .. [[
383 if (__lua__obj==0) {
384 lua_pushstring(L, "trying to reference deleted pointer");
385 lua_error(L);
386 return 0;
389 --]==]
390 has_this = 1
393 -- GETTING ARGUMENTS
394 for argi = 1, table.maxn(args) do
395 local arg = args[argi]
396 local argname = 'arg' .. tostring(argi)
398 local argt = self:find_id(arg.attr.type)
399 local argtype = self:type_name(argt)
400 local def = arg.attr.default
402 if def and string.match(string.sub(def, 1, 1), '[%l%u]') then
403 def = self:context_name(argt)..def
404 elseif def then
405 def = 'static_cast< ' .. argtype .. ' >(' .. def .. ')'
408 --print ('getting arg type', argtype, arg.attr.type)
410 body = body .. ' ' .. argtype .. ' ' .. argname .. ' = '
411 .. (def and (self:type_test(argt)(argi+has_this) .. '?') or '')
412 .. self:type_from_stack(argt)(argi+has_this)
413 body = body .. (def and (':' .. tostring(def)) or '') .. ';\n' -- '// default = '..tostring(def)..'\n'
415 body = body .. ' '
417 if f.tag=='Constructor' then
418 --[[
419 local my_class = self:find_id(f.attr.context)
420 if my_class.attr.abstract='1' then error'cannot construct abstract class' end
421 --]]
422 ret_type = pointer_to_class
423 funcname = 'new ' .. self.wrapclass(f.attr.name)
425 -- ret_type = self:find_id(f.attr.context) -- wrong?
426 -- body = body .. self:type_name(ret_type) .. ' * ret = new '
427 -- print (self:type_name(ret_type))
428 elseif f.tag=='Destructor' then
429 -- TREATED AS SPECIAL CASE
430 body = body .. 'delete __lua__obj;\n'
431 body = body .. ' __lua__obj = 0;\n';
432 body = body .. ' return 0;\n}\n'
433 return body
434 else
435 ret_type = self:find_id(f.attr.returns)
438 -- GET RETURN TYPE
439 if ret_type.attr.name=='void' then
440 ret_type = nil
441 else
442 body = body .. self:type_name(ret_type) .. ' ret = '
445 -- CALL FUNCTION
446 if has_this==1 then
447 body = body .. '__lua__obj->' .. funcname .. '('
448 else
449 body = body .. funcname .. '('
452 -- IF OVERRIDING CONSTRUCTOR ADD STATE POINTER
453 if f.tag=='Constructor' then
454 body = body .. 'L' .. ((table.maxn(args) > 0) and ', ' or '')
457 -- ADD ARGS TO FUNCTION CALL
458 if table.maxn(args) > 0 then body = body .. 'arg1' end
459 for argi = 2, table.maxn(args) do
460 body = body .. ', arg' .. tostring(argi)
463 body = body .. ');\n'
465 -- HANDLE RETURN VALUE
466 if f.tag=='Constructor' then
467 body = body .. ' lqtL_passudata(L, ret, "'..f.attr.name..'*");\n'
468 body = body .. ' return 1;\n}\n'
469 elseif ret_type then
470 -- print('pushing', binder:type_name(ret_type))
471 local ret_to_stack = self:type_to_stack(ret_type)'ret'
472 body = body .. ' ' .. ret_to_stack .. ';\n'
473 body = body .. ' return 1;\n}\n'
474 else
475 body = body .. ' return 0;\n}\n'
478 return body
481 function binder:function_test(p, score)
482 local ret = ''
483 local isstatic = 0
485 ret = ret .. ' ' .. score .. ' = 0;\n'
487 if p.attr.static~='1' and p.tag=='Method' then
488 ret = ret .. ' ' .. score .. ' += ' .. self:type_test( self.fake_pointer(p.attr.context) )(1)
489 .. '?premium:-premium*premium;\n'
490 isstatic = 1
493 local args = self.arguments_of(p)
495 for argi = 1, table.maxn(args) do
496 local arg = args[argi]
497 --print ( 'ARGUMENT TEST', argi)
498 local argname = 'arg' .. tostring(argi)
499 if (type(arg)=='table') and (arg.tag=='Argument') then
500 ret = ret .. ' if (' .. self:type_test( self:find_id(arg.attr.type) )(argi+isstatic) .. ') {\n'
501 ret = ret .. ' ' .. score .. ' += premium;\n'
502 ret = ret .. ' } else if (' .. tostring(arg.attr.default and true or false) .. ') {\n'
503 ret = ret .. ' ' .. score .. ' += premium-1; // '..tostring(arg, arg.attr.default)..';\n'
504 ret = ret .. ' } else {\n'
505 ret = ret .. ' ' .. score .. ' -= premium*premium;\n'
506 ret = ret .. ' }\n'
508 -- ret = ret .. ' ' .. score .. ' += ' .. type_on_stack_test( find_id(arg.attr.type) , argi+isstatic )
509 -- .. '?' .. tostring(premium) .. ':-' .. tostring(premium) .. '*' .. tostring(premium) .. ';\n'
513 return ret
516 function binder:get_members (c)
517 if not self.members then self.members = {} end
518 if not self.members[c] then
519 local ret = { functions={}, enumerations={}, classes={}, methods={}, constructors={}, virtuals={} }
520 for s in string.gmatch(c.attr.members, '(_%d+) ') do
521 local m = self:find_id(s)
522 local n = m.attr.name
523 print("member of", c.attr.name , "found:", s, "name:", n)
525 local filtered, motive = false, ''
526 if self.filter then
527 filtered, motive = self.filter(m)
530 if filtered then
531 print('Filtered member: '..n..' for '..(motive or 'no apparent reason.'))
532 elseif m.tag=='Enumeration' then
533 table.insert(ret.enumerations, m)
534 elseif m.tag=='Function' then
535 ret.functions[n] = ret.functions[n] or {}
536 table.insert(ret.functions[n], m)
537 elseif m.tag=='Method' and (m.attr.access=='public') then
538 ret.methods[n] = ret.methods[n] or {}
539 table.insert(ret.methods[n], m)
540 elseif m.tag=='Constructor' and (m.attr.access=='public') then
541 table.insert(ret.constructors, m)
542 elseif m.tag=='Destructor' then
543 ret.destructor = m
544 elseif m.tag=='Class' or m.tag=='Struct' then
545 table.insert(ret.classes, m)
548 if (m.attr.virtual=='1') and (m.tag~='Constructor') and (m.tag~='Destructor') and not filtered then
549 table.insert(ret.virtuals, m)
551 --[[
552 local n = n..' < < of type > > '.. m.tag ..' < < with access > > ' .. m.attr.access
553 ret.cache[n] = ret.cache[n] or {}
554 table.insert(ret.cache[n], m)
557 self.members[c] = ret
559 return self.members[c]
562 function binder:code_function (f)
563 local body, test = {}, {}
565 for i, m in ipairs(f) do
566 local fname = self.wrapcall(m, overloaded, j)
568 if not fname then error'this shout *NOT* happen!' end
569 local st, err
571 st, err = pcall(self.function_body, self, m)
572 if st then
573 body[i] = err
574 else
575 print(err)
576 body[i] = nil
579 st, err = pcall(self.function_test, self, m, 'score['..i..']')
580 if st then
581 test[i] = err
582 else
583 print(err)
584 test[i] = nil
587 --body[i] = self:function_body(m)
588 --test[i] = self:function_test(m, 'score['..i..']')
591 return body, test
594 function binder:begin_dispatch(n, m)
595 return self.lua_proto(n) .. ' {\n int score[' .. (m+1)
596 ..'];\n const int premium = 11+lua_gettop(L);\n'
599 function binder:choose_dispatch(m)
600 return [[
601 int best = 1;
602 for (int i=1;i<=]]..m..[[;i++) {
603 if (score[best] < score[i]) { best = i; }
605 switch (best) {
609 function binder:solve_overload (f, n, c)
610 local proto, def = '', ''
611 local body, test = self:code_function(f)
613 local number = 0
614 for i = 1,table.maxn(f) do if (type(body[i])=='string') and (type(test[i])=='string') then number = number + 1 end end
616 if number>1 then
617 local fulltest = self:begin_dispatch(c..n, table.maxn(f))
619 for i = 1,table.maxn(f) do
620 local fullname = n..'__OverloadedVersion__'..i
621 if (type(body[i])=='string') and (type(test[i])=='string') then
622 proto = proto .. ' static '..self.lua_proto(fullname)..';\n'
623 def = def .. self.lua_proto(c..fullname)..' '..body[i]
624 fulltest = fulltest .. test[i]
628 fulltest = fulltest .. self:choose_dispatch(table.maxn(f))
630 for i = 1,table.maxn(f) do
631 if (type(body[i])=='string') and (type(test[i])=='string') then
632 local fullname = n..'__OverloadedVersion__'..i
633 fulltest = fulltest .. ' case ' .. i .. ': return ' .. fullname ..'(L); break;\n'
637 -- TODO: move to a function?
638 -- TODO: trigger an error
639 fulltest = fulltest .. [[
641 lua_pushstring(L, "no overload of function ]].. n ..[[ matching arguments");
642 lua_error(L);
643 return 0;
647 proto = proto .. ' static '..self.lua_proto(n)..';\n'
648 def = def .. fulltest
649 elseif number==1 then
650 proto, def = nil, nil
651 for i, v in ipairs(body) do
652 proto = ' static '..self.lua_proto(n)..';\n'
653 def = self.lua_proto(c..n)..' '..v
655 else
656 proto, def = nil, nil
659 return proto, def
662 function binder:enum_push_body(id, c)
663 local enum = (type(id)=='string') and self:find_id(id) or id
664 local e_static = (self:find_id(enum.attr.context).tag == 'Class') and 'static ' or ''
665 local e_context = self:context_name(enum)
666 local e_name = 'lqt_pushenum_' .. enum.attr.name
667 local e_proto, e_def = '', ''
669 e_proto = e_proto .. ' ' .. e_static .. self.lua_proto(e_name) .. ';\n'
670 e_def = e_def .. self.lua_proto(c .. e_name) .. ' '
671 e_def = e_def .. '{\n'
672 e_def = e_def .. ' int enum_table = 0;\n'
673 e_def = e_def .. ' lua_getfield(L, LUA_REGISTRYINDEX, LQT_ENUMS);\n'
674 e_def = e_def .. ' if (!lua_istable(L, -1)) {\n'
675 e_def = e_def .. ' lua_pop(L, 1);\n'
676 e_def = e_def .. ' lua_newtable(L);\n'
677 e_def = e_def .. ' lua_pushvalue(L, -1);\n'
678 e_def = e_def .. ' lua_setfield(L, LUA_REGISTRYINDEX, LQT_ENUMS);\n'
679 e_def = e_def .. ' }\n'
681 e_def = e_def .. ' lua_newtable(L);\n'
682 e_def = e_def .. ' enum_table = lua_gettop(L);\n'
683 for i, e in ipairs(enum) do
684 if (type(e)=='table') and (e.tag=='EnumValue') then
685 e_def = e_def .. ' lua_pushstring(L, "' .. e.attr.name .. '");\n'
686 e_def = e_def .. ' lua_rawseti(L, enum_table, ' .. e.attr.init .. ');\n'
687 e_def = e_def .. ' lua_pushinteger(L, ' .. e.attr.init .. ');\n'
688 e_def = e_def .. ' lua_setfield(L, enum_table, "' .. e.attr.name .. '");\n'
691 e_def = e_def .. ' lua_pushvalue(L, -1);\n'
692 e_def = e_def .. ' lua_setfield(L, -3, "' .. e_context .. enum.attr.name .. '");\n'
693 e_def = e_def .. ' lua_remove(L, -2);\n'
694 e_def = e_def .. ' return 1;\n'
695 e_def = e_def .. '}\n'
696 --print (e_def)
697 return e_proto, e_def, e_name
700 function binder:mangled (f)
701 local args = self:arguments_of(f)
702 local k = f.attr.name..'('
703 for i = 1, table.maxn(args) do
704 k = k..', '..self:type_name(args.attr.type)
706 k = k..')'
707 return k
710 function binder:get_virtuals (c)
711 local c_v = self:get_members(c).virtuals
712 local mang_virtuals = {}
714 for n, f in pairs(c_v) do
715 if f.attr.virtual=='1' then
716 local k = self:mangled(f)
717 mang_virtuals[k] = mang_virtuals[k] or f
722 for s in string.gmatch(c.attr.bases or '', '(_%d+) ') do
723 local my_base = self:find_id(s)
724 local my_virtual = self:get_virtuals(my_base)
725 for k, f in pairs(my_virtual) do
726 mang_virtuals[k] = mang_virtuals[k] or f
730 return mang_virtuals
733 function binder:proto_preamble (n, ...)
734 -- FIXME: this is only Qt (the inclusion by name of class)
735 -- FIXED?
736 i = i or n
737 local ret = [[
738 #include "lqt_common.hpp"
740 for n = 1,select('#', ...) do
741 local i = select(n, ...)
742 ret = ret .. '#include <'..i..'>\n'
745 ret = ret .. [[
747 template <> class ]] .. self.wrapclass(n) .. [[ : public ]] .. n .. [[ {
748 private:
749 lua_State *L;
750 public:
752 return ret
755 function binder:proto_ending (n)
756 return [[
762 function binder:copy_constructor(c)
763 local constr = ' '
764 local args = self.arguments_of(c)
765 constr = constr .. self.wrapclass(c.attr.name) .. ' (lua_State *l'
766 for argi = 1, table.maxn(args) do
767 local argt = self:find_id(args[argi].attr.type)
768 local argtype = self:type_name(argt)
769 constr = constr .. ', ' .. argtype .. ' arg'..tostring(argi)
771 constr = constr .. '):'..c.attr.name..'('
772 for argi = 1, table.maxn(args) do
773 constr = constr .. ((argi>1) and ', ' or '') .. 'arg'..tostring(argi)
775 constr = constr .. '), L(l) {}\n'
776 return constr, nil
779 function binder.meta_constr_proto (n) return 'int luaopen_'..n..' (lua_State *L);\n' end
780 function binder.meta_constr_preamble (n)
781 return [[
782 int luaopen_]]..n..[[ (lua_State *L) {
783 if (luaL_newmetatable(L, "]]..n..[[*")) {
786 function binder.meta_constr_method (n, c)
787 c = c or ''
788 return ' lua_pushcfunction(L, '..c..n..');\n lua_setfield(L, -2, "'..n..'");\n'
790 function binder.meta_constr_ending (n)
791 return [[
792 lua_pushcfunction(L, lqtL_newindex);
793 lua_setfield(L, -2, "__newindex");
794 lua_pushcfunction(L, lqtL_index);
795 lua_setfield(L, -2, "__index");
796 lua_pushcfunction(L, lqtL_gc);
797 lua_setfield(L, -2, "__gc");
798 lua_pushstring(L, "]]..n..[[");
799 lua_setfield(L, -2, "__qtype");
800 lua_setglobal(L, "]]..n..[[");
801 } else {
802 lua_pop(L, 1);
804 return 0;
809 function binder:virtual_overload (f, c, id)
810 --if f.attr.access~='public' then error'only public virtual function are exported' end
811 if f.attr.access=='private' then error'private virtual function are not exported' end
813 c = c or ''
814 local args = self.arguments_of(f)
815 local ret_t = f.attr.returns and self:find_id(f.attr.returns)
816 local ret_n = ret_t and self:type_name(ret_t) or 'void'
817 local fh, fb = ' ', ''
818 fh = fh .. ret_n .. ' ' .. f.attr.name .. ' ('
819 fb = fb .. ret_n .. ' ' .. c .. f.attr.name .. ' ('
821 -- GETTING ARGUMENTS
822 for argi = 1, table.maxn(args) do
823 local arg = args[argi]
824 local argname = 'arg' .. tostring(argi)
826 local argt = self:find_id(arg.attr.type)
827 local argtype = self:type_name(argt)
828 local def = arg.attr.default or nil
830 def = def and (self:context_name(argt)..def)
832 --print ('signing arg type', argtype)
834 if argi>1 then fh = fh .. ', ' fb = fb .. ', ' end
835 fh = fh .. argtype .. ' ' .. argname .. (def and (' = '..def) or '')
836 fb = fb .. argtype .. ' ' .. argname
839 fh = fh .. ')' .. (f.attr.const and ' const' or '') .. ';\n'
841 if f.attr.access~='public' then
842 fh = f.attr.access .. ':\n' .. fh .. 'public:\n'
845 fb = fb .. ')' .. (f.attr.const and ' const' or '') .. ' {\n'
846 fb = fb .. ' bool absorbed = false;\n int oldtop = lua_gettop(L);\n'
848 local context = self:context_name(f)
849 local pointer_to_class = self.fake_pointer ( id or f.attr.context )
850 local push_this = self:type_to_stack(pointer_to_class)'this'
851 --fb = fb .. ' ' .. push_this .. ';\n'
852 --fb = fb .. ' lua_getfield(L, -1, "'..(f.attr.name)..'");\n lua_insert(L, -2);\n'
853 ---[=[
854 fb = fb .. ' ' .. push_this .. [[;
855 if (lua_getmetatable(L, -1)) {
856 lua_getfield(L, -1, "]]..(f.attr.name)..[[");
857 lua_remove(L, -2);
858 } else {
859 lua_pushnil(L);
861 lua_insert(L, -2);
863 --]=]
866 for argi = 1, table.maxn(args) do
867 local arg = args[argi]
868 local argname = 'arg' .. tostring(argi)
870 local argt = self:find_id(arg.attr.type)
871 local argtype = self:type_name(argt)
872 local def = arg.attr.default
874 def = def and (self:context_name(argt)..def)
876 local to_stack = self:type_to_stack(argt)(argname)
877 --to_stack = (type(to_stack)=='string') and to_stack or table.concat(to_stack, '\n ')
878 fb = fb .. ' ' .. to_stack .. ';\n'
881 local sig = '(' .. (args[1] and 'arg1' or '')
882 for argi = 2, table.maxn(args) do
883 sig = sig .. ', arg' .. argi
885 sig = sig .. ')'
887 fb = fb .. [[
888 if (lua_isfunction(L, -]]..table.maxn(args)..[[-2)) {
889 lua_pcall(L, ]] .. table.maxn(args) .. [[+1, 2, 0);
890 absorbed = (bool)lua_toboolean(L, -1) || (bool)lua_toboolean(L, -2);
891 lua_pop(L, 1);
893 if (!absorbed) {
894 lua_settop(L, oldtop);
895 ]] .. (f.attr.pure_virtual~='1' and (((ret_n~='void') and 'return ' or '')..'this->'..context..f.attr.name..sig..';\n') or '') .. [[
898 -- fb = fb .. ' if (!lua_isnil)' -- TODO: check?
899 if ret_n~='void' then
900 fb = fb .. ' ' .. ret_n .. ' ret = ' .. self:type_from_stack(ret_t)(-1) .. ';\n'
901 fb = fb .. ' lua_settop(L, oldtop);\n'
902 fb = fb .. ' return ret;\n'
903 else
904 fb = fb .. ' lua_settop(L, oldtop);\n'
906 fb = fb .. '}\n'
908 return fh, fb
911 function binder:virtual_destructor (f, c)
912 c = c or ''
913 local lname = self.wrapclass(f.attr.name)
914 local pclass = self.fake_pointer(f.attr.context)
915 local push_this = self:type_to_stack(pclass)'this'
916 return [[
917 ~]]..lname..[[ ();
918 ]],
919 c .. [[
920 ~]]..lname..[[ () {
921 int oldtop = lua_gettop(L);
922 ]] .. push_this .. [[;
923 lua_getfield(L, -1, "~]]..f.attr.name..[[");
925 if (lua_isfunction(L, -1)) {
926 lua_insert(L, -2);
927 lua_pcall(L, 1, 1, 0);
928 } else {
930 lua_settop(L, oldtop);
936 function binder:make_namespace(tname, include_file, ...)
937 local bind_file = 'lqt_bind_'..include_file..'.hpp'
938 if string.match(include_file, '(%.[hH]([pP]?)%2)$') then
939 bind_file = 'lqt_bind_'..include_file
942 local my_class = self:find_id(tname) or self:find_name(tname)
943 local my_context = self.wrapclass(tname)..'::'
945 local my = self:get_members(my_class)
947 local my_enums = nil
948 my.virtuals = self:get_virtuals(my_class)
950 print 'writing preambles'
952 local fullproto = self:proto_preamble(tname, include_file, ...)
953 local fulldef = '#include "'..bind_file..'"\n\n'
954 local metatable_constructor = self.meta_constr_preamble(tname)
956 print 'binding each member'
958 local my_members = {}
959 table.foreach(my.methods, function(k, v) my_members[k] = v end)
960 my_members.new = my.constructors
961 my_members.delete = { my.destructor }
962 for n, l in pairs(my_members) do
963 local fname = self.WRAPCALL..n
964 local proto, def = self:solve_overload(l, fname, my_context)
965 if (proto and def) then
966 fullproto = fullproto .. proto
967 fulldef = fulldef .. def
968 metatable_constructor = metatable_constructor .. self.meta_constr_method (n, my_context..self.WRAPCALL)
972 print'binding virtual methods'
974 for s, f in pairs(my.virtuals) do
975 print ('virtual', s)
976 local ret, h, c = pcall(self.virtual_overload, self, f, my_context, my_class.attr.id)
977 if ret then
978 fullproto, fulldef = fullproto..h, fulldef..c
979 else
980 print(h)
984 print'overriding virtual destructor'
985 if my.destructor and my.destructor.attr.virtual == '1' then
986 local h, c = self:virtual_destructor(my.destructor, my_context)
987 fullproto, fulldef = fullproto..h, fulldef..c
990 print'creating enum translation tables'
991 for k, e in pairs(my.enumerations) do
992 local e_p, e_d, e_n = self:enum_push_body(e, my_context)
993 fulldef = fulldef .. e_d
994 fullproto = fullproto .. e_p
995 metatable_constructor = metatable_constructor .. ' ' .. my_context .. e_n .. '(L);\n lua_setfield(L, -2, "'..e.attr.name..'");\n'
998 print'copying constructors'
999 for i, v in ipairs(my.constructors) do
1000 fullproto = fullproto..self:copy_constructor(v)
1002 fullproto = fullproto .. self:proto_ending(tname) .. self.meta_constr_proto (tname)
1004 print'specifying bases'
1005 metatable_constructor = metatable_constructor .. ' lua_newtable(L);\n'
1006 local deep_bases = {}
1007 for s in string.gmatch(my_class.attr.bases or '', '(_%d+) ') do
1008 local base = self:find_id(s)
1009 local bname = self:type_name(base)
1010 metatable_constructor = metatable_constructor .. [[
1011 lua_pushboolean(L, 1);
1012 lua_setfield(L, -2, "]]..bname..[[*");
1014 deep_bases = self.set_union(deep_bases, self:tree_of_bases(base))
1016 for n in pairs(deep_bases) do
1017 metatable_constructor = metatable_constructor .. [[
1018 lua_pushboolean(L, 0);
1019 lua_setfield(L, -2, "]]..n..[[*");
1022 metatable_constructor = metatable_constructor .. ' lua_setfield(L, -2, "__base");\n'
1025 print'finalizing code'
1026 metatable_constructor = metatable_constructor .. self.meta_constr_ending (tname)
1027 fulldef = fulldef .. metatable_constructor
1029 return fullproto, fulldef
1032 function binder.set_union(...)
1033 local ret = {}
1034 for _, s in ipairs{...} do
1035 for v, t in pairs(s) do
1036 if t==true then ret[v] = true end
1039 return ret
1042 function binder:tree_of_bases(c)
1043 local ret = {}
1044 for s in string.gmatch(c.attr.bases or '', '(_%d+) ') do
1045 local b = self:find_id(s)
1046 ret[b.attr.name] = true
1047 local bb = self:tree_of_bases(b)
1048 ret = self.set_union(ret, bb)
1050 return ret
1054 return binder