2
0

pgenutil.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  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;_prettyname:string;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,globtype,tokens,verbose,
  35. { symtable }
  36. symconst,symbase,symsym,symtable,
  37. { modules }
  38. fmodule,
  39. { pass 1 }
  40. htypechk,
  41. node,nobj,nmem,
  42. { parser }
  43. scanner,
  44. pbase,pexpr,pdecsub,ptype;
  45. procedure generate_specialization(var tt:tdef;parse_class_parent:boolean;_prettyname:string;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. prettyname : ansistring;
  63. uspecializename,
  64. countstr,genname,ugenname,specializename : string;
  65. vmtbuilder : TVMTBuilder;
  66. specializest : tsymtable;
  67. item : tobject;
  68. old_current_structdef : tabstractrecorddef;
  69. old_current_genericdef,old_current_specializedef : tstoreddef;
  70. tempst : tglobalsymtable;
  71. old_block_type: tblock_type;
  72. begin
  73. { retrieve generic def that we are going to replace }
  74. genericdef:=tstoreddef(tt);
  75. tt:=nil;
  76. { either symname must be given or genericdef needs to be valid }
  77. if (symname='') and
  78. (not assigned(genericdef) or
  79. not assigned(genericdef.typesym) or
  80. (genericdef.typesym.typ<>typesym)) then
  81. internalerror(2011042701);
  82. { Only parse the parameters for recovery or
  83. for recording in genericbuf }
  84. if parse_generic then
  85. begin
  86. consume(_LSHARPBRACKET);
  87. gencount:=0;
  88. repeat
  89. pt2:=factor(false,true);
  90. pt2.free;
  91. inc(gencount);
  92. until not try_to_consume(_COMMA);
  93. consume(_RSHARPBRACKET);
  94. { we need to return a def that can later pass some checks like
  95. whether it's an interface or not }
  96. if parse_generic and (not assigned(tt) or (tt.typ=undefineddef)) then
  97. begin
  98. if (symname='') and (df_generic in genericdef.defoptions) then
  99. { this happens in non-Delphi modes }
  100. tt:=genericdef
  101. else
  102. begin
  103. { find the corresponding generic symbol so that any checks
  104. done on the returned def will be handled correctly }
  105. str(gencount,countstr);
  106. if symname='' then
  107. genname:=ttypesym(genericdef.typesym).realname
  108. else
  109. genname:=symname;
  110. genname:=genname+'$'+countstr;
  111. ugenname:=upper(genname);
  112. if not searchsym(ugenname,srsym,st) or
  113. (srsym.typ<>typesym) then
  114. begin
  115. identifier_not_found(genname);
  116. exit;
  117. end;
  118. tt:=ttypesym(srsym).typedef;
  119. end;
  120. end;
  121. exit;
  122. end;
  123. if not assigned(parsedtype) and not try_to_consume(_LT) then
  124. consume(_LSHARPBRACKET);
  125. generictypelist:=TFPObjectList.create(false);
  126. genericdeflist:=TFPObjectList.Create(false);
  127. { Parse type parameters }
  128. err:=false;
  129. { set the block type to type, so that the parsed type are returned as
  130. ttypenode (e.g. classes are in non type-compatible blocks returned as
  131. tloadvmtaddrnode) }
  132. old_block_type:=block_type;
  133. { if parsedtype is set, then the first type identifer was already parsed
  134. (happens in inline specializations) and thus we only need to parse
  135. the remaining types and do as if the first one was already given }
  136. first:=not assigned(parsedtype);
  137. if assigned(parsedtype) then
  138. begin
  139. genericdeflist.Add(parsedtype);
  140. specializename:='$'+parsedtype.typesym.realname;
  141. prettyname:=parsedtype.typesym.prettyname;
  142. end
  143. else
  144. begin
  145. specializename:='';
  146. prettyname:='';
  147. end;
  148. while not (token in [_GT,_RSHARPBRACKET]) do
  149. begin
  150. { "first" is set to false at the end of the loop! }
  151. if not first then
  152. consume(_COMMA);
  153. block_type:=bt_type;
  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. begin
  164. specializename:=specializename+'$'+pt2.resultdef.typesym.realname;
  165. if first then
  166. prettyname:=prettyname+pt2.resultdef.typesym.prettyname
  167. else
  168. prettyname:=prettyname+','+pt2.resultdef.typesym.prettyname;
  169. end;
  170. end
  171. else
  172. begin
  173. Message(type_e_type_id_expected);
  174. err:=true;
  175. end;
  176. pt2.free;
  177. first:=false;
  178. end;
  179. block_type:=old_block_type;
  180. if err then
  181. begin
  182. try_to_consume(_RSHARPBRACKET);
  183. exit;
  184. end;
  185. { search a generic with the given count of params }
  186. countstr:='';
  187. str(genericdeflist.Count,countstr);
  188. { use the name of the symbol as procvars return a user friendly version
  189. of the name }
  190. if symname='' then
  191. genname:=ttypesym(genericdef.typesym).realname
  192. else
  193. genname:=symname;
  194. { in case of non-Delphi mode the type name could already be a generic
  195. def (but maybe the wrong one) }
  196. if assigned(genericdef) and (df_generic in genericdef.defoptions) then
  197. begin
  198. { remove the type count suffix from the generic's name }
  199. for i:=Length(genname) downto 1 do
  200. if genname[i]='$' then
  201. begin
  202. genname:=copy(genname,1,i-1);
  203. break;
  204. end;
  205. end;
  206. genname:=genname+'$'+countstr;
  207. ugenname:=upper(genname);
  208. if not searchsym(ugenname,srsym,st)
  209. or (srsym.typ<>typesym) then
  210. begin
  211. identifier_not_found(genname);
  212. genericdeflist.Free;
  213. generictypelist.Free;
  214. exit;
  215. end;
  216. { we've found the correct def }
  217. genericdef:=tstoreddef(ttypesym(srsym).typedef);
  218. { build the new type's name }
  219. specializename:=genname+specializename;
  220. uspecializename:=upper(specializename);
  221. prettyname:=genericdef.typesym.prettyname+'<'+prettyname+'>';
  222. { select the symtable containing the params }
  223. case genericdef.typ of
  224. procdef:
  225. st:=genericdef.GetSymtable(gs_para);
  226. objectdef,
  227. recorddef:
  228. st:=genericdef.GetSymtable(gs_record);
  229. arraydef:
  230. st:=tarraydef(genericdef).symtable;
  231. procvardef:
  232. st:=genericdef.GetSymtable(gs_para);
  233. else
  234. internalerror(200511182);
  235. end;
  236. { build the list containing the types for the generic params }
  237. gencount:=0;
  238. for i:=0 to st.SymList.Count-1 do
  239. begin
  240. srsym:=tsym(st.SymList[i]);
  241. if sp_generic_para in srsym.symoptions then
  242. begin
  243. if gencount=genericdeflist.Count then
  244. internalerror(2011042702);
  245. generictype:=ttypesym.create(srsym.realname,tdef(genericdeflist[gencount]));
  246. generictypelist.add(generictype);
  247. inc(gencount);
  248. end;
  249. end;
  250. { Special case if we are referencing the current defined object }
  251. if assigned(current_structdef) and
  252. (current_structdef.objname^=uspecializename) then
  253. tt:=current_structdef;
  254. { decide in which symtable to put the specialization }
  255. if current_module.is_unit and current_module.in_interface then
  256. specializest:=current_module.globalsymtable
  257. else
  258. specializest:=current_module.localsymtable;
  259. { Can we reuse an already specialized type? }
  260. if not assigned(tt) then
  261. begin
  262. srsym:=tsym(specializest.find(uspecializename));
  263. if assigned(srsym) then
  264. begin
  265. if srsym.typ<>typesym then
  266. internalerror(200710171);
  267. tt:=ttypesym(srsym).typedef;
  268. end;
  269. end;
  270. if not assigned(tt) then
  271. begin
  272. { Setup symtablestack at definition time
  273. to get types right, however this is not perfect, we should probably record
  274. the resolved symbols }
  275. oldsymtablestack:=symtablestack;
  276. oldextendeddefs:=current_module.extendeddefs;
  277. current_module.extendeddefs:=TFPHashObjectList.create(true);
  278. symtablestack:=tdefawaresymtablestack.create;
  279. if not assigned(genericdef) then
  280. internalerror(200705151);
  281. hmodule:=find_module_from_symtable(genericdef.owner);
  282. if hmodule=nil then
  283. internalerror(200705152);
  284. pu:=tused_unit(hmodule.used_units.first);
  285. while assigned(pu) do
  286. begin
  287. if not assigned(pu.u.globalsymtable) then
  288. internalerror(200705153);
  289. symtablestack.push(pu.u.globalsymtable);
  290. pu:=tused_unit(pu.next);
  291. end;
  292. if assigned(hmodule.globalsymtable) then
  293. symtablestack.push(hmodule.globalsymtable);
  294. { push the localsymtable if needed }
  295. if (hmodule<>current_module) or not current_module.in_interface then
  296. symtablestack.push(current_module.localsymtable);
  297. { push a temporary global symtable so that the specialization is
  298. added to the correct symtable; this symtable does not contain
  299. any other symbols, so that the type resolution can not be
  300. influenced by symbols in the current unit }
  301. tempst:=tspecializesymtable.create(current_module.modulename^,current_module.moduleid);
  302. symtablestack.push(tempst);
  303. { Reparse the original type definition }
  304. if not err then
  305. begin
  306. if parse_class_parent then
  307. begin
  308. old_current_structdef:=current_structdef;
  309. old_current_genericdef:=current_genericdef;
  310. old_current_specializedef:=current_specializedef;
  311. if genericdef.owner.symtabletype in [recordsymtable,objectsymtable] then
  312. current_structdef:=tabstractrecorddef(genericdef.owner.defowner)
  313. else
  314. current_structdef:=nil;
  315. current_genericdef:=nil;
  316. current_specializedef:=nil;
  317. end;
  318. { First a new typesym so we can reuse this specialization and
  319. references to this specialization can be handled }
  320. srsym:=ttypesym.create(specializename,generrordef);
  321. specializest.insert(srsym);
  322. { specializations are declarations as such it is the wisest to
  323. declare set the blocktype to "type"; otherwise we'll
  324. experience unexpected side effects like the addition of
  325. classrefdefs if we have a generic that's derived from another
  326. generic }
  327. old_block_type:=block_type;
  328. block_type:=bt_type;
  329. if not assigned(genericdef.generictokenbuf) then
  330. internalerror(200511171);
  331. current_scanner.startreplaytokens(genericdef.generictokenbuf,
  332. genericdef.change_endian);
  333. read_named_type(tt,specializename,genericdef,generictypelist,false);
  334. ttypesym(srsym).typedef:=tt;
  335. tt.typesym:=srsym;
  336. if _prettyname<>'' then
  337. ttypesym(tt.typesym).fprettyname:=_prettyname
  338. else
  339. ttypesym(tt.typesym).fprettyname:=prettyname;
  340. { Note regarding hint directives:
  341. There is no need to remove the flags for them from the
  342. specialized generic symbol, because hint directives that
  343. follow the specialization are handled by the code in
  344. pdecl.types_dec and added to the type symbol.
  345. E.g.: TFoo = TBar<Blubb> deprecated;
  346. Here the symbol TBar$1$Blubb will contain the
  347. "sp_hint_deprecated" flag while the TFoo symbol won't.}
  348. case tt.typ of
  349. { Build VMT indexes for classes and read hint directives }
  350. objectdef:
  351. begin
  352. try_consume_hintdirective(srsym.symoptions,srsym.deprecatedmsg);
  353. consume(_SEMICOLON);
  354. vmtbuilder:=TVMTBuilder.Create(tobjectdef(tt));
  355. vmtbuilder.generate_vmt;
  356. vmtbuilder.free;
  357. end;
  358. { handle params, calling convention, etc }
  359. procvardef:
  360. begin
  361. if not check_proc_directive(true) then
  362. begin
  363. try_consume_hintdirective(ttypesym(srsym).symoptions,ttypesym(srsym).deprecatedmsg);
  364. consume(_SEMICOLON);
  365. end;
  366. parse_var_proc_directives(ttypesym(srsym));
  367. handle_calling_convention(tprocvardef(tt));
  368. if try_consume_hintdirective(ttypesym(srsym).symoptions,ttypesym(srsym).deprecatedmsg) then
  369. consume(_SEMICOLON);
  370. end;
  371. else
  372. { parse hint directives for records and arrays }
  373. begin
  374. try_consume_hintdirective(srsym.symoptions,srsym.deprecatedmsg);
  375. consume(_SEMICOLON);
  376. end;
  377. end;
  378. { Consume the semicolon if it is also recorded }
  379. try_to_consume(_SEMICOLON);
  380. block_type:=old_block_type;
  381. if parse_class_parent then
  382. begin
  383. current_structdef:=old_current_structdef;
  384. current_genericdef:=old_current_genericdef;
  385. current_specializedef:=old_current_specializedef;
  386. end;
  387. end;
  388. { extract all created symbols and defs from the temporary symtable
  389. and add them to the specializest }
  390. for i:=0 to tempst.SymList.Count-1 do begin
  391. item:=tempst.SymList.Items[i];
  392. specializest.SymList.Add(tempst.SymList.NameOfIndex(i),item);
  393. tsym(item).Owner:=specializest;
  394. tempst.SymList.Extract(item);
  395. end;
  396. for i:=0 to tempst.DefList.Count-1 do begin
  397. item:=tempst.DefList.Items[i];
  398. specializest.DefList.Add(item);
  399. tdef(item).owner:=specializest;
  400. tempst.DefList.Extract(item);
  401. end;
  402. tempst.free;
  403. { Restore symtablestack }
  404. current_module.extendeddefs.free;
  405. current_module.extendeddefs:=oldextendeddefs;
  406. symtablestack.free;
  407. symtablestack:=oldsymtablestack;
  408. end;
  409. if not (token in [_GT, _RSHARPBRACKET]) then
  410. begin
  411. consume(_RSHARPBRACKET);
  412. exit;
  413. end
  414. else
  415. consume(token);
  416. genericdeflist.free;
  417. generictypelist.free;
  418. if assigned(genericdef) then
  419. begin
  420. { check the hints of the found generic symbol }
  421. srsym:=genericdef.typesym;
  422. check_hints(srsym,srsym.symoptions,srsym.deprecatedmsg);
  423. end;
  424. end;
  425. function parse_generic_parameters:TFPObjectList;
  426. var
  427. generictype : ttypesym;
  428. begin
  429. result:=TFPObjectList.Create(false);
  430. repeat
  431. if token=_ID then
  432. begin
  433. generictype:=ttypesym.create(orgpattern,cundefinedtype);
  434. include(generictype.symoptions,sp_generic_para);
  435. result.add(generictype);
  436. end;
  437. consume(_ID);
  438. until not try_to_consume(_COMMA) ;
  439. end;
  440. procedure insert_generic_parameter_types(def:tstoreddef;genericdef:tstoreddef;genericlist:TFPObjectList);
  441. var
  442. i: longint;
  443. generictype: ttypesym;
  444. st: tsymtable;
  445. begin
  446. def.genericdef:=genericdef;
  447. if not assigned(genericlist) then
  448. exit;
  449. case def.typ of
  450. recorddef,objectdef: st:=tabstractrecorddef(def).symtable;
  451. arraydef: st:=tarraydef(def).symtable;
  452. procvardef,procdef: st:=tabstractprocdef(def).parast;
  453. else
  454. internalerror(201101020);
  455. end;
  456. for i:=0 to genericlist.count-1 do
  457. begin
  458. generictype:=ttypesym(genericlist[i]);
  459. if generictype.typedef.typ=undefineddef then
  460. include(def.defoptions,df_generic)
  461. else
  462. include(def.defoptions,df_specialization);
  463. st.insert(generictype);
  464. end;
  465. end;
  466. end.