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 = 'tolua_isusertype' |
---|
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 | output('tolua_tousertype(tolua_S,1,0);') |
---|
253 | elseif static then |
---|
254 | _,_,self.mod = strfind(self.mod,'^%s*static%s%s*(.*)') |
---|
255 | end |
---|
256 | -- declare parameters |
---|
257 | if self.args[1].type ~= 'void' then |
---|
258 | local i=1 |
---|
259 | while self.args[i] do |
---|
260 | self.args[i]:declare(narg) |
---|
261 | if isbasic(self.args[i].type) ~= "state" then |
---|
262 | narg = narg+1 |
---|
263 | end |
---|
264 | i = i+1 |
---|
265 | end |
---|
266 | end |
---|
267 | |
---|
268 | -- check self |
---|
269 | if class and self.name~='new' and static==nil then |
---|
270 | output('#ifndef TOLUA_RELEASE\n') |
---|
271 | output(' if (!self) tolua_error(tolua_S,"invalid \'self\' in function \''..self.name..'\'",NULL);'); |
---|
272 | output('#endif\n') |
---|
273 | end |
---|
274 | |
---|
275 | -- get array element values |
---|
276 | if class then narg=2 else narg=1 end |
---|
277 | if self.args[1].type ~= 'void' then |
---|
278 | local i=1 |
---|
279 | while self.args[i] do |
---|
280 | self.args[i]:getarray(narg) |
---|
281 | narg = narg+1 |
---|
282 | i = i+1 |
---|
283 | end |
---|
284 | end |
---|
285 | |
---|
286 | -------------------------------------------------- |
---|
287 | -- CEGUILua mod |
---|
288 | -- init exception handling |
---|
289 | local throws = false |
---|
290 | do |
---|
291 | local pattern = "tolua_throws|.*|" |
---|
292 | local i,j = string.find(self.mod, pattern) |
---|
293 | if i then |
---|
294 | throws = {} |
---|
295 | -- ensure table is empty. Used to be: table.setn(throws,0) |
---|
296 | for x in pairs(throws) do |
---|
297 | throws[x] = nil |
---|
298 | end |
---|
299 | local excepts = string.sub(self.mod, i+12,j) |
---|
300 | local epattern = "|.-|" |
---|
301 | local i,j = string.find(excepts, epattern) |
---|
302 | while i do |
---|
303 | local e = string.sub(excepts,i+1,j-1) |
---|
304 | local _,_,name,rest = string.find(e, "([%w:_]+),?(.*)") |
---|
305 | table.insert(throws,{name=name, ret=rest}) |
---|
306 | i,j = string.find(excepts, epattern, j) |
---|
307 | end |
---|
308 | self.mod = string.gsub(self.mod, pattern, "") |
---|
309 | end |
---|
310 | end |
---|
311 | local exRaiseError = false |
---|
312 | -------------------------------------------------- |
---|
313 | |
---|
314 | local out = string.find(self.mod, "tolua_outside") |
---|
315 | |
---|
316 | --------------- |
---|
317 | -- CEGUILua mod |
---|
318 | -- remove "tolua_outside" from self.mod |
---|
319 | if out then |
---|
320 | self.mod = string.gsub(self.mod, "tolua_outside", "") |
---|
321 | end |
---|
322 | |
---|
323 | -- call function |
---|
324 | if class and self.name=='delete' then |
---|
325 | output(' delete self;') |
---|
326 | elseif class and self.name == 'operator&[]' then |
---|
327 | if flags['1'] then -- for compatibility with tolua5 ? |
---|
328 | output(' self->operator[](',self.args[1].name,'-1) = ',self.args[2].name,';') |
---|
329 | else |
---|
330 | output(' self->operator[](',self.args[1].name,') = ',self.args[2].name,';') |
---|
331 | end |
---|
332 | else |
---|
333 | -- CEGUILua mod begin- throws |
---|
334 | if throws then |
---|
335 | for i=1,table.getn(throws) do |
---|
336 | if string.find(throws[i].ret, "error") then |
---|
337 | output("char errorBuffer["..exceptionMessageBufferSize.."];\n") |
---|
338 | output("bool errorDoIt = false;\n") |
---|
339 | exRaiseError = true |
---|
340 | break |
---|
341 | end |
---|
342 | end |
---|
343 | output("try\n") |
---|
344 | end |
---|
345 | -- CEGUILua mod end - throws |
---|
346 | output(' {') |
---|
347 | if self.type ~= '' and self.type ~= 'void' then |
---|
348 | output(' ',self.mod,self.type,self.ptr,'tolua_ret = ') |
---|
349 | output('(',self.mod,self.type,self.ptr,') ') |
---|
350 | else |
---|
351 | output(' ') |
---|
352 | end |
---|
353 | if class and self.name=='new' then |
---|
354 | output('new',self.type,'(') |
---|
355 | elseif class and static then |
---|
356 | if out then |
---|
357 | output(self.name,'(') |
---|
358 | else |
---|
359 | output(class..'::'..self.name,'(') |
---|
360 | end |
---|
361 | elseif class then |
---|
362 | if out then |
---|
363 | output(self.name,'(') |
---|
364 | else |
---|
365 | if self.cast_operator then |
---|
366 | output('static_cast<',self.mod,self.type,self.ptr,'>(*self') |
---|
367 | else |
---|
368 | output('self->'..self.name,'(') |
---|
369 | end |
---|
370 | end |
---|
371 | else |
---|
372 | output(self.name,'(') |
---|
373 | end |
---|
374 | |
---|
375 | if out and not static then |
---|
376 | output('self') |
---|
377 | if self.args[1] and self.args[1].name ~= '' then |
---|
378 | output(',') |
---|
379 | end |
---|
380 | end |
---|
381 | -- write parameters |
---|
382 | local i=1 |
---|
383 | while self.args[i] do |
---|
384 | self.args[i]:passpar() |
---|
385 | i = i+1 |
---|
386 | if self.args[i] then |
---|
387 | output(',') |
---|
388 | end |
---|
389 | end |
---|
390 | |
---|
391 | if class and self.name == 'operator[]' and flags['1'] then |
---|
392 | output('-1);') |
---|
393 | else |
---|
394 | output(');') |
---|
395 | end |
---|
396 | |
---|
397 | -- return values |
---|
398 | if self.type ~= '' and self.type ~= 'void' then |
---|
399 | nret = nret + 1 |
---|
400 | local t,ct = isbasic(self.type) |
---|
401 | if t then |
---|
402 | if self.cast_operator and _basic_raw_push[t] then |
---|
403 | output(' ',_basic_raw_push[t],'(tolua_S,(',ct,')tolua_ret);') |
---|
404 | else |
---|
405 | output(' tolua_push'..t..'(tolua_S,(',ct,')tolua_ret);') |
---|
406 | end |
---|
407 | else |
---|
408 | t = self.type |
---|
409 | new_t = string.gsub(t, "const%s+", "") |
---|
410 | if self.ptr == '' then |
---|
411 | output(' {') |
---|
412 | output('#ifdef __cplusplus\n') |
---|
413 | output(' void* tolua_obj = new',new_t,'(tolua_ret);') |
---|
414 | output(' tolua_pushusertype_and_takeownership(tolua_S,tolua_obj,"',t,'");') |
---|
415 | output('#else\n') |
---|
416 | output(' void* tolua_obj = tolua_copy(tolua_S,(void*)&tolua_ret,sizeof(',t,'));') |
---|
417 | output(' tolua_pushusertype_and_takeownership(tolua_S,tolua_obj,"',t,'");') |
---|
418 | output('#endif\n') |
---|
419 | output(' }') |
---|
420 | elseif self.ptr == '&' then |
---|
421 | output(' tolua_pushusertype(tolua_S,(void*)&tolua_ret,"',t,'");') |
---|
422 | else |
---|
423 | if local_constructor then |
---|
424 | output(' tolua_pushusertype_and_takeownership(tolua_S,(void *)tolua_ret,"',t,'");') |
---|
425 | else |
---|
426 | output(' tolua_pushusertype(tolua_S,(void*)tolua_ret,"',t,'");') |
---|
427 | end |
---|
428 | end |
---|
429 | end |
---|
430 | end |
---|
431 | local i=1 |
---|
432 | while self.args[i] do |
---|
433 | nret = nret + self.args[i]:retvalue() |
---|
434 | i = i+1 |
---|
435 | end |
---|
436 | output(' }') |
---|
437 | |
---|
438 | ------------------------------------------ |
---|
439 | -- CEGUILua mod |
---|
440 | -- finish exception handling |
---|
441 | -- catch |
---|
442 | if throws then |
---|
443 | outputExceptionCatchBlocks(self.name, throws, exRaiseError) |
---|
444 | end |
---|
445 | ------------------------------------------ |
---|
446 | |
---|
447 | -- set array element values |
---|
448 | if class then narg=2 else narg=1 end |
---|
449 | if self.args[1].type ~= 'void' then |
---|
450 | local i=1 |
---|
451 | while self.args[i] do |
---|
452 | self.args[i]:setarray(narg) |
---|
453 | narg = narg+1 |
---|
454 | i = i+1 |
---|
455 | end |
---|
456 | end |
---|
457 | |
---|
458 | -- free dynamically allocated array |
---|
459 | if self.args[1].type ~= 'void' then |
---|
460 | local i=1 |
---|
461 | while self.args[i] do |
---|
462 | self.args[i]:freearray() |
---|
463 | i = i+1 |
---|
464 | end |
---|
465 | end |
---|
466 | end |
---|
467 | |
---|
468 | output(' }') |
---|
469 | output(' return '..nret..';') |
---|
470 | |
---|
471 | -- call overloaded function or generate error |
---|
472 | if overload < 0 then |
---|
473 | |
---|
474 | output('#ifndef TOLUA_RELEASE\n') |
---|
475 | output('tolua_lerror:\n') |
---|
476 | output(' tolua_error(tolua_S,"#ferror in function \''..self.lname..'\'.",&tolua_err);') |
---|
477 | output(' return 0;') |
---|
478 | output('#endif\n') |
---|
479 | else |
---|
480 | local _local = "" |
---|
481 | if local_constructor then |
---|
482 | _local = "_local" |
---|
483 | end |
---|
484 | output('tolua_lerror:\n') |
---|
485 | output(' return '..strsub(self.cname,1,-3)..format("%02d",overload).._local..'(tolua_S);') |
---|
486 | end |
---|
487 | output('}') |
---|
488 | output('#endif //#ifndef TOLUA_DISABLE\n') |
---|
489 | output('\n') |
---|
490 | |
---|
491 | -- recursive call to write local constructor |
---|
492 | if class and self.name=='new' and not local_constructor then |
---|
493 | |
---|
494 | self:supcode(1) |
---|
495 | end |
---|
496 | |
---|
497 | end |
---|
498 | |
---|
499 | |
---|
500 | -- register function |
---|
501 | function classFunction:register (pre) |
---|
502 | |
---|
503 | if not self:check_public_access() then |
---|
504 | return |
---|
505 | end |
---|
506 | |
---|
507 | if self.name == 'new' and self.parent.flags.pure_virtual then |
---|
508 | -- no constructor for classes with pure virtual methods |
---|
509 | return |
---|
510 | end |
---|
511 | |
---|
512 | output(pre..'tolua_function(tolua_S,"'..self.lname..'",'..self.cname..');') |
---|
513 | if self.name == 'new' then |
---|
514 | output(pre..'tolua_function(tolua_S,"new_local",'..self.cname..'_local);') |
---|
515 | output(pre..'tolua_function(tolua_S,".call",'..self.cname..'_local);') |
---|
516 | --output(' tolua_set_call_event(tolua_S,'..self.cname..'_local, "'..self.parent.type..'");') |
---|
517 | end |
---|
518 | end |
---|
519 | |
---|
520 | -- Print method |
---|
521 | function classFunction:print (ident,close) |
---|
522 | print(ident.."Function{") |
---|
523 | print(ident.." mod = '"..self.mod.."',") |
---|
524 | print(ident.." type = '"..self.type.."',") |
---|
525 | print(ident.." ptr = '"..self.ptr.."',") |
---|
526 | print(ident.." name = '"..self.name.."',") |
---|
527 | print(ident.." lname = '"..self.lname.."',") |
---|
528 | print(ident.." const = '"..self.const.."',") |
---|
529 | print(ident.." cname = '"..self.cname.."',") |
---|
530 | print(ident.." lname = '"..self.lname.."',") |
---|
531 | print(ident.." args = {") |
---|
532 | local i=1 |
---|
533 | while self.args[i] do |
---|
534 | self.args[i]:print(ident.." ",",") |
---|
535 | i = i+1 |
---|
536 | end |
---|
537 | print(ident.." }") |
---|
538 | print(ident.."}"..close) |
---|
539 | end |
---|
540 | |
---|
541 | -- check if it returns an object by value |
---|
542 | function classFunction:requirecollection (t) |
---|
543 | local r = false |
---|
544 | if self.type ~= '' and not isbasic(self.type) and self.ptr=='' then |
---|
545 | local type = gsub(self.type,"%s*const%s+","") |
---|
546 | t[type] = "tolua_collect_" .. clean_template(type) |
---|
547 | r = true |
---|
548 | end |
---|
549 | local i=1 |
---|
550 | while self.args[i] do |
---|
551 | r = self.args[i]:requirecollection(t) or r |
---|
552 | i = i+1 |
---|
553 | end |
---|
554 | return r |
---|
555 | end |
---|
556 | |
---|
557 | -- determine lua function name overload |
---|
558 | function classFunction:overload () |
---|
559 | return self.parent:overload(self.lname) |
---|
560 | end |
---|
561 | |
---|
562 | |
---|
563 | function param_object(par) -- returns true if the parameter has an object as its default value |
---|
564 | |
---|
565 | if not string.find(par, '=') then return false end -- it has no default value |
---|
566 | |
---|
567 | local _,_,def = string.find(par, "=(.*)$") |
---|
568 | |
---|
569 | if string.find(par, "|") then -- a list of flags |
---|
570 | |
---|
571 | return true |
---|
572 | end |
---|
573 | |
---|
574 | if string.find(par, "%*") then -- it's a pointer with a default value |
---|
575 | |
---|
576 | if string.find(par, '=%s*new') then -- it's a pointer with an instance as default parameter.. is that valid? |
---|
577 | return true |
---|
578 | end |
---|
579 | return false -- default value is 'NULL' or something |
---|
580 | end |
---|
581 | |
---|
582 | |
---|
583 | if string.find(par, "[%(&]") then |
---|
584 | return true |
---|
585 | end -- default value is a constructor call (most likely for a const reference) |
---|
586 | |
---|
587 | --if string.find(par, "&") then |
---|
588 | |
---|
589 | -- if string.find(def, ":") or string.find(def, "^%s*new%s+") then |
---|
590 | |
---|
591 | -- -- it's a reference with default to something like Class::member, or 'new Class' |
---|
592 | -- return true |
---|
593 | -- end |
---|
594 | --end |
---|
595 | |
---|
596 | return false -- ? |
---|
597 | end |
---|
598 | |
---|
599 | function strip_last_arg(all_args, last_arg) -- strips the default value from the last argument |
---|
600 | |
---|
601 | local _,_,s_arg = string.find(last_arg, "^([^=]+)") |
---|
602 | last_arg = string.gsub(last_arg, "([%%%(%)])", "%%%1"); |
---|
603 | all_args = string.gsub(all_args, "%s*,%s*"..last_arg.."%s*%)%s*$", ")") |
---|
604 | return all_args, s_arg |
---|
605 | end |
---|
606 | |
---|
607 | |
---|
608 | |
---|
609 | -- Internal constructor |
---|
610 | function _Function (t) |
---|
611 | setmetatable(t,classFunction) |
---|
612 | |
---|
613 | if t.const ~= 'const' and t.const ~= '' then |
---|
614 | error("#invalid 'const' specification") |
---|
615 | end |
---|
616 | |
---|
617 | append(t) |
---|
618 | if t:inclass() then |
---|
619 | --print ('t.name is '..t.name..', parent.name is '..t.parent.name) |
---|
620 | if string.gsub(t.name, "%b<>", "") == string.gsub(t.parent.original_name or t.parent.name, "%b<>", "") then |
---|
621 | t.name = 'new' |
---|
622 | t.lname = 'new' |
---|
623 | t.parent._new = true |
---|
624 | t.type = t.parent.name |
---|
625 | t.ptr = '*' |
---|
626 | elseif string.gsub(t.name, "%b<>", "") == '~'..string.gsub(t.parent.original_name or t.parent.name, "%b<>", "") then |
---|
627 | t.name = 'delete' |
---|
628 | t.lname = 'delete' |
---|
629 | t.parent._delete = true |
---|
630 | end |
---|
631 | end |
---|
632 | t.cname = t:cfuncname("tolua")..t:overload(t) |
---|
633 | return t |
---|
634 | end |
---|
635 | |
---|
636 | -- Constructor |
---|
637 | -- Expects three strings: one representing the function declaration, |
---|
638 | -- another representing the argument list, and the third representing |
---|
639 | -- the "const" or empty string. |
---|
640 | function Function (d,a,c) |
---|
641 | --local t = split(strsub(a,2,-2),',') -- eliminate braces |
---|
642 | --local t = split_params(strsub(a,2,-2)) |
---|
643 | |
---|
644 | if not flags['W'] and string.find(a, "%.%.%.%s*%)") then |
---|
645 | |
---|
646 | warning("Functions with variable arguments (`...') are not supported. Ignoring "..d..a..c) |
---|
647 | return nil |
---|
648 | end |
---|
649 | |
---|
650 | |
---|
651 | local i=1 |
---|
652 | local l = {n=0} |
---|
653 | |
---|
654 | a = string.gsub(a, "%s*([%(%)])%s*", "%1") |
---|
655 | local t,strip,last = strip_pars(strsub(a,2,-2)); |
---|
656 | if strip then |
---|
657 | --local ns = string.sub(strsub(a,1,-2), 1, -(string.len(last)+1)) |
---|
658 | local ns = join(t, ",", 1, last-1) |
---|
659 | |
---|
660 | ns = "("..string.gsub(ns, "%s*,%s*$", "")..')' |
---|
661 | --ns = strip_defaults(ns) |
---|
662 | |
---|
663 | Function(d, ns, c) |
---|
664 | for i=1,last do |
---|
665 | t[i] = string.gsub(t[i], "=.*$", "") |
---|
666 | end |
---|
667 | end |
---|
668 | |
---|
669 | while t[i] do |
---|
670 | l.n = l.n+1 |
---|
671 | l[l.n] = Declaration(t[i],'var',true) |
---|
672 | i = i+1 |
---|
673 | end |
---|
674 | local f = Declaration(d,'func') |
---|
675 | f.args = l |
---|
676 | f.const = c |
---|
677 | return _Function(f) |
---|
678 | end |
---|
679 | |
---|
680 | function join(t, sep, first, last) |
---|
681 | |
---|
682 | first = first or 1 |
---|
683 | last = last or table.getn(t) |
---|
684 | local lsep = "" |
---|
685 | local ret = "" |
---|
686 | local loop = false |
---|
687 | for i = first,last do |
---|
688 | |
---|
689 | ret = ret..lsep..t[i] |
---|
690 | lsep = sep |
---|
691 | loop = true |
---|
692 | end |
---|
693 | if not loop then |
---|
694 | return "" |
---|
695 | end |
---|
696 | |
---|
697 | return ret |
---|
698 | end |
---|
699 | |
---|
700 | function strip_pars(s) |
---|
701 | |
---|
702 | local t = split_c_tokens(s, ',') |
---|
703 | local strip = false |
---|
704 | local last |
---|
705 | |
---|
706 | for i=t.n,1,-1 do |
---|
707 | |
---|
708 | if not strip and param_object(t[i]) then |
---|
709 | last = i |
---|
710 | strip = true |
---|
711 | end |
---|
712 | --if strip then |
---|
713 | -- t[i] = string.gsub(t[i], "=.*$", "") |
---|
714 | --end |
---|
715 | end |
---|
716 | |
---|
717 | return t,strip,last |
---|
718 | |
---|
719 | end |
---|
720 | |
---|
721 | function strip_defaults(s) |
---|
722 | |
---|
723 | s = string.gsub(s, "^%(", "") |
---|
724 | s = string.gsub(s, "%)$", "") |
---|
725 | |
---|
726 | local t = split_c_tokens(s, ",") |
---|
727 | local sep, ret = "","" |
---|
728 | for i=1,t.n do |
---|
729 | t[i] = string.gsub(t[i], "=.*$", "") |
---|
730 | ret = ret..sep..t[i] |
---|
731 | sep = "," |
---|
732 | end |
---|
733 | |
---|
734 | return "("..ret..")" |
---|
735 | end |
---|
736 | |
---|
737 | |
---|