objcutil.pas 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888
  1. {
  2. Copyright (c) 2009 by Jonas Maebe
  3. This unit implements some Objective-C helper routines at the node tree
  4. level.
  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 objcutil;
  20. interface
  21. uses
  22. node,
  23. symtype,symdef;
  24. { Check whether a string contains a syntactically valid selector name. }
  25. function objcvalidselectorname(value_str: pchar; len: longint): boolean;
  26. { Generate a node loading the superclass structure necessary to call
  27. an inherited Objective-C method. }
  28. function objcsuperclassnode(def: tdef): tnode;
  29. { The internals of Objective-C's @encode() functionality: encode a
  30. type into the internal format used by the run time. Returns false
  31. if a type is not representable by the Objective-C run time, and in
  32. that case also the failing definition. }
  33. function objctryencodetype(def: tdef; out encodedtype: ansistring; out founderror: tdef): boolean;
  34. { Encode a method's parameters and result type into the format used by the
  35. run time (for generating protocol and class rtti). }
  36. function objcencodemethod(pd: tprocdef): ansistring;
  37. { Check whether a type can be used in an Objective-C method
  38. signature or field declaration. }
  39. function objcchecktype(def: tdef; out founderror: tdef): boolean;
  40. { Exports all assembler symbols related to the obj-c class }
  41. procedure exportobjcclass(def: tobjectdef);
  42. implementation
  43. uses
  44. globtype,
  45. cutils,cclasses,
  46. pass_1,
  47. verbose,systems,
  48. symtable,symconst,symsym,
  49. defutil,paramgr,
  50. nbas,nmem,ncal,nld,ncon,ncnv,
  51. export;
  52. {******************************************************************
  53. validselectorname
  54. *******************************************************************}
  55. function objcvalidselectorname(value_str: pchar; len: longint): boolean;
  56. var
  57. i : longint;
  58. gotcolon : boolean;
  59. begin
  60. result:=false;
  61. { empty name is not allowed }
  62. if (len=0) then
  63. exit;
  64. gotcolon:=false;
  65. { if the first character is a colon, all of them must be colons }
  66. if (value_str[0] = ':') then
  67. begin
  68. for i:=1 to len-1 do
  69. if (value_str[i]<>':') then
  70. exit;
  71. end
  72. else
  73. begin
  74. { no special characters other than ':'
  75. }
  76. for i:=0 to len-1 do
  77. if (value_str[i] = ':') then
  78. gotcolon:=true
  79. else if not(value_str[i] in ['_','A'..'Z','a'..'z','0'..'9',':']) then
  80. exit;
  81. { if there is at least one colon, the final character must
  82. also be a colon (in case it's only one character that is
  83. a colon, this was already checked before the above loop)
  84. }
  85. if gotcolon and
  86. (value_str[len-1] <> ':') then
  87. exit;
  88. end;
  89. result:=true;
  90. end;
  91. {******************************************************************
  92. objcsuperclassnode
  93. *******************************************************************}
  94. function objcloadbasefield(n: tnode; const fieldname: string): tnode;
  95. var
  96. vs : tsym;
  97. begin
  98. result:=cderefnode.create(ctypeconvnode.create_internal(n,objc_idtype));
  99. vs:=tsym(tabstractrecorddef(objc_objecttype).symtable.Find(fieldname));
  100. if not assigned(vs) or
  101. (vs.typ<>fieldvarsym) then
  102. internalerror(200911301);
  103. result:=csubscriptnode.create(vs,result);
  104. end;
  105. function objcsuperclassnode(def: tdef): tnode;
  106. var
  107. para : tcallparanode;
  108. begin
  109. { only valid for Objective-C classes and classrefs }
  110. if not is_objcclass(def) and
  111. not is_objcclassref(def) then
  112. internalerror(2009090901);
  113. { Can be done a lot more efficiently with direct symbol accesses, but
  114. requires extra node types. Maybe later. }
  115. if is_objcclassref(def) then
  116. begin
  117. if (oo_is_classhelper in tobjectdef(tclassrefdef(def).pointeddef).objectoptions) then
  118. begin
  119. { in case we are in a category method, we need the metaclass of the
  120. superclass class extended by this category (= metaclass of superclass of superclass)
  121. for the fragile abi, and the metaclass of the superclass for the non-fragile ABI }
  122. {$if defined(onlymacosx10_6) or defined(arm) }
  123. { NOTE: those send2 methods are only available on Mac OS X 10.6 and later!
  124. (but also on all iPhone SDK revisions we support) }
  125. if (target_info.system in system_objc_nfabi) then
  126. result:=cloadvmtaddrnode.create(ctypenode.create(tobjectdef(tclassrefdef(def).pointeddef).childof))
  127. else
  128. {$endif onlymacosx10_6 or arm}
  129. result:=cloadvmtaddrnode.create(ctypenode.create(tobjectdef(tclassrefdef(def).pointeddef).childof.childof));
  130. result:=objcloadbasefield(result,'ISA');
  131. typecheckpass(result);
  132. { we're done }
  133. exit;
  134. end
  135. else
  136. begin
  137. { otherwise we need the superclass of the metaclass }
  138. para:=ccallparanode.create(cstringconstnode.createstr(tobjectdef(tclassrefdef(def).pointeddef).objextname^),nil);
  139. result:=ccallnode.createinternfromunit('OBJC','OBJC_GETMETACLASS',para);
  140. end
  141. end
  142. else
  143. begin
  144. if not(oo_is_classhelper in tobjectdef(def).objectoptions) then
  145. result:=cloadvmtaddrnode.create(ctypenode.create(def))
  146. else
  147. result:=cloadvmtaddrnode.create(ctypenode.create(tobjectdef(def).childof))
  148. end;
  149. {$if defined(onlymacosx10_6) or defined(arm) }
  150. { For the non-fragile ABI, the superclass send2 method itself loads the
  151. superclass. For the fragile ABI, we have to do this ourselves.
  152. NOTE: those send2 methods are only available on Mac OS X 10.6 and later!
  153. (but also on all iPhone SDK revisions we support) }
  154. if not(target_info.system in system_objc_nfabi) then
  155. {$endif onlymacosx10_6 or arm}
  156. result:=objcloadbasefield(result,'SUPERCLASS');
  157. typecheckpass(result);
  158. end;
  159. {******************************************************************
  160. Type encoding
  161. *******************************************************************}
  162. type
  163. trecordinfostate = (ris_initial, ris_afterpointer, ris_dontprint);
  164. function objcparasize(vs: tparavarsym): ptrint;
  165. begin
  166. result:=vs.paraloc[callerside].intsize;
  167. { In Objective-C, all ordinal types are widened to at least the
  168. size of the C "int" type. Assume __LP64__/4 byte ints for now. }
  169. if is_ordinal(vs.vardef) and
  170. (result<4) then
  171. result:=4;
  172. end;
  173. function addencodedtype(def: tdef; recordinfostate: trecordinfostate; bpacked: boolean; var encodedstr: ansistring; out founderror: tdef): boolean; forward;
  174. function encoderecst(const recname: ansistring; recst: tabstractrecordsymtable; var encodedstr: ansistring; out founderror: tdef): boolean;
  175. var
  176. variantstarts: tfplist;
  177. i, varindex: longint;
  178. field,
  179. firstfield: tfieldvarsym;
  180. firstfieldvariant,
  181. bpacked: boolean;
  182. begin
  183. result:=false;
  184. bpacked:=recst.fieldalignment=bit_alignment;
  185. { Is the first field already the start of a variant? }
  186. firstfield:=nil;
  187. firstfieldvariant:=false;
  188. for i:=0 to recst.symlist.count-1 do
  189. begin
  190. if (tsym(recst.symlist[i]).typ<>fieldvarsym) then
  191. continue;
  192. field:=tfieldvarsym(recst.symlist[i]);
  193. if not assigned(firstfield) then
  194. firstfield:=field
  195. else if (vo_is_first_field in field.varoptions) then
  196. begin
  197. if (field.fieldoffset=firstfield.fieldoffset) then
  198. firstfieldvariant:=true;
  199. end;
  200. end;
  201. variantstarts:=tfplist.create;
  202. encodedstr:=encodedstr+'{'+recname+'=';
  203. for i:=0 to recst.symlist.count-1 do
  204. begin
  205. if (tsym(recst.symlist[i]).typ<>fieldvarsym) then
  206. continue;
  207. field:=tfieldvarsym(recst.symlist[i]);
  208. { start of a variant part? }
  209. if ((field=firstfield) and
  210. firstfieldvariant) or
  211. ((field<>firstfield) and
  212. (vo_is_first_field in field.varoptions)) then
  213. begin
  214. varindex:=variantstarts.count-1;
  215. if (varindex=-1) or
  216. (tfieldvarsym(variantstarts[varindex]).fieldoffset<field.fieldoffset) then
  217. begin
  218. { new, more deeply nested variant }
  219. encodedstr:=encodedstr+'(?={?=';
  220. variantstarts.add(field);
  221. end
  222. else
  223. begin
  224. { close existing nested variants if any }
  225. while (varindex>=0) and
  226. (tfieldvarsym(variantstarts[varindex]).fieldoffset>field.fieldoffset) do
  227. begin
  228. { close more deeply nested variants }
  229. encodedstr:=encodedstr+'})';
  230. dec(varindex);
  231. end;
  232. if (varindex<0) then
  233. internalerror(2009081805);
  234. if (tfieldvarsym(variantstarts[varindex]).fieldoffset<>field.fieldoffset) then
  235. internalerror(2009081804);
  236. { variant at the same level as a previous one }
  237. variantstarts.count:=varindex+1;
  238. { No need to add this field, it has the same offset as the
  239. previous one at this position. }
  240. if tfieldvarsym(variantstarts[varindex]).fieldoffset<>field.fieldoffset then
  241. internalerror(2009081601);
  242. { close previous variant sub-part and start new one }
  243. encodedstr:=encodedstr+'}{?=';
  244. end
  245. end;
  246. if not addencodedtype(field.vardef,ris_afterpointer,bpacked,encodedstr,founderror) then
  247. exit;
  248. end;
  249. for i:=0 to variantstarts.count-1 do
  250. encodedstr:=encodedstr+'})';
  251. variantstarts.free;
  252. encodedstr:=encodedstr+'}';
  253. result:=true
  254. end;
  255. function addencodedtype(def: tdef; recordinfostate: trecordinfostate; bpacked: boolean; var encodedstr: ansistring; out founderror: tdef): boolean;
  256. var
  257. recname: ansistring;
  258. recdef: trecorddef;
  259. objdef: tobjectdef;
  260. len: aint;
  261. c: char;
  262. newstate: trecordinfostate;
  263. addrpara: boolean;
  264. begin
  265. result:=true;
  266. case def.typ of
  267. stringdef :
  268. begin
  269. case tstringdef(def).stringtype of
  270. st_shortstring:
  271. { include length byte }
  272. encodedstr:=encodedstr+'['+tostr(tstringdef(def).len+1)+'C]';
  273. else
  274. { While we could handle refcounted Pascal strings correctly
  275. when such methods are called from Pascal code, things would
  276. completely break down if they were called from Objective-C
  277. code/reflection since the necessary refcount helper calls
  278. would be missing on the caller side (unless we'd
  279. automatically generate wrappers). }
  280. result:=false;
  281. end;
  282. end;
  283. enumdef,
  284. orddef :
  285. begin
  286. if bpacked and
  287. not is_void(def) then
  288. encodedstr:=encodedstr+'b'+tostr(def.packedbitsize)
  289. else
  290. begin
  291. if is_void(def) then
  292. c:='v'
  293. { in gcc, sizeof(_Bool) = sizeof(char) }
  294. else if is_boolean(def) and
  295. (def.size=1) then
  296. c:='B'
  297. else
  298. begin
  299. case def.size of
  300. 1:
  301. c:='c';
  302. 2:
  303. c:='s';
  304. 4:
  305. c:='i';
  306. 8:
  307. c:='q';
  308. else
  309. internalerror(2009081502);
  310. end;
  311. if not is_signed(def) then
  312. c:=upcase(c);
  313. end;
  314. encodedstr:=encodedstr+c;
  315. end;
  316. end;
  317. pointerdef :
  318. begin
  319. if is_pchar(def) then
  320. encodedstr:=encodedstr+'*'
  321. else if (def=objc_idtype) then
  322. encodedstr:=encodedstr+'@'
  323. else if (def=objc_seltype) then
  324. encodedstr:=encodedstr+':'
  325. else if (def=objc_metaclasstype) then
  326. encodedstr:=encodedstr+'#'
  327. else
  328. begin
  329. encodedstr:=encodedstr+'^';
  330. newstate:=recordinfostate;
  331. if (recordinfostate<ris_dontprint) then
  332. newstate:=succ(newstate);
  333. if not addencodedtype(tpointerdef(def).pointeddef,newstate,false,encodedstr,founderror) then
  334. begin
  335. result:=false;
  336. { report the exact (nested) error defintion }
  337. exit;
  338. end;
  339. end;
  340. end;
  341. floatdef :
  342. begin
  343. case tfloatdef(def).floattype of
  344. s32real:
  345. c:='f';
  346. s64real:
  347. c:='d';
  348. else
  349. begin
  350. c:='!';
  351. result:=false;
  352. end;
  353. end;
  354. encodedstr:=encodedstr+c;
  355. end;
  356. filedef :
  357. result:=false;
  358. recorddef :
  359. begin
  360. if assigned(def.typesym) then
  361. recname:=def.typename
  362. else
  363. recname:='?';
  364. if (recordinfostate<>ris_dontprint) then
  365. begin
  366. if not encoderecst(recname,tabstractrecordsymtable(trecorddef(def).symtable),encodedstr,founderror) then
  367. begin
  368. result:=false;
  369. { report the exact (nested) error defintion }
  370. exit;
  371. end
  372. end
  373. else
  374. encodedstr:=encodedstr+'{'+recname+'}'
  375. end;
  376. variantdef :
  377. begin
  378. recdef:=trecorddef(search_system_type('TVARDATA').typedef);
  379. if (recordinfostate<>ris_dontprint) then
  380. begin
  381. if not encoderecst(recdef.typename,tabstractrecordsymtable(recdef.symtable),encodedstr,founderror) then
  382. begin
  383. result:=false;
  384. { report the exact (nested) error defintion }
  385. exit;
  386. end
  387. end
  388. else
  389. encodedstr:=encodedstr+'{'+recdef.typename+'}';
  390. end;
  391. classrefdef :
  392. begin
  393. encodedstr:=encodedstr+'^';
  394. newstate:=recordinfostate;
  395. if (recordinfostate<>ris_dontprint) then
  396. newstate:=succ(newstate);
  397. if is_objcclassref(def) then
  398. begin
  399. objdef:=tobjectdef(tclassrefdef(def).pointeddef);
  400. if (newstate<>ris_dontprint) then
  401. { anonymous (objc)class definitions do not exist }
  402. begin
  403. if not encoderecst(objdef.objextname^,tabstractrecordsymtable(objdef.symtable),encodedstr,founderror) then
  404. { The fields of an Objective-C class should always be
  405. encodeable. }
  406. internalerror(2009081702);
  407. end
  408. else
  409. encodedstr:=encodedstr+'{'+objdef.objextname^+'}'
  410. end
  411. { Object Pascal classrefdefs point to a vmt, not really useful
  412. to completely write those here. I'm not even sure what the
  413. Objective-C run time uses this information for, since in C you
  414. can have forward struct definitions so not all structs passed
  415. to functions can be written out here either -> treat
  416. classrefdefs the same as such forward-defined structs. }
  417. else
  418. begin
  419. if assigned(def.typesym) then
  420. recname:=def.typename
  421. else
  422. recname:='?';
  423. encodedstr:=encodedstr+'{'+recname;
  424. if (newstate<>ris_dontprint) then
  425. encodedstr:=encodedstr+'=';
  426. encodedstr:=encodedstr+'}'
  427. end;
  428. end;
  429. setdef :
  430. begin
  431. addrpara:=paramanager.push_addr_param(vs_value,def,pocall_cdecl);
  432. if not addrpara then
  433. { encode as an record, they are always passed by value in C. }
  434. encodedstr:=encodedstr+'{?=';
  435. { Encode the set itself as an array. Without an encompassing
  436. record, these are always passed by reference in C. }
  437. encodedstr:=encodedstr+'['+tostr(def.size)+'C]';
  438. if not addrpara then
  439. encodedstr:=encodedstr+'}';
  440. end;
  441. formaldef :
  442. begin
  443. encodedstr:=encodedstr+'^v';
  444. end;
  445. arraydef :
  446. begin
  447. if is_array_of_const(def) then
  448. { do nothing, varargs are ignored in signatures }
  449. else if is_special_array(def) then
  450. result:=false
  451. else
  452. begin
  453. len:=tarraydef(def).highrange-tarraydef(def).lowrange+1;
  454. if is_packed_array(def) then
  455. begin
  456. { convert from bits to bytes for bitpacked arrays }
  457. len:=(len+7) div 8;
  458. { and encode as plain array of bytes }
  459. encodedstr:=encodedstr+'['+tostr(len)+'C]';
  460. end
  461. else
  462. begin
  463. encodedstr:=encodedstr+'['+tostr(len);
  464. { Embedded structured types in the array are printed
  465. in full regardless of the current recordinfostate. }
  466. if not addencodedtype(tarraydef(def).elementdef,ris_initial,false,encodedstr,founderror) then
  467. begin
  468. result:=false;
  469. { report the exact (nested) error defintion }
  470. exit;
  471. end;
  472. encodedstr:=encodedstr+']';
  473. end;
  474. end;
  475. end;
  476. procvardef :
  477. encodedstr:=encodedstr+'^?';
  478. objectdef :
  479. case tobjectdef(def).objecttype of
  480. odt_class,
  481. odt_object,
  482. odt_cppclass:
  483. begin
  484. newstate:=recordinfostate;
  485. { implicit pointer for classes }
  486. if (tobjectdef(def).objecttype=odt_class) then
  487. begin
  488. encodedstr:=encodedstr+'^';
  489. if (recordinfostate<ris_dontprint) then
  490. newstate:=succ(newstate);
  491. end;
  492. if newstate<>ris_dontprint then
  493. begin
  494. if not encoderecst(def.typename,tabstractrecordsymtable(tobjectdef(def).symtable),encodedstr,founderror) then
  495. begin
  496. result:=false;
  497. { report the exact (nested) error defintion }
  498. exit;
  499. end
  500. end
  501. else
  502. encodedstr:=encodedstr+'{'+def.typename+'}'
  503. end;
  504. odt_interfacecom,
  505. odt_interfacecom_property,
  506. odt_interfacecom_function,
  507. odt_dispinterface:
  508. result:=false;
  509. odt_interfacecorba:
  510. encodedstr:=encodedstr+'^{'+def.typename+'=}';
  511. { In Objective-C, the actual types of class instances are
  512. NSObject* etc, and those are encoded as "@". In FPC, to keep
  513. the similarity with Delphi-style Object Pascal, the type is
  514. NSObject and the pointer is implicit. Objective-C's "NSObject"
  515. has "class of NSObject" as equivalent here. }
  516. odt_objcclass,
  517. odt_objcprotocol:
  518. encodedstr:=encodedstr+'@';
  519. else
  520. internalerror(2009081509);
  521. end;
  522. undefineddef,
  523. errordef :
  524. result:=false;
  525. procdef :
  526. { must be done via objcencodemethod() }
  527. internalerror(2009081511);
  528. else
  529. internalerror(2009150812);
  530. end;
  531. if not result then
  532. founderror:=def;
  533. end;
  534. function objctryencodetype(def: tdef; out encodedtype: ansistring; out founderror: tdef): boolean;
  535. begin
  536. result:=addencodedtype(def,ris_initial,false,encodedtype,founderror);
  537. end;
  538. function objcencodemethod(pd: tprocdef): ansistring;
  539. var
  540. parasize,
  541. totalsize: aint;
  542. vs: tparavarsym;
  543. i: longint;
  544. temp: ansistring;
  545. founderror: tdef;
  546. begin
  547. result:='';
  548. totalsize:=0;
  549. if not pd.has_paraloc_info then
  550. begin
  551. pd.requiredargarea:=paramanager.create_paraloc_info(pd,callerside);
  552. pd.has_paraloc_info:=true;
  553. end;
  554. {$if defined(powerpc) and defined(dummy)}
  555. { Disabled, because neither Clang nor gcc does this, and the ObjC
  556. runtime contains an explicit fix to detect this error. }
  557. { On ppc, the callee is responsible for removing the hidden function
  558. result parameter from the stack, so it has to know. On i386, it's
  559. the caller that does this. }
  560. if (pd.returndef<>voidtype) and
  561. paramgr.ret_in_param(pd.returndef,pocall_cdecl) then
  562. inc(totalsize,sizeof(pint));
  563. {$endif}
  564. for i:=0 to pd.paras.count-1 do
  565. begin
  566. vs:=tparavarsym(pd.paras[i]);
  567. if (vo_is_funcret in vs.varoptions) then
  568. continue;
  569. { addencodedtype always assumes a value parameter, so add
  570. a pointer indirection for var/out parameters. }
  571. if not paramanager.push_addr_param(vs_value,vs.vardef,pocall_cdecl) and
  572. (vs.varspez in [vs_var,vs_out]) then
  573. result:=result+'^';
  574. { Add the parameter type. }
  575. if not addencodedtype(vs.vardef,ris_initial,false,result,founderror) then
  576. { should be checked earlier on }
  577. internalerror(2009081701);
  578. { And the total size of the parameters coming before this one
  579. (i.e., the "offset" of this parameter). }
  580. result:=result+tostr(totalsize);
  581. { Update the total parameter size }
  582. parasize:=objcparasize(vs);
  583. inc(totalsize,parasize);
  584. end;
  585. { Prepend the total parameter size. }
  586. result:=tostr(totalsize)+result;
  587. { And the type of the function result (void in case of a procedure). }
  588. temp:='';
  589. if not addencodedtype(pd.returndef,ris_initial,false,temp,founderror) then
  590. internalerror(2009081801);
  591. result:=temp+result;
  592. end;
  593. {******************************************************************
  594. ObjC type validity checking
  595. *******************************************************************}
  596. function objcdochecktype(def: tdef; recordinfostate: trecordinfostate; out founderror: tdef): boolean; forward;
  597. function checkrecsttype(recst: tabstractrecordsymtable; recordinfostate: trecordinfostate; out founderror: tdef): boolean;
  598. var
  599. i: longint;
  600. field: tfieldvarsym;
  601. newstate: trecordinfostate;
  602. begin
  603. result:=false;
  604. newstate:=recordinfostate;
  605. { Although we never have to print the type info for nested
  606. records, check them anyway in case we're not after a pointer
  607. since if such records contain refcounted types then they
  608. can cause just as much trouble as if they were a simple
  609. refcounted field. }
  610. if (newstate=ris_afterpointer) then
  611. newstate:=ris_dontprint;
  612. for i:=0 to recst.symlist.count-1 do
  613. begin
  614. if (tsym(recst.symlist[i]).typ<>fieldvarsym) then
  615. continue;
  616. field:=tfieldvarsym(recst.symlist[i]);
  617. if not objcdochecktype(field.vardef,newstate,founderror) then
  618. exit;
  619. end;
  620. result:=true
  621. end;
  622. function objcdochecktype(def: tdef; recordinfostate: trecordinfostate; out founderror: tdef): boolean;
  623. var
  624. recdef: trecorddef;
  625. objdef: tobjectdef;
  626. newstate: trecordinfostate;
  627. begin
  628. result:=true;
  629. case def.typ of
  630. stringdef :
  631. begin
  632. case tstringdef(def).stringtype of
  633. st_shortstring:
  634. ;
  635. else
  636. { While we could handle refcounted Pascal strings correctly
  637. when such methods are called from Pascal code, things would
  638. completely break down if they were called from Objective-C
  639. code/reflection since the necessary refcount helper calls
  640. would be missing on the caller side (unless we'd
  641. automatically generate wrappers). }
  642. result:=false;
  643. end;
  644. end;
  645. enumdef,
  646. orddef :
  647. ;
  648. pointerdef :
  649. begin
  650. newstate:=recordinfostate;
  651. if (recordinfostate<ris_dontprint) then
  652. newstate:=succ(newstate);
  653. if not objcdochecktype(tpointerdef(def).pointeddef,newstate,founderror) then
  654. begin
  655. result:=false;
  656. { report the exact (nested) error defintion }
  657. exit;
  658. end;
  659. end;
  660. floatdef :
  661. begin
  662. case tfloatdef(def).floattype of
  663. s32real,
  664. s64real:
  665. ;
  666. else
  667. result:=false;
  668. end;
  669. end;
  670. filedef :
  671. result:=false;
  672. recorddef :
  673. begin
  674. if (recordinfostate<>ris_dontprint) then
  675. begin
  676. if not checkrecsttype(tabstractrecordsymtable(trecorddef(def).symtable),recordinfostate,founderror) then
  677. begin
  678. result:=false;
  679. { report the exact (nested) error defintion }
  680. exit;
  681. end
  682. end
  683. end;
  684. variantdef :
  685. begin
  686. recdef:=trecorddef(search_system_type('TVARDATA').typedef);
  687. if (recordinfostate<>ris_dontprint) then
  688. begin
  689. if not checkrecsttype(tabstractrecordsymtable(recdef.symtable),recordinfostate,founderror) then
  690. begin
  691. result:=false;
  692. { report the exact (nested) error defintion }
  693. exit;
  694. end
  695. end;
  696. end;
  697. classrefdef:
  698. begin
  699. if is_objcclassref(def) then
  700. begin
  701. objdef:=tobjectdef(tclassrefdef(def).pointeddef);
  702. newstate:=recordinfostate;
  703. if (recordinfostate<ris_dontprint) then
  704. newstate:=succ(newstate);
  705. if (newstate<>ris_dontprint) then
  706. begin
  707. if not checkrecsttype(tabstractrecordsymtable(objdef.symtable),recordinfostate,founderror) then
  708. begin
  709. result:=false;
  710. { report the exact (nested) error defintion }
  711. exit;
  712. end
  713. end
  714. end
  715. end;
  716. setdef,
  717. formaldef :
  718. ;
  719. arraydef :
  720. begin
  721. if is_array_of_const(def) then
  722. { ok, varargs are ignored in signatures }
  723. else if is_special_array(def) then
  724. result:=false
  725. else
  726. begin
  727. if not is_packed_array(def) then
  728. begin
  729. if not objcdochecktype(tarraydef(def).elementdef,ris_initial,founderror) then
  730. begin
  731. result:=false;
  732. { report the exact (nested) error defintion }
  733. exit;
  734. end;
  735. end;
  736. end;
  737. end;
  738. procvardef :
  739. ;
  740. objectdef :
  741. case tobjectdef(def).objecttype of
  742. odt_class,
  743. odt_object,
  744. odt_cppclass:
  745. begin
  746. newstate:=recordinfostate;
  747. { implicit pointer for classes }
  748. if (tobjectdef(def).objecttype=odt_class) then
  749. begin
  750. if (recordinfostate<ris_dontprint) then
  751. newstate:=succ(newstate);
  752. end;
  753. if newstate<>ris_dontprint then
  754. begin
  755. if not checkrecsttype(tabstractrecordsymtable(tobjectdef(def).symtable),newstate,founderror) then
  756. begin
  757. result:=false;
  758. { report the exact (nested) error defintion }
  759. exit;
  760. end
  761. end
  762. end;
  763. odt_interfacecom,
  764. odt_interfacecom_property,
  765. odt_interfacecom_function,
  766. odt_dispinterface:
  767. result:=false;
  768. odt_interfacecorba,
  769. odt_objcclass,
  770. odt_objcprotocol:
  771. ;
  772. else
  773. internalerror(2009081709);
  774. end;
  775. undefineddef,
  776. errordef :
  777. result:=false;
  778. procdef :
  779. result:=false;
  780. else
  781. internalerror(2009170812);
  782. end;
  783. if not result then
  784. founderror:=def;
  785. end;
  786. function objcchecktype(def: tdef; out founderror: tdef): boolean;
  787. begin
  788. result:=objcdochecktype(def,ris_initial,founderror);
  789. end;
  790. {******************************************************************
  791. ObjC class exporting
  792. *******************************************************************}
  793. procedure exportobjcclassfields(objccls: tobjectdef);
  794. var
  795. i: longint;
  796. vf: tfieldvarsym;
  797. prefix: string;
  798. begin
  799. prefix:=target_info.cprefix+'OBJC_IVAR_$_'+objccls.objextname^+'.';
  800. for i:=0 to objccls.symtable.SymList.Count-1 do
  801. if tsym(objccls.symtable.SymList[i]).typ=fieldvarsym then
  802. begin
  803. vf:=tfieldvarsym(objccls.symtable.SymList[i]);
  804. { TODO: package visibility (private_extern) -- must not be exported
  805. either}
  806. if not(vf.visibility in [vis_private,vis_strictprivate]) then
  807. exportname(prefix+vf.RealName,0);
  808. end;
  809. end;
  810. procedure exportobjcclass(def: tobjectdef);
  811. begin
  812. if (target_info.system in system_objc_nfabi) then
  813. begin
  814. { export class and metaclass symbols }
  815. exportname(def.rtti_mangledname(objcclassrtti),0);
  816. exportname(def.rtti_mangledname(objcmetartti),0);
  817. { export public/protected instance variable offset symbols }
  818. exportobjcclassfields(def);
  819. end
  820. else
  821. begin
  822. { export the class symbol }
  823. exportname('.objc_class_name_'+def.objextname^,0);
  824. end;
  825. end;
  826. end.