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