1
-- tolua: function class
2
-- Written by Waldemar Celes
5
-- $Id: tlx_function.lua 13010 2007-06-22 21:18:04Z wsimpson $
7
-- This code is free software; you can redistribute it and/or modify it.
8
-- The software provided hereunder is on an "as is" basis, and
9
-- the author has no obligation to provide maintenance, support, updates,
10
-- enhancements, or modifications.
15
-- Represents a function or a class method.
16
-- The following fields are stored:
17
-- mod = type modifiers
19
-- ptr = "*" or "&", if representing a pointer or a reference
22
-- args = list of argument declarations
23
-- const = if it is a method receiving a const "this".
31
last_overload_error = true,
32
last_overload_rmfun = false
34
classFunction.__index = classFunction
35
setmetatable(classFunction,classFeature)
38
function classFunction:decltype ()
39
self.type = typevar(self.type)
40
if strfind(self.mod,'const') then
41
self.type = 'const '..self.type
42
self.mod = gsub(self.mod,'const','')
46
self.args[i]:decltype()
52
-- Write binding function
53
-- Outputs C/C++ binding function.
54
function classFunction:supcode (local_constructor)
55
local overload = strsub(self.cname,-2,-1) - 1 -- indicate overloaded func
56
local nret = 0 -- number of returned values
57
local class = self:inclass()
58
local _,_,static = strfind(self.mod,'^%s*(static)')
60
if self.name == 'new' and self.parent.flags.pure_virtual then
61
-- no constructor for classes with pure virtual methods
65
if local_constructor then
66
output("/* method: new_local of class ",class," */")
68
output("/* method:",self.name," of class ",class," */")
71
output("/* function:",self.name," */")
74
if local_constructor then
75
output("#ifndef TOLUA_DISABLE_"..self.cname.."_local")
76
output("\nstatic int",self.cname.."_local","(lua_State* tolua_S)")
78
output("#ifndef TOLUA_DISABLE_"..self.cname)
79
output("\nstatic int",self.cname,"(lua_State* tolua_S)")
85
--output('#ifndef TOLUA_RELEASE\n')
87
output(' tolua_Error tolua_err;')
91
if class then narg=2 else narg=1 end
93
local func = 'tolua_isusertype'
94
local type = self.parent.type
95
if self.name=='new' or static~=nil then
96
func = 'tolua_isusertable'
97
type = self.parent.type
99
if self.const ~= '' then
100
type = "const "..type
102
output(' !'..func..'(tolua_S,1,"'..type..'",0,&tolua_err) ||\n')
105
if self.args[1].type ~= 'void' then
107
while self.args[i] do
108
local btype = isbasic(self.args[i].type)
109
if btype ~= 'value' and btype ~= 'state' then
110
output(' !'..self.args[i]:outchecktype(narg)..' ||\n')
112
if btype ~= 'state' then
119
output(' !tolua_isnoobj(tolua_S,'..narg..',&tolua_err)\n )')
120
output(' goto tolua_lerror;')
128
-- declare self, if the case
130
if class then narg=2 else narg=1 end
131
if class and self.name~='new' and static==nil then
132
output(' ',self.const,self.parent.type,'*','self = ')
133
output('(',self.const,self.parent.type,'*) ')
134
output('tolua_tousertype(tolua_S,1,0);')
136
_,_,self.mod = strfind(self.mod,'^%s*static%s%s*(.*)')
138
-- declare parameters
139
if self.args[1].type ~= 'void' then
141
while self.args[i] do
142
self.args[i]:declare(narg)
143
if isbasic(self.args[i].type) ~= "state" then
151
if class and self.name~='new' and static==nil then
152
--output('#ifndef TOLUA_RELEASE\n')
153
output(' if (!self) tolua_error(tolua_S,"invalid \'self\' in function \''..self.name..'\'",NULL);');
157
-- get array element values
158
if class then narg=2 else narg=1 end
159
if self.args[1].type ~= 'void' then
161
while self.args[i] do
162
self.args[i]:getarray(narg)
168
local out = string.find(self.mod, "tolua_outside")
170
if class and self.name=='delete' then
171
output(' delete self;')
172
elseif class and self.name == 'operator&[]' then
173
if flags['1'] then -- for compatibility with tolua5 ?
174
output(' self->operator[](',self.args[1].name,'-1) = ',self.args[2].name,';')
176
output(' self->operator[](',self.args[1].name,') = ',self.args[2].name,';')
180
if self.type ~= '' and self.type ~= 'void' then
181
output(' ',self.mod,self.type,self.ptr,'tolua_ret = ')
182
output('(',self.mod,self.type,self.ptr,') ')
186
if class and self.name=='new' then
187
output('new',self.type,'(')
188
elseif class and static then
190
output(self.name,'(')
192
output(class..'::'..self.name,'(')
196
output(self.name,'(')
198
if self.cast_operator then
199
output('static_cast<',self.mod,self.type,self.ptr,'>(*self')
201
output('self->'..self.name,'(')
205
output(self.name,'(')
208
if out and not static then
210
if self.args[1] and self.args[1].name ~= '' then
216
while self.args[i] do
217
self.args[i]:passpar()
224
if class and self.name == 'operator[]' and flags['1'] then
231
if self.type ~= '' and self.type ~= 'void' then
233
local t,ct = isbasic(self.type)
235
if self.rets.dnil then
236
output(' if(tolua_ret=='..self.rets.def..') ')
237
if self.try_overload_nil and overload >= 0 then
238
output('goto tolua_lerror;')
240
output('tolua_pushnil(tolua_S);')
244
if self.cast_operator and _basic_raw_push[t] then
245
output(' ',_basic_raw_push[t],'(tolua_S,(',ct,')tolua_ret);')
247
output(' tolua_push'..t..'(tolua_S,(',ct,')tolua_ret);')
250
if self.try_overload_nil and overload >= 0 then
251
output(' if(tolua_ret==NULL) goto tolua_lerror;')
254
new_t = string.gsub(t, "const%s+", "")
255
if self.ptr == '' then
257
output('#ifdef __cplusplus\n')
258
output(' void* tolua_obj = new',new_t,'(tolua_ret);')
259
output(' tolua_pushusertype_and_takeownership(tolua_S,tolua_obj,"',t,'");')
261
output(' void* tolua_obj = tolua_copy(tolua_S,(void*)&tolua_ret,sizeof(',t,'));')
262
output(' tolua_pushusertype_and_takeownership(tolua_S,tolua_obj,"',t,'");')
265
elseif self.ptr == '&' then
266
output(' tolua_pushusertype(tolua_S,(void*)&tolua_ret,"',t,'");')
268
if local_constructor then
269
output(' tolua_pushusertype_and_takeownership(tolua_S,(void *)tolua_ret,"',t,'");')
271
output(' tolua_pushusertype(tolua_S,(void*)tolua_ret,"',t,'");')
277
while self.args[i] do
278
if self.args.n==2 then
279
if self.try_overload_nil and overload >= 0 then
280
self.args[i].try_overload_nil=true
283
nret = nret + self.args[i]:retvalue()
288
-- set array element values
289
if class then narg=2 else narg=1 end
290
if self.args[1].type ~= 'void' then
292
while self.args[i] do
293
self.args[i]:setarray(narg)
299
-- free dynamically allocated array
300
if self.args[1].type ~= 'void' then
302
while self.args[i] do
303
self.args[i]:freearray()
310
output(' return '..nret..';')
312
-- call overloaded function or generate error
314
if self.last_overload_error then
315
--output('#ifndef TOLUA_RELEASE\n')
316
output('tolua_lerror:\n')
317
output(' tolua_error(tolua_S,"#ferror in function \''..self.lname..'\'.",&tolua_err);')
321
--output('#ifndef TOLUA_RELEASE\n')
322
output('tolua_lerror:\n')
323
--if self.last_overload_rmfun then
324
-- output(' lua_remove(tolua_S,2);\n')
325
-- output(' return '..tostring(narg-1)..';')
327
output(' return '..tostring(narg-1)..';\n')
333
if local_constructor then
336
output('tolua_lerror:\n')
337
output(' return '..strsub(self.cname,1,-3)..format("%02d",overload).._local..'(tolua_S);')
340
output('#endif //#ifndef TOLUA_DISABLE\n')
343
-- recursive call to write local constructor
344
if class and self.name=='new' and not local_constructor then
352
function classFunction:register (pre)
353
if not self:check_public_access() then return end
355
if self.name == 'new' and self.parent.flags.pure_virtual then
356
-- no constructor for classes with pure virtual methods
360
output(pre..'tolua_function(tolua_S,"'..self.lname..'",'..self.cname..');')
361
if self.name == 'new' then
362
output(pre..'tolua_function(tolua_S,"new_local",'..self.cname..'_local);')
363
output(pre..'tolua_function(tolua_S,".call",'..self.cname..'_local);')
364
--output(' tolua_set_call_event(tolua_S,'..self.cname..'_local, "'..self.parent.type..'");')
369
function classFunction:print (ident,close)
370
print(ident.."Function{")
371
print(ident.." mod = '"..self.mod.."',")
372
print(ident.." type = '"..self.type.."',")
373
print(ident.." ptr = '"..self.ptr.."',")
374
print(ident.." name = '"..self.name.."',")
375
print(ident.." lname = '"..self.lname.."',")
376
print(ident.." const = '"..self.const.."',")
377
print(ident.." cname = '"..self.cname.."',")
378
print(ident.." lname = '"..self.lname.."',")
379
print(ident.." args = {")
381
while self.args[i] do
382
self.args[i]:print(ident.." ",",")
386
print(ident.." rets=")
387
self.rets:print(ident.." ",",")
388
print(ident.."}"..close)
391
-- check if it returns an object by value
392
function classFunction:requirecollection (t)
394
if self.type ~= '' and not isbasic(self.type) and self.ptr=='' then
395
local type = gsub(self.type,"%s*const%s+","")
396
t[type] = "tolua_collect_" .. clean_template(type)
400
while self.args[i] do
401
r = self.args[i]:requirecollection(t) or r
407
-- determine lua function name overload
408
function classFunction:overload ()
409
return self.parent:overload(self.lname)
413
function param_object(par) -- returns true if the parameter has an object as its default value
414
if not string.find(par, '=') then return false end -- it has no default value
415
local _,_,def = string.find(par, "=(.*)$")
416
if string.find(par, "|") then -- a list of flags
419
if string.find(par, "%*") then -- it's a pointer with a default value
420
if string.find(par, '=%s*new') then -- it's a pointer with an instance as default parameter.. is that valid?
423
return false -- default value is 'NULL' or something
426
if string.find(par, "[%(&]") then
428
end -- default value is a constructor call (most likely for a const reference)
429
--if string.find(par, "&") then
430
-- if string.find(def, ":") or string.find(def, "^%s*new%s+") then
431
-- -- it's a reference with default to something like Class::member, or 'new Class'
439
function strip_last_arg(all_args, last_arg) -- strips the default value from the last argument
440
local _,_,s_arg = string.find(last_arg, "^([^=]+)")
441
last_arg = string.gsub(last_arg, "([%%%(%)])", "%%%1");
442
all_args = string.gsub(all_args, "%s*,%s*"..last_arg.."%s*%)%s*$", ")")
443
return all_args, s_arg
448
-- Internal constructor
449
function _Function (t)
450
setmetatable(t,classFunction)
452
if t.const ~= 'const' and t.const ~= '' then
453
error("#invalid 'const' specification")
458
--print ('t.name is '..t.name..', parent.name is '..t.parent.name)
459
if string.gsub(t.name, "%b<>", "") == string.gsub(t.parent.original_name or t.parent.name, "%b<>", "") then
463
t.type = t.parent.name
465
elseif string.gsub(t.name, "%b<>", "") == '~'..string.gsub(t.parent.original_name or t.parent.name, "%b<>", "") then
468
t.parent._delete = true
471
t.cname = t:cfuncname("tolua")..t:overload(t)
476
-- Expects three strings: one representing the function declaration,
477
-- another representing the argument list, and the third representing
478
-- the "const" or empty string.
479
function Function (d,a,c,r)
480
--local t = split(strsub(a,2,-2),',') -- eliminate braces
481
--local t = split_params(strsub(a,2,-2))
482
if not flags['W'] and string.find(a, "%.%.%.%s*%)") then
483
warning("Functions with variable arguments (`...') are not supported. Ignoring "..d..a..c)
491
a = string.gsub(a, "%s*([%(%)])%s*", "%1")
492
local t,strip,last = strip_pars(strsub(a,2,-2));
494
--local ns = string.sub(strsub(a,1,-2), 1, -(string.len(last)+1))
495
local ns = join(t, ",", 1, last-1)
497
ns = "("..string.gsub(ns, "%s*,%s*$", "")..')'
498
--ns = strip_defaults(ns)
502
t[i] = string.gsub(t[i], "=.*$", "")
508
l[l.n] = Declaration(t[i],'var',true)
511
local f = Declaration(d,'func')
514
f.rets = Declaration(f.type..r,'var',true)
518
function join(t, sep, first, last)
520
last = last or table.getn(t)
524
for i = first,last do
525
ret = ret..lsep..t[i]
535
function strip_pars(s)
536
local t = split_c_tokens(s, ',')
542
if not strip and param_object(t[i]) then
547
-- t[i] = string.gsub(t[i], "=.*$", "")
554
function strip_defaults(s)
555
s = string.gsub(s, "^%(", "")
556
s = string.gsub(s, "%)$", "")
558
local t = split_c_tokens(s, ",")
559
local sep, ret = "",""
561
t[i] = string.gsub(t[i], "=.*$", "")