]> git.saurik.com Git - cycript.git/blame - ObjectiveC/Library.mm
Split $objc_msgSend apart, normalizing exceptions.
[cycript.git] / ObjectiveC / Library.mm
CommitLineData
b3378a02 1/* Cycript - Optimizing JavaScript Compiler/Runtime
c15969fd 2 * Copyright (C) 2009-2013 Jay Freeman (saurik)
e91fbe93
JF
3*/
4
c15969fd 5/* GNU General Public License, Version 3 {{{ */
e91fbe93 6/*
c15969fd
JF
7 * Cycript is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation, either version 3 of the License,
10 * or (at your option) any later version.
e91fbe93 11 *
c15969fd
JF
12 * Cycript is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
e91fbe93 16 *
c15969fd 17 * You should have received a copy of the GNU General Public License
b3378a02
JF
18 * along with Cycript. If not, see <http://www.gnu.org/licenses/>.
19**/
e91fbe93
JF
20/* }}} */
21
37954781 22#include <Foundation/Foundation.h>
3c1c3635 23
2fd4c9a9
JF
24#include "ObjectiveC/Internal.hpp"
25
8ad1528b 26#include <objc/objc-api.h>
aabea98c 27
37954781 28#include "cycript.hpp"
3c1c3635 29
37954781 30#include "ObjectiveC/Internal.hpp"
3c1c3635 31
37954781
JF
32#ifdef __APPLE__
33#include <CoreFoundation/CoreFoundation.h>
37954781 34#include <JavaScriptCore/JSStringRefCF.h>
0939f869 35#include <objc/runtime.h>
37954781 36#endif
3c1c3635 37
37954781
JF
38#include "Error.hpp"
39#include "JavaScript.hpp"
40#include "String.hpp"
0f3a21d5 41#include "Execute.hpp"
3c1c3635 42
aabea98c 43#include <cmath>
37954781 44#include <map>
30c4d7e0 45#include <set>
3c1c3635 46
c44063e0
JF
47#include <dlfcn.h>
48
f1b5a47f 49#define CYObjectiveTry_ { \
37954781
JF
50 try
51#define CYObjectiveTry { \
f1b5a47f 52 JSContextRef context(context_); \
37954781
JF
53 try
54#define CYObjectiveCatch \
55 catch (const CYException &error) { \
f1b5a47f 56 @throw CYCastNSObject(NULL, context, error.CastJSValue(context)); \
37954781 57 } \
3c1c3635
JF
58}
59
37954781
JF
60#define CYPoolTry { \
61 id _saved(nil); \
62 NSAutoreleasePool *_pool([[NSAutoreleasePool alloc] init]); \
63 @try
64#define CYPoolCatch(value) \
65 @catch (NSException *error) { \
66 _saved = [error retain]; \
67 throw CYJSError(context, CYCastJSValue(context, error)); \
68 return value; \
69 } @finally { \
70 [_pool release]; \
71 if (_saved != nil) \
72 [_saved autorelease]; \
73 } \
3c1c3635
JF
74}
75
b64ab4da
JF
76#define CYSadTry { \
77 @try
ea840434 78#define CYSadCatch(value) \
b64ab4da
JF
79 @catch (NSException *error ) { \
80 throw CYJSError(context, CYCastJSValue(context, error)); \
e0ddeff1 81 } return value; \
b64ab4da
JF
82}
83
37954781
JF
84#ifndef __APPLE__
85#define class_getSuperclass GSObjCSuper
aabea98c
JF
86#define class_getInstanceVariable GSCGetInstanceVariableDefinition
87#define class_getName GSNameFromClass
88
89#define class_removeMethods(cls, list) GSRemoveMethodList(cls, list, YES)
90
91#define ivar_getName(ivar) ((ivar)->ivar_name)
92#define ivar_getOffset(ivar) ((ivar)->ivar_offset)
93#define ivar_getTypeEncoding(ivar) ((ivar)->ivar_type)
94
95#define method_getName(method) ((method)->method_name)
96#define method_getImplementation(method) ((method)->method_imp)
97#define method_getTypeEncoding(method) ((method)->method_types)
98#define method_setImplementation(method, imp) ((void) ((method)->method_imp = (imp)))
99
ba4fa42f
JF
100#undef objc_getClass
101#define objc_getClass GSClassFromName
102
aabea98c
JF
103#define objc_getProtocol GSProtocolFromName
104
37954781 105#define object_getClass GSObjCClass
aabea98c
JF
106
107#define object_getInstanceVariable(object, name, value) ({ \
108 objc_ivar *ivar(class_getInstanceVariable(object_getClass(object), name)); \
9fe95800 109 _assert(value != NULL); \
ba4fa42f
JF
110 if (ivar != NULL) \
111 GSObjCGetVariable(object, ivar_getOffset(ivar), sizeof(void *), value); \
aabea98c
JF
112 ivar; \
113})
114
115#define object_setIvar(object, ivar, value) ({ \
116 void *data = (value); \
117 GSObjCSetVariable(object, ivar_getOffset(ivar), sizeof(void *), &data); \
118})
119
120#define protocol_getName(protocol) [(protocol) name]
37954781 121#endif
3c1c3635 122
c44063e0
JF
123static void (*$objc_setAssociatedObject)(id object, void *key, id value, objc_AssociationPolicy policy);
124static id (*$objc_getAssociatedObject)(id object, void *key);
125static void (*$objc_removeAssociatedObjects)(id object);
126
07ae2f7f
JF
127struct BlockLiteral {
128 Class isa;
129 int flags;
130 int reserved;
131 void (*invoke)(void *, ...);
132 void *descriptor;
133};
134
868ad7d8
JF
135struct BlockDescriptor1 {
136 unsigned long int reserved;
137 unsigned long int size;
138};
139
140struct BlockDescriptor2 {
07ae2f7f
JF
141 void (*copy_helper)(BlockLiteral *dst, BlockLiteral *src);
142 void (*dispose_helper)(BlockLiteral *src);
868ad7d8
JF
143};
144
145struct BlockDescriptor3 {
146 const char *signature;
147 const char *layout;
148};
149
868ad7d8
JF
150enum {
151 BLOCK_DEALLOCATING = 0x0001,
152 BLOCK_REFCOUNT_MASK = 0xfffe,
153 BLOCK_NEEDS_FREE = 1 << 24,
154 BLOCK_HAS_COPY_DISPOSE = 1 << 25,
155 BLOCK_HAS_CTOR = 1 << 26,
156 BLOCK_IS_GC = 1 << 27,
157 BLOCK_IS_GLOBAL = 1 << 28,
158 BLOCK_HAS_STRET = 1 << 29,
159 BLOCK_HAS_SIGNATURE = 1 << 30,
160};
161
9d512587 162JSValueRef CYSendMessage(CYPool &pool, JSContextRef context, id self, Class super, SEL _cmd, size_t count, const JSValueRef arguments[], bool initialize);
3c1c3635 163
3c1c3635 164/* Objective-C Pool Release {{{ */
1560b2c8 165void CYPoolRelease_(void *data) {
3c1c3635
JF
166 id object(reinterpret_cast<id>(data));
167 [object release];
3c1c3635
JF
168}
169
b799113b 170id CYPoolRelease_(CYPool *pool, id object) {
3c1c3635
JF
171 if (object == nil)
172 return nil;
173 else if (pool == NULL)
174 return [object autorelease];
175 else {
1560b2c8 176 pool->atexit(CYPoolRelease_);
3c1c3635
JF
177 return object;
178 }
179}
180
181template <typename Type_>
b799113b 182Type_ CYPoolRelease(CYPool *pool, Type_ object) {
3c1c3635
JF
183 return (Type_) CYPoolRelease_(pool, (id) object);
184}
185/* }}} */
186/* Objective-C Strings {{{ */
b799113b 187const char *CYPoolCString(CYPool &pool, JSContextRef context, NSString *value) {
0cbeddf8
JF
188 size_t size([value maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1);
189 char *string(new(pool) char[size]);
190 if (![value getCString:string maxLength:size encoding:NSUTF8StringEncoding])
191 throw CYJSError(context, "[NSString getCString:maxLength:encoding:] == NO");
192 return string;
3c1c3635
JF
193}
194
aabea98c 195JSStringRef CYCopyJSString(JSContextRef context, NSString *value) {
3c1c3635
JF
196#ifdef __APPLE__
197 return JSStringCreateWithCFString(reinterpret_cast<CFStringRef>(value));
198#else
199 CYPool pool;
aabea98c 200 return CYCopyJSString(CYPoolCString(pool, context, value));
3c1c3635
JF
201#endif
202}
203
8665da0c 204JSStringRef CYCopyJSString(JSContextRef context, NSObject *value) {
3c1c3635
JF
205 if (value == nil)
206 return NULL;
207 // XXX: this definition scares me; is anyone using this?!
208 NSString *string([value description]);
8665da0c 209 return CYCopyJSString(context, string);
3c1c3635
JF
210}
211
212NSString *CYCopyNSString(const CYUTF8String &value) {
213#ifdef __APPLE__
214 return (NSString *) CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(value.data), value.size, kCFStringEncodingUTF8, true);
215#else
216 return [[NSString alloc] initWithBytes:value.data length:value.size encoding:NSUTF8StringEncoding];
217#endif
218}
219
aabea98c 220NSString *CYCopyNSString(JSContextRef context, JSStringRef value) {
3c1c3635
JF
221#ifdef __APPLE__
222 return (NSString *) JSStringCopyCFString(kCFAllocatorDefault, value);
223#else
aabea98c
JF
224 CYPool pool;
225 return CYCopyNSString(CYPoolUTF8String(pool, context, value));
3c1c3635
JF
226#endif
227}
228
229NSString *CYCopyNSString(JSContextRef context, JSValueRef value) {
aabea98c 230 return CYCopyNSString(context, CYJSString(context, value));
3c1c3635
JF
231}
232
b799113b 233NSString *CYCastNSString(CYPool *pool, const CYUTF8String &value) {
3c1c3635
JF
234 return CYPoolRelease(pool, CYCopyNSString(value));
235}
236
b799113b 237NSString *CYCastNSString(CYPool *pool, SEL sel) {
3c1c3635
JF
238 const char *name(sel_getName(sel));
239 return CYPoolRelease(pool, CYCopyNSString(CYUTF8String(name, strlen(name))));
240}
241
b799113b 242NSString *CYCastNSString(CYPool *pool, JSContextRef context, JSStringRef value) {
aabea98c 243 return CYPoolRelease(pool, CYCopyNSString(context, value));
3c1c3635 244}
c239b9f8 245
3c1c3635
JF
246CYUTF8String CYCastUTF8String(NSString *value) {
247 NSData *data([value dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO]);
248 return CYUTF8String(reinterpret_cast<const char *>([data bytes]), [data length]);
249}
250/* }}} */
ff783f8c 251
ba4fa42f
JF
252JSValueRef CYCastJSValue(JSContextRef context, NSObject *value);
253
3c1c3635
JF
254void CYThrow(JSContextRef context, NSException *error, JSValueRef *exception) {
255 if (exception == NULL)
256 throw error;
257 *exception = CYCastJSValue(context, error);
258}
bce8339b 259
3c1c3635
JF
260size_t CYGetIndex(NSString *value) {
261 return CYGetIndex(CYCastUTF8String(value));
262}
ff783f8c 263
b799113b 264bool CYGetOffset(CYPool &pool, JSContextRef context, NSString *value, ssize_t &index) {
3c1c3635
JF
265 return CYGetOffset(CYPoolCString(pool, context, value), index);
266}
ff783f8c 267
3c1c3635 268static JSClassRef Instance_;
aaa3cd1e 269
1fb9f0d0 270static JSClassRef ArrayInstance_;
aaa3cd1e 271static JSClassRef FunctionInstance_;
1fb9f0d0
JF
272static JSClassRef ObjectInstance_;
273static JSClassRef StringInstance_;
274
b63701b2 275static JSClassRef Class_;
3c1c3635
JF
276static JSClassRef Internal_;
277static JSClassRef Message_;
278static JSClassRef Messages_;
279static JSClassRef Selector_;
280static JSClassRef Super_;
ff783f8c 281
3c1c3635 282static JSClassRef ObjectiveC_Classes_;
26ef7a82 283static JSClassRef ObjectiveC_Constants_;
aabea98c
JF
284static JSClassRef ObjectiveC_Protocols_;
285
286#ifdef __APPLE__
3c1c3635
JF
287static JSClassRef ObjectiveC_Image_Classes_;
288static JSClassRef ObjectiveC_Images_;
aabea98c 289#endif
ff783f8c 290
3c1c3635
JF
291#ifdef __APPLE__
292static Class NSCFBoolean_;
293static Class NSCFType_;
aaa4a269 294static Class NSGenericDeallocHandler_;
b5dd57dc 295static Class NSZombie_;
30c4d7e0
JF
296
297static std::set<Class> banned_;
c074e774
JF
298#else
299static Class NSBoolNumber_;
3c1c3635 300#endif
ff783f8c 301
3c1c3635 302static Class NSArray_;
aaa3cd1e 303static Class NSBlock_;
3c1c3635 304static Class NSDictionary_;
4cb8aa43 305static Class NSString_;
3c1c3635 306static Class Object_;
b24eb750 307
3c1c3635
JF
308static Type_privateData *Object_type;
309static Type_privateData *Selector_type;
7b184c00
JF
310
311Type_privateData *Instance::GetType() const {
3c1c3635 312 return Object_type;
7b184c00
JF
313}
314
315Type_privateData *Selector_privateData::GetType() const {
3c1c3635 316 return Selector_type;
7b184c00 317}
ff783f8c 318
4cb8aa43
JF
319static JSValueRef Instance_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception);
320
bc3080fd 321JSValueRef CYGetClassPrototype(JSContextRef context, Class self, bool meta) {
3c1c3635 322 if (self == nil)
498c3570 323 return CYGetCachedObject(context, CYJSString("Instance_prototype"));
bc3080fd 324 else if (meta && !class_isMetaClass(self))
b63701b2 325 return CYGetCachedObject(context, CYJSString("Class_prototype"));
bd17e6f3 326
b64ab4da
JF
327 JSObjectRef global(CYGetGlobalObject(context));
328 JSObjectRef cy(CYCastJSObject(context, CYGetProperty(context, global, cy_s)));
329
330 char label[32];
331 sprintf(label, "i%p", self);
332 CYJSString name(label);
bd17e6f3 333
b64ab4da
JF
334 JSValueRef value(CYGetProperty(context, cy, name));
335 if (!JSValueIsUndefined(context, value))
3c1c3635 336 return value;
bd17e6f3 337
3c1c3635
JF
338 JSClassRef _class(NULL);
339 JSValueRef prototype;
bd17e6f3 340
3c1c3635 341 if (self == NSArray_)
4a2eef6c 342 prototype = CYGetCachedObject(context, CYJSString("ArrayInstance_prototype"));
aaa3cd1e
JF
343 else if (self == NSBlock_)
344 prototype = CYGetCachedObject(context, CYJSString("FunctionInstance_prototype"));
3c1c3635 345 else if (self == NSDictionary_)
11f3e89e 346 prototype = CYGetCachedObject(context, CYJSString("ObjectInstance_prototype"));
6732f195
JF
347 else if (self == NSString_)
348 prototype = CYGetCachedObject(context, CYJSString("StringInstance_prototype"));
349 else
bc3080fd 350 prototype = CYGetClassPrototype(context, class_getSuperclass(self), meta);
bd17e6f3 351
6732f195 352 JSObjectRef object(JSObjectMake(context, _class, NULL));
3c1c3635 353 JSObjectSetPrototype(context, object, prototype);
b64ab4da 354 CYSetProperty(context, cy, name, object);
4cb8aa43 355
3c1c3635 356 return object;
bd17e6f3
JF
357}
358
bc3080fd
JF
359_finline JSValueRef CYGetClassPrototype(JSContextRef context, Class self) {
360 return CYGetClassPrototype(context, self, class_isMetaClass(self));
361}
362
8150077d 363JSObjectRef Messages::Make(JSContextRef context, Class _class) {
3c1c3635 364 JSObjectRef value(JSObjectMake(context, Messages_, new Messages(_class)));
3c1c3635 365 if (Class super = class_getSuperclass(_class))
8150077d 366 JSObjectSetPrototype(context, value, Messages::Make(context, super));
3c1c3635
JF
367 return value;
368}
dc68b74c 369
3c1c3635
JF
370JSObjectRef Internal::Make(JSContextRef context, id object, JSObjectRef owner) {
371 return JSObjectMake(context, Internal_, new Internal(object, context, owner));
372}
f33b048a 373
3c1c3635
JF
374namespace cy {
375JSObjectRef Super::Make(JSContextRef context, id object, Class _class) {
376 JSObjectRef value(JSObjectMake(context, Super_, new Super(object, _class)));
377 return value;
378} }
f33b048a 379
3c1c3635
JF
380JSObjectRef Instance::Make(JSContextRef context, id object, Flags flags) {
381 JSObjectRef value(JSObjectMake(context, Instance_, new Instance(object, flags)));
382 JSObjectSetPrototype(context, value, CYGetClassPrototype(context, object_getClass(object)));
383 return value;
384}
4e39dc0b 385
3c1c3635
JF
386Instance::~Instance() {
387 if ((flags_ & Transient) == 0)
388 // XXX: does this handle background threads correctly?
389 // XXX: this simply does not work on the console because I'm stupid
390 [GetValue() performSelector:@selector(release) withObject:nil afterDelay:0];
391}
f33b048a 392
dc68b74c 393struct Message_privateData :
37954781 394 cy::Functor
dc68b74c
JF
395{
396 SEL sel_;
397
398 Message_privateData(SEL sel, const char *type, IMP value = NULL) :
37954781 399 cy::Functor(type, reinterpret_cast<void (*)()>(value)),
dc68b74c
JF
400 sel_(sel)
401 {
402 }
403};
404
f7c38a29 405JSObjectRef CYMakeInstance(JSContextRef context, id object, bool transient) {
2b52f27e
JF
406 Instance::Flags flags;
407
408 if (transient)
409 flags = Instance::Transient;
410 else {
411 flags = Instance::None;
478d4ed0 412 object = [object retain];
2b52f27e
JF
413 }
414
415 return Instance::Make(context, object, flags);
478d4ed0 416}
0c862573 417
107e3ed0 418@interface NSMethodSignature (Cycript)
7ba62cfd
JF
419- (NSString *) _typeString;
420@end
421
107e3ed0 422@interface NSObject (Cycript)
b4aa79af 423
88c6482c 424- (JSValueRef) cy$valueOfInContext:(JSContextRef)context;
b4aa79af
JF
425- (JSType) cy$JSType;
426
e23a9070 427- (JSValueRef) cy$toJSON:(NSString *)key inContext:(JSContextRef)context;
dd18424c 428- (NSString *) cy$toCYON:(bool)objective;
b4aa79af 429
7b184c00 430- (bool) cy$hasProperty:(NSString *)name;
cc103044 431- (NSObject *) cy$getProperty:(NSString *)name;
6b9e29d2 432- (JSValueRef) cy$getProperty:(NSString *)name inContext:(JSContextRef)context;
cc103044
JF
433- (bool) cy$setProperty:(NSString *)name to:(NSObject *)value;
434- (bool) cy$deleteProperty:(NSString *)name;
8665da0c 435- (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context;
b4aa79af 436
3e264692
JF
437+ (bool) cy$hasImplicitProperties;
438
c1582939
JF
439@end
440
f7c38a29 441@protocol Cycript
f2f0d1d1 442- (id) cy$box;
88c6482c 443- (JSValueRef) cy$valueOfInContext:(JSContextRef)context;
f7c38a29 444@end
88c977fa 445
dd18424c 446NSString *CYCastNSCYON(id value, bool objective) {
520c130f
JF
447 NSString *string;
448
449 if (value == nil)
450 string = @"nil";
451 else {
452 Class _class(object_getClass(value));
dd18424c 453 SEL sel(@selector(cy$toCYON:));
520c130f
JF
454
455 if (objc_method *toCYON = class_getInstanceMethod(_class, sel))
74988263 456 string = reinterpret_cast<NSString *(*)(id, SEL, bool)>(method_getImplementation(toCYON))(value, sel, objective);
520c130f
JF
457 else if (objc_method *methodSignatureForSelector = class_getInstanceMethod(_class, @selector(methodSignatureForSelector:))) {
458 if (reinterpret_cast<NSMethodSignature *(*)(id, SEL, SEL)>(method_getImplementation(methodSignatureForSelector))(value, @selector(methodSignatureForSelector:), sel) != nil)
dd18424c 459 string = [value cy$toCYON:objective];
520c130f
JF
460 else goto fail;
461 } else fail: {
b5dd57dc
JF
462 if (false);
463#ifdef __APPLE__
464 else if (value == NSZombie_)
520c130f
JF
465 string = @"_NSZombie_";
466 else if (_class == NSZombie_)
467 string = [NSString stringWithFormat:@"<_NSZombie_: %p>", value];
468 // XXX: frowny /in/ the pants
30c4d7e0 469 else if (banned_.find(value) != banned_.end())
520c130f 470 string = nil;
b5dd57dc 471#endif
520c130f
JF
472 else
473 string = [NSString stringWithFormat:@"%@", value];
474 }
475
476 // XXX: frowny pants
477 if (string == nil)
478 string = @"undefined";
479 }
480
481 return string;
482}
520c130f 483
cbaa5f0f 484#ifdef __APPLE__
4afefdd9
JF
485struct PropertyAttributes {
486 CYPool pool_;
487
488 const char *name;
489
490 const char *variable;
491
492 const char *getter_;
493 const char *setter_;
494
495 bool readonly;
496 bool copy;
497 bool retain;
498 bool nonatomic;
499 bool dynamic;
500 bool weak;
501 bool garbage;
502
503 PropertyAttributes(objc_property_t property) :
504 variable(NULL),
505 getter_(NULL),
506 setter_(NULL),
507 readonly(false),
508 copy(false),
509 retain(false),
510 nonatomic(false),
511 dynamic(false),
512 weak(false),
513 garbage(false)
514 {
515 name = property_getName(property);
516 const char *attributes(property_getAttributes(property));
517
5f6951a6
JF
518 for (char *token(pool_.strdup(attributes)), *next; token != NULL; token = next) {
519 if ((next = strchr(token, ',')) != NULL)
520 *next++ = '\0';
4afefdd9
JF
521 switch (*token) {
522 case 'R': readonly = true; break;
523 case 'C': copy = true; break;
524 case '&': retain = true; break;
525 case 'N': nonatomic = true; break;
526 case 'G': getter_ = token + 1; break;
527 case 'S': setter_ = token + 1; break;
528 case 'V': variable = token + 1; break;
529 }
530 }
531
532 /*if (variable == NULL) {
533 variable = property_getName(property);
534 size_t size(strlen(variable));
535 char *name(new(pool_) char[size + 2]);
536 name[0] = '_';
537 memcpy(name + 1, variable, size);
538 name[size + 1] = '\0';
539 variable = name;
540 }*/
541 }
542
543 const char *Getter() {
544 if (getter_ == NULL)
b799113b 545 getter_ = pool_.strdup(name);
4afefdd9
JF
546 return getter_;
547 }
548
549 const char *Setter() {
550 if (setter_ == NULL && !readonly) {
551 size_t length(strlen(name));
552
553 char *temp(new(pool_) char[length + 5]);
554 temp[0] = 's';
555 temp[1] = 'e';
556 temp[2] = 't';
557
3c1c3635
JF
558 if (length != 0) {
559 temp[3] = toupper(name[0]);
560 memcpy(temp + 4, name + 1, length - 1);
561 }
562
563 temp[length + 3] = ':';
564 temp[length + 4] = '\0';
565 setter_ = temp;
566 }
567
568 return setter_;
569 }
570
571};
572#endif
573
3c1c3635
JF
574@interface CYWebUndefined : NSObject {
575}
576
577+ (CYWebUndefined *) undefined;
578
579@end
580
581@implementation CYWebUndefined
582
583+ (CYWebUndefined *) undefined {
584 static CYWebUndefined *instance_([[CYWebUndefined alloc] init]);
585 return instance_;
586}
587
588@end
589
590#define WebUndefined CYWebUndefined
3c1c3635
JF
591
592/* Bridge: CYJSObject {{{ */
593@interface CYJSObject : NSMutableDictionary {
594 JSObjectRef object_;
54e3490b 595 JSGlobalContextRef context_;
3c1c3635
JF
596}
597
598- (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context;
599
3c1c3635
JF
600- (NSUInteger) count;
601- (id) objectForKey:(id)key;
602- (NSEnumerator *) keyEnumerator;
603- (void) setObject:(id)object forKey:(id)key;
604- (void) removeObjectForKey:(id)key;
605
606@end
607/* }}} */
608/* Bridge: CYJSArray {{{ */
609@interface CYJSArray : NSMutableArray {
610 JSObjectRef object_;
54e3490b 611 JSGlobalContextRef context_;
3c1c3635
JF
612}
613
614- (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context;
615
616- (NSUInteger) count;
617- (id) objectAtIndex:(NSUInteger)index;
618
619- (void) addObject:(id)anObject;
620- (void) insertObject:(id)anObject atIndex:(NSUInteger)index;
621- (void) removeLastObject;
622- (void) removeObjectAtIndex:(NSUInteger)index;
623- (void) replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
624
625@end
626/* }}} */
4afefdd9 627
8150077d
JF
628_finline bool CYJSValueIsNSObject(JSContextRef context, JSValueRef value) {
629 return JSValueIsObjectOfClass(context, value, Instance_);
630}
631
993e8ed5 632_finline bool CYJSValueIsInstanceOfCachedConstructor(JSContextRef context, JSValueRef value, JSStringRef cache) {
f1b5a47f 633 return _jsccall(JSValueIsInstanceOfConstructor, context, value, CYGetCachedObject(context, cache));
3c1c3635 634}
4afefdd9 635
3f9ae37c
JF
636NSObject *CYMakeBlock(void (*invoke)(), sig::Signature &signature) {
637 BlockLiteral *literal(reinterpret_cast<BlockLiteral *>(malloc(sizeof(BlockLiteral))));
638
639 struct Descriptor {
640 struct {
641 BlockDescriptor1 one_;
642 BlockDescriptor2 two_;
643 BlockDescriptor3 three_;
644 } d_;
645
646 CYPool pool_;
647 };
648
649 Descriptor *descriptor(new Descriptor);
650 memset(&descriptor->d_, 0, sizeof(descriptor->d_));
651
652 literal->isa = objc_getClass("__NSGlobalBlock__");
653 literal->flags = BLOCK_HAS_SIGNATURE | BLOCK_HAS_COPY_DISPOSE | BLOCK_IS_GLOBAL;
654 literal->reserved = 0;
655 literal->invoke = reinterpret_cast<void (*)(void *, ...)>(invoke);
656 literal->descriptor = descriptor;
657
658 descriptor->d_.one_.size = sizeof(descriptor->d_);
659 descriptor->d_.three_.signature = sig::Unparse(descriptor->pool_, &signature);
660
661 return reinterpret_cast<NSObject *>(literal);
662}
663
b799113b 664NSObject *CYCastNSObject(CYPool *pool, JSContextRef context, JSObjectRef object) {
8150077d 665 if (CYJSValueIsNSObject(context, object)) {
3c1c3635
JF
666 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
667 return internal->GetValue();
4afefdd9 668 }
993e8ed5 669
3f9ae37c
JF
670 if (JSValueIsObjectOfClass(context, object, Functor_)) {
671 cy::Functor *internal(reinterpret_cast<cy::Functor *>(JSObjectGetPrivate(object)));
672 return CYMakeBlock(internal->GetValue(), internal->signature_);
673 }
674
993e8ed5
JF
675 bool array(CYJSValueIsInstanceOfCachedConstructor(context, object, Array_s));
676 id value(array ? [CYJSArray alloc] : [CYJSObject alloc]);
677 return CYPoolRelease(pool, [value initWithJSObject:object inContext:context]);
3c1c3635 678}
4afefdd9 679
3c1c3635
JF
680NSNumber *CYCopyNSNumber(JSContextRef context, JSValueRef value) {
681 return [[NSNumber alloc] initWithDouble:CYCastDouble(context, value)];
682}
4afefdd9 683
c074e774
JF
684#ifndef __APPLE__
685@interface NSBoolNumber : NSNumber {
686}
687@end
688#endif
689
b799113b 690id CYNSObject(CYPool *pool, JSContextRef context, JSValueRef value, bool cast) {
3c1c3635
JF
691 id object;
692 bool copy;
693
694 switch (JSType type = JSValueGetType(context, value)) {
695 case kJSTypeUndefined:
696 object = [WebUndefined undefined];
697 copy = false;
698 break;
699
700 case kJSTypeNull:
701 return NULL;
702 break;
703
704 case kJSTypeBoolean:
cbaa5f0f 705#ifdef __APPLE__
3c1c3635
JF
706 object = (id) (CYCastBool(context, value) ? kCFBooleanTrue : kCFBooleanFalse);
707 copy = false;
708#else
c074e774 709 object = [[NSBoolNumber alloc] initWithBool:CYCastBool(context, value)];
3c1c3635 710 copy = true;
b24eb750 711#endif
3c1c3635 712 break;
c239b9f8 713
3c1c3635
JF
714 case kJSTypeNumber:
715 object = CYCopyNSNumber(context, value);
716 copy = true;
717 break;
993f82f8 718
3c1c3635
JF
719 case kJSTypeString:
720 object = CYCopyNSString(context, value);
721 copy = true;
722 break;
993f82f8 723
3c1c3635
JF
724 case kJSTypeObject:
725 // XXX: this might could be more efficient
726 object = CYCastNSObject(pool, context, (JSObjectRef) value);
727 copy = false;
728 break;
993f82f8 729
3c1c3635 730 default:
37954781 731 throw CYJSError(context, "JSValueGetType() == 0x%x", type);
3c1c3635
JF
732 break;
733 }
993f82f8 734
3c1c3635
JF
735 if (cast != copy)
736 return object;
737 else if (copy)
738 return CYPoolRelease(pool, object);
739 else
740 return [object retain];
993f82f8
JF
741}
742
b799113b 743NSObject *CYCastNSObject(CYPool *pool, JSContextRef context, JSValueRef value) {
3c1c3635
JF
744 return CYNSObject(pool, context, value, true);
745}
993f82f8 746
b799113b
JF
747NSObject *CYCopyNSObject(CYPool &pool, JSContextRef context, JSValueRef value) {
748 return CYNSObject(&pool, context, value, false);
3c1c3635 749}
993f82f8 750
365abb0a 751/* Bridge: NSArray {{{ */
107e3ed0 752@implementation NSArray (Cycript)
62ca2b82 753
f2f0d1d1
JF
754- (id) cy$box {
755 return [[self mutableCopy] autorelease];
756}
757
dd18424c 758- (NSString *) cy$toCYON:(bool)objective {
c1582939 759 NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
5b1f57ee 760 [json appendString:@"@["];
c1582939
JF
761
762 bool comma(false);
cbaa5f0f 763#ifdef __APPLE__
62ca2b82 764 for (id object in self) {
cbaa5f0f 765#else
cbaa5f0f 766 for (size_t index(0), count([self count]); index != count; ++index) {
af4272e6 767 id object([self objectAtIndex:index]);
cbaa5f0f 768#endif
c1582939
JF
769 if (comma)
770 [json appendString:@","];
771 else
772 comma = true;
7b184c00 773 if (object == nil || [object cy$JSType] != kJSTypeUndefined)
dd18424c 774 [json appendString:CYCastNSCYON(object, true)];
6b8a9500
JF
775 else {
776 [json appendString:@","];
777 comma = false;
778 }
c1582939
JF
779 }
780
781 [json appendString:@"]"];
782 return json;
62ca2b82
JF
783}
784
7b184c00
JF
785- (bool) cy$hasProperty:(NSString *)name {
786 if ([name isEqualToString:@"length"])
787 return true;
788
520c130f 789 size_t index(CYGetIndex(name));
faf69207 790 if (index == _not(size_t) || index >= [self count])
7b184c00
JF
791 return [super cy$hasProperty:name];
792 else
793 return true;
794}
795
cc103044 796- (NSObject *) cy$getProperty:(NSString *)name {
520c130f 797 size_t index(CYGetIndex(name));
faf69207 798 if (index == _not(size_t) || index >= [self count])
cc103044
JF
799 return [super cy$getProperty:name];
800 else
801 return [self objectAtIndex:index];
802}
803
6b9e29d2 804- (JSValueRef) cy$getProperty:(NSString *)name inContext:(JSContextRef)context {
f1b5a47f 805 CYObjectiveTry_ {
6b9e29d2
JF
806 if ([name isEqualToString:@"length"])
807 return CYCastJSValue(context, [self count]);
808 } CYObjectiveCatch
809
810 return [super cy$getProperty:name inContext:context];
811}
812
8665da0c
JF
813- (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
814 [super cy$getPropertyNames:names inContext:context];
d3760804
JF
815
816 for (size_t index(0), count([self count]); index != count; ++index) {
817 id object([self objectAtIndex:index]);
818 if (object == nil || [object cy$JSType] != kJSTypeUndefined) {
819 char name[32];
820 sprintf(name, "%zu", index);
821 JSPropertyNameAccumulatorAddName(names, CYJSString(name));
822 }
823 }
824}
825
334bdca2
JF
826+ (bool) cy$hasImplicitProperties {
827 return false;
828}
829
cc103044 830@end
365abb0a 831/* }}} */
aaa3cd1e
JF
832/* Bridge: NSBlock {{{ */
833#ifdef __APPLE__
834@interface NSBlock
835- (void) invoke;
836@end
837#endif
838/* }}} */
c074e774
JF
839/* Bridge: NSBoolNumber {{{ */
840#ifndef __APPLE__
841@implementation NSBoolNumber (Cycript)
842
843- (JSType) cy$JSType {
844 return kJSTypeBoolean;
845}
846
dd18424c
JF
847- (NSString *) cy$toCYON:(bool)objective {
848 NSString *value([self boolValue] ? @"true" : @"false");
849 return objective ? value : [NSString stringWithFormat:@"@%@", value];
c074e774
JF
850}
851
f1b5a47f 852- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
c074e774
JF
853 return CYCastJSValue(context, (bool) [self boolValue]);
854} CYObjectiveCatch }
855
856@end
857#endif
858/* }}} */
365abb0a
JF
859/* Bridge: NSDictionary {{{ */
860@implementation NSDictionary (Cycript)
861
f2f0d1d1
JF
862- (id) cy$box {
863 return [[self mutableCopy] autorelease];
864}
865
dd18424c 866- (NSString *) cy$toCYON:(bool)objective {
365abb0a 867 NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
5b1f57ee 868 [json appendString:@"@{"];
365abb0a
JF
869
870 bool comma(false);
cbaa5f0f 871#ifdef __APPLE__
0226d428 872 for (NSObject *key in self) {
cbaa5f0f
JF
873#else
874 NSEnumerator *keys([self keyEnumerator]);
0226d428 875 while (NSObject *key = [keys nextObject]) {
cbaa5f0f 876#endif
365abb0a
JF
877 if (comma)
878 [json appendString:@","];
879 else
880 comma = true;
dd18424c 881 [json appendString:CYCastNSCYON(key, true)];
365abb0a
JF
882 [json appendString:@":"];
883 NSObject *object([self objectForKey:key]);
dd18424c 884 [json appendString:CYCastNSCYON(object, true)];
365abb0a 885 }
cc103044 886
365abb0a
JF
887 [json appendString:@"}"];
888 return json;
889}
890
891- (bool) cy$hasProperty:(NSString *)name {
892 return [self objectForKey:name] != nil;
893}
894
895- (NSObject *) cy$getProperty:(NSString *)name {
896 return [self objectForKey:name];
897}
898
8665da0c
JF
899- (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
900 [super cy$getPropertyNames:names inContext:context];
d3760804
JF
901
902#ifdef __APPLE__
0226d428 903 for (NSObject *key in self) {
d3760804
JF
904#else
905 NSEnumerator *keys([self keyEnumerator]);
0226d428 906 while (NSObject *key = [keys nextObject]) {
d3760804 907#endif
8665da0c 908 JSPropertyNameAccumulatorAddName(names, CYJSString(context, key));
d3760804
JF
909 }
910}
911
3e264692
JF
912+ (bool) cy$hasImplicitProperties {
913 return false;
914}
915
365abb0a
JF
916@end
917/* }}} */
918/* Bridge: NSMutableArray {{{ */
cc103044
JF
919@implementation NSMutableArray (Cycript)
920
921- (bool) cy$setProperty:(NSString *)name to:(NSObject *)value {
faf69207
JF
922 if ([name isEqualToString:@"length"]) {
923 // XXX: is this not intelligent?
cbaa5f0f
JF
924 NSNumber *number(reinterpret_cast<NSNumber *>(value));
925#ifdef __APPLE__
926 NSUInteger size([number unsignedIntegerValue]);
927#else
928 NSUInteger size([number unsignedIntValue]);
929#endif
faf69207
JF
930 NSUInteger count([self count]);
931 if (size < count)
932 [self removeObjectsInRange:NSMakeRange(size, count - size)];
933 else if (size != count) {
934 WebUndefined *undefined([WebUndefined undefined]);
935 for (size_t i(count); i != size; ++i)
936 [self addObject:undefined];
937 }
938 return true;
939 }
940
520c130f 941 size_t index(CYGetIndex(name));
faf69207 942 if (index == _not(size_t))
cc103044 943 return [super cy$setProperty:name to:value];
faf69207
JF
944
945 id object(value ?: [NSNull null]);
946
947 size_t count([self count]);
948 if (index < count)
949 [self replaceObjectAtIndex:index withObject:object];
cc103044 950 else {
faf69207
JF
951 if (index != count) {
952 WebUndefined *undefined([WebUndefined undefined]);
953 for (size_t i(count); i != index; ++i)
954 [self addObject:undefined];
955 }
956
957 [self addObject:object];
cc103044 958 }
faf69207 959
365abb0a 960 return true;
7b184c00
JF
961}
962
365abb0a 963- (bool) cy$deleteProperty:(NSString *)name {
520c130f 964 size_t index(CYGetIndex(name));
365abb0a
JF
965 if (index == _not(size_t) || index >= [self count])
966 return [super cy$deleteProperty:name];
967 [self replaceObjectAtIndex:index withObject:[WebUndefined undefined]];
968 return true;
cc103044
JF
969}
970
971@end
365abb0a
JF
972/* }}} */
973/* Bridge: NSMutableDictionary {{{ */
cc103044
JF
974@implementation NSMutableDictionary (Cycript)
975
976- (bool) cy$setProperty:(NSString *)name to:(NSObject *)value {
b6ea08b6 977 [self setObject:(value ?: [NSNull null]) forKey:name];
cc103044
JF
978 return true;
979}
980
981- (bool) cy$deleteProperty:(NSString *)name {
982 if ([self objectForKey:name] == nil)
983 return false;
984 else {
985 [self removeObjectForKey:name];
986 return true;
987 }
988}
989
62ca2b82 990@end
365abb0a
JF
991/* }}} */
992/* Bridge: NSNumber {{{ */
107e3ed0 993@implementation NSNumber (Cycript)
62ca2b82 994
b4aa79af 995- (JSType) cy$JSType {
b53b30c1 996#ifdef __APPLE__
b4aa79af 997 // XXX: this just seems stupid
b53b30c1
JF
998 if ([self class] == NSCFBoolean_)
999 return kJSTypeBoolean;
1000#endif
1001 return kJSTypeNumber;
b4aa79af
JF
1002}
1003
dd18424c
JF
1004- (NSString *) cy$toCYON:(bool)objective {
1005 NSString *value([self cy$JSType] != kJSTypeBoolean ? [self stringValue] : [self boolValue] ? @"true" : @"false");
1006 return objective ? value : [NSString stringWithFormat:@"@%@", value];
62ca2b82
JF
1007}
1008
f1b5a47f 1009- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
77f56624 1010 return [self cy$JSType] != kJSTypeBoolean ? CYCastJSValue(context, [self doubleValue]) : CYCastJSValue(context, static_cast<bool>([self boolValue]));
3c1c3635 1011} CYObjectiveCatch }
62ca2b82
JF
1012
1013@end
365abb0a
JF
1014/* }}} */
1015/* Bridge: NSNull {{{ */
1016@implementation NSNull (Cycript)
1017
1018- (JSType) cy$JSType {
1019 return kJSTypeNull;
1020}
1021
dd18424c
JF
1022- (NSString *) cy$toCYON:(bool)objective {
1023 NSString *value(@"null");
1024 return objective ? value : [NSString stringWithFormat:@"@%@", value];
365abb0a
JF
1025}
1026
f1b5a47f 1027- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
e23a9070
JF
1028 return CYJSNull(context);
1029} CYObjectiveCatch }
1030
365abb0a
JF
1031@end
1032/* }}} */
1033/* Bridge: NSObject {{{ */
1034@implementation NSObject (Cycript)
1035
f2f0d1d1
JF
1036- (id) cy$box {
1037 return self;
1038}
1039
e23a9070
JF
1040- (JSValueRef) cy$toJSON:(NSString *)key inContext:(JSContextRef)context {
1041 return [self cy$valueOfInContext:context];
1042}
1043
f1b5a47f 1044- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
95221eed 1045 return NULL;
3c1c3635 1046} CYObjectiveCatch }
365abb0a
JF
1047
1048- (JSType) cy$JSType {
1049 return kJSTypeObject;
1050}
1051
dd18424c 1052- (NSString *) cy$toCYON:(bool)objective {
e23a9070 1053 return [[self description] cy$toCYON:objective];
365abb0a
JF
1054}
1055
365abb0a
JF
1056- (bool) cy$hasProperty:(NSString *)name {
1057 return false;
1058}
1059
1060- (NSObject *) cy$getProperty:(NSString *)name {
1061 return nil;
1062}
1063
f1b5a47f 1064- (JSValueRef) cy$getProperty:(NSString *)name inContext:(JSContextRef)context { CYObjectiveTry_ {
6b9e29d2
JF
1065 if (NSObject *value = [self cy$getProperty:name])
1066 return CYCastJSValue(context, value);
1067 return NULL;
1068} CYObjectiveCatch }
1069
365abb0a
JF
1070- (bool) cy$setProperty:(NSString *)name to:(NSObject *)value {
1071 return false;
1072}
1073
1074- (bool) cy$deleteProperty:(NSString *)name {
1075 return false;
1076}
1077
8665da0c 1078- (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
d3760804
JF
1079}
1080
3e264692
JF
1081+ (bool) cy$hasImplicitProperties {
1082 return true;
1083}
1084
365abb0a
JF
1085@end
1086/* }}} */
1087/* Bridge: NSProxy {{{ */
1088@implementation NSProxy (Cycript)
1089
dd18424c 1090- (NSString *) cy$toCYON:(bool)objective {
e23a9070 1091 return [[self description] cy$toCYON:objective];
365abb0a 1092}
c1582939 1093
365abb0a
JF
1094@end
1095/* }}} */
1096/* Bridge: NSString {{{ */
107e3ed0 1097@implementation NSString (Cycript)
62ca2b82 1098
f2f0d1d1
JF
1099- (id) cy$box {
1100 return [[self copy] autorelease];
1101}
1102
b4aa79af
JF
1103- (JSType) cy$JSType {
1104 return kJSTypeString;
1105}
1106
dd18424c 1107- (NSString *) cy$toCYON:(bool)objective {
3c1c3635 1108 std::ostringstream str;
dd18424c
JF
1109 if (!objective)
1110 str << '@';
3c1c3635
JF
1111 CYUTF8String string(CYCastUTF8String(self));
1112 CYStringify(str, string.data, string.size);
1113 std::string value(str.str());
1114 return CYCastNSString(NULL, CYUTF8String(value.c_str(), value.size()));
1115}
b09da87b 1116
6aa16f29 1117- (bool) cy$hasProperty:(NSString *)name {
6aa16f29
JF
1118 size_t index(CYGetIndex(name));
1119 if (index == _not(size_t) || index >= [self length])
1120 return [super cy$hasProperty:name];
1121 else
1122 return true;
1123}
1124
1125- (NSObject *) cy$getProperty:(NSString *)name {
6aa16f29
JF
1126 size_t index(CYGetIndex(name));
1127 if (index == _not(size_t) || index >= [self length])
1128 return [super cy$getProperty:name];
1129 else
1130 return [self substringWithRange:NSMakeRange(index, 1)];
1131}
1132
1133- (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
1134 [super cy$getPropertyNames:names inContext:context];
1135
1136 for (size_t index(0), length([self length]); index != length; ++index) {
1137 char name[32];
1138 sprintf(name, "%zu", index);
1139 JSPropertyNameAccumulatorAddName(names, CYJSString(name));
1140 }
1141}
1142
f1b5a47f 1143- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
95221eed
JF
1144 return CYCastJSValue(context, CYJSString(context, self));
1145} CYObjectiveCatch }
1146
3c1c3635
JF
1147@end
1148/* }}} */
1149/* Bridge: WebUndefined {{{ */
1150@implementation WebUndefined (Cycript)
b09da87b 1151
3c1c3635
JF
1152- (JSType) cy$JSType {
1153 return kJSTypeUndefined;
b09da87b
JF
1154}
1155
308f0d72 1156- (NSString *) cy$toCYON:(bool)objective {
dd18424c
JF
1157 NSString *value(@"undefined");
1158 return value; // XXX: maybe use the below code, adding @undefined?
1159 //return objective ? value : [NSString stringWithFormat:@"@%@", value];
c1582939
JF
1160}
1161
f1b5a47f 1162- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
3c1c3635
JF
1163 return CYJSUndefined(context);
1164} CYObjectiveCatch }
1165
1166@end
1167/* }}} */
1168
cacd1a88 1169static bool CYIsClass(id self) {
aabea98c 1170#ifdef __APPLE__
489b8a0a 1171 return class_isMetaClass(object_getClass(self));
aabea98c
JF
1172#else
1173 return GSObjCIsClass(self);
1174#endif
cacd1a88
JF
1175}
1176
b799113b
JF
1177Class CYCastClass(CYPool &pool, JSContextRef context, JSValueRef value) {
1178 id self(CYCastNSObject(&pool, context, value));
cacd1a88
JF
1179 if (CYIsClass(self))
1180 return (Class) self;
37954781 1181 throw CYJSError(context, "got something that is not a Class");
cacd1a88
JF
1182 return NULL;
1183}
1184
aabea98c 1185NSArray *CYCastNSArray(JSContextRef context, JSPropertyNameArrayRef names) {
b09da87b 1186 CYPool pool;
62ca2b82
JF
1187 size_t size(JSPropertyNameArrayGetCount(names));
1188 NSMutableArray *array([NSMutableArray arrayWithCapacity:size]);
1189 for (size_t index(0); index != size; ++index)
b799113b 1190 [array addObject:CYCastNSString(&pool, context, JSPropertyNameArrayGetNameAtIndex(names, index))];
62ca2b82
JF
1191 return array;
1192}
62ca2b82 1193
ba4fa42f 1194JSValueRef CYCastJSValue(JSContextRef context, NSObject *value) { CYPoolTry {
f7c38a29
JF
1195 if (value == nil)
1196 return CYJSNull(context);
f7c38a29
JF
1197 else
1198 return CYMakeInstance(context, value, false);
7c6c5b0a 1199} CYPoolCatch(NULL) return /*XXX*/ NULL; }
af4272e6 1200
b21525c7 1201@implementation CYJSObject
62ca2b82 1202
f1b5a47f 1203- (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context { CYObjectiveTry_ {
62ca2b82
JF
1204 if ((self = [super init]) != nil) {
1205 object_ = object;
bc60fb46 1206 context_ = CYGetJSContext(context);
54e3490b 1207 JSGlobalContextRetain(context_);
75b0a457 1208 JSValueProtect(context_, object_);
62ca2b82 1209 } return self;
3c1c3635 1210} CYObjectiveCatch }
62ca2b82 1211
3c1c3635 1212- (void) dealloc { CYObjectiveTry {
75b0a457 1213 JSValueUnprotect(context_, object_);
54e3490b 1214 JSGlobalContextRelease(context_);
75b0a457 1215 [super dealloc];
3c1c3635 1216} CYObjectiveCatch }
75b0a457 1217
dd18424c 1218- (NSString *) cy$toCYON:(bool)objective { CYObjectiveTry {
af4272e6 1219 CYPool pool;
f1b5a47f 1220 const char *cyon(CYPoolCCYON(pool, context, object_));
8aa3e970 1221 if (cyon == NULL)
dd18424c 1222 return [super cy$toCYON:objective];
8aa3e970
JF
1223 else
1224 return [NSString stringWithUTF8String:cyon];
3c1c3635 1225} CYObjectiveCatch }
b4aa79af 1226
3c1c3635 1227- (NSUInteger) count { CYObjectiveTry {
f1b5a47f 1228 JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context, object_));
62ca2b82
JF
1229 size_t size(JSPropertyNameArrayGetCount(names));
1230 JSPropertyNameArrayRelease(names);
1231 return size;
3c1c3635 1232} CYObjectiveCatch }
62ca2b82 1233
3c1c3635 1234- (id) objectForKey:(id)key { CYObjectiveTry {
f1b5a47f
JF
1235 JSValueRef value(CYGetProperty(context, object_, CYJSString(context, (NSObject *) key)));
1236 if (JSValueIsUndefined(context, value))
d0a00196 1237 return nil;
f1b5a47f 1238 return CYCastNSObject(NULL, context, value) ?: [NSNull null];
3c1c3635 1239} CYObjectiveCatch }
62ca2b82 1240
3c1c3635 1241- (NSEnumerator *) keyEnumerator { CYObjectiveTry {
f1b5a47f
JF
1242 JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context, object_));
1243 NSEnumerator *enumerator([CYCastNSArray(context, names) objectEnumerator]);
62ca2b82
JF
1244 JSPropertyNameArrayRelease(names);
1245 return enumerator;
3c1c3635 1246} CYObjectiveCatch }
62ca2b82 1247
3c1c3635 1248- (void) setObject:(id)object forKey:(id)key { CYObjectiveTry {
f1b5a47f 1249 CYSetProperty(context, object_, CYJSString(context, (NSObject *) key), CYCastJSValue(context, (NSString *) object));
3c1c3635 1250} CYObjectiveCatch }
62ca2b82 1251
3c1c3635 1252- (void) removeObjectForKey:(id)key { CYObjectiveTry {
f1b5a47f 1253 (void) _jsccall(JSObjectDeleteProperty, context, object_, CYJSString(context, (NSObject *) key));
3c1c3635 1254} CYObjectiveCatch }
62ca2b82
JF
1255
1256@end
1257
b21525c7 1258@implementation CYJSArray
c1582939 1259
f1b5a47f 1260- (NSString *) cy$toCYON:(bool)objective { CYObjectiveTry {
4ee70134 1261 CYPool pool;
f1b5a47f
JF
1262 return [NSString stringWithUTF8String:CYPoolCCYON(pool, context, object_)];
1263} CYObjectiveCatch }
4ee70134 1264
f1b5a47f 1265- (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context { CYObjectiveTry_ {
c1582939
JF
1266 if ((self = [super init]) != nil) {
1267 object_ = object;
bc60fb46 1268 context_ = CYGetJSContext(context);
54e3490b 1269 JSGlobalContextRetain(context_);
75b0a457 1270 JSValueProtect(context_, object_);
c1582939 1271 } return self;
3c1c3635 1272} CYObjectiveCatch }
c1582939 1273
3c1c3635 1274- (void) dealloc { CYObjectiveTry {
75b0a457 1275 JSValueUnprotect(context_, object_);
54e3490b 1276 JSGlobalContextRelease(context_);
75b0a457 1277 [super dealloc];
3c1c3635 1278} CYObjectiveCatch }
75b0a457 1279
3c1c3635 1280- (NSUInteger) count { CYObjectiveTry {
f1b5a47f 1281 return CYArrayLength(context, object_);
3c1c3635 1282} CYObjectiveCatch }
c1582939 1283
3c1c3635 1284- (id) objectAtIndex:(NSUInteger)index { CYObjectiveTry {
9a2db8b2
JF
1285 size_t bounds([self count]);
1286 if (index >= bounds)
afdeb404 1287 @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"*** -[CYJSArray objectAtIndex:]: index (%zu) beyond bounds (%zu)", static_cast<size_t>(index), bounds] userInfo:nil];
f1b5a47f
JF
1288 JSValueRef value(_jsccall(JSObjectGetPropertyAtIndex, context, object_, index));
1289 return CYCastNSObject(NULL, context, value) ?: [NSNull null];
3c1c3635 1290} CYObjectiveCatch }
c1582939 1291
3c1c3635 1292- (void) addObject:(id)object { CYObjectiveTry {
f1b5a47f 1293 CYArrayPush(context, object_, CYCastJSValue(context, (NSObject *) object));
3c1c3635 1294} CYObjectiveCatch }
faf69207 1295
3c1c3635 1296- (void) insertObject:(id)object atIndex:(NSUInteger)index { CYObjectiveTry {
9a2db8b2
JF
1297 size_t bounds([self count] + 1);
1298 if (index >= bounds)
afdeb404 1299 @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"*** -[CYJSArray insertObject:atIndex:]: index (%zu) beyond bounds (%zu)", static_cast<size_t>(index), bounds] userInfo:nil];
faf69207 1300 JSValueRef arguments[3];
f1b5a47f
JF
1301 arguments[0] = CYCastJSValue(context, index);
1302 arguments[1] = CYCastJSValue(context, 0);
1303 arguments[2] = CYCastJSValue(context, (NSObject *) object);
1304 JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array_prototype")));
1305 _jsccall(JSObjectCallAsFunction, context, CYCastJSObject(context, CYGetProperty(context, Array, splice_s)), object_, 3, arguments);
3c1c3635 1306} CYObjectiveCatch }
af4272e6 1307
3c1c3635 1308- (void) removeLastObject { CYObjectiveTry {
f1b5a47f
JF
1309 JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array_prototype")));
1310 _jsccall(JSObjectCallAsFunction, context, CYCastJSObject(context, CYGetProperty(context, Array, pop_s)), object_, 0, NULL);
3c1c3635 1311} CYObjectiveCatch }
af4272e6 1312
3c1c3635
JF
1313- (void) removeObjectAtIndex:(NSUInteger)index { CYObjectiveTry {
1314 size_t bounds([self count]);
1315 if (index >= bounds)
afdeb404 1316 @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"*** -[CYJSArray removeObjectAtIndex:]: index (%zu) beyond bounds (%zu)", static_cast<size_t>(index), bounds] userInfo:nil];
3c1c3635 1317 JSValueRef arguments[2];
f1b5a47f
JF
1318 arguments[0] = CYCastJSValue(context, index);
1319 arguments[1] = CYCastJSValue(context, 1);
1320 JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array_prototype")));
1321 _jsccall(JSObjectCallAsFunction, context, CYCastJSObject(context, CYGetProperty(context, Array, splice_s)), object_, 2, arguments);
3c1c3635
JF
1322} CYObjectiveCatch }
1323
1324- (void) replaceObjectAtIndex:(NSUInteger)index withObject:(id)object { CYObjectiveTry {
1325 size_t bounds([self count]);
1326 if (index >= bounds)
afdeb404 1327 @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"*** -[CYJSArray replaceObjectAtIndex:withObject:]: index (%zu) beyond bounds (%zu)", static_cast<size_t>(index), bounds] userInfo:nil];
f1b5a47f 1328 CYSetProperty(context, object_, index, CYCastJSValue(context, (NSObject *) object));
3c1c3635
JF
1329} CYObjectiveCatch }
1330
1331@end
af4272e6 1332
c44063e0
JF
1333// XXX: inherit from or replace with CYJSObject
1334@interface CYInternal : NSObject {
54e3490b 1335 JSGlobalContextRef context_;
61933e16 1336 JSObjectRef object_;
c44063e0 1337}
61933e16 1338
c44063e0 1339@end
61933e16 1340
c44063e0 1341@implementation CYInternal
61933e16 1342
f1b5a47f 1343- (void) dealloc { CYObjectiveTry {
c44063e0 1344 JSValueUnprotect(context_, object_);
54e3490b 1345 JSGlobalContextRelease(context_);
c44063e0 1346 [super dealloc];
f1b5a47f 1347} CYObjectiveCatch }
61933e16 1348
f1b5a47f 1349- (id) initInContext:(JSContextRef)context { CYObjectiveTry_ {
c44063e0
JF
1350 if ((self = [super init]) != nil) {
1351 context_ = CYGetJSContext(context);
54e3490b 1352 JSGlobalContextRetain(context_);
c44063e0 1353 } return self;
f1b5a47f 1354} CYObjectiveCatch }
61933e16 1355
c44063e0
JF
1356- (bool) hasProperty:(JSStringRef)name inContext:(JSContextRef)context {
1357 if (object_ == NULL)
1358 return false;
61933e16 1359
c44063e0
JF
1360 return JSObjectHasProperty(context, object_, name);
1361}
61933e16 1362
c44063e0
JF
1363- (JSValueRef) getProperty:(JSStringRef)name inContext:(JSContextRef)context {
1364 if (object_ == NULL)
1365 return NULL;
1366
1367 return CYGetProperty(context, object_, name);
1368}
1369
1370- (void) setProperty:(JSStringRef)name toValue:(JSValueRef)value inContext:(JSContextRef)context {
1371 @synchronized (self) {
1372 if (object_ == NULL) {
1373 object_ = JSObjectMake(context, NULL, NULL);
1374 JSValueProtect(context, object_);
1375 }
7b184c00
JF
1376 }
1377
c44063e0
JF
1378 CYSetProperty(context, object_, name, value);
1379}
1380
1381+ (CYInternal *) get:(id)object {
1382 if ($objc_getAssociatedObject == NULL)
1383 return nil;
1384
1385 @synchronized (object) {
1386 if (CYInternal *internal = $objc_getAssociatedObject(object, @selector(cy$internal)))
1387 return internal;
61933e16
JF
1388 }
1389
c44063e0
JF
1390 return nil;
1391}
1392
1393+ (CYInternal *) set:(id)object inContext:(JSContextRef)context {
1394 if ($objc_getAssociatedObject == NULL)
1395 return nil;
1396
1397 @synchronized (object) {
1398 if (CYInternal *internal = $objc_getAssociatedObject(object, @selector(cy$internal)))
1399 return internal;
1400
1401 if ($objc_setAssociatedObject == NULL)
1402 return nil;
1403
1404 CYInternal *internal([[[CYInternal alloc] initInContext:context] autorelease]);
1405 objc_setAssociatedObject(object, @selector(cy$internal), internal, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1406 return internal;
61933e16 1407 }
c44063e0
JF
1408
1409 return nil;
1410}
1411
1412@end
61933e16 1413
534fb6da 1414static JSObjectRef CYMakeSelector(JSContextRef context, SEL sel) {
9e562cfc
JF
1415 Selector_privateData *internal(new Selector_privateData(sel));
1416 return JSObjectMake(context, Selector_, internal);
dea834b0 1417}
b09da87b 1418
534fb6da 1419static SEL CYCastSEL(JSContextRef context, JSValueRef value) {
4afefdd9 1420 if (JSValueIsObjectOfClass(context, value, Selector_)) {
9e562cfc
JF
1421 Selector_privateData *internal(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate((JSObjectRef) value)));
1422 return reinterpret_cast<SEL>(internal->value_);
4afefdd9
JF
1423 } else
1424 return CYCastPointer<SEL>(context, value);
1425}
1426
b64ab4da 1427void *CYObjectiveC_ExecuteStart(JSContextRef context) { CYSadTry {
3c1c3635 1428 return (void *) [[NSAutoreleasePool alloc] init];
ea840434 1429} CYSadCatch(NULL) }
ea2d184c 1430
b64ab4da 1431void CYObjectiveC_ExecuteEnd(JSContextRef context, void *handle) { CYSadTry {
3c1c3635 1432 return [(NSAutoreleasePool *) handle release];
ea840434 1433} CYSadCatch() }
ea2d184c 1434
f0d43c71 1435JSValueRef CYObjectiveC_RuntimeProperty(JSContextRef context, CYUTF8String name) { CYPoolTry {
3c1c3635
JF
1436 if (name == "nil")
1437 return Instance::Make(context, nil);
1438 if (Class _class = objc_getClass(name.data))
1439 return CYMakeInstance(context, _class, true);
64b8d29f
JF
1440 if (Protocol *protocol = objc_getProtocol(name.data))
1441 return CYMakeInstance(context, protocol, true);
3c1c3635 1442 return NULL;
7c6c5b0a 1443} CYPoolCatch(NULL) return /*XXX*/ NULL; }
d3760804 1444
b64ab4da 1445static void CYObjectiveC_CallFunction(JSContextRef context, ffi_cif *cif, void (*function)(), uint8_t *value, void **values) { CYSadTry {
d3760804 1446 ffi_call(cif, function, value, values);
ea840434 1447} CYSadCatch() }
ea2d184c 1448
b799113b 1449static bool CYObjectiveC_PoolFFI(CYPool *pool, JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, JSValueRef value) { CYSadTry {
3c1c3635 1450 switch (type->primitive) {
ecf94af8
JF
1451 // XXX: do something epic about blocks
1452 case sig::block_P:
ea2d184c
JF
1453 case sig::object_P:
1454 case sig::typename_P:
b799113b 1455 // XXX: this works for return values, but not for properties and fields
b09da87b 1456 *reinterpret_cast<id *>(data) = CYCastNSObject(pool, context, value);
7ba62cfd
JF
1457 break;
1458
ea2d184c 1459 case sig::selector_P:
7ba62cfd
JF
1460 *reinterpret_cast<SEL *>(data) = CYCastSEL(context, value);
1461 break;
ea2d184c 1462
bd17e6f3 1463 default:
3c1c3635 1464 return false;
ea2d184c 1465 }
ea2d184c 1466
3c1c3635 1467 return true;
ea840434 1468} CYSadCatch(false) }
ea2d184c 1469
f0d43c71 1470static JSValueRef CYObjectiveC_FromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) { CYPoolTry {
ea2d184c 1471 switch (type->primitive) {
ecf94af8
JF
1472 // XXX: do something epic about blocks
1473 case sig::block_P:
3c1c3635 1474 case sig::object_P:
ba4fa42f 1475 if (NSObject *object = *reinterpret_cast<NSObject **>(data)) {
3c1c3635 1476 JSValueRef value(CYCastJSValue(context, object));
2b52f27e
JF
1477 if (initialize)
1478 [object release];
3c1c3635 1479 return value;
2b52f27e 1480 } else goto null;
dea834b0 1481
b09da87b 1482 case sig::typename_P:
3c1c3635 1483 return CYMakeInstance(context, *reinterpret_cast<Class *>(data), true);
b09da87b 1484
dea834b0
JF
1485 case sig::selector_P:
1486 if (SEL sel = *reinterpret_cast<SEL *>(data))
3c1c3635 1487 return CYMakeSelector(context, sel);
f610e1a0 1488 else goto null;
f610e1a0
JF
1489
1490 null:
3c1c3635 1491 return CYJSNull(context);
bd17e6f3 1492 default:
3c1c3635 1493 return NULL;
ea2d184c 1494 }
7c6c5b0a 1495} CYPoolCatch(NULL) return /*XXX*/ NULL; }
ea2d184c 1496
8e0afb16 1497static bool CYImplements(id object, Class _class, SEL selector, bool devoid = false) {
39bb4b6a 1498 if (objc_method *method = class_getInstanceMethod(_class, selector)) {
8a199b13
JF
1499 if (!devoid)
1500 return true;
7c6c5b0a 1501#if OBJC_API_VERSION >= 2
8a199b13
JF
1502 char type[16];
1503 method_getReturnType(method, type, sizeof(type));
b5dd57dc
JF
1504#else
1505 const char *type(method_getTypeEncoding(method));
1506#endif
8a199b13
JF
1507 if (type[0] != 'v')
1508 return true;
1509 }
1510
7b184c00 1511 // XXX: possibly use a more "awesome" check?
8a199b13 1512 return false;
7b184c00
JF
1513}
1514
b799113b 1515static const char *CYPoolTypeEncoding(CYPool &pool, JSContextRef context, SEL sel, objc_method *method) {
dc68b74c
JF
1516 if (method != NULL)
1517 return method_getTypeEncoding(method);
856b8cd0
JF
1518
1519 const char *name(sel_getName(sel));
2f51d6ab 1520 size_t length(strlen(name));
856b8cd0 1521
2f51d6ab
JF
1522 char keyed[length + 2];
1523 keyed[0] = '6';
1524 keyed[length + 1] = '\0';
1525 memcpy(keyed + 1, name, length);
dc68b74c 1526
2f51d6ab
JF
1527 if (CYBridgeEntry *entry = CYBridgeHash(keyed, length + 1))
1528 return entry->value_;
dc68b74c 1529
3c1c3635 1530 return NULL;
dc68b74c
JF
1531}
1532
9ec7dd18 1533static JSValueRef MessageAdapter_(JSContextRef context, size_t count, JSValueRef values[], JSObjectRef function) {
3c1c3635 1534 JSObjectRef _this(CYCastJSObject(context, values[0]));
9ec7dd18
JF
1535 return CYCallAsFunction(context, function, _this, count - 2, values + 2);
1536}
3c1c3635 1537
9ec7dd18
JF
1538static void MessageClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) {
1539 CYExecuteClosure(cif, result, arguments, arg, &MessageAdapter_);
dc68b74c
JF
1540}
1541
1542static JSObjectRef CYMakeMessage(JSContextRef context, SEL sel, IMP imp, const char *type) {
1543 Message_privateData *internal(new Message_privateData(sel, type, imp));
1544 return JSObjectMake(context, Message_, internal);
1545}
1546
1547static IMP CYMakeMessage(JSContextRef context, JSValueRef value, const char *type) {
1548 JSObjectRef function(CYCastJSObject(context, value));
1549 Closure_privateData *internal(CYMakeFunctor_(context, function, type, &MessageClosure_));
2fd4c9a9 1550 // XXX: see notes in Library.cpp about needing to leak
dc68b74c
JF
1551 return reinterpret_cast<IMP>(internal->GetValue());
1552}
1553
365abb0a
JF
1554static bool Messages_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
1555 Messages *internal(reinterpret_cast<Messages *>(JSObjectGetPrivate(object)));
dc68b74c
JF
1556 Class _class(internal->GetValue());
1557
1558 CYPool pool;
3c1c3635 1559 const char *name(CYPoolCString(pool, context, property));
dc68b74c
JF
1560
1561 if (SEL sel = sel_getUid(name))
1562 if (class_getInstanceMethod(_class, sel) != NULL)
1563 return true;
1564
1565 return false;
1566}
1567
62d94d32 1568static JSValueRef Messages_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
365abb0a 1569 Messages *internal(reinterpret_cast<Messages *>(JSObjectGetPrivate(object)));
dc68b74c
JF
1570 Class _class(internal->GetValue());
1571
1572 CYPool pool;
3c1c3635 1573 const char *name(CYPoolCString(pool, context, property));
dc68b74c
JF
1574
1575 if (SEL sel = sel_getUid(name))
39bb4b6a 1576 if (objc_method *method = class_getInstanceMethod(_class, sel))
dc68b74c
JF
1577 return CYMakeMessage(context, sel, method_getImplementation(method), method_getTypeEncoding(method));
1578
1579 return NULL;
62d94d32 1580} CYCatch(NULL) }
dc68b74c 1581
62d94d32 1582static bool Messages_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
365abb0a 1583 Messages *internal(reinterpret_cast<Messages *>(JSObjectGetPrivate(object)));
dc68b74c
JF
1584 Class _class(internal->GetValue());
1585
1586 CYPool pool;
3c1c3635 1587 const char *name(CYPoolCString(pool, context, property));
dc68b74c
JF
1588
1589 SEL sel(sel_registerName(name));
1590
39bb4b6a 1591 objc_method *method(class_getInstanceMethod(_class, sel));
dc68b74c
JF
1592
1593 const char *type;
1594 IMP imp;
1595
1596 if (JSValueIsObjectOfClass(context, value, Message_)) {
1597 Message_privateData *message(reinterpret_cast<Message_privateData *>(JSObjectGetPrivate((JSObjectRef) value)));
1598 type = sig::Unparse(pool, &message->signature_);
1599 imp = reinterpret_cast<IMP>(message->GetValue());
1600 } else {
37954781 1601 type = CYPoolTypeEncoding(pool, context, sel, method);
dc68b74c
JF
1602 imp = CYMakeMessage(context, value, type);
1603 }
1604
1605 if (method != NULL)
1606 method_setImplementation(method, imp);
b5dd57dc
JF
1607 else {
1608#ifdef GNU_RUNTIME
1609 GSMethodList list(GSAllocMethodList(1));
1610 GSAppendMethodToList(list, sel, type, imp, YES);
1611 GSAddMethodList(_class, list, YES);
1612 GSFlushMethodCacheForClass(_class);
1613#else
1614 class_addMethod(_class, sel, imp, type);
1615#endif
1616 }
dc68b74c
JF
1617
1618 return true;
62d94d32 1619} CYCatch(false) }
dc68b74c 1620
7c6c5b0a 1621#if 0 && OBJC_API_VERSION < 2
62d94d32 1622static bool Messages_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
365abb0a 1623 Messages *internal(reinterpret_cast<Messages *>(JSObjectGetPrivate(object)));
dc68b74c
JF
1624 Class _class(internal->GetValue());
1625
1626 CYPool pool;
aabea98c 1627 const char *name(CYPoolCString(pool, context, property));
dc68b74c
JF
1628
1629 if (SEL sel = sel_getUid(name))
39bb4b6a 1630 if (objc_method *method = class_getInstanceMethod(_class, sel)) {
dc68b74c
JF
1631 objc_method_list list = {NULL, 1, {method}};
1632 class_removeMethods(_class, &list);
1633 return true;
1634 }
1635
1636 return false;
62d94d32 1637} CYCatch(false) }
dc68b74c
JF
1638#endif
1639
365abb0a
JF
1640static void Messages_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
1641 Messages *internal(reinterpret_cast<Messages *>(JSObjectGetPrivate(object)));
dc68b74c
JF
1642 Class _class(internal->GetValue());
1643
7c6c5b0a 1644#if OBJC_API_VERSION >= 2
dc68b74c 1645 unsigned int size;
39bb4b6a 1646 objc_method **data(class_copyMethodList(_class, &size));
dc68b74c
JF
1647 for (size_t i(0); i != size; ++i)
1648 JSPropertyNameAccumulatorAddName(names, CYJSString(sel_getName(method_getName(data[i]))));
1649 free(data);
aabea98c
JF
1650#else
1651 for (objc_method_list *methods(_class->methods); methods != NULL; methods = methods->method_next)
1652 for (int i(0); i != methods->method_count; ++i)
1653 JSPropertyNameAccumulatorAddName(names, CYJSString(sel_getName(method_getName(&methods->method_list[i]))));
1654#endif
dc68b74c
JF
1655}
1656
3e264692
JF
1657static bool CYHasImplicitProperties(Class _class) {
1658 // XXX: this is an evil hack to deal with NSProxy; fix elsewhere
8e0afb16 1659 if (!CYImplements(_class, object_getClass(_class), @selector(cy$hasImplicitProperties)))
3e264692
JF
1660 return true;
1661 return [_class cy$hasImplicitProperties];
1662}
1663
7b184c00
JF
1664static bool Instance_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
1665 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
1666 id self(internal->GetValue());
1667
1668 if (JSStringIsEqualToUTF8CString(property, "$cyi"))
1669 return true;
1670
c239b9f8 1671 CYPool pool;
b799113b 1672 NSString *name(CYCastNSString(&pool, context, property));
7b184c00 1673
c44063e0
JF
1674 if (CYInternal *internal = [CYInternal get:self])
1675 if ([internal hasProperty:property inContext:context])
7b184c00
JF
1676 return true;
1677
365abb0a
JF
1678 Class _class(object_getClass(self));
1679
7b184c00 1680 CYPoolTry {
365abb0a 1681 // XXX: this is an evil hack to deal with NSProxy; fix elsewhere
8e0afb16 1682 if (CYImplements(self, _class, @selector(cy$hasProperty:)))
365abb0a
JF
1683 if ([self cy$hasProperty:name])
1684 return true;
7b184c00
JF
1685 } CYPoolCatch(false)
1686
3c1c3635 1687 const char *string(CYPoolCString(pool, context, name));
7b184c00 1688
aabea98c 1689#ifdef __APPLE__
7b184c00
JF
1690 if (class_getProperty(_class, string) != NULL)
1691 return true;
aabea98c 1692#endif
7b184c00 1693
3e264692
JF
1694 if (CYHasImplicitProperties(_class))
1695 if (SEL sel = sel_getUid(string))
1696 if (CYImplements(self, _class, sel, true))
1697 return true;
7b184c00
JF
1698
1699 return false;
1700}
1701
3c1c3635 1702static JSValueRef Instance_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
7b184c00
JF
1703 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
1704 id self(internal->GetValue());
1705
1706 if (JSStringIsEqualToUTF8CString(property, "$cyi"))
1707 return Internal::Make(context, self, object);
c239b9f8 1708
3c1c3635 1709 CYPool pool;
b799113b 1710 NSString *name(CYCastNSString(&pool, context, property));
c239b9f8 1711
c44063e0
JF
1712 if (CYInternal *internal = [CYInternal get:self])
1713 if (JSValueRef value = [internal getProperty:property inContext:context])
3c1c3635 1714 return value;
c239b9f8 1715
3c1c3635 1716 CYPoolTry {
6b9e29d2
JF
1717 if (JSValueRef value = [self cy$getProperty:name inContext:context])
1718 return value;
3c1c3635 1719 } CYPoolCatch(NULL)
c239b9f8 1720
3c1c3635
JF
1721 const char *string(CYPoolCString(pool, context, name));
1722 Class _class(object_getClass(self));
c239b9f8 1723
cbaa5f0f 1724#ifdef __APPLE__
3c1c3635
JF
1725 if (objc_property_t property = class_getProperty(_class, string)) {
1726 PropertyAttributes attributes(property);
1727 SEL sel(sel_registerName(attributes.Getter()));
9d512587 1728 return CYSendMessage(pool, context, self, NULL, sel, 0, NULL, false);
3c1c3635 1729 }
cbaa5f0f 1730#endif
c239b9f8 1731
3e264692
JF
1732 if (CYHasImplicitProperties(_class))
1733 if (SEL sel = sel_getUid(string))
1734 if (CYImplements(self, _class, sel, true))
9d512587 1735 return CYSendMessage(pool, context, self, NULL, sel, 0, NULL, false);
8953777c 1736
3c1c3635 1737 return NULL;
55c6d6ab 1738} CYCatch(NULL) }
c239b9f8 1739
3c1c3635 1740static bool Instance_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
dc68b74c
JF
1741 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
1742 id self(internal->GetValue());
1743
c239b9f8
JF
1744 CYPool pool;
1745
b799113b
JF
1746 NSString *name(CYCastNSString(&pool, context, property));
1747 NSObject *data(CYCastNSObject(&pool, context, value));
8953777c 1748
3c1c3635
JF
1749 CYPoolTry {
1750 if ([self cy$setProperty:name to:data])
c239b9f8 1751 return true;
55c6d6ab 1752 } CYPoolCatch(false)
dc68b74c 1753
3c1c3635 1754 const char *string(CYPoolCString(pool, context, name));
c239b9f8
JF
1755 Class _class(object_getClass(self));
1756
8aa3e970 1757#ifdef __APPLE__
3c1c3635
JF
1758 if (objc_property_t property = class_getProperty(_class, string)) {
1759 PropertyAttributes attributes(property);
1760 if (const char *setter = attributes.Setter()) {
1761 SEL sel(sel_registerName(setter));
1762 JSValueRef arguments[1] = {value};
9d512587 1763 CYSendMessage(pool, context, self, NULL, sel, 1, arguments, false);
9b5527f0
JF
1764 return true;
1765 }
3c1c3635 1766 }
b24eb750 1767#endif
c239b9f8 1768
3c1c3635 1769 size_t length(strlen(string));
9e20b0b7 1770
3c1c3635 1771 char set[length + 5];
f33b048a 1772
3c1c3635
JF
1773 set[0] = 's';
1774 set[1] = 'e';
1775 set[2] = 't';
f33b048a 1776
3c1c3635
JF
1777 if (string[0] != '\0') {
1778 set[3] = toupper(string[0]);
1779 memcpy(set + 4, string + 1, length - 1);
e0dc20ec 1780 }
bd17e6f3 1781
3c1c3635
JF
1782 set[length + 3] = ':';
1783 set[length + 4] = '\0';
9b5527f0 1784
3c1c3635 1785 if (SEL sel = sel_getUid(set))
8e0afb16 1786 if (CYImplements(self, _class, sel)) {
3c1c3635 1787 JSValueRef arguments[1] = {value};
9d512587 1788 CYSendMessage(pool, context, self, NULL, sel, 1, arguments, false);
975cde38 1789 return true;
3c1c3635 1790 }
f37b3d2b 1791
c44063e0
JF
1792 if (CYInternal *internal = [CYInternal set:self inContext:context]) {
1793 [internal setProperty:property toValue:value inContext:context];
f37b3d2b 1794 return true;
3c1c3635 1795 }
f37b3d2b 1796
3c1c3635 1797 return false;
55c6d6ab 1798} CYCatch(false) }
9b5527f0 1799
3c1c3635
JF
1800static bool Instance_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1801 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
1802 id self(internal->GetValue());
9b5527f0 1803
3c1c3635 1804 CYPoolTry {
aabea98c 1805 NSString *name(CYCastNSString(NULL, context, property));
3c1c3635 1806 return [self cy$deleteProperty:name];
55c6d6ab
JF
1807 } CYPoolCatch(false)
1808} CYCatch(false) return /*XXX*/ false; }
9b5527f0 1809
ec18fc0e
JF
1810static void Instance_getPropertyNames_message(JSPropertyNameAccumulatorRef names, objc_method *method) {
1811 const char *name(sel_getName(method_getName(method)));
1812 if (strchr(name, ':') != NULL)
1813 return;
1814
1815 const char *type(method_getTypeEncoding(method));
1816 if (type == NULL || *type == '\0' || *type == 'v')
1817 return;
1818
1819 JSPropertyNameAccumulatorAddName(names, CYJSString(name));
1820}
1821
3c1c3635
JF
1822static void Instance_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
1823 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
1824 id self(internal->GetValue());
9b5527f0 1825
3c1c3635
JF
1826 CYPool pool;
1827 Class _class(object_getClass(self));
9b5527f0 1828
3c1c3635
JF
1829#ifdef __APPLE__
1830 {
1831 unsigned int size;
1832 objc_property_t *data(class_copyPropertyList(_class, &size));
1833 for (size_t i(0); i != size; ++i)
1834 JSPropertyNameAccumulatorAddName(names, CYJSString(property_getName(data[i])));
1835 free(data);
1836 }
1837#endif
d3760804 1838
326a9dba
JF
1839 if (CYHasImplicitProperties(_class))
1840 for (Class current(_class); current != nil; current = class_getSuperclass(current)) {
ec18fc0e 1841#if OBJC_API_VERSION >= 2
326a9dba
JF
1842 unsigned int size;
1843 objc_method **data(class_copyMethodList(current, &size));
1844 for (size_t i(0); i != size; ++i)
1845 Instance_getPropertyNames_message(names, data[i]);
1846 free(data);
ec18fc0e 1847#else
326a9dba
JF
1848 for (objc_method_list *methods(current->methods); methods != NULL; methods = methods->method_next)
1849 for (int i(0); i != methods->method_count; ++i)
1850 Instance_getPropertyNames_message(names, &methods->method_list[i]);
ec18fc0e 1851#endif
326a9dba 1852 }
ec18fc0e 1853
d3760804
JF
1854 CYPoolTry {
1855 // XXX: this is an evil hack to deal with NSProxy; fix elsewhere
8e0afb16 1856 if (CYImplements(self, _class, @selector(cy$getPropertyNames:inContext:)))
8665da0c 1857 [self cy$getPropertyNames:names inContext:context];
d3760804 1858 } CYPoolCatch()
9b5527f0
JF
1859}
1860
3c1c3635
JF
1861static JSObjectRef Instance_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1862 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
1863 JSObjectRef value(Instance::Make(context, [internal->GetValue() alloc], Instance::Uninitialized));
1864 return value;
55c6d6ab 1865} CYCatch(NULL) }
bd17e6f3 1866
aaa3cd1e
JF
1867static JSValueRef Instance_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1868 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
1869 id self(internal->GetValue());
1870
1871 if (![self isKindOfClass:NSBlock_])
1872 CYThrow("non-NSBlock object is not a function");
f5d7110c
JF
1873 // XXX: replace above logic with the following assertion
1874 //_assert([self isKindOfClass:NSBlock_]);
1875 // to do this, make it so FunctionInstance_ is the class of blocks
1876 // to do /that/, generalize the various "is exactly Instance_" checks
1877 // then, move Instance_callAsFunction to only be on FunctionInstance
aaa3cd1e 1878
868ad7d8 1879 BlockLiteral *literal(reinterpret_cast<BlockLiteral *>(self));
aaa3cd1e
JF
1880
1881 if ((literal->flags & BLOCK_HAS_SIGNATURE) != 0) {
1882 uint8_t *descriptor(reinterpret_cast<uint8_t *>(literal->descriptor));
1883 descriptor += sizeof(BlockDescriptor1);
1884 if ((literal->flags & BLOCK_HAS_COPY_DISPOSE) != 0)
1885 descriptor += sizeof(BlockDescriptor2);
1886 BlockDescriptor3 *descriptor3(reinterpret_cast<BlockDescriptor3 *>(descriptor));
1887
1888 if (const char *type = descriptor3->signature) {
1889 CYPool pool;
1890
1891 void *setup[1];
1892 setup[0] = &self;
1893
1894 sig::Signature signature;
1895 sig::Parse(pool, &signature, type, &Structor_);
1896
1897 ffi_cif cif;
1898 sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif);
1899
1900 void (*function)() = reinterpret_cast<void (*)()>(literal->invoke);
9d512587 1901 return CYCallFunction(pool, context, 1, setup, count, arguments, false, &signature, &cif, function);
aaa3cd1e
JF
1902 }
1903 }
1904
1905 if (count != 0)
1906 CYThrow("NSBlock without signature field passed arguments");
1907
1908 CYPoolTry {
1909 [self invoke];
1910 } CYPoolCatch(NULL);
1911
1912 return NULL;
55c6d6ab 1913} CYCatch(NULL) }
aaa3cd1e 1914
3c1c3635
JF
1915static bool Instance_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef instance, JSValueRef *exception) { CYTry {
1916 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate((JSObjectRef) constructor)));
1917 Class _class(internal->GetValue());
1918 if (!CYIsClass(_class))
1919 return false;
bd17e6f3 1920
8150077d 1921 if (CYJSValueIsNSObject(context, instance)) {
3c1c3635
JF
1922 Instance *linternal(reinterpret_cast<Instance *>(JSObjectGetPrivate((JSObjectRef) instance)));
1923 // XXX: this isn't always safe
1924 return [linternal->GetValue() isKindOfClass:_class];
1925 }
ff783f8c 1926
3c1c3635 1927 return false;
55c6d6ab 1928} CYCatch(false) }
bd17e6f3 1929
f2f0d1d1
JF
1930static JSValueRef Instance_box_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1931 if (count == 0)
1932 throw CYJSError(context, "incorrect number of arguments to Instance");
1933 CYPool pool;
b799113b 1934 id value(CYCastNSObject(&pool, context, arguments[0]));
f2f0d1d1
JF
1935 if (value == nil)
1936 value = [NSNull null];
1937 return CYCastJSValue(context, [value cy$box]);
55c6d6ab 1938} CYCatch(NULL) }
f2f0d1d1 1939
3c1c3635
JF
1940static bool Internal_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
1941 Internal *internal(reinterpret_cast<Internal *>(JSObjectGetPrivate(object)));
f33b048a 1942 CYPool pool;
bd17e6f3 1943
3c1c3635
JF
1944 id self(internal->GetValue());
1945 const char *name(CYPoolCString(pool, context, property));
520c130f 1946
3c1c3635 1947 if (object_getInstanceVariable(self, name, NULL) != NULL)
bd17e6f3 1948 return true;
3c1c3635
JF
1949
1950 return false;
bd17e6f3
JF
1951}
1952
d3fa0357
JF
1953static void CYBitField(unsigned &length, unsigned &shift, id self, Ivar ivar, const char *encoding, unsigned offset) {
1954 length = CYCastDouble(encoding + 1);
1955 shift = 0;
1956
1957 unsigned int size;
1958 objc_ivar **ivars(class_copyIvarList(object_getClass(self), &size));
1959 for (size_t i(0); i != size; ++i)
1960 if (ivars[i] == ivar)
1961 break;
1962 else if (ivar_getOffset(ivars[i]) == offset) {
1963 const char *encoding(ivar_getTypeEncoding(ivars[i]));
1964 _assert(encoding[0] == 'b');
1965 shift += CYCastDouble(encoding + 1);
1966 }
1967 free(ivars);
1968}
1969
3c1c3635
JF
1970static JSValueRef Internal_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1971 Internal *internal(reinterpret_cast<Internal *>(JSObjectGetPrivate(object)));
1972 CYPool pool;
930aa21b 1973
3c1c3635
JF
1974 id self(internal->GetValue());
1975 const char *name(CYPoolCString(pool, context, property));
f33b048a 1976
db69c1f7
JF
1977#ifdef __arm64__
1978 if (strcmp(name, "isa") == 0)
1979 return CYCastJSValue(context, object_getClass(self));
1980#endif
1981
aabea98c 1982 if (objc_ivar *ivar = object_getInstanceVariable(self, name, NULL)) {
ad22d2f8
JF
1983 ptrdiff_t offset(ivar_getOffset(ivar));
1984 void *data(reinterpret_cast<uint8_t *>(self) + offset);
1985
1986 const char *encoding(ivar_getTypeEncoding(ivar));
1987 if (encoding[0] == 'b') {
d3fa0357
JF
1988 unsigned length, shift;
1989 CYBitField(length, shift, self, ivar, encoding, offset);
ad22d2f8 1990 _assert(shift + length <= sizeof(uintptr_t) * 8);
d3fa0357
JF
1991 uintptr_t &field(*reinterpret_cast<uintptr_t *>(data));
1992 uintptr_t mask((1 << length) - 1);
1993 return CYCastJSValue(context, (field >> shift) & mask);
ad22d2f8
JF
1994 } else {
1995 Type_privateData type(pool, ivar_getTypeEncoding(ivar));
1996 return CYFromFFI(context, type.type_, type.GetFFI(), data);
1997 }
3c1c3635 1998 }
f33b048a 1999
3c1c3635 2000 return NULL;
55c6d6ab 2001} CYCatch(NULL) }
283e7e33 2002
3c1c3635
JF
2003static bool Internal_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
2004 Internal *internal(reinterpret_cast<Internal *>(JSObjectGetPrivate(object)));
2005 CYPool pool;
283e7e33 2006
3c1c3635
JF
2007 id self(internal->GetValue());
2008 const char *name(CYPoolCString(pool, context, property));
283e7e33 2009
aabea98c 2010 if (objc_ivar *ivar = object_getInstanceVariable(self, name, NULL)) {
d3fa0357
JF
2011 ptrdiff_t offset(ivar_getOffset(ivar));
2012 void *data(reinterpret_cast<uint8_t *>(self) + offset);
2013
2014 const char *encoding(ivar_getTypeEncoding(ivar));
2015 if (encoding[0] == 'b') {
2016 unsigned length, shift;
2017 CYBitField(length, shift, self, ivar, encoding, offset);
2018 _assert(shift + length <= sizeof(uintptr_t) * 8);
2019 uintptr_t &field(*reinterpret_cast<uintptr_t *>(data));
2020 uintptr_t mask((1 << length) - 1);
2021 field = field & ~(mask << shift) | (uintptr_t(CYCastDouble(context, value)) & mask) << shift;
2022 } else {
2023 Type_privateData type(pool, ivar_getTypeEncoding(ivar));
2024 CYPoolFFI(&pool, context, type.type_, type.GetFFI(), reinterpret_cast<uint8_t *>(self) + ivar_getOffset(ivar), value);
2025 return true;
2026 }
283e7e33 2027 }
f33b048a 2028
3c1c3635 2029 return false;
55c6d6ab 2030} CYCatch(false) }
85a33bf5 2031
3c1c3635
JF
2032static void Internal_getPropertyNames_(Class _class, JSPropertyNameAccumulatorRef names) {
2033 if (Class super = class_getSuperclass(_class))
2034 Internal_getPropertyNames_(super, names);
ea2d184c 2035
7c6c5b0a 2036#if OBJC_API_VERSION >= 2
3c1c3635 2037 unsigned int size;
aabea98c 2038 objc_ivar **data(class_copyIvarList(_class, &size));
3c1c3635
JF
2039 for (size_t i(0); i != size; ++i)
2040 JSPropertyNameAccumulatorAddName(names, CYJSString(ivar_getName(data[i])));
2041 free(data);
b5dd57dc
JF
2042#else
2043 if (objc_ivar_list *ivars = _class->ivars)
2044 for (int i(0); i != ivars->ivar_count; ++i)
2045 JSPropertyNameAccumulatorAddName(names, CYJSString(ivar_getName(&ivars->ivar_list[i])));
2046#endif
3c1c3635
JF
2047}
2048
2049static void Internal_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
2050 Internal *internal(reinterpret_cast<Internal *>(JSObjectGetPrivate(object)));
2051 CYPool pool;
ea2d184c 2052
3c1c3635
JF
2053 id self(internal->GetValue());
2054 Class _class(object_getClass(self));
7ba62cfd 2055
3c1c3635 2056 Internal_getPropertyNames_(_class, names);
7ba62cfd 2057}
ea2d184c 2058
62d94d32 2059static JSValueRef Internal_callAsFunction_$cya(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
3c1c3635
JF
2060 Internal *internal(reinterpret_cast<Internal *>(JSObjectGetPrivate(object)));
2061 return internal->GetOwner();
62d94d32 2062} CYCatch(NULL) }
c239b9f8 2063
3c1c3635
JF
2064static JSValueRef ObjectiveC_Classes_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2065 CYPool pool;
b799113b 2066 NSString *name(CYCastNSString(&pool, context, property));
3c1c3635
JF
2067 if (Class _class = NSClassFromString(name))
2068 return CYMakeInstance(context, _class, true);
2069 return NULL;
55c6d6ab 2070} CYCatch(NULL) }
3c1c3635 2071
c239b9f8 2072static void ObjectiveC_Classes_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
aabea98c 2073#ifdef __APPLE__
c239b9f8
JF
2074 size_t size(objc_getClassList(NULL, 0));
2075 Class *data(reinterpret_cast<Class *>(malloc(sizeof(Class) * size)));
2076
2077 get:
2078 size_t writ(objc_getClassList(data, size));
2079 if (size < writ) {
2080 size = writ;
2081 if (Class *copy = reinterpret_cast<Class *>(realloc(data, sizeof(Class) * writ))) {
2082 data = copy;
2083 goto get;
2084 } else goto done;
2085 }
2086
2087 for (size_t i(0); i != writ; ++i)
2088 JSPropertyNameAccumulatorAddName(names, CYJSString(class_getName(data[i])));
2089
2090 done:
2091 free(data);
aabea98c
JF
2092#else
2093 void *state(NULL);
2094 while (Class _class = objc_next_class(&state))
2095 JSPropertyNameAccumulatorAddName(names, CYJSString(class_getName(_class)));
2096#endif
c239b9f8
JF
2097}
2098
7c6c5b0a 2099#if OBJC_API_VERSION >= 2
3c1c3635 2100static JSValueRef ObjectiveC_Image_Classes_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
c239b9f8
JF
2101 const char *internal(reinterpret_cast<const char *>(JSObjectGetPrivate(object)));
2102
3c1c3635
JF
2103 CYPool pool;
2104 const char *name(CYPoolCString(pool, context, property));
2105 unsigned int size;
2106 const char **data(objc_copyClassNamesForImage(internal, &size));
2107 JSValueRef value;
2108 for (size_t i(0); i != size; ++i)
2109 if (strcmp(name, data[i]) == 0) {
2110 if (Class _class = objc_getClass(name)) {
2111 value = CYMakeInstance(context, _class, true);
2112 goto free;
2113 } else
2114 break;
2115 }
2116 value = NULL;
2117 free:
2118 free(data);
2119 return value;
55c6d6ab 2120} CYCatch(NULL) }
c239b9f8
JF
2121
2122static void ObjectiveC_Image_Classes_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
2123 const char *internal(reinterpret_cast<const char *>(JSObjectGetPrivate(object)));
2124 unsigned int size;
2125 const char **data(objc_copyClassNamesForImage(internal, &size));
2126 for (size_t i(0); i != size; ++i)
2127 JSPropertyNameAccumulatorAddName(names, CYJSString(data[i]));
2128 free(data);
2129}
2130
3c1c3635
JF
2131static JSValueRef ObjectiveC_Images_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2132 CYPool pool;
2133 const char *name(CYPoolCString(pool, context, property));
2134 unsigned int size;
2135 const char **data(objc_copyImageNames(&size));
2136 for (size_t i(0); i != size; ++i)
2137 if (strcmp(name, data[i]) == 0) {
2138 name = data[i];
2139 goto free;
2140 }
2141 name = NULL;
2142 free:
2143 free(data);
2144 if (name == NULL)
2145 return NULL;
2146 JSObjectRef value(JSObjectMake(context, NULL, NULL));
2147 CYSetProperty(context, value, CYJSString("classes"), JSObjectMake(context, ObjectiveC_Image_Classes_, const_cast<char *>(name)));
2148 return value;
55c6d6ab 2149} CYCatch(NULL) }
c239b9f8
JF
2150
2151static void ObjectiveC_Images_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
2152 unsigned int size;
2153 const char **data(objc_copyImageNames(&size));
2154 for (size_t i(0); i != size; ++i)
2155 JSPropertyNameAccumulatorAddName(names, CYJSString(data[i]));
2156 free(data);
2157}
aabea98c 2158#endif
c239b9f8 2159
3c1c3635
JF
2160static JSValueRef ObjectiveC_Protocols_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2161 CYPool pool;
aabea98c
JF
2162 const char *name(CYPoolCString(pool, context, property));
2163 if (Protocol *protocol = objc_getProtocol(name))
3c1c3635
JF
2164 return CYMakeInstance(context, protocol, true);
2165 return NULL;
55c6d6ab 2166} CYCatch(NULL) }
c239b9f8
JF
2167
2168static void ObjectiveC_Protocols_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
7c6c5b0a 2169#if OBJC_API_VERSION >= 2
c239b9f8
JF
2170 unsigned int size;
2171 Protocol **data(objc_copyProtocolList(&size));
2172 for (size_t i(0); i != size; ++i)
2173 JSPropertyNameAccumulatorAddName(names, CYJSString(protocol_getName(data[i])));
2174 free(data);
aabea98c
JF
2175#else
2176 // XXX: fix this!
2177#endif
c239b9f8 2178}
707bcb93 2179
26ef7a82
JF
2180static JSValueRef ObjectiveC_Constants_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2181 CYPool pool;
2182 CYUTF8String name(CYPoolUTF8String(pool, context, property));
2183 if (name == "nil")
2184 return Instance::Make(context, nil);
2185 return NULL;
55c6d6ab 2186} CYCatch(NULL) }
26ef7a82
JF
2187
2188static void ObjectiveC_Constants_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
2189 JSPropertyNameAccumulatorAddName(names, CYJSString("nil"));
2190}
2191
aabea98c 2192#ifdef __APPLE__
5e7d5188
JF
2193#if defined(__i386__) || defined(__x86_64__)
2194#define OBJC_MAX_STRUCT_BY_VALUE 8
2195static int struct_forward_array[] = {
2196 0, 0, 0, 1, 0, 1, 1, 1, 0 };
2197#elif defined(__arm__)
2198#define OBJC_MAX_STRUCT_BY_VALUE 1
2199static int struct_forward_array[] = {
2200 0, 0 };
5f39cfcc
JF
2201#elif defined(__arm64__)
2202#define CY_NO_STRET
5e7d5188
JF
2203#else
2204#error missing objc-runtime-info
2205#endif
2206
5f39cfcc 2207#ifndef CY_NO_STRET
534fb6da 2208static bool stret(ffi_type *ffi_type) {
04450da0
JF
2209 return ffi_type->type == FFI_TYPE_STRUCT && (
2210 ffi_type->size > OBJC_MAX_STRUCT_BY_VALUE ||
2211 struct_forward_array[ffi_type->size] != 0
2212 );
2213}
aabea98c 2214#endif
5f39cfcc 2215#endif
b09da87b 2216
9d512587 2217JSValueRef CYSendMessage(CYPool &pool, JSContextRef context, id self, Class _class, SEL _cmd, size_t count, const JSValueRef arguments[], bool initialize) {
7ba62cfd 2218 const char *type;
ea2d184c 2219
cacd1a88
JF
2220 if (_class == NULL)
2221 _class = object_getClass(self);
2222
aabea98c
JF
2223 IMP imp;
2224
2225 if (objc_method *method = class_getInstanceMethod(_class, _cmd)) {
2226 imp = method_getImplementation(method);
4afefdd9 2227 type = method_getTypeEncoding(method);
aabea98c
JF
2228 } else {
2229 imp = NULL;
2230
3c1c3635
JF
2231 CYPoolTry {
2232 NSMethodSignature *method([self methodSignatureForSelector:_cmd]);
2233 if (method == nil)
37954781 2234 throw CYJSError(context, "unrecognized selector %s sent to object %p", sel_getName(_cmd), self);
3c1c3635
JF
2235 type = CYPoolCString(pool, context, [method _typeString]);
2236 } CYPoolCatch(NULL)
4afefdd9
JF
2237 }
2238
2239 void *setup[2];
f623c5d8 2240 setup[0] = &self;
4afefdd9
JF
2241 setup[1] = &_cmd;
2242
2243 sig::Signature signature;
f33b048a 2244 sig::Parse(pool, &signature, type, &Structor_);
4afefdd9 2245
0add079d
JF
2246 size_t used(count + 3);
2247 if (used > signature.count) {
2248 sig::Element *elements(new (pool) sig::Element[used]);
2249 memcpy(elements, signature.elements, used * sizeof(sig::Element));
2250
2251 for (size_t index(signature.count); index != used; ++index) {
2252 sig::Element *element(&elements[index]);
2253 element->name = NULL;
2254 element->offset = _not(size_t);
2255
2256 sig::Type *type(new (pool) sig::Type);
2257 memset(type, 0, sizeof(*type));
2258 type->primitive = sig::object_P;
2259 element->type = type;
2260 }
2261
2262 signature.elements = elements;
2263 signature.count = used;
2264 }
2265
4afefdd9
JF
2266 ffi_cif cif;
2267 sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif);
2268
f623c5d8 2269 if (imp == NULL) {
aabea98c 2270#ifdef __APPLE__
5f39cfcc 2271#ifndef CY_NO_STRET
aabea98c
JF
2272 if (stret(cif.rtype))
2273 imp = class_getMethodImplementation_stret(_class, _cmd);
2274 else
5f39cfcc 2275#endif
aabea98c
JF
2276 imp = class_getMethodImplementation(_class, _cmd);
2277#else
f623c5d8 2278 objc_super super = {self, _class};
aabea98c
JF
2279 imp = objc_msg_lookup_super(&super, _cmd);
2280#endif
f623c5d8 2281 }
aabea98c
JF
2282
2283 void (*function)() = reinterpret_cast<void (*)()>(imp);
9d512587
JF
2284 return CYCallFunction(pool, context, 2, setup, count, arguments, initialize, &signature, &cif, function);
2285}
367eebb1 2286
4696a568 2287static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[]) {
3c1c3635 2288 if (count < 2)
37954781 2289 throw CYJSError(context, "too few arguments to objc_msgSend");
367eebb1 2290
478d4ed0
JF
2291 CYPool pool;
2292
2b52f27e
JF
2293 bool uninitialized;
2294
4afefdd9
JF
2295 id self;
2296 SEL _cmd;
cacd1a88 2297 Class _class;
4afefdd9 2298
3c1c3635
JF
2299 if (JSValueIsObjectOfClass(context, arguments[0], Super_)) {
2300 cy::Super *internal(reinterpret_cast<cy::Super *>(JSObjectGetPrivate((JSObjectRef) arguments[0])));
2301 self = internal->GetValue();
2302 _class = internal->class_;;
2303 uninitialized = false;
8150077d 2304 } else if (CYJSValueIsNSObject(context, arguments[0])) {
3c1c3635
JF
2305 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate((JSObjectRef) arguments[0])));
2306 self = internal->GetValue();
2307 _class = nil;
2308 uninitialized = internal->IsUninitialized();
2309 if (uninitialized)
2310 internal->value_ = nil;
2311 } else {
b799113b 2312 self = CYCastNSObject(&pool, context, arguments[0]);
3c1c3635
JF
2313 _class = nil;
2314 uninitialized = false;
2315 }
2b52f27e 2316
3c1c3635
JF
2317 if (self == nil)
2318 return CYJSNull(context);
7ba62cfd 2319
3c1c3635 2320 _cmd = CYCastSEL(context, arguments[1]);
ea2d184c 2321
9d512587 2322 return CYSendMessage(pool, context, self, _class, _cmd, count - 2, arguments + 2, uninitialized);
4696a568
JF
2323}
2324
2325static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2326 return $objc_msgSend(context, object, _this, count, arguments);
55c6d6ab 2327} CYCatch(NULL) }
7ba62cfd 2328
62d94d32 2329static JSValueRef Selector_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
dea834b0
JF
2330 JSValueRef setup[count + 2];
2331 setup[0] = _this;
2332 setup[1] = object;
4afefdd9 2333 memcpy(setup + 2, arguments, sizeof(JSValueRef) * count);
4696a568 2334 return $objc_msgSend(context, NULL, NULL, count + 2, setup);
62d94d32 2335} CYCatch(NULL) }
dea834b0 2336
62d94d32 2337static JSValueRef Message_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
dc68b74c
JF
2338 CYPool pool;
2339 Message_privateData *internal(reinterpret_cast<Message_privateData *>(JSObjectGetPrivate(object)));
2340
2341 // XXX: handle Instance::Uninitialized?
b799113b 2342 id self(CYCastNSObject(&pool, context, _this));
dc68b74c
JF
2343
2344 void *setup[2];
2345 setup[0] = &self;
2346 setup[1] = &internal->sel_;
2347
9d512587 2348 return CYCallFunction(pool, context, 2, setup, count, arguments, false, &internal->signature_, &internal->cif_, internal->GetValue());
62d94d32 2349} CYCatch(NULL) }
dc68b74c 2350
3c1c3635
JF
2351static JSObjectRef Super_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2352 if (count != 2)
37954781 2353 throw CYJSError(context, "incorrect number of arguments to Super constructor");
4afefdd9 2354 CYPool pool;
b799113b 2355 id self(CYCastNSObject(&pool, context, arguments[0]));
3c1c3635
JF
2356 Class _class(CYCastClass(pool, context, arguments[1]));
2357 return cy::Super::Make(context, self, _class);
55c6d6ab 2358} CYCatch(NULL) }
bce8339b 2359
3c1c3635
JF
2360static JSObjectRef Selector_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2361 if (count != 1)
37954781
JF
2362 throw CYJSError(context, "incorrect number of arguments to Selector constructor");
2363 CYPool pool;
2364 const char *name(CYPoolCString(pool, context, arguments[0]));
3c1c3635 2365 return CYMakeSelector(context, sel_registerName(name));
55c6d6ab 2366} CYCatch(NULL) }
7b184c00 2367
3c1c3635
JF
2368static JSObjectRef Instance_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2369 if (count > 1)
37954781 2370 throw CYJSError(context, "incorrect number of arguments to Instance constructor");
3c1c3635 2371 id self(count == 0 ? nil : CYCastPointer<id>(context, arguments[0]));
15024d7e 2372 return CYMakeInstance(context, self, false);
55c6d6ab 2373} CYCatch(NULL) }
ea2d184c 2374
62d94d32 2375static JSValueRef CYValue_getProperty_value(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
61933e16
JF
2376 CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(object)));
2377 return CYCastJSValue(context, reinterpret_cast<uintptr_t>(internal->value_));
62d94d32 2378} CYCatch(NULL) }
04450da0 2379
62d94d32 2380static JSValueRef CYValue_callAsFunction_$cya(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
7b184c00
JF
2381 CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this)));
2382 Type_privateData *typical(internal->GetType());
2383
2384 sig::Type *type;
2385 ffi_type *ffi;
2386
2387 if (typical == NULL) {
2388 type = NULL;
2389 ffi = NULL;
2390 } else {
2391 type = typical->type_;
2392 ffi = typical->ffi_;
2393 }
2394
53ba31e9 2395 return CYMakePointer(context, &internal->value_, _not(size_t), type, ffi, object);
62d94d32 2396} CYCatch(NULL) }
4afefdd9 2397
62d94d32 2398static JSValueRef Instance_getProperty_constructor(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
dc68b74c 2399 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
ec599edf 2400 return Instance::Make(context, (id) object_getClass(internal->GetValue()));
62d94d32 2401} CYCatch(NULL) }
dc68b74c 2402
2f1295ff 2403static JSValueRef Instance_getProperty_prototype(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
365abb0a
JF
2404 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
2405 id self(internal->GetValue());
2406 if (!CYIsClass(self))
2407 return CYJSUndefined(context);
3c1c3635 2408 return CYGetClassPrototype(context, self);
55c6d6ab 2409} CYCatch(NULL) }
365abb0a 2410
62d94d32 2411static JSValueRef Instance_getProperty_messages(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
dc68b74c
JF
2412 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
2413 id self(internal->GetValue());
b5dd57dc 2414 if (!CYIsClass(self))
dc68b74c 2415 return CYJSUndefined(context);
b5dd57dc 2416 return Messages::Make(context, (Class) self);
62d94d32 2417} CYCatch(NULL) }
dc68b74c 2418
3c1c3635 2419static JSValueRef Instance_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
8150077d 2420 if (!CYJSValueIsNSObject(context, _this))
365abb0a
JF
2421 return NULL;
2422
7b184c00 2423 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
dd18424c 2424 return CYCastJSValue(context, CYJSString(context, CYCastNSCYON(internal->GetValue(), false)));
55c6d6ab 2425} CYCatch(NULL) }
7b184c00 2426
3c1c3635 2427static JSValueRef Instance_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
8150077d 2428 if (!CYJSValueIsNSObject(context, _this))
365abb0a
JF
2429 return NULL;
2430
7b184c00 2431 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
e23a9070 2432 id value(internal->GetValue());
7b184c00 2433
3c1c3635 2434 CYPoolTry {
b5dd57dc
JF
2435 NSString *key;
2436 if (count == 0)
2437 key = nil;
2438 else
2439 key = CYCastNSString(NULL, context, CYJSString(context, arguments[0]));
e23a9070
JF
2440
2441 if (!CYImplements(value, object_getClass(value), @selector(cy$toJSON:inContext:)))
2442 return CYJSUndefined(context);
2443 else if (JSValueRef json = [value cy$toJSON:key inContext:context])
2444 return json;
2445 else
2446 return CYCastJSValue(context, CYJSString(context, [value description]));
3c1c3635 2447 } CYPoolCatch(NULL)
55c6d6ab 2448} CYCatch(NULL) return /*XXX*/ NULL; }
b4aa79af 2449
c30687a7 2450static JSValueRef Instance_callAsFunction_valueOf(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
8150077d 2451 if (!CYJSValueIsNSObject(context, _this))
c30687a7
JF
2452 return NULL;
2453
2454 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
95221eed
JF
2455 id value(internal->GetValue());
2456
88c6482c 2457 if (![value respondsToSelector:@selector(cy$valueOfInContext:)])
95221eed
JF
2458 return _this;
2459
88c6482c 2460 if (JSValueRef result = [value cy$valueOfInContext:context])
95221eed
JF
2461 return result;
2462
2463 return _this;
55c6d6ab 2464} CYCatch(NULL) return /*XXX*/ NULL; }
20ded97a
JF
2465
2466static JSValueRef Instance_callAsFunction_toPointer(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
8150077d 2467 if (!CYJSValueIsNSObject(context, _this))
20ded97a
JF
2468 return NULL;
2469
2470 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
2471 // XXX: but... but... THIS ISN'T A POINTER! :(
2472 return CYCastJSValue(context, reinterpret_cast<uintptr_t>(internal->GetValue()));
55c6d6ab 2473} CYCatch(NULL) return /*XXX*/ NULL; }
c30687a7 2474
3c1c3635 2475static JSValueRef Instance_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
8150077d 2476 if (!CYJSValueIsNSObject(context, _this))
365abb0a
JF
2477 return NULL;
2478
9e562cfc 2479 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
7db9993a 2480 id value(internal->GetValue());
6d056e33 2481
3c1c3635
JF
2482 CYPoolTry {
2483 // XXX: this seems like a stupid implementation; what if it crashes? why not use the CYONifier backend?
6d056e33 2484 return CYCastJSValue(context, CYJSString(context, [value description]));
3c1c3635 2485 } CYPoolCatch(NULL)
55c6d6ab 2486} CYCatch(NULL) return /*XXX*/ NULL; }
478d4ed0 2487
b63701b2 2488static JSValueRef Class_callAsFunction_pointerTo(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
80ea020e
JF
2489 if (!CYJSValueIsNSObject(context, _this))
2490 return NULL;
2491
2492 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
2493 id value(internal->GetValue());
2494
2495 if (!CYIsClass(value))
2496 CYThrow("non-Class object cannot be used as Type");
2497
2498 // XXX: this is a very silly implementation
2499
2500 std::ostringstream type;
2501 type << "@\"";
2502 type << class_getName(value);
2503 type << "\"";
2504
2505 CYPoolTry {
2506 return CYMakeType(context, type.str().c_str());
2507 } CYPoolCatch(NULL)
55c6d6ab 2508} CYCatch(NULL) return /*XXX*/ NULL; }
80ea020e 2509
3c1c3635 2510static JSValueRef Selector_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
9e562cfc 2511 Selector_privateData *internal(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate(_this)));
3c1c3635 2512 return CYCastJSValue(context, sel_getName(internal->GetValue()));
55c6d6ab 2513} CYCatch(NULL) }
478d4ed0 2514
62d94d32 2515static JSValueRef Selector_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
b4aa79af 2516 return Selector_callAsFunction_toString(context, object, _this, count, arguments, exception);
62d94d32 2517} CYCatch(NULL) }
b4aa79af 2518
3c1c3635 2519static JSValueRef Selector_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
7b184c00
JF
2520 Selector_privateData *internal(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate(_this)));
2521 const char *name(sel_getName(internal->GetValue()));
2522
3c1c3635 2523 CYPoolTry {
95678376
JF
2524 NSString *string([NSString stringWithFormat:@"@selector(%s)", name]);
2525 return CYCastJSValue(context, CYJSString(context, string));
3c1c3635 2526 } CYPoolCatch(NULL)
55c6d6ab 2527} CYCatch(NULL) return /*XXX*/ NULL; }
e5bc40db 2528
3c1c3635
JF
2529static JSValueRef Selector_callAsFunction_type(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2530 if (count != 1)
37954781
JF
2531 throw CYJSError(context, "incorrect number of arguments to Selector.type");
2532
3c1c3635
JF
2533 CYPool pool;
2534 Selector_privateData *internal(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate(_this)));
37954781
JF
2535 SEL sel(internal->GetValue());
2536
2537 objc_method *method;
2538 if (Class _class = CYCastClass(pool, context, arguments[0]))
2539 method = class_getInstanceMethod(_class, sel);
2540 else
2541 method = NULL;
2542
2543 if (const char *type = CYPoolTypeEncoding(pool, context, sel, method))
2544 return CYCastJSValue(context, CYJSString(type));
e5bc40db 2545
3c1c3635 2546 return CYJSNull(context);
55c6d6ab 2547} CYCatch(NULL) }
e5bc40db 2548
856b8cd0 2549static JSStaticValue Selector_staticValues[2] = {
61933e16 2550 {"value", &CYValue_getProperty_value, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete},
04450da0
JF
2551 {NULL, NULL, NULL, 0}
2552};
953647c1 2553
365abb0a 2554static JSStaticValue Instance_staticValues[5] = {
9e562cfc 2555 {"constructor", &Instance_getProperty_constructor, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
365abb0a 2556 {"messages", &Instance_getProperty_messages, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2f1295ff 2557 {"prototype", &Instance_getProperty_prototype, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
9e562cfc 2558 {"value", &CYValue_getProperty_value, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
9b5527f0
JF
2559 {NULL, NULL, NULL, 0}
2560};
2561
b63701b2 2562static JSStaticFunction Instance_staticFunctions[7] = {
7b184c00 2563 {"$cya", &CYValue_callAsFunction_$cya, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
b4aa79af
JF
2564 {"toCYON", &Instance_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2565 {"toJSON", &Instance_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
95221eed 2566 {"valueOf", &Instance_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
20ded97a 2567 {"toPointer", &Instance_callAsFunction_toPointer, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
478d4ed0 2568 {"toString", &Instance_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
b63701b2
JF
2569 {NULL, NULL, 0}
2570};
2571
2572static JSStaticFunction Class_staticFunctions[2] = {
2573 {"pointerTo", &Class_callAsFunction_pointerTo, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
478d4ed0
JF
2574 {NULL, NULL, 0}
2575};
2576
9b5527f0
JF
2577static JSStaticFunction Internal_staticFunctions[2] = {
2578 {"$cya", &Internal_callAsFunction_$cya, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2579 {NULL, NULL, 0}
2580};
2581
b4aa79af
JF
2582static JSStaticFunction Selector_staticFunctions[5] = {
2583 {"toCYON", &Selector_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2584 {"toJSON", &Selector_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
478d4ed0 2585 {"toString", &Selector_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
b09da87b
JF
2586 {"type", &Selector_callAsFunction_type, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2587 {NULL, NULL, 0}
2588};
ea2d184c 2589
e23a9070 2590#ifdef __APPLE__
f1b5a47f 2591JSValueRef NSCFType$cy$toJSON$inContext$(id self, SEL sel, JSValueRef key, JSContextRef context) { CYObjectiveTry_ {
e23a9070
JF
2592 return CYCastJSValue(context, [(NSString *) CFCopyDescription((CFTypeRef) self) autorelease]);
2593} CYObjectiveCatch }
2594#endif
2595
3c9f7e22 2596void CYObjectiveC_Initialize() { /*XXX*/ JSContextRef context(NULL); CYPoolTry {
c44063e0
JF
2597 $objc_setAssociatedObject = reinterpret_cast<void (*)(id, void *, id value, objc_AssociationPolicy)>(dlsym(RTLD_DEFAULT, "objc_setAssociatedObject"));
2598 $objc_getAssociatedObject = reinterpret_cast<id (*)(id, void *)>(dlsym(RTLD_DEFAULT, "objc_getAssociatedObject"));
2599 $objc_removeAssociatedObjects = reinterpret_cast<void (*)(id)>(dlsym(RTLD_DEFAULT, "objc_removeAssociatedObjects"));
2600
b799113b 2601 CYPool &pool(CYGetGlobalPool());
37954781 2602
807a88be
JF
2603 Object_type = new(pool) Type_privateData("@");
2604 Selector_type = new(pool) Type_privateData(":");
7b184c00 2605
30c4d7e0
JF
2606 NSArray_ = objc_getClass("NSArray");
2607 NSBlock_ = objc_getClass("NSBlock");
2608 NSDictionary_ = objc_getClass("NSDictionary");
2609 NSString_ = objc_getClass("NSString");
2610 Object_ = objc_getClass("Object");
2611
b53b30c1 2612#ifdef __APPLE__
0fe4a14b
JF
2613 // XXX: apparently, iOS now has both of these
2614 NSCFBoolean_ = objc_getClass("__NSCFBoolean");
18ed94e4 2615 if (NSCFBoolean_ == nil)
0fe4a14b 2616 NSCFBoolean_ = objc_getClass("NSCFBoolean");
18ed94e4 2617
c239b9f8 2618 NSCFType_ = objc_getClass("NSCFType");
30c4d7e0 2619
b5dd57dc 2620 NSZombie_ = objc_getClass("_NSZombie_");
30c4d7e0
JF
2621
2622 banned_.insert(Object_);
2623 banned_.insert(objc_getClass("__NSAtom"));
2624 banned_.insert(objc_getClass("__NSGenericDeallocHandler"));
2625 banned_.insert(objc_getClass("NSMessageBuilder"));
2626 banned_.insert(objc_getClass("__NSMessageBuilder"));
c074e774
JF
2627#else
2628 NSBoolNumber_ = objc_getClass("NSBoolNumber");
b53b30c1
JF
2629#endif
2630
3c1c3635
JF
2631 JSClassDefinition definition;
2632
2633 definition = kJSClassDefinitionEmpty;
2634 definition.className = "Instance";
2635 definition.staticValues = Instance_staticValues;
2636 definition.staticFunctions = Instance_staticFunctions;
2637 definition.hasProperty = &Instance_hasProperty;
2638 definition.getProperty = &Instance_getProperty;
2639 definition.setProperty = &Instance_setProperty;
2640 definition.deleteProperty = &Instance_deleteProperty;
2641 definition.getPropertyNames = &Instance_getPropertyNames;
2642 definition.callAsConstructor = &Instance_callAsConstructor;
aaa3cd1e 2643 definition.callAsFunction = &Instance_callAsFunction;
3c1c3635 2644 definition.hasInstance = &Instance_hasInstance;
37954781 2645 definition.finalize = &CYFinalize;
3c1c3635
JF
2646 Instance_ = JSClassCreate(&definition);
2647
1fb9f0d0
JF
2648 definition.className = "ArrayInstance";
2649 ArrayInstance_ = JSClassCreate(&definition);
2650
3d79777a
JF
2651 definition.className = "FunctionInstance";
2652 FunctionInstance_ = JSClassCreate(&definition);
2653
1fb9f0d0
JF
2654 definition.className = "ObjectInstance";
2655 ObjectInstance_ = JSClassCreate(&definition);
2656
2657 definition.className = "StringInstance";
2658 StringInstance_ = JSClassCreate(&definition);
2659
b63701b2
JF
2660 definition = kJSClassDefinitionEmpty;
2661 definition.className = "Class";
2662 definition.staticFunctions = Class_staticFunctions;
2663 Class_ = JSClassCreate(&definition);
f5d7110c 2664
3c1c3635
JF
2665 definition = kJSClassDefinitionEmpty;
2666 definition.className = "Internal";
2667 definition.staticFunctions = Internal_staticFunctions;
2668 definition.hasProperty = &Internal_hasProperty;
2669 definition.getProperty = &Internal_getProperty;
2670 definition.setProperty = &Internal_setProperty;
2671 definition.getPropertyNames = &Internal_getPropertyNames;
37954781 2672 definition.finalize = &CYFinalize;
3c1c3635
JF
2673 Internal_ = JSClassCreate(&definition);
2674
2675 definition = kJSClassDefinitionEmpty;
2676 definition.className = "Message";
37954781 2677 definition.staticFunctions = cy::Functor::StaticFunctions;
3c1c3635 2678 definition.callAsFunction = &Message_callAsFunction;
37954781 2679 definition.finalize = &CYFinalize;
3c1c3635
JF
2680 Message_ = JSClassCreate(&definition);
2681
2682 definition = kJSClassDefinitionEmpty;
2683 definition.className = "Messages";
2684 definition.hasProperty = &Messages_hasProperty;
2685 definition.getProperty = &Messages_getProperty;
2686 definition.setProperty = &Messages_setProperty;
7c6c5b0a 2687#if 0 && OBJC_API_VERSION < 2
3c1c3635
JF
2688 definition.deleteProperty = &Messages_deleteProperty;
2689#endif
2690 definition.getPropertyNames = &Messages_getPropertyNames;
37954781 2691 definition.finalize = &CYFinalize;
3c1c3635
JF
2692 Messages_ = JSClassCreate(&definition);
2693
2694 definition = kJSClassDefinitionEmpty;
2695 definition.className = "Selector";
2696 definition.staticValues = Selector_staticValues;
2697 definition.staticFunctions = Selector_staticFunctions;
2698 definition.callAsFunction = &Selector_callAsFunction;
37954781 2699 definition.finalize = &CYFinalize;
3c1c3635
JF
2700 Selector_ = JSClassCreate(&definition);
2701
2702 definition = kJSClassDefinitionEmpty;
2703 definition.className = "Super";
2704 definition.staticFunctions = Internal_staticFunctions;
37954781 2705 definition.finalize = &CYFinalize;
3c1c3635
JF
2706 Super_ = JSClassCreate(&definition);
2707
2708 definition = kJSClassDefinitionEmpty;
2709 definition.className = "ObjectiveC::Classes";
2710 definition.getProperty = &ObjectiveC_Classes_getProperty;
2711 definition.getPropertyNames = &ObjectiveC_Classes_getPropertyNames;
2712 ObjectiveC_Classes_ = JSClassCreate(&definition);
2713
26ef7a82
JF
2714 definition = kJSClassDefinitionEmpty;
2715 definition.className = "ObjectiveC::Constants";
2716 definition.getProperty = &ObjectiveC_Constants_getProperty;
2717 definition.getPropertyNames = &ObjectiveC_Constants_getPropertyNames;
2718 ObjectiveC_Constants_ = JSClassCreate(&definition);
2719
7c6c5b0a 2720#if OBJC_API_VERSION >= 2
3c1c3635
JF
2721 definition = kJSClassDefinitionEmpty;
2722 definition.className = "ObjectiveC::Images";
2723 definition.getProperty = &ObjectiveC_Images_getProperty;
2724 definition.getPropertyNames = &ObjectiveC_Images_getPropertyNames;
2725 ObjectiveC_Images_ = JSClassCreate(&definition);
2726
2727 definition = kJSClassDefinitionEmpty;
2728 definition.className = "ObjectiveC::Image::Classes";
2729 definition.getProperty = &ObjectiveC_Image_Classes_getProperty;
2730 definition.getPropertyNames = &ObjectiveC_Image_Classes_getPropertyNames;
2731 ObjectiveC_Image_Classes_ = JSClassCreate(&definition);
3c9f7e22 2732#endif
3c1c3635 2733
3c9f7e22
JF
2734 definition = kJSClassDefinitionEmpty;
2735 definition.className = "ObjectiveC::Protocols";
2736 definition.getProperty = &ObjectiveC_Protocols_getProperty;
2737 definition.getPropertyNames = &ObjectiveC_Protocols_getPropertyNames;
2738 ObjectiveC_Protocols_ = JSClassCreate(&definition);
2739
3c9f7e22 2740#ifdef __APPLE__
f9393f36
JF
2741// XXX: this is horrible; there has to be a better way to do this
2742#ifdef __LP64__
2743 class_addMethod(NSCFType_, @selector(cy$toJSON:inContext:), reinterpret_cast<IMP>(&NSCFType$cy$toJSON$inContext$), "^{OpaqueJSValue=}32@0:8@16^{OpaqueJSContext=}24");
2744#else
e23a9070 2745 class_addMethod(NSCFType_, @selector(cy$toJSON:inContext:), reinterpret_cast<IMP>(&NSCFType$cy$toJSON$inContext$), "^{OpaqueJSValue=}16@0:4@8^{OpaqueJSContext=}12");
3c9f7e22 2746#endif
f9393f36 2747#endif
3c9f7e22
JF
2748} CYPoolCatch() }
2749
2750void CYObjectiveC_SetupContext(JSContextRef context) { CYPoolTry {
2751 JSObjectRef global(CYGetGlobalObject(context));
498c3570 2752 JSObjectRef cy(CYCastJSObject(context, CYGetProperty(context, global, cy_s)));
2385c806
JF
2753 JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
2754 JSObjectRef all(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("all"))));
26ef7a82 2755 JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls"))));
3c9f7e22
JF
2756
2757 JSObjectRef ObjectiveC(JSObjectMake(context, NULL, NULL));
2385c806 2758 CYSetProperty(context, cycript, CYJSString("ObjectiveC"), ObjectiveC);
3c9f7e22 2759
26ef7a82
JF
2760 JSObjectRef protocols(JSObjectMake(context, ObjectiveC_Protocols_, NULL));
2761 CYSetProperty(context, ObjectiveC, CYJSString("protocols"), protocols);
2762 CYArrayPush(context, alls, protocols);
2763
2764 JSObjectRef classes(JSObjectMake(context, ObjectiveC_Classes_, NULL));
2765 CYSetProperty(context, ObjectiveC, CYJSString("classes"), classes);
2766 CYArrayPush(context, alls, classes);
2767
2768 JSObjectRef constants(JSObjectMake(context, ObjectiveC_Constants_, NULL));
2769 CYSetProperty(context, ObjectiveC, CYJSString("constants"), constants);
2770 CYArrayPush(context, alls, constants);
3c9f7e22
JF
2771
2772#if OBJC_API_VERSION >= 2
3c1c3635 2773 CYSetProperty(context, ObjectiveC, CYJSString("images"), JSObjectMake(context, ObjectiveC_Images_, NULL));
aabea98c 2774#endif
3c1c3635 2775
b63701b2 2776 JSObjectRef Class(JSObjectMakeConstructor(context, Class_, NULL));
3c1c3635
JF
2777 JSObjectRef Instance(JSObjectMakeConstructor(context, Instance_, &Instance_new));
2778 JSObjectRef Message(JSObjectMakeConstructor(context, Message_, NULL));
2779 JSObjectRef Selector(JSObjectMakeConstructor(context, Selector_, &Selector_new));
2780 JSObjectRef Super(JSObjectMakeConstructor(context, Super_, &Super_new));
2781
498c3570
JF
2782 JSObjectRef Instance_prototype(CYCastJSObject(context, CYGetProperty(context, Instance, prototype_s)));
2783 CYSetProperty(context, cy, CYJSString("Instance_prototype"), Instance_prototype);
3c1c3635 2784
1fb9f0d0 2785 JSObjectRef ArrayInstance(JSObjectMakeConstructor(context, ArrayInstance_, NULL));
4a2eef6c
JF
2786 JSObjectRef ArrayInstance_prototype(CYCastJSObject(context, CYGetProperty(context, ArrayInstance, prototype_s)));
2787 CYSetProperty(context, cy, CYJSString("ArrayInstance_prototype"), ArrayInstance_prototype);
2788 JSObjectRef Array_prototype(CYGetCachedObject(context, CYJSString("Array_prototype")));
2789 JSObjectSetPrototype(context, ArrayInstance_prototype, Array_prototype);
2790
aaa3cd1e
JF
2791 JSObjectRef FunctionInstance(JSObjectMakeConstructor(context, FunctionInstance_, NULL));
2792 JSObjectRef FunctionInstance_prototype(CYCastJSObject(context, CYGetProperty(context, FunctionInstance, prototype_s)));
2793 CYSetProperty(context, cy, CYJSString("FunctionInstance_prototype"), FunctionInstance_prototype);
2794 JSObjectRef Function_prototype(CYGetCachedObject(context, CYJSString("Function_prototype")));
2795 JSObjectSetPrototype(context, FunctionInstance_prototype, Function_prototype);
2796
1fb9f0d0 2797 JSObjectRef ObjectInstance(JSObjectMakeConstructor(context, ObjectInstance_, NULL));
11f3e89e
JF
2798 JSObjectRef ObjectInstance_prototype(CYCastJSObject(context, CYGetProperty(context, ObjectInstance, prototype_s)));
2799 CYSetProperty(context, cy, CYJSString("ObjectInstance_prototype"), ObjectInstance_prototype);
2800 JSObjectRef Object_prototype(CYGetCachedObject(context, CYJSString("Object_prototype")));
2801 JSObjectSetPrototype(context, ObjectInstance_prototype, Object_prototype);
2802
1fb9f0d0 2803 JSObjectRef StringInstance(JSObjectMakeConstructor(context, StringInstance_, NULL));
6732f195
JF
2804 JSObjectRef StringInstance_prototype(CYCastJSObject(context, CYGetProperty(context, StringInstance, prototype_s)));
2805 CYSetProperty(context, cy, CYJSString("StringInstance_prototype"), StringInstance_prototype);
6732f195
JF
2806 JSObjectRef String_prototype(CYGetCachedObject(context, CYJSString("String_prototype")));
2807 JSObjectSetPrototype(context, StringInstance_prototype, String_prototype);
2808
b63701b2
JF
2809 JSObjectRef Class_prototype(CYCastJSObject(context, CYGetProperty(context, Class, prototype_s)));
2810 CYSetProperty(context, cy, CYJSString("Class_prototype"), Class_prototype);
2811 JSObjectSetPrototype(context, Class_prototype, Instance_prototype);
bc3080fd 2812
2385c806
JF
2813 CYSetProperty(context, cycript, CYJSString("Instance"), Instance);
2814 CYSetProperty(context, cycript, CYJSString("Selector"), Selector);
2815 CYSetProperty(context, cycript, CYJSString("Super"), Super);
3c1c3635 2816
f2f0d1d1
JF
2817 JSObjectRef box(JSObjectMakeFunctionWithCallback(context, CYJSString("box"), &Instance_box_callAsFunction));
2818 CYSetProperty(context, Instance, CYJSString("box"), box);
2819
8ad1528b 2820#if defined(__APPLE__) && defined(__arm__) && 0
98ea05a3 2821 CYSetProperty(context, all, CYJSString("objc_registerClassPair"), &objc_registerClassPair_, kJSPropertyAttributeDontEnum);
b5dd57dc
JF
2822#endif
2823
98ea05a3 2824 CYSetProperty(context, all, CYJSString("objc_msgSend"), &$objc_msgSend, kJSPropertyAttributeDontEnum);
3c1c3635 2825
498c3570
JF
2826 JSObjectSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Message, prototype_s)), Function_prototype);
2827 JSObjectSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Selector, prototype_s)), Function_prototype);
3c9f7e22 2828} CYPoolCatch() }
b5dd57dc
JF
2829
2830static CYHooks CYObjectiveCHooks = {
2831 &CYObjectiveC_ExecuteStart,
2832 &CYObjectiveC_ExecuteEnd,
b5dd57dc 2833 &CYObjectiveC_CallFunction,
3c9f7e22 2834 &CYObjectiveC_Initialize,
b5dd57dc
JF
2835 &CYObjectiveC_SetupContext,
2836 &CYObjectiveC_PoolFFI,
2837 &CYObjectiveC_FromFFI,
2838};
2839
2840struct CYObjectiveC {
2841 CYObjectiveC() {
2842 hooks_ = &CYObjectiveCHooks;
6faa533c
DWT
2843 // XXX: evil magic juju to make this actually take effect on a Mac when compiled with autoconf/libtool doom!
2844 _assert(hooks_ != NULL);
b5dd57dc
JF
2845 }
2846} CYObjectiveC;