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