Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/pch/src/tolua/lua/declaration.lua @ 3127

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

Update to tolua 1.0.93

  • Property svn:eol-style set to native
File size: 17.3 KB
Line 
1-- tolua: declaration 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-- Declaration class
14-- Represents variable, function, or argument declaration.
15-- Stores the following fields:
16--  mod  = type modifiers
17--  type = type
18--  ptr  = "*" or "&", if representing a pointer or a reference
19--  name = name
20--  dim  = dimension, if a vector
21--  def  = default value, if any (only for arguments)
22--  ret  = "*" or "&", if value is to be returned (only for arguments)
23classDeclaration = {
24    mod = '',
25    type = '',
26    ptr = '',
27    name = '',
28    dim = '',
29    ret = '',
30    def = ''
31}
32classDeclaration.__index = classDeclaration
33setmetatable(classDeclaration,classFeature)
34
35-- Create an unique variable name
36function create_varname ()
37    if not _varnumber then _varnumber = 0 end
38    _varnumber = _varnumber + 1
39    return "tolua_var_".._varnumber
40end
41
42-- Check declaration name
43-- It also identifies default values
44function classDeclaration:checkname ()
45
46    if strsub(self.name,1,1) == '[' and not findtype(self.type) then
47        self.name = self.type..self.name
48        local m = split(self.mod,'%s%s*')
49        self.type = m[m.n]
50        self.mod = concat(m,1,m.n-1)
51    end
52
53    local t = split(self.name,'=')
54    if t.n==2 then
55        self.name = t[1]
56        self.def = find_enum_var(t[t.n])
57    end
58
59    local b,e,d = strfind(self.name,"%[(.-)%]")
60    if b then
61        self.name = strsub(self.name,1,b-1)
62        self.dim = find_enum_var(d)
63    end
64
65
66    if self.type ~= '' and self.type ~= 'void' and self.name == '' then
67        self.name = create_varname()
68    elseif self.kind=='var' then
69        if self.type=='' and self.name~='' then
70            self.type = self.type..self.name
71            self.name = create_varname()
72        elseif findtype(self.name) then
73            if self.type=='' then self.type = self.name
74            else self.type = self.type..' '..self.name end
75            self.name = create_varname()
76        end
77    end
78
79    -- adjust type of string
80    if self.type == 'char' and self.dim ~= '' then
81        self.type = 'char*'
82    end
83
84    if self.kind and self.kind == 'var' then
85        self.name = string.gsub(self.name, ":.*$", "") -- ???
86    end
87end
88
89-- Check declaration type
90-- Substitutes typedef's.
91function classDeclaration:checktype ()
92
93    -- check if there is a pointer to basic type
94    local basic = isbasic(self.type)
95    if self.kind == 'func' and basic=='number' and string.find(self.ptr, "%*") then
96        self.type = '_userdata'
97        self.ptr = ""
98    end
99    if basic and self.ptr~='' then
100        self.ret = self.ptr
101        self.ptr = nil
102        if isbasic(self.type) == 'number' then
103            self.return_userdata = true
104        end
105    end
106
107    -- check if there is array to be returned
108    if self.dim~='' and self.ret~='' then
109        error('#invalid parameter: cannot return an array of values')
110    end
111    -- restore 'void*' and 'string*'
112    if self.type == '_userdata' then self.type = 'void*'
113    elseif self.type == '_cstring' then self.type = 'char*'
114    elseif self.type == '_lstate' then self.type = 'lua_State*'
115    end
116
117    -- resolve types inside the templates
118    if self.type then
119        self.type = resolve_template_types(self.type)
120    end
121
122    --
123    -- -- if returning value, automatically set default value
124    -- if self.ret ~= '' and self.def == '' then
125    --  self.def = '0'
126    -- end
127    --
128
129end
130
131function resolve_template_types(type)
132
133    if isbasic(type) then
134        return type
135    end
136    local b,_,m = string.find(type, "(%b<>)")
137    if b then
138
139        m = split_c_tokens(string.sub(m, 2, -2), ",")
140        for i=1, table.getn(m) do
141            m[i] = string.gsub(m[i],"%s*([%*&])", "%1")
142            if not isbasic(m[i]) then
143                if not isenum(m[i]) then _, m[i] = applytypedef("", m[i]) end
144                m[i] = findtype(m[i]) or m[i]
145                m[i] = resolve_template_types(m[i])
146            end
147        end
148
149        local b,i
150        type,b,i = break_template(type)
151        --print("concat is ",concat(m, 1, m.n))
152        local template_part = "<"..concat(m, 1, m.n, ",")..">"
153        type = rebuild_template(type, b, template_part)
154        type = string.gsub(type, ">>", "> >")
155    end
156    return type
157end
158
159function break_template(s)
160    local b,e,timpl = string.find(s, "(%b<>)")
161    if timpl then
162        s = string.gsub(s, "%b<>", "")
163        return s, b, timpl
164    else
165        return s, 0, nil
166    end
167end
168
169function rebuild_template(s, b, timpl)
170
171    if b == 0 then
172        return s
173    end
174
175    return string.sub(s, 1, b-1)..timpl..string.sub(s, b, -1)
176end
177
178-- Print method
179function classDeclaration:print (ident,close)
180    print(ident.."Declaration{")
181    print(ident.." mod  = '"..self.mod.."',")
182    print(ident.." type = '"..self.type.."',")
183    print(ident.." ptr  = '"..self.ptr.."',")
184    print(ident.." name = '"..self.name.."',")
185    print(ident.." dim  = '"..self.dim.."',")
186    print(ident.." def  = '"..self.def.."',")
187    print(ident.." ret  = '"..self.ret.."',")
188    print(ident.."}"..close)
189end
190
191-- check if array of values are returned to Lua
192function classDeclaration:requirecollection (t)
193    if self.mod ~= 'const' and
194        self.dim and self.dim ~= '' and
195                 not isbasic(self.type) and
196                 self.ptr == '' and self:check_public_access() then
197        local type = gsub(self.type,"%s*const%s+","")
198        t[type] = "tolua_collect_" .. clean_template(type)
199        return true
200    end
201    return false
202end
203
204-- declare tag
205function classDeclaration:decltype ()
206
207    self.type = typevar(self.type)
208    if strfind(self.mod,'const') then
209        self.type = 'const '..self.type
210        self.mod = gsub(self.mod,'const%s*','')
211    end
212end
213
214
215-- output type checking
216function classDeclaration:outchecktype (narg)
217    local def
218    local t = isbasic(self.type)
219    if self.def~='' then
220        def = 1
221    else
222        def = 0
223    end
224    if self.dim ~= '' then
225        --if t=='string' then
226        --    return 'tolua_isstringarray(tolua_S,'..narg..','..def..',&tolua_err)'
227        --else
228        return '!tolua_istable(tolua_S,'..narg..',0,&tolua_err)'
229        --end
230    elseif t then
231        return '!tolua_is'..t..'(tolua_S,'..narg..','..def..',&tolua_err)'
232    else
233        local is_func = get_is_function(self.type)
234        if self.ptr == '&' or self.ptr == '' then
235            return '(tolua_isvaluenil(tolua_S,'..narg..',&tolua_err) || !'..is_func..'(tolua_S,'..narg..',"'..self.type..'",'..def..',&tolua_err))'
236        else
237            return '!'..is_func..'(tolua_S,'..narg..',"'..self.type..'",'..def..',&tolua_err)'
238        end
239   end
240end
241
242function classDeclaration:builddeclaration (narg, cplusplus)
243    local array = self.dim ~= '' and tonumber(self.dim)==nil
244    local line = ""
245    local ptr = ''
246    local mod
247    local type = self.type
248    local nctype = gsub(self.type,'const%s+','')
249    if self.dim ~= '' then
250        type = gsub(self.type,'const%s+','')  -- eliminates const modifier for arrays
251    end
252    if self.ptr~='' and not isbasic(type) then ptr = '*' end
253    line = concatparam(line," ",self.mod,type,ptr)
254    if array then
255        line = concatparam(line,'*')
256    end
257    line = concatparam(line,self.name)
258    if self.dim ~= '' then
259        if tonumber(self.dim)~=nil then
260            line = concatparam(line,'[',self.dim,'];')
261        else
262            if cplusplus then
263                line = concatparam(line,' = Mtolua_new_dim(',type,ptr,', '..self.dim..');')
264            else
265                line = concatparam(line,' = (',type,ptr,'*)',
266                'malloc((',self.dim,')*sizeof(',type,ptr,'));')
267            end
268        end
269    else
270    local t = isbasic(type)
271    line = concatparam(line,' = ')
272    if t == 'state' then
273        line = concatparam(line, 'tolua_S;')
274    else
275        --print("t is "..tostring(t)..", ptr is "..tostring(self.ptr))
276        if t == 'number' and string.find(self.ptr, "%*") then
277            t = 'userdata'
278        end
279        if not t and ptr=='' then line = concatparam(line,'*') end
280            line = concatparam(line,'((',self.mod,type)
281            if not t then
282                line = concatparam(line,'*')
283            end
284            line = concatparam(line,') ')
285            if isenum(nctype) then
286                line = concatparam(line,'(int) ')
287            end
288            local def = 0
289            if self.def ~= '' then
290                def = self.def
291                if (ptr == '' or self.ptr == '&') and not t then
292                    def = "(void*)&(const "..type..")"..def
293                end
294            end
295            if t then
296                line = concatparam(line,'tolua_to'..t,'(tolua_S,',narg,',',def,'));')
297            else
298                local to_func = get_to_function(type)
299                line = concatparam(line,to_func..'(tolua_S,',narg,',',def,'));')
300            end
301        end
302    end
303    return line
304end
305
306-- Declare variable
307function classDeclaration:declare (narg)
308    if self.dim ~= '' and tonumber(self.dim)==nil then
309        output('#ifdef __cplusplus\n')
310        output(self:builddeclaration(narg,true))
311        output('#else\n')
312        output(self:builddeclaration(narg,false))
313        output('#endif\n')
314    else
315        output(self:builddeclaration(narg,false))
316    end
317end
318
319-- Get parameter value
320function classDeclaration:getarray (narg)
321    if self.dim ~= '' then
322        local type = gsub(self.type,'const ','')
323        output('  {')
324        output('#ifndef TOLUA_RELEASE\n')
325        local def; if self.def~='' then def=1 else def=0 end
326        local t = isbasic(type)
327        if (t) then
328            output('   if (!tolua_is'..t..'array(tolua_S,',narg,',',self.dim,',',def,',&tolua_err))')
329        else
330            output('   if (!tolua_isusertypearray(tolua_S,',narg,',"',type,'",',self.dim,',',def,',&tolua_err))')
331        end
332        output('    goto tolua_lerror;')
333        output('   else\n')
334        output('#endif\n')
335        output('   {')
336        output('    int i;')
337        output('    for(i=0; i<'..self.dim..';i++)')
338        local t = isbasic(type)
339        local ptr = ''
340        if self.ptr~='' then ptr = '*' end
341        output('   ',self.name..'[i] = ')
342        if not t and ptr=='' then output('*') end
343        output('((',type)
344        if not t then
345            output('*')
346        end
347        output(') ')
348        local def = 0
349        if self.def ~= '' then def = self.def end
350        if t then
351            output('tolua_tofield'..t..'(tolua_S,',narg,',i+1,',def,'));')
352        else
353            output('tolua_tofieldusertype(tolua_S,',narg,',i+1,',def,'));')
354        end
355        output('   }')
356        output('  }')
357    end
358end
359
360-- Get parameter value
361function classDeclaration:setarray (narg)
362    if not strfind(self.type,'const%s+') and self.dim ~= '' then
363        local type = gsub(self.type,'const ','')
364        output('  {')
365        output('   int i;')
366        output('   for(i=0; i<'..self.dim..';i++)')
367        local t,ct = isbasic(type)
368        if t then
369            output('    tolua_pushfield'..t..'(tolua_S,',narg,',i+1,(',ct,')',self.name,'[i]);')
370        else
371            if self.ptr == '' then
372                output('   {')
373                output('#ifdef __cplusplus\n')
374                output('    void* tolua_obj = Mtolua_new((',type,')(',self.name,'[i]));')
375                output('    tolua_pushfieldusertype_and_takeownership(tolua_S,',narg,',i+1,tolua_obj,"',type,'");')
376                output('#else\n')
377                output('    void* tolua_obj = tolua_copy(tolua_S,(void*)&',self.name,'[i],sizeof(',type,'));')
378                output('    tolua_pushfieldusertype(tolua_S,',narg,',i+1,tolua_obj,"',type,'");')
379                output('#endif\n')
380                output('   }')
381            else
382                output('   tolua_pushfieldusertype(tolua_S,',narg,',i+1,(void*)',self.name,'[i],"',type,'");')
383            end
384        end
385        output('  }')
386    end
387end
388
389-- Free dynamically allocated array
390function classDeclaration:freearray ()
391    if self.dim ~= '' and tonumber(self.dim)==nil then
392        output('#ifdef __cplusplus\n')
393        output('  Mtolua_delete_dim(',self.name,');')
394        output('#else\n')
395        output('  free(',self.name,');')
396        output('#endif\n')
397    end
398end
399
400-- Pass parameter
401function classDeclaration:passpar ()
402    if self.ptr=='&' and not isbasic(self.type) then
403        output('*'..self.name)
404    elseif self.ret=='*' then
405        output('&'..self.name)
406    else
407        output(self.name)
408    end
409end
410
411-- Return parameter value
412function classDeclaration:retvalue ()
413    if self.ret ~= '' then
414        local t,ct = isbasic(self.type)
415        if t and t~='' then
416            output('   tolua_push'..t..'(tolua_S,(',ct,')'..self.name..');')
417        else
418            local push_func = get_push_function(self.type)
419            output('   ',push_func,'(tolua_S,(void*)'..self.name..',"',self.type,'");')
420        end
421        return 1
422    end
423    return 0
424end
425
426-- Internal constructor
427function _Declaration (t)
428
429    setmetatable(t,classDeclaration)
430    t:buildnames()
431    t:checkname()
432    t:checktype()
433    local ft = findtype(t.type) or t.type
434    if not isenum(ft) then
435        t.mod, t.type = applytypedef(t.mod, ft)
436    end
437
438    if t.kind=="var" and (string.find(t.mod, "tolua_property%s") or string.find(t.mod, "tolua_property$")) then
439        t.mod = string.gsub(t.mod, "tolua_property", "tolua_property__"..get_property_type())
440    end
441
442    return t
443end
444
445-- Constructor
446-- Expects the string declaration.
447-- The kind of declaration can be "var" or "func".
448function Declaration (s,kind,is_parameter)
449
450    -- eliminate spaces if default value is provided
451    s = gsub(s,"%s*=%s*","=")
452    s = gsub(s, "%s*<", "<")
453
454    local defb,tmpdef
455    defb,_,tmpdef = string.find(s, "(=.*)$")
456    if defb then
457        s = string.gsub(s, "=.*$", "")
458    else
459        tmpdef = ''
460    end
461    if kind == "var" then
462        -- check the form: void
463        if s == '' or s == 'void' then
464            return _Declaration{type = 'void', kind = kind, is_parameter = is_parameter}
465        end
466    end
467
468    -- check the form: mod type*& name
469    local t = split_c_tokens(s,'%*%s*&')
470    if t.n == 2 then
471        if kind == 'func' then
472            error("#invalid function return type: "..s)
473        end
474        --local m = split(t[1],'%s%s*')
475        local m = split_c_tokens(t[1],'%s+')
476        return _Declaration {
477            name = t[2]..tmpdef,
478            ptr = '*',
479            ret = '&',
480            --type = rebuild_template(m[m.n], tb, timpl),
481            type = m[m.n],
482            mod = concat(m,1,m.n-1),
483            is_parameter = is_parameter,
484            kind = kind
485        }
486    end
487
488    -- check the form: mod type** name
489    t = split_c_tokens(s,'%*%s*%*')
490    if t.n == 2 then
491        if kind == 'func' then
492            error("#invalid function return type: "..s)
493        end
494        --local m = split(t[1],'%s%s*')
495        local m = split_c_tokens(t[1],'%s+')
496        return _Declaration {
497            name = t[2]..tmpdef,
498            ptr = '*',
499            ret = '*',
500            --type = rebuild_template(m[m.n], tb, timpl),
501            type = m[m.n],
502            mod = concat(m,1,m.n-1),
503            is_parameter = is_parameter,
504            kind = kind
505        }
506    end
507
508    -- check the form: mod type& name
509    t = split_c_tokens(s,'&')
510    if t.n == 2 then
511        --local m = split(t[1],'%s%s*')
512        local m = split_c_tokens(t[1],'%s+')
513        return _Declaration {
514            name = t[2]..tmpdef,
515            ptr = '&',
516            --type = rebuild_template(m[m.n], tb, timpl),
517            type = m[m.n],
518            mod = concat(m,1,m.n-1),
519            is_parameter = is_parameter,
520            kind = kind
521        }
522    end
523
524    -- check the form: mod type* name
525    local s1 = gsub(s,"(%b\[\])",function (n) return gsub(n,'%*','\1') end)
526    t = split_c_tokens(s1,'%*')
527    if t.n == 2 then
528        t[2] = gsub(t[2],'\1','%*') -- restore * in dimension expression
529        --local m = split(t[1],'%s%s*')
530        local m = split_c_tokens(t[1],'%s+')
531        return _Declaration {
532            name = t[2]..tmpdef,
533            ptr = '*',
534            type = m[m.n],
535            --type = rebuild_template(m[m.n], tb, timpl),
536            mod = concat(m,1,m.n-1)   ,
537            is_parameter = is_parameter,
538            kind = kind
539        }
540    end
541
542    if kind == 'var' then
543        -- check the form: mod type name
544        --t = split(s,'%s%s*')
545        t = split_c_tokens(s,'%s+')
546        local v
547        if findtype(t[t.n]) then v = create_varname() else v = t[t.n]; t.n = t.n-1 end
548        return _Declaration {
549            name = v..tmpdef,
550            --type = rebuild_template(t[t.n], tb, timpl),
551            type = t[t.n],
552            mod = concat(t,1,t.n-1),
553            is_parameter = is_parameter,
554            kind = kind
555        }
556
557    else -- kind == "func"
558
559        -- check the form: mod type name
560        --t = split(s,'%s%s*')
561        t = split_c_tokens(s,'%s+')
562        local v = t[t.n]  -- last word is the function name
563        local tp,md
564        if t.n>1 then
565            tp = t[t.n-1]
566            md = concat(t,1,t.n-2)
567        end
568        --if tp then tp = rebuild_template(tp, tb, timpl) end
569        return _Declaration {
570            name = v,
571            type = tp,
572            mod = md,
573            is_parameter = is_parameter,
574            kind = kind
575        }
576    end
577
578end
579
Note: See TracBrowser for help on using the repository browser.