pgenutil.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  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. { common }
  23. cclasses,
  24. { symtable }
  25. symtype,symdef;
  26. procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;parsedtype:tdef;symname:string);
  27. function parse_generic_parameters:TFPObjectList;
  28. procedure insert_generic_parameter_types(def:tstoreddef;genericdef:tstoreddef;genericlist:TFPObjectList);
  29. implementation
  30. uses
  31. { common }
  32. cutils,
  33. { global }
  34. globals,tokens,verbose,
  35. { symtable }
  36. symconst,symbase,symsym,symtable,
  37. { modules }
  38. fmodule,
  39. { pass 1 }
  40. htypechk,
  41. node,nobj,
  42. { parser }
  43. scanner,
  44. pbase,pexpr,pdecsub,ptype;
  45. procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;parsedtype:tdef;symname:string);
  46. var
  47. st : TSymtable;
  48. srsym : tsym;
  49. pt2 : tnode;
  50. first,
  51. err : boolean;
  52. i,
  53. gencount : longint;
  54. genericdef : tstoreddef;
  55. generictype : ttypesym;
  56. genericdeflist : TFPObjectList;
  57. generictypelist : TFPObjectList;
  58. oldsymtablestack : tsymtablestack;
  59. oldextendeddefs : TFPHashObjectList;
  60. hmodule : tmodule;
  61. pu : tused_unit;
  62. uspecializename,
  63. countstr,genname,ugenname,specializename : string;
  64. vmtbuilder : TVMTBuilder;
  65. onlyparsepara : boolean;
  66. specializest : tsymtable;
  67. item: psymtablestackitem;
  68. begin
  69. { retrieve generic def that we are going to replace }
  70. genericdef:=tstoreddef(tt);
  71. tt:=nil;
  72. onlyparsepara:=false;
  73. { either symname must be given or genericdef needs to be valid }
  74. if (symname='') and
  75. (not assigned(genericdef) or
  76. not assigned(genericdef.typesym) or
  77. (genericdef.typesym.typ<>typesym)) then
  78. internalerror(2011042701);
  79. { only need to record the tokens, then we don't know the type yet ... }
  80. if parse_generic then
  81. begin
  82. { ... but we have to insert a def into the symtable if the generic
  83. is not a parent or an implemented interface else the deflist
  84. of generic and specialization might not be equally sized which
  85. is later assumed }
  86. if not parse_class_parent then
  87. tt:=tundefineddef.create;
  88. onlyparsepara:=true;
  89. end;
  90. { Only parse the parameters for recovery or
  91. for recording in genericbuf }
  92. if onlyparsepara then
  93. begin
  94. consume(_LSHARPBRACKET);
  95. gencount:=0;
  96. repeat
  97. pt2:=factor(false,true);
  98. pt2.free;
  99. inc(gencount);
  100. until not try_to_consume(_COMMA);
  101. consume(_RSHARPBRACKET);
  102. { we need to return a def that can later pass some checks like
  103. whether it's an interface or not }
  104. if parse_generic and (not assigned(tt) or (tt.typ=undefineddef)) then
  105. begin
  106. if (symname='') and (df_generic in genericdef.defoptions) then
  107. { this happens in non-Delphi modes }
  108. tt:=genericdef
  109. else
  110. begin
  111. { find the corresponding generic symbol so that any checks
  112. done on the returned def will be handled correctly }
  113. str(gencount,countstr);
  114. if symname='' then
  115. genname:=ttypesym(genericdef.typesym).realname
  116. else
  117. genname:=symname;
  118. genname:=genname+'$'+countstr;
  119. ugenname:=upper(genname);
  120. if not searchsym(ugenname,srsym,st) or
  121. (srsym.typ<>typesym) then
  122. begin
  123. identifier_not_found(genname);
  124. exit;
  125. end;
  126. if not (ttypesym(srsym).typedef is tstoreddef) then
  127. Internalerror(2011091601);
  128. tt:=ttypesym(srsym).typedef;
  129. end;
  130. end;
  131. exit;
  132. end;
  133. if not assigned(parsedtype) and not try_to_consume(_LT) then
  134. consume(_LSHARPBRACKET);
  135. generictypelist:=TFPObjectList.create(false);
  136. genericdeflist:=TFPObjectList.Create(false);
  137. { Parse type parameters }
  138. err:=false;
  139. { if parsedtype is set, then the first type identifer was already parsed
  140. (happens in inline specializations) and thus we only need to parse
  141. the remaining types and do as if the first one was already given }
  142. first:=not assigned(parsedtype);
  143. if assigned(parsedtype) then
  144. begin
  145. genericdeflist.Add(parsedtype);
  146. specializename:='$'+parsedtype.typesym.realname;
  147. end
  148. else
  149. specializename:='';
  150. while not (token in [_GT,_RSHARPBRACKET]) do
  151. begin
  152. if not first then
  153. consume(_COMMA)
  154. else
  155. first:=false;
  156. pt2:=factor(false,true);
  157. if pt2.nodetype=typen then
  158. begin
  159. if df_generic in pt2.resultdef.defoptions then
  160. Message(parser_e_no_generics_as_params);
  161. genericdeflist.Add(pt2.resultdef);
  162. if not assigned(pt2.resultdef.typesym) then
  163. message(type_e_generics_cannot_reference_itself)
  164. else
  165. specializename:=specializename+'$'+pt2.resultdef.typesym.realname;
  166. end
  167. else
  168. begin
  169. Message(type_e_type_id_expected);
  170. err:=true;
  171. end;
  172. pt2.free;
  173. end;
  174. if err then
  175. begin
  176. try_to_consume(_RSHARPBRACKET);
  177. exit;
  178. end;
  179. { search a generic with the given count of params }
  180. countstr:='';
  181. str(genericdeflist.Count,countstr);
  182. { use the name of the symbol as procvars return a user friendly version
  183. of the name }
  184. if symname='' then
  185. genname:=ttypesym(genericdef.typesym).realname
  186. else
  187. genname:=symname;
  188. { in case of non-Delphi mode the type name could already be a generic
  189. def (but maybe the wrong one) }
  190. if assigned(genericdef) and (df_generic in genericdef.defoptions) then
  191. begin
  192. { remove the type count suffix from the generic's name }
  193. for i:=Length(genname) downto 1 do
  194. if genname[i]='$' then
  195. begin
  196. genname:=copy(genname,1,i-1);
  197. break;
  198. end;
  199. end;
  200. genname:=genname+'$'+countstr;
  201. ugenname:=upper(genname);
  202. if not searchsym(ugenname,srsym,st)
  203. or (srsym.typ<>typesym) then
  204. begin
  205. identifier_not_found(genname);
  206. genericdeflist.Free;
  207. generictypelist.Free;
  208. exit;
  209. end;
  210. { we've found the correct def }
  211. genericdef:=tstoreddef(ttypesym(srsym).typedef);
  212. { build the new type's name }
  213. specializename:=genname+specializename;
  214. uspecializename:=upper(specializename);
  215. { select the symtable containing the params }
  216. case genericdef.typ of
  217. procdef:
  218. st:=genericdef.GetSymtable(gs_para);
  219. objectdef,
  220. recorddef:
  221. st:=genericdef.GetSymtable(gs_record);
  222. arraydef:
  223. st:=tarraydef(genericdef).symtable;
  224. procvardef:
  225. st:=genericdef.GetSymtable(gs_para);
  226. else
  227. internalerror(200511182);
  228. end;
  229. { build the list containing the types for the generic params }
  230. gencount:=0;
  231. for i:=0 to st.SymList.Count-1 do
  232. begin
  233. srsym:=tsym(st.SymList[i]);
  234. if sp_generic_para in srsym.symoptions then
  235. begin
  236. if gencount=genericdeflist.Count then
  237. internalerror(2011042702);
  238. generictype:=ttypesym.create(srsym.realname,tdef(genericdeflist[gencount]));
  239. generictypelist.add(generictype);
  240. inc(gencount);
  241. end;
  242. end;
  243. { Special case if we are referencing the current defined object }
  244. if assigned(current_structdef) and
  245. (current_structdef.objname^=uspecializename) then
  246. tt:=current_structdef;
  247. { for units specializations can already be needed in the interface, therefor we
  248. will use the global symtable. Programs don't have a globalsymtable and there we
  249. use the localsymtable }
  250. if current_module.is_unit then
  251. specializest:=current_module.globalsymtable
  252. else
  253. specializest:=current_module.localsymtable;
  254. { Can we reuse an already specialized type? }
  255. if not assigned(tt) then
  256. begin
  257. srsym:=tsym(specializest.find(uspecializename));
  258. if assigned(srsym) then
  259. begin
  260. if srsym.typ<>typesym then
  261. internalerror(200710171);
  262. tt:=ttypesym(srsym).typedef;
  263. end;
  264. end;
  265. if not assigned(tt) then
  266. begin
  267. { Setup symtablestack at definition time
  268. to get types right, however this is not perfect, we should probably record
  269. the resolved symbols }
  270. oldsymtablestack:=symtablestack;
  271. oldextendeddefs:=current_module.extendeddefs;
  272. current_module.extendeddefs:=TFPHashObjectList.create(true);
  273. symtablestack:=tdefawaresymtablestack.create;
  274. if not assigned(genericdef) then
  275. internalerror(200705151);
  276. hmodule:=find_module_from_symtable(genericdef.owner);
  277. if hmodule=nil then
  278. internalerror(200705152);
  279. pu:=tused_unit(hmodule.used_units.first);
  280. while assigned(pu) do
  281. begin
  282. if not assigned(pu.u.globalsymtable) then
  283. internalerror(200705153);
  284. symtablestack.push(pu.u.globalsymtable);
  285. pu:=tused_unit(pu.next);
  286. end;
  287. if assigned(hmodule.globalsymtable) then
  288. symtablestack.push(hmodule.globalsymtable);
  289. { in case of a parent or an implemented interface the class needs
  290. to be inserted in the current unit and not in the class it's
  291. used in }
  292. { TODO: check whether we are using the correct symtable }
  293. if not parse_class_parent then
  294. begin
  295. { hacky, but necessary to insert the newly generated class properly }
  296. item:=oldsymtablestack.stack;
  297. while assigned(item) and (item^.symtable.symtablelevel>main_program_level) do
  298. item:=item^.next;
  299. if assigned(item) and (item^.symtable<>symtablestack.top) then
  300. symtablestack.push(item^.symtable);
  301. end;
  302. { Reparse the original type definition }
  303. if not err then
  304. begin
  305. { First a new typesym so we can reuse this specialization and
  306. references to this specialization can be handled }
  307. srsym:=ttypesym.create(specializename,generrordef);
  308. specializest.insert(srsym);
  309. if not assigned(genericdef.generictokenbuf) then
  310. internalerror(200511171);
  311. current_scanner.startreplaytokens(genericdef.generictokenbuf);
  312. read_named_type(tt,specializename,genericdef,generictypelist,false);
  313. ttypesym(srsym).typedef:=tt;
  314. tt.typesym:=srsym;
  315. { Note regarding hint directives:
  316. There is no need to remove the flags for them from the
  317. specialized generic symbol, because hint directives that
  318. follow the specialization are handled by the code in
  319. pdecl.types_dec and added to the type symbol.
  320. E.g.: TFoo = TBar<Blubb> deprecated;
  321. Here the symbol TBar$1$Blubb will contain the
  322. "sp_hint_deprecated" flag while the TFoo symbol won't.}
  323. case tt.typ of
  324. { Build VMT indexes for classes and read hint directives }
  325. objectdef:
  326. begin
  327. try_consume_hintdirective(srsym.symoptions,srsym.deprecatedmsg);
  328. consume(_SEMICOLON);
  329. vmtbuilder:=TVMTBuilder.Create(tobjectdef(tt));
  330. vmtbuilder.generate_vmt;
  331. vmtbuilder.free;
  332. end;
  333. { handle params, calling convention, etc }
  334. procvardef:
  335. begin
  336. if not check_proc_directive(true) then
  337. begin
  338. try_consume_hintdirective(ttypesym(srsym).symoptions,ttypesym(srsym).deprecatedmsg);
  339. consume(_SEMICOLON);
  340. end;
  341. parse_var_proc_directives(ttypesym(srsym));
  342. handle_calling_convention(tprocvardef(tt));
  343. if try_consume_hintdirective(ttypesym(srsym).symoptions,ttypesym(srsym).deprecatedmsg) then
  344. consume(_SEMICOLON);
  345. end;
  346. else
  347. { parse hint directives for records and arrays }
  348. begin
  349. try_consume_hintdirective(srsym.symoptions,srsym.deprecatedmsg);
  350. consume(_SEMICOLON);
  351. end;
  352. end;
  353. { Consume the semicolon if it is also recorded }
  354. try_to_consume(_SEMICOLON);
  355. end;
  356. { Restore symtablestack }
  357. current_module.extendeddefs.free;
  358. current_module.extendeddefs:=oldextendeddefs;
  359. symtablestack.free;
  360. symtablestack:=oldsymtablestack;
  361. end
  362. else
  363. begin
  364. { There is comment few lines before ie 200512115
  365. saying "We are parsing the same objectdef, the def index numbers
  366. are the same". This is wrong (index numbers are not same)
  367. in case there is specialization (S2 in this case) inside
  368. specialized generic (G2 in this case) which is equal to
  369. some previous specialization (S1 in this case). In that case,
  370. new symbol is not added to currently specialized type
  371. (S in this case) for that specializations (S2 in this case),
  372. and this results in that specialization and generic definition
  373. don't have same number of elements in their object symbol tables.
  374. This patch adds undefined def to ensure that those
  375. two symbol tables will have same number of elements.
  376. }
  377. tundefineddef.create;
  378. end;
  379. if not (token in [_GT, _RSHARPBRACKET]) then
  380. begin
  381. consume(_RSHARPBRACKET);
  382. exit;
  383. end
  384. else
  385. consume(token);
  386. genericdeflist.free;
  387. generictypelist.free;
  388. if assigned(genericdef) then
  389. begin
  390. { check the hints of the found generic symbol }
  391. srsym:=genericdef.typesym;
  392. check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
  393. end;
  394. end;
  395. function parse_generic_parameters:TFPObjectList;
  396. var
  397. generictype : ttypesym;
  398. begin
  399. result:=TFPObjectList.Create(false);
  400. repeat
  401. if token=_ID then
  402. begin
  403. generictype:=ttypesym.create(orgpattern,cundefinedtype);
  404. include(generictype.symoptions,sp_generic_para);
  405. result.add(generictype);
  406. end;
  407. consume(_ID);
  408. until not try_to_consume(_COMMA) ;
  409. end;
  410. procedure insert_generic_parameter_types(def:tstoreddef;genericdef:tstoreddef;genericlist:TFPObjectList);
  411. var
  412. i: longint;
  413. generictype: ttypesym;
  414. st: tsymtable;
  415. begin
  416. def.genericdef:=genericdef;
  417. if not assigned(genericlist) then
  418. exit;
  419. case def.typ of
  420. recorddef,objectdef: st:=tabstractrecorddef(def).symtable;
  421. arraydef: st:=tarraydef(def).symtable;
  422. procvardef,procdef: st:=tabstractprocdef(def).parast;
  423. else
  424. internalerror(201101020);
  425. end;
  426. for i:=0 to genericlist.count-1 do
  427. begin
  428. generictype:=ttypesym(genericlist[i]);
  429. if generictype.typedef.typ=undefineddef then
  430. include(def.defoptions,df_generic)
  431. else
  432. include(def.defoptions,df_specialization);
  433. st.insert(generictype);
  434. end;
  435. end;
  436. end.