Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/tolua/lua/declaration.lua @ 3200

Last change on this file since 3200 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: 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.