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
)
16 local xmlf
= io
.open(filename
, 'r')
17 local xmls
= xmlf
:read('*a')
19 --self.tree = lxp.lom.parse(xmls)
21 self
.tree
= xml
:collect(xmls
)
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,
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 = {}
85 function binder
.wrapclass(n
)
86 return 'LuaBinder< '..n
..' >'
89 function binder
.lua_proto(s
)
90 return 'int '..s
..' (lua_State *L)'
93 function binder
.fake_pointer (id
)
94 return { tag='PointerType', attr
={ type=id
} }
97 function binder
:find(f
, t
)
99 if type(t
)~='table' then return nil end;
100 if f(t
) then return t
end
102 for k
,v
in pairs(t
) do
103 ret
= ret
or self
:find(f
, v
)
104 if ret
then break end
109 function binder
.name_search (n
)
111 return (type(t
)=='table') and (type(t
.attr
)=='table') and (t
.attr
.name
==n
)
115 function binder
.id_search (i
)
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
)
123 return (type(t
)=='table') and (t
.tag==n
) -- or ((type(i)==table) and i[t.attr.id])
127 function binder
.pointer_search(id
)
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
))
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
))
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
..'::')
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
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
194 error('cannot determine type name: ' .. self
.debug_type(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 '')
211 function binder
.arguments_of(f
)
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
])
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)
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
)
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)
257 return string.sub(base
, 2)
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
266 error('cannot deternime how to retrieve type: '.. ((type(el
)=='table') and (el
.tag..' '..el
.attr
.id
) or 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 '<>')
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
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
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 '<>')
311 error('cannot deternime how to push on stack type: '.. self
.debug_type(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
)
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 '<>')
347 error('cannot deternime how to test type: '.. self
.debug_type(el
))
353 function binder
:function_body(f
)
354 if f
.attr
.pure_virtual
=='1' then error'cannot call pure vitual functions' end
358 --local base_class = nil
359 local args
= self
.arguments_of(f
)
360 local funcname
= self
:context_name(f
) .. f
.attr
.name
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))
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';
377 lua_pushstring(L, "trying to reference deleted pointer");
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
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'
410 if f
.tag=='Constructor' then
412 local my_class = self:find_id(f.attr.context)
413 if my_class.attr.abstract='1' then error'cannot construct abstract class' end
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'
428 ret_type
= self
:find_id(f
.attr
.returns
)
432 if ret_type
.attr
.name
=='void' then
435 body
= body
.. self
:type_name(ret_type
) .. ' ret = '
440 body
= body
.. '__lua__obj->' .. funcname
.. '('
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'
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'
468 body
= body
.. ' return 0;\n}\n'
474 function binder
:function_test(p
, score
)
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'
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'
501 -- ret = ret .. ' ' .. score .. ' += ' .. type_on_stack_test( find_id(arg.attr.type) , argi+isstatic )
502 -- .. '?' .. tostring(premium) .. ':-' .. tostring(premium) .. '*' .. tostring(premium) .. ';\n'
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, ''
520 filtered
, motive
= self
.filter(m
)
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
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
)
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
564 st
, err
= pcall(self
.function_body
, self
, m
)
572 st
, err
= pcall(self
.function_test
, self
, m
, 'score['..i
..']')
580 --body[i] = self:function_body(m)
581 --test[i] = self:function_test(m, 'score['..i..']')
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
)
595 for (int i=1;i<=]]..m
..[[;i++) {
596 if (score[best] < score[i]) { best = i; }
602 function binder
:solve_overload (f
, n
, c
)
603 local proto
, def
= '', ''
604 local body
, test
= self
:code_function(f
)
607 for i
= 1,table.maxn(f
) do if (type(body
[i
])=='string') and (type(test
[i
])=='string') then number = number + 1 end end
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");
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
649 proto
, def
= nil, nil
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'
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)
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
726 function binder
:proto_preamble (n
, ...)
727 -- FIXME: this is only Qt (the inclusion by name of class)
731 #include "lqt_common.hpp"
733 for n
= 1,select('#', ...) do
734 local i
= select(n
, ...)
735 ret
= ret
.. '#include <'..i
..'>\n'
740 template <> class ]] .. self
.wrapclass(n
) .. [[ : public ]] .. n
.. [[ {
748 function binder
:proto_ending (n
)
755 function binder
:copy_constructor(c
)
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'
772 function binder
.meta_constr_proto (n
) return 'int luaopen_'..n
..' (lua_State *L);\n' end
773 function binder
.meta_constr_preamble (n
)
775 int luaopen_]]..n
..[[ (lua_State *L) {
776 if (luaL_newmetatable(L, "]]..n
..[[*")) {
779 function binder
.meta_constr_method (n
, c
)
781 return ' lua_pushcfunction(L, '..c
..n
..');\n lua_setfield(L, -2, "'..n
..'");\n'
783 function binder
.meta_constr_ending (n
)
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
..[[");
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
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
.. ' ('
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'
847 fb
= fb
.. ' ' .. push_this
.. [[;
848 if (lua_getmetatable(L, -1)) {
849 lua_getfield(L, -1, "]]..(f
.attr
.name
)..[[");
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
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);
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'
897 fb
= fb
.. ' lua_settop(L, oldtop);\n'
904 function binder
:virtual_destructor (f
, c
)
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'
914 int oldtop = lua_gettop(L);
915 ]] .. push_this
.. [[;
916 lua_getfield(L, -1, "~]]..f
.attr
.name
..[[");
918 if (lua_isfunction(L, -1)) {
920 lua_pcall(L, 1, 1, 0);
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
)
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
969 local ret
, h
, c
= pcall(self
.virtual_overload
, self
, f
, my_context
, my_class
.attr
.id
)
971 fullproto
, fulldef
= fullproto
..h
, fulldef
..c
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(...)
1027 for _
, s
in ipairs
{...} do
1028 for v
, t
in pairs(s
) do
1029 if t
==true then ret
[v
] = true end
1035 function binder
:tree_of_bases(c
)
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
)