Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/gui/src/tolua/lua/package.lua @ 1650

Last change on this file since 1650 was 1650, checked in by rgrieder, 16 years ago

added preliminary automatic creation of tolua generator that creates the actual executable
(please don't ask about the egg-hen question…)

File size: 9.8 KB
Line 
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--  local temp = string.reverse(flags.H)
122--  local start1, end1 = string.find(temp, '/')
123--  local start2, end2 = string.find(temp, '\\')
124--  local res
125--  if not start1 == nil then
126--   if not start2 == nil then
127--    if start1 > start2 then
128--     res = string.sub(temp, 1, start2)
129--    else
130--     res = string.sub(temp, 1, start1)
131--    end
132--   else
133--    res = string.sub(temp, 1, start1)
134--   end
135--  elseif not start2 == nil then
136--   res = string.sub(temp, 1, start2)
137--  end
138--  res = string.reverse(res)
139  output('#include "tolua_bind.h"')
140  output('\n')
141 end
142
143 local i=1
144 while self[i] do
145  self[i]:preamble()
146  i = i+1
147 end
148
149        if self:requirecollection(_collect) then
150                output('\n')
151                output('/* function to release collected object via destructor */')
152                output('#ifdef __cplusplus\n')
153                for i,v in pairs(_collect) do
154                 output('\nstatic int '..v..' (lua_State* tolua_S)')
155                        output('{')
156                        output(' '..i..'* self = ('..i..'*) tolua_tousertype(tolua_S,1,0);')
157                        output('        delete self;')
158                        output('        return 0;')
159                        output('}')
160                end
161                output('#endif\n\n')
162        end
163
164 output('\n')
165 output('/* function to register type */')
166 output('static void tolua_reg_types (lua_State* tolua_S)')
167 output('{')
168 foreach(_usertype,function(n,v) output(' tolua_usertype(tolua_S,"',v,'");') end)
169        if flags.t then
170                output("#ifndef Mtolua_typeid\n#define Mtolua_typeid(L,TI,T)\n#endif\n")
171                foreach(_usertype,function(n,v) output(' Mtolua_typeid(tolua_S,typeid(',v,'), "',v,'");') end)
172        end
173 output('}')
174 output('\n')
175end
176
177-- register package
178-- write package open function
179function classPackage:register (pre)
180 pre = pre or ''
181 push(self)
182 output(pre.."/* Open function */")
183 output(pre.."int tolua_"..self.name.."_open (lua_State* tolua_S)")
184 output(pre.."{")
185 output(pre.." tolua_open(tolua_S);")
186 output(pre.." tolua_reg_types(tolua_S);")
187 output(pre.." tolua_module(tolua_S,NULL,",self:hasvar(),");")
188 output(pre.." tolua_beginmodule(tolua_S,NULL);")
189 local i=1
190 while self[i] do
191  self[i]:register(pre.."  ")
192  i = i+1
193 end
194 output(pre.." tolua_endmodule(tolua_S);")
195 output(pre.." return 1;")
196 output(pre.."}")
197
198 output("\n\n")
199 output("#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501\n");
200 output(pre.."int luaopen_"..self.name.." (lua_State* tolua_S) {")
201 output(pre.." return tolua_"..self.name.."_open(tolua_S);")
202 output(pre.."};")
203 output("#endif\n\n")
204
205        pop()
206end
207
208-- write header file
209function classPackage:header ()
210 output('/*\n') output('** Lua binding: '..self.name..'\n')
211 output('** Generated automatically by '..TOLUA_VERSION..' on '..date()..'.\n')
212 output('*/\n\n')
213
214 if not flags.h then
215  output('#include "../'..self.name..'Prereqs.h"\n')
216  output('/* Exported function */')
217  output('_'..self.name..'Export int  tolua_'..self.name..'_open (lua_State* tolua_S);')
218  output('\n')
219 end
220end
221
222-- Internal constructor
223function _Package (self)
224 setmetatable(self,classPackage)
225 return self
226end
227
228-- Parse C header file with tolua directives
229-- *** Thanks to Ariel Manzur for fixing bugs in nested directives ***
230function extract_code(fn,s)
231        local code = '\n$#include "'..fn..'"\n'
232        s= "\n" .. s .. "\n" -- add blank lines as sentinels
233        local _,e,c,t = strfind(s, "\n([^\n]-)[Tt][Oo][Ll][Uu][Aa]_([^%s]*)[^\n]*\n")
234        while e do
235                t = strlower(t)
236                if t == "begin" then
237                        _,e,c = strfind(s,"(.-)\n[^\n]*[Tt][Oo][Ll][Uu][Aa]_[Ee][Nn][Dd][^\n]*\n",e)
238                        if not e then
239                         tolua_error("Unbalanced 'tolua_begin' directive in header file")
240                        end
241                end
242                code = code .. c .. "\n"
243         _,e,c,t = strfind(s, "\n([^\n]-)[Tt][Oo][Ll][Uu][Aa]_([^%s]*)[^\n]*\n",e)
244        end
245        return code
246end
247
248-- Constructor
249-- Expects the package name, the file extension, and the file text.
250function Package (name,fn)
251 local ext = "pkg"
252
253 -- open input file, if any
254 if fn then
255  local st, msg = readfrom(flags.f)
256  if not st then
257   error('#'..msg)
258  end
259                local _; _, _, ext = strfind(fn,".*%.(.*)$")
260 end
261 local code = "\n" .. read('*a')
262        if ext == 'h' or ext == 'hpp' then
263         code = extract_code(fn,code)
264        end
265
266 -- close file
267 if fn then
268  readfrom()
269 end
270
271 -- deal with include directive
272 local nsubst
273 repeat
274  code,nsubst = gsub(code,'\n%s*%$(.)file%s*"(.-)"([^\n]*)\n',
275                function (kind,fn,extra)
276                        local _, _, ext = strfind(fn,".*%.(.*)$")
277                        local fp,msg = openfile(fn,'r')
278                        if not fp then
279                                error('#'..msg..': '..fn)
280                        end
281                        local s = read(fp,'*a')
282                        closefile(fp)
283                        if kind == 'c' or kind == 'h' then
284                                return extract_code(fn,s)
285                        elseif kind == 'p' then
286                                return "\n\n" .. s
287                        elseif kind == 'l' then
288                                return "\n$[--##"..fn.."\n" .. s .. "\n$]\n"
289                        elseif kind == 'i' then
290                                local t = {code=s}
291                                extra = string.gsub(extra, "^%s*,%s*", "")
292                                local pars = split_c_tokens(extra, ",")
293                                include_file_hook(t, fn, unpack(pars))
294                                return "\n\n" .. t.code
295                        else
296                                error('#Invalid include directive (use $cfile, $pfile, $lfile or $ifile)')
297                        end
298                end)
299 until nsubst==0
300
301 -- deal with renaming directive
302 repeat -- I don't know why this is necesary
303        code,nsubst = gsub(code,'\n%s*%$renaming%s*(.-)%s*\n', function (r) appendrenaming(r) return "\n" end)
304 until nsubst == 0
305
306 local t = _Package(_Container{name=name, code=code})
307 push(t)
308 preprocess_hook(t)
309 t:preprocess()
310 preparse_hook(t)
311 t:parse(t.code)
312 pop()
313 return t
314end
315
316
Note: See TracBrowser for help on using the repository browser.