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
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.
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
)
43 local xmlf
= io
.open(filename
, 'r')
44 local xmls
= xmlf
:read('*a')
46 --self.tree = lxp.lom.parse(xmls)
48 self
.tree
= xml
:collect(xmls
)
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,
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 = {}
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
)
133 if type(t
)~='table' then return nil end;
134 if f(t
) then return t
end
136 for k
,v
in pairs(t
) do
137 ret
= ret
or self
:find(f
, v
)
138 if ret
then break end
143 function binder
.name_search (n
)
145 return (type(t
)=='table') and (type(t
.attr
)=='table') and (t
.attr
.name
==n
)
149 function binder
.id_search (i
)
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
)
157 return (type(t
)=='table') and (t
.tag==n
) -- or ((type(i)==table) and i[t.attr.id])
161 function binder
.pointer_search(id
)
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
))
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
))
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
..'::')
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
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
228 error('cannot determine type name: ' .. self
.debug_type(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 '')
245 function binder
.arguments_of(f
)
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
])
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)
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
)
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)
291 return string.sub(base
, 2)
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
300 error('cannot deternime how to retrieve type: '.. ((type(el
)=='table') and (el
.tag..' '..el
.attr
.id
) or 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 '<>')
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
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
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 '<>')
345 error('cannot deternime how to push on stack type: '.. self
.debug_type(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
)
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 '<>')
381 error('cannot deternime how to test type: '.. self
.debug_type(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'
396 --local base_class = nil
397 local args
= self
.arguments_of(f
)
398 local funcname
= self
:context_name(f
) .. f
.attr
.name
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))
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';
415 lua_pushstring(L, "trying to reference deleted pointer");
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
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'
448 if f
.tag=='Constructor' then
450 local my_class = self:find_id(f.attr.context)
451 if my_class.attr.abstract='1' then error'cannot construct abstract class' end
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'
466 ret_type
= self
:find_id(f
.attr
.returns
)
470 if ret_type
.attr
.name
=='void' then
473 body
= body
.. self
:type_name(ret_type
) .. ' ret = '
478 body
= body
.. '__lua__obj->' .. funcname
.. '('
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'
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'
506 body
= body
.. ' return 0;\n}\n'
512 function binder
:function_test(p
, score
)
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'
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'
539 -- ret = ret .. ' ' .. score .. ' += ' .. type_on_stack_test( find_id(arg.attr.type) , argi+isstatic )
540 -- .. '?' .. tostring(premium) .. ':-' .. tostring(premium) .. '*' .. tostring(premium) .. ';\n'
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, ''
558 filtered
, motive
= self
.filter(m
)
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
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
)
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
602 st
, err
= pcall(self
.function_body
, self
, m
)
610 st
, err
= pcall(self
.function_test
, self
, m
, 'score['..i
..']')
618 --body[i] = self:function_body(m)
619 --test[i] = self:function_test(m, 'score['..i..']')
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
)
633 for (int i=1;i<=]]..m
..[[;i++) {
634 if (score[best] < score[i]) { best = i; }
640 function binder
:solve_overload (f
, n
, c
)
641 local proto
, def
= '', ''
642 local body
, test
= self
:code_function(f
)
645 for i
= 1,table.maxn(f
) do if (type(body
[i
])=='string') and (type(test
[i
])=='string') then number = number + 1 end end
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");
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
687 proto
, def
= nil, nil
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'
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)
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
764 function binder
:proto_preamble (n
, ...)
765 -- FIXME: this is only Qt (the inclusion by name of class)
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
779 template <> class ]] .. self
.wrapclass(n
) .. [[ : public ]] .. n
.. [[ {
787 function binder
:proto_ending (n
)
794 function binder
:copy_constructor(c
)
795 if c
.tag=='Constructor' and c
.attr
.artificial
=='1' then
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'
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
)
817 int luaopen_]]..n
..[[ (lua_State *L) {
818 if (luaL_newmetatable(L, "]]..n
..[[*")) {
821 function binder
.meta_constr_method (n
, c
)
823 return ' lua_pushcfunction(L, '..c
..n
..');\n lua_setfield(L, -2, "'..n
..'");\n'
825 function binder
.meta_constr_ending (n
)
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
..[[");
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
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
.. ' ('
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'
889 fb
= fb
.. ' ' .. push_this
.. [[;
890 if (lua_getmetatable(L, -1)) {
891 lua_getfield(L, -1, "]]..(f
.attr
.name
)..[[");
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
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);
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'
939 fb
= fb
.. ' lua_settop(L, oldtop);\n'
946 function binder
:virtual_destructor (f
, c
)
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'
956 int oldtop = lua_gettop(L);
957 ]] .. push_this
.. [[;
958 lua_getfield(L, -1, "~]]..f
.attr
.name
..[[");
960 if (lua_isfunction(L, -1)) {
962 lua_pcall(L, 1, 1, 0);
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
)
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
)
1014 fullproto
, fulldef
= fullproto
..h
, fulldef
..c
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(...)
1070 for _
, s
in ipairs
{...} do
1071 for v
, t
in pairs(s
) do
1072 if t
==true then ret
[v
] = true end
1078 function binder
:tree_of_bases(c
)
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
)