PageRenderTime 47ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/tolua++-1.0.93/src/bin/lua/declaration.lua

https://bitbucket.org/dbindel/axfem
Lua | 579 lines | 449 code | 55 blank | 75 comment | 103 complexity | 7a9d795bcc7ddc5dfdbd4e59d91753f8 MD5 | raw file
Possible License(s): LGPL-2.1
  1. -- tolua: declaration class
  2. -- Written by Waldemar Celes
  3. -- TeCGraf/PUC-Rio
  4. -- Jul 1998
  5. -- $Id: $
  6. -- This code is free software; you can redistribute it and/or modify it.
  7. -- The software provided hereunder is on an "as is" basis, and
  8. -- the author has no obligation to provide maintenance, support, updates,
  9. -- enhancements, or modifications.
  10. -- Declaration class
  11. -- Represents variable, function, or argument declaration.
  12. -- Stores the following fields:
  13. -- mod = type modifiers
  14. -- type = type
  15. -- ptr = "*" or "&", if representing a pointer or a reference
  16. -- name = name
  17. -- dim = dimension, if a vector
  18. -- def = default value, if any (only for arguments)
  19. -- ret = "*" or "&", if value is to be returned (only for arguments)
  20. classDeclaration = {
  21. mod = '',
  22. type = '',
  23. ptr = '',
  24. name = '',
  25. dim = '',
  26. ret = '',
  27. def = ''
  28. }
  29. classDeclaration.__index = classDeclaration
  30. setmetatable(classDeclaration,classFeature)
  31. -- Create an unique variable name
  32. function create_varname ()
  33. if not _varnumber then _varnumber = 0 end
  34. _varnumber = _varnumber + 1
  35. return "tolua_var_".._varnumber
  36. end
  37. -- Check declaration name
  38. -- It also identifies default values
  39. function classDeclaration:checkname ()
  40. if strsub(self.name,1,1) == '[' and not findtype(self.type) then
  41. self.name = self.type..self.name
  42. local m = split(self.mod,'%s%s*')
  43. self.type = m[m.n]
  44. self.mod = concat(m,1,m.n-1)
  45. end
  46. local t = split(self.name,'=')
  47. if t.n==2 then
  48. self.name = t[1]
  49. self.def = find_enum_var(t[t.n])
  50. end
  51. local b,e,d = strfind(self.name,"%[(.-)%]")
  52. if b then
  53. self.name = strsub(self.name,1,b-1)
  54. self.dim = find_enum_var(d)
  55. end
  56. if self.type ~= '' and self.type ~= 'void' and self.name == '' then
  57. self.name = create_varname()
  58. elseif self.kind=='var' then
  59. if self.type=='' and self.name~='' then
  60. self.type = self.type..self.name
  61. self.name = create_varname()
  62. elseif findtype(self.name) then
  63. if self.type=='' then self.type = self.name
  64. else self.type = self.type..' '..self.name end
  65. self.name = create_varname()
  66. end
  67. end
  68. -- adjust type of string
  69. if self.type == 'char' and self.dim ~= '' then
  70. self.type = 'char*'
  71. end
  72. if self.kind and self.kind == 'var' then
  73. self.name = string.gsub(self.name, ":.*$", "") -- ???
  74. end
  75. end
  76. -- Check declaration type
  77. -- Substitutes typedef's.
  78. function classDeclaration:checktype ()
  79. -- check if there is a pointer to basic type
  80. local basic = isbasic(self.type)
  81. if self.kind == 'func' and basic=='number' and string.find(self.ptr, "%*") then
  82. self.type = '_userdata'
  83. self.ptr = ""
  84. end
  85. if basic and self.ptr~='' then
  86. self.ret = self.ptr
  87. self.ptr = nil
  88. if isbasic(self.type) == 'number' then
  89. self.return_userdata = true
  90. end
  91. end
  92. -- check if there is array to be returned
  93. if self.dim~='' and self.ret~='' then
  94. error('#invalid parameter: cannot return an array of values')
  95. end
  96. -- restore 'void*' and 'string*'
  97. if self.type == '_userdata' then self.type = 'void*'
  98. elseif self.type == '_cstring' then self.type = 'char*'
  99. elseif self.type == '_lstate' then self.type = 'lua_State*'
  100. end
  101. -- resolve types inside the templates
  102. if self.type then
  103. self.type = resolve_template_types(self.type)
  104. end
  105. --
  106. -- -- if returning value, automatically set default value
  107. -- if self.ret ~= '' and self.def == '' then
  108. -- self.def = '0'
  109. -- end
  110. --
  111. end
  112. function resolve_template_types(type)
  113. if isbasic(type) then
  114. return type
  115. end
  116. local b,_,m = string.find(type, "(%b<>)")
  117. if b then
  118. m = split_c_tokens(string.sub(m, 2, -2), ",")
  119. for i=1, table.getn(m) do
  120. m[i] = string.gsub(m[i],"%s*([%*&])", "%1")
  121. if not isbasic(m[i]) then
  122. if not isenum(m[i]) then _, m[i] = applytypedef("", m[i]) end
  123. m[i] = findtype(m[i]) or m[i]
  124. m[i] = resolve_template_types(m[i])
  125. end
  126. end
  127. local b,i
  128. type,b,i = break_template(type)
  129. --print("concat is ",concat(m, 1, m.n))
  130. local template_part = "<"..concat(m, 1, m.n, ",")..">"
  131. type = rebuild_template(type, b, template_part)
  132. type = string.gsub(type, ">>", "> >")
  133. end
  134. return type
  135. end
  136. function break_template(s)
  137. local b,e,timpl = string.find(s, "(%b<>)")
  138. if timpl then
  139. s = string.gsub(s, "%b<>", "")
  140. return s, b, timpl
  141. else
  142. return s, 0, nil
  143. end
  144. end
  145. function rebuild_template(s, b, timpl)
  146. if b == 0 then
  147. return s
  148. end
  149. return string.sub(s, 1, b-1)..timpl..string.sub(s, b, -1)
  150. end
  151. -- Print method
  152. function classDeclaration:print (ident,close)
  153. print(ident.."Declaration{")
  154. print(ident.." mod = '"..self.mod.."',")
  155. print(ident.." type = '"..self.type.."',")
  156. print(ident.." ptr = '"..self.ptr.."',")
  157. print(ident.." name = '"..self.name.."',")
  158. print(ident.." dim = '"..self.dim.."',")
  159. print(ident.." def = '"..self.def.."',")
  160. print(ident.." ret = '"..self.ret.."',")
  161. print(ident.."}"..close)
  162. end
  163. -- check if array of values are returned to Lua
  164. function classDeclaration:requirecollection (t)
  165. if self.mod ~= 'const' and
  166. self.dim and self.dim ~= '' and
  167. not isbasic(self.type) and
  168. self.ptr == '' and self:check_public_access() then
  169. local type = gsub(self.type,"%s*const%s+","")
  170. t[type] = "tolua_collect_" .. clean_template(type)
  171. return true
  172. end
  173. return false
  174. end
  175. -- declare tag
  176. function classDeclaration:decltype ()
  177. self.type = typevar(self.type)
  178. if strfind(self.mod,'const') then
  179. self.type = 'const '..self.type
  180. self.mod = gsub(self.mod,'const%s*','')
  181. end
  182. end
  183. -- output type checking
  184. function classDeclaration:outchecktype (narg)
  185. local def
  186. local t = isbasic(self.type)
  187. if self.def~='' then
  188. def = 1
  189. else
  190. def = 0
  191. end
  192. if self.dim ~= '' then
  193. --if t=='string' then
  194. -- return 'tolua_isstringarray(tolua_S,'..narg..','..def..',&tolua_err)'
  195. --else
  196. return '!tolua_istable(tolua_S,'..narg..',0,&tolua_err)'
  197. --end
  198. elseif t then
  199. return '!tolua_is'..t..'(tolua_S,'..narg..','..def..',&tolua_err)'
  200. else
  201. local is_func = get_is_function(self.type)
  202. if self.ptr == '&' or self.ptr == '' then
  203. return '(tolua_isvaluenil(tolua_S,'..narg..',&tolua_err) || !'..is_func..'(tolua_S,'..narg..',"'..self.type..'",'..def..',&tolua_err))'
  204. else
  205. return '!'..is_func..'(tolua_S,'..narg..',"'..self.type..'",'..def..',&tolua_err)'
  206. end
  207. end
  208. end
  209. function classDeclaration:builddeclaration (narg, cplusplus)
  210. local array = self.dim ~= '' and tonumber(self.dim)==nil
  211. local line = ""
  212. local ptr = ''
  213. local mod
  214. local type = self.type
  215. local nctype = gsub(self.type,'const%s+','')
  216. if self.dim ~= '' then
  217. type = gsub(self.type,'const%s+','') -- eliminates const modifier for arrays
  218. end
  219. if self.ptr~='' and not isbasic(type) then ptr = '*' end
  220. line = concatparam(line," ",self.mod,type,ptr)
  221. if array then
  222. line = concatparam(line,'*')
  223. end
  224. line = concatparam(line,self.name)
  225. if self.dim ~= '' then
  226. if tonumber(self.dim)~=nil then
  227. line = concatparam(line,'[',self.dim,'];')
  228. else
  229. if cplusplus then
  230. line = concatparam(line,' = Mtolua_new_dim(',type,ptr,', '..self.dim..');')
  231. else
  232. line = concatparam(line,' = (',type,ptr,'*)',
  233. 'malloc((',self.dim,')*sizeof(',type,ptr,'));')
  234. end
  235. end
  236. else
  237. local t = isbasic(type)
  238. line = concatparam(line,' = ')
  239. if t == 'state' then
  240. line = concatparam(line, 'tolua_S;')
  241. else
  242. --print("t is "..tostring(t)..", ptr is "..tostring(self.ptr))
  243. if t == 'number' and string.find(self.ptr, "%*") then
  244. t = 'userdata'
  245. end
  246. if not t and ptr=='' then line = concatparam(line,'*') end
  247. line = concatparam(line,'((',self.mod,type)
  248. if not t then
  249. line = concatparam(line,'*')
  250. end
  251. line = concatparam(line,') ')
  252. if isenum(nctype) then
  253. line = concatparam(line,'(int) ')
  254. end
  255. local def = 0
  256. if self.def ~= '' then
  257. def = self.def
  258. if (ptr == '' or self.ptr == '&') and not t then
  259. def = "(void*)&(const "..type..")"..def
  260. end
  261. end
  262. if t then
  263. line = concatparam(line,'tolua_to'..t,'(tolua_S,',narg,',',def,'));')
  264. else
  265. local to_func = get_to_function(type)
  266. line = concatparam(line,to_func..'(tolua_S,',narg,',',def,'));')
  267. end
  268. end
  269. end
  270. return line
  271. end
  272. -- Declare variable
  273. function classDeclaration:declare (narg)
  274. if self.dim ~= '' and tonumber(self.dim)==nil then
  275. output('#ifdef __cplusplus\n')
  276. output(self:builddeclaration(narg,true))
  277. output('#else\n')
  278. output(self:builddeclaration(narg,false))
  279. output('#endif\n')
  280. else
  281. output(self:builddeclaration(narg,false))
  282. end
  283. end
  284. -- Get parameter value
  285. function classDeclaration:getarray (narg)
  286. if self.dim ~= '' then
  287. local type = gsub(self.type,'const ','')
  288. output(' {')
  289. output('#ifndef TOLUA_RELEASE\n')
  290. local def; if self.def~='' then def=1 else def=0 end
  291. local t = isbasic(type)
  292. if (t) then
  293. output(' if (!tolua_is'..t..'array(tolua_S,',narg,',',self.dim,',',def,',&tolua_err))')
  294. else
  295. output(' if (!tolua_isusertypearray(tolua_S,',narg,',"',type,'",',self.dim,',',def,',&tolua_err))')
  296. end
  297. output(' goto tolua_lerror;')
  298. output(' else\n')
  299. output('#endif\n')
  300. output(' {')
  301. output(' int i;')
  302. output(' for(i=0; i<'..self.dim..';i++)')
  303. local t = isbasic(type)
  304. local ptr = ''
  305. if self.ptr~='' then ptr = '*' end
  306. output(' ',self.name..'[i] = ')
  307. if not t and ptr=='' then output('*') end
  308. output('((',type)
  309. if not t then
  310. output('*')
  311. end
  312. output(') ')
  313. local def = 0
  314. if self.def ~= '' then def = self.def end
  315. if t then
  316. output('tolua_tofield'..t..'(tolua_S,',narg,',i+1,',def,'));')
  317. else
  318. output('tolua_tofieldusertype(tolua_S,',narg,',i+1,',def,'));')
  319. end
  320. output(' }')
  321. output(' }')
  322. end
  323. end
  324. -- Get parameter value
  325. function classDeclaration:setarray (narg)
  326. if not strfind(self.type,'const%s+') and self.dim ~= '' then
  327. local type = gsub(self.type,'const ','')
  328. output(' {')
  329. output(' int i;')
  330. output(' for(i=0; i<'..self.dim..';i++)')
  331. local t,ct = isbasic(type)
  332. if t then
  333. output(' tolua_pushfield'..t..'(tolua_S,',narg,',i+1,(',ct,')',self.name,'[i]);')
  334. else
  335. if self.ptr == '' then
  336. output(' {')
  337. output('#ifdef __cplusplus\n')
  338. output(' void* tolua_obj = Mtolua_new((',type,')(',self.name,'[i]));')
  339. output(' tolua_pushfieldusertype_and_takeownership(tolua_S,',narg,',i+1,tolua_obj,"',type,'");')
  340. output('#else\n')
  341. output(' void* tolua_obj = tolua_copy(tolua_S,(void*)&',self.name,'[i],sizeof(',type,'));')
  342. output(' tolua_pushfieldusertype(tolua_S,',narg,',i+1,tolua_obj,"',type,'");')
  343. output('#endif\n')
  344. output(' }')
  345. else
  346. output(' tolua_pushfieldusertype(tolua_S,',narg,',i+1,(void*)',self.name,'[i],"',type,'");')
  347. end
  348. end
  349. output(' }')
  350. end
  351. end
  352. -- Free dynamically allocated array
  353. function classDeclaration:freearray ()
  354. if self.dim ~= '' and tonumber(self.dim)==nil then
  355. output('#ifdef __cplusplus\n')
  356. output(' Mtolua_delete_dim(',self.name,');')
  357. output('#else\n')
  358. output(' free(',self.name,');')
  359. output('#endif\n')
  360. end
  361. end
  362. -- Pass parameter
  363. function classDeclaration:passpar ()
  364. if self.ptr=='&' and not isbasic(self.type) then
  365. output('*'..self.name)
  366. elseif self.ret=='*' then
  367. output('&'..self.name)
  368. else
  369. output(self.name)
  370. end
  371. end
  372. -- Return parameter value
  373. function classDeclaration:retvalue ()
  374. if self.ret ~= '' then
  375. local t,ct = isbasic(self.type)
  376. if t and t~='' then
  377. output(' tolua_push'..t..'(tolua_S,(',ct,')'..self.name..');')
  378. else
  379. local push_func = get_push_function(self.type)
  380. output(' ',push_func,'(tolua_S,(void*)'..self.name..',"',self.type,'");')
  381. end
  382. return 1
  383. end
  384. return 0
  385. end
  386. -- Internal constructor
  387. function _Declaration (t)
  388. setmetatable(t,classDeclaration)
  389. t:buildnames()
  390. t:checkname()
  391. t:checktype()
  392. local ft = findtype(t.type) or t.type
  393. if not isenum(ft) then
  394. t.mod, t.type = applytypedef(t.mod, ft)
  395. end
  396. if t.kind=="var" and (string.find(t.mod, "tolua_property%s") or string.find(t.mod, "tolua_property$")) then
  397. t.mod = string.gsub(t.mod, "tolua_property", "tolua_property__"..get_property_type())
  398. end
  399. return t
  400. end
  401. -- Constructor
  402. -- Expects the string declaration.
  403. -- The kind of declaration can be "var" or "func".
  404. function Declaration (s,kind,is_parameter)
  405. -- eliminate spaces if default value is provided
  406. s = gsub(s,"%s*=%s*","=")
  407. s = gsub(s, "%s*<", "<")
  408. local defb,tmpdef
  409. defb,_,tmpdef = string.find(s, "(=.*)$")
  410. if defb then
  411. s = string.gsub(s, "=.*$", "")
  412. else
  413. tmpdef = ''
  414. end
  415. if kind == "var" then
  416. -- check the form: void
  417. if s == '' or s == 'void' then
  418. return _Declaration{type = 'void', kind = kind, is_parameter = is_parameter}
  419. end
  420. end
  421. -- check the form: mod type*& name
  422. local t = split_c_tokens(s,'%*%s*&')
  423. if t.n == 2 then
  424. if kind == 'func' then
  425. error("#invalid function return type: "..s)
  426. end
  427. --local m = split(t[1],'%s%s*')
  428. local m = split_c_tokens(t[1],'%s+')
  429. return _Declaration{
  430. name = t[2]..tmpdef,
  431. ptr = '*',
  432. ret = '&',
  433. --type = rebuild_template(m[m.n], tb, timpl),
  434. type = m[m.n],
  435. mod = concat(m,1,m.n-1),
  436. is_parameter = is_parameter,
  437. kind = kind
  438. }
  439. end
  440. -- check the form: mod type** name
  441. t = split_c_tokens(s,'%*%s*%*')
  442. if t.n == 2 then
  443. if kind == 'func' then
  444. error("#invalid function return type: "..s)
  445. end
  446. --local m = split(t[1],'%s%s*')
  447. local m = split_c_tokens(t[1],'%s+')
  448. return _Declaration{
  449. name = t[2]..tmpdef,
  450. ptr = '*',
  451. ret = '*',
  452. --type = rebuild_template(m[m.n], tb, timpl),
  453. type = m[m.n],
  454. mod = concat(m,1,m.n-1),
  455. is_parameter = is_parameter,
  456. kind = kind
  457. }
  458. end
  459. -- check the form: mod type& name
  460. t = split_c_tokens(s,'&')
  461. if t.n == 2 then
  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. --type = rebuild_template(m[m.n], tb, timpl),
  468. type = m[m.n],
  469. mod = concat(m,1,m.n-1),
  470. is_parameter = is_parameter,
  471. kind = kind
  472. }
  473. end
  474. -- check the form: mod type* name
  475. local s1 = gsub(s,"(%b\[\])",function (n) return gsub(n,'%*','\1') end)
  476. t = split_c_tokens(s1,'%*')
  477. if t.n == 2 then
  478. t[2] = gsub(t[2],'\1','%*') -- restore * in dimension expression
  479. --local m = split(t[1],'%s%s*')
  480. local m = split_c_tokens(t[1],'%s+')
  481. return _Declaration{
  482. name = t[2]..tmpdef,
  483. ptr = '*',
  484. type = m[m.n],
  485. --type = rebuild_template(m[m.n], tb, timpl),
  486. mod = concat(m,1,m.n-1) ,
  487. is_parameter = is_parameter,
  488. kind = kind
  489. }
  490. end
  491. if kind == 'var' then
  492. -- check the form: mod type name
  493. --t = split(s,'%s%s*')
  494. t = split_c_tokens(s,'%s+')
  495. local v
  496. if findtype(t[t.n]) then v = create_varname() else v = t[t.n]; t.n = t.n-1 end
  497. return _Declaration{
  498. name = v..tmpdef,
  499. --type = rebuild_template(t[t.n], tb, timpl),
  500. type = t[t.n],
  501. mod = concat(t,1,t.n-1),
  502. is_parameter = is_parameter,
  503. kind = kind
  504. }
  505. else -- kind == "func"
  506. -- check the form: mod type name
  507. --t = split(s,'%s%s*')
  508. t = split_c_tokens(s,'%s+')
  509. local v = t[t.n] -- last word is the function name
  510. local tp,md
  511. if t.n>1 then
  512. tp = t[t.n-1]
  513. md = concat(t,1,t.n-2)
  514. end
  515. --if tp then tp = rebuild_template(tp, tb, timpl) end
  516. return _Declaration{
  517. name = v,
  518. type = tp,
  519. mod = md,
  520. is_parameter = is_parameter,
  521. kind = kind
  522. }
  523. end
  524. end