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