2
0

pgenutil.pas 20 KB

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