symcreat.pas 29 KB

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