symcreat.pas 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  1. {
  2. Copyright (c) 2011 by Jonas Maebe
  3. This unit provides helpers for creating new syms/defs based on string
  4. representations.
  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. {$i fpcdefs.inc}
  19. unit symcreat;
  20. interface
  21. uses
  22. finput,tokens,scanner,globtype,
  23. aasmdata,
  24. symconst,symbase,symtype,symdef,symsym;
  25. type
  26. tscannerstate = record
  27. old_scanner: tscannerfile;
  28. old_token: ttoken;
  29. old_c: char;
  30. old_modeswitches: tmodeswitches;
  31. valid: boolean;
  32. end;
  33. { save/restore the scanner state before/after injecting }
  34. procedure replace_scanner(const tempname: string; out sstate: tscannerstate);
  35. procedure restore_scanner(const sstate: tscannerstate);
  36. { parses a (class or regular) method/constructor/destructor declaration from
  37. str, as if it were declared in astruct's declaration body
  38. WARNING: save the scanner state before calling this routine, and restore
  39. when done. }
  40. function str_parse_method_dec(str: ansistring; potype: tproctypeoption; is_classdef: boolean; astruct: tabstractrecorddef; out pd: tprocdef): boolean;
  41. { parses a (class or regular) method/constructor/destructor implementation
  42. from str, as if it appeared in the current unit's implementation section
  43. WARNINGS:
  44. * save the scanner state before calling this routine, and restore when done.
  45. * the code *must* be written in objfpc style
  46. }
  47. function str_parse_method_impl(str: ansistring; usefwpd: tprocdef; is_classdef: boolean):boolean;
  48. { in the JVM, constructors are not automatically inherited (so you can hide
  49. them). To emulate the Pascal behaviour, we have to automatically add
  50. all parent constructors to the current class as well.}
  51. procedure add_missing_parent_constructors_intf(obj: tobjectdef; forcevis: tvisibility);
  52. { goes through all defs in st to add implementations for synthetic methods
  53. added earlier }
  54. procedure add_synthetic_method_implementations(st: tsymtable);
  55. procedure finish_copied_procdef(var pd: tprocdef; const realname: string; newparentst: tsymtable; newstruct: tabstractrecorddef);
  56. { create "parent frame pointer" record skeleton for procdef, in which local
  57. variables and parameters from pd accessed from nested routines can be
  58. stored }
  59. procedure build_parentfpstruct(pd: tprocdef);
  60. { checks whether sym (a local or para of pd) already has a counterpart in
  61. pd's parentfpstruct, and if not adds a new field to the struct with type
  62. "vardef" (can be different from sym's type in case it's a call-by-reference
  63. parameter, which is indicated by addrparam). If it already has a field in
  64. the parentfpstruct, this field is returned. }
  65. function maybe_add_sym_to_parentfpstruct(pd: tprocdef; sym: tsym; vardef: tdef; addrparam: boolean): tsym;
  66. { given a localvarsym or paravarsym of pd, returns the field of the
  67. parentfpstruct corresponding to this sym }
  68. function find_sym_in_parentfpstruct(pd: tprocdef; sym: tsym): tsym;
  69. { replaces all local and paravarsyms that have been mirrored in the
  70. parentfpstruct with aliasvarsyms that redirect to these fields (used to
  71. make sure that references to these syms in the owning procdef itself also
  72. use the ones in the parentfpstructs) }
  73. procedure redirect_parentfpstruct_local_syms(pd: tprocdef);
  74. { finalises the parentfpstruct (alignment padding, ...) }
  75. procedure finish_parentfpstruct(pd: tprocdef);
  76. procedure maybe_guarantee_record_typesym(var def: tdef; st: tsymtable);
  77. implementation
  78. uses
  79. cutils,cclasses,globals,verbose,systems,comphook,fmodule,
  80. symtable,defutil,
  81. pbase,pdecobj,pdecsub,psub,ptconst,
  82. {$ifdef jvm}
  83. pjvm,
  84. {$endif jvm}
  85. node,nbas,nld,nmem,
  86. defcmp,
  87. paramgr;
  88. procedure replace_scanner(const tempname: string; out sstate: tscannerstate);
  89. var
  90. old_block_type: tblock_type;
  91. begin
  92. { would require saving of idtoken, pattern etc }
  93. if (token=_ID) then
  94. internalerror(2011032201);
  95. sstate.old_scanner:=current_scanner;
  96. sstate.old_token:=token;
  97. sstate.old_c:=c;
  98. sstate.old_modeswitches:=current_settings.modeswitches;
  99. sstate.valid:=true;
  100. { creating a new scanner resets the block type, while we want to continue
  101. in the current one }
  102. old_block_type:=block_type;
  103. current_scanner:=tscannerfile.Create('_Macro_.'+tempname);
  104. block_type:=old_block_type;
  105. { required for e.g. FpcDeepCopy record method (uses "out" parameter; field
  106. names are escaped via &, so should not cause conflicts }
  107. current_settings.modeswitches:=objfpcmodeswitches;
  108. end;
  109. procedure restore_scanner(const sstate: tscannerstate);
  110. begin
  111. if sstate.valid then
  112. begin
  113. current_scanner.free;
  114. current_scanner:=sstate.old_scanner;
  115. token:=sstate.old_token;
  116. current_settings.modeswitches:=sstate.old_modeswitches;
  117. c:=sstate.old_c;
  118. end;
  119. end;
  120. function str_parse_method_dec(str: ansistring; potype: tproctypeoption; is_classdef: boolean; astruct: tabstractrecorddef; out pd: tprocdef): boolean;
  121. var
  122. oldparse_only: boolean;
  123. begin
  124. Message1(parser_d_internal_parser_string,str);
  125. oldparse_only:=parse_only;
  126. parse_only:=true;
  127. result:=false;
  128. { inject the string in the scanner }
  129. str:=str+'end;';
  130. current_scanner.substitutemacro('meth_head_macro',@str[1],length(str),current_scanner.line_no,current_scanner.inputfile.ref_index);
  131. current_scanner.readtoken(false);
  132. { and parse it... }
  133. case potype of
  134. potype_class_constructor:
  135. pd:=class_constructor_head(astruct);
  136. potype_class_destructor:
  137. pd:=class_destructor_head(astruct);
  138. potype_constructor:
  139. pd:=constructor_head;
  140. potype_destructor:
  141. pd:=destructor_head;
  142. else
  143. pd:=method_dec(astruct,is_classdef);
  144. end;
  145. if assigned(pd) then
  146. result:=true;
  147. parse_only:=oldparse_only;
  148. end;
  149. function str_parse_method_impl(str: ansistring; usefwpd: tprocdef; is_classdef: boolean):boolean;
  150. var
  151. oldparse_only: boolean;
  152. tmpstr: ansistring;
  153. begin
  154. if ((status.verbosity and v_debug)<>0) then
  155. begin
  156. if assigned(usefwpd) then
  157. Message1(parser_d_internal_parser_string,usefwpd.customprocname([pno_proctypeoption,pno_paranames,pno_noclassmarker,pno_noleadingdollar])+str)
  158. else
  159. begin
  160. if is_classdef then
  161. tmpstr:='class '
  162. else
  163. tmpstr:='';
  164. Message1(parser_d_internal_parser_string,tmpstr+str);
  165. end;
  166. end;
  167. oldparse_only:=parse_only;
  168. parse_only:=false;
  169. result:=false;
  170. { inject the string in the scanner }
  171. str:=str+'end;';
  172. current_scanner.substitutemacro('meth_impl_macro',@str[1],length(str),current_scanner.line_no,current_scanner.inputfile.ref_index);
  173. current_scanner.readtoken(false);
  174. { and parse it... }
  175. read_proc(is_classdef,usefwpd);
  176. parse_only:=oldparse_only;
  177. result:=true;
  178. end;
  179. procedure add_missing_parent_constructors_intf(obj: tobjectdef; forcevis: tvisibility);
  180. var
  181. parent: tobjectdef;
  182. def: tdef;
  183. parentpd,
  184. childpd: tprocdef;
  185. i: longint;
  186. srsym: tsym;
  187. srsymtable: tsymtable;
  188. begin
  189. if (oo_is_external in obj.objectoptions) or
  190. not assigned(obj.childof) then
  191. exit;
  192. parent:=obj.childof;
  193. { find all constructor in the parent }
  194. for i:=0 to tobjectsymtable(parent.symtable).deflist.count-1 do
  195. begin
  196. def:=tdef(tobjectsymtable(parent.symtable).deflist[i]);
  197. if (def.typ<>procdef) or
  198. (tprocdef(def).proctypeoption<>potype_constructor) or
  199. not is_visible_for_object(tprocdef(def),obj) then
  200. continue;
  201. parentpd:=tprocdef(def);
  202. { do we have this constructor too? (don't use
  203. search_struct_member/searchsym_in_class, since those will
  204. search parents too) }
  205. if searchsym_in_record(obj,parentpd.procsym.name,srsym,srsymtable) then
  206. begin
  207. { there's a symbol with the same name, is it a constructor
  208. with the same parameters? }
  209. if srsym.typ=procsym then
  210. begin
  211. childpd:=tprocsym(srsym).find_procdef_bytype_and_para(
  212. potype_constructor,parentpd.paras,nil,
  213. [cpo_ignorehidden,cpo_ignoreuniv,cpo_openequalisexact]);
  214. if assigned(childpd) then
  215. continue;
  216. end;
  217. end;
  218. { if we get here, we did not find it in the current objectdef ->
  219. add }
  220. childpd:=tprocdef(parentpd.getcopy);
  221. if forcevis<>vis_none then
  222. childpd.visibility:=forcevis;
  223. finish_copied_procdef(childpd,parentpd.procsym.realname,obj.symtable,obj);
  224. exclude(childpd.procoptions,po_external);
  225. include(childpd.procoptions,po_overload);
  226. childpd.synthetickind:=tsk_anon_inherited;
  227. include(obj.objectoptions,oo_has_constructor);
  228. end;
  229. end;
  230. procedure implement_anon_inherited(pd: tprocdef);
  231. var
  232. str: ansistring;
  233. isclassmethod: boolean;
  234. begin
  235. isclassmethod:=
  236. (po_classmethod in pd.procoptions) and
  237. not(pd.proctypeoption in [potype_constructor,potype_destructor]);
  238. str:='begin inherited end;';
  239. str_parse_method_impl(str,pd,isclassmethod);
  240. end;
  241. procedure implement_jvm_clone(pd: tprocdef);
  242. var
  243. struct: tabstractrecorddef;
  244. str: ansistring;
  245. i: longint;
  246. sym: tsym;
  247. fsym: tfieldvarsym;
  248. begin
  249. if not(pd.struct.typ in [recorddef,objectdef]) then
  250. internalerror(2011032802);
  251. struct:=pd.struct;
  252. { anonymous record types must get an artificial name, so we can generate
  253. a typecast at the scanner level }
  254. if (struct.typ=recorddef) and
  255. not assigned(struct.typesym) then
  256. internalerror(2011032812);
  257. { the inherited clone will already copy all fields in a shallow way ->
  258. copy records/regular arrays in a regular way }
  259. str:='type _fpc_ptrt = ^'+struct.typesym.realname+'; begin clone:=inherited;';
  260. for i:=0 to struct.symtable.symlist.count-1 do
  261. begin
  262. sym:=tsym(struct.symtable.symlist[i]);
  263. if (sym.typ=fieldvarsym) then
  264. begin
  265. fsym:=tfieldvarsym(sym);
  266. if (fsym.vardef.typ=recorddef) or
  267. ((fsym.vardef.typ=arraydef) and
  268. not is_dynamic_array(fsym.vardef)) or
  269. ((fsym.vardef.typ=setdef) and
  270. not is_smallset(fsym.vardef)) then
  271. str:=str+'_fpc_ptrt(clone)^.&'+fsym.realname+':='+fsym.realname+';';
  272. end;
  273. end;
  274. str:=str+'end;';
  275. str_parse_method_impl(str,pd,false);
  276. end;
  277. procedure implement_record_deepcopy(pd: tprocdef);
  278. var
  279. struct: tabstractrecorddef;
  280. str: ansistring;
  281. i: longint;
  282. sym: tsym;
  283. fsym: tfieldvarsym;
  284. begin
  285. if not(pd.struct.typ in [recorddef,objectdef]) then
  286. internalerror(2011032810);
  287. struct:=pd.struct;
  288. { anonymous record types must get an artificial name, so we can generate
  289. a typecast at the scanner level }
  290. if (struct.typ=recorddef) and
  291. not assigned(struct.typesym) then
  292. internalerror(2011032811);
  293. { copy all fields }
  294. str:='begin ';
  295. for i:=0 to struct.symtable.symlist.count-1 do
  296. begin
  297. sym:=tsym(struct.symtable.symlist[i]);
  298. if (sym.typ=fieldvarsym) then
  299. begin
  300. fsym:=tfieldvarsym(sym);
  301. str:=str+'result.&'+fsym.realname+':='+fsym.realname+';';
  302. end;
  303. end;
  304. str:=str+'end;';
  305. str_parse_method_impl(str,pd,false);
  306. end;
  307. procedure implement_empty(pd: tprocdef);
  308. var
  309. str: ansistring;
  310. isclassmethod: boolean;
  311. begin
  312. isclassmethod:=
  313. (po_classmethod in pd.procoptions) and
  314. not(pd.proctypeoption in [potype_constructor,potype_destructor]);
  315. str:='begin end;';
  316. str_parse_method_impl(str,pd,isclassmethod);
  317. end;
  318. procedure implement_jvm_enum_values(pd: tprocdef);
  319. begin
  320. str_parse_method_impl('begin result:=__fpc_FVALUES end;',pd,true);
  321. end;
  322. procedure implement_jvm_enum_valuof(pd: tprocdef);
  323. begin
  324. str_parse_method_impl('begin result:=__FPC_TEnumClassAlias(inherited valueOf(JLClass(__FPC_TEnumClassAlias),__fpc_str)) end;',pd,true);
  325. end;
  326. procedure implement_jvm_enum_jumps_constr(pd: tprocdef);
  327. begin
  328. str_parse_method_impl('begin inherited create(__fpc_name,__fpc_ord); __fpc_fenumval:=__fpc_initenumval end;',pd,false);
  329. end;
  330. procedure implement_jvm_enum_fpcordinal(pd: tprocdef);
  331. var
  332. enumclass: tobjectdef;
  333. enumdef: tenumdef;
  334. begin
  335. enumclass:=tobjectdef(pd.owner.defowner);
  336. enumdef:=tenumdef(ttypesym(search_struct_member(enumclass,'__FPC_TENUMALIAS')).typedef);
  337. if not enumdef.has_jumps then
  338. str_parse_method_impl('begin result:=ordinal end;',pd,false)
  339. else
  340. str_parse_method_impl('begin result:=__fpc_fenumval end;',pd,false);
  341. end;
  342. procedure implement_jvm_enum_fpcvalueof(pd: tprocdef);
  343. var
  344. enumclass: tobjectdef;
  345. enumdef: tenumdef;
  346. begin
  347. enumclass:=tobjectdef(pd.owner.defowner);
  348. enumdef:=tenumdef(ttypesym(search_struct_member(enumclass,'__FPC_TENUMALIAS')).typedef);
  349. { convert integer to corresponding enum instance: in case of no jumps
  350. get it from the $VALUES array, otherwise from the __fpc_ord2enum
  351. hashmap }
  352. if not enumdef.has_jumps then
  353. str_parse_method_impl('begin result:=__fpc_FVALUES[__fpc_int] end;',pd,false)
  354. else
  355. str_parse_method_impl('begin result:=__FPC_TEnumClassAlias(__fpc_ord2enum.get(JLInteger.valueOf(__fpc_int))) end;',pd,true);
  356. end;
  357. function CompareEnumSyms(Item1, Item2: Pointer): Integer;
  358. var
  359. I1 : tenumsym absolute Item1;
  360. I2 : tenumsym absolute Item2;
  361. begin
  362. Result:=I1.value-I2.value;
  363. end;
  364. procedure implement_jvm_enum_classconstr(pd: tprocdef);
  365. var
  366. enumclass: tobjectdef;
  367. enumdef: tenumdef;
  368. str: ansistring;
  369. i: longint;
  370. enumsym: tenumsym;
  371. classfield: tstaticvarsym;
  372. orderedenums: tfpobjectlist;
  373. begin
  374. enumclass:=tobjectdef(pd.owner.defowner);
  375. enumdef:=tenumdef(ttypesym(search_struct_member(enumclass,'__FPC_TENUMALIAS')).typedef);
  376. if not assigned(enumdef) then
  377. internalerror(2011062305);
  378. str:='begin ';
  379. if enumdef.has_jumps then
  380. { init hashmap for ordinal -> enum instance mapping; don't let it grow,
  381. and set the capacity to the next prime following the total number of
  382. enum elements to minimise the number of collisions }
  383. str:=str+'__fpc_ord2enum:=JUHashMap.Create('+tostr(next_prime(enumdef.symtable.symlist.count))+',1.0);';
  384. { iterate over all enum elements and initialise the class fields, and
  385. store them in the values array. Since the java.lang.Enum doCompare
  386. method is final and hardcoded to compare based on declaration order
  387. (= java.lang.Enum.ordinal() value), we have to create them in order of
  388. ascending FPC ordinal values (which may not be the same as the FPC
  389. declaration order in case of jumps }
  390. orderedenums:=tfpobjectlist.create(false);
  391. for i:=0 to enumdef.symtable.symlist.count-1 do
  392. orderedenums.add(enumdef.symtable.symlist[i]);
  393. if enumdef.has_jumps then
  394. orderedenums.sort(@CompareEnumSyms);
  395. for i:=0 to orderedenums.count-1 do
  396. begin
  397. enumsym:=tenumsym(orderedenums[i]);
  398. classfield:=tstaticvarsym(search_struct_member(enumclass,enumsym.name));
  399. if not assigned(classfield) then
  400. internalerror(2011062306);
  401. str:=str+classfield.name+':=__FPC_TEnumClassAlias.Create('''+enumsym.realname+''','+tostr(i);
  402. if enumdef.has_jumps then
  403. str:=str+','+tostr(enumsym.value);
  404. str:=str+');';
  405. { alias for $VALUES array used internally by the JDK, and also by FPC
  406. in case of no jumps }
  407. str:=str+'__fpc_FVALUES['+tostr(i)+']:='+classfield.name+';';
  408. if enumdef.has_jumps then
  409. str:=str+'__fpc_ord2enum.put(JLInteger.valueOf('+tostr(enumsym.value)+'),'+classfield.name+');';
  410. end;
  411. orderedenums.free;
  412. str:=str+' end;';
  413. str_parse_method_impl(str,pd,true);
  414. end;
  415. procedure add_synthetic_method_implementations_for_struct(struct: tabstractrecorddef);
  416. var
  417. i : longint;
  418. def : tdef;
  419. pd : tprocdef;
  420. begin
  421. for i:=0 to struct.symtable.deflist.count-1 do
  422. begin
  423. def:=tdef(struct.symtable.deflist[i]);
  424. if (def.typ<>procdef) then
  425. continue;
  426. pd:=tprocdef(def);
  427. case pd.synthetickind of
  428. tsk_none:
  429. ;
  430. tsk_anon_inherited:
  431. implement_anon_inherited(pd);
  432. tsk_jvm_clone:
  433. implement_jvm_clone(pd);
  434. tsk_record_deepcopy:
  435. implement_record_deepcopy(pd);
  436. tsk_empty,
  437. { special handling for this one is done in tnodeutils.wrap_proc_body }
  438. tsk_tcinit:
  439. implement_empty(pd);
  440. tsk_jvm_enum_values:
  441. implement_jvm_enum_values(pd);
  442. tsk_jvm_enum_valueof:
  443. implement_jvm_enum_valuof(pd);
  444. tsk_jvm_enum_classconstr:
  445. implement_jvm_enum_classconstr(pd);
  446. tsk_jvm_enum_jumps_constr:
  447. implement_jvm_enum_jumps_constr(pd);
  448. tsk_jvm_enum_fpcordinal:
  449. implement_jvm_enum_fpcordinal(pd);
  450. tsk_jvm_enum_fpcvalueof:
  451. implement_jvm_enum_fpcvalueof(pd);
  452. else
  453. internalerror(2011032801);
  454. end;
  455. end;
  456. end;
  457. procedure add_synthetic_method_implementations(st: tsymtable);
  458. var
  459. i: longint;
  460. def: tdef;
  461. sstate: tscannerstate;
  462. begin
  463. { only necessary for the JVM target currently }
  464. if not (target_info.system in [system_jvm_java32]) then
  465. exit;
  466. sstate.valid:=false;
  467. for i:=0 to st.deflist.count-1 do
  468. begin
  469. def:=tdef(st.deflist[i]);
  470. if (def.typ=procdef) and
  471. assigned(tprocdef(def).localst) and
  472. { not true for the "main" procedure, whose localsymtable is the staticsymtable }
  473. (tprocdef(def).localst.symtabletype=localsymtable) then
  474. add_synthetic_method_implementations(tprocdef(def).localst)
  475. else if (is_javaclass(def) and
  476. not(oo_is_external in tobjectdef(def).objectoptions)) or
  477. (def.typ=recorddef) then
  478. begin
  479. if not sstate.valid then
  480. replace_scanner('synthetic_impl',sstate);
  481. add_synthetic_method_implementations_for_struct(tabstractrecorddef(def));
  482. { also complete nested types }
  483. add_synthetic_method_implementations(tabstractrecorddef(def).symtable);
  484. end;
  485. end;
  486. restore_scanner(sstate);
  487. end;
  488. procedure finish_copied_procdef(var pd: tprocdef; const realname: string; newparentst: tsymtable; newstruct: tabstractrecorddef);
  489. var
  490. sym: tsym;
  491. parasym: tparavarsym;
  492. ps: tprocsym;
  493. stname: string;
  494. i: longint;
  495. begin
  496. { associate the procdef with a procsym in the owner }
  497. if not(pd.proctypeoption in [potype_class_constructor,potype_class_destructor]) then
  498. stname:=upper(realname)
  499. else
  500. stname:=lower(realname);
  501. sym:=tsym(newparentst.find(stname));
  502. if assigned(sym) then
  503. begin
  504. if sym.typ<>procsym then
  505. internalerror(2011040601);
  506. ps:=tprocsym(sym);
  507. end
  508. else
  509. begin
  510. ps:=tprocsym.create(realname);
  511. newparentst.insert(ps);
  512. end;
  513. pd.procsym:=ps;
  514. pd.struct:=newstruct;
  515. { in case of methods, replace the special parameter types with new ones }
  516. if assigned(newstruct) then
  517. begin
  518. symtablestack.push(pd.parast);
  519. for i:=0 to pd.paras.count-1 do
  520. begin
  521. parasym:=tparavarsym(pd.paras[i]);
  522. if vo_is_self in parasym.varoptions then
  523. begin
  524. if parasym.vardef.typ=classrefdef then
  525. parasym.vardef:=tclassrefdef.create(newstruct)
  526. else
  527. parasym.vardef:=newstruct;
  528. end
  529. end;
  530. { also fix returndef in case of a constructor }
  531. if pd.proctypeoption=potype_constructor then
  532. pd.returndef:=newstruct;
  533. symtablestack.pop(pd.parast);
  534. end;
  535. proc_add_definition(pd);
  536. end;
  537. procedure build_parentfpstruct(pd: tprocdef);
  538. var
  539. nestedvars: tsym;
  540. nestedvarsst: tsymtable;
  541. pnestedvarsdef,
  542. nestedvarsdef: tdef;
  543. old_symtablestack: tsymtablestack;
  544. begin
  545. { make sure the defs are not registered in the current symtablestack,
  546. because they may be for a parent procdef (changeowner does remove a def
  547. from the symtable in which it was originally created, so that by itself
  548. is not enough) }
  549. old_symtablestack:=symtablestack;
  550. symtablestack:=old_symtablestack.getcopyuntil(current_module.localsymtable);
  551. { create struct to hold local variables and parameters that are
  552. accessed from within nested routines }
  553. nestedvarsst:=trecordsymtable.create(current_module.realmodulename^+'$$_fpc_nestedvars$'+tostr(pd.defid),current_settings.alignment.localalignmax);
  554. nestedvarsdef:=trecorddef.create(nestedvarsst.name^,nestedvarsst);
  555. {$ifdef jvm}
  556. maybe_guarantee_record_typesym(nestedvarsdef,nestedvarsdef.owner);
  557. { don't add clone/FpcDeepCopy, because the field names are not all
  558. representable in source form and we don't need them anyway }
  559. symtablestack.push(trecorddef(nestedvarsdef).symtable);
  560. maybe_add_public_default_java_constructor(trecorddef(nestedvarsdef));
  561. symtablestack.pop(trecorddef(nestedvarsdef).symtable);
  562. {$endif}
  563. symtablestack.free;
  564. symtablestack:=old_symtablestack.getcopyuntil(pd.localst);
  565. pnestedvarsdef:=tpointerdef.create(nestedvarsdef);
  566. nestedvars:=tlocalvarsym.create('$nestedvars',vs_var,nestedvarsdef,[]);
  567. pd.localst.insert(nestedvars);
  568. pd.parentfpstruct:=nestedvars;
  569. pd.parentfpstructptrtype:=pnestedvarsdef;
  570. pd.parentfpinitblock:=cblocknode.create(nil);
  571. symtablestack.free;
  572. symtablestack:=old_symtablestack;
  573. end;
  574. function maybe_add_sym_to_parentfpstruct(pd: tprocdef; sym: tsym; vardef: tdef; addrparam: boolean): tsym;
  575. var
  576. fieldvardef,
  577. nestedvarsdef: tdef;
  578. nestedvarsst: tsymtable;
  579. initcode: tnode;
  580. old_filepos: tfileposinfo;
  581. begin
  582. nestedvarsdef:=tlocalvarsym(pd.parentfpstruct).vardef;
  583. result:=search_struct_member(trecorddef(nestedvarsdef),sym.name);
  584. if not assigned(result) then
  585. begin
  586. { mark that this symbol is mirrored in the parentfpstruct }
  587. tabstractnormalvarsym(sym).inparentfpstruct:=true;
  588. { add field to the struct holding all locals accessed
  589. by nested routines }
  590. nestedvarsst:=trecorddef(nestedvarsdef).symtable;
  591. { indicate whether or not this is a var/out/constref/... parameter }
  592. if addrparam then
  593. fieldvardef:=tpointerdef.create(vardef)
  594. else
  595. fieldvardef:=vardef;
  596. result:=tfieldvarsym.create(sym.realname,vs_value,fieldvardef,[]);
  597. if nestedvarsst.symlist.count=0 then
  598. include(tfieldvarsym(result).varoptions,vo_is_first_field);
  599. nestedvarsst.insert(result);
  600. trecordsymtable(nestedvarsst).addfield(tfieldvarsym(result),vis_public);
  601. { add initialization with original value if it's a parameter }
  602. if (sym.typ=paravarsym) then
  603. begin
  604. old_filepos:=current_filepos;
  605. fillchar(current_filepos,sizeof(current_filepos),0);
  606. initcode:=cloadnode.create(sym,sym.owner);
  607. { indicate that this load should not be transformed into a load
  608. from the parentfpstruct, but instead should load the original
  609. value }
  610. include(initcode.flags,nf_internal);
  611. { in case it's a var/out/constref parameter, store the address of the
  612. parameter in the struct }
  613. if addrparam then
  614. begin
  615. initcode:=caddrnode.create_internal(initcode);
  616. include(initcode.flags,nf_typedaddr);
  617. end;
  618. initcode:=cassignmentnode.create(
  619. csubscriptnode.create(result,cloadnode.create(pd.parentfpstruct,pd.parentfpstruct.owner)),
  620. initcode);
  621. tblocknode(pd.parentfpinitblock).left:=cstatementnode.create
  622. (initcode,tblocknode(pd.parentfpinitblock).left);
  623. current_filepos:=old_filepos;
  624. end;
  625. end;
  626. end;
  627. procedure redirect_parentfpstruct_local_syms(pd: tprocdef);
  628. var
  629. nestedvarsdef: trecorddef;
  630. sl: tpropaccesslist;
  631. fsym,
  632. lsym,
  633. aliassym: tsym;
  634. i: longint;
  635. begin
  636. nestedvarsdef:=trecorddef(tlocalvarsym(pd.parentfpstruct).vardef);
  637. for i:=0 to nestedvarsdef.symtable.symlist.count-1 do
  638. begin
  639. fsym:=tsym(nestedvarsdef.symtable.symlist[i]);
  640. if fsym.typ<>fieldvarsym then
  641. continue;
  642. lsym:=tsym(pd.localst.find(fsym.name));
  643. if not assigned(lsym) then
  644. lsym:=tsym(pd.parast.find(fsym.name));
  645. if not assigned(lsym) then
  646. internalerror(2011060408);
  647. { add an absolute variable that redirects to the field }
  648. sl:=tpropaccesslist.create;
  649. sl.addsym(sl_load,pd.parentfpstruct);
  650. sl.addsym(sl_subscript,tfieldvarsym(fsym));
  651. aliassym:=tabsolutevarsym.create_ref(lsym.name,tfieldvarsym(fsym).vardef,sl);
  652. { hide the original variable (can't delete, because there
  653. may be other loadnodes that reference it)
  654. -- only for locals; hiding parameters changes the
  655. function signature }
  656. if lsym.typ<>paravarsym then
  657. hidesym(lsym);
  658. { insert the absolute variable in the localst of the
  659. routine; ignore duplicates, because this will also check the
  660. parasymtable and we want to override parameters with our local
  661. versions }
  662. pd.localst.insert(aliassym,false);
  663. end;
  664. end;
  665. function find_sym_in_parentfpstruct(pd: tprocdef; sym: tsym): tsym;
  666. var
  667. nestedvarsdef: tdef;
  668. begin
  669. nestedvarsdef:=tlocalvarsym(pd.parentfpstruct).vardef;
  670. result:=search_struct_member(trecorddef(nestedvarsdef),sym.name);
  671. end;
  672. procedure finish_parentfpstruct(pd: tprocdef);
  673. begin
  674. trecordsymtable(trecorddef(tlocalvarsym(pd.parentfpstruct).vardef).symtable).addalignmentpadding;
  675. end;
  676. procedure maybe_guarantee_record_typesym(var def: tdef; st: tsymtable);
  677. var
  678. ts: ttypesym;
  679. begin
  680. { create a dummy typesym for the JVM target, because the record
  681. has to be wrapped by a class }
  682. if (target_info.system=system_jvm_java32) and
  683. (def.typ=recorddef) and
  684. not assigned(def.typesym) then
  685. begin
  686. ts:=ttypesym.create(trecorddef(def).symtable.realname^,def);
  687. st.insert(ts);
  688. ts.visibility:=vis_strictprivate;
  689. end;
  690. end;
  691. end.