objcdef.pas 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. {
  2. Copyright (c) 2010 by Jonas Maebe
  3. This unit implements some Objective-C type helper routines (minimal
  4. unit dependencies, usable in symdef).
  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 objcdef;
  20. interface
  21. uses
  22. symtype;
  23. { The internals of Objective-C's @encode() functionality: encode a
  24. type into the internal format used by the run time. Returns false
  25. if a type is not representable by the Objective-C run time, and in
  26. that case also the failing definition. }
  27. function objctryencodetype(def: tdef; out encodedtype: ansistring; out founderror: tdef): boolean;
  28. { Check whether a type can be used in an Objective-C method
  29. signature or field declaration. }
  30. function objcchecktype(def: tdef; out founderror: tdef): boolean;
  31. { add type info for def at the end of encodedstr. recordinfostate influences
  32. whether a record-style type will be fully encoded, or just using its
  33. type name. bpacked indicates whether a record/array is bitpacked.
  34. On error, founderror contains the type that triggered the error. }
  35. type
  36. trecordinfostate = (ris_initial, ris_afterpointer, ris_dontprint);
  37. function objcaddencodedtype(def: tdef; recordinfostate: trecordinfostate; bpacked: boolean; var encodedstr: ansistring; out founderror: tdef): boolean;
  38. implementation
  39. uses
  40. globtype,
  41. cutils,cclasses,
  42. verbose,
  43. symtable,symconst,symsym,symdef,
  44. defutil,paramgr;
  45. {******************************************************************
  46. Type encoding
  47. *******************************************************************}
  48. function encoderecst(const recname: ansistring; recst: tabstractrecordsymtable; var encodedstr: ansistring; out founderror: tdef): boolean;
  49. var
  50. variantstarts: tfplist;
  51. i, varindex: longint;
  52. field,
  53. firstfield: tfieldvarsym;
  54. firstfieldvariant,
  55. bpacked: boolean;
  56. begin
  57. result:=false;
  58. bpacked:=recst.fieldalignment=bit_alignment;
  59. { Is the first field already the start of a variant? }
  60. firstfield:=nil;
  61. firstfieldvariant:=false;
  62. for i:=0 to recst.symlist.count-1 do
  63. begin
  64. if (tsym(recst.symlist[i]).typ<>fieldvarsym) then
  65. continue;
  66. field:=tfieldvarsym(recst.symlist[i]);
  67. if not assigned(firstfield) then
  68. firstfield:=field
  69. else if (vo_is_first_field in field.varoptions) then
  70. begin
  71. if (field.fieldoffset=firstfield.fieldoffset) then
  72. firstfieldvariant:=true;
  73. end;
  74. end;
  75. variantstarts:=tfplist.create;
  76. encodedstr:=encodedstr+'{'+recname+'=';
  77. for i:=0 to recst.symlist.count-1 do
  78. begin
  79. if (tsym(recst.symlist[i]).typ<>fieldvarsym) then
  80. continue;
  81. field:=tfieldvarsym(recst.symlist[i]);
  82. { start of a variant part? }
  83. if ((field=firstfield) and
  84. firstfieldvariant) or
  85. ((field<>firstfield) and
  86. (vo_is_first_field in field.varoptions)) then
  87. begin
  88. varindex:=variantstarts.count-1;
  89. if (varindex=-1) or
  90. (tfieldvarsym(variantstarts[varindex]).fieldoffset<field.fieldoffset) then
  91. begin
  92. { new, more deeply nested variant }
  93. encodedstr:=encodedstr+'(?={?=';
  94. variantstarts.add(field);
  95. end
  96. else
  97. begin
  98. { close existing nested variants if any }
  99. while (varindex>=0) and
  100. (tfieldvarsym(variantstarts[varindex]).fieldoffset>field.fieldoffset) do
  101. begin
  102. { close more deeply nested variants }
  103. encodedstr:=encodedstr+'})';
  104. dec(varindex);
  105. end;
  106. if (varindex<0) then
  107. internalerror(2009081805);
  108. { variant at the same level as a previous one }
  109. variantstarts.count:=varindex+1;
  110. { No need to add this field, it has the same offset as the
  111. previous one at this position. }
  112. if tfieldvarsym(variantstarts[varindex]).fieldoffset<>field.fieldoffset then
  113. internalerror(2009081601);
  114. { close previous variant sub-part and start new one }
  115. encodedstr:=encodedstr+'}{?=';
  116. end
  117. end;
  118. if not objcaddencodedtype(field.vardef,ris_afterpointer,bpacked,encodedstr,founderror) then
  119. exit;
  120. end;
  121. for i:=0 to variantstarts.count-1 do
  122. encodedstr:=encodedstr+'})';
  123. variantstarts.free;
  124. variantstarts := nil;
  125. encodedstr:=encodedstr+'}';
  126. result:=true
  127. end;
  128. function objcaddencodedtype(def: tdef; recordinfostate: trecordinfostate; bpacked: boolean; var encodedstr: ansistring; out founderror: tdef): boolean;
  129. var
  130. recname: ansistring;
  131. recdef: trecorddef;
  132. objdef: tobjectdef;
  133. len: aint;
  134. c: char;
  135. newstate: trecordinfostate;
  136. addrpara: boolean;
  137. begin
  138. result:=true;
  139. case def.typ of
  140. stringdef :
  141. begin
  142. case tstringdef(def).stringtype of
  143. st_shortstring:
  144. { include length byte }
  145. encodedstr:=encodedstr+'['+tostr(tstringdef(def).len+1)+'C]';
  146. else
  147. { While we could handle refcounted Pascal strings correctly
  148. when such methods are called from Pascal code, things would
  149. completely break down if they were called from Objective-C
  150. code/reflection since the necessary refcount helper calls
  151. would be missing on the caller side (unless we'd
  152. automatically generate wrappers). }
  153. result:=false;
  154. end;
  155. end;
  156. enumdef,
  157. orddef :
  158. begin
  159. if bpacked and
  160. not is_void(def) then
  161. encodedstr:=encodedstr+'b'+tostr(def.packedbitsize)
  162. else
  163. begin
  164. if is_void(def) then
  165. c:='v'
  166. { in gcc, sizeof(_Bool) = sizeof(char) }
  167. else if is_boolean(def) and
  168. (def.size=1) then
  169. c:='B'
  170. else
  171. begin
  172. case def.size of
  173. 1:
  174. c:='c';
  175. 2:
  176. c:='s';
  177. 4:
  178. c:='i';
  179. 8:
  180. c:='q';
  181. else
  182. internalerror(2009081502);
  183. end;
  184. if not is_signed(def) then
  185. c:=upcase(c);
  186. end;
  187. encodedstr:=encodedstr+c;
  188. end;
  189. end;
  190. pointerdef :
  191. begin
  192. if is_pchar(def) then
  193. encodedstr:=encodedstr+'*'
  194. else if (def=objc_idtype) then
  195. encodedstr:=encodedstr+'@'
  196. else if (def=objc_seltype) then
  197. encodedstr:=encodedstr+':'
  198. else if (def=objc_metaclasstype) then
  199. encodedstr:=encodedstr+'#'
  200. else
  201. begin
  202. encodedstr:=encodedstr+'^';
  203. newstate:=recordinfostate;
  204. if (recordinfostate<ris_dontprint) then
  205. newstate:=succ(newstate);
  206. if not objcaddencodedtype(tpointerdef(def).pointeddef,newstate,false,encodedstr,founderror) then
  207. begin
  208. result:=false;
  209. { report the exact (nested) error defintion }
  210. exit;
  211. end;
  212. end;
  213. end;
  214. floatdef :
  215. begin
  216. case tfloatdef(def).floattype of
  217. s32real:
  218. c:='f';
  219. s64real:
  220. c:='d';
  221. else
  222. begin
  223. c:='!';
  224. result:=false;
  225. end;
  226. end;
  227. encodedstr:=encodedstr+c;
  228. end;
  229. filedef :
  230. result:=false;
  231. recorddef :
  232. begin
  233. if assigned(def.typesym) then
  234. recname:=def.typename
  235. else
  236. recname:='?';
  237. if (recordinfostate<>ris_dontprint) then
  238. begin
  239. if not encoderecst(recname,tabstractrecordsymtable(trecorddef(def).symtable),encodedstr,founderror) then
  240. begin
  241. result:=false;
  242. { report the exact (nested) error defintion }
  243. exit;
  244. end
  245. end
  246. else
  247. encodedstr:=encodedstr+'{'+recname+'}'
  248. end;
  249. variantdef :
  250. begin
  251. recdef:=trecorddef(search_system_type('TVARDATA').typedef);
  252. if (recordinfostate<>ris_dontprint) then
  253. begin
  254. if not encoderecst(recdef.typename,tabstractrecordsymtable(recdef.symtable),encodedstr,founderror) then
  255. begin
  256. result:=false;
  257. { report the exact (nested) error defintion }
  258. exit;
  259. end
  260. end
  261. else
  262. encodedstr:=encodedstr+'{'+recdef.typename+'}';
  263. end;
  264. classrefdef :
  265. begin
  266. encodedstr:=encodedstr+'^';
  267. newstate:=recordinfostate;
  268. if (recordinfostate<>ris_dontprint) then
  269. newstate:=succ(newstate);
  270. if is_objcclassref(def) then
  271. begin
  272. objdef:=tobjectdef(tclassrefdef(def).pointeddef);
  273. if (newstate<>ris_dontprint) then
  274. { anonymous (objc)class definitions do not exist }
  275. begin
  276. if not encoderecst(objdef.objextname^,tabstractrecordsymtable(objdef.symtable),encodedstr,founderror) then
  277. { The fields of an Objective-C class should always be
  278. encodeable. }
  279. internalerror(2009081702);
  280. end
  281. else
  282. encodedstr:=encodedstr+'{'+objdef.objextname^+'}'
  283. end
  284. { Object Pascal classrefdefs point to a vmt, not really useful
  285. to completely write those here. I'm not even sure what the
  286. Objective-C run time uses this information for, since in C you
  287. can have forward struct definitions so not all structs passed
  288. to functions can be written out here either -> treat
  289. classrefdefs the same as such forward-defined structs. }
  290. else
  291. begin
  292. if assigned(def.typesym) then
  293. recname:=def.typename
  294. else
  295. recname:='?';
  296. encodedstr:=encodedstr+'{'+recname;
  297. if (newstate<>ris_dontprint) then
  298. encodedstr:=encodedstr+'=';
  299. encodedstr:=encodedstr+'}'
  300. end;
  301. end;
  302. setdef :
  303. begin
  304. addrpara:=paramanager.push_addr_param(vs_value,def,pocall_cdecl);
  305. if not addrpara then
  306. { encode as an record, they are always passed by value in C. }
  307. encodedstr:=encodedstr+'{?=';
  308. { Encode the set itself as an array. Without an encompassing
  309. record, these are always passed by reference in C. }
  310. encodedstr:=encodedstr+'['+tostr(def.size)+'C]';
  311. if not addrpara then
  312. encodedstr:=encodedstr+'}';
  313. end;
  314. formaldef :
  315. begin
  316. encodedstr:=encodedstr+'^v';
  317. end;
  318. arraydef :
  319. begin
  320. if is_array_of_const(def) then
  321. { do nothing, varargs are ignored in signatures }
  322. else if is_special_array(def) then
  323. result:=false
  324. else
  325. begin
  326. len:=tarraydef(def).highrange-tarraydef(def).lowrange+1;
  327. if is_packed_array(def) then
  328. begin
  329. { convert from bits to bytes for bitpacked arrays }
  330. len:=(len+7) div 8;
  331. { and encode as plain array of bytes }
  332. encodedstr:=encodedstr+'['+tostr(len)+'C]';
  333. end
  334. else
  335. begin
  336. encodedstr:=encodedstr+'['+tostr(len);
  337. { Embedded structured types in the array are printed
  338. in full regardless of the current recordinfostate. }
  339. if not objcaddencodedtype(tarraydef(def).elementdef,ris_initial,false,encodedstr,founderror) then
  340. begin
  341. result:=false;
  342. { report the exact (nested) error defintion }
  343. exit;
  344. end;
  345. encodedstr:=encodedstr+']';
  346. end;
  347. end;
  348. end;
  349. procvardef :
  350. if not(po_is_block in tprocvardef(def).procoptions) then
  351. encodedstr:=encodedstr+'^?'
  352. else
  353. encodedstr:=encodedstr+'@?';
  354. objectdef :
  355. case tobjectdef(def).objecttype of
  356. odt_helper,
  357. odt_class,
  358. odt_object,
  359. odt_cppclass:
  360. begin
  361. newstate:=recordinfostate;
  362. { implicit pointer for classes }
  363. if (tobjectdef(def).objecttype in [odt_class,odt_helper]) then
  364. begin
  365. encodedstr:=encodedstr+'^';
  366. { make all classes opaque, so even if they contain a
  367. reference-counted field there is no problem. Since a
  368. "dereferenced class" object does not exist, this should
  369. not cause problems }
  370. newstate:=ris_dontprint;
  371. end;
  372. if newstate<>ris_dontprint then
  373. begin
  374. if not encoderecst(def.typename,tabstractrecordsymtable(tobjectdef(def).symtable),encodedstr,founderror) then
  375. begin
  376. result:=false;
  377. { report the exact (nested) error defintion }
  378. exit;
  379. end
  380. end
  381. else
  382. encodedstr:=encodedstr+'{'+def.typename+'}'
  383. end;
  384. odt_interfacecom,
  385. odt_interfacecom_property,
  386. odt_interfacecom_function,
  387. odt_dispinterface:
  388. result:=false;
  389. odt_interfacecorba:
  390. encodedstr:=encodedstr+'^{'+def.typename+'=}';
  391. { In Objective-C, the actual types of class instances are
  392. NSObject* etc, and those are encoded as "@". In FPC, to keep
  393. the similarity with Delphi-style Object Pascal, the type is
  394. NSObject and the pointer is implicit. Objective-C's "NSObject"
  395. has "class of NSObject" as equivalent here. }
  396. odt_objcclass,
  397. odt_objcprotocol:
  398. encodedstr:=encodedstr+'@';
  399. else
  400. internalerror(2009081509);
  401. end;
  402. undefineddef,
  403. errordef :
  404. result:=false;
  405. procdef :
  406. { must be done via objcencodemethod() }
  407. internalerror(2009081511);
  408. else
  409. internalerror(2009150812);
  410. end;
  411. if not result then
  412. founderror:=def;
  413. end;
  414. function objctryencodetype(def: tdef; out encodedtype: ansistring; out founderror: tdef): boolean;
  415. begin
  416. result:=objcaddencodedtype(def,ris_initial,false,encodedtype,founderror);
  417. end;
  418. {******************************************************************
  419. ObjC type validity checking
  420. *******************************************************************}
  421. function objcdochecktype(def: tdef; recordinfostate: trecordinfostate; out founderror: tdef): boolean; forward;
  422. function checkrecsttype(recst: tabstractrecordsymtable; recordinfostate: trecordinfostate; out founderror: tdef): boolean;
  423. var
  424. i: longint;
  425. field: tfieldvarsym;
  426. newstate: trecordinfostate;
  427. begin
  428. result:=false;
  429. newstate:=recordinfostate;
  430. { Although we never have to print the type info for nested
  431. records, check them anyway in case we're not after a pointer
  432. since if such records contain refcounted types then they
  433. can cause just as much trouble as if they were a simple
  434. refcounted field. }
  435. if (newstate=ris_afterpointer) then
  436. newstate:=ris_dontprint;
  437. for i:=0 to recst.symlist.count-1 do
  438. begin
  439. if (tsym(recst.symlist[i]).typ<>fieldvarsym) then
  440. continue;
  441. field:=tfieldvarsym(recst.symlist[i]);
  442. if not objcdochecktype(field.vardef,newstate,founderror) then
  443. exit;
  444. end;
  445. result:=true
  446. end;
  447. function objcdochecktype(def: tdef; recordinfostate: trecordinfostate; out founderror: tdef): boolean;
  448. var
  449. recdef: trecorddef;
  450. objdef: tobjectdef;
  451. newstate: trecordinfostate;
  452. begin
  453. result:=true;
  454. case def.typ of
  455. stringdef :
  456. begin
  457. case tstringdef(def).stringtype of
  458. st_shortstring:
  459. ;
  460. else
  461. { While we could handle refcounted Pascal strings correctly
  462. when such methods are called from Pascal code, things would
  463. completely break down if they were called from Objective-C
  464. code/reflection since the necessary refcount helper calls
  465. would be missing on the caller side (unless we'd
  466. automatically generate wrappers). }
  467. result:=false;
  468. end;
  469. end;
  470. enumdef,
  471. orddef :
  472. ;
  473. pointerdef :
  474. begin
  475. newstate:=recordinfostate;
  476. if (recordinfostate<ris_dontprint) then
  477. newstate:=succ(newstate);
  478. if not objcdochecktype(tpointerdef(def).pointeddef,newstate,founderror) then
  479. begin
  480. result:=false;
  481. { report the exact (nested) error defintion }
  482. exit;
  483. end;
  484. end;
  485. floatdef :
  486. begin
  487. case tfloatdef(def).floattype of
  488. s32real,
  489. s64real:
  490. ;
  491. else
  492. result:=false;
  493. end;
  494. end;
  495. filedef :
  496. result:=false;
  497. recorddef :
  498. begin
  499. if (recordinfostate<>ris_dontprint) then
  500. begin
  501. if not checkrecsttype(tabstractrecordsymtable(trecorddef(def).symtable),recordinfostate,founderror) then
  502. begin
  503. result:=false;
  504. { report the exact (nested) error defintion }
  505. exit;
  506. end
  507. end
  508. end;
  509. variantdef :
  510. begin
  511. recdef:=trecorddef(search_system_type('TVARDATA').typedef);
  512. if (recordinfostate<>ris_dontprint) then
  513. begin
  514. if not checkrecsttype(tabstractrecordsymtable(recdef.symtable),recordinfostate,founderror) then
  515. begin
  516. result:=false;
  517. { report the exact (nested) error defintion }
  518. exit;
  519. end
  520. end;
  521. end;
  522. classrefdef:
  523. begin
  524. if is_objcclassref(def) then
  525. begin
  526. objdef:=tobjectdef(tclassrefdef(def).pointeddef);
  527. newstate:=recordinfostate;
  528. if (recordinfostate<ris_dontprint) then
  529. newstate:=succ(newstate);
  530. if (newstate<>ris_dontprint) then
  531. begin
  532. if not checkrecsttype(tabstractrecordsymtable(objdef.symtable),recordinfostate,founderror) then
  533. begin
  534. result:=false;
  535. { report the exact (nested) error defintion }
  536. exit;
  537. end
  538. end
  539. end
  540. end;
  541. setdef,
  542. formaldef :
  543. ;
  544. arraydef :
  545. begin
  546. if is_array_of_const(def) then
  547. { ok, varargs are ignored in signatures }
  548. else if is_special_array(def) then
  549. result:=false
  550. else
  551. begin
  552. if not is_packed_array(def) then
  553. begin
  554. if not objcdochecktype(tarraydef(def).elementdef,ris_initial,founderror) then
  555. begin
  556. result:=false;
  557. { report the exact (nested) error defintion }
  558. exit;
  559. end;
  560. end;
  561. end;
  562. end;
  563. procvardef :
  564. ;
  565. objectdef :
  566. case tobjectdef(def).objecttype of
  567. odt_helper,
  568. odt_class,
  569. odt_object,
  570. odt_cppclass:
  571. begin
  572. newstate:=recordinfostate;
  573. { implicit pointer for classes }
  574. if (tobjectdef(def).objecttype in [odt_class,odt_helper]) then
  575. begin
  576. { make all classes opaque, so even if they contain a
  577. reference-counted field there is no problem. Since a
  578. "dereferenced class" object does not exist, this should
  579. not cause problems }
  580. newstate:=ris_dontprint;
  581. end;
  582. if newstate<>ris_dontprint then
  583. begin
  584. if not checkrecsttype(tabstractrecordsymtable(tobjectdef(def).symtable),newstate,founderror) then
  585. begin
  586. result:=false;
  587. { report the exact (nested) error defintion }
  588. exit;
  589. end
  590. end
  591. end;
  592. odt_interfacecom,
  593. odt_interfacecom_property,
  594. odt_interfacecom_function,
  595. odt_dispinterface:
  596. result:=false;
  597. odt_interfacecorba,
  598. odt_objcclass,
  599. odt_objcprotocol:
  600. ;
  601. else
  602. internalerror(2009081709);
  603. end;
  604. undefineddef,
  605. errordef :
  606. result:=false;
  607. procdef :
  608. result:=false;
  609. else
  610. internalerror(2009170812);
  611. end;
  612. if not result then
  613. founderror:=def;
  614. end;
  615. function objcchecktype(def: tdef; out founderror: tdef): boolean;
  616. begin
  617. result:=objcdochecktype(def,ris_initial,founderror);
  618. end;
  619. end.