pgenutil.pas 29 KB

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