Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2372 was 2087, checked in by landauf, 16 years ago

merged objecthierarchy branch back to trunk

  • Property svn:eol-style set to native
File size: 14.1 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                        m[i] = findtype(m[i]) or m[i]
143                        m[i] = resolve_template_types(m[i])
144                end
145
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
153end
154
155function break_template(s)
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
163end
164
165function rebuild_template(s, b, timpl)
166
167        if b == 0 then
168                return s
169        end
170
171        return string.sub(s, 1, b-1)..timpl..string.sub(s, b, -1)
172end
173
174-- Print method
175function classDeclaration:print (ident,close)
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)
185end
186
187-- check if array of values are returned to Lua
188function classDeclaration:requirecollection (t)
189 if self.mod ~= 'const' and
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
198end
199
200-- declare tag
201function classDeclaration:decltype ()
202
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
208end
209
210
211-- output type checking
212function classDeclaration:outchecktype (narg)
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
231end
232
233function classDeclaration:builddeclaration (narg, cplusplus)
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
293end
294
295-- Declare variable
296function classDeclaration:declare (narg)
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
306end
307
308-- Get parameter value
309function classDeclaration:getarray (narg)
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
347end
348
349-- Get parameter value
350function classDeclaration:setarray (narg)
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
376end
377
378-- Free dynamically allocated array
379function classDeclaration:freearray ()
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
387end
388
389-- Pass parameter
390function classDeclaration:passpar ()
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
398end
399
400-- Return parameter value
401function classDeclaration:retvalue ()
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
412end
413
414-- Internal constructor
415function _Declaration (t)
416
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
425
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
429
430 return t
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
438 -- eliminate spaces if default value is provided
439 s = gsub(s,"%s*=%s*","=")
440 s = gsub(s, "%s*<", "<")
441
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
455
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
475
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
495
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
511
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
529
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  }
544
545 else -- kind == "func"
546
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
565
566end
567
Note: See TracBrowser for help on using the repository browser.