Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/gui/src/tolua/lua/declaration.lua @ 1650

Last change on this file since 1650 was 1650, checked in by rgrieder, 16 years ago

added preliminary automatic creation of tolua generator that creates the actual executable
(please don't ask about the egg-hen question…)

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.