Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/tolua/lua/package.lua @ 4906

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

Merged buildsystem3 containing buildsystem2 containing Adi's buildsystem branch back to the trunk.
Please update the media directory if you were not using buildsystem3 before.

  • Property svn:eol-style set to native
File size: 11.6 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    )
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)
50                                               tinsert(C,c)
51                                               return "\n#<"..getn(C)..">#"
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)
58                                               tinsert(C,c)
59                                               return "\n#<"..getn(C)..">#"
60                                           end
61    )
62
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'
65
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    )
73
74    -- perform global substitution
75
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
84    --self.code = gsub(self.code,"%s?extern(%s)","%1") -- eliminate 'extern' keyword
85    --self.code = gsub(self.code,"%s?virtual(%s)","%1") -- eliminate 'virtual' keyword
86    --self.code = gsub(self.code,"public:","") -- eliminate 'public:' keyword
87    self.code = gsub(self.code,"([^%w_])void%s*%*","%1_userdata ") -- substitute 'void*'
88    self.code = gsub(self.code,"([^%w_])void%s*%*","%1_userdata ") -- substitute 'void*'
89    self.code = gsub(self.code,"([^%w_])char%s*%*","%1_cstring ")  -- substitute 'char*'
90    self.code = gsub(self.code,"([^%w_])lua_State%s*%*","%1_lstate ")  -- substitute 'lua_State*'
91
92    -- restore embedded Lua code
93    self.code = gsub(self.code,"%#%[(%d+)%]%#", function (n)
94                                                    return L[tonumber(n)]
95                                                end
96    )
97    -- restore embedded C code
98    self.code = gsub(self.code,"%#%<(%d+)%>%#", function (n)
99                                                    return C[tonumber(n)]
100                                                end
101    )
102    -- restore verbatim lines
103    self.code = gsub(self.code,"%#(%d+)%#", function (n)
104                                                return V[tonumber(n)]
105                                            end
106    )
107
108    self.code = string.gsub(self.code, "\n%s*%$([^\n]+)", function (l)
109                                                              Verbatim(l.."\n")
110                                                              return "\n"
111                                                          end
112    )
113end
114
115-- translate verbatim
116function classPackage:preamble ()
117    output('/*\n')
118    output('** Lua binding: '..self.name..'\n')
119    output('** Generated automatically by '..TOLUA_VERSION..' on '..date()..'.\n')
120    output('*/\n\n')
121
122    output('#ifndef __cplusplus\n')
123    output('#include <stdlib.h>\n')
124    output('#endif\n')
125    output('#include <string.h>\n\n')
126    output('#include <tolua/tolua++.h>\n\n')
127
128    if flags.H then
129        local header = gsub(flags.H, '^.-([%w_]*%.[%w_]*)$', '%1')
130        local package_lower = string.lower(self.name)
131        output('#include "'..header..'"\n')
132    end
133
134    local i=1
135    while self[i] do
136        self[i]:preamble()
137        i = i+1
138    end
139
140    if self:requirecollection(_collect) then
141        output('\n')
142        output('/* function to release collected object via destructor */')
143        output('#ifdef __cplusplus\n')
144        for i,v in pairs(_collect) do
145            output('\nstatic int '..v..' (lua_State* tolua_S)')
146            output('{')
147            output(' '..i..'* self = ('..i..'*) tolua_tousertype(tolua_S,1,0);')
148            output('    delete self;')
149            output('    return 0;')
150            output('}')
151        end
152        output('#endif\n\n')
153    end
154
155    output('\n')
156    output('/* function to register type */')
157    output('static void tolua_reg_types (lua_State* tolua_S)')
158    output('{')
159    foreach(_usertype,function(n,v) output(' tolua_usertype(tolua_S,"',v,'");') end)
160    if flags.t then
161        output("#ifndef Mtolua_typeid\n#define Mtolua_typeid(L,TI,T)\n#endif\n")
162        foreach(_usertype,function(n,v) output(' Mtolua_typeid(tolua_S,typeid(',v,'), "',v,'");') end)
163    end
164    output('}')
165    output('\n')
166end
167
168-- register package
169-- write package open function
170function classPackage:register (pre)
171    pre = pre or ''
172    push(self)
173    output(pre.."/* Open function */")
174    output(pre.."int tolua_"..self.name.."_open (lua_State* tolua_S)")
175    output(pre.."{")
176    output(pre.." tolua_open(tolua_S);")
177    output(pre.." tolua_reg_types(tolua_S);")
178    output(pre.." tolua_module(tolua_S,NULL,",self:hasvar(),");")
179    output(pre.." tolua_beginmodule(tolua_S,NULL);")
180    local i=1
181    while self[i] do
182        self[i]:register(pre.."  ")
183        i = i+1
184    end
185    output(pre.." tolua_endmodule(tolua_S);")
186    output(pre.." return 1;")
187    output(pre.."}")
188
189    output("\n\n")
190    output("#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501\n");
191    output(pre.."int luaopen_"..self.name.." (lua_State* tolua_S) {")
192    output(pre.." return tolua_"..self.name.."_open(tolua_S);")
193    output(pre.."};")
194    output("#endif\n\n")
195
196    pop()
197end
198
199-- write header file
200function classPackage:header ()
201    output('/*\n') output('** Lua binding: '..self.name..'\n')
202    output('** Generated automatically by '..TOLUA_VERSION..' on '..date()..'.\n')
203    output('*/\n\n')
204
205    if flags.H then
206        local package_lower = string.lower(self.name)
207        output('#include "'..package_lower..'/'..self.name..'Prereqs.h"\n')
208        output('/* Exported function */')
209        output('_'..self.name..'Export')
210        output('int  tolua_'..self.name..'_open (lua_State* tolua_S);')
211        output('\n')
212    end
213end
214
215-- Internal constructor
216function _Package (self)
217    setmetatable(self,classPackage)
218    return self
219end
220
221-- Parse C header file with tolua directives
222-- *** Thanks to Ariel Manzur for fixing bugs in nested directives ***
223function extract_code(fn,s)
224    local code = '\n$#include "'..string.lower(flags.n)..'/'..fn..'"\n'
225    s= "\n" .. s .. "\n" -- add blank lines as sentinels
226
227    -- eliminate export macro problems in class declarations
228    s = gsub(s, ' _%w*Export ', ' ')
229
230    local _,e,c,t = strfind(s, "\n([^\n]-)[Tt][Oo][Ll][Uu][Aa]_([^%s]*)[^\n]*\n")
231    while e do
232        t = strlower(t)
233        if t == "begin" then
234            _,e,c = strfind(s,"(.-)\n[^\n]*[Tt][Oo][Ll][Uu][Aa]_[Ee][Nn][Dd][^\n]*\n",e)
235            if not e then
236             tolua_error("Unbalanced 'tolua_begin' directive in header file")
237            end
238        end
239        code = code .. c .. "\n"
240        _,e,c,t = strfind(s, "\n([^\n]-)[Tt][Oo][Ll][Uu][Aa]_([^%s]*)[^\n]*\n",e)
241    end
242    return code
243end
244
245-- Constructor
246-- Expects the package name, the file extension, and the file text.
247function Package (name,fn)
248    local ext = "pkg"
249
250    -- open input file, if any
251    if fn then
252        local file
253        if flags.f then
254            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
255                file = flags.f
256            else
257                file = flags.w..'/'..flags.f
258            end
259        else
260            file = flags.f
261        end
262        local st, msg = readfrom(file)
263        if not st then
264            error('#'..msg..' path: '..flags.f)
265        end
266        local _; _, _, ext = strfind(fn,".*%.(.*)$")
267    end
268    local code = "\n" .. read('*a')
269    if ext == 'h' or ext == 'hpp' then
270        code = extract_code(fn,code)
271    end
272
273    -- close file
274    if fn then
275        readfrom()
276    end
277
278    -- prepare working directory
279    local current_path
280    if not flags.w and flags.f then
281        current_path = gsub(flags.f, '(/)[^/]*%.?[^/]*$', '%1')
282    elseif flags.w then
283        if not (string.sub(flags.w, string.len(flags.w)) == '/') then
284            current_path = flags.w..'/'
285        else
286            current_path = flags.w
287        end
288    else
289        current_path = ''
290    end
291
292    -- deal with include directive
293    local nsubst
294    repeat
295        code,nsubst = gsub(code,'\n%s*%$(.)file%s*"(.-)"([^\n]*)\n',
296            function (kind,fn,extra)
297                local _, _, ext = strfind(fn,".*%.(.*)$")
298                local fp,msg = openfile(current_path..fn,'r')
299                if not fp then
300                    error('#'..msg..': '..fn)
301                end
302                local s = read(fp,'*a')
303                closefile(fp)
304                if kind == 'c' or kind == 'h' then
305                    return extract_code(fn,s)
306                elseif kind == 'p' then
307                    return "\n\n" .. s
308                elseif kind == 'l' then
309                    return "\n$[--##"..fn.."\n" .. s .. "\n$]\n"
310                elseif kind == 'i' then
311                    local t = {code=s}
312                    extra = string.gsub(extra, "^%s*,%s*", "")
313                    local pars = split_c_tokens(extra, ",")
314                    include_file_hook(t, fn, unpack(pars))
315                    return "\n\n" .. t.code
316                else
317                    error('#Invalid include directive (use $cfile, $pfile, $lfile or $ifile)')
318                end
319            end
320        )
321    until nsubst==0
322
323    -- deal with renaming directive
324    repeat -- I don't know why this is necesary
325        code,nsubst = gsub(code,'\n%s*%$renaming%s*(.-)%s*\n', function (r) appendrenaming(r) return "\n" end)
326    until nsubst == 0
327
328    local t = _Package(_Container{name=name, code=code})
329    push(t)
330    preprocess_hook(t)
331    t:preprocess()
332    preparse_hook(t)
333    t:parse(t.code)
334    pop()
335    return t
336end
337
338
Note: See TracBrowser for help on using the repository browser.