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) |
---|
23 | classDeclaration = { |
---|
24 | mod = '', |
---|
25 | type = '', |
---|
26 | ptr = '', |
---|
27 | name = '', |
---|
28 | dim = '', |
---|
29 | ret = '', |
---|
30 | def = '' |
---|
31 | } |
---|
32 | classDeclaration.__index = classDeclaration |
---|
33 | setmetatable(classDeclaration,classFeature) |
---|
34 | |
---|
35 | -- Create an unique variable name |
---|
36 | function create_varname () |
---|
37 | if not _varnumber then _varnumber = 0 end |
---|
38 | _varnumber = _varnumber + 1 |
---|
39 | return "tolua_var_".._varnumber |
---|
40 | end |
---|
41 | |
---|
42 | -- Check declaration name |
---|
43 | -- It also identifies default values |
---|
44 | function 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 |
---|
87 | end |
---|
88 | |
---|
89 | -- Check declaration type |
---|
90 | -- Substitutes typedef's. |
---|
91 | function 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 | |
---|
129 | end |
---|
130 | |
---|
131 | function 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 |
---|
153 | end |
---|
154 | |
---|
155 | function 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 |
---|
163 | end |
---|
164 | |
---|
165 | function 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) |
---|
172 | end |
---|
173 | |
---|
174 | -- Print method |
---|
175 | function 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) |
---|
185 | end |
---|
186 | |
---|
187 | -- check if array of values are returned to Lua |
---|
188 | function 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 |
---|
198 | end |
---|
199 | |
---|
200 | -- declare tag |
---|
201 | function 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 |
---|
208 | end |
---|
209 | |
---|
210 | |
---|
211 | -- output type checking |
---|
212 | function 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 |
---|
231 | end |
---|
232 | |
---|
233 | function 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 |
---|
293 | end |
---|
294 | |
---|
295 | -- Declare variable |
---|
296 | function 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 |
---|
306 | end |
---|
307 | |
---|
308 | -- Get parameter value |
---|
309 | function 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 |
---|
347 | end |
---|
348 | |
---|
349 | -- Get parameter value |
---|
350 | function 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 |
---|
376 | end |
---|
377 | |
---|
378 | -- Free dynamically allocated array |
---|
379 | function 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 |
---|
387 | end |
---|
388 | |
---|
389 | -- Pass parameter |
---|
390 | function 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 |
---|
398 | end |
---|
399 | |
---|
400 | -- Return parameter value |
---|
401 | function 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 |
---|
412 | end |
---|
413 | |
---|
414 | -- Internal constructor |
---|
415 | function _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 |
---|
431 | end |
---|
432 | |
---|
433 | -- Constructor |
---|
434 | -- Expects the string declaration. |
---|
435 | -- The kind of declaration can be "var" or "func". |
---|
436 | function 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 | |
---|
566 | end |
---|
567 | |
---|