pgenutil.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. {
  2. Copyright (c) 2011
  3. Contains different functions that are used in the context of
  4. parsing generics.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit pgenutil;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. symtype;
  23. procedure generate_specialization(var tt:tdef;parse_class_parent:boolean);
  24. implementation
  25. uses
  26. { common }
  27. cclasses,cutils,
  28. { global }
  29. globals,tokens,verbose,
  30. { symtable }
  31. symconst,symbase,symdef,symsym,symtable,
  32. { modules }
  33. fmodule,
  34. { pass 1 }
  35. node,nobj,
  36. { parser }
  37. scanner,
  38. pbase,pexpr,pdecsub,ptype;
  39. procedure generate_specialization(var tt:tdef;parse_class_parent:boolean);
  40. var
  41. st : TSymtable;
  42. srsym : tsym;
  43. pt2 : tnode;
  44. found,
  45. first,
  46. err : boolean;
  47. i,
  48. j,
  49. gencount : longint;
  50. sym : tsym;
  51. genericdef : tstoreddef;
  52. genericsym,
  53. generictype : ttypesym;
  54. genericdeflist : TFPObjectList;
  55. generictypelist : TFPObjectList;
  56. oldsymtablestack : tsymtablestack;
  57. oldextendeddefs : TFPHashObjectList;
  58. hmodule : tmodule;
  59. pu : tused_unit;
  60. uspecializename,
  61. specializename : string;
  62. vmtbuilder : TVMTBuilder;
  63. onlyparsepara : boolean;
  64. specializest : tsymtable;
  65. item: psymtablestackitem;
  66. def : tdef;
  67. begin
  68. { retrieve generic def that we are going to replace }
  69. genericdef:=tstoreddef(tt);
  70. tt:=nil;
  71. onlyparsepara:=false;
  72. if not assigned(genericdef.typesym) or
  73. (genericdef.typesym.typ<>typesym) then
  74. internalerror(2011042701);
  75. genericsym:=ttypesym(genericdef.typesym);
  76. if genericsym.gendeflist.Count=0 then
  77. begin
  78. { TODO : search for other generics with the same name }
  79. Message(parser_e_special_onlygenerics);
  80. tt:=generrordef;
  81. onlyparsepara:=true;
  82. end;
  83. { only need to record the tokens, then we don't know the type yet ... }
  84. if parse_generic then
  85. begin
  86. { ... but we have to insert a def into the symtable else the deflist
  87. of generic and specialization might not be equally sized which
  88. is later assumed }
  89. tt:=tundefineddef.create;
  90. if parse_class_parent then
  91. tt:=genericdef;
  92. onlyparsepara:=true;
  93. end;
  94. { Only parse the parameters for recovery or
  95. for recording in genericbuf }
  96. if onlyparsepara then
  97. begin
  98. consume(_LSHARPBRACKET);
  99. repeat
  100. pt2:=factor(false,true);
  101. pt2.free;
  102. until not try_to_consume(_COMMA);
  103. consume(_RSHARPBRACKET);
  104. exit;
  105. end;
  106. if not try_to_consume(_LT) then
  107. consume(_LSHARPBRACKET);
  108. generictypelist:=TFPObjectList.create(false);
  109. genericdeflist:=TFPObjectList.Create(false);
  110. { Parse type parameters }
  111. if not assigned(genericdef.typesym) then
  112. internalerror(200710173);
  113. err:=false;
  114. first:=true;
  115. specializename:='';
  116. while not (token in [_GT,_RSHARPBRACKET]) do
  117. begin
  118. if not first then
  119. consume(_COMMA)
  120. else
  121. first:=false;
  122. pt2:=factor(false,true);
  123. if pt2.nodetype=typen then
  124. begin
  125. if df_generic in pt2.resultdef.defoptions then
  126. Message(parser_e_no_generics_as_params);
  127. genericdeflist.Add(pt2.resultdef);
  128. if not assigned(pt2.resultdef.typesym) then
  129. message(type_e_generics_cannot_reference_itself)
  130. else
  131. specializename:=specializename+'$'+pt2.resultdef.typesym.realname;
  132. end
  133. else
  134. begin
  135. Message(type_e_type_id_expected);
  136. err:=true;
  137. end;
  138. pt2.free;
  139. end;
  140. if err then
  141. begin
  142. try_to_consume(_RSHARPBRACKET);
  143. exit;
  144. end;
  145. { check whether we have a generic with the correct amount of params }
  146. found:=false;
  147. for i:=0 to genericsym.gendeflist.Count-1 do begin
  148. def:=tdef(genericsym.gendeflist[i]);
  149. { select the symtable containing the params }
  150. case def.typ of
  151. procdef:
  152. st:=def.GetSymtable(gs_para);
  153. objectdef,
  154. recorddef:
  155. st:=def.GetSymtable(gs_record);
  156. arraydef:
  157. st:=tarraydef(def).symtable;
  158. procvardef:
  159. st:=def.GetSymtable(gs_para);
  160. else
  161. internalerror(200511182);
  162. end;
  163. gencount:=0;
  164. for j:=0 to st.SymList.Count-1 do
  165. begin
  166. if sp_generic_para in tsym(st.SymList[j]).symoptions then
  167. inc(gencount);
  168. end;
  169. if gencount=genericdeflist.count then
  170. begin
  171. found:=true;
  172. break;
  173. end;
  174. end;
  175. if not found then
  176. begin
  177. identifier_not_found(genericdef.typename);
  178. tt:=generrordef;
  179. exit;
  180. end;
  181. { we've found the correct def, so use it }
  182. genericdef:=tstoreddef(def);
  183. { build the new type's name }
  184. specializename:=genericdef.typesym.realname+specializename;
  185. uspecializename:=upper(specializename);
  186. { build the list containing the types for the generic params }
  187. gencount:=0;
  188. for i:=0 to st.SymList.Count-1 do
  189. begin
  190. sym:=tsym(st.SymList[i]);
  191. if sp_generic_para in sym.symoptions then
  192. begin
  193. if gencount=genericdeflist.Count then
  194. internalerror(2011042702);
  195. generictype:=ttypesym.create(sym.realname,tdef(genericdeflist[gencount]));
  196. generictypelist.add(generictype);
  197. inc(gencount);
  198. end;
  199. end;
  200. { Special case if we are referencing the current defined object }
  201. if assigned(current_structdef) and
  202. (current_structdef.objname^=uspecializename) then
  203. tt:=current_structdef;
  204. { for units specializations can already be needed in the interface, therefor we
  205. will use the global symtable. Programs don't have a globalsymtable and there we
  206. use the localsymtable }
  207. if current_module.is_unit then
  208. specializest:=current_module.globalsymtable
  209. else
  210. specializest:=current_module.localsymtable;
  211. { Can we reuse an already specialized type? }
  212. if not assigned(tt) then
  213. begin
  214. srsym:=tsym(specializest.find(uspecializename));
  215. if assigned(srsym) then
  216. begin
  217. if srsym.typ<>typesym then
  218. internalerror(200710171);
  219. tt:=ttypesym(srsym).typedef;
  220. end;
  221. end;
  222. if not assigned(tt) then
  223. begin
  224. { Setup symtablestack at definition time
  225. to get types right, however this is not perfect, we should probably record
  226. the resolved symbols }
  227. oldsymtablestack:=symtablestack;
  228. oldextendeddefs:=current_module.extendeddefs;
  229. current_module.extendeddefs:=TFPHashObjectList.create(true);
  230. symtablestack:=tdefawaresymtablestack.create;
  231. if not assigned(genericdef) then
  232. internalerror(200705151);
  233. hmodule:=find_module_from_symtable(genericdef.owner);
  234. if hmodule=nil then
  235. internalerror(200705152);
  236. pu:=tused_unit(hmodule.used_units.first);
  237. while assigned(pu) do
  238. begin
  239. if not assigned(pu.u.globalsymtable) then
  240. internalerror(200705153);
  241. symtablestack.push(pu.u.globalsymtable);
  242. pu:=tused_unit(pu.next);
  243. end;
  244. if assigned(hmodule.globalsymtable) then
  245. symtablestack.push(hmodule.globalsymtable);
  246. { hacky, but necessary to insert the newly generated class properly }
  247. item:=oldsymtablestack.stack;
  248. while assigned(item) and (item^.symtable.symtablelevel>main_program_level) do
  249. item:=item^.next;
  250. if assigned(item) and (item^.symtable<>symtablestack.top) then
  251. symtablestack.push(item^.symtable);
  252. { Reparse the original type definition }
  253. if not err then
  254. begin
  255. { First a new typesym so we can reuse this specialization and
  256. references to this specialization can be handled }
  257. srsym:=ttypesym.create(specializename,generrordef);
  258. specializest.insert(srsym);
  259. if not assigned(genericdef.generictokenbuf) then
  260. internalerror(200511171);
  261. current_scanner.startreplaytokens(genericdef.generictokenbuf);
  262. read_named_type(tt,specializename,genericdef,generictypelist,false);
  263. ttypesym(srsym).typedef:=tt;
  264. tt.typesym:=srsym;
  265. case tt.typ of
  266. { Build VMT indexes for classes }
  267. objectdef:
  268. begin
  269. vmtbuilder:=TVMTBuilder.Create(tobjectdef(tt));
  270. vmtbuilder.generate_vmt;
  271. vmtbuilder.free;
  272. end;
  273. { handle params, calling convention, etc }
  274. procvardef:
  275. begin
  276. if not check_proc_directive(true) then
  277. begin
  278. try_consume_hintdirective(ttypesym(srsym).symoptions,ttypesym(srsym).deprecatedmsg);
  279. consume(_SEMICOLON);
  280. end;
  281. parse_var_proc_directives(ttypesym(srsym));
  282. handle_calling_convention(tprocvardef(tt));
  283. if try_consume_hintdirective(ttypesym(srsym).symoptions,ttypesym(srsym).deprecatedmsg) then
  284. consume(_SEMICOLON);
  285. end;
  286. end;
  287. { Consume the semicolon if it is also recorded }
  288. try_to_consume(_SEMICOLON);
  289. end;
  290. { Restore symtablestack }
  291. current_module.extendeddefs.free;
  292. current_module.extendeddefs:=oldextendeddefs;
  293. symtablestack.free;
  294. symtablestack:=oldsymtablestack;
  295. end
  296. else
  297. begin
  298. { There is comment few lines before ie 200512115
  299. saying "We are parsing the same objectdef, the def index numbers
  300. are the same". This is wrong (index numbers are not same)
  301. in case there is specialization (S2 in this case) inside
  302. specialized generic (G2 in this case) which is equal to
  303. some previous specialization (S1 in this case). In that case,
  304. new symbol is not added to currently specialized type
  305. (S in this case) for that specializations (S2 in this case),
  306. and this results in that specialization and generic definition
  307. don't have same number of elements in their object symbol tables.
  308. This patch adds undefined def to ensure that those
  309. two symbol tables will have same number of elements.
  310. }
  311. tundefineddef.create;
  312. end;
  313. genericdeflist.free;
  314. generictypelist.free;
  315. if not try_to_consume(_GT) then
  316. consume(_RSHARPBRACKET);
  317. end;
  318. end.