2
0

objcdef.pas 25 KB

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