pgenutil.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  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. old_current_structdef : tabstractrecorddef;
  69. old_current_genericdef,old_current_specializedef : tstoreddef;
  70. begin
  71. { retrieve generic def that we are going to replace }
  72. genericdef:=tstoreddef(tt);
  73. tt:=nil;
  74. onlyparsepara:=false;
  75. { either symname must be given or genericdef needs to be valid }
  76. if (symname='') and
  77. (not assigned(genericdef) or
  78. not assigned(genericdef.typesym) or
  79. (genericdef.typesym.typ<>typesym)) then
  80. internalerror(2011042701);
  81. { only need to record the tokens, then we don't know the type yet ... }
  82. if parse_generic then
  83. begin
  84. { ... but we have to insert a def into the symtable if the generic
  85. is not a parent or an implemented interface else the deflist
  86. of generic and specialization might not be equally sized which
  87. is later assumed }
  88. if not parse_class_parent then
  89. tt:=tundefineddef.create;
  90. onlyparsepara:=true;
  91. end;
  92. { Only parse the parameters for recovery or
  93. for recording in genericbuf }
  94. if onlyparsepara then
  95. begin
  96. consume(_LSHARPBRACKET);
  97. gencount:=0;
  98. repeat
  99. pt2:=factor(false,true);
  100. pt2.free;
  101. inc(gencount);
  102. until not try_to_consume(_COMMA);
  103. consume(_RSHARPBRACKET);
  104. { we need to return a def that can later pass some checks like
  105. whether it's an interface or not }
  106. if parse_generic and (not assigned(tt) or (tt.typ=undefineddef)) then
  107. begin
  108. if (symname='') and (df_generic in genericdef.defoptions) then
  109. { this happens in non-Delphi modes }
  110. tt:=genericdef
  111. else
  112. begin
  113. { find the corresponding generic symbol so that any checks
  114. done on the returned def will be handled correctly }
  115. str(gencount,countstr);
  116. if symname='' then
  117. genname:=ttypesym(genericdef.typesym).realname
  118. else
  119. genname:=symname;
  120. genname:=genname+'$'+countstr;
  121. ugenname:=upper(genname);
  122. if not searchsym(ugenname,srsym,st) or
  123. (srsym.typ<>typesym) then
  124. begin
  125. identifier_not_found(genname);
  126. exit;
  127. end;
  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. if parse_class_parent then
  306. begin
  307. old_current_structdef:=current_structdef;
  308. old_current_genericdef:=current_genericdef;
  309. old_current_specializedef:=current_specializedef;
  310. if genericdef.owner.symtabletype in [recordsymtable,objectsymtable] then
  311. current_structdef:=tabstractrecorddef(genericdef.owner.defowner)
  312. else
  313. current_structdef:=nil;
  314. current_genericdef:=nil;
  315. current_specializedef:=nil;
  316. end;
  317. { First a new typesym so we can reuse this specialization and
  318. references to this specialization can be handled }
  319. srsym:=ttypesym.create(specializename,generrordef);
  320. specializest.insert(srsym);
  321. if not assigned(genericdef.generictokenbuf) then
  322. internalerror(200511171);
  323. current_scanner.startreplaytokens(genericdef.generictokenbuf);
  324. read_named_type(tt,specializename,genericdef,generictypelist,false);
  325. ttypesym(srsym).typedef:=tt;
  326. tt.typesym:=srsym;
  327. { Note regarding hint directives:
  328. There is no need to remove the flags for them from the
  329. specialized generic symbol, because hint directives that
  330. follow the specialization are handled by the code in
  331. pdecl.types_dec and added to the type symbol.
  332. E.g.: TFoo = TBar<Blubb> deprecated;
  333. Here the symbol TBar$1$Blubb will contain the
  334. "sp_hint_deprecated" flag while the TFoo symbol won't.}
  335. case tt.typ of
  336. { Build VMT indexes for classes and read hint directives }
  337. objectdef:
  338. begin
  339. try_consume_hintdirective(srsym.symoptions,srsym.deprecatedmsg);
  340. consume(_SEMICOLON);
  341. vmtbuilder:=TVMTBuilder.Create(tobjectdef(tt));
  342. vmtbuilder.generate_vmt;
  343. vmtbuilder.free;
  344. end;
  345. { handle params, calling convention, etc }
  346. procvardef:
  347. begin
  348. if not check_proc_directive(true) then
  349. begin
  350. try_consume_hintdirective(ttypesym(srsym).symoptions,ttypesym(srsym).deprecatedmsg);
  351. consume(_SEMICOLON);
  352. end;
  353. parse_var_proc_directives(ttypesym(srsym));
  354. handle_calling_convention(tprocvardef(tt));
  355. if try_consume_hintdirective(ttypesym(srsym).symoptions,ttypesym(srsym).deprecatedmsg) then
  356. consume(_SEMICOLON);
  357. end;
  358. else
  359. { parse hint directives for records and arrays }
  360. begin
  361. try_consume_hintdirective(srsym.symoptions,srsym.deprecatedmsg);
  362. consume(_SEMICOLON);
  363. end;
  364. end;
  365. { Consume the semicolon if it is also recorded }
  366. try_to_consume(_SEMICOLON);
  367. if parse_class_parent then
  368. begin
  369. current_structdef:=old_current_structdef;
  370. current_genericdef:=old_current_genericdef;
  371. current_specializedef:=old_current_specializedef;
  372. end;
  373. end;
  374. { Restore symtablestack }
  375. current_module.extendeddefs.free;
  376. current_module.extendeddefs:=oldextendeddefs;
  377. symtablestack.free;
  378. symtablestack:=oldsymtablestack;
  379. end
  380. else
  381. begin
  382. { There is comment few lines before ie 200512115
  383. saying "We are parsing the same objectdef, the def index numbers
  384. are the same". This is wrong (index numbers are not same)
  385. in case there is specialization (S2 in this case) inside
  386. specialized generic (G2 in this case) which is equal to
  387. some previous specialization (S1 in this case). In that case,
  388. new symbol is not added to currently specialized type
  389. (S in this case) for that specializations (S2 in this case),
  390. and this results in that specialization and generic definition
  391. don't have same number of elements in their object symbol tables.
  392. This patch adds undefined def to ensure that those
  393. two symbol tables will have same number of elements.
  394. }
  395. tundefineddef.create;
  396. end;
  397. if not (token in [_GT, _RSHARPBRACKET]) then
  398. begin
  399. consume(_RSHARPBRACKET);
  400. exit;
  401. end
  402. else
  403. consume(token);
  404. genericdeflist.free;
  405. generictypelist.free;
  406. if assigned(genericdef) then
  407. begin
  408. { check the hints of the found generic symbol }
  409. srsym:=genericdef.typesym;
  410. check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
  411. end;
  412. end;
  413. function parse_generic_parameters:TFPObjectList;
  414. var
  415. generictype : ttypesym;
  416. begin
  417. result:=TFPObjectList.Create(false);
  418. repeat
  419. if token=_ID then
  420. begin
  421. generictype:=ttypesym.create(orgpattern,cundefinedtype);
  422. include(generictype.symoptions,sp_generic_para);
  423. result.add(generictype);
  424. end;
  425. consume(_ID);
  426. until not try_to_consume(_COMMA) ;
  427. end;
  428. procedure insert_generic_parameter_types(def:tstoreddef;genericdef:tstoreddef;genericlist:TFPObjectList);
  429. var
  430. i: longint;
  431. generictype: ttypesym;
  432. st: tsymtable;
  433. begin
  434. def.genericdef:=genericdef;
  435. if not assigned(genericlist) then
  436. exit;
  437. case def.typ of
  438. recorddef,objectdef: st:=tabstractrecorddef(def).symtable;
  439. arraydef: st:=tarraydef(def).symtable;
  440. procvardef,procdef: st:=tabstractprocdef(def).parast;
  441. else
  442. internalerror(201101020);
  443. end;
  444. for i:=0 to genericlist.count-1 do
  445. begin
  446. generictype:=ttypesym(genericlist[i]);
  447. if generictype.typedef.typ=undefineddef then
  448. include(def.defoptions,df_generic)
  449. else
  450. include(def.defoptions,df_specialization);
  451. st.insert(generictype);
  452. end;
  453. end;
  454. end.