changed macros in lqt_common.hpp to reflect new header name
[lqt.git] / binder.lua
blob05698cfa4e00a584d22241909da031f1de5503cd
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 ['const char *'] = function(i) return 'lua_pushstring(L, ' .. tostring(i) .. ')' end,
28 ['short int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
29 ['unsigned short int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
30 ['short unsigned int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
31 ['int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
32 ['unsigned int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
33 ['long int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
34 ['unsigned long int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
35 ['long unsigned int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
36 ['long long int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
37 ['unsigned long long int'] = function(i) return 'lua_pushinteger(L, ' .. tostring(i) .. ')' end,
38 ['float'] = function(i) return 'lua_pushnumber(L, ' .. tostring(i) .. ')' end,
39 ['double'] = function(i) return 'lua_pushnumber(L, ' .. tostring(i) .. ')' end,
40 ['bool'] = function(i) return 'lua_pushboolean(L, ' .. tostring(i) .. ')' end,
41 ['void *'] = function(i) return 'lua_pushlightuserdata(L, ' .. tostring(i) .. ')' end,
42 ['void * *'] = function(i) return 'lua_pushlightuserdata(L, ' .. tostring(i) .. ')' end,
44 self.types_from_stack = {
45 ['const char *'] = function(i) return 'lua_tostring(L, ' .. tostring(i) .. ')' end,
46 ['short int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
47 ['unsigned short int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
48 ['short unsigned int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
49 ['int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
50 ['unsigned int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
51 ['long int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
52 ['unsigned long int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
53 ['long unsigned int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
54 ['long long int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
55 ['unsigned long long int'] = function(i) return 'lua_tointeger(L, ' .. tostring(i) .. ')' end,
56 ['float'] = function(i) return 'lua_tonumber(L, ' .. tostring(i) .. ')' end,
57 ['double'] = function(i) return 'lua_tonumber(L, ' .. tostring(i) .. ')' end,
58 ['bool'] = function(i) return '(bool)lua_toboolean(L, ' .. tostring(i) .. ')' end,
59 ['void *'] = function(i) return 'lua_touserdata(L, ' .. tostring(i) .. ')' end,
60 ['void * *'] = function(i) return 'static_cast<void **>(lua_touserdata(L, ' .. tostring(i) .. '))' end,
62 self.types_test = {
63 ['const char *'] = function(i) return '(lua_type(L, ' .. tostring(i) .. ')==LUA_TSTRING)' end,
64 ['short int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
65 ['unsigned short int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
66 ['short unsigned int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
67 ['int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
68 ['unsigned int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
69 ['long int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
70 ['unsigned long int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
71 ['long unsigned int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
72 ['long long int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
73 ['unsigned long long int'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
74 ['float'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
75 ['double'] = function(i) return 'lua_isnumber(L, ' .. tostring(i) .. ')' end,
76 ['bool'] = function(i) return 'lua_isboolean(L, ' .. tostring(i) .. ')' end,
77 ['void *'] = function(i) return 'lua_isuserdata(L, ' .. tostring(i) .. ')' end,
78 ['void * *'] = function(i) return 'lua_isuserdata(L, ' .. tostring(i) .. ')' end,
80 -- self.conditions = {}
82 return self.tree
83 end
85 function binder.wrapclass(n)
86 return 'LuaBinder< '..n..' >'
87 end
89 function binder.lua_proto(s)
90 return 'int '..s..' (lua_State *L)'
91 end
93 function binder.fake_pointer (id)
94 return { tag='PointerType', attr={ type=id } }
95 end
97 function binder:find(f, t)
98 t = t or self.tree
99 if type(t)~='table' then return nil end;
100 if f(t) then return t end
101 local ret = nil
102 for k,v in pairs(t) do
103 ret = ret or self:find(f, v)
104 if ret then break end
105 end;
106 return ret;
109 function binder.name_search (n)
110 return function (t)
111 return (type(t)=='table') and (type(t.attr)=='table') and (t.attr.name==n)
115 function binder.id_search (i)
116 return function (t)
117 return (type(t)=='table') and (type(t.attr)=='table') and (t.attr.id==i) -- or ((type(i)=='table') and i[t.attr.id])
121 function binder.tag_search (n)
122 return function (t)
123 return (type(t)=='table') and (t.tag==n) -- or ((type(i)==table) and i[t.attr.id])
127 function binder.pointer_search(id)
128 return function (t)
129 return (type(t)=='table') and (t.tag=='PointerType') and (type(t.attr)=='table') and (t.attr.type==id)
133 function binder:find_name (n)
134 if not self.names then self.names = {} end
135 if not self.names[n] then
136 self.names[n] = self:find(self.name_search(n))
138 return self.names[n]
141 function binder:find_id (n)
142 if not self.ids then self.ids = {} end
143 if not self.ids[n] then
144 self.ids[n] = self:find(self.id_search(n))
146 return self.ids[n]
149 function binder:find_pointer (n)
150 if not self.pointers then self.pointers = {} end
151 if not self.pointers[n] then
152 self.pointers[n] = self:find(self.pointer_search(n.attr.id))
154 return self.pointers[n]
157 function binder:context_name(el)
158 if type(el.attr)~='table' then return '' end
159 if type(el.attr.context)~='string' then return '' end
161 local context_el = self:find_id(el.attr.context)
163 if not context_el then return '' end
165 local context = (context_el.attr.name=='::') and '' or (context_el.attr.name..'::')
166 return context
169 function binder:type_name(el)
170 -- print('getting name of', el, el.tag)
172 self.type_names = self.type_names or {}
173 local t = self.type_names
175 if t[el] then return t[el] end
177 if el.tag == 'FundamentalType' then
178 t[el] = el.attr.name
179 elseif (el.tag == 'Class') or (el.tag == 'Struct') or (el.tag=='Union') then
180 t[el] = self:context_name(el) .. el.attr.name
181 elseif el.tag == 'Typedef' then
182 t[el] = self:type_name(self:find_id(el.attr.type))
183 elseif el.tag == 'PointerType' then
184 t[el] = self:type_name(self:find_id(el.attr.type)) .. ' *'
185 elseif el.tag == 'ReferenceType' then
186 t[el] = self:type_name(self:find_id(el.attr.type)) .. '&'
187 elseif el.tag == 'CvQualifiedType' then
188 t[el] = ( (el.attr.volatile=='1') and 'volatile ' or '' )
189 .. ( (el.attr.const=='1') and 'const ' or '' )
190 .. self:type_name(self:find_id(el.attr.type))
191 elseif el.tag == 'Enumeration' then
192 t[el] = self:context_name(el) .. el.attr.name
193 else
194 error('cannot determine type name: ' .. self.debug_type(el))
196 return t[el]
199 function binder.wrapcall(m, overload, n)
200 if m.tag=='Method' then
201 return binder.WRAPCALL..m.attr.name..(overload and '__OverloadedVersion'..tostring(n) or '')
202 elseif m.tag=='Constructor' then
203 return binder.WRAPCALL..m.attr.name..'__new'..(overload and '__OverloadedVersion'..tostring(n) or '')
204 elseif m.tag=='Destructor' then
205 -- cannot be overloaded, true?
206 return binder.WRAPCALL..m.attr.name..'__delete'..(overload and '__OverloadedVersion'..tostring(n) or '')
208 return false
211 function binder.arguments_of(f)
212 local ret = {}
213 for argi = 1, table.maxn(f) do
214 if (type(f[argi])=='table') and (f[argi].tag=='Argument') then
215 table.insert(ret, f[argi])
218 return ret
222 function binder:base_type(el)
223 local ret = self:find_id(el.attr.type)
224 while (ret.tag=='Typedef') or (ret.tag=='CvQualifiedType') do
225 ret = self:find_id(ret.attr.type)
227 return ret
230 function binder:type_from_stack(el)
231 local t = self.types_from_stack
232 if t[el] then return t[el] end
234 local name = self:type_name(el)
235 if t[name] then
236 t[el] = t[name]
237 return t[el]
240 if (el.tag=='Class') or (el.tag=='Struct') or (el.tag=='Union') then
241 t[el] = function(i) return '**static_cast<'..name..'**>(lqtL_checkudata(L, '..tostring(i)..', "' ..name.. '*"))' end
242 elseif (el.tag=='CvQualifiedType') then
243 t[el] = self:type_from_stack(self:find_id(el.attr.type))
244 elseif (el.tag=='ReferenceType') then
245 t[el] = self:type_from_stack(self:find_id(el.attr.type))
246 elseif (el.tag=='Typedef') then
247 t[el] = self:type_from_stack(self:find_id(el.attr.type))
248 elseif (el.tag=='Enumeration') then
249 t[el] = function (i) return 'static_cast<'..name..'>(lqtL_toenum(L, '..tostring(i)..', "'..name..'"))' end
250 elseif (el.tag=='PointerType') then
251 local b = self:base_type(el)
252 local base_t = self:type_from_stack(b)
253 t[el] = (type(base_t)=='function') and function (i)
254 local base = base_t(i)
255 local c = string.sub(base, 1, 1)
256 if (c=='*') then
257 return string.sub(base, 2)
258 else
259 return 'static_cast<'..name..'>(lua_touserdata(L, '..tostring(i)..'))'
261 end or function (i) return '0' end
262 elseif (el.tag=='FunctionType') then -- FIXME
265 if t[el]==nil then
266 error('cannot deternime how to retrieve type: '.. ((type(el)=='table') and (el.tag..' '..el.attr.id) or el))
268 return t[el]
272 function binder:type_to_stack(el)
273 local t = self.types_to_stack
275 if t[el] then return t[el] end
277 local name = self:type_name(el)
278 -- print (el.tag, '|'..name..'|', rawget(t,el) or '<>')
280 if t[name] then
281 t[el] = t[name]
282 return t[el]
285 if (el.tag=='Class') or (el.tag=='Struct') or (el.tag=='Union') then
286 -- FIXME: force deep copy if possible
287 t[el] = function(i) return 'lqtL_passudata(L, new '..name..'('..tostring(i)..'), "'..name..'*")' end
288 elseif (el.tag=='CvQualifiedType') then -- FIXED? FIXME: this is just a mess
289 local base_t = self:base_type(el)
290 local non_cv = self:type_to_stack(base_t)
291 --if (base_t.tag=='Class') or (base_t.tag=='Struct') or (base_t.tag=='Union') then else end
292 t[el] = non_cv
293 elseif (el.tag=='ReferenceType') then
294 local base_t = self:base_type(el)
295 if (base_t.tag=='Class') or (base_t.tag=='Struct') or (base_t.tag=='Union') then
296 t[el] = function(i) return 'lqtL_pushudata(L, &('..tostring(i)..'), "'..self:type_name(base_t)..'*")' end
297 else
298 t[el] = self:type_to_stack(self:find_id(el.attr.type))
300 elseif (el.tag=='Typedef') then
301 t[el] = self:type_to_stack(self:find_id(el.attr.type))
302 elseif (el.tag=='Enumeration') then
303 t[el] = function (i) return 'lqtL_pushenum(L, '..tostring(i)..', "'..name..'")' end
304 elseif (el.tag=='PointerType') then
305 local base_t = self:base_type(el)
306 t[el] = function(i) return 'lqtL_pushudata(L, '..tostring(i)..', "'..self:type_name(base_t)..'*")' end
309 -- print (el.tag, el, rawget(t,el) or '<>')
310 if t[el]==nil then
311 error('cannot deternime how to push on stack type: '.. self.debug_type(el))
313 return t[el]
318 function binder:type_test(el)
319 local t = self.types_test
321 if t[el] then return t[el] end
323 local name = self:type_name(el)
325 if t[name] then
326 t[el] = t[name]
327 return t[el]
330 if (el.tag=='Class') or (el.tag=='Struct') or (el.tag=='Union') then
331 t[el] = function(i) return 'lqtL_testudata(L, ' .. tostring(i) .. ', "' .. name .. '*")' end
332 elseif (el.tag=='CvQualifiedType') then
333 t[el] = self:type_test(self:find_id(el.attr.type))
334 elseif (el.tag=='ReferenceType') then
335 t[el] = self:type_test(self:find_id(el.attr.type))
336 elseif (el.tag=='Typedef') then
337 t[el] = self:type_test(self:find_id(el.attr.type))
338 elseif (el.tag=='Enumeration') then
339 t[el] = function (i) return 'lqtL_isenum(L, '..tostring(i)..', "'..name..'")' end
340 elseif (el.tag=='PointerType') then
341 t[el] = self:type_test(self:find_id(el.attr.type)) or function() return '(true)' end
342 elseif (el.tag=='FunctionType') then -- FIXME
345 -- print (el.tag, el, rawget(t,el) or '<>')
346 if t[el]==nil then
347 error('cannot deternime how to test type: '.. self.debug_type(el))
349 return t[el]
353 function binder:function_body(f)
354 if f.attr.pure_virtual=='1' then error'cannot call pure vitual functions' end
356 local body = '{\n'
357 local has_this = 0
358 --local base_class = nil
359 local args = self.arguments_of(f)
360 local funcname = self:context_name(f) .. f.attr.name
361 local ret_type = nil
362 local pointer_to_class = self.fake_pointer(f.attr.context)
364 --if f.attr.context then base_class = self:find_id(f.attr.context) end
365 --if base_class and ((base_class.tag=='Class') or (base_class.tag=='Struct')) then
366 --pointer_base = self:find(self.pointer_search(f.attr.context))
367 --end
369 -- NEEDS THIS POINTER?
370 if ( (f.tag=='Method') and (f.attr.static~='1') ) or (f.tag == 'Destructor') then
371 local pointer_base = pointer_to_class
372 body = body .. ' ' .. self:type_name(pointer_base) .. '& __lua__obj = '
373 .. self:type_from_stack(pointer_base)(1) .. ';\n';
374 ---[==[
375 body = body .. [[
376 if (__lua__obj==0) {
377 lua_pushstring(L, "trying to reference deleted pointer");
378 lua_error(L);
379 return 0;
382 --]==]
383 has_this = 1
386 -- GETTING ARGUMENTS
387 for argi = 1, table.maxn(args) do
388 local arg = args[argi]
389 local argname = 'arg' .. tostring(argi)
391 local argt = self:find_id(arg.attr.type)
392 local argtype = self:type_name(argt)
393 local def = arg.attr.default
395 if def and string.match(string.sub(def, 1, 1), '[%l%u]') then
396 def = self:context_name(argt)..def
397 elseif def then
398 def = 'static_cast< ' .. argtype .. ' >(' .. def .. ')'
401 --print ('getting arg type', argtype, arg.attr.type)
403 body = body .. ' ' .. argtype .. ' ' .. argname .. ' = '
404 .. (def and (self:type_test(argt)(argi+has_this) .. '?') or '')
405 .. self:type_from_stack(argt)(argi+has_this)
406 body = body .. (def and (':' .. tostring(def)) or '') .. ';\n' -- '// default = '..tostring(def)..'\n'
408 body = body .. ' '
410 if f.tag=='Constructor' then
411 --[[
412 local my_class = self:find_id(f.attr.context)
413 if my_class.attr.abstract='1' then error'cannot construct abstract class' end
414 --]]
415 ret_type = pointer_to_class
416 funcname = 'new ' .. self.wrapclass(f.attr.name)
418 -- ret_type = self:find_id(f.attr.context) -- wrong?
419 -- body = body .. self:type_name(ret_type) .. ' * ret = new '
420 -- print (self:type_name(ret_type))
421 elseif f.tag=='Destructor' then
422 -- TREATED AS SPECIAL CASE
423 body = body .. 'delete __lua__obj;\n'
424 body = body .. ' __lua__obj = 0;\n';
425 body = body .. ' return 0;\n}\n'
426 return body
427 else
428 ret_type = self:find_id(f.attr.returns)
431 -- GET RETURN TYPE
432 if ret_type.attr.name=='void' then
433 ret_type = nil
434 else
435 body = body .. self:type_name(ret_type) .. ' ret = '
438 -- CALL FUNCTION
439 if has_this==1 then
440 body = body .. '__lua__obj->' .. funcname .. '('
441 else
442 body = body .. funcname .. '('
445 -- IF OVERRIDING CONSTRUCTOR ADD STATE POINTER
446 if f.tag=='Constructor' then
447 body = body .. 'L' .. ((table.maxn(args) > 0) and ', ' or '')
450 -- ADD ARGS TO FUNCTION CALL
451 if table.maxn(args) > 0 then body = body .. 'arg1' end
452 for argi = 2, table.maxn(args) do
453 body = body .. ', arg' .. tostring(argi)
456 body = body .. ');\n'
458 -- HANDLE RETURN VALUE
459 if f.tag=='Constructor' then
460 body = body .. ' lqtL_passudata(L, ret, "'..f.attr.name..'*");\n'
461 body = body .. ' return 1;\n}\n'
462 elseif ret_type then
463 -- print('pushing', binder:type_name(ret_type))
464 local ret_to_stack = self:type_to_stack(ret_type)'ret'
465 body = body .. ' ' .. ret_to_stack .. ';\n'
466 body = body .. ' return 1;\n}\n'
467 else
468 body = body .. ' return 0;\n}\n'
471 return body
474 function binder:function_test(p, score)
475 local ret = ''
476 local isstatic = 0
478 ret = ret .. ' ' .. score .. ' = 0;\n'
480 if p.attr.static~='1' and p.tag=='Method' then
481 ret = ret .. ' ' .. score .. ' += ' .. self:type_test( self.fake_pointer(p.attr.context) )(1)
482 .. '?premium:-premium*premium;\n'
483 isstatic = 1
486 local args = self.arguments_of(p)
488 for argi = 1, table.maxn(args) do
489 local arg = args[argi]
490 --print ( 'ARGUMENT TEST', argi)
491 local argname = 'arg' .. tostring(argi)
492 if (type(arg)=='table') and (arg.tag=='Argument') then
493 ret = ret .. ' if (' .. self:type_test( self:find_id(arg.attr.type) )(argi+isstatic) .. ') {\n'
494 ret = ret .. ' ' .. score .. ' += premium;\n'
495 ret = ret .. ' } else if (' .. tostring(arg.attr.default and true or false) .. ') {\n'
496 ret = ret .. ' ' .. score .. ' += premium-1; // '..tostring(arg, arg.attr.default)..';\n'
497 ret = ret .. ' } else {\n'
498 ret = ret .. ' ' .. score .. ' -= premium*premium;\n'
499 ret = ret .. ' }\n'
501 -- ret = ret .. ' ' .. score .. ' += ' .. type_on_stack_test( find_id(arg.attr.type) , argi+isstatic )
502 -- .. '?' .. tostring(premium) .. ':-' .. tostring(premium) .. '*' .. tostring(premium) .. ';\n'
506 return ret
509 function binder:get_members (c)
510 if not self.members then self.members = {} end
511 if not self.members[c] then
512 local ret = { functions={}, enumerations={}, classes={}, methods={}, constructors={}, virtuals={} }
513 for s in string.gmatch(c.attr.members, '(_%d+) ') do
514 local m = self:find_id(s)
515 local n = m.attr.name
516 print("member of", c.attr.name , "found:", s, "name:", n)
518 local filtered, motive = false, ''
519 if self.filter then
520 filtered, motive = self.filter(m)
523 if filtered then
524 print('Filtered member: '..n..' for '..(motive or 'no apparent reason.'))
525 elseif m.tag=='Enumeration' then
526 table.insert(ret.enumerations, m)
527 elseif m.tag=='Function' then
528 ret.functions[n] = ret.functions[n] or {}
529 table.insert(ret.functions[n], m)
530 elseif m.tag=='Method' and (m.attr.access=='public') then
531 ret.methods[n] = ret.methods[n] or {}
532 table.insert(ret.methods[n], m)
533 elseif m.tag=='Constructor' and (m.attr.access=='public') then
534 table.insert(ret.constructors, m)
535 elseif m.tag=='Destructor' then
536 ret.destructor = m
537 elseif m.tag=='Class' or m.tag=='Struct' then
538 table.insert(ret.classes, m)
541 if (m.attr.virtual=='1') and (m.tag~='Constructor') and (m.tag~='Destructor') and not filtered then
542 table.insert(ret.virtuals, m)
544 --[[
545 local n = n..' < < of type > > '.. m.tag ..' < < with access > > ' .. m.attr.access
546 ret.cache[n] = ret.cache[n] or {}
547 table.insert(ret.cache[n], m)
550 self.members[c] = ret
552 return self.members[c]
555 function binder:code_function (f)
556 local body, test = {}, {}
558 for i, m in ipairs(f) do
559 local fname = self.wrapcall(m, overloaded, j)
561 if not fname then error'this shout *NOT* happen!' end
562 local st, err
564 st, err = pcall(self.function_body, self, m)
565 if st then
566 body[i] = err
567 else
568 print(err)
569 body[i] = nil
572 st, err = pcall(self.function_test, self, m, 'score['..i..']')
573 if st then
574 test[i] = err
575 else
576 print(err)
577 test[i] = nil
580 --body[i] = self:function_body(m)
581 --test[i] = self:function_test(m, 'score['..i..']')
584 return body, test
587 function binder:begin_dispatch(n, m)
588 return self.lua_proto(n) .. ' {\n int score[' .. (m+1)
589 ..'];\n const int premium = 11+lua_gettop(L);\n'
592 function binder:choose_dispatch(m)
593 return [[
594 int best = 1;
595 for (int i=1;i<=]]..m..[[;i++) {
596 if (score[best] < score[i]) { best = i; }
598 switch (best) {
602 function binder:solve_overload (f, n, c)
603 local proto, def = '', ''
604 local body, test = self:code_function(f)
606 local number = 0
607 for i = 1,table.maxn(f) do if (type(body[i])=='string') and (type(test[i])=='string') then number = number + 1 end end
609 if number>1 then
610 local fulltest = self:begin_dispatch(c..n, table.maxn(f))
612 for i = 1,table.maxn(f) do
613 local fullname = n..'__OverloadedVersion__'..i
614 if (type(body[i])=='string') and (type(test[i])=='string') then
615 proto = proto .. ' static '..self.lua_proto(fullname)..';\n'
616 def = def .. self.lua_proto(c..fullname)..' '..body[i]
617 fulltest = fulltest .. test[i]
621 fulltest = fulltest .. self:choose_dispatch(table.maxn(f))
623 for i = 1,table.maxn(f) do
624 if (type(body[i])=='string') and (type(test[i])=='string') then
625 local fullname = n..'__OverloadedVersion__'..i
626 fulltest = fulltest .. ' case ' .. i .. ': return ' .. fullname ..'(L); break;\n'
630 -- TODO: move to a function?
631 -- TODO: trigger an error
632 fulltest = fulltest .. [[
634 lua_pushstring(L, "no overload of function ]].. n ..[[ matching arguments");
635 lua_error(L);
636 return 0;
640 proto = proto .. ' static '..self.lua_proto(n)..';\n'
641 def = def .. fulltest
642 elseif number==1 then
643 proto, def = nil, nil
644 for i, v in ipairs(body) do
645 proto = ' static '..self.lua_proto(n)..';\n'
646 def = self.lua_proto(c..n)..' '..v
648 else
649 proto, def = nil, nil
652 return proto, def
655 function binder:enum_push_body(id, c)
656 local enum = (type(id)=='string') and self:find_id(id) or id
657 local e_static = (self:find_id(enum.attr.context).tag == 'Class') and 'static ' or ''
658 local e_context = self:context_name(enum)
659 local e_name = 'lqt_pushenum_' .. enum.attr.name
660 local e_proto, e_def = '', ''
662 e_proto = e_proto .. ' ' .. e_static .. self.lua_proto(e_name) .. ';\n'
663 e_def = e_def .. self.lua_proto(c .. e_name) .. ' '
664 e_def = e_def .. '{\n'
665 e_def = e_def .. ' int enum_table = 0;\n'
666 e_def = e_def .. ' lua_getfield(L, LUA_REGISTRYINDEX, LQT_ENUMS);\n'
667 e_def = e_def .. ' if (!lua_istable(L, -1)) {\n'
668 e_def = e_def .. ' lua_pop(L, 1);\n'
669 e_def = e_def .. ' lua_newtable(L);\n'
670 e_def = e_def .. ' lua_pushvalue(L, -1);\n'
671 e_def = e_def .. ' lua_setfield(L, LUA_REGISTRYINDEX, LQT_ENUMS);\n'
672 e_def = e_def .. ' }\n'
674 e_def = e_def .. ' lua_newtable(L);\n'
675 e_def = e_def .. ' enum_table = lua_gettop(L);\n'
676 for i, e in ipairs(enum) do
677 if (type(e)=='table') and (e.tag=='EnumValue') then
678 e_def = e_def .. ' lua_pushstring(L, "' .. e.attr.name .. '");\n'
679 e_def = e_def .. ' lua_rawseti(L, enum_table, ' .. e.attr.init .. ');\n'
680 e_def = e_def .. ' lua_pushinteger(L, ' .. e.attr.init .. ');\n'
681 e_def = e_def .. ' lua_setfield(L, enum_table, "' .. e.attr.name .. '");\n'
684 e_def = e_def .. ' lua_pushvalue(L, -1);\n'
685 e_def = e_def .. ' lua_setfield(L, -3, "' .. e_context .. enum.attr.name .. '");\n'
686 e_def = e_def .. ' lua_remove(L, -2);\n'
687 e_def = e_def .. ' return 1;\n'
688 e_def = e_def .. '}\n'
689 --print (e_def)
690 return e_proto, e_def, e_name
693 function binder:mangled (f)
694 local args = self:arguments_of(f)
695 local k = f.attr.name..'('
696 for i = 1, table.maxn(args) do
697 k = k..', '..self:type_name(args.attr.type)
699 k = k..')'
700 return k
703 function binder:get_virtuals (c)
704 local c_v = self:get_members(c).virtuals
705 local mang_virtuals = {}
707 for n, f in pairs(c_v) do
708 if f.attr.virtual=='1' then
709 local k = self:mangled(f)
710 mang_virtuals[k] = mang_virtuals[k] or f
715 for s in string.gmatch(c.attr.bases or '', '(_%d+) ') do
716 local my_base = self:find_id(s)
717 local my_virtual = self:get_virtuals(my_base)
718 for k, f in pairs(my_virtual) do
719 mang_virtuals[k] = mang_virtuals[k] or f
723 return mang_virtuals
726 function binder:proto_preamble (n, ...)
727 -- FIXME: this is only Qt (the inclusion by name of class)
728 -- FIXED?
729 i = i or n
730 local ret = [[
731 #include "lqt_common.hpp"
733 for n = 1,select('#', ...) do
734 local i = select(n, ...)
735 ret = ret .. '#include <'..i..'>\n'
738 ret = ret .. [[
740 template <> class ]] .. self.wrapclass(n) .. [[ : public ]] .. n .. [[ {
741 private:
742 lua_State *L;
743 public:
745 return ret
748 function binder:proto_ending (n)
749 return [[
755 function binder:copy_constructor(c)
756 local constr = ' '
757 local args = self.arguments_of(c)
758 constr = constr .. self.wrapclass(c.attr.name) .. ' (lua_State *l'
759 for argi = 1, table.maxn(args) do
760 local argt = self:find_id(args[argi].attr.type)
761 local argtype = self:type_name(argt)
762 constr = constr .. ', ' .. argtype .. ' arg'..tostring(argi)
764 constr = constr .. '):'..c.attr.name..'('
765 for argi = 1, table.maxn(args) do
766 constr = constr .. ((argi>1) and ', ' or '') .. 'arg'..tostring(argi)
768 constr = constr .. '), L(l) {}\n'
769 return constr, nil
772 function binder.meta_constr_proto (n) return 'int luaopen_'..n..' (lua_State *L);\n' end
773 function binder.meta_constr_preamble (n)
774 return [[
775 int luaopen_]]..n..[[ (lua_State *L) {
776 if (luaL_newmetatable(L, "]]..n..[[*")) {
779 function binder.meta_constr_method (n, c)
780 c = c or ''
781 return ' lua_pushcfunction(L, '..c..n..');\n lua_setfield(L, -2, "'..n..'");\n'
783 function binder.meta_constr_ending (n)
784 return [[
785 lua_pushcfunction(L, lqtL_newindex);
786 lua_setfield(L, -2, "__newindex");
787 lua_pushcfunction(L, lqtL_index);
788 lua_setfield(L, -2, "__index");
789 lua_pushcfunction(L, lqtL_gc);
790 lua_setfield(L, -2, "__gc");
791 lua_pushstring(L, "]]..n..[[");
792 lua_setfield(L, -2, "__qtype");
793 lua_setglobal(L, "]]..n..[[");
794 } else {
795 lua_pop(L, 1);
797 return 0;
802 function binder:virtual_overload (f, c, id)
803 --if f.attr.access~='public' then error'only public virtual function are exported' end
804 if f.attr.access=='private' then error'private virtual function are not exported' end
806 c = c or ''
807 local args = self.arguments_of(f)
808 local ret_t = f.attr.returns and self:find_id(f.attr.returns)
809 local ret_n = ret_t and self:type_name(ret_t) or 'void'
810 local fh, fb = ' ', ''
811 fh = fh .. ret_n .. ' ' .. f.attr.name .. ' ('
812 fb = fb .. ret_n .. ' ' .. c .. f.attr.name .. ' ('
814 -- GETTING ARGUMENTS
815 for argi = 1, table.maxn(args) do
816 local arg = args[argi]
817 local argname = 'arg' .. tostring(argi)
819 local argt = self:find_id(arg.attr.type)
820 local argtype = self:type_name(argt)
821 local def = arg.attr.default or nil
823 def = def and (self:context_name(argt)..def)
825 --print ('signing arg type', argtype)
827 if argi>1 then fh = fh .. ', ' fb = fb .. ', ' end
828 fh = fh .. argtype .. ' ' .. argname .. (def and (' = '..def) or '')
829 fb = fb .. argtype .. ' ' .. argname
832 fh = fh .. ')' .. (f.attr.const and ' const' or '') .. ';\n'
834 if f.attr.access~='public' then
835 fh = f.attr.access .. ':\n' .. fh .. 'public:\n'
838 fb = fb .. ')' .. (f.attr.const and ' const' or '') .. ' {\n'
839 fb = fb .. ' bool absorbed = false;\n int oldtop = lua_gettop(L);\n'
841 local context = self:context_name(f)
842 local pointer_to_class = self.fake_pointer ( id or f.attr.context )
843 local push_this = self:type_to_stack(pointer_to_class)'this'
844 --fb = fb .. ' ' .. push_this .. ';\n'
845 --fb = fb .. ' lua_getfield(L, -1, "'..(f.attr.name)..'");\n lua_insert(L, -2);\n'
846 ---[=[
847 fb = fb .. ' ' .. push_this .. [[;
848 if (lua_getmetatable(L, -1)) {
849 lua_getfield(L, -1, "]]..(f.attr.name)..[[");
850 lua_remove(L, -2);
851 } else {
852 lua_pushnil(L);
854 lua_insert(L, -2);
856 --]=]
859 for argi = 1, table.maxn(args) do
860 local arg = args[argi]
861 local argname = 'arg' .. tostring(argi)
863 local argt = self:find_id(arg.attr.type)
864 local argtype = self:type_name(argt)
865 local def = arg.attr.default
867 def = def and (self:context_name(argt)..def)
869 local to_stack = self:type_to_stack(argt)(argname)
870 --to_stack = (type(to_stack)=='string') and to_stack or table.concat(to_stack, '\n ')
871 fb = fb .. ' ' .. to_stack .. ';\n'
874 local sig = '(' .. (args[1] and 'arg1' or '')
875 for argi = 2, table.maxn(args) do
876 sig = sig .. ', arg' .. argi
878 sig = sig .. ')'
880 fb = fb .. [[
881 if (lua_isfunction(L, -]]..table.maxn(args)..[[-2)) {
882 lua_pcall(L, ]] .. table.maxn(args) .. [[+1, 2, 0);
883 absorbed = (bool)lua_toboolean(L, -1) || (bool)lua_toboolean(L, -2);
884 lua_pop(L, 1);
886 if (!absorbed) {
887 lua_settop(L, oldtop);
888 ]] .. (f.attr.pure_virtual~='1' and (((ret_n~='void') and 'return ' or '')..'this->'..context..f.attr.name..sig..';\n') or '') .. [[
891 -- fb = fb .. ' if (!lua_isnil)' -- TODO: check?
892 if ret_n~='void' then
893 fb = fb .. ' ' .. ret_n .. ' ret = ' .. self:type_from_stack(ret_t)(-1) .. ';\n'
894 fb = fb .. ' lua_settop(L, oldtop);\n'
895 fb = fb .. ' return ret;\n'
896 else
897 fb = fb .. ' lua_settop(L, oldtop);\n'
899 fb = fb .. '}\n'
901 return fh, fb
904 function binder:virtual_destructor (f, c)
905 c = c or ''
906 local lname = self.wrapclass(f.attr.name)
907 local pclass = self.fake_pointer(f.attr.context)
908 local push_this = self:type_to_stack(pclass)'this'
909 return [[
910 ~]]..lname..[[ ();
911 ]],
912 c .. [[
913 ~]]..lname..[[ () {
914 int oldtop = lua_gettop(L);
915 ]] .. push_this .. [[;
916 lua_getfield(L, -1, "~]]..f.attr.name..[[");
918 if (lua_isfunction(L, -1)) {
919 lua_insert(L, -2);
920 lua_pcall(L, 1, 1, 0);
921 } else {
923 lua_settop(L, oldtop);
929 function binder:make_namespace(tname, include_file, ...)
930 local bind_file = 'lqt_bind_'..include_file..'.hpp'
931 if string.match(include_file, '(%.[hH]([pP]?)%2)$') then
932 bind_file = 'lqt_bind_'..include_file
935 local my_class = self:find_id(tname) or self:find_name(tname)
936 local my_context = self.wrapclass(tname)..'::'
938 local my = self:get_members(my_class)
940 local my_enums = nil
941 my.virtuals = self:get_virtuals(my_class)
943 print 'writing preambles'
945 local fullproto = self:proto_preamble(tname, include_file, ...)
946 local fulldef = '#include "'..bind_file..'"\n\n'
947 local metatable_constructor = self.meta_constr_preamble(tname)
949 print 'binding each member'
951 local my_members = {}
952 table.foreach(my.methods, function(k, v) my_members[k] = v end)
953 my_members.new = my.constructors
954 my_members.delete = { my.destructor }
955 for n, l in pairs(my_members) do
956 local fname = self.WRAPCALL..n
957 local proto, def = self:solve_overload(l, fname, my_context)
958 if (proto and def) then
959 fullproto = fullproto .. proto
960 fulldef = fulldef .. def
961 metatable_constructor = metatable_constructor .. self.meta_constr_method (n, my_context..self.WRAPCALL)
965 print'binding virtual methods'
967 for s, f in pairs(my.virtuals) do
968 print ('virtual', s)
969 local ret, h, c = pcall(self.virtual_overload, self, f, my_context, my_class.attr.id)
970 if ret then
971 fullproto, fulldef = fullproto..h, fulldef..c
972 else
973 print(h)
977 print'overriding virtual destructor'
978 if my.destructor and my.destructor.attr.virtual == '1' then
979 local h, c = self:virtual_destructor(my.destructor, my_context)
980 fullproto, fulldef = fullproto..h, fulldef..c
983 print'creating enum translation tables'
984 for k, e in pairs(my.enumerations) do
985 local e_p, e_d, e_n = self:enum_push_body(e, my_context)
986 fulldef = fulldef .. e_d
987 fullproto = fullproto .. e_p
988 metatable_constructor = metatable_constructor .. ' ' .. my_context .. e_n .. '(L);\n lua_setfield(L, -2, "'..e.attr.name..'");\n'
991 print'copying constructors'
992 for i, v in ipairs(my.constructors) do
993 fullproto = fullproto..self:copy_constructor(v)
995 fullproto = fullproto .. self:proto_ending(tname) .. self.meta_constr_proto (tname)
997 print'specifying bases'
998 metatable_constructor = metatable_constructor .. ' lua_newtable(L);\n'
999 local deep_bases = {}
1000 for s in string.gmatch(my_class.attr.bases or '', '(_%d+) ') do
1001 local base = self:find_id(s)
1002 local bname = self:type_name(base)
1003 metatable_constructor = metatable_constructor .. [[
1004 lua_pushboolean(L, 1);
1005 lua_setfield(L, -2, "]]..bname..[[*");
1007 deep_bases = self.set_union(deep_bases, self:tree_of_bases(base))
1009 for n in pairs(deep_bases) do
1010 metatable_constructor = metatable_constructor .. [[
1011 lua_pushboolean(L, 0);
1012 lua_setfield(L, -2, "]]..n..[[*");
1015 metatable_constructor = metatable_constructor .. ' lua_setfield(L, -2, "__base");\n'
1018 print'finalizing code'
1019 metatable_constructor = metatable_constructor .. self.meta_constr_ending (tname)
1020 fulldef = fulldef .. metatable_constructor
1022 return fullproto, fulldef
1025 function binder.set_union(...)
1026 local ret = {}
1027 for _, s in ipairs{...} do
1028 for v, t in pairs(s) do
1029 if t==true then ret[v] = true end
1032 return ret
1035 function binder:tree_of_bases(c)
1036 local ret = {}
1037 for s in string.gmatch(c.attr.bases or '', '(_%d+) ') do
1038 local b = self:find_id(s)
1039 ret[b.attr.name] = true
1040 local bb = self:tree_of_bases(b)
1041 ret = self.set_union(ret, bb)
1043 return ret
1047 return binder