| [1650] | 1 | -- tolua: package class | 
|---|
|  | 2 | -- Written by Waldemar Celes | 
|---|
|  | 3 | -- TeCGraf/PUC-Rio | 
|---|
|  | 4 | -- Jul 1998 | 
|---|
|  | 5 | -- $Id: $ | 
|---|
|  | 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 |  | 
|---|
|  | 14 | -- Package class | 
|---|
|  | 15 | -- Represents the whole package being bound. | 
|---|
|  | 16 | -- The following fields are stored: | 
|---|
|  | 17 | --    {i} = list of objects in the package. | 
|---|
|  | 18 | classPackage = { | 
|---|
| [2710] | 19 | classtype = 'package' | 
|---|
| [1650] | 20 | } | 
|---|
|  | 21 | classPackage.__index = classPackage | 
|---|
|  | 22 | setmetatable(classPackage,classContainer) | 
|---|
|  | 23 |  | 
|---|
|  | 24 | -- Print method | 
|---|
|  | 25 | function classPackage:print () | 
|---|
| [2710] | 26 | print("Package: "..self.name) | 
|---|
|  | 27 | local i=1 | 
|---|
|  | 28 | while self[i] do | 
|---|
|  | 29 | self[i]:print("","") | 
|---|
|  | 30 | i = i+1 | 
|---|
|  | 31 | end | 
|---|
| [1650] | 32 | end | 
|---|
|  | 33 |  | 
|---|
|  | 34 | function classPackage:preprocess () | 
|---|
|  | 35 |  | 
|---|
| [2710] | 36 | -- avoid preprocessing embedded Lua code | 
|---|
|  | 37 | local L = {} | 
|---|
|  | 38 | self.code = gsub(self.code,"\n%s*%$%[","\1") -- deal with embedded lua code | 
|---|
|  | 39 | self.code = gsub(self.code,"\n%s*%$%]","\2") | 
|---|
|  | 40 | self.code = gsub(self.code,"(%b\1\2)", function (c) | 
|---|
| [1650] | 41 | tinsert(L,c) | 
|---|
|  | 42 | return "\n#["..getn(L).."]#" | 
|---|
| [2710] | 43 | end | 
|---|
|  | 44 | ) | 
|---|
|  | 45 | -- avoid preprocessing embedded C code | 
|---|
|  | 46 | local C = {} | 
|---|
|  | 47 | self.code = gsub(self.code,"\n%s*%$%<","\3") -- deal with embedded C code | 
|---|
|  | 48 | self.code = gsub(self.code,"\n%s*%$%>","\4") | 
|---|
|  | 49 | self.code = gsub(self.code,"(%b\3\4)", function (c) | 
|---|
| [1650] | 50 | tinsert(C,c) | 
|---|
|  | 51 | return "\n#<"..getn(C)..">#" | 
|---|
| [2710] | 52 | end | 
|---|
|  | 53 | ) | 
|---|
|  | 54 | -- avoid preprocessing embedded C code | 
|---|
|  | 55 | self.code = gsub(self.code,"\n%s*%$%{","\5") -- deal with embedded C code | 
|---|
|  | 56 | self.code = gsub(self.code,"\n%s*%$%}","\6") | 
|---|
|  | 57 | self.code = gsub(self.code,"(%b\5\6)", function (c) | 
|---|
| [1650] | 58 | tinsert(C,c) | 
|---|
|  | 59 | return "\n#<"..getn(C)..">#" | 
|---|
| [2710] | 60 | end | 
|---|
|  | 61 | ) | 
|---|
| [1650] | 62 |  | 
|---|
| [2710] | 63 | --self.code = gsub(self.code,"\n%s*#[^d][^\n]*\n", "\n\n") -- eliminate preprocessor directives that don't start with 'd' | 
|---|
|  | 64 | self.code = gsub(self.code,"\n[ \t]*#[ \t]*[^d%<%[]", "\n//") -- eliminate preprocessor directives that don't start with 'd' | 
|---|
| [1650] | 65 |  | 
|---|
| [2710] | 66 | -- avoid preprocessing verbatim lines | 
|---|
|  | 67 | local V = {} | 
|---|
|  | 68 | self.code = gsub(self.code,"\n(%s*%$[^%[%]][^\n]*)", function (v) | 
|---|
|  | 69 | tinsert(V,v) | 
|---|
|  | 70 | return "\n#"..getn(V).."#" | 
|---|
|  | 71 | end | 
|---|
|  | 72 | ) | 
|---|
| [1650] | 73 |  | 
|---|
| [2710] | 74 | -- perform global substitution | 
|---|
| [1650] | 75 |  | 
|---|
| [2710] | 76 | self.code = gsub(self.code,"(//[^\n]*)","")     -- eliminate C++ comments | 
|---|
|  | 77 | self.code = gsub(self.code,"/%*","\1") | 
|---|
|  | 78 | self.code = gsub(self.code,"%*/","\2") | 
|---|
|  | 79 | self.code = gsub(self.code,"%b\1\2","") | 
|---|
|  | 80 | self.code = gsub(self.code,"\1","/%*") | 
|---|
|  | 81 | self.code = gsub(self.code,"\2","%*/") | 
|---|
|  | 82 | self.code = gsub(self.code,"%s*@%s*","@") -- eliminate spaces beside @ | 
|---|
|  | 83 | self.code = gsub(self.code,"%s?inline(%s)","%1") -- eliminate 'inline' keyword | 
|---|
| [10818] | 84 | self.code = gsub(self.code,"%)%s?override;",");") -- eliminate 'override' keyword... at least most of the times | 
|---|
| [2710] | 85 | --self.code = gsub(self.code,"%s?extern(%s)","%1") -- eliminate 'extern' keyword | 
|---|
|  | 86 | --self.code = gsub(self.code,"%s?virtual(%s)","%1") -- eliminate 'virtual' keyword | 
|---|
|  | 87 | --self.code = gsub(self.code,"public:","") -- eliminate 'public:' keyword | 
|---|
|  | 88 | self.code = gsub(self.code,"([^%w_])void%s*%*","%1_userdata ") -- substitute 'void*' | 
|---|
|  | 89 | self.code = gsub(self.code,"([^%w_])void%s*%*","%1_userdata ") -- substitute 'void*' | 
|---|
|  | 90 | self.code = gsub(self.code,"([^%w_])char%s*%*","%1_cstring ")  -- substitute 'char*' | 
|---|
|  | 91 | self.code = gsub(self.code,"([^%w_])lua_State%s*%*","%1_lstate ")  -- substitute 'lua_State*' | 
|---|
| [1650] | 92 |  | 
|---|
| [2710] | 93 | -- restore embedded Lua code | 
|---|
|  | 94 | self.code = gsub(self.code,"%#%[(%d+)%]%#", function (n) | 
|---|
|  | 95 | return L[tonumber(n)] | 
|---|
|  | 96 | end | 
|---|
|  | 97 | ) | 
|---|
|  | 98 | -- restore embedded C code | 
|---|
|  | 99 | self.code = gsub(self.code,"%#%<(%d+)%>%#", function (n) | 
|---|
|  | 100 | return C[tonumber(n)] | 
|---|
|  | 101 | end | 
|---|
|  | 102 | ) | 
|---|
|  | 103 | -- restore verbatim lines | 
|---|
|  | 104 | self.code = gsub(self.code,"%#(%d+)%#", function (n) | 
|---|
|  | 105 | return V[tonumber(n)] | 
|---|
|  | 106 | end | 
|---|
|  | 107 | ) | 
|---|
| [1650] | 108 |  | 
|---|
| [2710] | 109 | self.code = string.gsub(self.code, "\n%s*%$([^\n]+)", function (l) | 
|---|
|  | 110 | Verbatim(l.."\n") | 
|---|
|  | 111 | return "\n" | 
|---|
|  | 112 | end | 
|---|
|  | 113 | ) | 
|---|
| [1650] | 114 | end | 
|---|
|  | 115 |  | 
|---|
|  | 116 | -- translate verbatim | 
|---|
|  | 117 | function classPackage:preamble () | 
|---|
| [2710] | 118 | output('/*\n') | 
|---|
|  | 119 | output('** Lua binding: '..self.name..'\n') | 
|---|
|  | 120 | output('** Generated automatically by '..TOLUA_VERSION..' on '..date()..'.\n') | 
|---|
|  | 121 | output('*/\n\n') | 
|---|
| [1650] | 122 |  | 
|---|
| [2710] | 123 | output('#ifndef __cplusplus\n') | 
|---|
|  | 124 | output('#include <stdlib.h>\n') | 
|---|
|  | 125 | output('#endif\n') | 
|---|
|  | 126 | output('#include <string.h>\n\n') | 
|---|
| [8351] | 127 | output('#include <tolua++.h>\n\n') | 
|---|
| [1650] | 128 |  | 
|---|
| [2710] | 129 | if flags.H then | 
|---|
| [5752] | 130 | output('#include "'..flags.H..'"\n') | 
|---|
| [2710] | 131 | end | 
|---|
| [1650] | 132 |  | 
|---|
| [2710] | 133 | local i=1 | 
|---|
|  | 134 | while self[i] do | 
|---|
|  | 135 | self[i]:preamble() | 
|---|
|  | 136 | i = i+1 | 
|---|
|  | 137 | end | 
|---|
| [1650] | 138 |  | 
|---|
| [8729] | 139 | post_include_hook(self.name) | 
|---|
|  | 140 |  | 
|---|
| [8363] | 141 | output('\n') | 
|---|
|  | 142 | output('#ifdef ORXONOX_RELEASE\n') | 
|---|
|  | 143 | output('#  define TOLUA_RELEASE\n') | 
|---|
|  | 144 | output('#endif\n') | 
|---|
|  | 145 |  | 
|---|
| [2710] | 146 | if self:requirecollection(_collect) then | 
|---|
|  | 147 | output('\n') | 
|---|
|  | 148 | output('/* function to release collected object via destructor */') | 
|---|
|  | 149 | output('#ifdef __cplusplus\n') | 
|---|
|  | 150 | for i,v in pairs(_collect) do | 
|---|
|  | 151 | output('\nstatic int '..v..' (lua_State* tolua_S)') | 
|---|
|  | 152 | output('{') | 
|---|
|  | 153 | output(' '..i..'* self = ('..i..'*) tolua_tousertype(tolua_S,1,0);') | 
|---|
|  | 154 | output('    delete self;') | 
|---|
|  | 155 | output('    return 0;') | 
|---|
|  | 156 | output('}') | 
|---|
|  | 157 | end | 
|---|
|  | 158 | output('#endif\n\n') | 
|---|
|  | 159 | end | 
|---|
| [1650] | 160 |  | 
|---|
| [2710] | 161 | output('\n') | 
|---|
|  | 162 | output('/* function to register type */') | 
|---|
|  | 163 | output('static void tolua_reg_types (lua_State* tolua_S)') | 
|---|
|  | 164 | output('{') | 
|---|
|  | 165 | foreach(_usertype,function(n,v) output(' tolua_usertype(tolua_S,"',v,'");') end) | 
|---|
|  | 166 | if flags.t then | 
|---|
|  | 167 | output("#ifndef Mtolua_typeid\n#define Mtolua_typeid(L,TI,T)\n#endif\n") | 
|---|
|  | 168 | foreach(_usertype,function(n,v) output(' Mtolua_typeid(tolua_S,typeid(',v,'), "',v,'");') end) | 
|---|
|  | 169 | end | 
|---|
|  | 170 | output('}') | 
|---|
|  | 171 | output('\n') | 
|---|
| [1650] | 172 | end | 
|---|
|  | 173 |  | 
|---|
|  | 174 | -- register package | 
|---|
|  | 175 | -- write package open function | 
|---|
|  | 176 | function classPackage:register (pre) | 
|---|
| [2710] | 177 | pre = pre or '' | 
|---|
|  | 178 | push(self) | 
|---|
|  | 179 | output(pre.."/* Open function */") | 
|---|
|  | 180 | output(pre.."int tolua_"..self.name.."_open (lua_State* tolua_S)") | 
|---|
|  | 181 | output(pre.."{") | 
|---|
|  | 182 | output(pre.." tolua_open(tolua_S);") | 
|---|
|  | 183 | output(pre.." tolua_reg_types(tolua_S);") | 
|---|
|  | 184 | output(pre.." tolua_module(tolua_S,NULL,",self:hasvar(),");") | 
|---|
|  | 185 | output(pre.." tolua_beginmodule(tolua_S,NULL);") | 
|---|
|  | 186 | local i=1 | 
|---|
|  | 187 | while self[i] do | 
|---|
|  | 188 | self[i]:register(pre.."  ") | 
|---|
|  | 189 | i = i+1 | 
|---|
|  | 190 | end | 
|---|
|  | 191 | output(pre.." tolua_endmodule(tolua_S);") | 
|---|
|  | 192 | output(pre.." return 1;") | 
|---|
|  | 193 | output(pre.."}") | 
|---|
| [1650] | 194 |  | 
|---|
| [2710] | 195 | output("\n\n") | 
|---|
|  | 196 | output("#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501\n"); | 
|---|
|  | 197 | output(pre.."int luaopen_"..self.name.." (lua_State* tolua_S) {") | 
|---|
|  | 198 | output(pre.." return tolua_"..self.name.."_open(tolua_S);") | 
|---|
|  | 199 | output(pre.."};") | 
|---|
|  | 200 | output("#endif\n\n") | 
|---|
| [1650] | 201 |  | 
|---|
| [2710] | 202 | pop() | 
|---|
| [1650] | 203 | end | 
|---|
|  | 204 |  | 
|---|
|  | 205 | -- write header file | 
|---|
|  | 206 | function classPackage:header () | 
|---|
| [2710] | 207 | output('/*\n') output('** Lua binding: '..self.name..'\n') | 
|---|
|  | 208 | output('** Generated automatically by '..TOLUA_VERSION..' on '..date()..'.\n') | 
|---|
|  | 209 | output('*/\n\n') | 
|---|
| [1650] | 210 |  | 
|---|
| [2710] | 211 | if flags.H then | 
|---|
| [5752] | 212 | output('#include "'..flags.w..'/'..self.name..'Prereqs.h"\n') | 
|---|
| [2710] | 213 | output('/* Exported function */') | 
|---|
|  | 214 | output('_'..self.name..'Export') | 
|---|
|  | 215 | output('int  tolua_'..self.name..'_open (lua_State* tolua_S);') | 
|---|
|  | 216 | output('\n') | 
|---|
|  | 217 | end | 
|---|
| [1650] | 218 | end | 
|---|
|  | 219 |  | 
|---|
|  | 220 | -- Internal constructor | 
|---|
|  | 221 | function _Package (self) | 
|---|
| [2710] | 222 | setmetatable(self,classPackage) | 
|---|
|  | 223 | return self | 
|---|
| [1650] | 224 | end | 
|---|
|  | 225 |  | 
|---|
|  | 226 | -- Parse C header file with tolua directives | 
|---|
|  | 227 | -- *** Thanks to Ariel Manzur for fixing bugs in nested directives *** | 
|---|
|  | 228 | function extract_code(fn,s) | 
|---|
| [5752] | 229 | local code = '\n$#include "'..flags.w..'/'..fn..'"\n' | 
|---|
| [2710] | 230 | s= "\n" .. s .. "\n" -- add blank lines as sentinels | 
|---|
|  | 231 |  | 
|---|
|  | 232 | -- eliminate export macro problems in class declarations | 
|---|
|  | 233 | s = gsub(s, ' _%w*Export ', ' ') | 
|---|
|  | 234 |  | 
|---|
|  | 235 | local _,e,c,t = strfind(s, "\n([^\n]-)[Tt][Oo][Ll][Uu][Aa]_([^%s]*)[^\n]*\n") | 
|---|
|  | 236 | while e do | 
|---|
|  | 237 | t = strlower(t) | 
|---|
|  | 238 | if t == "begin" then | 
|---|
|  | 239 | _,e,c = strfind(s,"(.-)\n[^\n]*[Tt][Oo][Ll][Uu][Aa]_[Ee][Nn][Dd][^\n]*\n",e) | 
|---|
|  | 240 | if not e then | 
|---|
|  | 241 | tolua_error("Unbalanced 'tolua_begin' directive in header file") | 
|---|
|  | 242 | end | 
|---|
|  | 243 | end | 
|---|
|  | 244 | code = code .. c .. "\n" | 
|---|
|  | 245 | _,e,c,t = strfind(s, "\n([^\n]-)[Tt][Oo][Ll][Uu][Aa]_([^%s]*)[^\n]*\n",e) | 
|---|
|  | 246 | end | 
|---|
|  | 247 | return code | 
|---|
| [1650] | 248 | end | 
|---|
|  | 249 |  | 
|---|
|  | 250 | -- Constructor | 
|---|
|  | 251 | -- Expects the package name, the file extension, and the file text. | 
|---|
|  | 252 | function Package (name,fn) | 
|---|
| [2710] | 253 | local ext = "pkg" | 
|---|
| [1650] | 254 |  | 
|---|
| [2710] | 255 | -- open input file, if any | 
|---|
|  | 256 | if fn then | 
|---|
|  | 257 | local file | 
|---|
|  | 258 | if flags.f then | 
|---|
|  | 259 | if string.sub(flags.f, 1, 1) == '/' or string.sub(flags.f, 1, 1) == '\\' or (string.len(flags.f) > 1 and string.sub(flags.f, 2, 2) == ':') then | 
|---|
|  | 260 | file = flags.f | 
|---|
|  | 261 | else | 
|---|
|  | 262 | file = flags.w..'/'..flags.f | 
|---|
|  | 263 | end | 
|---|
|  | 264 | else | 
|---|
|  | 265 | file = flags.f | 
|---|
|  | 266 | end | 
|---|
|  | 267 | local st, msg = readfrom(file) | 
|---|
|  | 268 | if not st then | 
|---|
|  | 269 | error('#'..msg..' path: '..flags.f) | 
|---|
|  | 270 | end | 
|---|
|  | 271 | local _; _, _, ext = strfind(fn,".*%.(.*)$") | 
|---|
|  | 272 | end | 
|---|
|  | 273 | local code = "\n" .. read('*a') | 
|---|
|  | 274 | if ext == 'h' or ext == 'hpp' then | 
|---|
|  | 275 | code = extract_code(fn,code) | 
|---|
|  | 276 | end | 
|---|
| [1650] | 277 |  | 
|---|
| [2710] | 278 | -- close file | 
|---|
|  | 279 | if fn then | 
|---|
|  | 280 | readfrom() | 
|---|
|  | 281 | end | 
|---|
| [1650] | 282 |  | 
|---|
| [2710] | 283 | -- prepare working directory | 
|---|
|  | 284 | local current_path | 
|---|
|  | 285 | if not flags.w and flags.f then | 
|---|
|  | 286 | current_path = gsub(flags.f, '(/)[^/]*%.?[^/]*$', '%1') | 
|---|
|  | 287 | elseif flags.w then | 
|---|
|  | 288 | if not (string.sub(flags.w, string.len(flags.w)) == '/') then | 
|---|
|  | 289 | current_path = flags.w..'/' | 
|---|
|  | 290 | else | 
|---|
|  | 291 | current_path = flags.w | 
|---|
|  | 292 | end | 
|---|
|  | 293 | else | 
|---|
|  | 294 | current_path = '' | 
|---|
|  | 295 | end | 
|---|
| [1650] | 296 |  | 
|---|
| [2710] | 297 | -- deal with include directive | 
|---|
|  | 298 | local nsubst | 
|---|
|  | 299 | repeat | 
|---|
|  | 300 | code,nsubst = gsub(code,'\n%s*%$(.)file%s*"(.-)"([^\n]*)\n', | 
|---|
|  | 301 | function (kind,fn,extra) | 
|---|
|  | 302 | local _, _, ext = strfind(fn,".*%.(.*)$") | 
|---|
|  | 303 | local fp,msg = openfile(current_path..fn,'r') | 
|---|
|  | 304 | if not fp then | 
|---|
|  | 305 | error('#'..msg..': '..fn) | 
|---|
|  | 306 | end | 
|---|
|  | 307 | local s = read(fp,'*a') | 
|---|
|  | 308 | closefile(fp) | 
|---|
|  | 309 | if kind == 'c' or kind == 'h' then | 
|---|
|  | 310 | return extract_code(fn,s) | 
|---|
|  | 311 | elseif kind == 'p' then | 
|---|
|  | 312 | return "\n\n" .. s | 
|---|
|  | 313 | elseif kind == 'l' then | 
|---|
|  | 314 | return "\n$[--##"..fn.."\n" .. s .. "\n$]\n" | 
|---|
|  | 315 | elseif kind == 'i' then | 
|---|
|  | 316 | local t = {code=s} | 
|---|
|  | 317 | extra = string.gsub(extra, "^%s*,%s*", "") | 
|---|
|  | 318 | local pars = split_c_tokens(extra, ",") | 
|---|
|  | 319 | include_file_hook(t, fn, unpack(pars)) | 
|---|
|  | 320 | return "\n\n" .. t.code | 
|---|
|  | 321 | else | 
|---|
|  | 322 | error('#Invalid include directive (use $cfile, $pfile, $lfile or $ifile)') | 
|---|
|  | 323 | end | 
|---|
|  | 324 | end | 
|---|
|  | 325 | ) | 
|---|
|  | 326 | until nsubst==0 | 
|---|
| [1650] | 327 |  | 
|---|
| [2710] | 328 | -- deal with renaming directive | 
|---|
|  | 329 | repeat -- I don't know why this is necesary | 
|---|
|  | 330 | code,nsubst = gsub(code,'\n%s*%$renaming%s*(.-)%s*\n', function (r) appendrenaming(r) return "\n" end) | 
|---|
|  | 331 | until nsubst == 0 | 
|---|
|  | 332 |  | 
|---|
|  | 333 | local t = _Package(_Container{name=name, code=code}) | 
|---|
|  | 334 | push(t) | 
|---|
|  | 335 | preprocess_hook(t) | 
|---|
|  | 336 | t:preprocess() | 
|---|
|  | 337 | preparse_hook(t) | 
|---|
|  | 338 | t:parse(t.code) | 
|---|
|  | 339 | pop() | 
|---|
|  | 340 | return t | 
|---|
| [1650] | 341 | end | 
|---|
|  | 342 |  | 
|---|
|  | 343 |  | 
|---|