symcreat.pas 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  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_callthrough(pd: tprocdef);
  344. var
  345. str: ansistring;
  346. callpd: tprocdef;
  347. currpara: tparavarsym;
  348. i: longint;
  349. firstpara,
  350. isclassmethod: boolean;
  351. begin
  352. isclassmethod:=
  353. (po_classmethod in pd.procoptions) and
  354. not(pd.proctypeoption in [potype_constructor,potype_destructor]);
  355. callpd:=tprocdef(pd.skpara);
  356. str:='begin ';
  357. if pd.returndef<>voidtype then
  358. str:=str+'result:=';
  359. str:=str+callpd.procsym.realname+'(';
  360. firstpara:=true;
  361. for i:=0 to pd.paras.count-1 do
  362. begin
  363. currpara:=tparavarsym(pd.paras[i]);
  364. if not(vo_is_hidden_para in currpara.varoptions) then
  365. begin
  366. if not firstpara then
  367. str:=str+',';
  368. firstpara:=false;
  369. str:=str+currpara.realname;
  370. end;
  371. end;
  372. str:=str+') end;';
  373. str_parse_method_impl(str,pd,isclassmethod);
  374. end;
  375. procedure implement_jvm_enum_values(pd: tprocdef);
  376. begin
  377. str_parse_method_impl('begin result:=__fpc_FVALUES end;',pd,true);
  378. end;
  379. procedure implement_jvm_enum_valuof(pd: tprocdef);
  380. begin
  381. str_parse_method_impl('begin result:=__FPC_TEnumClassAlias(inherited valueOf(JLClass(__FPC_TEnumClassAlias),__fpc_str)) end;',pd,true);
  382. end;
  383. procedure implement_jvm_enum_jumps_constr(pd: tprocdef);
  384. begin
  385. str_parse_method_impl('begin inherited create(__fpc_name,__fpc_ord); __fpc_fenumval:=__fpc_initenumval end;',pd,false);
  386. end;
  387. procedure implement_jvm_enum_fpcordinal(pd: tprocdef);
  388. var
  389. enumclass: tobjectdef;
  390. enumdef: tenumdef;
  391. begin
  392. enumclass:=tobjectdef(pd.owner.defowner);
  393. enumdef:=tenumdef(ttypesym(search_struct_member(enumclass,'__FPC_TENUMALIAS')).typedef);
  394. if not enumdef.has_jumps then
  395. str_parse_method_impl('begin result:=ordinal end;',pd,false)
  396. else
  397. str_parse_method_impl('begin result:=__fpc_fenumval end;',pd,false);
  398. end;
  399. procedure implement_jvm_enum_fpcvalueof(pd: tprocdef);
  400. var
  401. enumclass: tobjectdef;
  402. enumdef: tenumdef;
  403. begin
  404. enumclass:=tobjectdef(pd.owner.defowner);
  405. enumdef:=tenumdef(ttypesym(search_struct_member(enumclass,'__FPC_TENUMALIAS')).typedef);
  406. { convert integer to corresponding enum instance: in case of no jumps
  407. get it from the $VALUES array, otherwise from the __fpc_ord2enum
  408. hashmap }
  409. if not enumdef.has_jumps then
  410. str_parse_method_impl('begin result:=__fpc_FVALUES[__fpc_int] end;',pd,false)
  411. else
  412. str_parse_method_impl('begin result:=__FPC_TEnumClassAlias(__fpc_ord2enum.get(JLInteger.valueOf(__fpc_int))) end;',pd,true);
  413. end;
  414. function CompareEnumSyms(Item1, Item2: Pointer): Integer;
  415. var
  416. I1 : tenumsym absolute Item1;
  417. I2 : tenumsym absolute Item2;
  418. begin
  419. Result:=I1.value-I2.value;
  420. end;
  421. procedure implement_jvm_enum_classconstr(pd: tprocdef);
  422. var
  423. enumclass: tobjectdef;
  424. enumdef: tenumdef;
  425. str: ansistring;
  426. i: longint;
  427. enumsym: tenumsym;
  428. classfield: tstaticvarsym;
  429. orderedenums: tfpobjectlist;
  430. begin
  431. enumclass:=tobjectdef(pd.owner.defowner);
  432. enumdef:=tenumdef(ttypesym(search_struct_member(enumclass,'__FPC_TENUMALIAS')).typedef);
  433. if not assigned(enumdef) then
  434. internalerror(2011062305);
  435. str:='begin ';
  436. if enumdef.has_jumps then
  437. { init hashmap for ordinal -> enum instance mapping; don't let it grow,
  438. and set the capacity to the next prime following the total number of
  439. enum elements to minimise the number of collisions }
  440. str:=str+'__fpc_ord2enum:=JUHashMap.Create('+tostr(next_prime(enumdef.symtable.symlist.count))+',1.0);';
  441. { iterate over all enum elements and initialise the class fields, and
  442. store them in the values array. Since the java.lang.Enum doCompare
  443. method is final and hardcoded to compare based on declaration order
  444. (= java.lang.Enum.ordinal() value), we have to create them in order of
  445. ascending FPC ordinal values (which may not be the same as the FPC
  446. declaration order in case of jumps }
  447. orderedenums:=tfpobjectlist.create(false);
  448. for i:=0 to enumdef.symtable.symlist.count-1 do
  449. orderedenums.add(enumdef.symtable.symlist[i]);
  450. if enumdef.has_jumps then
  451. orderedenums.sort(@CompareEnumSyms);
  452. for i:=0 to orderedenums.count-1 do
  453. begin
  454. enumsym:=tenumsym(orderedenums[i]);
  455. classfield:=tstaticvarsym(search_struct_member(enumclass,enumsym.name));
  456. if not assigned(classfield) then
  457. internalerror(2011062306);
  458. str:=str+classfield.name+':=__FPC_TEnumClassAlias.Create('''+enumsym.realname+''','+tostr(i);
  459. if enumdef.has_jumps then
  460. str:=str+','+tostr(enumsym.value);
  461. str:=str+');';
  462. { alias for $VALUES array used internally by the JDK, and also by FPC
  463. in case of no jumps }
  464. str:=str+'__fpc_FVALUES['+tostr(i)+']:='+classfield.name+';';
  465. if enumdef.has_jumps then
  466. str:=str+'__fpc_ord2enum.put(JLInteger.valueOf('+tostr(enumsym.value)+'),'+classfield.name+');';
  467. end;
  468. orderedenums.free;
  469. str:=str+' end;';
  470. str_parse_method_impl(str,pd,true);
  471. end;
  472. procedure add_synthetic_method_implementations_for_struct(struct: tabstractrecorddef);
  473. var
  474. i : longint;
  475. def : tdef;
  476. pd : tprocdef;
  477. begin
  478. for i:=0 to struct.symtable.deflist.count-1 do
  479. begin
  480. def:=tdef(struct.symtable.deflist[i]);
  481. if (def.typ<>procdef) then
  482. continue;
  483. pd:=tprocdef(def);
  484. case pd.synthetickind of
  485. tsk_none:
  486. ;
  487. tsk_anon_inherited:
  488. implement_anon_inherited(pd);
  489. tsk_jvm_clone:
  490. implement_jvm_clone(pd);
  491. tsk_record_deepcopy:
  492. implement_record_deepcopy(pd);
  493. tsk_empty,
  494. { special handling for this one is done in tnodeutils.wrap_proc_body }
  495. tsk_tcinit:
  496. implement_empty(pd);
  497. tsk_callthrough:
  498. implement_callthrough(pd);
  499. tsk_jvm_enum_values:
  500. implement_jvm_enum_values(pd);
  501. tsk_jvm_enum_valueof:
  502. implement_jvm_enum_valuof(pd);
  503. tsk_jvm_enum_classconstr:
  504. implement_jvm_enum_classconstr(pd);
  505. tsk_jvm_enum_jumps_constr:
  506. implement_jvm_enum_jumps_constr(pd);
  507. tsk_jvm_enum_fpcordinal:
  508. implement_jvm_enum_fpcordinal(pd);
  509. tsk_jvm_enum_fpcvalueof:
  510. implement_jvm_enum_fpcvalueof(pd);
  511. else
  512. internalerror(2011032801);
  513. end;
  514. end;
  515. end;
  516. procedure add_synthetic_method_implementations(st: tsymtable);
  517. var
  518. i: longint;
  519. def: tdef;
  520. sstate: tscannerstate;
  521. begin
  522. { only necessary for the JVM target currently }
  523. if not (target_info.system in [system_jvm_java32]) then
  524. exit;
  525. sstate.valid:=false;
  526. for i:=0 to st.deflist.count-1 do
  527. begin
  528. def:=tdef(st.deflist[i]);
  529. if (def.typ=procdef) and
  530. assigned(tprocdef(def).localst) and
  531. { not true for the "main" procedure, whose localsymtable is the staticsymtable }
  532. (tprocdef(def).localst.symtabletype=localsymtable) then
  533. add_synthetic_method_implementations(tprocdef(def).localst)
  534. else if (is_javaclass(def) and
  535. not(oo_is_external in tobjectdef(def).objectoptions)) or
  536. (def.typ=recorddef) then
  537. begin
  538. if not sstate.valid then
  539. replace_scanner('synthetic_impl',sstate);
  540. add_synthetic_method_implementations_for_struct(tabstractrecorddef(def));
  541. { also complete nested types }
  542. add_synthetic_method_implementations(tabstractrecorddef(def).symtable);
  543. end;
  544. end;
  545. restore_scanner(sstate);
  546. end;
  547. procedure finish_copied_procdef(var pd: tprocdef; const realname: string; newparentst: tsymtable; newstruct: tabstractrecorddef);
  548. var
  549. sym: tsym;
  550. parasym: tparavarsym;
  551. ps: tprocsym;
  552. stname: string;
  553. i: longint;
  554. begin
  555. { associate the procdef with a procsym in the owner }
  556. if not(pd.proctypeoption in [potype_class_constructor,potype_class_destructor]) then
  557. stname:=upper(realname)
  558. else
  559. stname:=lower(realname);
  560. sym:=tsym(newparentst.find(stname));
  561. if assigned(sym) then
  562. begin
  563. if sym.typ<>procsym then
  564. internalerror(2011040601);
  565. ps:=tprocsym(sym);
  566. end
  567. else
  568. begin
  569. ps:=tprocsym.create(realname);
  570. newparentst.insert(ps);
  571. end;
  572. pd.procsym:=ps;
  573. pd.struct:=newstruct;
  574. { in case of methods, replace the special parameter types with new ones }
  575. if assigned(newstruct) then
  576. begin
  577. symtablestack.push(pd.parast);
  578. for i:=0 to pd.paras.count-1 do
  579. begin
  580. parasym:=tparavarsym(pd.paras[i]);
  581. if vo_is_self in parasym.varoptions then
  582. begin
  583. if parasym.vardef.typ=classrefdef then
  584. parasym.vardef:=tclassrefdef.create(newstruct)
  585. else
  586. parasym.vardef:=newstruct;
  587. end
  588. end;
  589. { also fix returndef in case of a constructor }
  590. if pd.proctypeoption=potype_constructor then
  591. pd.returndef:=newstruct;
  592. symtablestack.pop(pd.parast);
  593. end;
  594. proc_add_definition(pd);
  595. end;
  596. procedure build_parentfpstruct(pd: tprocdef);
  597. var
  598. nestedvars: tsym;
  599. nestedvarsst: tsymtable;
  600. pnestedvarsdef,
  601. nestedvarsdef: tdef;
  602. old_symtablestack: tsymtablestack;
  603. begin
  604. { make sure the defs are not registered in the current symtablestack,
  605. because they may be for a parent procdef (changeowner does remove a def
  606. from the symtable in which it was originally created, so that by itself
  607. is not enough) }
  608. old_symtablestack:=symtablestack;
  609. symtablestack:=old_symtablestack.getcopyuntil(current_module.localsymtable);
  610. { create struct to hold local variables and parameters that are
  611. accessed from within nested routines (start with extra dollar to prevent
  612. the JVM from thinking this is a nested class in the unit) }
  613. nestedvarsst:=trecordsymtable.create('$'+current_module.realmodulename^+'$$_fpc_nestedvars$'+tostr(pd.defid),current_settings.alignment.localalignmax);
  614. nestedvarsdef:=trecorddef.create(nestedvarsst.name^,nestedvarsst);
  615. {$ifdef jvm}
  616. maybe_guarantee_record_typesym(nestedvarsdef,nestedvarsdef.owner);
  617. { don't add clone/FpcDeepCopy, because the field names are not all
  618. representable in source form and we don't need them anyway }
  619. symtablestack.push(trecorddef(nestedvarsdef).symtable);
  620. maybe_add_public_default_java_constructor(trecorddef(nestedvarsdef));
  621. symtablestack.pop(trecorddef(nestedvarsdef).symtable);
  622. {$endif}
  623. symtablestack.free;
  624. symtablestack:=old_symtablestack.getcopyuntil(pd.localst);
  625. pnestedvarsdef:=getpointerdef(nestedvarsdef);
  626. nestedvars:=tlocalvarsym.create('$nestedvars',vs_var,nestedvarsdef,[]);
  627. pd.localst.insert(nestedvars);
  628. pd.parentfpstruct:=nestedvars;
  629. pd.parentfpstructptrtype:=pnestedvarsdef;
  630. pd.parentfpinitblock:=cblocknode.create(nil);
  631. symtablestack.free;
  632. symtablestack:=old_symtablestack;
  633. end;
  634. function maybe_add_sym_to_parentfpstruct(pd: tprocdef; sym: tsym; vardef: tdef; addrparam: boolean): tsym;
  635. var
  636. fieldvardef,
  637. nestedvarsdef: tdef;
  638. nestedvarsst: tsymtable;
  639. initcode: tnode;
  640. old_filepos: tfileposinfo;
  641. begin
  642. nestedvarsdef:=tlocalvarsym(pd.parentfpstruct).vardef;
  643. result:=search_struct_member(trecorddef(nestedvarsdef),sym.name);
  644. if not assigned(result) then
  645. begin
  646. { mark that this symbol is mirrored in the parentfpstruct }
  647. tabstractnormalvarsym(sym).inparentfpstruct:=true;
  648. { add field to the struct holding all locals accessed
  649. by nested routines }
  650. nestedvarsst:=trecorddef(nestedvarsdef).symtable;
  651. { indicate whether or not this is a var/out/constref/... parameter }
  652. if addrparam then
  653. fieldvardef:=getpointerdef(vardef)
  654. else
  655. fieldvardef:=vardef;
  656. result:=tfieldvarsym.create(sym.realname,vs_value,fieldvardef,[]);
  657. if nestedvarsst.symlist.count=0 then
  658. include(tfieldvarsym(result).varoptions,vo_is_first_field);
  659. nestedvarsst.insert(result);
  660. trecordsymtable(nestedvarsst).addfield(tfieldvarsym(result),vis_public);
  661. { add initialization with original value if it's a parameter }
  662. if (sym.typ=paravarsym) then
  663. begin
  664. old_filepos:=current_filepos;
  665. fillchar(current_filepos,sizeof(current_filepos),0);
  666. initcode:=cloadnode.create(sym,sym.owner);
  667. { indicate that this load should not be transformed into a load
  668. from the parentfpstruct, but instead should load the original
  669. value }
  670. include(initcode.flags,nf_internal);
  671. { in case it's a var/out/constref parameter, store the address of the
  672. parameter in the struct }
  673. if addrparam then
  674. begin
  675. initcode:=caddrnode.create_internal(initcode);
  676. include(initcode.flags,nf_typedaddr);
  677. end;
  678. initcode:=cassignmentnode.create(
  679. csubscriptnode.create(result,cloadnode.create(pd.parentfpstruct,pd.parentfpstruct.owner)),
  680. initcode);
  681. tblocknode(pd.parentfpinitblock).left:=cstatementnode.create
  682. (initcode,tblocknode(pd.parentfpinitblock).left);
  683. current_filepos:=old_filepos;
  684. end;
  685. end;
  686. end;
  687. procedure redirect_parentfpstruct_local_syms(pd: tprocdef);
  688. var
  689. nestedvarsdef: trecorddef;
  690. sl: tpropaccesslist;
  691. fsym,
  692. lsym,
  693. aliassym: tsym;
  694. i: longint;
  695. begin
  696. nestedvarsdef:=trecorddef(tlocalvarsym(pd.parentfpstruct).vardef);
  697. for i:=0 to nestedvarsdef.symtable.symlist.count-1 do
  698. begin
  699. fsym:=tsym(nestedvarsdef.symtable.symlist[i]);
  700. if fsym.typ<>fieldvarsym then
  701. continue;
  702. lsym:=tsym(pd.localst.find(fsym.name));
  703. if not assigned(lsym) then
  704. lsym:=tsym(pd.parast.find(fsym.name));
  705. if not assigned(lsym) then
  706. internalerror(2011060408);
  707. { add an absolute variable that redirects to the field }
  708. sl:=tpropaccesslist.create;
  709. sl.addsym(sl_load,pd.parentfpstruct);
  710. sl.addsym(sl_subscript,tfieldvarsym(fsym));
  711. aliassym:=tabsolutevarsym.create_ref(lsym.name,tfieldvarsym(fsym).vardef,sl);
  712. { hide the original variable (can't delete, because there
  713. may be other loadnodes that reference it)
  714. -- only for locals; hiding parameters changes the
  715. function signature }
  716. if lsym.typ<>paravarsym then
  717. hidesym(lsym);
  718. { insert the absolute variable in the localst of the
  719. routine; ignore duplicates, because this will also check the
  720. parasymtable and we want to override parameters with our local
  721. versions }
  722. pd.localst.insert(aliassym,false);
  723. end;
  724. end;
  725. function find_sym_in_parentfpstruct(pd: tprocdef; sym: tsym): tsym;
  726. var
  727. nestedvarsdef: tdef;
  728. begin
  729. nestedvarsdef:=tlocalvarsym(pd.parentfpstruct).vardef;
  730. result:=search_struct_member(trecorddef(nestedvarsdef),sym.name);
  731. end;
  732. procedure finish_parentfpstruct(pd: tprocdef);
  733. begin
  734. trecordsymtable(trecorddef(tlocalvarsym(pd.parentfpstruct).vardef).symtable).addalignmentpadding;
  735. end;
  736. procedure maybe_guarantee_record_typesym(var def: tdef; st: tsymtable);
  737. var
  738. ts: ttypesym;
  739. begin
  740. { create a dummy typesym for the JVM target, because the record
  741. has to be wrapped by a class }
  742. if (target_info.system=system_jvm_java32) and
  743. (def.typ=recorddef) and
  744. not assigned(def.typesym) then
  745. begin
  746. ts:=ttypesym.create(trecorddef(def).symtable.realname^,def);
  747. st.insert(ts);
  748. ts.visibility:=vis_strictprivate;
  749. end;
  750. end;
  751. end.