Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/pch/src/tolua/lua/package.lua @ 3129

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

Fixed tolua update:

  • Too many changes in package.lua (somehow glitched..)
  • Lua has a problem with the variadic function used.
  • Property svn:eol-style set to native
File size: 12.9 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('    Mtolua_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
160    if flags.t then
161        output("#ifndef Mtolua_typeid\n#define Mtolua_typeid(L,TI,T)\n#endif\n")
162    end
163    foreach(_usertype,function(n,v)
164        if (not _global_classes[v]) or _global_classes[v]:check_public_access() then
165            output(' tolua_usertype(tolua_S,"',v,'");')
166            if flags.t then
167                output(' Mtolua_typeid(tolua_S,typeid(',v,'), "',v,'");')
168            end
169        end
170    end)
171 output('}')
172    output('\n')
173end
174
175-- register package
176-- write package open function
177function classPackage:register (pre)
178    pre = pre or ''
179    push(self)
180    output(pre.."/* Open function */")
181    output(pre.."int tolua_"..self.name.."_open (lua_State* tolua_S)")
182    output(pre.."{")
183    output(pre.." tolua_open(tolua_S);")
184    output(pre.." tolua_reg_types(tolua_S);")
185    output(pre.." tolua_module(tolua_S,NULL,",self:hasvar(),");")
186    output(pre.." tolua_beginmodule(tolua_S,NULL);")
187    local i=1
188    while self[i] do
189        self[i]:register(pre.."  ")
190        i = i+1
191    end
192    output(pre.." tolua_endmodule(tolua_S);")
193    output(pre.." return 1;")
194    output(pre.."}")
195
196    output("\n\n")
197    output("#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501\n");
198    output(pre.."int luaopen_"..self.name.." (lua_State* tolua_S) {")
199    output(pre.." return tolua_"..self.name.."_open(tolua_S);")
200    output(pre.."};")
201    output("#endif\n\n")
202
203    pop()
204end
205
206-- write header file
207function classPackage:header ()
208    output('/*\n') output('** Lua binding: '..self.name..'\n')
209    output('** Generated automatically by '..TOLUA_VERSION..' on '..date()..'.\n')
210    output('*/\n\n')
211
212    if flags.H then
213        local package_lower = string.lower(self.name)
214        output('#include "'..package_lower..'/'..self.name..'Prereqs.h"\n')
215        output('/* Exported function */')
216        output('_'..self.name..'Export')
217        output('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 "'..string.lower(flags.n)..'/'..fn..'"\n'
232    s= "\n" .. s .. "\n" -- add blank lines as sentinels
233
234    -- eliminate export macro problems in class declarations
235    s = gsub(s, ' _%w*Export ', ' ')
236
237    local _,e,c,t = strfind(s, "\n([^\n]-)[Tt][Oo][Ll][Uu][Aa]_([^%s]*)[^\n]*\n")
238    while e do
239        t = strlower(t)
240        if t == "begin" then
241            _,e,c = strfind(s,"(.-)\n[^\n]*[Tt][Oo][Ll][Uu][Aa]_[Ee][Nn][Dd][^\n]*\n",e)
242            if not e then
243             tolua_error("Unbalanced 'tolua_begin' directive in header file")
244            end
245        end
246        code = code .. c .. "\n"
247        _,e,c,t = strfind(s, "\n([^\n]-)[Tt][Oo][Ll][Uu][Aa]_([^%s]*)[^\n]*\n",e)
248    end
249    return code
250end
251
252-- Constructor
253-- Expects the package name, the file extension, and the file text.
254function Package (name,fn)
255    local ext = "pkg"
256
257    -- open input file, if any
258    local st,msg
259    if fn then
260        local file
261        if flags.f then
262            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
263                file = flags.f
264            else
265                file = flags.w..'/'..flags.f
266            end
267        else
268            file = flags.f
269        end
270        st, msg = readfrom(file)
271        if not st then
272            error('#'..msg..' path: '..flags.f)
273        end
274        local _; _, _, ext = strfind(fn,".*%.(.*)$")
275    end
276    local code
277    if ext == 'pkg' then
278        code = prep(st)
279    else
280        code = "\n" .. read('*a')
281        if ext == 'h' or ext == 'hpp' then
282            code = extract_code(fn,code)
283        end
284    end
285
286    -- close file
287    if fn then
288        readfrom()
289    end
290
291    -- prepare working directory
292    local current_path
293    if not flags.w and flags.f then
294        current_path = gsub(flags.f, '(/)[^/]*%.?[^/]*$', '%1')
295    elseif flags.w then
296        if not (string.sub(flags.w, string.len(flags.w)) == '/') then
297            current_path = flags.w..'/'
298        else
299            current_path = flags.w
300        end
301    else
302        current_path = ''
303    end
304
305    -- deal with include directive
306    local nsubst
307    repeat
308        code,nsubst = gsub(code,'\n%s*%$(.)file%s*"(.-)"([^\n]*)\n',
309            function (kind,fn,extra)
310                local _, _, ext = strfind(fn,".*%.(.*)$")
311                local fp,msg = openfile(current_path..fn,'r')
312                if not fp then
313                    error('#'..msg..': '..fn)
314                end
315                if kind == 'p' then
316                    local s = prep(fp)
317                    closefile(fp)
318                    return s
319                end
320                local s = read(fp,'*a')
321                closefile(fp)
322                if kind == 'c' or kind == 'h' then
323                    return extract_code(fn,s)
324                elseif kind == 'l' then
325                    return "\n$[--##"..fn.."\n" .. s .. "\n$]\n"
326                elseif kind == 'i' then
327                    local t = {code=s}
328                    extra = string.gsub(extra, "^%s*,%s*", "")
329                    local pars = split_c_tokens(extra, ",")
330                    include_file_hook(t, fn, unpack(pars))
331                    return "\n\n" .. t.code
332                else
333                    error('#Invalid include directive (use $cfile, $pfile, $lfile or $ifile)')
334                end
335            end
336        )
337    until nsubst==0
338
339    -- deal with renaming directive
340    repeat -- I don't know why this is necesary
341        code,nsubst = gsub(code,'\n%s*%$renaming%s*(.-)%s*\n', function (r) appendrenaming(r) return "\n" end)
342    until nsubst == 0
343
344    local t = _Package(_Container{name=name, code=code})
345    push(t)
346    preprocess_hook(t)
347    t:preprocess()
348    preparse_hook(t)
349    t:parse(t.code)
350    pop()
351    return t
352end
353
354
355setmetatable(_extra_parameters, { __index = _G })
356
357function prep(file)
358
359    local chunk = {'local __ret = {"\\n"}\n'}
360    for line in file:lines() do
361        if string.find(line, "^##") then
362            table.insert(chunk, string.sub(line, 3) .. "\n")
363        else
364            local last = 1
365            for text, expr, index in string.gfind(line, "(.-)$(%b())()") do 
366                last = index
367                if text ~= "" then
368                    table.insert(chunk, string.format('table.insert(__ret, %q )', text))
369                end
370                table.insert(chunk, string.format('table.insert(__ret, %s )', expr))
371            end
372            table.insert(chunk, string.format('table.insert(__ret, %q)\n',
373                                string.sub(line, last).."\n"))
374        end
375    end
376    table.insert(chunk, '\nreturn table.concat(__ret)\n')
377    local f,e = loadstring(table.concat(chunk))
378    if e then
379        error("#"..e)
380    end
381    setfenv(f, _extra_parameters)
382    return f()
383end
Note: See TracBrowser for help on using the repository browser.