symcreat.pas 33 KB

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