1 | -- tolua: function class |
---|
2 | -- Written by Waldemar Celes |
---|
3 | -- TeCGraf/PUC-Rio |
---|
4 | -- Jul 1998 |
---|
5 | -- $Id: function.lua 1597 2008-03-11 22:25:01Z ice-drezday $ |
---|
6 | |
---|
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. |
---|
11 | |
---|
12 | |
---|
13 | -- CEGUILua mod |
---|
14 | -- exception handling |
---|
15 | -- patch from Tov |
---|
16 | -- modded by Lindquist |
---|
17 | exceptionDefs = exceptionDefs or {} |
---|
18 | exceptionDefs["std::exception"] = {} |
---|
19 | exceptionDefs["std::exception"]["var"] = "&e" |
---|
20 | exceptionDefs["std::exception"]["c_str"] = "e.what()" |
---|
21 | |
---|
22 | exceptionDefs["any"] = {} |
---|
23 | exceptionDefs["any"]["var"] = "" |
---|
24 | exceptionDefs["any"]["c_str"] = '"Unknown"' |
---|
25 | |
---|
26 | exceptionMessageBufferSize = 512 |
---|
27 | |
---|
28 | function outputExceptionError(f,e,errBuf) |
---|
29 | -- if the exception is not "..." then use the "c_str" info the get a real exception message |
---|
30 | local messageC_str = true |
---|
31 | if e.name == "any" then |
---|
32 | messageC_str = false |
---|
33 | end |
---|
34 | |
---|
35 | -- make a default e.ret if empty |
---|
36 | if not e.ret or e.ret == "" then |
---|
37 | e.ret = "nil,message" |
---|
38 | end |
---|
39 | |
---|
40 | -- create a default exceptionDef if we dont have one |
---|
41 | if not exceptionDefs[e.name] then |
---|
42 | exceptionDefs[e.name] = {} |
---|
43 | exceptionDefs[e.name].var = "&e" |
---|
44 | exceptionDefs[e.name].c_str = '"Unknown"' |
---|
45 | end |
---|
46 | |
---|
47 | -- print catch header |
---|
48 | local nameToEcho = e.name |
---|
49 | if nameToEcho == "any" then |
---|
50 | nameToEcho = "..." |
---|
51 | end |
---|
52 | if e.ret == "nil" then |
---|
53 | output("catch(",nameToEcho," CEGUIDeadException(",exceptionDefs[e.name].var,"))\n{\n") |
---|
54 | else |
---|
55 | output("catch(",nameToEcho,exceptionDefs[e.name].var,")\n{\n") |
---|
56 | end |
---|
57 | |
---|
58 | -- if just a nil |
---|
59 | if e.ret == "nil" then |
---|
60 | output("return 0;\n") |
---|
61 | -- if error should be raised |
---|
62 | elseif string.find(e.ret,"error") then |
---|
63 | if messageC_str then |
---|
64 | output("snprintf(errorBuffer,"..exceptionMessageBufferSize..",\"Exception of type '"..e.name.."' was thrown by function '"..f.."'\\nMessage: %s\","..exceptionDefs[e.name].c_str..");\n") |
---|
65 | else |
---|
66 | output("snprintf(errorBuffer,"..exceptionMessageBufferSize..",\"Unknown exception thrown by function '"..f.."'\");\n") |
---|
67 | end |
---|
68 | output("errorDoIt = true;\n") |
---|
69 | -- else go through the returns |
---|
70 | else |
---|
71 | -- buffer for message |
---|
72 | if string.find(e.ret,"message") and messageC_str and errBuf == false then |
---|
73 | output("char errorBuffer["..exceptionMessageBufferSize.."];\n") |
---|
74 | end |
---|
75 | local numrets = 0 |
---|
76 | local retpat = "(%w+),?" |
---|
77 | local i,j,retval = string.find(e.ret,retpat) |
---|
78 | while i do |
---|
79 | local code = "" |
---|
80 | |
---|
81 | -- NIL |
---|
82 | if retval == "nil" then |
---|
83 | code = "tolua_pushnil(tolua_S);\n" |
---|
84 | |
---|
85 | -- MESSAGE |
---|
86 | elseif retval == "message" then |
---|
87 | if messageC_str then |
---|
88 | code = "snprintf(errorBuffer,"..exceptionMessageBufferSize..",\"Exception of type '"..e.name.."' was thrown by function '"..f.."'\\nMessage: %s\","..exceptionDefs[e.name].c_str..");\ntolua_pushstring(tolua_S,errorBuffer);\n" |
---|
89 | else |
---|
90 | code = "tolua_pushstring(tolua_S,\"Unknown exception thrown by function '"..f.."'\");\n" |
---|
91 | end |
---|
92 | |
---|
93 | -- TRUE |
---|
94 | elseif retval == "true" then |
---|
95 | code = "tolua_pushboolean(tolua_S, 1);\n" |
---|
96 | |
---|
97 | -- FALSE |
---|
98 | elseif retval == "false" then |
---|
99 | code = "tolua_pushboolean(tolua_S, 0);\n" |
---|
100 | end |
---|
101 | |
---|
102 | -- print code for this return value |
---|
103 | if code ~= "" then |
---|
104 | output(code) |
---|
105 | numrets = numrets + 1 |
---|
106 | end |
---|
107 | |
---|
108 | -- next return value |
---|
109 | i,j,retval = string.find(e.ret,retpat,j+1) |
---|
110 | end |
---|
111 | output("return ",numrets,";\n") |
---|
112 | end |
---|
113 | |
---|
114 | -- print catch footer |
---|
115 | output("}\n") |
---|
116 | end |
---|
117 | |
---|
118 | function outputExceptionCatchBlocks(func,throws,err) |
---|
119 | for i=1,table.getn(throws) do |
---|
120 | outputExceptionError(func, throws[i], err) |
---|
121 | end |
---|
122 | |
---|
123 | -- if an error should be raised, we do it here |
---|
124 | if err then |
---|
125 | output("if (errorDoIt) {\n") |
---|
126 | output("luaL_error(tolua_S,errorBuffer);\n") |
---|
127 | output("}\n") |
---|
128 | end |
---|
129 | end |
---|
130 | |
---|
131 | |
---|
132 | -- Function class |
---|
133 | -- Represents a function or a class method. |
---|
134 | -- The following fields are stored: |
---|
135 | -- mod = type modifiers |
---|
136 | -- type = type |
---|
137 | -- ptr = "*" or "&", if representing a pointer or a reference |
---|
138 | -- name = name |
---|
139 | -- lname = lua name |
---|
140 | -- args = list of argument declarations |
---|
141 | -- const = if it is a method receiving a const "this". |
---|
142 | classFunction = { |
---|
143 | mod = '', |
---|
144 | type = '', |
---|
145 | ptr = '', |
---|
146 | name = '', |
---|
147 | args = {n=0}, |
---|
148 | const = '', |
---|
149 | } |
---|
150 | classFunction.__index = classFunction |
---|
151 | setmetatable(classFunction,classFeature) |
---|
152 | |
---|
153 | -- declare tags |
---|
154 | function classFunction:decltype () |
---|
155 | self.type = typevar(self.type) |
---|
156 | if strfind(self.mod,'const') then |
---|
157 | self.type = 'const '..self.type |
---|
158 | self.mod = gsub(self.mod,'const','') |
---|
159 | end |
---|
160 | local i=1 |
---|
161 | while self.args[i] do |
---|
162 | self.args[i]:decltype() |
---|
163 | i = i+1 |
---|
164 | end |
---|
165 | end |
---|
166 | |
---|
167 | |
---|
168 | -- Write binding function |
---|
169 | -- Outputs C/C++ binding function. |
---|
170 | function classFunction:supcode (local_constructor) |
---|
171 | |
---|
172 | local overload = strsub(self.cname,-2,-1) - 1 -- indicate overloaded func |
---|
173 | local nret = 0 -- number of returned values |
---|
174 | local class = self:inclass() |
---|
175 | local _,_,static = strfind(self.mod,'^%s*(static)') |
---|
176 | if class then |
---|
177 | |
---|
178 | if self.name == 'new' and self.parent.flags.pure_virtual then |
---|
179 | -- no constructor for classes with pure virtual methods |
---|
180 | return |
---|
181 | end |
---|
182 | |
---|
183 | if local_constructor then |
---|
184 | output("/* method: new_local of class ",class," */") |
---|
185 | else |
---|
186 | output("/* method:",self.name," of class ",class," */") |
---|
187 | end |
---|
188 | else |
---|
189 | output("/* function:",self.name," */") |
---|
190 | end |
---|
191 | |
---|
192 | if local_constructor then |
---|
193 | output("#ifndef TOLUA_DISABLE_"..self.cname.."_local") |
---|
194 | output("\nstatic int",self.cname.."_local","(lua_State* tolua_S)") |
---|
195 | else |
---|
196 | output("#ifndef TOLUA_DISABLE_"..self.cname) |
---|
197 | output("\nstatic int",self.cname,"(lua_State* tolua_S)") |
---|
198 | end |
---|
199 | output("{") |
---|
200 | |
---|
201 | -- check types |
---|
202 | if overload < 0 then |
---|
203 | output('#ifndef TOLUA_RELEASE\n') |
---|
204 | end |
---|
205 | output(' tolua_Error tolua_err;') |
---|
206 | output(' if (\n') |
---|
207 | -- check self |
---|
208 | local narg |
---|
209 | if class then narg=2 else narg=1 end |
---|
210 | if class then |
---|
211 | local func = get_is_function(self.parent.type) |
---|
212 | local type = self.parent.type |
---|
213 | if self.name=='new' or static~=nil then |
---|
214 | func = 'tolua_isusertable' |
---|
215 | type = self.parent.type |
---|
216 | end |
---|
217 | if self.const ~= '' then |
---|
218 | type = "const "..type |
---|
219 | end |
---|
220 | output(' !'..func..'(tolua_S,1,"'..type..'",0,&tolua_err) ||\n') |
---|
221 | end |
---|
222 | -- check args |
---|
223 | if self.args[1].type ~= 'void' then |
---|
224 | local i=1 |
---|
225 | while self.args[i] do |
---|
226 | local btype = isbasic(self.args[i].type) |
---|
227 | if btype ~= 'value' and btype ~= 'state' then |
---|
228 | output(' '..self.args[i]:outchecktype(narg)..' ||\n') |
---|
229 | end |
---|
230 | if btype ~= 'state' then |
---|
231 | narg = narg+1 |
---|
232 | end |
---|
233 | i = i+1 |
---|
234 | end |
---|
235 | end |
---|
236 | -- check end of list |
---|
237 | output(' !tolua_isnoobj(tolua_S,'..narg..',&tolua_err)\n )') |
---|
238 | output(' goto tolua_lerror;') |
---|
239 | |
---|
240 | output(' else\n') |
---|
241 | if overload < 0 then |
---|
242 | output('#endif\n') |
---|
243 | end |
---|
244 | output(' {') |
---|
245 | |
---|
246 | -- declare self, if the case |
---|
247 | local narg |
---|
248 | if class then narg=2 else narg=1 end |
---|
249 | if class and self.name~='new' and static==nil then |
---|
250 | output(' ',self.const,self.parent.type,'*','self = ') |
---|
251 | output('(',self.const,self.parent.type,'*) ') |
---|
252 | local to_func = get_to_function(self.parent.type) |
---|
253 | output(to_func,'(tolua_S,1,0);') |
---|
254 | elseif static then |
---|
255 | _,_,self.mod = strfind(self.mod,'^%s*static%s%s*(.*)') |
---|
256 | end |
---|
257 | -- declare parameters |
---|
258 | if self.args[1].type ~= 'void' then |
---|
259 | local i=1 |
---|
260 | while self.args[i] do |
---|
261 | self.args[i]:declare(narg) |
---|
262 | if isbasic(self.args[i].type) ~= "state" then |
---|
263 | narg = narg+1 |
---|
264 | end |
---|
265 | i = i+1 |
---|
266 | end |
---|
267 | end |
---|
268 | |
---|
269 | -- check self |
---|
270 | if class and self.name~='new' and static==nil then |
---|
271 | output('#ifndef TOLUA_RELEASE\n') |
---|
272 | output(' if (!self) tolua_error(tolua_S,"'..output_error_hook("invalid \'self\' in function \'%s\'", self.name)..'", NULL);'); |
---|
273 | output('#endif\n') |
---|
274 | end |
---|
275 | |
---|
276 | -- get array element values |
---|
277 | if class then narg=2 else narg=1 end |
---|
278 | if self.args[1].type ~= 'void' then |
---|
279 | local i=1 |
---|
280 | while self.args[i] do |
---|
281 | self.args[i]:getarray(narg) |
---|
282 | narg = narg+1 |
---|
283 | i = i+1 |
---|
284 | end |
---|
285 | end |
---|
286 | |
---|
287 | -------------------------------------------------- |
---|
288 | -- CEGUILua mod |
---|
289 | -- init exception handling |
---|
290 | local throws = false |
---|
291 | do |
---|
292 | local pattern = "tolua_throws|.*|" |
---|
293 | local i,j = string.find(self.mod, pattern) |
---|
294 | if i then |
---|
295 | throws = {} |
---|
296 | -- ensure table is empty. Used to be: table.setn(throws,0) |
---|
297 | for x in pairs(throws) do |
---|
298 | throws[x] = nil |
---|
299 | end |
---|
300 | local excepts = string.sub(self.mod, i+12,j) |
---|
301 | local epattern = "|.-|" |
---|
302 | local i,j = string.find(excepts, epattern) |
---|
303 | while i do |
---|
304 | local e = string.sub(excepts,i+1,j-1) |
---|
305 | local _,_,name,rest = string.find(e, "([%w:_]+),?(.*)") |
---|
306 | table.insert(throws,{name=name, ret=rest}) |
---|
307 | i,j = string.find(excepts, epattern, j) |
---|
308 | end |
---|
309 | self.mod = string.gsub(self.mod, pattern, "") |
---|
310 | end |
---|
311 | end |
---|
312 | local exRaiseError = false |
---|
313 | -------------------------------------------------- |
---|
314 | |
---|
315 | pre_call_hook(self) |
---|
316 | |
---|
317 | local out = string.find(self.mod, "tolua_outside") |
---|
318 | |
---|
319 | --------------- |
---|
320 | -- CEGUILua mod |
---|
321 | -- remove "tolua_outside" from self.mod |
---|
322 | if out then |
---|
323 | self.mod = string.gsub(self.mod, "tolua_outside", "") |
---|
324 | end |
---|
325 | |
---|
326 | -- call function |
---|
327 | if class and self.name=='delete' then |
---|
328 | output(' Mtolua_delete(self);') |
---|
329 | elseif class and self.name == 'operator&[]' then |
---|
330 | if flags['1'] then -- for compatibility with tolua5 ? |
---|
331 | output(' self->operator[](',self.args[1].name,'-1) = ',self.args[2].name,';') |
---|
332 | else |
---|
333 | output(' self->operator[](',self.args[1].name,') = ',self.args[2].name,';') |
---|
334 | end |
---|
335 | else |
---|
336 | -- CEGUILua mod begin- throws |
---|
337 | if throws then |
---|
338 | for i=1,table.getn(throws) do |
---|
339 | if string.find(throws[i].ret, "error") then |
---|
340 | output("char errorBuffer["..exceptionMessageBufferSize.."];\n") |
---|
341 | output("bool errorDoIt = false;\n") |
---|
342 | exRaiseError = true |
---|
343 | break |
---|
344 | end |
---|
345 | end |
---|
346 | output("try\n") |
---|
347 | end |
---|
348 | -- CEGUILua mod end - throws |
---|
349 | output(' {') |
---|
350 | if self.type ~= '' and self.type ~= 'void' then |
---|
351 | output(' ',self.mod,self.type,self.ptr,'tolua_ret = ') |
---|
352 | output('(',self.mod,self.type,self.ptr,') ') |
---|
353 | else |
---|
354 | output(' ') |
---|
355 | end |
---|
356 | if class and self.name=='new' then |
---|
357 | output('Mtolua_new((',self.type,')(') |
---|
358 | elseif class and static then |
---|
359 | if out then |
---|
360 | output(self.name,'(') |
---|
361 | else |
---|
362 | output(class..'::'..self.name,'(') |
---|
363 | end |
---|
364 | elseif class then |
---|
365 | if out then |
---|
366 | output(self.name,'(') |
---|
367 | else |
---|
368 | if self.cast_operator then |
---|
369 | --output('static_cast<',self.mod,self.type,self.ptr,' >(*self') |
---|
370 | output('self->operator ',self.mod,self.type,'(') |
---|
371 | else |
---|
372 | output('self->'..self.name,'(') |
---|
373 | end |
---|
374 | end |
---|
375 | else |
---|
376 | output(self.name,'(') |
---|
377 | end |
---|
378 | |
---|
379 | if out and not static then |
---|
380 | output('self') |
---|
381 | if self.args[1] and self.args[1].name ~= '' then |
---|
382 | output(',') |
---|
383 | end |
---|
384 | end |
---|
385 | -- write parameters |
---|
386 | local i=1 |
---|
387 | while self.args[i] do |
---|
388 | self.args[i]:passpar() |
---|
389 | i = i+1 |
---|
390 | if self.args[i] then |
---|
391 | output(',') |
---|
392 | end |
---|
393 | end |
---|
394 | |
---|
395 | if class and self.name == 'operator[]' and flags['1'] then |
---|
396 | output('-1);') |
---|
397 | else |
---|
398 | if class and self.name=='new' then |
---|
399 | output('));') -- close Mtolua_new( |
---|
400 | else |
---|
401 | output(');') |
---|
402 | end |
---|
403 | end |
---|
404 | |
---|
405 | -- return values |
---|
406 | if self.type ~= '' and self.type ~= 'void' then |
---|
407 | nret = nret + 1 |
---|
408 | local t,ct = isbasic(self.type) |
---|
409 | if t and self.name ~= "new" then |
---|
410 | if self.cast_operator and _basic_raw_push[t] then |
---|
411 | output(' ',_basic_raw_push[t],'(tolua_S,(',ct,')tolua_ret);') |
---|
412 | else |
---|
413 | output(' tolua_push'..t..'(tolua_S,(',ct,')tolua_ret);') |
---|
414 | end |
---|
415 | else |
---|
416 | t = self.type |
---|
417 | new_t = string.gsub(t, "const%s+", "") |
---|
418 | local owned = false |
---|
419 | if string.find(self.mod, "tolua_owned") then |
---|
420 | owned = true |
---|
421 | end |
---|
422 | local push_func = get_push_function(t) |
---|
423 | if self.ptr == '' then |
---|
424 | output(' {') |
---|
425 | output('#ifdef __cplusplus\n') |
---|
426 | output(' void* tolua_obj = Mtolua_new((',new_t,')(tolua_ret));') |
---|
427 | output(' ',push_func,'(tolua_S,tolua_obj,"',t,'");') |
---|
428 | output(' tolua_register_gc(tolua_S,lua_gettop(tolua_S));') |
---|
429 | output('#else\n') |
---|
430 | output(' void* tolua_obj = tolua_copy(tolua_S,(void*)&tolua_ret,sizeof(',t,'));') |
---|
431 | output(' ',push_func,'(tolua_S,tolua_obj,"',t,'");') |
---|
432 | output(' tolua_register_gc(tolua_S,lua_gettop(tolua_S));') |
---|
433 | output('#endif\n') |
---|
434 | output(' }') |
---|
435 | elseif self.ptr == '&' then |
---|
436 | output(' ',push_func,'(tolua_S,(void*)&tolua_ret,"',t,'");') |
---|
437 | else |
---|
438 | output(' ',push_func,'(tolua_S,(void*)tolua_ret,"',t,'");') |
---|
439 | if owned or local_constructor then |
---|
440 | output(' tolua_register_gc(tolua_S,lua_gettop(tolua_S));') |
---|
441 | end |
---|
442 | end |
---|
443 | end |
---|
444 | end |
---|
445 | local i=1 |
---|
446 | while self.args[i] do |
---|
447 | nret = nret + self.args[i]:retvalue() |
---|
448 | i = i+1 |
---|
449 | end |
---|
450 | output(' }') |
---|
451 | |
---|
452 | ------------------------------------------ |
---|
453 | -- CEGUILua mod |
---|
454 | -- finish exception handling |
---|
455 | -- catch |
---|
456 | if throws then |
---|
457 | outputExceptionCatchBlocks(self.name, throws, exRaiseError) |
---|
458 | end |
---|
459 | ------------------------------------------ |
---|
460 | |
---|
461 | -- set array element values |
---|
462 | if class then narg=2 else narg=1 end |
---|
463 | if self.args[1].type ~= 'void' then |
---|
464 | local i=1 |
---|
465 | while self.args[i] do |
---|
466 | self.args[i]:setarray(narg) |
---|
467 | narg = narg+1 |
---|
468 | i = i+1 |
---|
469 | end |
---|
470 | end |
---|
471 | |
---|
472 | -- free dynamically allocated array |
---|
473 | if self.args[1].type ~= 'void' then |
---|
474 | local i=1 |
---|
475 | while self.args[i] do |
---|
476 | self.args[i]:freearray() |
---|
477 | i = i+1 |
---|
478 | end |
---|
479 | end |
---|
480 | end |
---|
481 | |
---|
482 | post_call_hook(self) |
---|
483 | |
---|
484 | output(' }') |
---|
485 | output(' return '..nret..';') |
---|
486 | |
---|
487 | -- call overloaded function or generate error |
---|
488 | if overload < 0 then |
---|
489 | |
---|
490 | output('#ifndef TOLUA_RELEASE\n') |
---|
491 | output('tolua_lerror:\n') |
---|
492 | output(' tolua_error(tolua_S,"'..output_error_hook("#ferror in function \'%s\'.", self.lname)..'",&tolua_err);') |
---|
493 | output(' return 0;') |
---|
494 | output('#endif\n') |
---|
495 | else |
---|
496 | local _local = "" |
---|
497 | if local_constructor then |
---|
498 | _local = "_local" |
---|
499 | end |
---|
500 | output('tolua_lerror:\n') |
---|
501 | output(' return '..strsub(self.cname,1,-3)..format("%02d",overload).._local..'(tolua_S);') |
---|
502 | end |
---|
503 | output('}') |
---|
504 | output('#endif //#ifndef TOLUA_DISABLE\n') |
---|
505 | output('\n') |
---|
506 | |
---|
507 | -- recursive call to write local constructor |
---|
508 | if class and self.name=='new' and not local_constructor then |
---|
509 | |
---|
510 | self:supcode(1) |
---|
511 | end |
---|
512 | |
---|
513 | end |
---|
514 | |
---|
515 | |
---|
516 | -- register function |
---|
517 | function classFunction:register (pre) |
---|
518 | |
---|
519 | if not self:check_public_access() then |
---|
520 | return |
---|
521 | end |
---|
522 | |
---|
523 | if self.name == 'new' and self.parent.flags.pure_virtual then |
---|
524 | -- no constructor for classes with pure virtual methods |
---|
525 | return |
---|
526 | end |
---|
527 | |
---|
528 | output(pre..'tolua_function(tolua_S,"'..self.lname..'",'..self.cname..');') |
---|
529 | if self.name == 'new' then |
---|
530 | output(pre..'tolua_function(tolua_S,"new_local",'..self.cname..'_local);') |
---|
531 | output(pre..'tolua_function(tolua_S,".call",'..self.cname..'_local);') |
---|
532 | --output(' tolua_set_call_event(tolua_S,'..self.cname..'_local, "'..self.parent.type..'");') |
---|
533 | end |
---|
534 | end |
---|
535 | |
---|
536 | -- Print method |
---|
537 | function classFunction:print (ident,close) |
---|
538 | print(ident.."Function{") |
---|
539 | print(ident.." mod = '"..self.mod.."',") |
---|
540 | print(ident.." type = '"..self.type.."',") |
---|
541 | print(ident.." ptr = '"..self.ptr.."',") |
---|
542 | print(ident.." name = '"..self.name.."',") |
---|
543 | print(ident.." lname = '"..self.lname.."',") |
---|
544 | print(ident.." const = '"..self.const.."',") |
---|
545 | print(ident.." cname = '"..self.cname.."',") |
---|
546 | print(ident.." lname = '"..self.lname.."',") |
---|
547 | print(ident.." args = {") |
---|
548 | local i=1 |
---|
549 | while self.args[i] do |
---|
550 | self.args[i]:print(ident.." ",",") |
---|
551 | i = i+1 |
---|
552 | end |
---|
553 | print(ident.." }") |
---|
554 | print(ident.."}"..close) |
---|
555 | end |
---|
556 | |
---|
557 | -- check if it returns an object by value |
---|
558 | function classFunction:requirecollection (t) |
---|
559 | local r = false |
---|
560 | if self.type ~= '' and not isbasic(self.type) and self.ptr=='' then |
---|
561 | local type = gsub(self.type,"%s*const%s+","") |
---|
562 | t[type] = "tolua_collect_" .. clean_template(type) |
---|
563 | r = true |
---|
564 | end |
---|
565 | local i=1 |
---|
566 | while self.args[i] do |
---|
567 | r = self.args[i]:requirecollection(t) or r |
---|
568 | i = i+1 |
---|
569 | end |
---|
570 | return r |
---|
571 | end |
---|
572 | |
---|
573 | -- determine lua function name overload |
---|
574 | function classFunction:overload () |
---|
575 | return self.parent:overload(self.lname) |
---|
576 | end |
---|
577 | |
---|
578 | |
---|
579 | function param_object(par) -- returns true if the parameter has an object as its default value |
---|
580 | |
---|
581 | if not string.find(par, '=') then return false end -- it has no default value |
---|
582 | |
---|
583 | local _,_,def = string.find(par, "=(.*)$") |
---|
584 | |
---|
585 | if string.find(par, "|") then -- a list of flags |
---|
586 | |
---|
587 | return true |
---|
588 | end |
---|
589 | |
---|
590 | if string.find(par, "%*") then -- it's a pointer with a default value |
---|
591 | |
---|
592 | if string.find(par, '=%s*new') or string.find(par, "%(") then -- it's a pointer with an instance as default parameter.. is that valid? |
---|
593 | return true |
---|
594 | end |
---|
595 | return false -- default value is 'NULL' or something |
---|
596 | end |
---|
597 | |
---|
598 | |
---|
599 | if string.find(par, "[%(&]") then |
---|
600 | return true |
---|
601 | end -- default value is a constructor call (most likely for a const reference) |
---|
602 | |
---|
603 | --if string.find(par, "&") then |
---|
604 | |
---|
605 | -- if string.find(def, ":") or string.find(def, "^%s*new%s+") then |
---|
606 | |
---|
607 | -- -- it's a reference with default to something like Class::member, or 'new Class' |
---|
608 | -- return true |
---|
609 | -- end |
---|
610 | --end |
---|
611 | |
---|
612 | return false -- ? |
---|
613 | end |
---|
614 | |
---|
615 | function strip_last_arg(all_args, last_arg) -- strips the default value from the last argument |
---|
616 | |
---|
617 | local _,_,s_arg = string.find(last_arg, "^([^=]+)") |
---|
618 | last_arg = string.gsub(last_arg, "([%%%(%)])", "%%%1"); |
---|
619 | all_args = string.gsub(all_args, "%s*,%s*"..last_arg.."%s*%)%s*$", ")") |
---|
620 | return all_args, s_arg |
---|
621 | end |
---|
622 | |
---|
623 | |
---|
624 | |
---|
625 | -- Internal constructor |
---|
626 | function _Function (t) |
---|
627 | setmetatable(t,classFunction) |
---|
628 | |
---|
629 | if t.const ~= 'const' and t.const ~= '' then |
---|
630 | error("#invalid 'const' specification") |
---|
631 | end |
---|
632 | |
---|
633 | append(t) |
---|
634 | if t:inclass() then |
---|
635 | --print ('t.name is '..t.name..', parent.name is '..t.parent.name) |
---|
636 | if string.gsub(t.name, "%b<>", "") == string.gsub(t.parent.original_name or t.parent.name, "%b<>", "") then |
---|
637 | t.name = 'new' |
---|
638 | t.lname = 'new' |
---|
639 | t.parent._new = true |
---|
640 | t.type = t.parent.name |
---|
641 | t.ptr = '*' |
---|
642 | elseif string.gsub(t.name, "%b<>", "") == '~'..string.gsub(t.parent.original_name or t.parent.name, "%b<>", "") then |
---|
643 | t.name = 'delete' |
---|
644 | t.lname = 'delete' |
---|
645 | t.parent._delete = true |
---|
646 | end |
---|
647 | end |
---|
648 | t.cname = t:cfuncname("tolua")..t:overload(t) |
---|
649 | return t |
---|
650 | end |
---|
651 | |
---|
652 | -- Constructor |
---|
653 | -- Expects three strings: one representing the function declaration, |
---|
654 | -- another representing the argument list, and the third representing |
---|
655 | -- the "const" or empty string. |
---|
656 | function Function (d,a,c) |
---|
657 | --local t = split(strsub(a,2,-2),',') -- eliminate braces |
---|
658 | --local t = split_params(strsub(a,2,-2)) |
---|
659 | |
---|
660 | if not flags['W'] and string.find(a, "%.%.%.%s*%)") then |
---|
661 | |
---|
662 | warning("Functions with variable arguments (`...') are not supported. Ignoring "..d..a..c) |
---|
663 | return nil |
---|
664 | end |
---|
665 | |
---|
666 | |
---|
667 | local i=1 |
---|
668 | local l = {n=0} |
---|
669 | |
---|
670 | a = string.gsub(a, "%s*([%(%)])%s*", "%1") |
---|
671 | local t,strip,last = strip_pars(strsub(a,2,-2)); |
---|
672 | if strip then |
---|
673 | --local ns = string.sub(strsub(a,1,-2), 1, -(string.len(last)+1)) |
---|
674 | local ns = join(t, ",", 1, last-1) |
---|
675 | |
---|
676 | ns = "("..string.gsub(ns, "%s*,%s*$", "")..')' |
---|
677 | --ns = strip_defaults(ns) |
---|
678 | |
---|
679 | local f = Function(d, ns, c) |
---|
680 | for i=1,last do |
---|
681 | t[i] = string.gsub(t[i], "=.*$", "") |
---|
682 | end |
---|
683 | end |
---|
684 | |
---|
685 | while t[i] do |
---|
686 | l.n = l.n+1 |
---|
687 | l[l.n] = Declaration(t[i],'var',true) |
---|
688 | i = i+1 |
---|
689 | end |
---|
690 | local f = Declaration(d,'func') |
---|
691 | f.args = l |
---|
692 | f.const = c |
---|
693 | return _Function(f) |
---|
694 | end |
---|
695 | |
---|
696 | function join(t, sep, first, last) |
---|
697 | |
---|
698 | first = first or 1 |
---|
699 | last = last or table.getn(t) |
---|
700 | local lsep = "" |
---|
701 | local ret = "" |
---|
702 | local loop = false |
---|
703 | for i = first,last do |
---|
704 | |
---|
705 | ret = ret..lsep..t[i] |
---|
706 | lsep = sep |
---|
707 | loop = true |
---|
708 | end |
---|
709 | if not loop then |
---|
710 | return "" |
---|
711 | end |
---|
712 | |
---|
713 | return ret |
---|
714 | end |
---|
715 | |
---|
716 | function strip_pars(s) |
---|
717 | |
---|
718 | local t = split_c_tokens(s, ',') |
---|
719 | local strip = false |
---|
720 | local last |
---|
721 | |
---|
722 | for i=t.n,1,-1 do |
---|
723 | |
---|
724 | if not strip and param_object(t[i]) then |
---|
725 | last = i |
---|
726 | strip = true |
---|
727 | end |
---|
728 | --if strip then |
---|
729 | -- t[i] = string.gsub(t[i], "=.*$", "") |
---|
730 | --end |
---|
731 | end |
---|
732 | |
---|
733 | return t,strip,last |
---|
734 | |
---|
735 | end |
---|
736 | |
---|
737 | function strip_defaults(s) |
---|
738 | |
---|
739 | s = string.gsub(s, "^%(", "") |
---|
740 | s = string.gsub(s, "%)$", "") |
---|
741 | |
---|
742 | local t = split_c_tokens(s, ",") |
---|
743 | local sep, ret = "","" |
---|
744 | for i=1,t.n do |
---|
745 | t[i] = string.gsub(t[i], "=.*$", "") |
---|
746 | ret = ret..sep..t[i] |
---|
747 | sep = "," |
---|
748 | end |
---|
749 | |
---|
750 | return "("..ret..")" |
---|
751 | end |
---|
752 | |
---|
753 | |
---|