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