1-- tolua: declaration class 2-- Written by Waldemar Celes 3-- TeCGraf/PUC-Rio 4-- Jul 1998 5-- $Id: declaration.lua,v 1.5 2011/01/13 13:43:46 fabraham Exp $ 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-- Declaration class 14-- Represents variable, function, or argument declaration. 15-- Stores the following fields: 16-- mod = type modifiers 17-- type = type 18-- ptr = "*" or "&", if representing a pointer or a reference 19-- name = name 20-- dim = dimension, if a vector 21-- def = default value, if any (only for arguments) 22-- ret = "*" or "&", if value is to be returned (only for arguments) 23classDeclaration = { 24 mod = '', 25 type = '', 26 ptr = '', 27 name = '', 28 dim = '', 29 ret = '', 30 def = '' 31} 32classDeclaration.__index = classDeclaration 33setmetatable(classDeclaration,classFeature) 34 35-- Create an unique variable name 36function create_varname () 37 if not _varnumber then _varnumber = 0 end 38 _varnumber = _varnumber + 1 39 return "tolua_var_".._varnumber 40end 41 42-- Check declaration name 43-- It also identifies default values 44function classDeclaration:checkname () 45 46 if strsub(self.name,1,1) == '[' and not findtype(self.type) then 47 self.name = self.type..self.name 48 local m = split(self.mod,'%s%s*') 49 self.type = m[m.n] 50 self.mod = concat(m,1,m.n-1) 51 end 52 53 local t = split(self.name,'=') 54 if t.n==2 then 55 self.name = t[1] 56 self.def = t[t.n] 57 end 58 59 local b,e,d = strfind(self.name,"%[(.-)%]") 60 if b then 61 self.name = strsub(self.name,1,b-1) 62 self.dim = d 63 end 64 65 if self.type ~= '' and self.type ~= 'void' and self.name == '' then 66 self.name = create_varname() 67 elseif self.kind=='var' then 68 if self.type=='' and self.name~='' then 69 self.type = self.type..self.name 70 self.name = create_varname() 71 elseif findtype(self.name) then 72 if self.type=='' then self.type = self.name 73 else self.type = self.type..' '..self.name end 74 self.name = create_varname() 75 end 76 end 77 78 -- adjust type of string 79-- if self.type == 'char' and self.dim ~= '' then 80-- self.type = 'char*' 81-- end 82end 83 84-- Check declaration type 85-- Substitutes typedef's. 86function classDeclaration:checktype () 87 88 -- check if there is a pointer to basic type 89 if isbasic(self.type) and self.ptr~='' then 90 self.ret = self.ptr 91 self.ptr = nil 92 end 93 94 -- check if there is array to be returned 95 if self.dim~='' and self.ret~='' then 96 error('#invalid parameter: cannot return an array of values') 97 end 98 99 -- restore 'void*' and 'string*' 100 if self.type == '_userdata' then self.type = 'void*' 101 elseif self.type == '_cstring' then self.type = 'char*' 102 elseif self.type == '_lstate' then self.type = 'lua_State*' 103 end 104 105-- 106-- -- if returning value, automatically set default value 107-- if self.ret ~= '' and self.def == '' then 108-- self.def = '0' 109-- end 110-- 111 112end 113 114-- Print method 115function classDeclaration:print (ident,close) 116 print(ident.."Declaration{") 117 print(ident.." mod = '"..self.mod.."',") 118 print(ident.." type = '"..self.type.."',") 119 print(ident.." ptr = '"..self.ptr.."',") 120 print(ident.." name = '"..self.name.."',") 121 print(ident.." dim = '"..self.dim.."',") 122 print(ident.." def = '"..self.def.."',") 123 print(ident.." ret = '"..self.ret.."',") 124 print(ident.."}"..close) 125end 126 127-- check if array of values are returned to Lua 128function classDeclaration:requirecollection (t) 129 if self.mod ~= 'const' and 130 self.dim and self.dim ~= '' and 131 not isbasic(self.type) and 132 self.ptr == '' then 133 local type = gsub(self.type,"%s*const%s*","") 134 t[type] = "tolua_collect_" .. gsub(type,"::","_") 135 return true 136 end 137 return false 138end 139 140-- declare tag 141function classDeclaration:decltype () 142 self.type = typevar(self.type) 143 if strfind(self.mod,'const') then 144 self.type = 'const '..self.type 145 self.mod = gsub(self.mod,'const%s*','') 146 end 147end 148 149 150-- output type checking 151function classDeclaration:outchecktype (narg,var) 152 local def 153 local t = isbasic(self.type) 154 if self.def~='' then 155 def = 1 156 else 157 def = 0 158 end 159 if self.dim ~= '' then 160 if var and self.type=='char' then 161 return 'tolua_isstring(tolua_S,'..narg..','..def..',&tolua_err)' 162 else 163 return 'tolua_istable(tolua_S,'..narg..',0,&tolua_err)' 164 end 165 elseif t then 166 return 'tolua_is'..t..'(tolua_S,'..narg..','..def..',&tolua_err)' 167 else 168 return 'tolua_isusertype(tolua_S,'..narg..',"'..self.type..'",'..def..',&tolua_err)' 169 end 170end 171 172function classDeclaration:builddeclaration (narg, cplusplus) 173 local array = self.dim ~= '' and tonumber(self.dim)==nil 174 local line = "" 175 local ptr = '' 176 local mod 177 local type = self.type 178 if self.dim ~= '' then 179 type = gsub(self.type,'const%s*','') -- eliminates const modifier for arrays 180 end 181 local ctype = type 182 if ctype=="lua_Object" or ctype=="lua_Function" then 183 ctype = "int" 184 end 185 if self.ptr~='' then ptr = '*' end 186 line = concatparam(line," ",self.mod,ctype,ptr) 187 if array then 188 line = concatparam(line,'*') 189 end 190 line = concatparam(line,self.name) 191 if self.dim ~= '' then 192 if tonumber(self.dim)~=nil then 193 line = concatparam(line,'[',self.dim,'];') 194 else 195 if cplusplus then 196 line = concatparam(line,' = new',type,ptr,'['..self.dim..'];') 197 else 198 line = concatparam(line,' = (',type,ptr,'*)', 199 'malloc((',self.dim,')*sizeof(',type,ptr,'));') 200 end 201 end 202 else 203 local t = isbasic(type) 204 line = concatparam(line,' = ') 205 if t == 'state' then 206 line = concatparam(line, 'tolua_S;') 207 else 208 if not t and ptr=='' then line = concatparam(line,'*') end 209 local ct = type 210 if t == 'value' or t == 'function' then 211 ct = 'int' 212 end 213 line = concatparam(line,'((',self.mod,ct) 214 if not t then 215 line = concatparam(line,'*') 216 end 217 line = concatparam(line,') ') 218 if isenum(type) then 219 --if not t and isenum(type) then 220 line = concatparam(line,'(int) ') 221 end 222 local def = 0 223 if self.def ~= '' then def = self.def end 224 if t then 225 if t=='function' then t='value' end 226 if self.type == "tolua_index" then 227 line = concatparam(line,'tolua_to'..t,'(tolua_S,',narg,',',def,')-1);') 228 else 229 line = concatparam(line,'tolua_to'..t,'(tolua_S,',narg,',',def,'));') 230 end 231 else 232 line = concatparam(line,'tolua_tousertype(tolua_S,',narg,',',def,'));') 233 end 234 end 235 end 236 return line 237end 238 239-- Declare variable 240function classDeclaration:declare (narg) 241 if self.dim ~= '' and self.type~='char' and tonumber(self.dim)==nil then 242 output('#ifdef __cplusplus\n') 243 output(self:builddeclaration(narg,true)) 244 output('#else\n') 245 output(self:builddeclaration(narg,false)) 246 output('#endif\n') 247 else 248 output(self:builddeclaration(narg,false)) 249 end 250end 251 252-- Get parameter value 253function classDeclaration:getarray (narg) 254 if self.dim ~= '' then 255 local type = gsub(self.type,'const ','') 256 output(' {') 257 output('#ifndef TOLUA_RELEASE\n') 258 local def; if self.def~='' then def=1 else def=0 end 259 local t = isbasic(type) 260 if (t) then 261 output(' if (!tolua_is'..t..'array(tolua_S,',narg,',',self.dim,',',def,',&tolua_err))') 262 else 263 output(' if (!tolua_isusertypearray(tolua_S,',narg,',"',type,'",',self.dim,',',def,',&tolua_err))') 264 end 265 output(' goto tolua_lerror;') 266 output(' else\n') 267 output('#endif\n') 268 output(' {') 269 output(' int i;') 270 output(' for(i=0; i<'..self.dim..';i++)') 271 local t = isbasic(type) 272 local ptr = '' 273 if self.ptr~='' then ptr = '*' end 274 output(' ',self.name..'[i] = ') 275 if not t and ptr=='' then output('*') end 276 output('((',type) 277 if not t then 278 output('*') 279 end 280 output(') ') 281 local def = 0 282 if self.def ~= '' then def = self.def end 283 if t then 284 if t=='function' then t='value' end 285 output('tolua_tofield'..t..'(tolua_S,',narg,',i+1,',def,'));') 286 else 287 output('tolua_tofieldusertype(tolua_S,',narg,',i+1,',def,'));') 288 end 289 output(' }') 290 output(' }') 291 end 292end 293 294-- Get parameter value 295function classDeclaration:setarray (narg) 296 if not strfind(self.type,'const') and self.dim ~= '' then 297 local type = gsub(self.type,'const ','') 298 output(' {') 299 output(' int i;') 300 output(' for(i=0; i<'..self.dim..';i++)') 301 local t,ct = isbasic(type) 302 if t then 303 if t=='function' then t='value' end 304 output(' tolua_pushfield'..t..'(tolua_S,',narg,',i+1,(',ct,')',self.name,'[i]);') 305 else 306 if self.ptr == '' then 307 output(' {') 308 output('#ifdef __cplusplus\n') 309 output(' void* tolua_obj = new',type,'(',self.name,'[i]);') 310 output(' tolua_pushfieldusertype(tolua_S,',narg,',i+1,tolua_clone(tolua_S,tolua_obj,'.. (_collect[type] or 'NULL') ..'),"',type,'");') 311 output('#else\n') 312 output(' void* tolua_obj = tolua_copy(tolua_S,(void*)&',self.name,'[i],sizeof(',type,'));') 313 output(' tolua_pushfieldusertype(tolua_S,',narg,',i+1,tolua_clone(tolua_S,tolua_obj,NULL),"',type,'");') 314 output('#endif\n') 315 output(' }') 316 else 317 output(' tolua_pushfieldusertype(tolua_S,',narg,',i+1,(void*)',self.name,'[i],"',type,'");') 318 end 319 end 320 output(' }') 321 end 322end 323 324-- Free dynamically allocated array 325function classDeclaration:freearray () 326 if self.dim ~= '' and tonumber(self.dim)==nil then 327 output('#ifdef __cplusplus\n') 328 output(' delete []',self.name,';') 329 output('#else\n') 330 output(' free(',self.name,');') 331 output('#endif\n') 332 end 333end 334 335-- Pass parameter 336function classDeclaration:passpar () 337 local name = self.name 338 if self.ptr=='&' then 339 output('*'..name) 340 elseif self.ret=='*' then 341 output('&'..name) 342 else 343 output(name) 344 end 345end 346 347-- Return parameter value 348function classDeclaration:retvalue () 349 if self.ret ~= '' then 350 local t,ct = isbasic(self.type) 351 if t then 352 if t=='function' then t='value' end 353 if self.type=="tolua_index" then 354 output(' tolua_push'..t..'(tolua_S,(',ct,')'..self.name..'+1);') 355 else 356 output(' tolua_push'..t..'(tolua_S,(',ct,')'..self.name..');') 357 end 358 else 359 output(' tolua_pushusertype(tolua_S,(void*)'..self.name..',"',self.type,'");') 360 end 361 return 1 362 end 363 return 0 364end 365 366-- Internal constructor 367function _Declaration (t) 368 setmetatable(t,classDeclaration) 369 t:buildnames() 370 t:checkname() 371 t:checktype() 372 return t 373end 374 375-- Constructor 376-- Expects the string declaration. 377-- The kind of declaration can be "var" or "func". 378function Declaration (s,kind) 379 -- eliminate spaces if default value is provided 380 s = gsub(s,"%s*=%s*","=") 381 382 if kind == "var" then 383 -- check the form: void 384 if s == '' or s == 'void' then 385 return _Declaration{type = 'void', kind = kind} 386 end 387 end 388 389 -- check the form: mod type*& name 390 local t = split(s,'%*%s*&') 391 if t.n == 2 then 392 if kind == 'func' then 393 error("#invalid function return type: "..s) 394 end 395 local m = split(t[1],'%s%s*') 396 return _Declaration{ 397 name = t[2], 398 ptr = '*', 399 ret = '&', 400 type = m[m.n], 401 mod = concat(m,1,m.n-1), 402 kind = kind 403 } 404 end 405 406 -- check the form: mod type** name 407 t = split(s,'%*%s*%*') 408 if t.n == 2 then 409 if kind == 'func' then 410 error("#invalid function return type: "..s) 411 end 412 local m = split(t[1],'%s%s*') 413 return _Declaration{ 414 name = t[2], 415 ptr = '*', 416 ret = '*', 417 type = m[m.n], 418 mod = concat(m,1,m.n-1), 419 kind = kind 420 } 421 end 422 423 -- check the form: mod type& name 424 t = split(s,'&') 425 if t.n == 2 then 426 local m = split(t[1],'%s%s*') 427 return _Declaration{ 428 name = t[2], 429 ptr = '&', 430 type = m[m.n], 431 mod = concat(m,1,m.n-1) , 432 kind = kind 433 } 434 end 435 436 -- check the form: mod type* name 437 local s1 = gsub(s,"(%b%[%])",function (n) return gsub(n,'%*','\1') end) 438 t = split(s1,'%*') 439 if t.n == 2 then 440 t[2] = gsub(t[2],'\1','%*') -- restore * in dimension expression 441 local m = split(t[1],'%s%s*') 442 return _Declaration{ 443 name = t[2], 444 ptr = '*', 445 type = m[m.n], 446 mod = concat(m,1,m.n-1) , 447 kind = kind 448 } 449 end 450 451 if kind == 'var' then 452 -- check the form: mod type name 453 t = split(s,'%s%s*') 454 local v 455 if findtype(t[t.n]) then v = '' else v = t[t.n]; t.n = t.n-1 end 456 return _Declaration{ 457 name = v, 458 type = t[t.n], 459 mod = concat(t,1,t.n-1), 460 kind = kind 461 } 462 463 else -- kind == "func" 464 465 -- check the form: mod type name 466 t = split(s,'%s%s*') 467 local v = t[t.n] -- last word is the function name 468 local tp,md 469 if t.n>1 then 470 tp = t[t.n-1] 471 md = concat(t,1,t.n-2) 472 end 473 return _Declaration{ 474 name = v, 475 type = tp, 476 mod = md, 477 kind = kind 478 } 479 end 480 481end 482 483