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,v in ipairs(_renaming) do 79 local m,n = gsub(s,v.old,v.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 local arg={...} 256 while i<=#arg do 257 if _cont and not strfind(_cont,'[%(,"]') and 258 strfind(arg[i],"^[%a_~]") then 259 line = line .. ' ' 260 end 261 line = line .. arg[i] 262 if arg[i] ~= '' then 263 _cont = strsub(arg[i],-1,-1) 264 end 265 i = i+1 266 end 267 if strfind(arg[#arg],"[%/%)%;%{%}]$") then 268 _cont=nil line = line .. '\n' 269 end 270 return line 271end 272 273-- output line 274function output (...) 275 local i=1 276 local arg = {...} 277 while i<=#arg do 278 if _cont and not strfind(_cont,'[%(,"]') and 279 strfind(arg[i],"^[%a_~]") then 280 write(' ') 281 end 282 write(arg[i]) 283 if arg[i] ~= '' then 284 _cont = strsub(arg[i],-1,-1) 285 end 286 i = i+1 287 end 288 if strfind(arg[#arg],"[%/%)%;%{%}]$") then 289 _cont=nil write('\n') 290 end 291end 292 293function get_property_methods(ptype, name) 294 295 if get_property_methods_hook and get_property_methods_hook(ptype,name) then 296 return get_property_methods_hook(ptype, name) 297 end 298 299 if ptype == "default" then -- get_name, set_name 300 return "get_"..name, "set_"..name 301 end 302 303 if ptype == "qt" then -- name, setName 304 return name, "set"..string.upper(string.sub(name, 1, 1))..string.sub(name, 2, -1) 305 end 306 307 if ptype == "overload" then -- name, name 308 return name,name 309 end 310 311 return nil 312end 313 314-------------- the hooks 315 316-- called right after processing the $[ichl]file directives, 317-- right before processing anything else 318-- takes the package object as the parameter 319function preprocess_hook(p) 320 -- p.code has all the input code from the pkg 321end 322 323 324-- called for every $ifile directive 325-- takes a table with a string called 'code' inside, the filename, and any extra arguments 326-- passed to $ifile. no return value 327function include_file_hook(t, filename, ...) 328 329end 330 331-- called after processing anything that's not code (like '$renaming', comments, etc) 332-- and right before parsing the actual code. 333-- takes the Package object with all the code on the 'code' key. no return value 334function preparse_hook(package) 335 336end 337 338-- called before starting output 339function pre_output_hook(package) 340 341end 342 343-- called after writing all the output. 344-- takes the Package object 345function post_output_hook(package) 346 347end 348 349 350-- called from 'get_property_methods' to get the methods to retrieve a property 351-- according to its type 352function get_property_methods_hook(property_type, name) 353 354end 355 356-- called from ClassContainer:doparse with the string being parsed 357-- return nil, or a substring 358function parser_hook(s) 359 360 return nil 361end 362 363-- called from classFunction:supcode, before the call to the function is output 364function pre_call_hook(f) 365 366end 367 368-- called from classFunction:supcode, after the call to the function is output 369function post_call_hook(f) 370 371end 372 373-- called before the register code is output 374function pre_register_hook(package) 375 376end 377 378 379-- called to output an error message 380function output_error_hook(...) 381 return string.format(table.unpack{...}) 382end 383 384-- custom pushers 385 386_push_functions = {} 387_is_functions = {} 388_to_functions = {} 389 390_base_push_functions = {} 391_base_is_functions = {} 392_base_to_functions = {} 393 394local function search_base(t, funcs) 395 396 local class = _global_classes[t] 397 398 while class do 399 if funcs[class.type] then 400 return funcs[class.type] 401 end 402 class = _global_classes[class.btype] 403 end 404 return nil 405end 406 407function get_push_function(t) 408 return _push_functions[t] or search_base(t, _base_push_functions) or "tolua_pushusertype" 409end 410 411function get_to_function(t) 412 return _to_functions[t] or search_base(t, _base_to_functions) or "tolua_tousertype" 413end 414 415function get_is_function(t) 416 return _is_functions[t] or search_base(t, _base_is_functions) or "tolua_isusertype" 417end 418