gravity_objc.m 89 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190
  1. //
  2. // gravity_objc.c
  3. // GravityObjC
  4. //
  5. // Created by Marco Bambini on 07/02/21.
  6. //
  7. #import <Foundation/Foundation.h>
  8. #import <objc/runtime.h>
  9. #import "gravity_macros.h"
  10. #import "gravity_utils.h"
  11. #import "gravity_core.h"
  12. #import "gravity_hash.h"
  13. #import "gravity_objc.h"
  14. // MARK: - Macros -
  15. #define GRAVITY_BRIDGE_DEGUB 0
  16. #define GRAVITY_BRIDGE_DEGUB_XDATA 0
  17. #define GRAVITY_BRIDGE_DEBUG_MEMORY 0
  18. #define GRAVITY_BRIDGE_RETAIN 1
  19. #if GRAVITY_BRIDGE_RETAIN
  20. #define RETAIN_OBJC_VALUE(v) (void *)CFBridgingRetain(v)
  21. #define FREE_OBJC_VALUE(v) CFBridgingRelease((CFTypeRef)v)
  22. #else
  23. #define RETAIN_OBJC_VALUE(v) ((__bridge void*)v)
  24. #define FREE_OBJC_VALUE(v)
  25. #endif
  26. #if GRAVITY_BRIDGE_DEGUB
  27. #define DEBUG_BRIDGE(...) NSLog(__VA_ARGS__)
  28. #else
  29. #define DEBUG_BRIDGE(...)
  30. #endif
  31. #if GRAVITY_BRIDGE_DEGUB_XDATA
  32. #define DEBUG_XDATA(...) NSLog(__VA_ARGS__)
  33. #else
  34. #define DEBUG_XDATA(...)
  35. #endif
  36. #define BRIDGE_NAME "ObjC"
  37. #define BRIDGE_LOAD "register"
  38. #define BRIDGE_EXECUTE "exec" // MUST BE equal to GRAVITY_INTERNAL_EXEC_NAME
  39. #define RETURN_VALUE(_v,_i) do {gravity_vm_setslot(vm, _v, _i); return true;} while(0)
  40. #define RETURN_NOVALUE() return true
  41. #define RETURN_ERROR(...) do { \
  42. char buffer[4096]; \
  43. snprintf(buffer, sizeof(buffer), __VA_ARGS__); \
  44. gravity_fiber_seterror(gravity_vm_fiber(vm), (const char *) buffer); \
  45. return false; \
  46. } while(0)
  47. #define CHECK_INT(_v) (VALUE_ISA_INT(_v) || VALUE_ISA_BOOL(_v) || VALUE_ISA_NULL(_v))
  48. #define CHECK_FLOAT(_v) (VALUE_ISA_FLOAT(_v))
  49. #define CHECK_NUMBER(_v) (CHECK_INT(_v) || CHECK_FLOAT(_v))
  50. #define CONVERT_NUMBER(_v) VALUE_ISA_FLOAT(_v) ? _v.f : _v.n
  51. #define SANITY_CHECK_VALUE(_v) if (VALUE_ISA_NULL(_v) || (VALUE_ISA_NOTVALID(_v))) return nil;
  52. #define RETURN_NIL_ON_NULL 1
  53. // MARK: - Common native ObjC type -
  54. // opaque data types
  55. typedef struct objc_bridge_var_t objc_bridge_var_t;
  56. typedef struct objc_bridge_func_t objc_bridge_func_t;
  57. typedef NS_ENUM(uint32_t, objc_bridge_type) {
  58. OBJC_BRIDGE_TYPE_UNKNOWN = 0, // unhandled case
  59. // basic C types: https://en.wikipedia.org/wiki/C_data_types
  60. OBJC_BRIDGE_TYPE_VOID = 1, // no return type
  61. OBJC_BRIDGE_TYPE_INT8 = 2, // char, signed char
  62. OBJC_BRIDGE_TYPE_INT16 = 3, // short, short int, signed short, signed short int
  63. OBJC_BRIDGE_TYPE_INT32 = 4, // int, long, long int, signed long, signed long int
  64. OBJC_BRIDGE_TYPE_INT64 = 5, // long long, long long int, signed long long, signed long long int
  65. OBJC_BRIDGE_TYPE_UINT8 = 6, // unsigned char
  66. OBJC_BRIDGE_TYPE_UINT16 = 7, // unsigned short, unsigned short int
  67. OBJC_BRIDGE_TYPE_UINT32 = 8, // unsigned int, unsigned long, unsigned long int
  68. OBJC_BRIDGE_TYPE_UINT64 = 9, // unsigned long long, unsigned long long int
  69. OBJC_BRIDGE_TYPE_FLOAT = 10, // float
  70. OBJC_BRIDGE_TYPE_DOUBLE = 11, // double
  71. OBJC_BRIDGE_TYPE_LDOUBLE = 12, // long double (unused)
  72. OBJC_BRIDGE_TYPE_BOOL = 13, // bool, boolean, Boolean, BOOL
  73. OBJC_BRIDGE_TYPE_VPTR = 14, // void*
  74. OBJC_BRIDGE_TYPE_CPTR = 15, // char*
  75. // ObjC basic types
  76. OBJC_BRIDGE_TYPE_INIT = 16, // implicit return value of init
  77. OBJC_BRIDGE_TYPE_ID = 17, // for OBJC_BRIDGE_TYPE_ID it is object responsibility to sanity check it
  78. OBJC_BRIDGE_TYPE_CLASS = 18, // UNUSED
  79. OBJC_BRIDGE_TYPE_SEL = 19, // UNUSED
  80. OBJC_BRIDGE_TYPE_NSINTEGER = 20, // on 32-bit systems, these are defined to be 32-bit signed/unsigned,
  81. OBJC_BRIDGE_TYPE_NSUINTEGER = 21, // and on 64-bit systems, they are 64-bit integers.
  82. OBJC_BRIDGE_TYPE_NSNUMBER = 22,
  83. OBJC_BRIDGE_TYPE_NSSTRING = 23,
  84. OBJC_BRIDGE_TYPE_NSARRAY = 24,
  85. OBJC_BRIDGE_TYPE_NSDICTIONARY = 25,
  86. OBJC_BRIDGE_TYPE_NSDATE = 26,
  87. OBJC_BRIDGE_TYPE_NSDATA = 27,
  88. // Struct based types
  89. OBJC_BRIDGE_TYPE_POINT = 28,
  90. OBJC_BRIDGE_TYPE_RECT = 29,
  91. OBJC_BRIDGE_TYPE_SIZE = 30,
  92. OBJC_BRIDGE_TYPE_EDGEINSETS = 31,
  93. OBJC_BRIDGE_TYPE_OFFSET = 32,
  94. OBJC_BRIDGE_TYPE_RANGE = 33,
  95. // Custom complex types
  96. OBJC_BRIDGE_TYPE_IMAGE = 34,
  97. OBJC_BRIDGE_TYPE_COLOR = 35,
  98. OBJC_BRIDGE_TYPE_GRADIENT = 36,
  99. OBJC_BRIDGE_TYPE_MOVIE = 37,
  100. OBJC_BRIDGE_TYPE_SOUND = 38,
  101. OBJC_BRIDGE_TYPE_FONT = 39,
  102. OBJC_BRIDGE_TYPE_GRAVITY = 40, // pass through of native gravity objects
  103. OBJC_BRIDGE_TYPE_CLOSURE = 41, // must be closure function (or a runtime error is generated)
  104. OBJC_BRIDGE_TYPE_USER = 100, // MUST BE LATEST ENTRY means handled by the bridge conversion protocol
  105. } ;
  106. // MARK: - Internal Prototypes -
  107. static inline gravity_value_t convert_id2gravity (gravity_vm *vm, id value);
  108. static inline NSValue *convert_gravity2nsrangevalue (gravity_vm *vm, gravity_value_t value);
  109. static inline NSDictionary *convert_gravity2nsdictionary (gravity_vm *vm, gravity_value_t v);
  110. static inline NSArray* convert_gravity2nsarray (gravity_vm *vm, gravity_value_t v);
  111. bool bridge_initinstance (gravity_vm *vm, void *xdata, gravity_value_t ctx, gravity_instance_t *instance, gravity_value_t args[], int16_t nargs);
  112. bool bridge_setvalue (gravity_vm *vm, void *xdata, gravity_value_t target, const char *key, gravity_value_t value);
  113. bool bridge_getvalue (gravity_vm *vm, void *xdata, gravity_value_t target, const char *key, uint32_t rindex);
  114. bool bridge_setundef (gravity_vm *vm, void *xdata, gravity_value_t target, const char *key, gravity_value_t value);
  115. bool bridge_getundef (gravity_vm *vm, void *xdata, gravity_value_t target, const char *key, uint32_t rindex);
  116. bool bridge_execute (gravity_vm *vm, void *xdata, gravity_value_t ctx, gravity_value_t args[], int16_t nargs, uint32_t rindex);
  117. void bridge_blacken (gravity_vm *vm, void *xdata);
  118. void *bridge_duplicate (gravity_vm *vm, void *xdata);
  119. void bridge_free (gravity_vm *vm, gravity_object_t *obj);
  120. bool bridge_equals (gravity_vm *vm, void *obj_1, void *obj_2);
  121. void *bridge_clone (gravity_vm *vm, void *xdata);
  122. const char *bridge_string (gravity_vm *vm, void *xdata, uint32_t *len);
  123. // xdata
  124. objc_bridge_var_t *objc_bridge_var_new (objc_bridge_type type, const char *key);
  125. void objc_bridge_var_set_type (objc_bridge_var_t *xdata, objc_bridge_type type);
  126. void objc_bridge_var_free (objc_bridge_var_t *xdata);
  127. objc_bridge_func_t *objc_bridge_func_new (SEL selector, const char *name, uint16_t nargs, objc_bridge_type rettype);
  128. void objc_bridge_func_set_name (objc_bridge_func_t *xdata, const char *name);
  129. void objc_bridge_func_set_rettype (objc_bridge_func_t *xdata, objc_bridge_type rettype);
  130. void objc_bridge_func_set_argtype (objc_bridge_func_t *xdata, objc_bridge_type type, uint8_t index);
  131. void objc_bridge_func_set_argvalue (objc_bridge_func_t *xdata, id value, uint8_t index);
  132. void objc_bridge_func_free (objc_bridge_func_t *xdata);
  133. // conversion
  134. gravity_instance_t *bridge_instance_byclassname (gravity_vm *vm, id value, const char* name, uint32_t length);
  135. gravity_value_t bridge_objc2gravity (gravity_vm *vm, id obj, objc_bridge_type type);
  136. id bridge_gravity2objc (gravity_vm *vm, gravity_value_t value, objc_bridge_type type);
  137. const char *bridge_property_name(gravity_vm *vm, gravity_class_t *c, const char *key);
  138. objc_bridge_type bridge_property_type(gravity_vm *vm, gravity_class_t *c, const char *key);
  139. gravity_class_t *objc_class_load (gravity_vm *vm, const char *name);
  140. // MARK: - Internal Types -
  141. typedef NS_ENUM(uint8_t, objc_bridge_tag) {
  142. OBJC_BRIDGE_TAG_METHOD = 0,
  143. OBJC_BRIDGE_TAG_PROPERTY = 1
  144. };
  145. struct objc_bridge_func_t {
  146. objc_bridge_tag tag;
  147. SEL selector;
  148. void *invocation;
  149. // exposed name (for better error reporting)
  150. const char *name;
  151. objc_bridge_type rettype;
  152. NSUInteger retlength;
  153. uint16_t nargs;
  154. objc_bridge_type *argtype;
  155. void **argvalue;
  156. } objc_bridge_func_s;
  157. struct objc_bridge_var_t {
  158. objc_bridge_tag tag;
  159. objc_bridge_type type;
  160. const char *key;
  161. // exposed name (for better error reporting)
  162. const char *name;
  163. } objc_bridge_var_s;
  164. // MARK: - Core functions -
  165. static const char *objc_build_function_name (const char *name, char *buffer, size_t bsize) {
  166. size_t len = strlen(name);
  167. if (len > bsize) len = bsize - 1;
  168. bzero(buffer, bsize);
  169. for (size_t i=0; i<len; ++i) {
  170. if (name[i] == ':') break;
  171. buffer[i] = name[i];
  172. }
  173. return buffer;
  174. }
  175. static objc_bridge_type objc_decode_type (const char *c) {
  176. int idx = 0;
  177. // take in account Objective-C annotations for method parameters and return values
  178. // from: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
  179. // explanation: http://stackoverflow.com/questions/5609564/objective-c-in-out-inout-byref-byval-and-so-on-what-are-they
  180. switch (c[0]) {
  181. case 'r': // const
  182. case 'n': // in
  183. case 'N': // inout
  184. case 'o': // out
  185. case 'O': // bycopy
  186. case 'R': // byref
  187. case 'V': // oneway
  188. ++idx;
  189. }
  190. switch (c[idx]) {
  191. case 'c': return OBJC_BRIDGE_TYPE_INT8;
  192. case 'i': return OBJC_BRIDGE_TYPE_INT32;
  193. case 's': return OBJC_BRIDGE_TYPE_INT16;
  194. case 'l': return OBJC_BRIDGE_TYPE_INT32;
  195. case 'q': return OBJC_BRIDGE_TYPE_INT64;
  196. case 'C': return OBJC_BRIDGE_TYPE_UINT8;
  197. case 'I': return OBJC_BRIDGE_TYPE_UINT32;
  198. case 'S': return OBJC_BRIDGE_TYPE_UINT16;
  199. case 'L': return OBJC_BRIDGE_TYPE_UINT32;
  200. case 'Q': return OBJC_BRIDGE_TYPE_UINT64;
  201. case 'f': return OBJC_BRIDGE_TYPE_FLOAT;
  202. case 'd': return OBJC_BRIDGE_TYPE_DOUBLE;
  203. case 'B': return OBJC_BRIDGE_TYPE_BOOL;
  204. case 'v': return OBJC_BRIDGE_TYPE_VOID;
  205. case '@': {
  206. if (c[idx+1] == '"') {
  207. // FOUNDATION
  208. if (strncmp(&c[idx+2], "NSString", 8) == 0) return OBJC_BRIDGE_TYPE_NSSTRING;
  209. if (strncmp(&c[idx+2], "NSMutableString", 15) == 0) return OBJC_BRIDGE_TYPE_NSSTRING;
  210. if (strncmp(&c[idx+2], "NSNumber", 8) == 0) return OBJC_BRIDGE_TYPE_NSNUMBER;
  211. if (strncmp(&c[idx+2], "NSDecimalNumber", 15) == 0) return OBJC_BRIDGE_TYPE_NSNUMBER;
  212. if (strncmp(&c[idx+2], "NSArray", 7) == 0) return OBJC_BRIDGE_TYPE_NSARRAY;
  213. if (strncmp(&c[idx+2], "NSMutableArray", 14) == 0) return OBJC_BRIDGE_TYPE_NSARRAY;
  214. if (strncmp(&c[idx+2], "NSDictionary", 12) == 0) return OBJC_BRIDGE_TYPE_NSDICTIONARY;
  215. if (strncmp(&c[idx+2], "NSMutableDictionary", 19) == 0) return OBJC_BRIDGE_TYPE_NSDICTIONARY;
  216. if (strncmp(&c[idx+2], "NSData", 6) == 0) return OBJC_BRIDGE_TYPE_NSDATA;
  217. if (strncmp(&c[idx+2], "NSMutableData", 13) == 0) return OBJC_BRIDGE_TYPE_NSDATA;
  218. if (strncmp(&c[idx+2], "NSDate", 6) == 0) return OBJC_BRIDGE_TYPE_NSDATE;
  219. // IMAGE
  220. if (strncmp(&c[idx+2], "NSImage", 7) == 0) return OBJC_BRIDGE_TYPE_IMAGE;
  221. if (strncmp(&c[idx+2], "UIImage", 7) == 0) return OBJC_BRIDGE_TYPE_IMAGE;
  222. if (strncmp(&c[idx+2], "CREOImage", 9) == 0) return OBJC_BRIDGE_TYPE_IMAGE;
  223. // COLOR
  224. if (strncmp(&c[idx+2], "NSColor", 7) == 0) return OBJC_BRIDGE_TYPE_COLOR;
  225. if (strncmp(&c[idx+2], "UIColor", 7) == 0) return OBJC_BRIDGE_TYPE_COLOR;
  226. if (strncmp(&c[idx+2], "CREOColor", 9) == 0) return OBJC_BRIDGE_TYPE_COLOR;
  227. // GRADIENT
  228. if (strncmp(&c[idx+2], "NSGradient", 10) == 0) return OBJC_BRIDGE_TYPE_GRADIENT;
  229. if (strncmp(&c[idx+2], "UIGradient", 10) == 0) return OBJC_BRIDGE_TYPE_GRADIENT;
  230. if (strncmp(&c[idx+2], "CREOGradient", 12) == 0) return OBJC_BRIDGE_TYPE_GRADIENT;
  231. // FONT
  232. if (strncmp(&c[idx+2], "NSFont", 6) == 0) return OBJC_BRIDGE_TYPE_FONT;
  233. if (strncmp(&c[idx+2], "UIFont", 6) == 0) return OBJC_BRIDGE_TYPE_FONT;
  234. if (strncmp(&c[idx+2], "CREOFont", 8) == 0) return OBJC_BRIDGE_TYPE_FONT;
  235. // SOUND
  236. if (strncmp(&c[idx+2], "NSSound", 7) == 0) return OBJC_BRIDGE_TYPE_SOUND;
  237. if (strncmp(&c[idx+2], "UISound", 7) == 0) return OBJC_BRIDGE_TYPE_SOUND;
  238. if (strncmp(&c[idx+2], "CREOSound", 9) == 0) return OBJC_BRIDGE_TYPE_SOUND;
  239. // MOVIE
  240. if (strncmp(&c[idx+2], "CREOMovie", 9) == 0) return OBJC_BRIDGE_TYPE_MOVIE;
  241. // RECT
  242. if (strncmp(&c[idx+2], "CREORect", 8) == 0) return OBJC_BRIDGE_TYPE_RECT;
  243. // POINT
  244. if (strncmp(&c[idx+2], "CREOPoint", 9) == 0) return OBJC_BRIDGE_TYPE_POINT;
  245. // SIZE
  246. if (strncmp(&c[idx+2], "CREOSize", 8) == 0) return OBJC_BRIDGE_TYPE_SIZE;
  247. } return OBJC_BRIDGE_TYPE_ID;
  248. }
  249. case '{':
  250. if (c[idx+1] == '"') {
  251. // if (strncmp(&c[idx+2], "NSPoint", 7) == 0) return OBJC_BRIDGE_TYPE_POINT;
  252. // if (strncmp(&c[idx+2], "CGPoint", 7) == 0) return OBJC_BRIDGE_TYPE_POINT;
  253. //
  254. // if (strncmp(&c[idx+2], "NSRect", 6) == 0) return OBJC_BRIDGE_TYPE_RECT;
  255. // if (strncmp(&c[idx+2], "CGRect", 6) == 0) return OBJC_BRIDGE_TYPE_RECT;
  256. //
  257. // if (strncmp(&c[idx+2], "NSSize", 6) == 0) return OBJC_BRIDGE_TYPE_SIZE;
  258. // if (strncmp(&c[idx+2], "CGSize", 6) == 0) return OBJC_BRIDGE_TYPE_SIZE;
  259. //
  260. // if (strncmp(&c[idx+2], "NSEdgeInsets", 12) == 0) return OBJC_BRIDGE_TYPE_EDGEINSETS;
  261. // if (strncmp(&c[idx+2], "UIEdgeInsets", 12) == 0) return OBJC_BRIDGE_TYPE_EDGEINSETS;
  262. //
  263. // if (strncmp(&c[idx+2], "UIOffset", 8) == 0) return OBJC_BRIDGE_TYPE_OFFSET;
  264. //
  265. // if (strncmp(&c[idx+2], "NSRange", 7) == 0) return OBJC_BRIDGE_TYPE_RANGE;
  266. } return OBJC_BRIDGE_TYPE_UNKNOWN;
  267. case '*': return OBJC_BRIDGE_TYPE_CPTR;
  268. case '#': return OBJC_BRIDGE_TYPE_CLASS;
  269. case ':': return OBJC_BRIDGE_TYPE_SEL;
  270. case '^': return OBJC_BRIDGE_TYPE_VPTR;
  271. case '?': return OBJC_BRIDGE_TYPE_UNKNOWN;
  272. //case '[': return OBJC_BRIDGE_TYPE_ARRAY;
  273. //case '(': return OBJC_BRIDGE_TYPE_UNION;
  274. //case 'b': return OBJC_BRIDGE_TYPE_BIT;
  275. }
  276. return OBJC_BRIDGE_TYPE_UNKNOWN;
  277. }
  278. static objc_bridge_type objc_decode_attributes (const char *attributes, bool *readonly, NSMutableDictionary *toskip) {
  279. const char *p = attributes;
  280. *readonly = false;
  281. objc_bridge_type type = OBJC_BRIDGE_TYPE_UNKNOWN;
  282. while (p[0]) {
  283. switch (p[0]) {
  284. case 'T': {
  285. // property type
  286. type = objc_decode_type(&p[1]);
  287. } break;
  288. case 'V': {
  289. // property name
  290. } break;
  291. case 'R': {
  292. // property readonly flag
  293. *readonly = true;
  294. } break;
  295. case 'G':
  296. case 'S': {
  297. // property custom getter/setter names
  298. // must be added to toSkip dictionary
  299. NSString *customName = [NSString stringWithUTF8String:&p[1]];
  300. customName = [customName substringToIndex:[customName length] - 1];
  301. toskip[customName] = [NSNull null];
  302. } break;
  303. }
  304. // skip next
  305. while (p[0]) {
  306. ++p; if (p[0] == ',') {++p; break;}
  307. }
  308. }
  309. return type;
  310. }
  311. // for some strange reasons some properties are reported as methods for example UIView alpha
  312. static BOOL objc_check_fake_method (Class native_class, gravity_class_t *c, NSString *name, Method m, NSMutableDictionary *toskip) {
  313. // check if this method is not really a method but a property
  314. // for example UIView.h defines alpha as a CGFloat property
  315. // but runtime reports alpha as a pair of methods (a getter and a setter)
  316. // skip init cases
  317. if ([name hasPrefix:@"init"]) return NO;
  318. BOOL isFake = NO;
  319. NSString *getterName = NULL;
  320. NSString *setterName = NULL;
  321. Method getter = NULL;
  322. if ([name hasPrefix:@"set"]) {
  323. setterName = name;
  324. NSString *temp = [name substringFromIndex:3];
  325. NSString *firstChar = [[temp substringToIndex:1] lowercaseString];
  326. getterName = [firstChar stringByAppendingString:[temp substringFromIndex:1]];
  327. getterName = [getterName substringToIndex:[getterName length] - 1];
  328. getter = class_getInstanceMethod(native_class, NSSelectorFromString(setterName));
  329. isFake = (getter != nil);
  330. } else {
  331. getter = m;
  332. getterName = name;
  333. NSString *firstChar = [[name substringToIndex:1] uppercaseString];
  334. setterName = [firstChar stringByAppendingString:[name substringFromIndex:1]];
  335. setterName = [NSString stringWithFormat:@"set%@:", setterName];
  336. Method setter = class_getInstanceMethod(native_class, NSSelectorFromString(setterName));
  337. isFake = (setter != nil);
  338. }
  339. if (!isFake) return NO;
  340. // so it seems a fake method
  341. // check number of arguments (it is a getter so they must be 2, self, _CMD)
  342. unsigned int nparams = method_getNumberOfArguments(getter);
  343. if (nparams != 2) return NO;
  344. // check return type
  345. char buffer[1024];
  346. method_getReturnType(getter, buffer, sizeof(buffer));
  347. objc_bridge_type type = objc_decode_type(buffer);
  348. // a getter that returns a void cannot be a property
  349. if (type == OBJC_BRIDGE_TYPE_VOID) return NO;
  350. // let's convert it to a property using the getter return value
  351. // create gravity property and bind it to the class
  352. const char *property_name = [getterName UTF8String];
  353. objc_bridge_var_t *xdata = objc_bridge_var_new(type, NULL);
  354. bool readonly = false;
  355. gravity_closure_t *fget = gravity_closure_new(NULL, gravity_function_new_bridged(NULL, NULL, (void *)xdata));
  356. gravity_closure_t *fset = (readonly) ? NULL : fget;
  357. gravity_closure_t *closure = gravity_closure_new(NULL, gravity_function_new_special(NULL, NULL, GRAVITY_BRIDGE_INDEX, fget, fset));
  358. gravity_class_bind(c, property_name, VALUE_FROM_OBJECT(closure));
  359. // set names to skip for next loops
  360. toskip[getterName] = [NSNull null];
  361. toskip[setterName] = [NSNull null];
  362. return YES;
  363. }
  364. static void objc_class_scan (gravity_vm* vm, Class native_class, gravity_class_t *c) {
  365. #pragma unused(vm)
  366. // setup a toSkip dictionary in order to not process custom getter and setter
  367. NSMutableDictionary *toskip = [[NSMutableDictionary alloc] init];
  368. DEBUG_BRIDGE(@"Scanning class: %@", NSStringFromClass(native_class));
  369. // process properties
  370. unsigned int n = 0;
  371. objc_property_t *plist = class_copyPropertyList(native_class, &n);
  372. for (unsigned int i=0; i<n; ++i) {
  373. const char *name = property_getName(plist[i]);
  374. const char *attributes = property_getAttributes(plist[i]);
  375. // reserved internal objc properties to skip
  376. if (name[0] == '.') continue;
  377. if (name[0] == '_') continue;
  378. // since it is a property we need to skip getter and setter methods
  379. // setup standard getter and setter names
  380. NSString *propertyName = [NSString stringWithUTF8String:name];
  381. // don't know why but UIView reports some properties twice
  382. // so I need to check for duplicates here
  383. if (toskip[propertyName]) continue;
  384. // standard getter
  385. toskip[propertyName] = [NSNull null];
  386. // standard setter
  387. NSString *firstChar = [propertyName substringToIndex:1];
  388. NSString *standardSetter = [[firstChar uppercaseString] stringByAppendingString:[propertyName substringFromIndex:1]];
  389. toskip[[NSString stringWithFormat:@"set%@:", standardSetter]] = [NSNull null];
  390. DEBUG_BRIDGE(@"Property %d/%d: %@", i, n, propertyName);
  391. bool readonly;
  392. objc_bridge_type type = objc_decode_attributes(attributes, &readonly, toskip);
  393. objc_bridge_var_t *xdata = objc_bridge_var_new(type, NULL);
  394. gravity_closure_t *getter = gravity_closure_new(NULL, gravity_function_new_bridged(NULL, NULL, (void *)xdata));
  395. gravity_closure_t *setter = (readonly) ? NULL : getter;
  396. gravity_closure_t *closure = gravity_closure_new(NULL, gravity_function_new_special(NULL, NULL, GRAVITY_BRIDGE_INDEX, getter, setter));
  397. gravity_class_bind(c, name, VALUE_FROM_OBJECT(closure));
  398. }
  399. if (plist) free(plist);
  400. // process methods
  401. Method *mlist = class_copyMethodList(native_class, &n);
  402. for (unsigned int i=0; i<n; ++i) {
  403. char buffer[1024];
  404. SEL selector = method_getName(mlist[i]);
  405. const char *selname = sel_getName(selector);
  406. unsigned int nparams = method_getNumberOfArguments(mlist[i]);
  407. // reserved internal objc methods to skip
  408. if (selname[0] == '.') continue;
  409. if (selname[0] == '_') continue;
  410. // check if method is a getter/setter
  411. NSString *methodName = [NSString stringWithUTF8String:selname];
  412. if (toskip[methodName]) continue;
  413. // for some strange reasons some properties are reported as methods for example UIView alpha
  414. if (objc_check_fake_method(native_class, c, methodName, mlist[i], toskip)) continue;
  415. // allocate xdata
  416. // nparams-2 because there are two implicit parameters (self and _cmd)
  417. method_getReturnType(mlist[i], buffer, sizeof(buffer));
  418. objc_bridge_func_t *m = objc_bridge_func_new(selector, NULL, nparams-2, objc_decode_type(buffer));
  419. // get and decode arguments
  420. for (unsigned int j=2; j<nparams; ++j) {
  421. method_getArgumentType(mlist[i], j, buffer, sizeof(buffer));
  422. m->argtype[j-2] = objc_decode_type(buffer);
  423. }
  424. // from exposeName:withName: to exposeName
  425. const char *name = objc_build_function_name(selname, buffer, sizeof(buffer));
  426. // check for special init methods
  427. if (string_casencmp(name, "init", 4) == 0) {
  428. if (nparams == 2) snprintf(buffer, sizeof(buffer), "%s", CLASS_INTERNAL_INIT_NAME);
  429. else snprintf(buffer, sizeof(buffer), "%s%d", CLASS_INTERNAL_INIT_NAME, nparams-2);
  430. name = buffer;
  431. m->rettype = OBJC_BRIDGE_TYPE_INIT;
  432. }
  433. // bind bridged function to class
  434. gravity_closure_t *closure = gravity_closure_new(NULL, gravity_function_new_bridged(NULL, NULL, (void *)m));
  435. gravity_class_bind(c, name, VALUE_FROM_OBJECT(closure));
  436. DEBUG_BRIDGE(@"Method %d/%d: %s", i, n, name);
  437. }
  438. if (mlist) free(mlist);
  439. }
  440. // dynamically load an objc class specified by name into vm
  441. // class is parsed only if not yet loaded into vm
  442. gravity_class_t *objc_class_load (gravity_vm *vm, const char *name) {
  443. // check if class is already loaded into VM
  444. gravity_value_t v = gravity_vm_getvalue(vm, name, (uint32_t)strlen(name));
  445. if (VALUE_ISA_VALID(v)) return VALUE_AS_CLASS(v);
  446. // lookup class into objc runtime (sanity check)
  447. Class native_class = objc_getClass(name);
  448. if (native_class == NULL) {
  449. gravity_vm_seterror(vm, "Unable to find class name %s in Objective-C runtime", name);
  450. return NULL;
  451. }
  452. // recursively scan class hierarchy
  453. gravity_class_t *result = NULL;
  454. gravity_class_t *base = NULL;
  455. while (native_class) {
  456. DEBUG_BRIDGE(@"Loading class %s", name);
  457. // create gravity class
  458. gravity_class_t *c = gravity_class_new_pair(vm, name, NULL, 0, 0);
  459. gravity_class_setxdata(c, RETAIN_OBJC_VALUE(native_class));
  460. // instance
  461. objc_class_scan(vm, native_class, c);
  462. // meta
  463. objc_class_scan(vm, objc_getMetaClass(name), c->objclass);
  464. // classes loaded from bridge are globally availables
  465. gravity_vm_setvalue(vm, name, VALUE_FROM_OBJECT(c));
  466. // c is overwritten in the loop, so save the first class and returns it
  467. if (!result) result = c;
  468. // set super class
  469. if (base) gravity_class_setsuper(base, c);
  470. // check for superclass
  471. native_class = class_getSuperclass(native_class);
  472. if (!native_class) break;
  473. if (native_class == [NSObject class]) break;
  474. // check if superclass is already loaded into gravity
  475. name = class_getName(native_class);
  476. gravity_value_t _v = gravity_vm_getvalue(vm, name, (uint32_t)strlen(name));
  477. if (VALUE_ISA_VALID(_v)) {
  478. DEBUG_BRIDGE(@"Loading class %s (already found in hierarchy)", name);
  479. // super class is already registered in gravity runtime
  480. // so set c super and stop loop
  481. gravity_class_setsuper(c, (gravity_class_t *)VALUE_AS_OBJECT(_v));
  482. break;
  483. }
  484. // save base to set super
  485. base = c;
  486. }
  487. return result;
  488. }
  489. static bool objc_load (gravity_vm* vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
  490. #pragma unused(nargs)
  491. const char *nativeName = VALUE_AS_CSTRING(args[1]);
  492. gravity_gc_setenabled(vm, false);
  493. gravity_class_t *c = objc_class_load(vm, nativeName);
  494. gravity_gc_setenabled(vm, true);
  495. if (!c) return false;
  496. RETURN_VALUE(VALUE_FROM_OBJECT(c), rindex);
  497. return true;
  498. }
  499. static bool objc_exec (gravity_vm* vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
  500. // sanity check parameters
  501. if (!VALUE_ISA_INSTANCE(args[1])) RETURN_ERROR("objc.exec 1st parameter must be an instance");
  502. if (!VALUE_ISA_STRING(args[2])) RETURN_ERROR("objc.exec 2nd parameter must be a string");
  503. // unbox parameters
  504. gravity_instance_t *instance = VALUE_AS_INSTANCE(args[1]);
  505. gravity_string_t *message = VALUE_AS_STRING(args[2]);
  506. // sanity check objc
  507. if (!instance->xdata) RETURN_ERROR("objc.exec 1st parameter must be an objc object");
  508. // sanity check selector
  509. SEL selector = NSSelectorFromString(@(message->s));
  510. id obj = (__bridge id)instance->xdata;
  511. if (![obj respondsToSelector:selector]) {
  512. RETURN_ERROR("objc object does not respond to given selector");
  513. }
  514. // retrieve method from objc runtime
  515. Method m = class_getInstanceMethod([obj class], selector);
  516. if (!m) RETURN_ERROR("objc object does not respond to given selector");
  517. // decode method
  518. char buffer[1024];
  519. unsigned int nparams = method_getNumberOfArguments(m);
  520. // allocate xdata
  521. // nparams-2 because there are two implicit parameters (self and _cmd)
  522. method_getReturnType(m, buffer, sizeof(buffer));
  523. objc_bridge_func_t *data = objc_bridge_func_new(selector, NULL, nparams-2, objc_decode_type(buffer));
  524. // get and decode arguments
  525. for (unsigned int j=2; j<nparams; ++j) {
  526. method_getArgumentType(m, j, buffer, sizeof(buffer));
  527. data->argtype[j-2] = objc_decode_type(buffer);
  528. }
  529. // execute objc selector
  530. args[2] = args[1];
  531. bool result = bridge_execute(vm, (void *)data, args[1], &args[2], nargs-2, rindex);
  532. // free temp data
  533. objc_bridge_func_free(data);
  534. return result;
  535. }
  536. // MARK: - Public functions -
  537. void objc_register (gravity_vm *vm) {
  538. // register bridge delegate into VM
  539. gravity_delegate_t *delegate = gravity_vm_delegate(vm);
  540. delegate->bridge_initinstance = bridge_initinstance;
  541. delegate->bridge_getvalue = bridge_getvalue;
  542. delegate->bridge_setvalue = bridge_setvalue;
  543. delegate->bridge_getundef = bridge_getundef;
  544. delegate->bridge_setundef = bridge_setundef;
  545. delegate->bridge_execute = bridge_execute;
  546. delegate->bridge_blacken = bridge_blacken;
  547. delegate->bridge_equals = bridge_equals;
  548. delegate->bridge_string = bridge_string;
  549. delegate->bridge_free = bridge_free;
  550. delegate->bridge_clone = bridge_clone;
  551. // register objc.loadClass method
  552. gravity_gc_setenabled(vm, false);
  553. // register objc class
  554. gravity_class_t *c = gravity_class_new_pair(vm, BRIDGE_NAME, NULL, 0, 0);
  555. // register class_load
  556. gravity_closure_t *closure1 = gravity_closure_new(vm, gravity_function_new_internal(vm, NULL, objc_load, 0));
  557. gravity_class_bind(gravity_class_get_meta(c), BRIDGE_LOAD, VALUE_FROM_OBJECT(closure1));
  558. // register exec
  559. gravity_closure_t *closure2 = gravity_closure_new(vm, gravity_function_new_internal(vm, NULL, objc_exec, 0));
  560. gravity_class_bind(gravity_class_get_meta(c), BRIDGE_EXECUTE, VALUE_FROM_OBJECT(closure2));
  561. gravity_vm_setvalue(vm, BRIDGE_NAME, VALUE_FROM_OBJECT(c));
  562. gravity_gc_setenabled(vm, true);
  563. }
  564. // MARK: - xdata Management -
  565. objc_bridge_var_t *objc_bridge_var_new (objc_bridge_type type, const char *key) {
  566. objc_bridge_var_t *xdata = (objc_bridge_var_t *) mem_alloc(NULL, sizeof(objc_bridge_var_t));
  567. xdata->tag = OBJC_BRIDGE_TAG_PROPERTY;
  568. xdata->type = type;
  569. xdata->key = key; // objc real property name (if different from the exposed one)
  570. return xdata;
  571. }
  572. void objc_bridge_var_set_type (objc_bridge_var_t *xdata, objc_bridge_type type) {
  573. xdata->type = type;
  574. }
  575. void objc_bridge_var_free (objc_bridge_var_t *xdata) {
  576. if (xdata->key) mem_free(xdata->key);
  577. mem_free(xdata);
  578. }
  579. #pragma mark -
  580. objc_bridge_func_t *objc_bridge_func_new (SEL selector, const char *name, uint16_t nargs, objc_bridge_type rettype) {
  581. objc_bridge_func_t *xdata = mem_alloc(NULL, sizeof(objc_bridge_func_t));
  582. xdata->tag = OBJC_BRIDGE_TAG_METHOD;
  583. xdata->selector = selector;
  584. xdata->nargs = nargs;
  585. xdata->rettype = rettype;
  586. xdata->argtype = NULL;
  587. xdata->argvalue = NULL;
  588. xdata->name = (name) ? string_dup(name) : NULL;
  589. if (nargs) xdata->argtype = (objc_bridge_type *)calloc(nargs, sizeof(objc_bridge_type));
  590. return xdata;
  591. }
  592. void objc_bridge_func_set_name (objc_bridge_func_t *xdata, const char *name) {
  593. xdata->name = (name) ? string_dup(name) : NULL;
  594. }
  595. const char *objc_bridge_get_exposed_name (objc_bridge_func_t *xdata) {
  596. if (xdata->rettype == OBJC_BRIDGE_TYPE_INIT) return "init";
  597. if (xdata->name) return xdata->name;
  598. if (xdata->selector) return NSStringFromSelector(xdata->selector).UTF8String;
  599. return "N/A";
  600. }
  601. void objc_bridge_func_set_rettype (objc_bridge_func_t *xdata, objc_bridge_type rettype) {
  602. xdata->rettype = rettype;
  603. }
  604. void objc_bridge_func_set_argtype (objc_bridge_func_t *xdata, objc_bridge_type type, uint8_t index) {
  605. assert(index < xdata->nargs);
  606. xdata->argtype[index] = type;
  607. }
  608. void objc_bridge_func_set_argvalue (objc_bridge_func_t *xdata, id value, uint8_t index) {
  609. assert(index < xdata->nargs);
  610. if (!xdata->argvalue) xdata->argvalue = (void **)calloc(xdata->nargs, sizeof(void *));
  611. xdata->argvalue[index] = (void *)CFBridgingRetain(value);
  612. }
  613. void objc_bridge_func_free (objc_bridge_func_t *xdata) {
  614. if (xdata->invocation) CFBridgingRelease((CFTypeRef)xdata->invocation);
  615. if (xdata->argtype) free(xdata->argtype);
  616. if (xdata->name) mem_free(xdata->name);
  617. if (xdata->argvalue) {
  618. for (uint32_t i=0; i<xdata->nargs; ++i) {
  619. if (xdata->argvalue[i]) CFBridgingRelease((CFTypeRef)xdata->argvalue[i]);
  620. }
  621. free(xdata->argvalue);
  622. }
  623. mem_free(xdata);
  624. }
  625. // MARK: - Gravity => ObjC -
  626. static inline id convert_gravity2id (gravity_vm *vm, gravity_value_t value) {
  627. if (VALUE_ISA_INT(value)) return @(value.n);
  628. if (VALUE_ISA_FLOAT(value)) return @(value.f);
  629. if (VALUE_ISA_BOOL(value)) return [NSNumber numberWithBool:(value.n)];
  630. if ((VALUE_ISA_NULL(value)) || (VALUE_ISA_UNDEFINED(value))) return nil;
  631. if (VALUE_ISA_STRING(value)) return [NSString stringWithUTF8String:VALUE_AS_CSTRING(value)];
  632. if (VALUE_ISA_RANGE(value)) return convert_gravity2nsrangevalue(vm, value);
  633. if (VALUE_ISA_MAP(value)) return convert_gravity2nsdictionary(vm, value);
  634. if (VALUE_ISA_LIST(value)) return convert_gravity2nsarray(vm, value);
  635. if (!VALUE_ISA_INSTANCE(value)) return nil;
  636. return (__bridge id)gravity_value_xdata(value);
  637. }
  638. static inline id convert_gravity2type (gravity_vm *vm, gravity_value_t value, objc_bridge_type type) {
  639. id obj = convert_gravity2id(vm, value);
  640. // can be nil
  641. return obj;
  642. }
  643. static inline NSRange convert_gravity2nsrange (gravity_vm *vm, gravity_value_t value) {
  644. #pragma unused(vm)
  645. if (VALUE_ISA_RANGE(value)) {
  646. gravity_range_t *r = VALUE_AS_RANGE(value);
  647. return NSMakeRange((NSUInteger)r->from, (NSUInteger)r->to);
  648. }
  649. return NSMakeRange(0, 0);
  650. }
  651. static inline NSValue *convert_gravity2nsrangevalue (gravity_vm *vm, gravity_value_t value) {
  652. NSRange range = convert_gravity2nsrange(vm, value);
  653. return [NSValue valueWithRange:NSMakeRange(range.location, range.length)];
  654. }
  655. static void convert_nsdictionary_callback (gravity_hash_t *hashtable, gravity_value_t key, gravity_value_t value, void *data1, void *data2) {
  656. #pragma unused (hashtable)
  657. NSMutableDictionary *d = (__bridge NSMutableDictionary*)data1;
  658. gravity_vm *vm = (gravity_vm *)data2;
  659. d[@(VALUE_AS_CSTRING(key))] = convert_gravity2id(vm, value);
  660. }
  661. static inline NSArray* convert_gravity2nsarray (gravity_vm *vm, gravity_value_t v) {
  662. #pragma unused(vm)
  663. #if RETURN_NIL_ON_NULL
  664. if (VALUE_ISA_NULL(v) || VALUE_ISA_UNDEFINED(v)) return nil;
  665. #endif
  666. NSMutableArray *r = [NSMutableArray array];
  667. if (VALUE_ISA_LIST(v)) {
  668. gravity_list_t *list = VALUE_AS_LIST(v);
  669. for (uint32_t i=0; i<marray_size(list->array); ++i) {
  670. id obj = convert_gravity2id(vm, marray_get(list->array, i));
  671. if (obj) [r addObject:obj];
  672. }
  673. }
  674. return r;
  675. }
  676. static inline NSDictionary *convert_gravity2nsdictionary (gravity_vm *vm, gravity_value_t v) {
  677. #pragma unused(vm)
  678. #if RETURN_NIL_ON_NULL
  679. if (VALUE_ISA_NULL(v) || VALUE_ISA_UNDEFINED(v)) return nil;
  680. #endif
  681. NSMutableDictionary *d = [NSMutableDictionary dictionary];
  682. if (VALUE_ISA_MAP(v)) {
  683. gravity_map_t *map = VALUE_AS_MAP(v);
  684. gravity_hash_iterate2(map->hash, convert_nsdictionary_callback, (__bridge void *)d, (void*)vm);
  685. }
  686. return d;
  687. }
  688. static inline id convert_gravity2obj (gravity_vm *vm, gravity_value_t value, objc_bridge_type type) {
  689. #if RETURN_NIL_ON_NULL
  690. if (VALUE_ISA_NULL(value) || VALUE_ISA_UNDEFINED(value)) {
  691. // STRUCT BASED VALUE
  692. return nil;
  693. }
  694. #endif
  695. switch (type) {
  696. case OBJC_BRIDGE_TYPE_UNKNOWN:
  697. case OBJC_BRIDGE_TYPE_VOID:
  698. case OBJC_BRIDGE_TYPE_VPTR:
  699. case OBJC_BRIDGE_TYPE_CPTR:
  700. case OBJC_BRIDGE_TYPE_CLASS:
  701. case OBJC_BRIDGE_TYPE_SEL: {
  702. NSLog(@"Unsupported conversion in gravity2obj");
  703. return nil;
  704. }
  705. case OBJC_BRIDGE_TYPE_CLOSURE: {
  706. return nil;
  707. }
  708. case OBJC_BRIDGE_TYPE_BOOL: {
  709. gravity_value_t v = convert_value2bool(vm, value);
  710. SANITY_CHECK_VALUE(v);
  711. return @((BOOL)v.n);
  712. };
  713. case OBJC_BRIDGE_TYPE_INT8: {
  714. gravity_value_t v = convert_value2int(vm, value);
  715. SANITY_CHECK_VALUE(v);
  716. return @((int8_t)v.n);
  717. };
  718. case OBJC_BRIDGE_TYPE_INT16: {
  719. gravity_value_t v = convert_value2int(vm, value);
  720. SANITY_CHECK_VALUE(v);
  721. return @((int16_t)v.n);
  722. };
  723. case OBJC_BRIDGE_TYPE_INT32: {
  724. gravity_value_t v = convert_value2int(vm, value);
  725. SANITY_CHECK_VALUE(v);
  726. return @((int32_t)v.n);
  727. };
  728. case OBJC_BRIDGE_TYPE_INT64: {
  729. gravity_value_t v = convert_value2int(vm, value);
  730. SANITY_CHECK_VALUE(v);
  731. return @((int64_t)v.n);
  732. };
  733. case OBJC_BRIDGE_TYPE_UINT8: {
  734. gravity_value_t v = convert_value2int(vm, value);
  735. SANITY_CHECK_VALUE(v);
  736. return @((uint8_t)v.n);
  737. };
  738. case OBJC_BRIDGE_TYPE_UINT16: {
  739. gravity_value_t v = convert_value2int(vm, value);
  740. SANITY_CHECK_VALUE(v);
  741. return @((uint16_t)v.n);
  742. };
  743. case OBJC_BRIDGE_TYPE_UINT32: {
  744. gravity_value_t v = convert_value2int(vm, value);
  745. SANITY_CHECK_VALUE(v);
  746. return @((uint32_t)v.n);
  747. };
  748. case OBJC_BRIDGE_TYPE_UINT64: {
  749. gravity_value_t v = convert_value2int(vm, value);
  750. SANITY_CHECK_VALUE(v);
  751. return @((uint64_t)v.n);
  752. };
  753. case OBJC_BRIDGE_TYPE_FLOAT: {
  754. gravity_value_t v = convert_value2float(vm, value);
  755. SANITY_CHECK_VALUE(v);
  756. return @((float)v.f);
  757. };
  758. case OBJC_BRIDGE_TYPE_LDOUBLE:
  759. case OBJC_BRIDGE_TYPE_DOUBLE: {
  760. gravity_value_t v = convert_value2float(vm, value);
  761. SANITY_CHECK_VALUE(v);
  762. return @((double)v.f);
  763. };
  764. case OBJC_BRIDGE_TYPE_NSINTEGER: {
  765. gravity_value_t v = convert_value2int(vm, value);
  766. SANITY_CHECK_VALUE(v);
  767. return @((NSInteger)v.n);
  768. };
  769. case OBJC_BRIDGE_TYPE_NSUINTEGER: {
  770. gravity_value_t v = convert_value2int(vm, value);
  771. SANITY_CHECK_VALUE(v);
  772. return @((NSUInteger)v.n);
  773. };
  774. case OBJC_BRIDGE_TYPE_NSNUMBER: {
  775. if (VALUE_ISA_INT(value)) return @(value.n);
  776. else if (VALUE_ISA_FLOAT(value)) return @(value.f);
  777. gravity_value_t v = convert_value2int(vm, value);
  778. SANITY_CHECK_VALUE(v);
  779. return @(v.n);
  780. };
  781. case OBJC_BRIDGE_TYPE_NSSTRING: {
  782. gravity_value_t v = convert_value2string(vm, value);
  783. SANITY_CHECK_VALUE(v);
  784. return [NSString stringWithUTF8String:VALUE_AS_CSTRING(v)];
  785. }
  786. case OBJC_BRIDGE_TYPE_NSARRAY:
  787. return convert_gravity2nsarray(vm, value);
  788. case OBJC_BRIDGE_TYPE_NSDICTIONARY:
  789. return convert_gravity2nsdictionary(vm, value);
  790. case OBJC_BRIDGE_TYPE_RANGE:
  791. return convert_gravity2nsrangevalue(vm, value);
  792. case OBJC_BRIDGE_TYPE_POINT:
  793. case OBJC_BRIDGE_TYPE_RECT:
  794. case OBJC_BRIDGE_TYPE_SIZE:
  795. case OBJC_BRIDGE_TYPE_OFFSET:
  796. case OBJC_BRIDGE_TYPE_EDGEINSETS:
  797. case OBJC_BRIDGE_TYPE_FONT:
  798. case OBJC_BRIDGE_TYPE_SOUND:
  799. case OBJC_BRIDGE_TYPE_MOVIE:
  800. case OBJC_BRIDGE_TYPE_GRADIENT:
  801. case OBJC_BRIDGE_TYPE_NSDATE:
  802. case OBJC_BRIDGE_TYPE_NSDATA:
  803. case OBJC_BRIDGE_TYPE_IMAGE:
  804. case OBJC_BRIDGE_TYPE_COLOR:
  805. return convert_gravity2type(vm, value, type);
  806. case OBJC_BRIDGE_TYPE_GRAVITY:
  807. case OBJC_BRIDGE_TYPE_INIT:
  808. case OBJC_BRIDGE_TYPE_ID: return convert_gravity2id(vm, value);
  809. case OBJC_BRIDGE_TYPE_USER:
  810. return convert_gravity2type(vm, value, OBJC_BRIDGE_TYPE_USER);
  811. }
  812. return convert_gravity2type(vm, value, type);
  813. }
  814. // MARK: - ObjC => Gravity -
  815. static inline gravity_value_t convert_nsnumber2gravity (gravity_vm *vm, NSNumber *value) {
  816. const char *internal = [value objCType];
  817. switch (internal[0]) {
  818. case 'c': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_BOOL);
  819. case 'i': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_INT32);
  820. case 's': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_INT16);
  821. case 'l': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_INT32);
  822. case 'q': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_INT64);
  823. case 'C': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_UINT8);
  824. case 'I': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_UINT32);
  825. case 'S': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_UINT16);
  826. case 'L': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_UINT32);
  827. case 'Q': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_UINT64);
  828. case 'f': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_FLOAT);
  829. case 'd': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_DOUBLE);
  830. case 'B': return bridge_objc2gravity(vm, value, OBJC_BRIDGE_TYPE_BOOL);
  831. }
  832. return VALUE_FROM_NULL;
  833. }
  834. static inline gravity_value_t convert_nsstring2gravity (gravity_vm *vm, NSString *value) {
  835. return VALUE_FROM_STRING(vm, value.UTF8String, (uint32_t)[value lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
  836. }
  837. static inline gravity_value_t convert_creo2gravity (gravity_vm *vm, id value, objc_bridge_type type, BOOL value_retained) {
  838. #ifdef CREO_PROJECT
  839. if ([value respondsToSelector:@selector(runtimeInstance)]) {
  840. // if the creo objects already has an associated gravity instance, return it
  841. CREORuntimeInstance *runtimeInstance = [(id<CREORuntimeInstanceProtocol>)value runtimeInstance];
  842. gravity_instance_t *instance = (gravity_instance_t *)runtimeInstance.instance;
  843. if (instance) return VALUE_FROM_OBJECT(instance);
  844. }
  845. if ((!value) || ([value isKindOfClass:[NSNull class]])) return VALUE_FROM_NULL;
  846. if ([value isKindOfClass:[NSNumber class]]) return convert_nsnumber2gravity(vm, value);
  847. if ([value isKindOfClass:[NSString class]]) return convert_nsstring2gravity(vm, value);
  848. id<CREORuntimeDelegate> delegate = (__bridge id<CREORuntimeDelegate>)(gravity_vm_getdata(vm));
  849. Class c = (type != OBJC_BRIDGE_TYPE_UNKNOWN) ? [delegate classByTag:type] : nil;
  850. if (!c) c = [value class];
  851. NSString *name = [delegate classExposedNameByRealName:NSStringFromClass(c)];
  852. gravity_value_t v = gravity_vm_getvalue(vm, name.UTF8String, (uint32_t)name.length);
  853. if (!VALUE_ISA_CLASS(v)) return VALUE_FROM_NULL;
  854. gravity_class_t *c2 = VALUE_AS_CLASS(v);
  855. gravity_instance_t *instance = gravity_instance_new(vm, c2);
  856. gravity_instance_setxdata(instance, (value_retained) ? (__bridge void *)value : RETAIN_OBJC_VALUE(value));
  857. set_runtime_instance(vm, value, instance);
  858. return VALUE_FROM_OBJECT(instance);
  859. #else
  860. #pragma unused (vm, value, type)
  861. return VALUE_FROM_NULL;
  862. #endif
  863. }
  864. static inline gravity_value_t convert_nsarray2gravity (gravity_vm *vm, NSArray *r) {
  865. NSUInteger count = r.count;
  866. gravity_list_t *list = gravity_list_new(vm, (uint32_t)count);
  867. if (!list) return VALUE_FROM_NULL;
  868. for (id obj in r) {
  869. gravity_value_t v = convert_id2gravity(vm, obj);
  870. marray_push(gravity_value_t, list->array, v);
  871. }
  872. return VALUE_FROM_OBJECT(list);
  873. }
  874. static inline gravity_value_t convert_nsdictionary2gravity (gravity_vm *vm, NSDictionary *d) {
  875. NSUInteger count = d.allKeys.count;
  876. gravity_map_t *map = gravity_map_new(vm, (uint32_t)count);
  877. for (NSString *key in d.allKeys) {
  878. id obj = d[key];
  879. gravity_value_t v = bridge_objc2gravity(vm, obj, OBJC_BRIDGE_TYPE_ID);
  880. gravity_value_t k = VALUE_FROM_STRING(vm, key.UTF8String, (uint32_t)[key lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
  881. gravity_hash_insert(map->hash, k, v);
  882. }
  883. return VALUE_FROM_OBJECT(map);
  884. }
  885. static inline gravity_value_t convert_nsvalue2gravity (gravity_vm *vm, id obj, objc_bridge_type type) {
  886. // called ONLY when I am sure that obj isKindOfClass NSValue
  887. NSValue *value = (NSValue*)obj;
  888. if (((type == OBJC_BRIDGE_TYPE_UNKNOWN) || (type == OBJC_BRIDGE_TYPE_RANGE)) && (strcmp(value.objCType, @encode(NSRange)) == 0)) {
  889. NSRange v = [value rangeValue];
  890. return VALUE_FROM_OBJECT(gravity_range_new(vm, v.location, v.length, true));
  891. }
  892. #ifdef CREO_PROJECT
  893. Class c = nil;
  894. if (((type == OBJC_BRIDGE_TYPE_UNKNOWN) || (type == OBJC_BRIDGE_TYPE_POINT)) && (strcmp(value.objCType, @encode(CGPoint)) == 0)) c = CREOPoint.class;
  895. else if (((type == OBJC_BRIDGE_TYPE_UNKNOWN) || (type == OBJC_BRIDGE_TYPE_RECT)) && (strcmp(value.objCType, @encode(CGRect)) == 0)) c = CREORect.class;
  896. else if (((type == OBJC_BRIDGE_TYPE_UNKNOWN) || (type == OBJC_BRIDGE_TYPE_SIZE)) && (strcmp(value.objCType, @encode(CGSize)) == 0)) c = CREOSize.class;
  897. else if (((type == OBJC_BRIDGE_TYPE_UNKNOWN) || (type == OBJC_BRIDGE_TYPE_OFFSET)) && (strcmp(value.objCType, @encode(UIOffset)) == 0)) c = CREOOffset.class;
  898. else if (((type == OBJC_BRIDGE_TYPE_UNKNOWN) || (type == OBJC_BRIDGE_TYPE_EDGEINSETS)) && (strcmp(value.objCType, @encode(UIEdgeInsets)) == 0)) c = CREOEdgeInsets.class;
  899. if (c) {
  900. CREOStruct *creoObj = (CREOStruct *)[[c alloc] init];
  901. [creoObj setValue:value];
  902. return convert_creo2gravity(vm, creoObj, type, NO);
  903. }
  904. #endif
  905. return VALUE_FROM_NULL;
  906. }
  907. static inline gravity_value_t convert_id2gravity (gravity_vm *vm, id value) {
  908. // not sure if its a good idea to not trigger a crash in this case
  909. if (!value) return VALUE_FROM_NULL;
  910. // NSNumber case
  911. if ([value isKindOfClass:[NSNumber class]]) {
  912. return convert_nsnumber2gravity(vm, value);
  913. }
  914. // NSString case
  915. if ([value isKindOfClass:[NSString class]]) {
  916. return convert_nsstring2gravity(vm, value);
  917. }
  918. // NSArray case
  919. if ([value isKindOfClass:[NSArray class]]) {
  920. return convert_nsarray2gravity(vm, value);
  921. }
  922. // NSDictionary case
  923. if ([value isKindOfClass:[NSDictionary class]]) {
  924. return convert_nsdictionary2gravity(vm, value);
  925. }
  926. // NSValue case
  927. if ([value isKindOfClass:[NSValue class]]) {
  928. return convert_nsvalue2gravity(vm, value, OBJC_BRIDGE_TYPE_UNKNOWN);
  929. }
  930. // NSNull case
  931. if ([value isKindOfClass:[NSNull class]]) {
  932. return VALUE_FROM_NULL;
  933. }
  934. return convert_creo2gravity(vm, value, OBJC_BRIDGE_TYPE_UNKNOWN, NO);
  935. }
  936. // MARK: - Bridge Utils -
  937. id bridge_gravity2objc (gravity_vm *vm, gravity_value_t value, objc_bridge_type type) {
  938. // must be protected because it is used by Creo in every event
  939. gravity_gc_setenabled(vm, false);
  940. id v = convert_gravity2obj(vm, value, type);
  941. gravity_gc_setenabled(vm, true);
  942. return v;
  943. }
  944. gravity_instance_t *bridge_instance_byclassname (gravity_vm *vm, id value, const char* name, uint32_t length) {
  945. gravity_value_t v = gravity_vm_getvalue(vm, name, length);
  946. if (!VALUE_ISA_CLASS(v)) return NULL;
  947. gravity_class_t *c2 = VALUE_AS_CLASS(v);
  948. gravity_instance_t *instance = gravity_instance_new(vm, c2);
  949. gravity_instance_setxdata(instance, RETAIN_OBJC_VALUE(value));
  950. return instance;
  951. }
  952. static gravity_value_t bridge_objc2gravity_retain_flag (gravity_vm *vm, id obj, objc_bridge_type type, BOOL value_retained) {
  953. // sanity check
  954. if (!obj) return VALUE_FROM_NULL;
  955. @try {
  956. switch (type) {
  957. case OBJC_BRIDGE_TYPE_UNKNOWN: {
  958. return convert_creo2gravity(vm, obj, OBJC_BRIDGE_TYPE_UNKNOWN, value_retained);
  959. }
  960. case OBJC_BRIDGE_TYPE_SEL:
  961. case OBJC_BRIDGE_TYPE_VPTR:
  962. case OBJC_BRIDGE_TYPE_CPTR:
  963. case OBJC_BRIDGE_TYPE_VOID:
  964. case OBJC_BRIDGE_TYPE_CLASS: {
  965. return VALUE_FROM_NULL;
  966. }
  967. case OBJC_BRIDGE_TYPE_INIT:
  968. case OBJC_BRIDGE_TYPE_ID:
  969. case OBJC_BRIDGE_TYPE_USER:
  970. case OBJC_BRIDGE_TYPE_GRAVITY: {
  971. return convert_id2gravity(vm, obj);
  972. }
  973. case OBJC_BRIDGE_TYPE_RANGE: {
  974. return convert_nsvalue2gravity(vm, obj, type);
  975. }
  976. case OBJC_BRIDGE_TYPE_POINT:
  977. case OBJC_BRIDGE_TYPE_RECT:
  978. case OBJC_BRIDGE_TYPE_SIZE:
  979. case OBJC_BRIDGE_TYPE_OFFSET:
  980. case OBJC_BRIDGE_TYPE_EDGEINSETS: {
  981. if ([obj isKindOfClass:[NSValue class]]) return convert_nsvalue2gravity(vm, obj, type);
  982. return convert_creo2gravity(vm, obj, type, value_retained);
  983. }
  984. case OBJC_BRIDGE_TYPE_NSDATE:
  985. case OBJC_BRIDGE_TYPE_NSDATA:
  986. case OBJC_BRIDGE_TYPE_IMAGE:
  987. case OBJC_BRIDGE_TYPE_COLOR:
  988. case OBJC_BRIDGE_TYPE_GRADIENT:
  989. case OBJC_BRIDGE_TYPE_MOVIE:
  990. case OBJC_BRIDGE_TYPE_SOUND:
  991. case OBJC_BRIDGE_TYPE_FONT: {
  992. return convert_creo2gravity(vm, obj, type, value_retained);
  993. }
  994. case OBJC_BRIDGE_TYPE_NSARRAY: {
  995. if ([obj isKindOfClass:[NSArray class]])
  996. return convert_nsarray2gravity(vm, obj);
  997. else
  998. return convert_nsarray2gravity(vm, @[obj]);
  999. }
  1000. case OBJC_BRIDGE_TYPE_NSDICTIONARY: {
  1001. if ([obj isKindOfClass:[NSDictionary class]])
  1002. return convert_nsdictionary2gravity(vm, obj);
  1003. else
  1004. return convert_creo2gravity(vm, obj, type, value_retained);
  1005. }
  1006. case OBJC_BRIDGE_TYPE_NSNUMBER: {
  1007. if ([obj isKindOfClass:[NSNumber class]])
  1008. return convert_nsnumber2gravity(vm, obj);
  1009. else
  1010. return convert_creo2gravity(vm, obj, type, value_retained);
  1011. }
  1012. case OBJC_BRIDGE_TYPE_INT8: {
  1013. int8_t value = [obj charValue];
  1014. return VALUE_FROM_INT((gravity_int_t)value);
  1015. }
  1016. case OBJC_BRIDGE_TYPE_INT16: {
  1017. int16_t value = [obj shortValue];
  1018. return VALUE_FROM_INT((gravity_int_t)value);
  1019. }
  1020. case OBJC_BRIDGE_TYPE_INT32: {
  1021. int32_t value = (int32_t)[obj longValue];
  1022. return VALUE_FROM_INT((gravity_int_t)value);
  1023. }
  1024. case OBJC_BRIDGE_TYPE_INT64: {
  1025. int64_t value = [obj longLongValue];
  1026. return VALUE_FROM_INT((gravity_int_t)value);
  1027. }
  1028. case OBJC_BRIDGE_TYPE_UINT8: {
  1029. uint8_t value = [obj unsignedCharValue];
  1030. return VALUE_FROM_INT((gravity_int_t)value);
  1031. }
  1032. case OBJC_BRIDGE_TYPE_UINT16: {
  1033. uint16_t value = [obj unsignedShortValue];
  1034. return VALUE_FROM_INT((gravity_int_t)value);
  1035. }
  1036. case OBJC_BRIDGE_TYPE_UINT32: {
  1037. uint32_t value = (uint32_t)[obj unsignedLongValue];
  1038. return VALUE_FROM_INT((gravity_int_t)value);
  1039. }
  1040. case OBJC_BRIDGE_TYPE_UINT64: {
  1041. uint64_t value = [obj unsignedLongLongValue];
  1042. return VALUE_FROM_INT((gravity_int_t)value);
  1043. }
  1044. case OBJC_BRIDGE_TYPE_FLOAT: {
  1045. float value = [obj floatValue];
  1046. return VALUE_FROM_FLOAT((gravity_float_t)value);
  1047. }
  1048. case OBJC_BRIDGE_TYPE_LDOUBLE:
  1049. case OBJC_BRIDGE_TYPE_DOUBLE: {
  1050. double value = [obj doubleValue];
  1051. return VALUE_FROM_FLOAT((gravity_float_t)value);
  1052. }
  1053. case OBJC_BRIDGE_TYPE_BOOL: {
  1054. BOOL value = [obj boolValue];
  1055. return VALUE_FROM_BOOL(value);
  1056. }
  1057. case OBJC_BRIDGE_TYPE_NSINTEGER: {
  1058. NSInteger value = [obj integerValue];
  1059. return VALUE_FROM_INT((gravity_int_t)value);
  1060. }
  1061. case OBJC_BRIDGE_TYPE_NSUINTEGER: {
  1062. NSUInteger value = [obj unsignedIntegerValue];
  1063. return VALUE_FROM_INT((gravity_int_t)value);
  1064. }
  1065. case OBJC_BRIDGE_TYPE_NSSTRING: {
  1066. return VALUE_FROM_STRING(vm, ((NSString*)obj).UTF8String, (uint32_t)[(NSString*)obj lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
  1067. }
  1068. default: {
  1069. return convert_creo2gravity(vm, obj, type, value_retained);
  1070. }
  1071. }
  1072. } @catch (NSException *exception) {
  1073. NSLog(@"bridge_objc2gravity %@ (%@ %d)", exception.reason, obj, type);
  1074. return convert_creo2gravity(vm, obj, type, value_retained);
  1075. }
  1076. return VALUE_FROM_NULL;
  1077. }
  1078. gravity_value_t bridge_objc2gravity (gravity_vm *vm, id obj, objc_bridge_type type) {
  1079. // must be protected because it is used by Creo in every event
  1080. gravity_gc_setenabled(vm, false);
  1081. gravity_value_t v = bridge_objc2gravity_retain_flag(vm, obj, type, NO);
  1082. gravity_gc_setenabled(vm, true);
  1083. return v;
  1084. }
  1085. static objc_bridge_var_t *bridge_property (gravity_vm *vm, gravity_class_t *c, const char *key) {
  1086. #pragma unused(vm)
  1087. STATICVALUE_FROM_STRING(k, key, strlen(key));
  1088. gravity_object_t *obj = gravity_class_lookup(c, k);
  1089. if (!obj) return NULL;
  1090. if (!OBJECT_ISA_CLOSURE(obj)) return NULL;
  1091. gravity_closure_t *closure = (gravity_closure_t*)obj;
  1092. if (closure->f->tag != EXEC_TYPE_SPECIAL) return NULL;
  1093. if (closure->f->index != GRAVITY_BRIDGE_INDEX) return NULL;
  1094. closure = (closure->f->special[0]) ? closure->f->special[0] : closure->f->special[1];
  1095. if (!closure || (!closure->f)) return NULL;
  1096. if (!closure->f->xdata) return NULL;
  1097. return (objc_bridge_var_t *)closure->f->xdata;
  1098. }
  1099. objc_bridge_type bridge_property_type (gravity_vm *vm, gravity_class_t *c, const char *key) {
  1100. objc_bridge_var_t *property = bridge_property(vm, c, key);
  1101. if (!property) return OBJC_BRIDGE_TYPE_UNKNOWN;
  1102. return property->type;
  1103. }
  1104. const char *bridge_property_name (gravity_vm *vm, gravity_class_t *c, const char *key) {
  1105. objc_bridge_var_t *property = bridge_property(vm, c, key);
  1106. if (!property) return key;
  1107. if (!property->key) return key;
  1108. return property->key;
  1109. }
  1110. // MARK: - Delegate -
  1111. bool bridge_initinstance (gravity_vm *vm, void *xdata, gravity_value_t ctx, gravity_instance_t *instance, gravity_value_t args[], int16_t nargs) {
  1112. gravity_class_t *class = instance->objclass;
  1113. Class c = (__bridge Class)(class->xdata);
  1114. // special case to force to use xdata directly
  1115. if (VALUE_ISA_NULL(ctx) && args == NULL && nargs == 1) c = (__bridge Class)xdata;
  1116. id obj = [c alloc];
  1117. gravity_instance_setxdata(instance, RETAIN_OBJC_VALUE(obj));
  1118. if (nargs == 1) {
  1119. // no arguments so just execute the init (obj2 can be different than obj, for example the NSDate init)
  1120. id obj2 = [obj init];
  1121. if (!obj2) RETURN_ERROR("Unable to initialize object.");
  1122. #ifdef CREO_PROJECT
  1123. set_runtime_instance(vm, obj2, instance);
  1124. #endif
  1125. if (obj != obj2) {
  1126. // note1:
  1127. // when the two objects are different (alloc != init) it means that in init there is a code like
  1128. // self = something
  1129. // and this line automatically send a release message to the original object so an explicit release
  1130. // is not needed
  1131. // RELEASE_OBJC_VALUE(obj);
  1132. gravity_instance_setxdata(instance, RETAIN_OBJC_VALUE(obj2));
  1133. }
  1134. RETURN_NOVALUE();
  1135. }
  1136. // there are more arguments so execute the init function
  1137. void *saved = gravity_vm_getdata(vm);
  1138. args[0] = VALUE_FROM_OBJECT(instance);
  1139. if (!bridge_execute(vm, xdata, ctx, args, nargs, GRAVITY_DATA_REGISTER)) {
  1140. gravity_instance_setxdata(instance, NULL);
  1141. return false;
  1142. }
  1143. // obj2 can be different from obj if the init method returns a different object from the previously allocated one
  1144. id obj2 = (__bridge id)(gravity_vm_getdata(vm));
  1145. gravity_vm_setdata(vm, saved);
  1146. if (!obj2) {
  1147. gravity_instance_setxdata(instance, NULL);
  1148. NSString *name = NULL;
  1149. RETURN_ERROR("Unable to initialize object of type %s.", (name) ? name.UTF8String : class->identifier);
  1150. }
  1151. #if GRAVITY_BRIDGE_DEBUG_MEMORY
  1152. NSLog(@"Created instance %p (%@)", obj2, NSStringFromClass([obj2 class]));
  1153. #endif
  1154. if (obj != obj2) {
  1155. // see note1 above
  1156. // RELEASE_OBJC_VALUE(obj);
  1157. // obj2 has already been retained in the bridge_execute
  1158. gravity_instance_setxdata(instance, (__bridge void *)(obj2));
  1159. }
  1160. RETURN_NOVALUE();
  1161. }
  1162. bool bridge_setvalue (gravity_vm *vm, void *xdata, gravity_value_t target, const char *key, gravity_value_t value) {
  1163. DEBUG_BRIDGE(@"bridge_setvalue %s", key);
  1164. // obtain property type and optional key from class xdata
  1165. objc_bridge_var_t *property = (objc_bridge_var_t *)xdata;
  1166. if (property->key) key = property->key;
  1167. id objcValue = convert_gravity2obj(vm, value, property->type);
  1168. // get objc obj from target xdata
  1169. id obj = (__bridge id)gravity_value_xdata(target);
  1170. if (!obj) return false;
  1171. @try {
  1172. [obj setValue:objcValue forKey:@(key)];
  1173. }
  1174. @catch (NSException * e) {
  1175. gravity_vm_seterror(vm, "An error occurred while writing key %s (%s).", key, [[e reason] UTF8String]);
  1176. return false;
  1177. }
  1178. RETURN_NOVALUE();
  1179. }
  1180. bool bridge_getvalue (gravity_vm *vm, void *xdata, gravity_value_t target, const char *key, uint32_t rindex) {
  1181. DEBUG_BRIDGE(@"bridge_getvalue %s", key);
  1182. // obtain property type and optional key from class xdata
  1183. objc_bridge_var_t *property = (objc_bridge_var_t *)xdata;
  1184. if (property->key) key = property->key;
  1185. // get objc obj from target xdata
  1186. id obj = (__bridge id)gravity_value_xdata(target);
  1187. if (!obj) return false;
  1188. id result;
  1189. @try {
  1190. result = [obj valueForKey:@(key)];
  1191. }
  1192. @catch (NSException * e) {
  1193. gravity_vm_seterror(vm, "An error occurred while reading key %s (%s).", key, [[e reason] UTF8String]);
  1194. return false;
  1195. }
  1196. gravity_value_t value = bridge_objc2gravity(vm, result, property->type);
  1197. RETURN_VALUE(value, rindex);
  1198. }
  1199. bool bridge_setundef (gravity_vm *vm, void *xdata, gravity_value_t target, const char *key, gravity_value_t value) {
  1200. #pragma unused(vm, xdata, target, key, value)
  1201. RETURN_NOVALUE();
  1202. }
  1203. bool bridge_getundef (gravity_vm *vm, void *xdata, gravity_value_t target, const char *key, uint32_t rindex) {
  1204. #pragma unused(vm, xdata, target, key, rindex)
  1205. RETURN_NOVALUE();
  1206. }
  1207. bool bridge_execute (gravity_vm *vm, void *data, gravity_value_t ctx, gravity_value_t args[], int16_t nargs, uint32_t rindex) {
  1208. gravity_value_t target = args[0];
  1209. objc_bridge_func_t *xdata = (objc_bridge_func_t *)data;
  1210. id callee = (__bridge id)gravity_value_xdata(target);
  1211. NSMutableArray *arguments = [NSMutableArray arrayWithCapacity:nargs];
  1212. // internal debug var
  1213. // struct objc_bridge_func_s *ddata = (struct objc_bridge_func_s *)data;
  1214. if (!callee || !xdata) {
  1215. // not an instance nor a class... so a runtime error I guess
  1216. RETURN_ERROR("Unable to process bridge request because target is not an instance nor a class.");
  1217. }
  1218. NSInvocation *invocation = (xdata->invocation) ? (__bridge NSInvocation *)(xdata->invocation) : nil;
  1219. if (!invocation) {
  1220. NSMethodSignature *signature = [callee methodSignatureForSelector:xdata->selector];
  1221. if (!signature) {
  1222. const char *name = objc_bridge_get_exposed_name(xdata);
  1223. const char *s = NSStringFromSelector(xdata->selector).UTF8String;
  1224. RETURN_ERROR("Unable to process bridge request because signature for method %s (selector %s) cannot be build.", name, s);
  1225. }
  1226. xdata->retlength = [signature methodReturnLength];
  1227. invocation = [NSInvocation invocationWithMethodSignature:signature];
  1228. [invocation setSelector:xdata->selector]; // hidden _cmd parameter
  1229. xdata->invocation = (void *)CFBridgingRetain(invocation); // cache invocation
  1230. if (xdata->rettype > OBJC_BRIDGE_TYPE_USER) xdata->rettype = OBJC_BRIDGE_TYPE_USER;
  1231. }
  1232. if (!invocation) {
  1233. RETURN_ERROR("Unable to process bridge request because invocation cannot be build.");
  1234. }
  1235. // nargs is at least ALWAYS 1 because of the implicit target argument
  1236. // last check added for default values
  1237. if ((nargs>1) && (nargs-1 < xdata->nargs) && (!xdata->argvalue)) {
  1238. const char *name = objc_bridge_get_exposed_name(xdata);
  1239. RETURN_ERROR("Unable to call %s because of missing parameters (passed %d, required %d)", name, nargs-1, xdata->nargs);
  1240. }
  1241. #if ENABLE_RUNTIME_CONTEXT
  1242. if ([callee respondsToSelector:@selector(runtimeInstance)]) {
  1243. CREORuntimeInstance *runtimeInstance = [callee runtimeInstance];
  1244. if (VALUE_ISA_INSTANCE(ctx)) runtimeInstance.context = (void *)VALUE_AS_INSTANCE(ctx);
  1245. else if (VALUE_ISA_CLASS(ctx)) runtimeInstance.context = (void *)VALUE_AS_CLASS(ctx);
  1246. else runtimeInstance.context = NULL;
  1247. }
  1248. #endif
  1249. // setup parameters (i starts from 2 due to implicit arguments)
  1250. for (uint16_t i=0, j=1, k=2; i<xdata->nargs; ++i, ++j, ++k) {
  1251. gravity_value_t gravity_value = (j<nargs) ? args[j] : VALUE_FROM_NULL;
  1252. BOOL is_default_value = NO;
  1253. // check for special default value case
  1254. if (((j>=nargs) || VALUE_ISA_UNDEFINED(gravity_value)) && xdata->argvalue) {
  1255. // sanity check
  1256. if (!xdata->argvalue[i]) {
  1257. const char *name = objc_bridge_get_exposed_name(xdata);
  1258. RETURN_ERROR("Unable to call %s because of missing parameters (passed %d, required %d)", name, nargs-1, xdata->nargs);
  1259. }
  1260. // unbox default value
  1261. if ((__bridge id)xdata->argvalue[i] == (id)[NSNull null]) gravity_value = VALUE_FROM_NULL;
  1262. else gravity_value = bridge_objc2gravity_retain_flag(vm, (__bridge id)xdata->argvalue[i], xdata->argtype[i], YES);
  1263. is_default_value = YES;
  1264. }
  1265. // convert argument
  1266. switch (xdata->argtype[i]) {
  1267. case OBJC_BRIDGE_TYPE_INIT:
  1268. case OBJC_BRIDGE_TYPE_UNKNOWN:
  1269. case OBJC_BRIDGE_TYPE_CPTR:
  1270. case OBJC_BRIDGE_TYPE_CLASS:
  1271. case OBJC_BRIDGE_TYPE_SEL:
  1272. case OBJC_BRIDGE_TYPE_VOID:
  1273. case OBJC_BRIDGE_TYPE_LDOUBLE:
  1274. assert(0);
  1275. case OBJC_BRIDGE_TYPE_CLOSURE: {
  1276. // extra check for argumennt to be a real closure
  1277. gravity_closure_t *closure;
  1278. if (VALUE_ISA_NULL(gravity_value)) closure = NULL;
  1279. else if (VALUE_ISA_CLOSURE(gravity_value)) closure = VALUE_AS_CLOSURE(gravity_value);
  1280. else RETURN_ERROR("Unable to convert parameter %d to Closure (in %s).", k-1, objc_bridge_get_exposed_name(xdata));
  1281. [invocation setArgument:&closure atIndex:k];
  1282. } break;
  1283. case OBJC_BRIDGE_TYPE_GRAVITY:
  1284. case OBJC_BRIDGE_TYPE_VPTR: {
  1285. // this case is used when an unknown number of arguments can be passed to an event
  1286. void *ptr;
  1287. if (gravity_value_isobject(gravity_value)) ptr = VALUE_AS_OBJECT(gravity_value);
  1288. else ptr = NULL;
  1289. [invocation setArgument:&ptr atIndex:k];
  1290. } break;
  1291. case OBJC_BRIDGE_TYPE_INT8: {
  1292. gravity_value_t v = convert_value2int(vm, gravity_value);
  1293. if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata));
  1294. char value = (char)v.n;
  1295. [invocation setArgument:&value atIndex:k];
  1296. } break;
  1297. case OBJC_BRIDGE_TYPE_INT16: {
  1298. gravity_value_t v = convert_value2int(vm, gravity_value);
  1299. if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata));
  1300. short value = (short)v.n;
  1301. [invocation setArgument:&value atIndex:k];
  1302. } break;
  1303. case OBJC_BRIDGE_TYPE_INT32: {
  1304. gravity_value_t v = convert_value2int(vm, gravity_value);
  1305. if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata));
  1306. long value = (long)v.n;
  1307. [invocation setArgument:&value atIndex:k];
  1308. } break;
  1309. case OBJC_BRIDGE_TYPE_INT64: {
  1310. gravity_value_t v = convert_value2int(vm, gravity_value);
  1311. if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata));
  1312. long long value = (long long)v.n;
  1313. [invocation setArgument:&value atIndex:k];
  1314. } break;
  1315. case OBJC_BRIDGE_TYPE_UINT8: {
  1316. gravity_value_t v = convert_value2int(vm, gravity_value);
  1317. if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata));
  1318. unsigned char value = (unsigned char)v.n;
  1319. [invocation setArgument:&value atIndex:k];
  1320. } break;
  1321. case OBJC_BRIDGE_TYPE_UINT16: {
  1322. gravity_value_t v = convert_value2int(vm, gravity_value);
  1323. if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata));
  1324. unsigned short value = (unsigned short)v.n;
  1325. [invocation setArgument:&value atIndex:k];
  1326. } break;
  1327. case OBJC_BRIDGE_TYPE_UINT32: {
  1328. gravity_value_t v = convert_value2int(vm, gravity_value);
  1329. if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata));
  1330. unsigned long value = (unsigned long)v.n;
  1331. [invocation setArgument:&value atIndex:k];
  1332. } break;
  1333. case OBJC_BRIDGE_TYPE_UINT64: {
  1334. gravity_value_t v = convert_value2int(vm, gravity_value);
  1335. if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata));
  1336. unsigned long long value = (unsigned long long)v.n;
  1337. [invocation setArgument:&value atIndex:k];
  1338. } break;
  1339. case OBJC_BRIDGE_TYPE_FLOAT: {
  1340. gravity_value_t v = convert_value2float(vm, gravity_value);
  1341. if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Float (in %s).", k-1, objc_bridge_get_exposed_name(xdata));
  1342. float value = (float)v.f;
  1343. [invocation setArgument:&value atIndex:k];
  1344. } break;
  1345. case OBJC_BRIDGE_TYPE_DOUBLE: {
  1346. gravity_value_t v = convert_value2float(vm, gravity_value);
  1347. if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Float (in %s).", k-1, objc_bridge_get_exposed_name(xdata));
  1348. double value = (double)v.f;
  1349. [invocation setArgument:&value atIndex:k];
  1350. } break;
  1351. case OBJC_BRIDGE_TYPE_BOOL: {
  1352. gravity_value_t v = convert_value2bool(vm, gravity_value);
  1353. if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Bool (in %s).", k-1, objc_bridge_get_exposed_name(xdata));
  1354. bool value = (bool)v.n;
  1355. [invocation setArgument:&value atIndex:k];
  1356. } break;
  1357. case OBJC_BRIDGE_TYPE_NSINTEGER: {
  1358. gravity_value_t v = convert_value2int(vm, gravity_value);
  1359. if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata));
  1360. NSInteger value = (NSInteger)v.n;
  1361. [invocation setArgument:&value atIndex:k];
  1362. } break;
  1363. case OBJC_BRIDGE_TYPE_NSUINTEGER: {
  1364. gravity_value_t v = convert_value2int(vm, gravity_value);
  1365. if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata));
  1366. NSUInteger value = (NSUInteger)v.n;
  1367. [invocation setArgument:&value atIndex:k];
  1368. } break;
  1369. case OBJC_BRIDGE_TYPE_ID: {
  1370. id value = nil;
  1371. if (VALUE_ISA_INSTANCE(gravity_value)) value = (__bridge id)(VALUE_AS_INSTANCE(gravity_value)->xdata);
  1372. else if (VALUE_ISA_LIST(gravity_value)) value = convert_gravity2nsarray(vm, gravity_value);
  1373. else if (VALUE_ISA_MAP(gravity_value)) value = convert_gravity2nsdictionary(vm, gravity_value);
  1374. else value = convert_gravity2obj(vm, gravity_value, OBJC_BRIDGE_TYPE_ID);
  1375. if (value) [arguments addObject:value];
  1376. [invocation setArgument:&value atIndex:k];
  1377. } break;
  1378. case OBJC_BRIDGE_TYPE_NSNUMBER: {
  1379. NSNumber *value = nil;
  1380. if (VALUE_ISA_INT(gravity_value)) value = @(gravity_value.n);
  1381. else if (VALUE_ISA_FLOAT(gravity_value)) value = @(gravity_value.f);
  1382. else {
  1383. gravity_value_t v = convert_value2int(vm, gravity_value);
  1384. if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to Int (in %s).", k-1, objc_bridge_get_exposed_name(xdata));
  1385. value = @(v.n);
  1386. }
  1387. [arguments addObject:value];
  1388. [invocation setArgument:&value atIndex:k];
  1389. } break;
  1390. case OBJC_BRIDGE_TYPE_NSSTRING: {
  1391. if (VALUE_ISA_NULL(gravity_value) && is_default_value) {
  1392. id value = nil;
  1393. [invocation setArgument:&value atIndex:k];
  1394. } else {
  1395. gravity_value_t v = convert_value2string(vm, gravity_value);
  1396. if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert parameter %d to String (in %s).", k-1, objc_bridge_get_exposed_name(xdata));
  1397. NSString *value = [NSString stringWithUTF8String:VALUE_AS_CSTRING(v)];
  1398. [arguments addObject:value];
  1399. [invocation setArgument:&value atIndex:k];
  1400. }
  1401. } break;
  1402. case OBJC_BRIDGE_TYPE_NSARRAY: {
  1403. id value = convert_gravity2nsarray(vm, gravity_value);
  1404. if (value) [arguments addObject:value];
  1405. [invocation setArgument:&value atIndex:k];
  1406. } break;
  1407. case OBJC_BRIDGE_TYPE_NSDICTIONARY: {
  1408. id value = convert_gravity2nsdictionary(vm, gravity_value);
  1409. if (value) [arguments addObject:value];
  1410. [invocation setArgument:&value atIndex:k];
  1411. } break;
  1412. // STRUCT BASED ARGUMENTS
  1413. case OBJC_BRIDGE_TYPE_POINT: {
  1414. // guarantee to return a non null NSValue
  1415. NSValue *value = (NSValue *)convert_gravity2type(vm, gravity_value, xdata->argtype[i]);
  1416. CGPoint point = value.pointValue;
  1417. [invocation setArgument:&point atIndex:k];
  1418. } break;
  1419. case OBJC_BRIDGE_TYPE_RECT: {
  1420. // guarantee to return a non null NSValue
  1421. NSValue *value = (NSValue *)convert_gravity2type(vm, gravity_value, xdata->argtype[i]);
  1422. CGRect rect = value.rectValue;
  1423. [invocation setArgument:&rect atIndex:k];
  1424. } break;
  1425. case OBJC_BRIDGE_TYPE_SIZE: {
  1426. // guarantee to return a non null NSValue
  1427. NSValue *value = (NSValue *)convert_gravity2type(vm, gravity_value, xdata->argtype[i]);
  1428. CGSize size = value.sizeValue;
  1429. [invocation setArgument:&size atIndex:k];
  1430. } break;
  1431. case OBJC_BRIDGE_TYPE_EDGEINSETS: {
  1432. #if TARGET_OS_IPHONE
  1433. // guarantee to return a non null NSValue
  1434. NSValue *value = (NSValue *)convert_gravity2type(vm, gravity_value, xdata->argtype[i]);
  1435. UIEdgeInsets insets = value.edgeInsetsValue;
  1436. [invocation setArgument:&insets atIndex:k];
  1437. #endif
  1438. } break;
  1439. case OBJC_BRIDGE_TYPE_OFFSET: {
  1440. #if TARGET_OS_IPHONE
  1441. // guarantee to return a non null NSValue
  1442. NSValue *value = (NSValue *)convert_gravity2type(vm, gravity_value, xdata->argtype[i]);
  1443. UIOffset offset = value.offsetValue;
  1444. [invocation setArgument:&offset atIndex:k];
  1445. #endif
  1446. } break;
  1447. case OBJC_BRIDGE_TYPE_RANGE: {
  1448. NSRange r = convert_gravity2nsrange (vm, gravity_value);
  1449. [invocation setArgument:&r atIndex:k];
  1450. } break;
  1451. // OBJ BASED ARGUMENTS
  1452. case OBJC_BRIDGE_TYPE_NSDATE:
  1453. case OBJC_BRIDGE_TYPE_NSDATA:
  1454. case OBJC_BRIDGE_TYPE_IMAGE:
  1455. case OBJC_BRIDGE_TYPE_COLOR:
  1456. case OBJC_BRIDGE_TYPE_GRADIENT:
  1457. case OBJC_BRIDGE_TYPE_SOUND:
  1458. case OBJC_BRIDGE_TYPE_MOVIE:
  1459. case OBJC_BRIDGE_TYPE_FONT: {
  1460. id value = convert_gravity2type(vm, gravity_value, xdata->argtype[i]);
  1461. if (value) [arguments addObject:value];
  1462. [invocation setArgument:&value atIndex:k];
  1463. } break;
  1464. case OBJC_BRIDGE_TYPE_USER:
  1465. default: {
  1466. #ifdef CREO_PROJECT
  1467. id<CREORuntimeDelegate> delegate = (__bridge id<CREORuntimeDelegate>)(gravity_vm_getdata(vm));
  1468. if (!delegate) RETURN_ERROR("Delegate not set.");
  1469. Class c = [delegate classByTag:xdata->argtype[i]];
  1470. if (!c) RETURN_ERROR("Unable to find class name for class tag %d", xdata->argtype[i]);
  1471. if (!VALUE_ISA_INSTANCE(gravity_value)) {
  1472. gravity_value_t v = convert_value2string(vm, gravity_value);
  1473. const char *cname = NSStringFromClass(c).UTF8String;
  1474. const char *vstring = (VALUE_ISA_STRING(v)) ? VALUE_AS_CSTRING(v) : "N/A";
  1475. RETURN_ERROR("Unable to convert parameter %s to %s in %s.", vstring, cname, xdata->name);
  1476. }
  1477. gravity_instance_t *instance = VALUE_AS_INSTANCE(gravity_value);
  1478. id value = (instance) ? (__bridge id)(instance->xdata) : nil;
  1479. if (![value isKindOfClass:c]) {
  1480. RETURN_ERROR("Wrong parameter (position %d of %s).", k-1, objc_bridge_get_exposed_name(xdata));
  1481. }
  1482. [arguments addObject:value];
  1483. [invocation setArgument:&value atIndex:k];
  1484. #else
  1485. assert(0);
  1486. #endif
  1487. } break;
  1488. }
  1489. }
  1490. // invoke function
  1491. @try {
  1492. [invocation invokeWithTarget:callee];
  1493. }
  1494. @catch (NSException * e) {
  1495. gravity_vm_seterror(vm, "An error occurred while calling %s (%s).", objc_bridge_get_exposed_name(xdata), [[e reason] UTF8String]);
  1496. return false;
  1497. }
  1498. // process return value
  1499. switch (xdata->rettype) {
  1500. case OBJC_BRIDGE_TYPE_UNKNOWN:
  1501. case OBJC_BRIDGE_TYPE_LDOUBLE:
  1502. assert(0);
  1503. case OBJC_BRIDGE_TYPE_VOID: {
  1504. gravity_vm_setslot(vm, VALUE_FROM_NULL, rindex);
  1505. break;
  1506. }
  1507. case OBJC_BRIDGE_TYPE_BOOL: {
  1508. char buffer[2] = {0};
  1509. [invocation getReturnValue:&buffer];
  1510. gravity_vm_setslot(vm, (buffer[0] == 0) ? VALUE_FROM_FALSE : VALUE_FROM_TRUE, rindex);
  1511. break;
  1512. }
  1513. case OBJC_BRIDGE_TYPE_INT16: {
  1514. short buffer = 0;
  1515. [invocation getReturnValue:&buffer];
  1516. gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex);
  1517. break;
  1518. }
  1519. case OBJC_BRIDGE_TYPE_INT32: {
  1520. long buffer = 0;
  1521. [invocation getReturnValue:&buffer];
  1522. gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex);
  1523. break;
  1524. }
  1525. case OBJC_BRIDGE_TYPE_INT64: {
  1526. long long buffer = 0;
  1527. [invocation getReturnValue:&buffer];
  1528. gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex);
  1529. break;
  1530. }
  1531. case OBJC_BRIDGE_TYPE_UINT8: {
  1532. unsigned char buffer = 0;
  1533. [invocation getReturnValue:&buffer];
  1534. gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex);
  1535. break;
  1536. }
  1537. case OBJC_BRIDGE_TYPE_UINT16: {
  1538. unsigned short buffer = 0;
  1539. [invocation getReturnValue:&buffer];
  1540. gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex);
  1541. break;
  1542. }
  1543. case OBJC_BRIDGE_TYPE_UINT32: {
  1544. unsigned long buffer = 0;
  1545. [invocation getReturnValue:&buffer];
  1546. gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex);
  1547. break;
  1548. }
  1549. case OBJC_BRIDGE_TYPE_UINT64: {
  1550. unsigned long long buffer = 0;
  1551. [invocation getReturnValue:&buffer];
  1552. gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex);
  1553. break;
  1554. }
  1555. case OBJC_BRIDGE_TYPE_NSINTEGER: {
  1556. NSInteger buffer = 0;
  1557. [invocation getReturnValue:&buffer];
  1558. gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex);
  1559. break;
  1560. }
  1561. case OBJC_BRIDGE_TYPE_NSUINTEGER: {
  1562. NSUInteger buffer = 0;
  1563. [invocation getReturnValue:&buffer];
  1564. gravity_vm_setslot(vm, VALUE_FROM_INT(buffer), rindex);
  1565. break;
  1566. }
  1567. case OBJC_BRIDGE_TYPE_FLOAT: {
  1568. float buffer = 0.0;
  1569. [invocation getReturnValue:&buffer];
  1570. gravity_vm_setslot(vm, VALUE_FROM_FLOAT(buffer), rindex);
  1571. break;
  1572. }
  1573. case OBJC_BRIDGE_TYPE_DOUBLE: {
  1574. double buffer = 0.0;
  1575. [invocation getReturnValue:&buffer];
  1576. gravity_vm_setslot(vm, VALUE_FROM_FLOAT(buffer), rindex);
  1577. break;
  1578. }
  1579. case OBJC_BRIDGE_TYPE_VPTR:
  1580. case OBJC_BRIDGE_TYPE_CPTR: {
  1581. void *buffer = NULL;
  1582. [invocation getReturnValue:&buffer];
  1583. assert(0);
  1584. }
  1585. case OBJC_BRIDGE_TYPE_INIT: {
  1586. assert(rindex == GRAVITY_DATA_REGISTER);
  1587. id obj = nil;
  1588. [invocation getReturnValue:&obj];
  1589. gravity_vm_setdata(vm, (void *)CFBridgingRetain(obj));
  1590. break;
  1591. }
  1592. case OBJC_BRIDGE_TYPE_NSNUMBER:
  1593. case OBJC_BRIDGE_TYPE_NSSTRING:
  1594. case OBJC_BRIDGE_TYPE_NSARRAY:
  1595. case OBJC_BRIDGE_TYPE_NSDICTIONARY:
  1596. case OBJC_BRIDGE_TYPE_NSDATE:
  1597. case OBJC_BRIDGE_TYPE_NSDATA:
  1598. case OBJC_BRIDGE_TYPE_ID:
  1599. case OBJC_BRIDGE_TYPE_USER:
  1600. case OBJC_BRIDGE_TYPE_GRAVITY:
  1601. case OBJC_BRIDGE_TYPE_COLOR:
  1602. case OBJC_BRIDGE_TYPE_SOUND:
  1603. case OBJC_BRIDGE_TYPE_IMAGE:
  1604. case OBJC_BRIDGE_TYPE_GRADIENT:
  1605. case OBJC_BRIDGE_TYPE_FONT: {
  1606. // https://stackoverflow.com/questions/11874056/nsinvocation-getreturnvalue-called-inside-forwardinvocation-makes-the-returned
  1607. __unsafe_unretained id obj = nil;
  1608. [invocation getReturnValue:&obj];
  1609. gravity_vm_setslot(vm, bridge_objc2gravity(vm, obj, xdata->rettype), rindex);
  1610. break;
  1611. }
  1612. case OBJC_BRIDGE_TYPE_POINT: {
  1613. CGPoint v;
  1614. [invocation getReturnValue:&v];
  1615. gravity_vm_setslot(vm, bridge_objc2gravity(vm, @(v), xdata->rettype), rindex);
  1616. break;
  1617. }
  1618. case OBJC_BRIDGE_TYPE_SIZE: {
  1619. CGSize v;
  1620. [invocation getReturnValue:&v];
  1621. gravity_vm_setslot(vm, bridge_objc2gravity(vm, @(v), xdata->rettype), rindex);
  1622. break;
  1623. }
  1624. case OBJC_BRIDGE_TYPE_RECT: {
  1625. CGRect v;
  1626. [invocation getReturnValue:&v];
  1627. gravity_vm_setslot(vm, bridge_objc2gravity(vm, @(v), xdata->rettype), rindex);
  1628. break;
  1629. }
  1630. case OBJC_BRIDGE_TYPE_EDGEINSETS: {
  1631. #if TARGET_OS_IPHONE
  1632. UIEdgeInsets v;
  1633. [invocation getReturnValue:&v];
  1634. gravity_vm_setslot(vm, bridge_objc2gravity(vm, [NSValue valueWithUIEdgeInsets:v], xdata->rettype), rindex);
  1635. #endif
  1636. break;
  1637. }
  1638. case OBJC_BRIDGE_TYPE_OFFSET: {
  1639. #if TARGET_OS_IPHONE
  1640. UIOffset v;
  1641. [invocation getReturnValue:&v];
  1642. gravity_vm_setslot(vm, bridge_objc2gravity(vm, [NSValue valueWithUIOffset:v], xdata->rettype), rindex);
  1643. #endif
  1644. break;
  1645. }
  1646. case OBJC_BRIDGE_TYPE_RANGE: {
  1647. NSRange v;
  1648. [invocation getReturnValue:&v];
  1649. gravity_vm_setslot(vm, bridge_objc2gravity(vm, [NSValue valueWithRange:v], xdata->rettype), rindex);
  1650. break;
  1651. }
  1652. default:
  1653. /*
  1654. OBJC_BRIDGE_TYPE_CLASS
  1655. OBJC_BRIDGE_TYPE_SEL
  1656. OBJC_BRIDGE_TYPE_MOVIE
  1657. */
  1658. // default is to ignore return values and not to assert
  1659. NSLog(@"Unhandled bridge_execute return value case");
  1660. gravity_vm_setslot(vm, VALUE_FROM_NULL, rindex);
  1661. break;
  1662. }
  1663. return true;
  1664. }
  1665. const char *bridge_string (gravity_vm *vm, void *xdata, uint32_t *len) {
  1666. #pragma unused(vm)
  1667. // assuming xdata is an objc object
  1668. NSObject *obj = (__bridge NSObject *)(xdata);
  1669. if ([obj respondsToSelector:@selector(description)]) {
  1670. NSString *description = [obj performSelector:@selector(description)];
  1671. *len = (uint32_t)[description lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
  1672. return description.UTF8String;
  1673. }
  1674. return NULL;
  1675. }
  1676. void bridge_blacken (gravity_vm *vm, void *xdata) {
  1677. // NSObject *obj = (__bridge NSObject *)(xdata);
  1678. // if ([obj respondsToSelector:@selector(runtimeInstance)]) {
  1679. // id r = [obj valueForKey:@"runtimeInstance"];
  1680. // if (!r) return;
  1681. // } else return;
  1682. //
  1683. ///*
  1684. // if ([obj respondsToSelector:@selector(gravityInstance)]) {
  1685. // gravity_instance_t *instance = (__bridge gravity_instance_t *)[obj valueForKey:@"gravityInstance"];
  1686. // if (instance) gravity_instance_blacken(vm, instance);
  1687. // }
  1688. // */
  1689. //
  1690. // #pragma clang diagnostic push
  1691. // #pragma clang diagnostic ignored "-Wundeclared-selector"
  1692. // if ([obj respondsToSelector:@selector(gravityBlacken)]) {
  1693. // [obj performSelector:@selector(gravityBlacken)];
  1694. // }
  1695. // #pragma clang diagnostic pop
  1696. }
  1697. bool bridge_equals (gravity_vm *vm, void *obj_1, void *obj_2) {
  1698. #pragma unused(vm)
  1699. // assuming both obj1 and obj2 are objc objects
  1700. NSObject *obj1 = (__bridge NSObject *)(obj_1);
  1701. NSObject *obj2 = (__bridge NSObject *)(obj_2);
  1702. if ([obj1 respondsToSelector:@selector(isEqual:)]) {
  1703. return [obj1 isEqual:obj2];
  1704. }
  1705. return false;
  1706. }
  1707. void *bridge_clone (gravity_vm *vm, void *xdata) {
  1708. if (!xdata) return NULL;
  1709. NSObject *clone = nil;
  1710. #ifdef CREO_PROJECT
  1711. NSObject *obj = (__bridge NSObject *)(xdata);
  1712. MKObjectID objectID = [obj objectID];
  1713. gravity_delegate_t *delegate = gravity_vm_delegate(vm);
  1714. CREOApplication *app = (__bridge CREOApplication *)delegate->xdata;
  1715. if (objectID != MKNotFound) {
  1716. clone = [app createObjectWithID:objectID container:nil error:nil useCache:NO];
  1717. } else {
  1718. clone = [app createObjectWithClass:obj.class];
  1719. if ([obj respondsToSelector:@selector(value)]) {
  1720. [clone setValue:[obj valueForKey:@"value"] forKey:@"value"];
  1721. }
  1722. }
  1723. // WE CURRENTLY DO NOT SUPPORT PROPERTY SET VIA CODE (ONLY INSPECTOR PROPERTIES ARE SUPPORTED)
  1724. // if (clone) {
  1725. // unsigned int outCount, i;
  1726. // objc_property_t *properties = class_copyPropertyList([obj class], &outCount);
  1727. // for (i = 0; i < outCount; i++) {
  1728. // objc_property_t property = properties[i];
  1729. // const char *propName = property_getName(property);
  1730. // if (propName) {
  1731. // NSString *key = @(propName);
  1732. // id value = [obj valueForKey:key];
  1733. // [clone setValue:value forKey:key];
  1734. // // NSLog(@"%@ %@", key, value);
  1735. // }
  1736. // }
  1737. // free(properties);
  1738. // }
  1739. #endif
  1740. return (clone) ? (void *)CFBridgingRetain(clone) : NULL;
  1741. }
  1742. // MARK: - Free -
  1743. static void bridge_free_instance (gravity_vm *vm, gravity_instance_t *i) {
  1744. #pragma unused(vm)
  1745. DEBUG_XDATA(@"\tBRIDGE FREE INSTANCE %@", i->xdata);
  1746. #if GRAVITY_BRIDGE_DEBUG_MEMORY
  1747. NSLog(@"Free instance %p (%@)", i->xdata, NSStringFromClass([(__bridge id)i->xdata class]));
  1748. #endif
  1749. if (!i->xdata) return;
  1750. #ifdef CREO_PROJECT
  1751. set_runtime_instance(vm, (__bridge id)(i->xdata), nil);
  1752. NSObject *obj = (__bridge NSObject *)(i->xdata);
  1753. if ([obj respondsToSelector:@selector(removeFromSuperview)]) [(UIView*)obj removeFromSuperview];
  1754. #endif
  1755. FREE_OBJC_VALUE(i->xdata);
  1756. }
  1757. static void bridge_free_closure (gravity_vm *vm, gravity_closure_t *closure, bool is_property) {
  1758. DEBUG_XDATA(@"\tBRIDGE FREE CLOSURE %p", closure->f);
  1759. #pragma unused(vm)
  1760. if (closure->f->tag == EXEC_TYPE_SPECIAL) {
  1761. assert(closure->f->index == GRAVITY_BRIDGE_INDEX);
  1762. if (closure->f->xdata) objc_bridge_var_free((objc_bridge_var_t *)closure->f->xdata);
  1763. closure->f->xdata = NULL;
  1764. gravity_closure_t *getter = (gravity_closure_t *)closure->f->special[0];
  1765. gravity_closure_t *setter = (closure->f->special[0] != closure->f->special[1]) ? (gravity_closure_t *)closure->f->special[1] : NULL;
  1766. if (getter) bridge_free_closure(vm, getter, true);
  1767. if (setter) bridge_free_closure(vm, setter, true);
  1768. }
  1769. if (closure->f->tag == EXEC_TYPE_BRIDGED) {
  1770. if (is_property) {
  1771. objc_bridge_var_free((objc_bridge_var_t *)closure->f->xdata);
  1772. } else {
  1773. objc_bridge_func_free((objc_bridge_func_t *)closure->f->xdata);
  1774. }
  1775. closure->f->xdata = NULL;
  1776. }
  1777. if (closure->f->xdata) {
  1778. objc_bridge_var_free((objc_bridge_var_t *)closure->f->xdata);
  1779. }
  1780. gravity_function_t *f = closure->f;
  1781. gravity_closure_free(NULL, closure);
  1782. gravity_function_free(NULL, f);
  1783. }
  1784. static void bridge_hash_iterate (gravity_hash_t *hashtable, gravity_value_t key, gravity_value_t value, void *data) {
  1785. #pragma unused(hashtable, key)
  1786. if (gravity_value_isobject(value)) {
  1787. bridge_free((gravity_vm*)data, VALUE_AS_OBJECT(value));
  1788. }
  1789. }
  1790. static void bridge_free_class (gravity_vm *vm, gravity_class_t *c) {
  1791. if (!c->xdata) return;
  1792. DEBUG_XDATA(@"BRIDGE FREE CLASS %s %p", c->identifier, c);
  1793. // free meta class first
  1794. gravity_class_t *meta = gravity_class_get_meta(c);
  1795. gravity_hash_iterate(meta->htable, bridge_hash_iterate, (void *)vm);
  1796. // then free real class
  1797. gravity_hash_iterate(c->htable, bridge_hash_iterate, (void *)vm);
  1798. FREE_OBJC_VALUE(c->xdata);
  1799. }
  1800. void bridge_free (gravity_vm *vm, gravity_object_t *obj) {
  1801. if (OBJECT_ISA_INSTANCE(obj)) {
  1802. bridge_free_instance(vm, (gravity_instance_t *)obj);
  1803. } else if (OBJECT_ISA_CLOSURE(obj)) {
  1804. bridge_free_closure(vm, (gravity_closure_t *)obj, false);
  1805. } else if (OBJECT_ISA_CLASS(obj)) {
  1806. bridge_free_class(vm, (gravity_class_t *)obj);
  1807. } else {
  1808. // should never reach this point
  1809. assert(0);
  1810. }
  1811. }