| 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 = {} | 
|---|
| 69 | function 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}) | 
|---|
| 75 | end | 
|---|
| 76 |  | 
|---|
| 77 | function 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 | 
|---|
| 85 | end | 
|---|
| 86 |  | 
|---|
| 87 | -- Error handler | 
|---|
| 88 | function tolua_error (s,f) | 
|---|
| 89 | if _curr_code then | 
|---|
| 90 | print("***curr code for error is "..tostring(_curr_code)) | 
|---|
| 91 | print(debug.traceback()) | 
|---|
| 92 | end | 
|---|
| 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 | 
|---|
| 111 | end | 
|---|
| 112 |  | 
|---|
| 113 | function warning (msg) | 
|---|
| 114 | local out = _OUTPUT | 
|---|
| 115 | _OUTPUT = _STDERR | 
|---|
| 116 | write("\n** tolua warning: "..msg..".\n\n") | 
|---|
| 117 | _OUTPUT = out | 
|---|
| 118 | end | 
|---|
| 119 |  | 
|---|
| 120 | -- register an user defined type: returns full type | 
|---|
| 121 | function regtype (t) | 
|---|
| 122 | --if isbasic(t) then | 
|---|
| 123 | --    return t | 
|---|
| 124 | --end | 
|---|
| 125 | local ft = findtype(t) | 
|---|
| 126 |  | 
|---|
| 127 | if not _usertype[ft] then | 
|---|
| 128 | return appendusertype(t) | 
|---|
| 129 | end | 
|---|
| 130 | return ft | 
|---|
| 131 | end | 
|---|
| 132 |  | 
|---|
| 133 | -- return type name: returns full type | 
|---|
| 134 | function typevar(type) | 
|---|
| 135 | if type == '' or type == 'void' then | 
|---|
| 136 | return type | 
|---|
| 137 | else | 
|---|
| 138 | local ft = findtype(type) | 
|---|
| 139 | if ft then | 
|---|
| 140 | return ft | 
|---|
| 141 | end | 
|---|
| 142 | _usertype[type] = type | 
|---|
| 143 | return type | 
|---|
| 144 | end | 
|---|
| 145 | end | 
|---|
| 146 |  | 
|---|
| 147 | -- check if basic type | 
|---|
| 148 | function isbasic (type) | 
|---|
| 149 | local t = gsub(type,'const ','') | 
|---|
| 150 | local m,t = applytypedef('', t) | 
|---|
| 151 | local b = _basic[t] | 
|---|
| 152 | if b then | 
|---|
| 153 | return b,_basic_ctype[b] | 
|---|
| 154 | end | 
|---|
| 155 | return nil | 
|---|
| 156 | end | 
|---|
| 157 |  | 
|---|
| 158 | -- split string using a token | 
|---|
| 159 | function split (s,t) | 
|---|
| 160 | local l = {n=0} | 
|---|
| 161 | local f = function (s) | 
|---|
| 162 | l.n = l.n + 1 | 
|---|
| 163 | l[l.n] = s | 
|---|
| 164 | return "" | 
|---|
| 165 | end | 
|---|
| 166 | local p = "%s*(.-)%s*"..t.."%s*" | 
|---|
| 167 | s = gsub(s,"^%s+","") | 
|---|
| 168 | s = gsub(s,"%s+$","") | 
|---|
| 169 | s = gsub(s,p,f) | 
|---|
| 170 | l.n = l.n + 1 | 
|---|
| 171 | l[l.n] = gsub(s,"(%s%s*)$","") | 
|---|
| 172 | return l | 
|---|
| 173 | end | 
|---|
| 174 |  | 
|---|
| 175 | -- splits a string using a pattern, considering the spacial cases of C code (templates, function parameters, etc) | 
|---|
| 176 | -- pattern can't contain the '^' (as used to identify the begining of the line) | 
|---|
| 177 | -- also strips whitespace | 
|---|
| 178 | function split_c_tokens(s, pat) | 
|---|
| 179 |  | 
|---|
| 180 | s = string.gsub(s, "^%s*", "") | 
|---|
| 181 | s = string.gsub(s, "%s*$", "") | 
|---|
| 182 |  | 
|---|
| 183 | local token_begin = 1 | 
|---|
| 184 | local token_end = 1 | 
|---|
| 185 | local ofs = 1 | 
|---|
| 186 | local ret = {n=0} | 
|---|
| 187 |  | 
|---|
| 188 | function add_token(ofs) | 
|---|
| 189 |  | 
|---|
| 190 | local t = string.sub(s, token_begin, ofs) | 
|---|
| 191 | t = string.gsub(t, "^%s*", "") | 
|---|
| 192 | t = string.gsub(t, "%s*$", "") | 
|---|
| 193 | ret.n = ret.n + 1 | 
|---|
| 194 | ret[ret.n] = t | 
|---|
| 195 | end | 
|---|
| 196 |  | 
|---|
| 197 | while ofs <= string.len(s) do | 
|---|
| 198 |  | 
|---|
| 199 | local sub = string.sub(s, ofs, -1) | 
|---|
| 200 | local b,e = string.find(sub, "^"..pat) | 
|---|
| 201 | if b then | 
|---|
| 202 | add_token(ofs-1) | 
|---|
| 203 | ofs = ofs+e | 
|---|
| 204 | token_begin = ofs | 
|---|
| 205 | else | 
|---|
| 206 | local char = string.sub(s, ofs, ofs) | 
|---|
| 207 | if char == "(" or char == "<" then | 
|---|
| 208 |  | 
|---|
| 209 | local block | 
|---|
| 210 | if char == "(" then block = "^%b()" end | 
|---|
| 211 | if char == "<" then block = "^%b<>" end | 
|---|
| 212 |  | 
|---|
| 213 | b,e = string.find(sub, block) | 
|---|
| 214 | if not b then | 
|---|
| 215 | -- unterminated block? | 
|---|
| 216 | ofs = ofs+1 | 
|---|
| 217 | else | 
|---|
| 218 | ofs = ofs + e | 
|---|
| 219 | end | 
|---|
| 220 |  | 
|---|
| 221 | else | 
|---|
| 222 | ofs = ofs+1 | 
|---|
| 223 | end | 
|---|
| 224 | end | 
|---|
| 225 |  | 
|---|
| 226 | end | 
|---|
| 227 | add_token(ofs) | 
|---|
| 228 | --if ret.n == 0 then | 
|---|
| 229 |  | 
|---|
| 230 | --    ret.n=1 | 
|---|
| 231 | --    ret[1] = "" | 
|---|
| 232 | --end | 
|---|
| 233 |  | 
|---|
| 234 | return ret | 
|---|
| 235 |  | 
|---|
| 236 | end | 
|---|
| 237 |  | 
|---|
| 238 | -- concatenate strings of a table | 
|---|
| 239 | function concat (t,f,l,jstr) | 
|---|
| 240 | jstr = jstr or " " | 
|---|
| 241 | local s = '' | 
|---|
| 242 | local i=f | 
|---|
| 243 | while i<=l do | 
|---|
| 244 | s = s..t[i] | 
|---|
| 245 | i = i+1 | 
|---|
| 246 | if i <= l then s = s..jstr end | 
|---|
| 247 | end | 
|---|
| 248 | return s | 
|---|
| 249 | end | 
|---|
| 250 |  | 
|---|
| 251 | -- concatenate all parameters, following output rules | 
|---|
| 252 | function concatparam (line, ...) | 
|---|
| 253 | local i=1 | 
|---|
| 254 | while i<=arg.n do | 
|---|
| 255 | if _cont and not strfind(_cont,'[%(,"]') and | 
|---|
| 256 | strfind(arg[i],"^[%a_~]") then | 
|---|
| 257 | line = line .. ' ' | 
|---|
| 258 | end | 
|---|
| 259 | line = line .. arg[i] | 
|---|
| 260 | if arg[i] ~= '' then | 
|---|
| 261 | _cont = strsub(arg[i],-1,-1) | 
|---|
| 262 | end | 
|---|
| 263 | i = i+1 | 
|---|
| 264 | end | 
|---|
| 265 | if strfind(arg[arg.n],"[%/%)%;%{%}]$") then | 
|---|
| 266 | _cont=nil line = line .. '\n' | 
|---|
| 267 | end | 
|---|
| 268 | return line | 
|---|
| 269 | end | 
|---|
| 270 |  | 
|---|
| 271 | -- output line | 
|---|
| 272 | function output (...) | 
|---|
| 273 | local i=1 | 
|---|
| 274 | while i<=arg.n do | 
|---|
| 275 | if _cont and not strfind(_cont,'[%(,"]') and | 
|---|
| 276 | strfind(arg[i],"^[%a_~]") then | 
|---|
| 277 | write(' ') | 
|---|
| 278 | end | 
|---|
| 279 | write(arg[i]) | 
|---|
| 280 | if arg[i] ~= '' then | 
|---|
| 281 | _cont = strsub(arg[i],-1,-1) | 
|---|
| 282 | end | 
|---|
| 283 | i = i+1 | 
|---|
| 284 | end | 
|---|
| 285 | if strfind(arg[arg.n],"[%/%)%;%{%}]$") then | 
|---|
| 286 | _cont=nil write('\n') | 
|---|
| 287 | end | 
|---|
| 288 | end | 
|---|
| 289 |  | 
|---|
| 290 | function get_property_methods(ptype, name) | 
|---|
| 291 |  | 
|---|
| 292 | if get_property_methods_hook and get_property_methods_hook(ptype,name) then | 
|---|
| 293 | return get_property_methods_hook(ptype, name) | 
|---|
| 294 | end | 
|---|
| 295 |  | 
|---|
| 296 | if ptype == "default" then -- get_name, set_name | 
|---|
| 297 | return "get_"..name, "set_"..name | 
|---|
| 298 | end | 
|---|
| 299 |  | 
|---|
| 300 | if ptype == "qt" then -- name, setName | 
|---|
| 301 | return name, "set"..string.upper(string.sub(name, 1, 1))..string.sub(name, 2, -1) | 
|---|
| 302 | end | 
|---|
| 303 |  | 
|---|
| 304 | if ptype == "overload" then -- name, name | 
|---|
| 305 | return name,name | 
|---|
| 306 | end | 
|---|
| 307 |  | 
|---|
| 308 | return nil | 
|---|
| 309 | end | 
|---|
| 310 |  | 
|---|
| 311 | -------------- the hooks | 
|---|
| 312 |  | 
|---|
| 313 | -- called right after processing the $[ichl]file directives, | 
|---|
| 314 | -- right before processing anything else | 
|---|
| 315 | -- takes the package object as the parameter | 
|---|
| 316 | function preprocess_hook(p) | 
|---|
| 317 | -- p.code has all the input code from the pkg | 
|---|
| 318 | end | 
|---|
| 319 |  | 
|---|
| 320 |  | 
|---|
| 321 | -- called for every $ifile directive | 
|---|
| 322 | -- takes a table with a string called 'code' inside, the filename, and any extra arguments | 
|---|
| 323 | -- passed to $ifile. no return value | 
|---|
| 324 | function include_file_hook(t, filename, ...) | 
|---|
| 325 |  | 
|---|
| 326 | end | 
|---|
| 327 |  | 
|---|
| 328 | -- called after processing anything that's not code (like '$renaming', comments, etc) | 
|---|
| 329 | -- and right before parsing the actual code. | 
|---|
| 330 | -- takes the Package object with all the code on the 'code' key. no return value | 
|---|
| 331 | function preparse_hook(package) | 
|---|
| 332 |  | 
|---|
| 333 | end | 
|---|
| 334 |  | 
|---|
| 335 |  | 
|---|
| 336 | -- called after writing all the output. | 
|---|
| 337 | -- takes the Package object | 
|---|
| 338 | function post_output_hook(package) | 
|---|
| 339 |  | 
|---|
| 340 | end | 
|---|
| 341 |  | 
|---|
| 342 |  | 
|---|
| 343 | -- called from 'get_property_methods' to get the methods to retrieve a property | 
|---|
| 344 | -- according to its type | 
|---|
| 345 | function get_property_methods_hook(property_type, name) | 
|---|
| 346 |  | 
|---|
| 347 | end | 
|---|
| 348 |  | 
|---|
| 349 | -- called from ClassContainer:doparse with the string being parsed | 
|---|
| 350 | -- return nil, or a substring | 
|---|
| 351 | function parser_hook(s) | 
|---|
| 352 |  | 
|---|
| 353 | return nil | 
|---|
| 354 | end | 
|---|
| 355 |  | 
|---|
| 356 | -- called after all the required C++ includes have been written | 
|---|
| 357 | function post_include_hook(package_name) | 
|---|
| 358 | end | 
|---|