Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/external/tolua/lua/declaration.lua @ 11949

Last change on this file since 11949 was 5738, checked in by landauf, 15 years ago

merged libraries2 back to trunk

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