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
460 -- print('pushing', binder:type_name(ret_type))
461 local ret_to_stack
= self
:type_to_stack(ret_type
)'ret'
462 body
= body
.. ' ' .. ret_to_stack
.. ';\n'
463 body
= body
.. ' return 1;\n}\n'
465 body
= body
.. ' return 0;\n}\n'
471 function binder
:function_test(p
, score
)
475 ret
= ret
.. ' ' .. score
.. ' = 0;\n'
477 if p
.attr
.static
~='1' and p
.tag=='Method' then
478 ret
= ret
.. ' ' .. score
.. ' += ' .. self
:type_test( self
.fake_pointer(p
.attr
.context
) )(1)
479 .. '?premium:-premium*premium;\n'
483 local args
= self
.arguments_of(p
)
485 for argi
= 1, table.maxn(args
) do
486 local arg
= args
[argi
]
487 --print ( 'ARGUMENT TEST', argi)
488 local argname
= 'arg' .. tostring(argi
)
489 if (type(arg
)=='table') and (arg
.tag=='Argument') then
490 ret
= ret
.. ' if (' .. self
:type_test( self
:find_id(arg
.attr
.type) )(argi
+isstatic
) .. ') {\n'
491 ret
= ret
.. ' ' .. score
.. ' += premium;\n'
492 ret
= ret
.. ' } else if (' .. tostring(arg
.attr
.default
and true or false) .. ') {\n'
493 ret
= ret
.. ' ' .. score
.. ' += premium-1; // '..tostring(arg
, arg
.attr
.default
)..';\n'
494 ret
= ret
.. ' } else {\n'
495 ret
= ret
.. ' ' .. score
.. ' -= premium*premium;\n'
498 -- ret = ret .. ' ' .. score .. ' += ' .. type_on_stack_test( find_id(arg.attr.type) , argi+isstatic )
499 -- .. '?' .. tostring(premium) .. ':-' .. tostring(premium) .. '*' .. tostring(premium) .. ';\n'
506 function binder
:get_members (c
)
507 if not self
.members
then self
.members
= {} end
508 if not self
.members
[c
] then
509 local ret
= { functions
={}, enumerations
={}, classes
={}, methods
={}, constructors
={}, virtuals
={} }
510 for s
in string.gmatch(c
.attr
.members
, '(_%d+) ') do
511 local m
= self
:find_id(s
)
512 local n
= m
.attr
.name
513 print("member of", c
.attr
.name
, "found:", s
, "name:", n
)
515 local filtered
, motive
= false, ''
517 filtered
, motive
= self
.filter(m
)
521 print('Filtered member: '..n
..' for '..(motive
or 'no apparent reason.'))
522 elseif m
.tag=='Enumeration' then
523 table.insert(ret
.enumerations
, m
)
524 elseif m
.tag=='Function' then
525 ret
.functions
[n
] = ret
.functions
[n
] or {}
526 table.insert(ret
.functions
[n
], m
)
527 elseif m
.tag=='Method' and (m
.attr
.access
=='public') then
528 ret
.methods
[n
] = ret
.methods
[n
] or {}
529 table.insert(ret
.methods
[n
], m
)
530 elseif m
.tag=='Constructor' and (m
.attr
.access
=='public') then
531 table.insert(ret
.constructors
, m
)
532 elseif m
.tag=='Destructor' then
534 elseif m
.tag=='Class' or m
.tag=='Struct' then
535 table.insert(ret
.classes
, m
)
538 if (m
.attr
.virtual
=='1') and (m
.tag~='Constructor') and (m
.tag~='Destructor') and not filtered
then
539 table.insert(ret
.virtuals
, m
)
542 local n = n..' < < of type > > '.. m.tag ..' < < with access > > ' .. m.attr.access
543 ret.cache[n] = ret.cache[n] or {}
544 table.insert(ret.cache[n], m)
547 self
.members
[c
] = ret
549 return self
.members
[c
]
552 function binder
:code_function (f
)
553 local body
, test
= {}, {}
555 for i
, m
in ipairs(f
) do
556 local fname
= self
.wrapcall(m
, overloaded
, j
)
558 if not fname
then error'this shout *NOT* happen!' end
561 st
, err
= pcall(self
.function_body
, self
, m
)
569 st
, err
= pcall(self
.function_test
, self
, m
, 'score['..i
..']')
577 --body[i] = self:function_body(m)
578 --test[i] = self:function_test(m, 'score['..i..']')
584 function binder
:begin_dispatch(n
, m
)
585 return self
.lua_proto(n
) .. ' {\n int score[' .. (m
+1)
586 ..'];\n const int premium = 11+lua_gettop(L);\n'
589 function binder
:choose_dispatch(m
)
592 for (int i=1;i<=]]..m
..[[;i++) {
593 if (score[best] < score[i]) { best = i; }
599 function binder
:solve_overload (f
, n
, c
)
600 local proto
, def
= '', ''
601 local body
, test
= self
:code_function(f
)
604 for i
= 1,table.maxn(f
) do if (type(body
[i
])=='string') and (type(test
[i
])=='string') then number = number + 1 end end
607 local fulltest
= self
:begin_dispatch(c
..n
, table.maxn(f
))
609 for i
= 1,table.maxn(f
) do
610 local fullname
= n
..'__OverloadedVersion__'..i
611 if (type(body
[i
])=='string') and (type(test
[i
])=='string') then
612 proto
= proto
.. ' static '..self
.lua_proto(fullname
)..';\n'
613 def
= def
.. self
.lua_proto(c
..fullname
)..' '..body
[i
]
614 fulltest
= fulltest
.. test
[i
]
618 fulltest
= fulltest
.. self
:choose_dispatch(table.maxn(f
))
620 for i
= 1,table.maxn(f
) do
621 if (type(body
[i
])=='string') and (type(test
[i
])=='string') then
622 local fullname
= n
..'__OverloadedVersion__'..i
623 fulltest
= fulltest
.. ' case ' .. i
.. ': return ' .. fullname
..'(L); break;\n'
627 -- TODO: move to a function?
628 -- TODO: trigger an error
629 fulltest
= fulltest
.. ' }\n return 0;\n}\n'
631 proto
= proto
.. ' static '..self
.lua_proto(n
)..';\n'
632 def
= def
.. fulltest
633 elseif number==1 then
634 proto
, def
= nil, nil
635 for i
, v
in ipairs(body
) do
636 proto
= ' static '..self
.lua_proto(n
)..';\n'
637 def
= self
.lua_proto(c
..n
)..' '..v
640 proto
, def
= nil, nil
646 function binder
:enum_push_body(id
, c
)
647 local enum
= (type(id
)=='string') and self
:find_id(id
) or id
648 local e_static
= (self
:find_id(enum
.attr
.context
).tag == 'Class') and 'static ' or ''
649 local e_context
= self
:context_name(enum
)
650 local e_name
= 'lqt_pushenum_' .. enum
.attr
.name
651 local e_proto
, e_def
= '', ''
653 e_proto
= e_proto
.. ' ' .. e_static
.. self
.lua_proto(e_name
) .. ';\n'
654 e_def
= e_def
.. self
.lua_proto(c
.. e_name
) .. ' '
655 e_def
= e_def
.. '{\n'
656 e_def
= e_def
.. ' int enum_table = 0;\n'
657 e_def
= e_def
.. ' lua_getfield(L, LUA_REGISTRYINDEX, LQT_ENUMS);\n'
658 e_def
= e_def
.. ' if (!lua_istable(L, -1)) {\n'
659 e_def
= e_def
.. ' lua_pop(L, 1);\n'
660 e_def
= e_def
.. ' lua_newtable(L);\n'
661 e_def
= e_def
.. ' lua_pushvalue(L, -1);\n'
662 e_def
= e_def
.. ' lua_setfield(L, LUA_REGISTRYINDEX, LQT_ENUMS);\n'
663 e_def
= e_def
.. ' }\n'
665 e_def
= e_def
.. ' lua_newtable(L);\n'
666 e_def
= e_def
.. ' enum_table = lua_gettop(L);\n'
667 for i
, e
in ipairs(enum
) do
668 if (type(e
)=='table') and (e
.tag=='EnumValue') then
669 e_def
= e_def
.. ' lua_pushstring(L, "' .. e
.attr
.name
.. '");\n'
670 e_def
= e_def
.. ' lua_rawseti(L, enum_table, ' .. e
.attr
.init
.. ');\n'
671 e_def
= e_def
.. ' lua_pushinteger(L, ' .. e
.attr
.init
.. ');\n'
672 e_def
= e_def
.. ' lua_setfield(L, enum_table, "' .. e
.attr
.name
.. '");\n'
675 e_def
= e_def
.. ' lua_pushvalue(L, -1);\n'
676 e_def
= e_def
.. ' lua_setfield(L, -3, "' .. e_context
.. enum
.attr
.name
.. '");\n'
677 e_def
= e_def
.. ' lua_remove(L, -2);\n'
678 e_def
= e_def
.. ' return 1;\n'
679 e_def
= e_def
.. '}\n'
681 return e_proto
, e_def
, e_name
684 function binder
:mangled (f
)
685 local args
= self
:arguments_of(f
)
686 local k
= f
.attr
.name
..'('
687 for i
= 1, table.maxn(args
) do
688 k
= k
..', '..self
:type_name(args
.attr
.type)
694 function binder
:get_virtuals (c
)
695 local c_v
= self
:get_members(c
).virtuals
696 local mang_virtuals
= {}
698 for n
, f
in pairs(c_v
) do
699 if f
.attr
.virtual
=='1' then
700 local k
= self
:mangled(f
)
701 mang_virtuals
[k
] = mang_virtuals
[k
] or f
706 for s
in string.gmatch(c
.attr
.bases
or '', '(_%d+) ') do
707 local my_base
= self
:find_id(s
)
708 local my_virtual
= self
:get_virtuals(my_base
)
709 for k
, f
in pairs(my_virtual
) do
710 mang_virtuals
[k
] = mang_virtuals
[k
] or f
717 function binder
:proto_preamble (n
, ...)
718 -- FIXME: this is only Qt (the inclusion by name of class)
722 #include "lqt_common.hpp"
724 for n
= 1,select('#', ...) do
725 local i
= select(n
, ...)
726 ret
= ret
.. '#include <'..i
..'>\n'
731 template <> class ]] .. self
.wrapclass(n
) .. [[ : public ]] .. n
.. [[ {
739 function binder
:proto_ending (n
)
746 function binder
:copy_constructor(c
)
748 local args
= self
.arguments_of(c
)
749 constr
= constr
.. self
.wrapclass(c
.attr
.name
) .. ' (lua_State *l'
750 for argi
= 1, table.maxn(args
) do
751 local argt
= self
:find_id(args
[argi
].attr
.type)
752 local argtype
= self
:type_name(argt
)
753 constr
= constr
.. ', ' .. argtype
.. ' arg'..tostring(argi
)
755 constr
= constr
.. '):'..c
.attr
.name
..'('
756 for argi
= 1, table.maxn(args
) do
757 constr
= constr
.. ((argi
>1) and ', ' or '') .. 'arg'..tostring(argi
)
759 constr
= constr
.. '), L(l) {}\n'
763 function binder
.meta_constr_proto (n
) return 'int luaopen_'..n
..' (lua_State *L);\n' end
764 function binder
.meta_constr_preamble (n
)
766 int luaopen_]]..n
..[[ (lua_State *L) {
767 if (luaL_newmetatable(L, "]]..n
..[[*")) {
770 function binder
.meta_constr_method (n
, c
)
772 return ' lua_pushcfunction(L, '..c
..n
..');\n lua_setfield(L, -2, "'..n
..'");\n'
774 function binder
.meta_constr_ending (n
)
776 lua_pushcfunction(L, lqtL_newindex);
777 lua_setfield(L, -2, "__newindex");
778 lua_pushcfunction(L, lqtL_index);
779 lua_setfield(L, -2, "__index");
780 lua_pushcfunction(L, lqtL_gc);
781 lua_setfield(L, -2, "__gc");
782 lua_pushstring(L, "]]..n
..[[");
783 lua_setfield(L, -2, "__qtype");
784 lua_setglobal(L, "]]..n
..[[");
793 function binder
:virtual_overload (f
, c
, id
)
794 --if f.attr.access~='public' then error'only public virtual function are exported' end
795 if f
.attr
.access
=='private' then error'private virtual function are not exported' end
798 local args
= self
.arguments_of(f
)
799 local ret_t
= f
.attr
.returns
and self
:find_id(f
.attr
.returns
)
800 local ret_n
= ret_t
and self
:type_name(ret_t
) or 'void'
801 local fh
, fb
= ' ', ''
802 fh
= fh
.. ret_n
.. ' ' .. f
.attr
.name
.. ' ('
803 fb
= fb
.. ret_n
.. ' ' .. c
.. f
.attr
.name
.. ' ('
806 for argi
= 1, table.maxn(args
) do
807 local arg
= args
[argi
]
808 local argname
= 'arg' .. tostring(argi
)
810 local argt
= self
:find_id(arg
.attr
.type)
811 local argtype
= self
:type_name(argt
)
812 local def
= arg
.attr
.default
or nil
814 def
= def
and (self
:context_name(argt
)..def
)
816 --print ('signing arg type', argtype)
818 if argi
>1 then fh
= fh
.. ', ' fb
= fb
.. ', ' end
819 fh
= fh
.. argtype
.. ' ' .. argname
.. (def
and (' = '..def
) or '')
820 fb
= fb
.. argtype
.. ' ' .. argname
823 fh
= fh
.. ')' .. (f
.attr
.const
and ' const' or '') .. ';\n'
825 if f
.attr
.access
~='public' then
826 fh
= f
.attr
.access
.. ':\n' .. fh
.. 'public:\n'
829 fb
= fb
.. ')' .. (f
.attr
.const
and ' const' or '') .. ' {\n'
830 fb
= fb
.. ' bool absorbed = false;\n int oldtop = lua_gettop(L);\n'
832 local context
= self
:context_name(f
)
833 local pointer_to_class
= self
.fake_pointer ( id
or f
.attr
.context
)
834 local push_this
= self
:type_to_stack(pointer_to_class
)'this'
835 --fb = fb .. ' ' .. push_this .. ';\n'
836 --fb = fb .. ' lua_getfield(L, -1, "'..(f.attr.name)..'");\n lua_insert(L, -2);\n'
838 fb
= fb
.. ' ' .. push_this
.. [[;
839 if (lua_getmetatable(L, -1)) {
840 lua_getfield(L, -1, "]]..(f
.attr
.name
)..[[");
850 for argi
= 1, table.maxn(args
) do
851 local arg
= args
[argi
]
852 local argname
= 'arg' .. tostring(argi
)
854 local argt
= self
:find_id(arg
.attr
.type)
855 local argtype
= self
:type_name(argt
)
856 local def
= arg
.attr
.default
858 def
= def
and (self
:context_name(argt
)..def
)
860 local to_stack
= self
:type_to_stack(argt
)(argname
)
861 --to_stack = (type(to_stack)=='string') and to_stack or table.concat(to_stack, '\n ')
862 fb
= fb
.. ' ' .. to_stack
.. ';\n'
865 local sig
= '(' .. (args
[1] and 'arg1' or '')
866 for argi
= 2, table.maxn(args
) do
867 sig
= sig
.. ', arg' .. argi
872 if (lua_isfunction(L, -]]..table.maxn(args
)..[[-2)) {
873 lua_pcall(L, ]] .. table.maxn(args
) .. [[+1, 2, 0);
874 absorbed = (bool)lua_toboolean(L, -1) || (bool)lua_toboolean(L, -2);
878 lua_settop(L, oldtop);
879 ]] .. (f
.attr
.pure_virtual
~='1' and (((ret_n
~='void') and 'return ' or '')..'this->'..context
..f
.attr
.name
..sig
..';\n') or '') .. [[
882 -- fb = fb .. ' if (!lua_isnil)' -- TODO: check?
883 if ret_n
~='void' then
884 fb
= fb
.. ' ' .. ret_n
.. ' ret = ' .. self
:type_from_stack(ret_t
)(-1) .. ';\n'
885 fb
= fb
.. ' lua_settop(L, oldtop);\n'
886 fb
= fb
.. ' return ret;\n'
888 fb
= fb
.. ' lua_settop(L, oldtop);\n'
895 function binder
:virtual_destructor (f
, c
)
897 local lname
= self
.wrapclass(f
.attr
.name
)
898 local pclass
= self
.fake_pointer(f
.attr
.context
)
899 local push_this
= self
:type_to_stack(pclass
)'this'
905 int oldtop = lua_gettop(L);
906 ]] .. push_this
.. [[;
907 lua_getfield(L, -1, "~]]..f
.attr
.name
..[[");
909 if (lua_isfunction(L, -1)) {
911 lua_pcall(L, 1, 1, 0);
914 lua_settop(L, oldtop);
920 function binder
:make_namespace(tname
, include_file
, ...)
921 local bind_file
= 'lqt_bind_'..include_file
..'.hpp'
922 if string.match(include_file
, '(%.[hH]([pP]?)%2)$') then
923 bind_file
= 'lqt_bind_'..include_file
926 local my_class
= self
:find_id(tname
) or self
:find_name(tname
)
927 local my_context
= self
.wrapclass(tname
)..'::'
929 local my
= self
:get_members(my_class
)
932 my
.virtuals
= self
:get_virtuals(my_class
)
934 print 'writing preambles'
936 local fullproto
= self
:proto_preamble(tname
, include_file
, ...)
937 local fulldef
= '#include "'..bind_file
..'"\n\n'
938 local metatable_constructor
= self
.meta_constr_preamble(tname
)
940 print 'binding each member'
942 local my_members
= {}
943 table.foreach(my
.methods
, function(k
, v
) my_members
[k
] = v
end)
944 my_members
.new
= my
.constructors
945 my_members
.delete
= { my
.destructor
}
946 for n
, l
in pairs(my_members
) do
947 local fname
= self
.WRAPCALL
..n
948 local proto
, def
= self
:solve_overload(l
, fname
, my_context
)
949 if (proto
and def
) then
950 fullproto
= fullproto
.. proto
951 fulldef
= fulldef
.. def
952 metatable_constructor
= metatable_constructor
.. self
.meta_constr_method (n
, my_context
..self
.WRAPCALL
)
956 print'binding virtual methods'
958 for s
, f
in pairs(my
.virtuals
) do
960 local ret
, h
, c
= pcall(self
.virtual_overload
, self
, f
, my_context
, my_class
.attr
.id
)
962 fullproto
, fulldef
= fullproto
..h
, fulldef
..c
968 print'overriding virtual destructor'
969 if my
.destructor
and my
.destructor
.attr
.virtual
== '1' then
970 local h
, c
= self
:virtual_destructor(my
.destructor
, my_context
)
971 fullproto
, fulldef
= fullproto
..h
, fulldef
..c
974 print'creating enum translation tables'
975 for k
, e
in pairs(my
.enumerations
) do
976 local e_p
, e_d
, e_n
= self
:enum_push_body(e
, my_context
)
977 fulldef
= fulldef
.. e_d
978 fullproto
= fullproto
.. e_p
979 metatable_constructor
= metatable_constructor
.. ' ' .. my_context
.. e_n
.. '(L);\n lua_setfield(L, -2, "'..e
.attr
.name
..'");\n'
982 print'copying constructors'
983 for i
, v
in ipairs(my
.constructors
) do
984 fullproto
= fullproto
..self
:copy_constructor(v
)
986 fullproto
= fullproto
.. self
:proto_ending(tname
) .. self
.meta_constr_proto (tname
)
988 print'specifying bases'
989 metatable_constructor
= metatable_constructor
.. ' lua_newtable(L);\n'
990 local deep_bases
= {}
991 for s
in string.gmatch(my_class
.attr
.bases
or '', '(_%d+) ') do
992 local base
= self
:find_id(s
)
993 local bname
= self
:type_name(base
)
994 metatable_constructor
= metatable_constructor
.. [[
995 lua_pushboolean(L, 1);
996 lua_setfield(L, -2, "]]..bname
..[[*");
998 deep_bases
= self
.set_union(deep_bases
, self
:tree_of_bases(base
))
1000 for n
in pairs(deep_bases
) do
1001 metatable_constructor
= metatable_constructor
.. [[
1002 lua_pushboolean(L, 0);
1003 lua_setfield(L, -2, "]]..n
..[[*");
1006 metatable_constructor
= metatable_constructor
.. ' lua_setfield(L, -2, "__base");\n'
1009 print'finalizing code'
1010 metatable_constructor
= metatable_constructor
.. self
.meta_constr_ending (tname
)
1011 fulldef
= fulldef
.. metatable_constructor
1013 return fullproto
, fulldef
1016 function binder
.set_union(...)
1018 for _
, s
in ipairs
{...} do
1019 for v
, t
in pairs(s
) do
1020 if t
==true then ret
[v
] = true end
1026 function binder
:tree_of_bases(c
)
1028 for s
in string.gmatch(c
.attr
.bases
or '', '(_%d+) ') do
1029 local b
= self
:find_id(s
)
1030 ret
[b
.attr
.name
] = true
1031 local bb
= self
:tree_of_bases(b
)
1032 ret
= self
.set_union(ret
, bb
)