1-- tolua: basic utility functions 2-- Written by Waldemar Celes 3-- TeCGraf/PUC-Rio 4-- Jul 1998 5-- Last update: Apr 2003 6-- $Id: $ 7 8-- This code is free software; you can redistribute it and/or modify it. 9-- The software provided hereunder is on an "as is" basis, and 10-- the author has no obligation to provide maintenance, support, updates, 11-- enhancements, or modifications. 12 13 14-- Basic C types and their corresponding Lua types 15-- All occurrences of "char*" will be replaced by "_cstring", 16-- and all occurrences of "void*" will be replaced by "_userdata" 17_basic = { 18 ['void'] = '', 19 ['char'] = 'number', 20 ['int'] = 'number', 21 ['short'] = 'number', 22 ['long'] = 'number', 23 ['unsigned'] = 'number', 24 ['float'] = 'number', 25 ['double'] = 'number', 26 ['_cstring'] = 'string', 27 ['_userdata'] = 'userdata', 28 ['char*'] = 'string', 29 ['void*'] = 'userdata', 30 ['bool'] = 'boolean', 31 ['lua_Object'] = 'value', 32 ['LUA_VALUE'] = 'value', -- for compatibility with tolua 4.0 33 ['lua_State*'] = 'state', 34 ['_lstate'] = 'state', 35 ['lua_Function'] = 'value', 36} 37 38_basic_ctype = { 39 number = "lua_Number", 40 string = "const char*", 41 userdata = "void*", 42 boolean = "bool", 43 value = "int", 44 state = "lua_State*", 45} 46 47-- functions the are used to do a 'raw push' of basic types 48_basic_raw_push = {} 49 50-- List of user defined types 51-- Each type corresponds to a variable name that stores its tag value. 52_usertype = {} 53 54-- List of types that have to be collected 55_collect = {} 56 57-- List of types 58_global_types = {n=0} 59_global_types_hash = {} 60 61-- list of classes 62_global_classes = {} 63 64-- List of enum constants 65_global_enums = {} 66 67-- List of auto renaming 68_renaming = {} 69function appendrenaming (s) 70 local b,e,old,new = strfind(s,"%s*(.-)%s*@%s*(.-)%s*$") 71 if not b then 72 error("#Invalid renaming syntax; it should be of the form: pattern@pattern") 73 end 74 tinsert(_renaming,{old=old, new=new}) 75end 76 77function applyrenaming (s) 78 for i=1,getn(_renaming) do 79 local m,n = gsub(s,_renaming[i].old,_renaming[i].new) 80 if n ~= 0 then 81 return m 82 end 83 end 84 return nil 85end 86 87-- Error handler 88function tolua_error (s,f) 89if _curr_code then 90 print("***curr code for error is "..tostring(_curr_code)) 91 print(debug.traceback()) 92end 93 local out = _OUTPUT 94 _OUTPUT = _STDERR 95 if strsub(s,1,1) == '#' then 96 write("\n** tolua: "..strsub(s,2)..".\n\n") 97 if _curr_code then 98 local _,_,s = strfind(_curr_code,"^%s*(.-\n)") -- extract first line 99 if s==nil then s = _curr_code end 100 s = gsub(s,"_userdata","void*") -- return with 'void*' 101 s = gsub(s,"_cstring","char*") -- return with 'char*' 102 s = gsub(s,"_lstate","lua_State*") -- return with 'lua_State*' 103 write("Code being processed:\n"..s.."\n") 104 end 105 else 106 if not f then f = "(f is nil)" end 107 print("\n** tolua internal error: "..f..s..".\n\n") 108 return 109 end 110 _OUTPUT = out 111end 112 113function warning (msg) 114 if flags.q then return end 115 local out = _OUTPUT 116 _OUTPUT = _STDERR 117 write("\n** tolua warning: "..msg..".\n\n") 118 _OUTPUT = out 119end 120 121-- register an user defined type: returns full type 122function regtype (t) 123 --if isbasic(t) then 124 -- return t 125 --end 126 local ft = findtype(t) 127 128 if not _usertype[ft] then 129 return appendusertype(t) 130 end 131 return ft 132end 133 134-- return type name: returns full type 135function typevar(type) 136 if type == '' or type == 'void' then 137 return type 138 else 139 local ft = findtype(type) 140 if ft then 141 return ft 142 end 143 _usertype[type] = type 144 return type 145 end 146end 147 148-- check if basic type 149function isbasic (type) 150 local t = gsub(type,'const ','') 151 local m,t = applytypedef('', t) 152 local b = _basic[t] 153 if b then 154 return b,_basic_ctype[b] 155 end 156 return nil 157end 158 159-- split string using a token 160function split (s,t) 161 local l = {n=0} 162 local f = function (s) 163 l.n = l.n + 1 164 l[l.n] = s 165 return "" 166 end 167 local p = "%s*(.-)%s*"..t.."%s*" 168 s = gsub(s,"^%s+","") 169 s = gsub(s,"%s+$","") 170 s = gsub(s,p,f) 171 l.n = l.n + 1 172 l[l.n] = gsub(s,"(%s%s*)$","") 173 return l 174end 175 176-- splits a string using a pattern, considering the spacial cases of C code (templates, function parameters, etc) 177-- pattern can't contain the '^' (as used to identify the begining of the line) 178-- also strips whitespace 179function split_c_tokens(s, pat) 180 181 s = string.gsub(s, "^%s*", "") 182 s = string.gsub(s, "%s*$", "") 183 184 local token_begin = 1 185 local token_end = 1 186 local ofs = 1 187 local ret = {n=0} 188 189 function add_token(ofs) 190 191 local t = string.sub(s, token_begin, ofs) 192 t = string.gsub(t, "^%s*", "") 193 t = string.gsub(t, "%s*$", "") 194 ret.n = ret.n + 1 195 ret[ret.n] = t 196 end 197 198 while ofs <= string.len(s) do 199 200 local sub = string.sub(s, ofs, -1) 201 local b,e = string.find(sub, "^"..pat) 202 if b then 203 add_token(ofs-1) 204 ofs = ofs+e 205 token_begin = ofs 206 else 207 local char = string.sub(s, ofs, ofs) 208 if char == "(" or char == "<" then 209 210 local block 211 if char == "(" then block = "^%b()" end 212 if char == "<" then block = "^%b<>" end 213 214 b,e = string.find(sub, block) 215 if not b then 216 -- unterminated block? 217 ofs = ofs+1 218 else 219 ofs = ofs + e 220 end 221 222 else 223 ofs = ofs+1 224 end 225 end 226 227 end 228 add_token(ofs) 229 --if ret.n == 0 then 230 231 -- ret.n=1 232 -- ret[1] = "" 233 --end 234 235 return ret 236 237end 238 239-- concatenate strings of a table 240function concat (t,f,l,jstr) 241 jstr = jstr or " " 242 local s = '' 243 local i=f 244 while i<=l do 245 s = s..t[i] 246 i = i+1 247 if i <= l then s = s..jstr end 248 end 249 return s 250end 251 252-- concatenate all parameters, following output rules 253function concatparam (line, ...) 254 local i=1 255 while i<=arg.n do 256 if _cont and not strfind(_cont,'[%(,"]') and 257 strfind(arg[i],"^[%a_~]") then 258 line = line .. ' ' 259 end 260 line = line .. arg[i] 261 if arg[i] ~= '' then 262 _cont = strsub(arg[i],-1,-1) 263 end 264 i = i+1 265 end 266 if strfind(arg[arg.n],"[%/%)%;%{%}]$") then 267 _cont=nil line = line .. '\n' 268 end 269 return line 270end 271 272-- output line 273function output (...) 274 local i=1 275 while i<=arg.n do 276 if _cont and not strfind(_cont,'[%(,"]') and 277 strfind(arg[i],"^[%a_~]") then 278 write(' ') 279 end 280 write(arg[i]) 281 if arg[i] ~= '' then 282 _cont = strsub(arg[i],-1,-1) 283 end 284 i = i+1 285 end 286 if strfind(arg[arg.n],"[%/%)%;%{%}]$") then 287 _cont=nil write('\n') 288 end 289end 290 291function get_property_methods(ptype, name) 292 293 if get_property_methods_hook and get_property_methods_hook(ptype,name) then 294 return get_property_methods_hook(ptype, name) 295 end 296 297 if ptype == "default" then -- get_name, set_name 298 return "get_"..name, "set_"..name 299 end 300 301 if ptype == "qt" then -- name, setName 302 return name, "set"..string.upper(string.sub(name, 1, 1))..string.sub(name, 2, -1) 303 end 304 305 if ptype == "overload" then -- name, name 306 return name,name 307 end 308 309 return nil 310end 311 312-------------- the hooks 313 314-- called right after processing the $[ichl]file directives, 315-- right before processing anything else 316-- takes the package object as the parameter 317function preprocess_hook(p) 318 -- p.code has all the input code from the pkg 319end 320 321 322-- called for every $ifile directive 323-- takes a table with a string called 'code' inside, the filename, and any extra arguments 324-- passed to $ifile. no return value 325function include_file_hook(t, filename, ...) 326 327end 328 329-- called after processing anything that's not code (like '$renaming', comments, etc) 330-- and right before parsing the actual code. 331-- takes the Package object with all the code on the 'code' key. no return value 332function preparse_hook(package) 333 334end 335 336-- called before starting output 337function pre_output_hook(package) 338 339end 340 341-- called after writing all the output. 342-- takes the Package object 343function post_output_hook(package) 344 345end 346 347 348-- called from 'get_property_methods' to get the methods to retrieve a property 349-- according to its type 350function get_property_methods_hook(property_type, name) 351 352end 353 354-- called from ClassContainer:doparse with the string being parsed 355-- return nil, or a substring 356function parser_hook(s) 357 358 return nil 359end 360 361-- called from classFunction:supcode, before the call to the function is output 362function pre_call_hook(f) 363 364end 365 366-- called from classFunction:supcode, after the call to the function is output 367function post_call_hook(f) 368 369end 370 371-- called before the register code is output 372function pre_register_hook(package) 373 374end 375 376-- called to output an error message 377function output_error_hook(...) 378 return string.format(...) 379end 380 381-- custom pushers 382 383_push_functions = {} 384_is_functions = {} 385_to_functions = {} 386 387_base_push_functions = {} 388_base_is_functions = {} 389_base_to_functions = {} 390 391local function search_base(t, funcs) 392 393 local class = _global_classes[t] 394 395 while class do 396 if funcs[class.type] then 397 return funcs[class.type] 398 end 399 class = _global_classes[class.btype] 400 end 401 return nil 402end 403 404function get_push_function(t) 405 return _push_functions[t] or search_base(t, _base_push_functions) or "tolua_pushusertype" 406end 407 408function get_to_function(t) 409 return _to_functions[t] or search_base(t, _base_to_functions) or "tolua_tousertype" 410end 411 412function get_is_function(t) 413 return _is_functions[t] or search_base(t, _base_is_functions) or "tolua_isusertype" 414end 415