pgenutil.pas 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  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. { global }
  25. globtype,
  26. { symtable }
  27. symtype,symdef,symbase;
  28. procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;_prettyname:string;parsedtype:tdef;symname:string);
  29. function parse_generic_parameters:TFPObjectList;
  30. function parse_generic_specialization_types(genericdeflist:tfpobjectlist;out prettyname,specializename:ansistring;parsedtype:tdef):boolean;
  31. procedure insert_generic_parameter_types(def:tstoreddef;genericdef:tstoreddef;genericlist:TFPObjectList);
  32. procedure maybe_insert_generic_rename_symbol(const name:tidstring;genericlist:tfpobjectlist);
  33. function generate_generic_name(const name:tidstring;specializename:ansistring):tidstring;
  34. type
  35. tspecializationstate = record
  36. oldsymtablestack : tsymtablestack;
  37. oldextendeddefs : TFPHashObjectList;
  38. end;
  39. procedure specialization_init(genericdef:tdef;var state:tspecializationstate);
  40. procedure specialization_done(var state:tspecializationstate);
  41. implementation
  42. uses
  43. { common }
  44. cutils,fpccrc,
  45. { global }
  46. globals,tokens,verbose,finput,
  47. { symtable }
  48. symconst,symsym,symtable,
  49. { modules }
  50. fmodule,
  51. { pass 1 }
  52. htypechk,
  53. node,nobj,nmem,
  54. { parser }
  55. scanner,
  56. pbase,pexpr,pdecsub,ptype;
  57. procedure maybe_add_waiting_unit(tt:tdef);
  58. var
  59. hmodule : tmodule;
  60. begin
  61. if not assigned(tt) or
  62. not (df_generic in tt.defoptions) then
  63. exit;
  64. hmodule:=find_module_from_symtable(tt.owner);
  65. if not assigned(hmodule) then
  66. internalerror(2012092401);
  67. if hmodule=current_module then
  68. exit;
  69. if hmodule.state<>ms_compiled then
  70. begin
  71. {$ifdef DEBUG_UNITWAITING}
  72. Writeln('Unit ', current_module.modulename^,
  73. ' waiting for ', hmodule.modulename^);
  74. {$endif DEBUG_UNITWAITING}
  75. if current_module.waitingforunit.indexof(hmodule)<0 then
  76. current_module.waitingforunit.add(hmodule);
  77. if hmodule.waitingunits.indexof(current_module)<0 then
  78. hmodule.waitingunits.add(current_module);
  79. end;
  80. end;
  81. procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;_prettyname:string;parsedtype:tdef;symname:string);
  82. var
  83. st : TSymtable;
  84. srsym : tsym;
  85. pt2 : tnode;
  86. found,
  87. first,
  88. err : boolean;
  89. errval,
  90. i,
  91. gencount : longint;
  92. crc : cardinal;
  93. genericdef,def : tstoreddef;
  94. generictype : ttypesym;
  95. genericdeflist : TFPObjectList;
  96. generictypelist : TFPObjectList;
  97. prettyname,specializename : ansistring;
  98. ufinalspecializename,
  99. countstr,genname,ugenname,finalspecializename : string;
  100. vmtbuilder : TVMTBuilder;
  101. specializest : tsymtable;
  102. item : tobject;
  103. old_current_structdef : tabstractrecorddef;
  104. old_current_genericdef,old_current_specializedef : tstoreddef;
  105. tempst : tglobalsymtable;
  106. old_block_type: tblock_type;
  107. hashedid: thashedidstring;
  108. state : tspecializationstate;
  109. hmodule : tmodule;
  110. oldcurrent_filepos : tfileposinfo;
  111. begin
  112. { retrieve generic def that we are going to replace }
  113. genericdef:=tstoreddef(tt);
  114. tt:=nil;
  115. { either symname must be given or genericdef needs to be valid }
  116. if (symname='') and
  117. (not assigned(genericdef) or
  118. not assigned(genericdef.typesym) or
  119. (genericdef.typesym.typ<>typesym)) then
  120. internalerror(2011042701);
  121. { Only parse the parameters for recovery or
  122. for recording in genericbuf }
  123. if parse_generic then
  124. begin
  125. first:=assigned(parsedtype);
  126. if not first and not try_to_consume(_LT) then
  127. consume(_LSHARPBRACKET);
  128. gencount:=0;
  129. repeat
  130. if not first then
  131. begin
  132. pt2:=factor(false,true);
  133. pt2.free;
  134. end;
  135. first:=false;
  136. inc(gencount);
  137. until not try_to_consume(_COMMA);
  138. if not try_to_consume(_GT) then
  139. consume(_RSHARPBRACKET);
  140. { we need to return a def that can later pass some checks like
  141. whether it's an interface or not }
  142. if not assigned(tt) or (tt.typ=undefineddef) then
  143. begin
  144. if (symname='') and (df_generic in genericdef.defoptions) then
  145. { this happens in non-Delphi modes }
  146. tt:=genericdef
  147. else
  148. begin
  149. { find the corresponding generic symbol so that any checks
  150. done on the returned def will be handled correctly }
  151. str(gencount,countstr);
  152. if symname='' then
  153. genname:=ttypesym(genericdef.typesym).realname
  154. else
  155. genname:=symname;
  156. genname:=genname+'$'+countstr;
  157. ugenname:=upper(genname);
  158. { first check whether the found name is the same as that of
  159. the current def or one of its (generic) surrounding defs;
  160. this is necessary as the symbol of the generic can not yet
  161. be used for lookup as it still contains a reference to an
  162. errordef) }
  163. def:=current_genericdef;
  164. repeat
  165. if def.typ in [objectdef,recorddef] then
  166. if tabstractrecorddef(def).objname^=ugenname then
  167. begin
  168. tt:=def;
  169. break;
  170. end;
  171. def:=tstoreddef(def.owner.defowner);
  172. until not assigned(def) or not (df_generic in def.defoptions);
  173. { it's not part of the current object hierarchy, so search
  174. for the symbol }
  175. if not assigned(tt) then
  176. begin
  177. if not searchsym(ugenname,srsym,st) or
  178. (srsym.typ<>typesym) then
  179. begin
  180. identifier_not_found(genname);
  181. tt:=generrordef;
  182. exit;
  183. end;
  184. tt:=ttypesym(srsym).typedef;
  185. { this happens in non-Delphi modes if we encounter a
  186. specialization of the generic class or record we're
  187. currently parsing }
  188. if (tt.typ=errordef) and assigned(current_structdef) and
  189. (current_structdef.objname^=ugenname) then
  190. tt:=current_structdef;
  191. end;
  192. end;
  193. end;
  194. exit;
  195. end;
  196. if not assigned(parsedtype) and not try_to_consume(_LT) then
  197. consume(_LSHARPBRACKET);
  198. generictypelist:=TFPObjectList.create(false);
  199. genericdeflist:=TFPObjectList.Create(false);
  200. { Parse type parameters }
  201. err:=not parse_generic_specialization_types(genericdeflist,prettyname,specializename,parsedtype);
  202. if err then
  203. begin
  204. try_to_consume(_RSHARPBRACKET);
  205. tt:=generrordef;
  206. exit;
  207. end;
  208. { use the name of the symbol as procvars return a user friendly version
  209. of the name }
  210. if symname='' then
  211. genname:=ttypesym(genericdef.typesym).realname
  212. else
  213. genname:=symname;
  214. { in case of non-Delphi mode the type name could already be a generic
  215. def (but maybe the wrong one) }
  216. if assigned(genericdef) and
  217. ([df_generic,df_specialization]*genericdef.defoptions<>[]) then
  218. begin
  219. { remove the type count suffix from the generic's name }
  220. for i:=Length(genname) downto 1 do
  221. if genname[i]='$' then
  222. begin
  223. genname:=copy(genname,1,i-1);
  224. break;
  225. end;
  226. { in case of a specialization we've only reached the specialization
  227. checksum yet }
  228. if df_specialization in genericdef.defoptions then
  229. for i:=length(genname) downto 1 do
  230. if genname[i]='$' then
  231. begin
  232. genname:=copy(genname,1,i-1);
  233. break;
  234. end;
  235. end
  236. else
  237. { search for a potential suffix }
  238. for i:=length(genname) downto 1 do
  239. if genname[i]='$' then
  240. begin
  241. { if the part right of the $ is a number we assume that the left
  242. part is the name of the generic, otherwise we assume that the
  243. complete name is the name of the generic }
  244. countstr:=copy(genname,i+1,length(genname)-i);
  245. gencount:=0;
  246. val(countstr,gencount,errval);
  247. if errval=0 then
  248. genname:=copy(genname,1,i-1);
  249. break;
  250. end;
  251. { search a generic with the given count of params }
  252. countstr:='';
  253. str(genericdeflist.Count,countstr);
  254. genname:=genname+'$'+countstr;
  255. ugenname:=upper(genname);
  256. if assigned(genericdef) and (genericdef.owner.symtabletype in [objectsymtable,recordsymtable]) then
  257. begin
  258. if genericdef.owner.symtabletype = objectsymtable then
  259. found:=searchsym_in_class(tobjectdef(genericdef.owner.defowner),tobjectdef(genericdef.owner.defowner),ugenname,srsym,st,false)
  260. else
  261. found:=searchsym_in_record(tabstractrecorddef(genericdef.owner.defowner),ugenname,srsym,st);
  262. end
  263. else
  264. found:=searchsym(ugenname,srsym,st);
  265. if not found or (srsym.typ<>typesym) then
  266. begin
  267. identifier_not_found(genname);
  268. genericdeflist.Free;
  269. generictypelist.Free;
  270. tt:=generrordef;
  271. exit;
  272. end;
  273. { we've found the correct def }
  274. genericdef:=tstoreddef(ttypesym(srsym).typedef);
  275. { build the new type's name }
  276. finalspecializename:=generate_generic_name(genname,specializename);
  277. ufinalspecializename:=upper(finalspecializename);
  278. prettyname:=genericdef.typesym.prettyname+'<'+prettyname+'>';
  279. { select the symtable containing the params }
  280. case genericdef.typ of
  281. procdef:
  282. st:=genericdef.GetSymtable(gs_para);
  283. objectdef,
  284. recorddef:
  285. st:=genericdef.GetSymtable(gs_record);
  286. arraydef:
  287. st:=tarraydef(genericdef).symtable;
  288. procvardef:
  289. st:=genericdef.GetSymtable(gs_para);
  290. else
  291. internalerror(200511182);
  292. end;
  293. { build the list containing the types for the generic params }
  294. gencount:=0;
  295. for i:=0 to st.SymList.Count-1 do
  296. begin
  297. srsym:=tsym(st.SymList[i]);
  298. if sp_generic_para in srsym.symoptions then
  299. begin
  300. if gencount=genericdeflist.Count then
  301. internalerror(2011042702);
  302. generictype:=ttypesym.create(srsym.realname,tdef(genericdeflist[gencount]));
  303. generictypelist.add(generictype);
  304. inc(gencount);
  305. end;
  306. end;
  307. { Special case if we are referencing the current defined object }
  308. if assigned(current_structdef) and
  309. (current_structdef.objname^=ufinalspecializename) then
  310. tt:=current_structdef;
  311. { decide in which symtable to put the specialization }
  312. if current_module.is_unit and current_module.in_interface then
  313. specializest:=current_module.globalsymtable
  314. else
  315. specializest:=current_module.localsymtable;
  316. { Can we reuse an already specialized type? }
  317. { for this first check whether we are currently specializing a nested
  318. type of the current (main) specialization (this is necessary, because
  319. during that time the symbol of the main specialization will still
  320. contain a reference to an errordef) }
  321. if not assigned(tt) and assigned(current_specializedef) then
  322. begin
  323. def:=current_specializedef;
  324. repeat
  325. if def.typ in [objectdef,recorddef] then
  326. if tabstractrecorddef(def).objname^=ufinalspecializename then begin
  327. tt:=def;
  328. break;
  329. end;
  330. def:=tstoreddef(def.owner.defowner);
  331. until not assigned(def) or not (df_specialization in def.defoptions);
  332. end;
  333. { now check whether there is a specialization somewhere else }
  334. if not assigned(tt) then
  335. begin
  336. hashedid.id:=ufinalspecializename;
  337. srsym:=tsym(specializest.findwithhash(hashedid));
  338. if assigned(srsym) then
  339. begin
  340. if srsym.typ<>typesym then
  341. internalerror(200710171);
  342. tt:=ttypesym(srsym).typedef;
  343. end
  344. else
  345. { the generic could have been specialized in the globalsymtable
  346. already, so search there as well }
  347. if (specializest<>current_module.globalsymtable) and assigned(current_module.globalsymtable) then
  348. begin
  349. srsym:=tsym(current_module.globalsymtable.findwithhash(hashedid));
  350. if assigned(srsym) then
  351. begin
  352. if srsym.typ<>typesym then
  353. internalerror(2011121101);
  354. tt:=ttypesym(srsym).typedef;
  355. end;
  356. end;
  357. end;
  358. if not assigned(tt) then
  359. begin
  360. specialization_init(genericdef,state);
  361. { push a temporary global symtable so that the specialization is
  362. added to the correct symtable; this symtable does not contain
  363. any other symbols, so that the type resolution can not be
  364. influenced by symbols in the current unit }
  365. tempst:=tspecializesymtable.create(current_module.modulename^,current_module.moduleid);
  366. symtablestack.push(tempst);
  367. { Reparse the original type definition }
  368. if not err then
  369. begin
  370. if parse_class_parent then
  371. begin
  372. old_current_structdef:=current_structdef;
  373. old_current_genericdef:=current_genericdef;
  374. old_current_specializedef:=current_specializedef;
  375. if genericdef.owner.symtabletype in [recordsymtable,objectsymtable] then
  376. current_structdef:=tabstractrecorddef(genericdef.owner.defowner)
  377. else
  378. current_structdef:=nil;
  379. current_genericdef:=nil;
  380. current_specializedef:=nil;
  381. end;
  382. maybe_add_waiting_unit(genericdef);
  383. { First a new typesym so we can reuse this specialization and
  384. references to this specialization can be handled }
  385. srsym:=ttypesym.create(finalspecializename,generrordef);
  386. specializest.insert(srsym);
  387. { specializations are declarations as such it is the wisest to
  388. declare set the blocktype to "type"; otherwise we'll
  389. experience unexpected side effects like the addition of
  390. classrefdefs if we have a generic that's derived from another
  391. generic }
  392. old_block_type:=block_type;
  393. block_type:=bt_type;
  394. if not assigned(genericdef.generictokenbuf) then
  395. internalerror(200511171);
  396. hmodule:=find_module_from_symtable(genericdef.owner);
  397. if hmodule=nil then
  398. internalerror(2012051202);
  399. oldcurrent_filepos:=current_filepos;
  400. { use the index the module got from the current compilation process }
  401. current_filepos.moduleindex:=hmodule.unit_index;
  402. current_tokenpos:=current_filepos;
  403. current_scanner.startreplaytokens(genericdef.generictokenbuf);
  404. read_named_type(tt,srsym,genericdef,generictypelist,false);
  405. current_filepos:=oldcurrent_filepos;
  406. ttypesym(srsym).typedef:=tt;
  407. tt.typesym:=srsym;
  408. if _prettyname<>'' then
  409. ttypesym(tt.typesym).fprettyname:=_prettyname
  410. else
  411. ttypesym(tt.typesym).fprettyname:=prettyname;
  412. { Note regarding hint directives:
  413. There is no need to remove the flags for them from the
  414. specialized generic symbol, because hint directives that
  415. follow the specialization are handled by the code in
  416. pdecl.types_dec and added to the type symbol.
  417. E.g.: TFoo = TBar<Blubb> deprecated;
  418. Here the symbol TBar$1$Blubb will contain the
  419. "sp_hint_deprecated" flag while the TFoo symbol won't.}
  420. case tt.typ of
  421. { Build VMT indexes for classes and read hint directives }
  422. objectdef:
  423. begin
  424. try_consume_hintdirective(srsym.symoptions,srsym.deprecatedmsg);
  425. consume(_SEMICOLON);
  426. vmtbuilder:=TVMTBuilder.Create(tobjectdef(tt));
  427. vmtbuilder.generate_vmt;
  428. vmtbuilder.free;
  429. end;
  430. { handle params, calling convention, etc }
  431. procvardef:
  432. begin
  433. if not check_proc_directive(true) then
  434. begin
  435. try_consume_hintdirective(ttypesym(srsym).symoptions,ttypesym(srsym).deprecatedmsg);
  436. consume(_SEMICOLON);
  437. end;
  438. parse_var_proc_directives(ttypesym(srsym));
  439. handle_calling_convention(tprocvardef(tt));
  440. if try_consume_hintdirective(ttypesym(srsym).symoptions,ttypesym(srsym).deprecatedmsg) then
  441. consume(_SEMICOLON);
  442. end;
  443. else
  444. { parse hint directives for records and arrays }
  445. begin
  446. try_consume_hintdirective(srsym.symoptions,srsym.deprecatedmsg);
  447. consume(_SEMICOLON);
  448. end;
  449. end;
  450. { Consume the semicolon if it is also recorded }
  451. try_to_consume(_SEMICOLON);
  452. block_type:=old_block_type;
  453. if parse_class_parent then
  454. begin
  455. current_structdef:=old_current_structdef;
  456. current_genericdef:=old_current_genericdef;
  457. current_specializedef:=old_current_specializedef;
  458. end;
  459. end;
  460. { extract all created symbols and defs from the temporary symtable
  461. and add them to the specializest }
  462. for i:=tempst.SymList.Count-1 downto 0 do
  463. begin
  464. item:=tempst.SymList.Items[i];
  465. { using changeowner the symbol is automatically added to the
  466. new symtable }
  467. tsym(item).ChangeOwner(specializest);
  468. end;
  469. for i:=tempst.DefList.Count-1 downto 0 do
  470. begin
  471. item:=tempst.DefList.Items[i];
  472. { using changeowner the def is automatically added to the new
  473. symtable }
  474. tdef(item).ChangeOwner(specializest);
  475. end;
  476. { if a generic was declared during the specialization we need to
  477. flag the specialize symtable accordingly }
  478. if sto_has_generic in tempst.tableoptions then
  479. specializest.includeoption(sto_has_generic);
  480. tempst.free;
  481. specialization_done(state);
  482. end;
  483. if not (token in [_GT, _RSHARPBRACKET]) then
  484. begin
  485. consume(_RSHARPBRACKET);
  486. exit;
  487. end
  488. else
  489. consume(token);
  490. genericdeflist.free;
  491. generictypelist.free;
  492. if assigned(genericdef) then
  493. begin
  494. { check the hints of the found generic symbol }
  495. srsym:=genericdef.typesym;
  496. check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
  497. end;
  498. end;
  499. function parse_generic_parameters:TFPObjectList;
  500. var
  501. generictype : ttypesym;
  502. begin
  503. result:=TFPObjectList.Create(false);
  504. repeat
  505. if token=_ID then
  506. begin
  507. generictype:=ttypesym.create(orgpattern,cundefinedtype);
  508. include(generictype.symoptions,sp_generic_para);
  509. result.add(generictype);
  510. end;
  511. consume(_ID);
  512. until not try_to_consume(_COMMA) ;
  513. end;
  514. function parse_generic_specialization_types(genericdeflist:tfpobjectlist;out prettyname,specializename:ansistring;parsedtype:tdef):boolean;
  515. var
  516. old_block_type : tblock_type;
  517. first : boolean;
  518. typeparam : tnode;
  519. begin
  520. result:=true;
  521. if genericdeflist=nil then
  522. internalerror(2012061401);
  523. { set the block type to type, so that the parsed type are returned as
  524. ttypenode (e.g. classes are in non type-compatible blocks returned as
  525. tloadvmtaddrnode) }
  526. old_block_type:=block_type;
  527. { if parsedtype is set, then the first type identifer was already parsed
  528. (happens in inline specializations) and thus we only need to parse
  529. the remaining types and do as if the first one was already given }
  530. first:=not assigned(parsedtype);
  531. if assigned(parsedtype) then
  532. begin
  533. genericdeflist.Add(parsedtype);
  534. specializename:='$'+parsedtype.typename;
  535. prettyname:=parsedtype.typesym.prettyname;
  536. end
  537. else
  538. begin
  539. specializename:='';
  540. prettyname:='';
  541. end;
  542. while not (token in [_GT,_RSHARPBRACKET]) do
  543. begin
  544. { "first" is set to false at the end of the loop! }
  545. if not first then
  546. consume(_COMMA);
  547. block_type:=bt_type;
  548. typeparam:=factor(false,true);
  549. if typeparam.nodetype=typen then
  550. begin
  551. if df_generic in typeparam.resultdef.defoptions then
  552. Message(parser_e_no_generics_as_params);
  553. genericdeflist.Add(typeparam.resultdef);
  554. if not assigned(typeparam.resultdef.typesym) then
  555. message(type_e_generics_cannot_reference_itself)
  556. else
  557. begin
  558. specializename:=specializename+'$'+typeparam.resultdef.typename;
  559. if first then
  560. prettyname:=prettyname+typeparam.resultdef.typesym.prettyname
  561. else
  562. prettyname:=prettyname+','+typeparam.resultdef.typesym.prettyname;
  563. end;
  564. end
  565. else
  566. begin
  567. Message(type_e_type_id_expected);
  568. result:=false;
  569. end;
  570. typeparam.free;
  571. first:=false;
  572. end;
  573. block_type:=old_block_type;
  574. end;
  575. procedure insert_generic_parameter_types(def:tstoreddef;genericdef:tstoreddef;genericlist:TFPObjectList);
  576. var
  577. i: longint;
  578. generictype: ttypesym;
  579. st: tsymtable;
  580. begin
  581. def.genericdef:=genericdef;
  582. if not assigned(genericlist) then
  583. exit;
  584. case def.typ of
  585. recorddef,objectdef: st:=tabstractrecorddef(def).symtable;
  586. arraydef: st:=tarraydef(def).symtable;
  587. procvardef,procdef: st:=tabstractprocdef(def).parast;
  588. else
  589. internalerror(201101020);
  590. end;
  591. for i:=0 to genericlist.count-1 do
  592. begin
  593. generictype:=ttypesym(genericlist[i]);
  594. if generictype.typedef.typ=undefineddef then
  595. include(def.defoptions,df_generic)
  596. else
  597. include(def.defoptions,df_specialization);
  598. st.insert(generictype);
  599. end;
  600. end;
  601. procedure maybe_insert_generic_rename_symbol(const name:tidstring;genericlist:tfpobjectlist);
  602. var
  603. gensym : ttypesym;
  604. begin
  605. { for generics in non-Delphi modes we insert a private type symbol
  606. that has the same base name as the currently parsed generic and
  607. that references this defs }
  608. if not (m_delphi in current_settings.modeswitches) and
  609. (
  610. (
  611. parse_generic and
  612. assigned(genericlist) and
  613. (genericlist.count>0)
  614. ) or
  615. (
  616. assigned(current_specializedef) and
  617. assigned(current_structdef.genericdef) and
  618. (current_structdef.genericdef.typ in [objectdef,recorddef]) and
  619. (pos('$',name)>0)
  620. )
  621. ) then
  622. begin
  623. { we need to pass nil as def here, because the constructor wants
  624. to set the typesym of the def which is not what we want }
  625. gensym:=ttypesym.create(copy(name,1,pos('$',name)-1),nil);
  626. gensym.typedef:=current_structdef;
  627. include(gensym.symoptions,sp_internal);
  628. { the symbol should be only visible to the generic class
  629. itself }
  630. gensym.visibility:=vis_strictprivate;
  631. symtablestack.top.insert(gensym);
  632. end;
  633. end;
  634. function generate_generic_name(const name:tidstring;specializename:ansistring):tidstring;
  635. var
  636. crc : cardinal;
  637. begin
  638. if specializename='' then
  639. internalerror(2012061901);
  640. { build the new type's name }
  641. crc:=UpdateCrc32(0,specializename[1],length(specializename));
  642. result:=name+'$crc'+hexstr(crc,8);
  643. end;
  644. procedure specialization_init(genericdef:tdef;var state: tspecializationstate);
  645. var
  646. pu : tused_unit;
  647. hmodule : tmodule;
  648. unitsyms : TFPHashObjectList;
  649. sym : tsym;
  650. i : Integer;
  651. begin
  652. if not assigned(genericdef) then
  653. internalerror(200705151);
  654. { Setup symtablestack at definition time
  655. to get types right, however this is not perfect, we should probably record
  656. the resolved symbols }
  657. state.oldsymtablestack:=symtablestack;
  658. state.oldextendeddefs:=current_module.extendeddefs;
  659. current_module.extendeddefs:=TFPHashObjectList.create(true);
  660. symtablestack:=tdefawaresymtablestack.create;
  661. hmodule:=find_module_from_symtable(genericdef.owner);
  662. if hmodule=nil then
  663. internalerror(200705152);
  664. { collect all unit syms in the generic's unit as we need to establish
  665. their unitsym.module link again so that unit identifiers can be used }
  666. unitsyms:=tfphashobjectlist.create(false);
  667. if (hmodule<>current_module) and assigned(hmodule.globalsymtable) then
  668. for i:=0 to hmodule.globalsymtable.symlist.count-1 do
  669. begin
  670. sym:=tsym(hmodule.globalsymtable.symlist[i]);
  671. if sym.typ=unitsym then
  672. unitsyms.add(upper(sym.realname),sym);
  673. end;
  674. { add all units if we are specializing inside the current unit (as the
  675. generic could have been declared in the implementation part), but load
  676. only interface units, if we are in a different unit as then the generic
  677. needs to be in the interface section }
  678. pu:=tused_unit(hmodule.used_units.first);
  679. while assigned(pu) do
  680. begin
  681. if not assigned(pu.u.globalsymtable) then
  682. { in certain circular, but valid unit constellations it can happen
  683. that we specialize a generic in a different unit that was used
  684. in the implementation section of the generic's unit and were the
  685. interface is still being parsed and thus the localsymtable is in
  686. reality the global symtable }
  687. if pu.u.in_interface then
  688. symtablestack.push(pu.u.localsymtable)
  689. else
  690. internalerror(200705153)
  691. else
  692. symtablestack.push(pu.u.globalsymtable);
  693. sym:=tsym(unitsyms.find(pu.u.modulename^));
  694. if assigned(sym) and not assigned(tunitsym(sym).module) then
  695. tunitsym(sym).module:=pu.u;
  696. pu:=tused_unit(pu.next);
  697. end;
  698. unitsyms.free;
  699. if assigned(hmodule.globalsymtable) then
  700. symtablestack.push(hmodule.globalsymtable);
  701. { push the localsymtable if needed }
  702. if (hmodule<>current_module) or not current_module.in_interface then
  703. symtablestack.push(hmodule.localsymtable);
  704. end;
  705. procedure specialization_done(var state: tspecializationstate);
  706. begin
  707. { Restore symtablestack }
  708. current_module.extendeddefs.free;
  709. current_module.extendeddefs:=state.oldextendeddefs;
  710. symtablestack.free;
  711. symtablestack:=state.oldsymtablestack;
  712. { clear the state record to be on the safe side }
  713. fillchar(state, sizeof(state), 0);
  714. end;
  715. end.