pgenutil.pas 17 KB

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