symcreat.pas 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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,
  23. symconst,symdef,symbase;
  24. { in the JVM, constructors are not automatically inherited (so you can hide
  25. them). To emulate the Pascal behaviour, we have to automatically add
  26. all parent constructors to the current class as well. }
  27. procedure add_missing_parent_constructors_intf(obj: tobjectdef);
  28. procedure add_missing_parent_constructors_impl(obj: tobjectdef);
  29. { parses a (class or regular) method/constructor/destructor declaration from
  30. str, as if it were declared in astruct's declaration body }
  31. function str_parse_method_dec(str: ansistring; is_classdef: boolean; astruct: tabstractrecorddef; out pd: tprocdef): boolean;
  32. { parses a (class or regular) method/constructor/destructor implementation
  33. from str, as if it appeared in the current unit's implementation section }
  34. function str_parse_method_impl(str: ansistring; is_classdef: boolean):boolean;
  35. { goes through all defs in st to add implementations for synthetic methods
  36. added earlier }
  37. procedure add_synthetic_method_implementations(st: tsymtable);
  38. implementation
  39. uses
  40. verbose,systems,
  41. tokens,scanner,
  42. symtype,symsym,symtable,
  43. pbase,pdecobj,psub,
  44. defcmp;
  45. type
  46. tscannerstate = record
  47. old_scanner: tscannerfile;
  48. old_token: ttoken;
  49. old_c: char;
  50. valid: boolean;
  51. end;
  52. procedure save_scanner(out sstate: tscannerstate);
  53. begin
  54. { would require saving of idtoken, pattern etc }
  55. if (token=_ID) then
  56. internalerror(2011032201);
  57. sstate.old_scanner:=current_scanner;
  58. sstate.old_token:=token;
  59. sstate.old_c:=c;
  60. sstate.valid:=true;
  61. end;
  62. procedure restore_scanner(const sstate: tscannerstate);
  63. begin
  64. if sstate.valid then
  65. begin
  66. current_scanner.free;
  67. current_scanner:=sstate.old_scanner;
  68. token:=sstate.old_token;
  69. c:=sstate.old_c;
  70. end;
  71. end;
  72. function str_parse_method_dec(str: ansistring; is_classdef: boolean; astruct: tabstractrecorddef; out pd: tprocdef): boolean;
  73. var
  74. oldparse_only: boolean;
  75. begin
  76. oldparse_only:=parse_only;
  77. parse_only:=true;
  78. result:=false;
  79. { inject the string in the scanner }
  80. str:=str+'end;';
  81. current_scanner.substitutemacro('meth_head_macro',@str[1],length(str),current_scanner.line_no,current_scanner.inputfile.ref_index);
  82. current_scanner.readtoken(false);
  83. { and parse it... }
  84. pd:=method_dec(astruct,is_classdef);
  85. if assigned(pd) then
  86. begin
  87. include(pd.procoptions,po_synthetic);
  88. result:=true;
  89. end;
  90. parse_only:=oldparse_only;
  91. end;
  92. function str_parse_method_impl(str: ansistring; is_classdef: boolean):boolean;
  93. var
  94. oldparse_only: boolean;
  95. begin
  96. oldparse_only:=parse_only;
  97. parse_only:=false;
  98. result:=false;
  99. { inject the string in the scanner }
  100. str:=str+'end;';
  101. current_scanner.substitutemacro('meth_impl_macro',@str[1],length(str),current_scanner.line_no,current_scanner.inputfile.ref_index);
  102. current_scanner.readtoken(false);
  103. { and parse it... }
  104. read_proc(is_classdef);
  105. parse_only:=oldparse_only;
  106. result:=true;
  107. end;
  108. procedure add_missing_parent_constructors_intf(obj: tobjectdef);
  109. var
  110. parent: tobjectdef;
  111. def: tdef;
  112. pd: tprocdef;
  113. newpd,
  114. parentpd: tprocdef;
  115. i: longint;
  116. srsym: tsym;
  117. srsymtable: tsymtable;
  118. isclassmethod: boolean;
  119. str: ansistring;
  120. sstate: tscannerstate;
  121. begin
  122. if not assigned(obj.childof) then
  123. exit;
  124. sstate.valid:=false;
  125. parent:=obj.childof;
  126. { find all constructor in the parent }
  127. for i:=0 to tobjectsymtable(parent.symtable).deflist.count-1 do
  128. begin
  129. def:=tdef(tobjectsymtable(parent.symtable).deflist[i]);
  130. if (def.typ<>procdef) or
  131. (tprocdef(def).proctypeoption<>potype_constructor) then
  132. continue;
  133. pd:=tprocdef(def);
  134. { do we have this constructor too? (don't use
  135. search_struct_member/searchsym_in_class, since those will
  136. search parents too) }
  137. if searchsym_in_record(obj,pd.procsym.name,srsym,srsymtable) then
  138. begin
  139. { there's a symbol with the same name, is it a constructor
  140. with the same parameters? }
  141. if srsym.typ=procsym then
  142. begin
  143. parentpd:=tprocsym(srsym).find_procdef_bytype_and_para(
  144. potype_constructor,pd.paras,tprocdef(def).returndef,
  145. [cpo_ignorehidden,cpo_ignoreuniv,cpo_openequalisexact]);
  146. if assigned(parentpd) then
  147. continue;
  148. end;
  149. end;
  150. { if we get here, we did not find it in the current objectdef ->
  151. add }
  152. if not sstate.valid then
  153. begin
  154. save_scanner(sstate);
  155. current_scanner:=tscannerfile.Create('_Macro_.parent_constructors_intf');
  156. end;
  157. isclassmethod:=
  158. (po_classmethod in tprocdef(pd).procoptions) and
  159. not(tprocdef(pd).proctypeoption in [potype_constructor,potype_destructor]);
  160. { + 'overload' for Delphi modes }
  161. str:=tprocdef(pd).customprocname([pno_proctypeoption,pno_paranames,pno_noclassmarker])+'overload;';
  162. if not str_parse_method_dec(str,isclassmethod,obj,newpd) then
  163. internalerror(2011032001);
  164. include(newpd.procoptions,po_synthetic);
  165. end;
  166. restore_scanner(sstate);
  167. end;
  168. procedure add_missing_parent_constructors_impl(obj: tobjectdef);
  169. var
  170. i: longint;
  171. def: tdef;
  172. str: ansistring;
  173. isclassmethod: boolean;
  174. begin
  175. for i:=0 to tobjectsymtable(obj.symtable).deflist.count-1 do
  176. begin
  177. def:=tdef(tobjectsymtable(obj.symtable).deflist[i]);
  178. if (def.typ<>procdef) or
  179. not(po_synthetic in tprocdef(def).procoptions) then
  180. continue;
  181. isclassmethod:=
  182. (po_classmethod in tprocdef(def).procoptions) and
  183. not(tprocdef(def).proctypeoption in [potype_constructor,potype_destructor]);
  184. str:=tprocdef(def).customprocname([pno_proctypeoption,pno_paranames,pno_ownername,pno_noclassmarker]);
  185. str:=str+'overload; begin inherited end;';
  186. str_parse_method_impl(str,isclassmethod);
  187. end;
  188. end;
  189. procedure add_synthetic_method_implementations(st: tsymtable);
  190. var
  191. i: longint;
  192. def: tdef;
  193. sstate: tscannerstate;
  194. begin
  195. { only necessary for the JVM target currently }
  196. if not (target_info.system in [system_jvm_java32]) then
  197. exit;
  198. sstate.valid:=false;
  199. for i:=0 to st.deflist.count-1 do
  200. begin
  201. def:=tdef(st.deflist[i]);
  202. if is_javaclass(def) and
  203. not(oo_is_external in tobjectdef(def).objectoptions) then
  204. begin
  205. if not sstate.valid then
  206. begin
  207. save_scanner(sstate);
  208. current_scanner:=tscannerfile.Create('_Macro_.parent_constructors_impl');
  209. end;
  210. add_missing_parent_constructors_impl(tobjectdef(def));
  211. end;
  212. end;
  213. restore_scanner(sstate);
  214. end;
  215. end.