| 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 |  | 
|---|