Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/buildsystem/src/tolua/lua/package.lua @ 2233

Last change on this file since 2233 was 2233, checked in by rgrieder, 15 years ago

Added 'w' argument for tolua. That specifies the working directory when including files in the package.
If 'w' is not specified, the path of the package file is used. And if even that is not given, the application working directory is used.

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