1 /* Cycript - The Truly Universal Scripting Language
2 * Copyright (C) 2009-2016 Jay Freeman (saurik)
5 /* GNU Affero General Public License, Version 3 {{{ */
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.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
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/>.
22 #include "cycript.hpp"
32 #include <malloc/malloc.h>
33 #include <mach/mach.h>
36 #include <objc/message.h>
37 #include <objc/runtime.h>
40 #include <CoreFoundation/CoreFoundation.h>
41 #include <JavaScriptCore/JSStringRefCF.h>
44 #include <Foundation/Foundation.h>
49 #include "Functor.hpp"
50 #include "JavaScript.hpp"
52 #include "Execute.hpp"
54 #include "ObjectiveC/Internal.hpp"
55 #include "ObjectiveC/Syntax.hpp"
57 #define CYObjectiveTry_ { \
59 #define CYObjectiveTry { \
60 JSContextRef context(context_); \
62 #define CYObjectiveCatch \
63 catch (const CYException &error) { \
64 @throw CYCastNSObject(NULL, context, error.CastJSValue(context, "Error")); \
70 NSAutoreleasePool *_pool([[NSAutoreleasePool alloc] init]); \
72 #define CYPoolCatch(value) \
73 @catch (NSException *error) { \
74 _saved = [error retain]; \
75 throw CYJSError(context, CYCastJSValue(context, error)); \
80 [_saved autorelease]; \
86 #define CYSadCatch(value) \
87 @catch (NSException *error ) { \
88 throw CYJSError(context, CYCastJSValue(context, error)); \
92 #define _oassert(test) \
94 @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"_assert(" #test ")" userInfo:nil];
102 void (*invoke)(void *, ...);
106 struct BlockDescriptor1 {
107 unsigned long int reserved;
108 unsigned long int size;
111 struct BlockDescriptor2 {
112 void (*copy_helper)(BlockLiteral *dst, BlockLiteral *src);
113 void (*dispose_helper)(BlockLiteral *src);
116 struct BlockDescriptor3 {
117 const char *signature;
122 BLOCK_DEALLOCATING = 0x0001,
123 BLOCK_REFCOUNT_MASK = 0xfffe,
124 BLOCK_NEEDS_FREE = 1 << 24,
125 BLOCK_HAS_COPY_DISPOSE = 1 << 25,
126 BLOCK_HAS_CTOR = 1 << 26,
127 BLOCK_IS_GC = 1 << 27,
128 BLOCK_IS_GLOBAL = 1 << 28,
129 BLOCK_HAS_STRET = 1 << 29,
130 BLOCK_HAS_SIGNATURE = 1 << 30,
133 static bool CYIsClass(id self) {
134 return class_isMetaClass(object_getClass(self));
137 JSValueRef CYSendMessage(CYPool &pool, JSContextRef context, id self, Class super, SEL _cmd, size_t count, const JSValueRef arguments[], bool initialize);
139 /* Objective-C Pool Release {{{ */
140 void CYPoolRelease_(void *data) {
141 id object(reinterpret_cast<id>(data));
145 id CYPoolRelease_(CYPool *pool, id object) {
148 else if (pool == NULL)
149 return [object autorelease];
151 pool->atexit(CYPoolRelease_);
156 template <typename Type_>
157 Type_ CYPoolRelease(CYPool *pool, Type_ object) {
158 return (Type_) CYPoolRelease_(pool, (id) object);
161 /* Objective-C Strings {{{ */
162 CYUTF8String CYPoolUTF8String(CYPool &pool, JSContextRef context, NSString *value) {
163 size_t size([value maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
164 char *string(new(pool) char[size + 1]);
165 if (![value getCString:string maxLength:size encoding:NSUTF8StringEncoding])
166 throw CYJSError(context, "[NSString getCString:maxLength:encoding:] == NO");
167 return CYUTF8String(string, [value lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
170 const char *CYPoolCString(CYPool &pool, JSContextRef context, NSString *value) {
171 CYUTF8String utf8(CYPoolUTF8String(pool, context, value));
172 _assert(memchr(utf8.data, '\0', utf8.size) == NULL);
177 JSStringRef CYCopyJSString(JSContextRef context, NSString *value) {
178 return JSStringCreateWithCFString(reinterpret_cast<CFStringRef>(value));
182 JSStringRef CYCopyJSString(JSContextRef context, NSObject *value) {
185 // XXX: this definition scares me; is anyone using this?!
186 NSString *string([value description]);
188 return CYCopyJSString(context, string);
191 return CYCopyJSString(CYPoolUTF8String(pool, context, string));
195 NSString *CYCopyNSString(const CYUTF8String &value) {
197 return (NSString *) CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(value.data), value.size, kCFStringEncodingUTF8, true);
199 return [[NSString alloc] initWithBytes:value.data length:value.size encoding:NSUTF8StringEncoding];
203 NSString *CYCopyNSString(JSContextRef context, JSStringRef value) {
205 return (NSString *) JSStringCopyCFString(kCFAllocatorDefault, value);
208 return CYCopyNSString(CYPoolUTF8String(pool, context, value));
212 NSString *CYCopyNSString(JSContextRef context, JSValueRef value) {
213 return CYCopyNSString(context, CYJSString(context, value));
216 NSString *CYCastNSString(CYPool *pool, const CYUTF8String &value) {
217 return CYPoolRelease(pool, CYCopyNSString(value));
220 NSString *CYCastNSString(CYPool *pool, SEL sel) {
221 const char *name(sel_getName(sel));
222 return CYPoolRelease(pool, CYCopyNSString(CYUTF8String(name, strlen(name))));
225 NSString *CYCastNSString(CYPool *pool, JSContextRef context, JSStringRef value) {
226 return CYPoolRelease(pool, CYCopyNSString(context, value));
229 CYUTF8String CYCastUTF8String(NSString *value) {
230 NSData *data([value dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO]);
231 return CYUTF8String(reinterpret_cast<const char *>([data bytes]), [data length]);
235 JSValueRef CYCastJSValue(JSContextRef context, NSObject *value);
237 void CYThrow(JSContextRef context, NSException *error, JSValueRef *exception) {
238 if (exception == NULL)
240 *exception = CYCastJSValue(context, error);
243 size_t CYGetIndex(NSString *value) {
244 return CYGetIndex(CYCastUTF8String(value));
247 bool CYGetOffset(CYPool &pool, JSContextRef context, NSString *value, ssize_t &index) {
248 return CYGetOffset(CYPoolCString(pool, context, value), index);
251 static JSClassRef ArrayInstance_;
252 static JSClassRef BooleanInstance_;
253 static JSClassRef FunctionInstance_;
254 static JSClassRef NumberInstance_;
255 static JSClassRef ObjectInstance_;
256 static JSClassRef StringInstance_;
258 static JSClassRef ObjectiveC_Classes_;
259 static JSClassRef ObjectiveC_Constants_;
260 static JSClassRef ObjectiveC_Protocols_;
263 static JSClassRef ObjectiveC_Image_Classes_;
264 static JSClassRef ObjectiveC_Images_;
268 static Class __NSMallocBlock__;
269 static Class NSCFBoolean_;
270 static Class NSCFType_;
271 static Class NSGenericDeallocHandler_;
273 static Class NSBoolNumber_;
276 static Class NSArray_;
277 static Class NSBlock_;
278 static Class NSDictionary_;
279 static Class NSNumber_;
280 static Class NSString_;
281 static Class NSZombie_;
282 static Class Object_;
284 static JSValueRef Instance_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception);
286 JSValueRef Prototype::GetPrototype(JSContextRef context) const {
288 if (value_ == NSCFBoolean_)
290 if (value_ == NSBoolNumber_)
292 return CYGetCachedObject(context, CYJSString("BooleanInstance_prototype"));
293 if (value_ == NSArray_)
294 return CYGetCachedObject(context, CYJSString("ArrayInstance_prototype"));
295 if (value_ == NSBlock_)
296 return CYGetCachedObject(context, CYJSString("FunctionInstance_prototype"));
297 if (value_ == NSNumber_)
298 return CYGetCachedObject(context, CYJSString("NumberInstance_prototype"));
299 if (value_ == NSDictionary_)
300 return CYGetCachedObject(context, CYJSString("ObjectInstance_prototype"));
301 if (value_ == NSString_)
302 return CYGetCachedObject(context, CYJSString("StringInstance_prototype"));
304 if (Class super = class_getSuperclass(value_))
305 return CYPrivate<Prototype>::Cache(context, super);
306 return CYGetCachedObject(context, CYJSString("Instance_prototype"));
309 JSValueRef Constructor::GetPrototype(JSContextRef context) const {
310 if (Class super = class_getSuperclass(value_))
311 return CYPrivate<Constructor>::Cache(context, super);
312 return CYGetCachedObject(context, CYJSString("Constructor_prototype"));
315 bool CYIsKindOfClass(id object, Class _class) {
316 for (Class isa(object_getClass(object)); isa != NULL; isa = class_getSuperclass(isa))
322 JSValueRef Instance::GetPrototype(JSContextRef context) const {
323 return CYPrivate<Prototype>::Cache(context, object_getClass(value_));
326 JSClassRef Instance::GetClass(id object, Flags flags) {
327 return CYIsKindOfClass(object, NSBlock_) ? FunctionInstance_ : Instance::Class_;
330 Instance::Instance(id value, Flags flags) :
335 /*else if ([value retainCount] == NSUInteger(-1))
336 flags_ |= Instance::Permanent;*/
338 value_ = [value_ retain];
341 Instance::~Instance() {
346 struct Message_privateData :
349 static JSClassRef Class_;
353 Message_privateData(SEL sel, const char *type, IMP value) :
354 cy::Functor(reinterpret_cast<void (*)()>(value), type),
359 static JSObjectRef Make(JSContextRef context, SEL sel, const char *type, IMP value);
362 JSClassRef Message_privateData::Class_;
364 JSObjectRef CYMakeInstance(JSContextRef context, id object, Instance::Flags flags = Instance::None) {
365 _assert(object != nil);
368 JSWeakObjectMapRef weak(CYCastPointer<JSWeakObjectMapRef>(context, CYGetCachedValue(context, weak_s)));
370 if (weak != NULL && &JSWeakObjectMapGet != NULL)
371 if (JSObjectRef instance = JSWeakObjectMapGet(context, weak, object))
375 JSObjectRef instance;
376 if (CYIsClass(object) && !class_isMetaClass(object))
377 instance = CYPrivate<Constructor>::Cache(context, object);
379 instance = Instance::Make(context, object, flags);
382 if (weak != NULL && &JSWeakObjectMapSet != NULL)
383 JSWeakObjectMapSet(context, weak, object, instance);
389 @interface NSMethodSignature (Cycript)
390 - (NSString *) _typeString;
393 @interface NSObject (Cycript)
395 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context;
396 - (JSType) cy$JSType;
398 - (JSValueRef) cy$toJSON:(NSString *)key inContext:(JSContextRef)context;
399 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects;
401 - (bool) cy$hasProperty:(NSString *)name;
402 - (NSObject *) cy$getProperty:(NSString *)name;
403 - (JSValueRef) cy$getProperty:(NSString *)name inContext:(JSContextRef)context;
404 - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value;
405 - (bool) cy$deleteProperty:(NSString *)name;
406 - (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context;
408 + (bool) cy$hasImplicitProperties;
414 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context;
417 NSString *CYCastNSCYON(id value, bool objective, std::set<void *> &objects) {
418 _assert(value != nil);
420 Class _class(object_getClass(value));
422 if (class_isMetaClass(_class)) {
423 const char *name(class_getName(value));
424 if (class_isMetaClass(value))
425 return [NSString stringWithFormat:@"object_getClass(%s)", name];
427 return [NSString stringWithUTF8String:name];
430 if (_class == NSZombie_)
431 return [NSString stringWithFormat:@"<_NSZombie_: %p>", value];
433 SEL sel(@selector(cy$toCYON:inSet:));
435 if (objc_method *toCYON = class_getInstanceMethod(_class, sel))
436 return reinterpret_cast<NSString *(*)(id, SEL, bool, std::set<void *> &)>(method_getImplementation(toCYON))(value, sel, objective, objects);
437 else if (objc_method *methodSignatureForSelector = class_getInstanceMethod(_class, @selector(methodSignatureForSelector:)))
438 if (reinterpret_cast<NSMethodSignature *(*)(id, SEL, SEL)>(method_getImplementation(methodSignatureForSelector))(value, @selector(methodSignatureForSelector:), sel) != nil)
439 return [value cy$toCYON:objective inSet:objects];
441 return [NSString stringWithFormat:@"%@", value];
444 NSString *CYCastNSCYON(id value, bool objective, std::set<void *> *objects) {
446 return CYCastNSCYON(value, objective, *objects);
448 std::set<void *> objects;
449 return CYCastNSCYON(value, objective, objects);
453 struct PropertyAttributes {
458 const char *variable;
471 PropertyAttributes(objc_property_t property) :
483 name = property_getName(property);
484 const char *attributes(property_getAttributes(property));
486 for (char *token(pool_.strdup(attributes)), *next; token != NULL; token = next) {
487 if ((next = strchr(token, ',')) != NULL)
490 case 'R': readonly = true; break;
491 case 'C': copy = true; break;
492 case '&': retain = true; break;
493 case 'N': nonatomic = true; break;
494 case 'G': getter_ = token + 1; break;
495 case 'S': setter_ = token + 1; break;
496 case 'V': variable = token + 1; break;
500 /*if (variable == NULL) {
501 variable = property_getName(property);
502 size_t size(strlen(variable));
503 char *name(new(pool_) char[size + 2]);
505 memcpy(name + 1, variable, size);
506 name[size + 1] = '\0';
511 const char *Getter() {
513 getter_ = pool_.strdup(name);
517 const char *Setter() {
518 if (setter_ == NULL && !readonly) {
519 size_t length(strlen(name));
521 char *temp(new(pool_) char[length + 5]);
527 temp[3] = toupper(name[0]);
528 memcpy(temp + 4, name + 1, length - 1);
531 temp[length + 3] = ':';
532 temp[length + 4] = '\0';
541 @interface CYWebUndefined : NSObject {
544 + (CYWebUndefined *) undefined;
548 @implementation CYWebUndefined
550 + (CYWebUndefined *) undefined {
551 static CYWebUndefined *instance_([[CYWebUndefined alloc] init]);
557 #define WebUndefined CYWebUndefined
559 /* Bridge: CYJSObject {{{ */
560 @interface CYJSObject : NSMutableDictionary {
562 JSGlobalContextRef context_;
565 - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context;
567 - (NSUInteger) count;
568 - (id) objectForKey:(id)key;
569 - (NSEnumerator *) keyEnumerator;
570 - (void) setObject:(id)object forKey:(id)key;
571 - (void) removeObjectForKey:(id)key;
575 /* Bridge: CYJSArray {{{ */
576 @interface CYJSArray : NSMutableArray {
578 JSGlobalContextRef context_;
581 - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context;
583 - (NSUInteger) count;
584 - (id) objectAtIndex:(NSUInteger)index;
586 - (void) addObject:(id)anObject;
587 - (void) insertObject:(id)anObject atIndex:(NSUInteger)index;
588 - (void) removeLastObject;
589 - (void) removeObjectAtIndex:(NSUInteger)index;
590 - (void) replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
595 _finline bool CYJSValueIsNSObject(JSContextRef context, JSValueRef value) {
596 return JSValueIsObjectOfClass(context, value, Instance::Class_) || JSValueIsObjectOfClass(context, value, FunctionInstance_) || JSValueIsObjectOfClass(context, value, CYPrivate<Constructor>::Class_);
599 _finline bool CYJSValueIsInstanceOfCachedConstructor(JSContextRef context, JSValueRef value, JSStringRef cache) {
600 return _jsccall(JSValueIsInstanceOfConstructor, context, value, CYGetCachedObject(context, cache));
604 struct CYBlockDescriptor {
606 BlockDescriptor1 one_;
607 BlockDescriptor2 two_;
608 BlockDescriptor3 three_;
611 Closure_privateData *internal_;
614 void CYDisposeBlock(BlockLiteral *literal) {
615 delete reinterpret_cast<CYBlockDescriptor *>(literal->descriptor)->internal_;
618 static JSValueRef BlockAdapter_(JSContextRef context, size_t count, JSValueRef values[], JSObjectRef function) {
619 JSObjectRef _this(CYCastJSObject(context, values[0]));
620 return CYCallAsFunction(context, function, _this, count - 1, values + 1);
623 NSBlock *CYMakeBlock(JSContextRef context, JSObjectRef function, sig::Signature &signature) {
624 _assert(__NSMallocBlock__ != Nil);
625 BlockLiteral *literal(reinterpret_cast<BlockLiteral *>(malloc(sizeof(BlockLiteral))));
627 CYBlockDescriptor *descriptor(new CYBlockDescriptor);
628 memset(&descriptor->d_, 0, sizeof(descriptor->d_));
630 descriptor->internal_ = CYMakeFunctor_(context, function, signature, &BlockAdapter_);
631 literal->invoke = reinterpret_cast<void (*)(void *, ...)>(descriptor->internal_->value_);
633 literal->isa = __NSMallocBlock__;
634 literal->flags = BLOCK_HAS_SIGNATURE | BLOCK_HAS_COPY_DISPOSE | BLOCK_IS_GLOBAL;
635 literal->reserved = 0;
636 literal->descriptor = descriptor;
638 descriptor->d_.one_.size = sizeof(descriptor->d_);
639 descriptor->d_.two_.dispose_helper = &CYDisposeBlock;
640 descriptor->d_.three_.signature = sig::Unparse(*descriptor->internal_->pool_, &signature);
642 return reinterpret_cast<NSBlock *>(literal);
646 NSObject *CYCastNSObject(CYPool *pool, JSContextRef context, JSObjectRef object) {
647 if (CYJSValueIsNSObject(context, object)) {
648 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
649 return internal->value_;
652 bool array(CYJSValueIsInstanceOfCachedConstructor(context, object, Array_s));
653 id value(array ? [CYJSArray alloc] : [CYJSObject alloc]);
654 return CYPoolRelease(pool, [value initWithJSObject:object inContext:context]);
657 NSNumber *CYCopyNSNumber(JSContextRef context, JSValueRef value) {
658 return [[NSNumber alloc] initWithDouble:CYCastDouble(context, value)];
662 @interface NSBoolNumber : NSNumber {
667 id CYNSObject(CYPool *pool, JSContextRef context, JSValueRef value, bool cast) {
671 switch (JSType type = JSValueGetType(context, value)) {
672 case kJSTypeUndefined:
673 object = [WebUndefined undefined];
683 object = (id) (CYCastBool(context, value) ? kCFBooleanTrue : kCFBooleanFalse);
686 object = [[NSBoolNumber alloc] initWithBool:CYCastBool(context, value)];
692 object = CYCopyNSNumber(context, value);
697 object = CYCopyNSString(context, value);
702 // XXX: this might could be more efficient
703 object = CYCastNSObject(pool, context, (JSObjectRef) value);
708 throw CYJSError(context, "JSValueGetType() == 0x%x", type);
715 return CYPoolRelease(pool, object);
717 return [object retain];
720 NSObject *CYCastNSObject(CYPool *pool, JSContextRef context, JSValueRef value) {
721 return CYNSObject(pool, context, value, true);
724 NSObject *CYCopyNSObject(CYPool &pool, JSContextRef context, JSValueRef value) {
725 return CYNSObject(&pool, context, value, false);
728 /* Bridge: NSArray {{{ */
729 @implementation NSArray (Cycript)
732 return [[self mutableCopy] autorelease];
735 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
736 _oassert(objects.insert(self).second);
738 NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
739 [json appendString:@"@["];
743 for (id object in self) {
745 for (size_t index(0), count([self count]); index != count; ++index) {
746 id object([self objectAtIndex:index]);
749 [json appendString:@","];
752 if (object != nil && [object cy$JSType] != kJSTypeUndefined)
753 [json appendString:CYCastNSCYON(object, true, objects)];
755 [json appendString:@","];
760 [json appendString:@"]"];
764 - (bool) cy$hasProperty:(NSString *)name {
765 if ([name isEqualToString:@"length"])
768 size_t index(CYGetIndex(name));
769 if (index == _not(size_t) || index >= [self count])
770 return [super cy$hasProperty:name];
775 - (NSObject *) cy$getProperty:(NSString *)name {
776 size_t index(CYGetIndex(name));
777 if (index == _not(size_t) || index >= [self count])
778 return [super cy$getProperty:name];
780 return [self objectAtIndex:index];
783 - (JSValueRef) cy$getProperty:(NSString *)name inContext:(JSContextRef)context {
785 if ([name isEqualToString:@"length"])
786 return CYCastJSValue(context, [self count]);
789 return [super cy$getProperty:name inContext:context];
792 - (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
793 [super cy$getPropertyNames:names inContext:context];
795 for (size_t index(0), count([self count]); index != count; ++index) {
796 id object([self objectAtIndex:index]);
797 if (object == nil || [object cy$JSType] != kJSTypeUndefined) {
799 sprintf(name, "%zu", index);
800 JSPropertyNameAccumulatorAddName(names, CYJSString(name));
805 + (bool) cy$hasImplicitProperties {
811 /* Bridge: NSBlock {{{ */
813 @interface NSBlock : NSObject
817 static const char *CYBlockEncoding(NSBlock *self);
818 static bool CYBlockSignature(CYPool &pool, NSBlock *self, sig::Signature &signature);
820 @implementation NSBlock (Cycript)
822 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
826 if (!CYBlockSignature(pool, self, type.signature))
827 return [super cy$toCYON:objective inSet:objects];
828 _oassert(objects.insert(self).second);
830 CYType *typed((new(pool) CYTypeExpression(CYDecodeType(pool, &type)))->typed_);
831 CYTypeModifier *&modifier(CYGetLast(typed->modifier_));
832 CYTypeBlockWith *with(dynamic_cast<CYTypeBlockWith *>(modifier));
833 _assert(with != NULL);
834 CYObjCBlock *block(new(pool) CYObjCBlock(typed, with->parameters_, NULL));
837 std::ostringstream str;
839 CYOutput out(*str.rdbuf(), options);
840 block->Output(out, CYNoFlags);
842 std::string value(str.str());
843 return CYCastNSString(NULL, CYUTF8String(value.c_str(), value.size()));
849 /* Bridge: NSBoolNumber {{{ */
851 @implementation NSBoolNumber (Cycript)
853 - (JSType) cy$JSType {
854 return kJSTypeBoolean;
857 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
858 NSString *value([self boolValue] ? @"true" : @"false");
859 return objective ? value : [NSString stringWithFormat:@"@%@", value];
862 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
863 return CYCastJSValue(context, (bool) [self boolValue]);
869 /* Bridge: NSDictionary {{{ */
870 @implementation NSDictionary (Cycript)
873 return [[self mutableCopy] autorelease];
876 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
877 _oassert(objects.insert(self).second);
879 NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
880 [json appendString:@"@{"];
884 for (NSObject *key in self) {
886 NSEnumerator *keys([self keyEnumerator]);
887 while (NSObject *key = [keys nextObject]) {
890 [json appendString:@","];
893 [json appendString:CYCastNSCYON(key, true, objects)];
894 [json appendString:@":"];
895 NSObject *object([self objectForKey:key]);
896 [json appendString:CYCastNSCYON(object, true, objects)];
899 [json appendString:@"}"];
903 - (bool) cy$hasProperty:(NSString *)name {
904 return [self objectForKey:name] != nil;
907 - (NSObject *) cy$getProperty:(NSString *)name {
908 return [self objectForKey:name];
911 - (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
912 [super cy$getPropertyNames:names inContext:context];
915 for (NSObject *key in self) {
917 NSEnumerator *keys([self keyEnumerator]);
918 while (NSObject *key = [keys nextObject]) {
920 JSPropertyNameAccumulatorAddName(names, CYJSString(context, key));
924 + (bool) cy$hasImplicitProperties {
930 /* Bridge: NSMutableArray {{{ */
931 @implementation NSMutableArray (Cycript)
933 - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value {
934 if ([name isEqualToString:@"length"]) {
935 // XXX: is this not intelligent?
936 NSNumber *number(reinterpret_cast<NSNumber *>(value));
937 NSUInteger size([number unsignedIntegerValue]);
938 NSUInteger count([self count]);
940 [self removeObjectsInRange:NSMakeRange(size, count - size)];
941 else if (size != count) {
942 WebUndefined *undefined([WebUndefined undefined]);
943 for (size_t i(count); i != size; ++i)
944 [self addObject:undefined];
949 size_t index(CYGetIndex(name));
950 if (index == _not(size_t))
951 return [super cy$setProperty:name to:value];
953 id object(value ?: [NSNull null]);
955 size_t count([self count]);
957 [self replaceObjectAtIndex:index withObject:object];
959 if (index != count) {
960 WebUndefined *undefined([WebUndefined undefined]);
961 for (size_t i(count); i != index; ++i)
962 [self addObject:undefined];
965 [self addObject:object];
971 - (bool) cy$deleteProperty:(NSString *)name {
972 size_t index(CYGetIndex(name));
973 if (index == _not(size_t) || index >= [self count])
974 return [super cy$deleteProperty:name];
975 [self replaceObjectAtIndex:index withObject:[WebUndefined undefined]];
981 /* Bridge: NSMutableDictionary {{{ */
982 @implementation NSMutableDictionary (Cycript)
984 - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value {
985 [self setObject:(value ?: [NSNull null]) forKey:name];
989 - (bool) cy$deleteProperty:(NSString *)name {
990 if ([self objectForKey:name] == nil)
993 [self removeObjectForKey:name];
1000 /* Bridge: NSNumber {{{ */
1001 @implementation NSNumber (Cycript)
1003 - (JSType) cy$JSType {
1005 // XXX: this just seems stupid
1006 if ([self class] == NSCFBoolean_)
1007 return kJSTypeBoolean;
1009 return kJSTypeNumber;
1012 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
1013 NSString *value([self cy$JSType] != kJSTypeBoolean ? [self stringValue] : [self boolValue] ? @"true" : @"false");
1014 return objective ? value : [NSString stringWithFormat:@"@%@", value];
1017 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
1018 return [self cy$JSType] != kJSTypeBoolean ? CYCastJSValue(context, [self doubleValue]) : CYCastJSValue(context, static_cast<bool>([self boolValue]));
1019 } CYObjectiveCatch }
1023 /* Bridge: NSNull {{{ */
1024 @implementation NSNull (Cycript)
1026 - (JSType) cy$JSType {
1030 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
1031 NSString *value(@"null");
1032 return objective ? value : [NSString stringWithFormat:@"@%@", value];
1035 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
1036 return CYJSNull(context);
1037 } CYObjectiveCatch }
1041 /* Bridge: NSObject {{{ */
1042 @implementation NSObject (Cycript)
1048 - (JSValueRef) cy$toJSON:(NSString *)key inContext:(JSContextRef)context {
1049 return [self cy$valueOfInContext:context];
1052 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
1054 } CYObjectiveCatch }
1056 - (JSType) cy$JSType {
1057 return kJSTypeObject;
1060 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
1061 return [@"#" stringByAppendingString:[[self description] cy$toCYON:true inSet:objects]];
1064 - (bool) cy$hasProperty:(NSString *)name {
1068 - (NSObject *) cy$getProperty:(NSString *)name {
1072 - (JSValueRef) cy$getProperty:(NSString *)name inContext:(JSContextRef)context { CYObjectiveTry_ {
1073 if (NSObject *value = [self cy$getProperty:name])
1074 return CYCastJSValue(context, value);
1076 } CYObjectiveCatch }
1078 - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value {
1082 - (bool) cy$deleteProperty:(NSString *)name {
1086 - (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
1089 + (bool) cy$hasImplicitProperties {
1095 /* Bridge: NSOrderedSet {{{ */
1097 @implementation NSOrderedSet (Cycript)
1099 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
1100 _oassert(objects.insert(self).second);
1102 NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
1103 [json appendString:@"[NSOrderedSet orderedSetWithArray:"];
1104 [json appendString:CYCastNSCYON([self array], true, objects)];
1105 [json appendString:@"]]"];
1112 /* Bridge: NSProxy {{{ */
1113 @implementation NSProxy (Cycript)
1115 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
1116 return [[self description] cy$toCYON:objective inSet:objects];
1121 /* Bridge: NSSet {{{ */
1122 @implementation NSSet (Cycript)
1124 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
1125 _oassert(objects.insert(self).second);
1127 NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
1128 [json appendString:@"[NSSet setWithArray:"];
1129 [json appendString:CYCastNSCYON([self allObjects], true, objects)];
1130 [json appendString:@"]]"];
1136 /* Bridge: NSString {{{ */
1137 @implementation NSString (Cycript)
1140 return [[self copy] autorelease];
1143 - (JSType) cy$JSType {
1144 return kJSTypeString;
1147 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
1148 std::ostringstream str;
1151 CYUTF8String string(CYCastUTF8String(self));
1152 CYStringify(str, string.data, string.size, true);
1153 std::string value(str.str());
1154 return CYCastNSString(NULL, CYUTF8String(value.c_str(), value.size()));
1157 - (bool) cy$hasProperty:(NSString *)name {
1158 size_t index(CYGetIndex(name));
1159 if (index == _not(size_t) || index >= [self length])
1160 return [super cy$hasProperty:name];
1165 - (NSObject *) cy$getProperty:(NSString *)name {
1166 size_t index(CYGetIndex(name));
1167 if (index == _not(size_t) || index >= [self length])
1168 return [super cy$getProperty:name];
1170 return [self substringWithRange:NSMakeRange(index, 1)];
1173 - (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
1174 [super cy$getPropertyNames:names inContext:context];
1176 for (size_t index(0), length([self length]); index != length; ++index) {
1178 sprintf(name, "%zu", index);
1179 JSPropertyNameAccumulatorAddName(names, CYJSString(name));
1183 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
1184 return CYCastJSValue(context, CYJSString(context, self));
1185 } CYObjectiveCatch }
1189 /* Bridge: WebUndefined {{{ */
1190 @implementation WebUndefined (Cycript)
1192 - (JSType) cy$JSType {
1193 return kJSTypeUndefined;
1196 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
1197 NSString *value(@"undefined");
1198 return value; // XXX: maybe use the below code, adding @undefined?
1199 //return objective ? value : [NSString stringWithFormat:@"@%@", value];
1202 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
1203 return CYJSUndefined(context);
1204 } CYObjectiveCatch }
1209 Class CYCastClass(CYPool &pool, JSContextRef context, JSValueRef value) {
1210 id self(CYCastNSObject(&pool, context, value));
1211 if (CYIsClass(self))
1212 return (Class) self;
1213 throw CYJSError(context, "got something that is not a Class");
1217 NSArray *CYCastNSArray(JSContextRef context, JSPropertyNameArrayRef names) {
1219 size_t size(JSPropertyNameArrayGetCount(names));
1220 NSMutableArray *array([NSMutableArray arrayWithCapacity:size]);
1221 for (size_t index(0); index != size; ++index)
1222 [array addObject:CYCastNSString(&pool, context, JSPropertyNameArrayGetNameAtIndex(names, index))];
1226 JSValueRef CYCastJSValue(JSContextRef context, NSObject *value) {
1228 return CYJSNull(context);
1229 return CYMakeInstance(context, value);
1232 @implementation CYJSObject
1234 - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context { CYObjectiveTry_ {
1235 if ((self = [super init]) != nil) {
1237 context_ = CYGetJSContext(context);
1238 JSGlobalContextRetain(context_);
1239 JSValueProtect(context_, object_);
1241 } CYObjectiveCatch }
1243 - (void) dealloc { CYObjectiveTry {
1244 JSValueUnprotect(context_, object_);
1245 JSGlobalContextRelease(context_);
1247 } CYObjectiveCatch }
1249 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects { CYObjectiveTry {
1251 const char *cyon(CYPoolCCYON(pool, context, object_, objects));
1253 return [super cy$toCYON:objective inSet:objects];
1255 return [NSString stringWithUTF8String:cyon];
1256 } CYObjectiveCatch }
1258 - (NSUInteger) count { CYObjectiveTry {
1259 JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context, object_));
1260 size_t size(JSPropertyNameArrayGetCount(names));
1261 JSPropertyNameArrayRelease(names);
1263 } CYObjectiveCatch }
1265 - (id) objectForKey:(id)key { CYObjectiveTry {
1266 JSValueRef value(CYGetProperty(context, object_, CYJSString(context, (NSObject *) key)));
1267 if (JSValueIsUndefined(context, value))
1269 return CYCastNSObject(NULL, context, value) ?: [NSNull null];
1270 } CYObjectiveCatch }
1272 - (NSEnumerator *) keyEnumerator { CYObjectiveTry {
1273 JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context, object_));
1274 NSEnumerator *enumerator([CYCastNSArray(context, names) objectEnumerator]);
1275 JSPropertyNameArrayRelease(names);
1277 } CYObjectiveCatch }
1279 - (void) setObject:(id)object forKey:(id)key { CYObjectiveTry {
1280 CYSetProperty(context, object_, CYJSString(context, (NSObject *) key), CYCastJSValue(context, (NSString *) object));
1281 } CYObjectiveCatch }
1283 - (void) removeObjectForKey:(id)key { CYObjectiveTry {
1284 (void) _jsccall(JSObjectDeleteProperty, context, object_, CYJSString(context, (NSObject *) key));
1285 } CYObjectiveCatch }
1289 @implementation CYJSArray
1291 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects { CYObjectiveTry {
1293 return [NSString stringWithUTF8String:CYPoolCCYON(pool, context, object_, objects)];
1294 } CYObjectiveCatch }
1296 - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context { CYObjectiveTry_ {
1297 if ((self = [super init]) != nil) {
1299 context_ = CYGetJSContext(context);
1300 JSGlobalContextRetain(context_);
1301 JSValueProtect(context_, object_);
1303 } CYObjectiveCatch }
1305 - (void) dealloc { CYObjectiveTry {
1306 JSValueUnprotect(context_, object_);
1307 JSGlobalContextRelease(context_);
1309 } CYObjectiveCatch }
1311 - (NSUInteger) count { CYObjectiveTry {
1312 return CYArrayLength(context, object_);
1313 } CYObjectiveCatch }
1315 - (id) objectAtIndex:(NSUInteger)index { CYObjectiveTry {
1316 size_t bounds([self count]);
1317 if (index >= bounds)
1318 @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"*** -[CYJSArray objectAtIndex:]: index (%zu) beyond bounds (%zu)", static_cast<size_t>(index), bounds] userInfo:nil];
1319 JSValueRef value(_jsccall(JSObjectGetPropertyAtIndex, context, object_, index));
1320 return CYCastNSObject(NULL, context, value) ?: [NSNull null];
1321 } CYObjectiveCatch }
1323 - (void) addObject:(id)object { CYObjectiveTry {
1324 CYArrayPush(context, object_, CYCastJSValue(context, (NSObject *) object));
1325 } CYObjectiveCatch }
1327 - (void) insertObject:(id)object atIndex:(NSUInteger)index { CYObjectiveTry {
1328 size_t bounds([self count] + 1);
1329 if (index >= bounds)
1330 @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"*** -[CYJSArray insertObject:atIndex:]: index (%zu) beyond bounds (%zu)", static_cast<size_t>(index), bounds] userInfo:nil];
1331 JSValueRef arguments[3];
1332 arguments[0] = CYCastJSValue(context, index);
1333 arguments[1] = CYCastJSValue(context, 0);
1334 arguments[2] = CYCastJSValue(context, (NSObject *) object);
1335 JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array_prototype")));
1336 _jsccall(JSObjectCallAsFunction, context, CYCastJSObject(context, CYGetProperty(context, Array, splice_s)), object_, 3, arguments);
1337 } CYObjectiveCatch }
1339 - (void) removeLastObject { CYObjectiveTry {
1340 JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array_prototype")));
1341 _jsccall(JSObjectCallAsFunction, context, CYCastJSObject(context, CYGetProperty(context, Array, pop_s)), object_, 0, NULL);
1342 } CYObjectiveCatch }
1344 - (void) removeObjectAtIndex:(NSUInteger)index { CYObjectiveTry {
1345 size_t bounds([self count]);
1346 if (index >= bounds)
1347 @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"*** -[CYJSArray removeObjectAtIndex:]: index (%zu) beyond bounds (%zu)", static_cast<size_t>(index), bounds] userInfo:nil];
1348 JSValueRef arguments[2];
1349 arguments[0] = CYCastJSValue(context, index);
1350 arguments[1] = CYCastJSValue(context, 1);
1351 JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array_prototype")));
1352 _jsccall(JSObjectCallAsFunction, context, CYCastJSObject(context, CYGetProperty(context, Array, splice_s)), object_, 2, arguments);
1353 } CYObjectiveCatch }
1355 - (void) replaceObjectAtIndex:(NSUInteger)index withObject:(id)object { CYObjectiveTry {
1356 size_t bounds([self count]);
1357 if (index >= bounds)
1358 @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"*** -[CYJSArray replaceObjectAtIndex:withObject:]: index (%zu) beyond bounds (%zu)", static_cast<size_t>(index), bounds] userInfo:nil];
1359 CYSetProperty(context, object_, index, CYCastJSValue(context, (NSObject *) object));
1360 } CYObjectiveCatch }
1364 // XXX: inherit from or replace with CYJSObject
1365 @interface CYInternal : NSObject {
1366 JSGlobalContextRef context_;
1367 JSObjectRef object_;
1372 @implementation CYInternal
1374 - (void) dealloc { CYObjectiveTry {
1375 JSValueUnprotect(context_, object_);
1376 JSGlobalContextRelease(context_);
1378 } CYObjectiveCatch }
1380 - (id) initInContext:(JSContextRef)context { CYObjectiveTry_ {
1381 if ((self = [super init]) != nil) {
1382 context_ = CYGetJSContext(context);
1383 JSGlobalContextRetain(context_);
1385 } CYObjectiveCatch }
1387 - (bool) hasProperty:(JSStringRef)name inContext:(JSContextRef)context {
1388 if (object_ == NULL)
1391 return JSObjectHasProperty(context, object_, name);
1394 - (JSValueRef) getProperty:(JSStringRef)name inContext:(JSContextRef)context {
1395 if (object_ == NULL)
1398 return CYGetProperty(context, object_, name);
1401 - (void) setProperty:(JSStringRef)name toValue:(JSValueRef)value inContext:(JSContextRef)context {
1402 @synchronized (self) {
1403 if (object_ == NULL) {
1404 object_ = JSObjectMake(context, NULL, NULL);
1405 JSValueProtect(context, object_);
1409 CYSetProperty(context, object_, name, value);
1412 + (CYInternal *) get:(id)object {
1414 if (&objc_getAssociatedObject == NULL)
1417 @synchronized (object) {
1418 if (CYInternal *internal = objc_getAssociatedObject(object, @selector(cy$internal)))
1426 + (CYInternal *) set:(id)object inContext:(JSContextRef)context {
1428 if (&objc_getAssociatedObject == NULL)
1431 @synchronized (object) {
1432 if (CYInternal *internal = objc_getAssociatedObject(object, @selector(cy$internal)))
1435 if (&objc_setAssociatedObject == NULL)
1438 CYInternal *internal([[[CYInternal alloc] initInContext:context] autorelease]);
1439 objc_setAssociatedObject(object, @selector(cy$internal), internal, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1449 static JSValueRef CYCastJSValue(JSContextRef context, SEL sel) {
1451 return CYJSNull(context);
1452 return CYPrivate<Selector_privateData>::Make(context, sel);
1455 static SEL CYCastSEL(JSContextRef context, JSValueRef value) {
1456 if (JSValueIsObjectOfClass(context, value, CYPrivate<Selector_privateData>::Class_)) {
1457 Selector_privateData *internal(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate((JSObjectRef) value)));
1458 return reinterpret_cast<SEL>(internal->value_);
1461 return sel_registerName(CYPoolCString(pool, context, value));
1465 void *CYObjectiveC_ExecuteStart(JSContextRef context) { CYSadTry {
1466 return (void *) [[NSAutoreleasePool alloc] init];
1467 } CYSadCatch(NULL) }
1469 void CYObjectiveC_ExecuteEnd(JSContextRef context, void *handle) { CYSadTry {
1470 return [(NSAutoreleasePool *) handle release];
1473 static void CYObjectiveC_CallFunction(CYPool &pool, JSContextRef context, ffi_cif *cif, void (*function)(), void *value, void **values) { CYSadTry {
1474 CYCallFunction(pool, context, cif, function, value, values);
1477 static NSBlock *CYCastNSBlock(CYPool &pool, JSContextRef context, JSValueRef value, const sig::Signature *signature) {
1479 if (JSValueIsNull(context, value))
1481 JSObjectRef object(CYCastJSObject(context, value));
1483 if (JSValueIsObjectOfClass(context, object, FunctionInstance_))
1484 return reinterpret_cast<Instance *>(JSObjectGetPrivate(object))->value_;
1486 if (JSValueIsObjectOfClass(context, object, Instance::Class_)) {
1487 _assert(reinterpret_cast<Instance *>(JSObjectGetPrivate(object))->value_ == nil);
1491 _assert(JSObjectIsFunction(context, object));
1493 _assert(signature != NULL);
1494 _assert(signature->count != 0);
1496 sig::Signature modified;
1497 modified.count = signature->count + 1;
1498 modified.elements = new(pool) sig::Element[modified.count];
1500 modified.elements[0] = signature->elements[0];
1501 memcpy(modified.elements + 2, signature->elements + 1, sizeof(sig::Element) * (signature->count - 1));
1503 modified.elements[1].name = NULL;
1504 modified.elements[1].type = new(pool) sig::Object();
1505 modified.elements[1].offset = _not(size_t);
1507 return CYMakeBlock(context, object, modified);
1515 void Block::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const {
1516 // XXX: this function actually needs to handle null pools as it is an autorelease
1517 _assert(pool != NULL);
1518 *reinterpret_cast<id *>(data) = CYCastNSBlock(*pool, context, value, &signature);
1521 // XXX: assigning to an indirect id * works for return values, but not for properties and fields
1522 void Object::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const {
1523 *reinterpret_cast<id *>(data) = CYCastNSObject(pool, context, value);
1526 void Meta::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const {
1527 *reinterpret_cast<id *>(data) = CYCastNSObject(pool, context, value);
1530 void Selector::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const {
1531 *reinterpret_cast<SEL *>(data) = CYCastSEL(context, value);
1534 JSValueRef Object::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
1535 NSObject *value(*reinterpret_cast<NSObject **>(data));
1537 return CYJSNull(context);
1538 JSObjectRef object(CYMakeInstance(context, value));
1541 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
1543 if (internal->IsUninitialized()) {
1544 internal->flags_ &= ~Instance::Uninitialized;
1545 if (internal->value_ == nil)
1546 internal->value_ = value;
1548 _assert(internal->value_ == value);
1557 JSValueRef Meta::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
1558 if (Class value = *reinterpret_cast<Class *>(data))
1559 return CYMakeInstance(context, value, Instance::Permanent);
1560 return CYJSNull(context);
1563 JSValueRef Selector::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
1564 return CYCastJSValue(context, *reinterpret_cast<SEL *>(data));
1567 JSValueRef Block::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
1568 return CYCastJSValue(context, *reinterpret_cast<NSObject **>(data));
1573 static bool CYImplements(id object, Class _class, SEL selector, bool devoid = false) {
1574 if (objc_method *method = class_getInstanceMethod(_class, selector)) {
1578 method_getReturnType(method, type, sizeof(type));
1583 // XXX: possibly use a more "awesome" check?
1587 static JSValueRef MessageAdapter_(JSContextRef context, size_t count, JSValueRef values[], JSObjectRef function) {
1588 JSObjectRef _this(CYCastJSObject(context, values[0]));
1589 return CYCallAsFunction(context, function, _this, count - 2, values + 2);
1592 JSObjectRef Message_privateData::Make(JSContextRef context, SEL sel, const char *type, IMP value) {
1593 Message_privateData *internal(new Message_privateData(sel, type, value));
1594 return JSObjectMake(context, Message_privateData::Class_, internal);
1597 static IMP CYMakeMessage(JSContextRef context, JSValueRef value, const char *encoding) {
1598 JSObjectRef function(CYCastJSObject(context, value));
1600 sig::Signature signature;
1601 sig::Parse(pool, &signature, encoding, &Structor_);
1602 Closure_privateData *internal(CYMakeFunctor_(context, function, signature, &MessageAdapter_));
1603 // XXX: see notes in Library.cpp about needing to leak
1604 return reinterpret_cast<IMP>(internal->value_);
1607 static bool Messages_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
1608 auto internal(CYPrivate<Messages>::Get(context, object));
1609 Class _class(internal->GetClass());
1612 const char *name(CYPoolCString(pool, context, property));
1614 if (SEL sel = sel_getUid(name))
1615 if (class_getInstanceMethod(_class, sel) != NULL)
1621 static JSValueRef Messages_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1622 auto internal(CYPrivate<Messages>::Get(context, object));
1623 Class _class(internal->GetClass());
1626 const char *name(CYPoolCString(pool, context, property));
1628 if (SEL sel = sel_getUid(name))
1629 if (objc_method *method = class_getInstanceMethod(_class, sel))
1630 return Message_privateData::Make(context, sel, method_getTypeEncoding(method), method_getImplementation(method));
1635 static bool Messages_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
1636 auto internal(CYPrivate<Messages>::Get(context, object));
1637 Class _class(internal->GetClass());
1640 const char *name(CYPoolCString(pool, context, property));
1641 SEL sel(sel_registerName(name));
1646 if (JSValueIsObjectOfClass(context, value, Message_privateData::Class_)) {
1647 Message_privateData *message(reinterpret_cast<Message_privateData *>(JSObjectGetPrivate((JSObjectRef) value)));
1648 type = sig::Unparse(pool, &message->signature_);
1649 imp = reinterpret_cast<IMP>(message->value_);
1650 } else if (objc_method *method = class_getInstanceMethod(_class, sel)) {
1651 type = method_getTypeEncoding(method);
1652 imp = CYMakeMessage(context, value, type);
1653 } else return false;
1655 objc_method *method(NULL);
1657 objc_method **methods(class_copyMethodList(_class, &size));
1658 pool.atexit(free, methods);
1660 for (size_t i(0); i != size; ++i)
1661 if (sel_isEqual(method_getName(methods[i]), sel)) {
1662 method = methods[i];
1667 method_setImplementation(method, imp);
1669 class_addMethod(_class, sel, imp, type);
1674 static JSValueRef Messages_complete_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1676 if (!CYCastBool(context, arguments[1]))
1677 return CYObjectMakeArray(context, 0, NULL);
1681 _assert(count == 1);
1683 CYUTF8String prefix(CYPoolUTF8String(pool, context, CYJSString(context, arguments[0])));
1685 auto internal(CYPrivate<Messages>::Get(context, _this));
1686 Class _class(internal->GetClass());
1689 objc_method **data(class_copyMethodList(_class, &size));
1690 pool.atexit(free, data);
1692 JSObjectRef array(NULL); {
1693 CYArrayBuilder<1024> values(context, array);
1695 for (size_t i(0); i != size; ++i) {
1696 CYUTF8String name(sel_getName(method_getName(data[i])));
1697 if (CYStartsWith(name, prefix))
1698 values(CYCastJSValue(context, CYJSString(name)));
1703 static bool CYHasImplicitProperties(JSContextRef context, Class _class) {
1704 if (!CYCastBool(context, CYGetCachedValue(context, CYJSString("cydget"))))
1706 // XXX: this is an evil hack to deal with NSProxy; fix elsewhere
1707 if (!CYImplements(_class, object_getClass(_class), @selector(cy$hasImplicitProperties)))
1709 return [_class cy$hasImplicitProperties];
1712 static objc_property_t CYFindProperty(CYPool &pool, Class _class, const char *name) {
1715 if (objc_property_t property = class_getProperty(_class, name))
1719 /* // XXX: I don't think any of this is required
1721 Protocol **protocols(class_copyProtocolList(_class, &count));
1722 // XXX: just implement a scope guard already :/
1723 pool.atexit(free, protocols);
1725 for (unsigned int i(0); i != count; ++i)
1726 if (objc_property_t property = protocol_getProperty(protocols[i], name, true, true))
1729 return CYFindProperty(pool, class_getSuperclass(_class), name); */
1732 static JSValueRef Constructor_getProperty_$cyi(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1733 auto internal(CYPrivate<Constructor>::Get(context, object));
1734 return CYPrivate<Interior>::Make(context, internal->value_, context, object);
1737 static bool Constructor_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
1738 auto internal(CYPrivate<Constructor>::Get(context, object));
1739 Class _class(object_getClass(internal->value_));
1740 if (!CYHasImplicitProperties(context, _class))
1743 if (SEL sel = sel_getUid(CYPoolCString(pool, context, property)))
1744 if (CYImplements(internal->value_, _class, sel, true))
1749 static JSValueRef Constructor_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1750 auto internal(CYPrivate<Constructor>::Get(context, object));
1751 Class _class(object_getClass(internal->value_));
1752 if (!CYHasImplicitProperties(context, _class))
1755 if (SEL sel = sel_getUid(CYPoolCString(pool, context, property)))
1756 if (CYImplements(internal->value_, _class, sel, true))
1757 return CYSendMessage(pool, context, internal->value_, NULL, sel, 0, NULL, false);
1761 static bool Instance_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
1762 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
1763 id self(internal->value_);
1765 if (JSStringIsEqualToUTF8CString(property, "$cyi"))
1769 NSString *name(CYCastNSString(&pool, context, property));
1771 if (CYInternal *internal = [CYInternal get:self])
1772 if ([internal hasProperty:property inContext:context])
1775 Class _class(object_getClass(self));
1778 // XXX: this is an evil hack to deal with NSProxy; fix elsewhere
1779 if (CYImplements(self, _class, @selector(cy$hasProperty:)))
1780 if ([self cy$hasProperty:name])
1782 } CYPoolCatch(false)
1784 const char *string(CYPoolCString(pool, context, name));
1786 if (CYFindProperty(pool, _class, string) != NULL)
1789 if (CYHasImplicitProperties(context, _class))
1790 if (SEL sel = sel_getUid(string))
1791 if (CYImplements(self, _class, sel, true))
1797 static JSValueRef Instance_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1798 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
1799 id self(internal->value_);
1801 if (JSStringIsEqualToUTF8CString(property, "$cyi"))
1802 return CYPrivate<Interior>::Make(context, self, context, object);
1805 NSString *name(CYCastNSString(&pool, context, property));
1807 if (CYInternal *internal = [CYInternal get:self])
1808 if (JSValueRef value = [internal getProperty:property inContext:context])
1812 if (JSValueRef value = [self cy$getProperty:name inContext:context])
1816 const char *string(CYPoolCString(pool, context, name));
1817 Class _class(object_getClass(self));
1819 if (objc_property_t property = CYFindProperty(pool, _class, string)) {
1820 PropertyAttributes attributes(property);
1821 SEL sel(sel_registerName(attributes.Getter()));
1822 return CYSendMessage(pool, context, self, NULL, sel, 0, NULL, false);
1825 if (CYHasImplicitProperties(context, _class))
1826 if (SEL sel = sel_getUid(string))
1827 if (CYImplements(self, _class, sel, true))
1828 return CYSendMessage(pool, context, self, NULL, sel, 0, NULL, false);
1833 static bool Instance_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
1834 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
1835 id self(internal->value_);
1839 NSString *name(CYCastNSString(&pool, context, property));
1840 NSObject *data(CYCastNSObject(&pool, context, value));
1843 if ([self cy$setProperty:name to:data])
1845 } CYPoolCatch(false)
1847 const char *string(CYPoolCString(pool, context, name));
1848 Class _class(object_getClass(self));
1850 if (objc_property_t property = CYFindProperty(pool, _class, string)) {
1851 PropertyAttributes attributes(property);
1852 if (const char *setter = attributes.Setter()) {
1853 SEL sel(sel_registerName(setter));
1854 JSValueRef arguments[1] = {value};
1855 CYSendMessage(pool, context, self, NULL, sel, 1, arguments, false);
1860 size_t length(strlen(string));
1862 char set[length + 5];
1868 if (string[0] != '\0') {
1869 set[3] = toupper(string[0]);
1870 memcpy(set + 4, string + 1, length - 1);
1873 set[length + 3] = ':';
1874 set[length + 4] = '\0';
1876 if (SEL sel = sel_getUid(set))
1877 if (CYImplements(self, _class, sel)) {
1878 JSValueRef arguments[1] = {value};
1879 CYSendMessage(pool, context, self, NULL, sel, 1, arguments, false);
1883 if (CYInternal *internal = [CYInternal set:self inContext:context]) {
1884 [internal setProperty:property toValue:value inContext:context];
1891 static bool Instance_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1892 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
1893 id self(internal->value_);
1896 NSString *name(CYCastNSString(NULL, context, property));
1897 return [self cy$deleteProperty:name];
1898 } CYPoolCatch(false)
1899 } CYCatch(false) return /*XXX*/ false; }
1901 static void CYForEachProperty(CYPool &pool, Class _class, const Functor<void (objc_method *, const char *)> &code) {
1902 for (; _class != Nil; _class = class_getSuperclass(_class)) {
1904 objc_method **data(class_copyMethodList(_class, &size));
1905 pool.atexit(free, data);
1907 for (size_t i(0); i != size; ++i) {
1908 objc_method *method(data[i]);
1910 const char *name(sel_getName(method_getName(method)));
1911 if (strchr(name, ':') != NULL)
1919 static void Instance_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
1920 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
1921 id self(internal->value_);
1924 Class _class(object_getClass(self));
1926 for (Class current(_class); current != Nil; current = class_getSuperclass(current)) {
1928 objc_property_t *data(class_copyPropertyList(current, &size));
1929 pool.atexit(free, data);
1931 for (size_t i(0); i != size; ++i)
1932 JSPropertyNameAccumulatorAddName(names, CYJSString(property_getName(data[i])));
1935 if (CYHasImplicitProperties(context, _class))
1936 CYForEachProperty(pool, _class, fun([&](objc_method *method, const char *name) {
1937 JSPropertyNameAccumulatorAddName(names, CYJSString(name));
1941 // XXX: this is an evil hack to deal with NSProxy; fix elsewhere
1942 if (CYImplements(self, _class, @selector(cy$getPropertyNames:inContext:)))
1943 [self cy$getPropertyNames:names inContext:context];
1947 static JSValueRef Instance_complete_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1948 if (!CYJSValueIsNSObject(context, _this))
1949 return CYObjectMakeArray(context, 0, NULL);
1951 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
1952 id self(internal->value_);
1954 _assert(count == 1 || count == 2);
1956 Class _class(object_getClass(self));
1958 CYUTF8String prefix(CYPoolUTF8String(pool, context, CYJSString(context, arguments[0])));
1960 JSObjectRef array(NULL); {
1961 CYArrayBuilder<1024> values(context, array);
1963 CYForEachProperty(pool, _class, fun([&](objc_method *method, const char *name) {
1964 if (!CYStartsWith(name, prefix))
1966 const char *type(method_getTypeEncoding(method));
1967 if (type == NULL || *type == '\0' || *type == 'v')
1969 if (class_getProperty(_class, name) != NULL)
1971 values(CYCastJSValue(context, CYJSString(pool.strcat(name, "()", NULL))));
1976 static JSObjectRef Constructor_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1977 auto internal(CYPrivate<Constructor>::Get(context, object));
1978 JSObjectRef value(CYMakeInstance(context, [internal->value_ alloc], Instance::Uninitialized));
1982 static const char *CYBlockEncoding(NSBlock *self) {
1983 BlockLiteral *literal(reinterpret_cast<BlockLiteral *>(self));
1984 if ((literal->flags & BLOCK_HAS_SIGNATURE) == 0)
1986 uint8_t *descriptor(reinterpret_cast<uint8_t *>(literal->descriptor));
1987 descriptor += sizeof(BlockDescriptor1);
1988 if ((literal->flags & BLOCK_HAS_COPY_DISPOSE) != 0)
1989 descriptor += sizeof(BlockDescriptor2);
1990 BlockDescriptor3 *descriptor3(reinterpret_cast<BlockDescriptor3 *>(descriptor));
1991 return descriptor3->signature;
1994 static bool CYBlockSignature(CYPool &pool, NSBlock *self, sig::Signature &signature) {
1995 const char *encoding(CYBlockEncoding(self));
1996 if (encoding == NULL)
1999 sig::Parse(pool, &signature, encoding, &Structor_);
2000 _assert(signature.count >= 2);
2002 _assert(dynamic_cast<sig::Object *>(signature.elements[1].type) != NULL);
2003 signature.elements[1] = signature.elements[0];
2005 ++signature.elements;
2011 static JSValueRef FunctionInstance_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2012 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
2013 id self(internal->value_);
2015 if (const char *encoding = CYBlockEncoding(self)) {
2021 sig::Signature signature;
2022 sig::Parse(pool, &signature, encoding, &Structor_);
2025 sig::sig_ffi_cif(pool, 0, signature, &cif);
2027 BlockLiteral *literal(reinterpret_cast<BlockLiteral *>(self));
2028 void (*function)() = reinterpret_cast<void (*)()>(literal->invoke);
2029 return CYCallFunction(pool, context, 1, setup, count, arguments, false, false, signature, &cif, function);
2033 CYThrow("NSBlock without signature field passed arguments");
2037 } CYPoolCatch(NULL);
2042 static bool Constructor_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef instance, JSValueRef *exception) { CYTry {
2043 auto internal(CYPrivate<Constructor>::Get(context, constructor));
2044 Class _class(internal->value_);
2046 if (CYJSValueIsNSObject(context, instance)) {
2047 Instance *linternal(reinterpret_cast<Instance *>(JSObjectGetPrivate((JSObjectRef) instance)));
2048 // XXX: this isn't always safe
2049 return [linternal->value_ isKindOfClass:_class];
2055 static JSValueRef Instance_box_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2057 throw CYJSError(context, "incorrect number of arguments to Instance");
2059 id value(CYCastNSObject(&pool, context, arguments[0]));
2061 value = [NSNull null];
2062 return CYCastJSValue(context, [value cy$box]);
2065 static bool Interior_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
2066 Interior *internal(reinterpret_cast<Interior *>(JSObjectGetPrivate(object)));
2069 id self(internal->value_);
2070 const char *name(CYPoolCString(pool, context, property));
2072 if (object_getInstanceVariable(self, name, NULL) != NULL)
2078 static void CYBitField(CYPool &pool, unsigned &length, unsigned &shift, id self, Ivar ivar, const char *encoding, unsigned offset) {
2079 length = CYCastDouble(encoding + 1);
2083 objc_ivar **ivars(class_copyIvarList(object_getClass(self), &size));
2084 pool.atexit(free, ivars);
2086 for (size_t i(0); i != size; ++i)
2087 if (ivars[i] == ivar)
2089 else if (ivar_getOffset(ivars[i]) == offset) {
2090 const char *encoding(ivar_getTypeEncoding(ivars[i]));
2091 _assert(encoding != NULL);
2092 _assert(encoding[0] == 'b');
2093 shift += CYCastDouble(encoding + 1);
2097 static JSValueRef Interior_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2098 Interior *internal(reinterpret_cast<Interior *>(JSObjectGetPrivate(object)));
2101 id self(internal->value_);
2102 const char *name(CYPoolCString(pool, context, property));
2104 if (objc_ivar *ivar = object_getInstanceVariable(self, name, NULL)) {
2105 ptrdiff_t offset(ivar_getOffset(ivar));
2106 void *data(reinterpret_cast<uint8_t *>(self) + offset);
2108 const char *encoding(ivar_getTypeEncoding(ivar));
2109 _assert(encoding != NULL);
2110 _assert(encoding[0] != '\0');
2111 if (encoding[0] == 'b') {
2112 unsigned length, shift;
2113 CYBitField(pool, length, shift, self, ivar, encoding, offset);
2114 _assert(shift + length <= sizeof(uintptr_t) * 8);
2115 uintptr_t &field(*reinterpret_cast<uintptr_t *>(data));
2116 uintptr_t mask((1 << length) - 1);
2117 return CYCastJSValue(context, (field >> shift) & mask);
2119 #if defined(__APPLE__) && defined(__LP64__)
2120 // XXX: maybe do even more verifications here
2121 if (strcmp(name, "isa") == 0)
2122 return CYCastJSValue(context, object_getClass(self));
2125 auto type(new(pool) Type_privateData(encoding));
2126 return type->type_->FromFFI(context, type->GetFFI(), data);
2133 static bool Interior_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
2134 Interior *internal(reinterpret_cast<Interior *>(JSObjectGetPrivate(object)));
2137 id self(internal->value_);
2138 const char *name(CYPoolCString(pool, context, property));
2140 if (objc_ivar *ivar = object_getInstanceVariable(self, name, NULL)) {
2141 ptrdiff_t offset(ivar_getOffset(ivar));
2142 void *data(reinterpret_cast<uint8_t *>(self) + offset);
2144 const char *encoding(ivar_getTypeEncoding(ivar));
2145 _assert(encoding != NULL);
2146 if (encoding[0] == 'b') {
2147 unsigned length, shift;
2148 CYBitField(pool, length, shift, self, ivar, encoding, offset);
2149 _assert(shift + length <= sizeof(uintptr_t) * 8);
2150 uintptr_t &field(*reinterpret_cast<uintptr_t *>(data));
2151 uintptr_t mask((1 << length) - 1);
2152 field = field & ~(mask << shift) | (uintptr_t(CYCastDouble(context, value)) & mask) << shift;
2154 auto type(new(pool) Type_privateData(ivar_getTypeEncoding(ivar)));
2155 type->type_->PoolFFI(&pool, context, type->GetFFI(), reinterpret_cast<uint8_t *>(self) + ivar_getOffset(ivar), value);
2163 static void Interior_getPropertyNames_(CYPool &pool, Class _class, JSPropertyNameAccumulatorRef names) {
2164 if (Class super = class_getSuperclass(_class))
2165 Interior_getPropertyNames_(pool, super, names);
2168 objc_ivar **data(class_copyIvarList(_class, &size));
2169 pool.atexit(free, data);
2171 for (size_t i(0); i != size; ++i)
2172 JSPropertyNameAccumulatorAddName(names, CYJSString(ivar_getName(data[i])));
2175 static void Interior_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
2176 Interior *internal(reinterpret_cast<Interior *>(JSObjectGetPrivate(object)));
2179 id self(internal->value_);
2180 Class _class(object_getClass(self));
2182 Interior_getPropertyNames_(pool, _class, names);
2185 static JSValueRef Interior_callAsFunction_$cya(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2186 Interior *internal(reinterpret_cast<Interior *>(JSObjectGetPrivate(object)));
2187 return internal->owner_;
2190 static bool ObjectiveC_Classes_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
2192 return objc_getClass(CYPoolCString(pool, context, property)) != Nil;
2195 static JSValueRef ObjectiveC_Classes_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2197 NSString *name(CYCastNSString(&pool, context, property));
2198 if (Class _class = NSClassFromString(name))
2199 return CYMakeInstance(context, _class, Instance::Permanent);
2203 static Class *CYCopyClassList(size_t &size) {
2204 size = objc_getClassList(NULL, 0);
2205 Class *data(reinterpret_cast<Class *>(malloc(sizeof(Class) * size)));
2208 size_t writ(objc_getClassList(data, size));
2214 Class *copy(reinterpret_cast<Class *>(realloc(data, sizeof(Class) * writ)));
2225 static void ObjectiveC_Classes_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
2229 if (Class *data = CYCopyClassList(size)) {
2230 pool.atexit(free, data);
2231 for (size_t i(0); i != size; ++i)
2232 JSPropertyNameAccumulatorAddName(names, CYJSString(class_getName(data[i])));
2237 static JSValueRef ObjectiveC_Image_Classes_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2238 const char *internal(reinterpret_cast<const char *>(JSObjectGetPrivate(object)));
2241 const char *name(CYPoolCString(pool, context, property));
2244 const char **data(objc_copyClassNamesForImage(internal, &size));
2245 pool.atexit(free, data);
2248 for (size_t i(0); i != size; ++i)
2249 if (strcmp(name, data[i]) == 0) {
2250 if (Class _class = objc_getClass(name))
2251 return CYMakeInstance(context, _class, Instance::Permanent);
2259 static void ObjectiveC_Image_Classes_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
2260 const char *internal(reinterpret_cast<const char *>(JSObjectGetPrivate(object)));
2264 const char **data(objc_copyClassNamesForImage(internal, &size));
2265 pool.atexit(free, data);
2267 for (size_t i(0); i != size; ++i)
2268 JSPropertyNameAccumulatorAddName(names, CYJSString(data[i]));
2271 static JSValueRef ObjectiveC_Images_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2273 CYUTF8String name(CYPoolUTF8String(pool, context, property));
2276 const char **data(objc_copyImageNames(&size));
2277 pool.atexit(free, data);
2279 for (size_t i(0); i != size; ++i)
2280 if (name == data[i]) {
2281 JSObjectRef value(JSObjectMake(context, NULL, NULL));
2282 CYSetProperty(context, value, CYJSString("classes"), JSObjectMake(context, ObjectiveC_Image_Classes_, const_cast<char *>(data[i])));
2289 static void ObjectiveC_Images_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
2293 const char **data(objc_copyImageNames(&size));
2294 pool.atexit(free, data);
2296 for (size_t i(0); i != size; ++i)
2297 JSPropertyNameAccumulatorAddName(names, CYJSString(data[i]));
2301 static JSValueRef ObjectiveC_Protocols_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2303 const char *name(CYPoolCString(pool, context, property));
2304 if (Protocol *protocol = objc_getProtocol(name))
2305 return CYMakeInstance(context, protocol, Instance::Permanent);
2309 static void ObjectiveC_Protocols_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
2313 Protocol **data(objc_copyProtocolList(&size));
2314 pool.atexit(free, data);
2316 for (size_t i(0); i != size; ++i)
2317 JSPropertyNameAccumulatorAddName(names, CYJSString(protocol_getName(data[i])));
2320 static JSValueRef ObjectiveC_Constants_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2322 CYUTF8String name(CYPoolUTF8String(pool, context, property));
2324 return CYJSNull(context);
2328 static void ObjectiveC_Constants_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
2329 JSPropertyNameAccumulatorAddName(names, CYJSString("nil"));
2333 static kern_return_t CYReadMemory(task_t task, vm_address_t address, vm_size_t size, void **data) {
2334 *data = reinterpret_cast<void *>(address);
2335 return KERN_SUCCESS;
2339 std::set<Class> query_;
2340 JSContextRef context_;
2341 JSObjectRef results_;
2344 struct CYObjectStruct {
2348 static void choose_(task_t task, void *baton, unsigned type, vm_range_t *ranges, unsigned count) {
2349 CYChoice *choice(reinterpret_cast<CYChoice *>(baton));
2350 JSContextRef context(choice->context_);
2352 for (unsigned i(0); i != count; ++i) {
2353 vm_range_t &range(ranges[i]);
2354 void *data(reinterpret_cast<void *>(range.address));
2355 size_t size(range.size);
2357 if (size < sizeof(CYObjectStruct))
2360 uintptr_t *pointers(reinterpret_cast<uintptr_t *>(data));
2361 #if defined(__APPLE__) && defined(__LP64__)
2362 Class isa(reinterpret_cast<Class>(pointers[0] & 0x1fffffff8));
2364 Class isa(reinterpret_cast<Class>(pointers[0]));
2367 std::set<Class>::const_iterator result(choice->query_.find(isa));
2368 if (result == choice->query_.end())
2371 size_t needed(class_getInstanceSize(*result));
2372 // XXX: if (size < needed)
2374 size_t boundary(496);
2378 if (needed <= boundary && (needed + 15) / 16 * 16 != size || needed > boundary && (needed + 511) / 512 * 512 != size)
2380 CYArrayPush(context, choice->results_, CYCastJSValue(context, reinterpret_cast<id>(data)));
2384 static JSValueRef choose(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2386 throw CYJSError(context, "choose() takes a class argument");
2388 CYGarbageCollect(context);
2391 id _class(CYCastNSObject(&pool, context, arguments[0]));
2393 vm_address_t *zones(NULL);
2395 kern_return_t error(malloc_get_all_zones(0, &CYReadMemory, &zones, &size));
2396 _assert(error == KERN_SUCCESS);
2398 JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array")));
2399 JSObjectRef results(_jsccall(JSObjectCallAsConstructor, context, Array, 0, NULL));
2402 choice.context_ = context;
2403 choice.results_ = results;
2406 Class *classes(CYCopyClassList(number));
2407 _assert(classes != NULL);
2408 pool.atexit(free, classes);
2410 for (size_t i(0); i != number; ++i)
2411 for (Class current(classes[i]); current != Nil; current = class_getSuperclass(current))
2412 if (current == _class) {
2413 choice.query_.insert(classes[i]);
2417 for (unsigned i(0); i != size; ++i) {
2418 const malloc_zone_t *zone(reinterpret_cast<const malloc_zone_t *>(zones[i]));
2419 if (zone == NULL || zone->introspect == NULL)
2422 zone->introspect->enumerator(mach_task_self(), &choice, MALLOC_PTR_IN_USE_RANGE_TYPE, zones[i], &CYReadMemory, &choose_);
2430 #if defined(__i386__) || defined(__x86_64__)
2431 #define OBJC_MAX_STRUCT_BY_VALUE 8
2432 static int struct_forward_array[] = {
2433 0, 0, 0, 1, 0, 1, 1, 1, 0 };
2434 #elif defined(__arm__)
2435 #define OBJC_MAX_STRUCT_BY_VALUE 1
2436 static int struct_forward_array[] = {
2438 #elif defined(__arm64__)
2441 #error missing objc-runtime-info
2445 static bool stret(ffi_type *ffi_type) {
2446 return ffi_type->type == FFI_TYPE_STRUCT && (
2447 ffi_type->size > OBJC_MAX_STRUCT_BY_VALUE ||
2448 struct_forward_array[ffi_type->size] != 0
2456 JSValueRef CYSendMessage(CYPool &pool, JSContextRef context, id self, Class _class, SEL _cmd, size_t count, const JSValueRef arguments[], bool initialize) {
2460 _class = object_getClass(self);
2464 if (objc_method *method = class_getInstanceMethod(_class, _cmd)) {
2465 imp = method_getImplementation(method);
2466 type = method_getTypeEncoding(method);
2471 if (NSMethodSignature *method = [self methodSignatureForSelector:_cmd])
2472 type = CYPoolCString(pool, context, [method _typeString]);
2478 throw CYJSError(context, "unrecognized selector %s sent to object %p", sel_getName(_cmd), self);
2485 sig::Signature signature;
2486 sig::Parse(pool, &signature, type, &Structor_);
2489 sig::sig_ffi_cif(pool, 0, signature, &cif);
2493 if (stret(cif.rtype))
2494 imp = class_getMethodImplementation_stret(_class, _cmd);
2497 imp = class_getMethodImplementation(_class, _cmd);
2500 void (*function)() = reinterpret_cast<void (*)()>(imp);
2501 return CYCallFunction(pool, context, 2, setup, count, arguments, initialize, true, signature, &cif, function);
2504 static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[]) {
2506 throw CYJSError(context, "too few arguments to objc_msgSend");
2516 if (JSValueIsObjectOfClass(context, arguments[0], CYPrivate<cy::Super>::Class_)) {
2517 cy::Super *internal(reinterpret_cast<cy::Super *>(JSObjectGetPrivate((JSObjectRef) arguments[0])));
2518 self = internal->value_;
2519 _class = internal->class_;;
2520 uninitialized = false;
2521 } else if (CYJSValueIsNSObject(context, arguments[0])) {
2522 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate((JSObjectRef) arguments[0])));
2523 self = internal->value_;
2525 uninitialized = internal->IsUninitialized();
2526 if (uninitialized && [internal->value_ retainCount] != NSUInteger(-1))
2527 internal->value_ = nil;
2529 self = CYCastNSObject(&pool, context, arguments[0]);
2531 uninitialized = false;
2535 return CYJSNull(context);
2537 _cmd = CYCastSEL(context, arguments[1]);
2539 return CYSendMessage(pool, context, self, _class, _cmd, count - 2, arguments + 2, uninitialized);
2542 static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2543 return $objc_msgSend(context, object, _this, count, arguments);
2546 static JSValueRef Selector_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2547 JSValueRef setup[count + 2];
2550 memcpy(setup + 2, arguments, sizeof(JSValueRef) * count);
2551 return $objc_msgSend(context, NULL, NULL, count + 2, setup);
2554 static JSValueRef Message_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2556 Message_privateData *internal(reinterpret_cast<Message_privateData *>(JSObjectGetPrivate(object)));
2558 // XXX: handle Instance::Uninitialized?
2559 id self(CYCastNSObject(&pool, context, _this));
2563 setup[1] = &internal->sel_;
2565 return CYCallFunction(pool, context, 2, setup, count, arguments, false, true, internal->signature_, &internal->cif_, internal->value_);
2568 static JSObjectRef Super_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2570 throw CYJSError(context, "incorrect number of arguments to objc_super constructor");
2572 id self(CYCastNSObject(&pool, context, arguments[0]));
2573 Class _class(CYCastClass(pool, context, arguments[1]));
2574 return CYPrivate<cy::Super>::Make(context, self, _class);
2577 static JSObjectRef Selector_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2579 throw CYJSError(context, "incorrect number of arguments to Selector constructor");
2581 const char *name(CYPoolCString(pool, context, arguments[0]));
2582 return CYPrivate<Selector_privateData>::Make(context, sel_registerName(name));
2585 static JSObjectRef Instance_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2587 throw CYJSError(context, "incorrect number of arguments to Instance constructor");
2588 return CYMakeInstance(context, CYCastPointer<id>(context, arguments[0]));
2591 static JSValueRef Selector_getProperty_$cyt(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2592 return CYMakeType(context, sig::Selector());
2595 static JSValueRef Instance_getProperty_$cyt(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2596 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
2597 id self(internal->value_);
2598 return CYMakeType(context, sig::Object(class_getName(object_getClass(self))));
2601 static JSValueRef FunctionInstance_getProperty_$cyt(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2602 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
2605 if (!CYBlockSignature(pool, internal->value_, type.signature))
2606 return CYJSNull(context);
2607 return CYMakeType(context, type);
2610 static JSValueRef Constructor_getProperty_$cyt(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2611 return CYMakeType(context, sig::Meta());
2614 static JSValueRef Instance_getProperty_constructor(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2615 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
2616 return CYMakeInstance(context, object_getClass(internal->value_), Instance::Permanent);
2619 static JSValueRef Constructor_getProperty_constructor(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2620 auto internal(CYPrivate<Constructor>::Get(context, object));
2621 return CYMakeInstance(context, object_getClass(internal->value_), Instance::Permanent);
2624 static JSValueRef Constructor_getProperty_prototype(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2625 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
2626 id self(internal->value_);
2627 return CYPrivate<Prototype>::Cache(context, self);
2630 static JSValueRef Instance_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2631 std::set<void *> *objects(CYCastObjects(context, _this, count, arguments));
2633 if (!CYJSValueIsNSObject(context, _this))
2636 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
2637 return CYCastJSValue(context, CYJSString(context, CYCastNSCYON(internal->value_, false, objects)));
2640 static JSValueRef Constructor_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2641 auto internal(CYPrivate<Constructor>::Get(context, _this));
2642 return CYCastJSValue(context, CYJSString(class_getName(internal->value_)));
2645 static JSValueRef Instance_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2646 if (!CYJSValueIsNSObject(context, _this))
2649 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
2650 id value(internal->value_);
2657 key = CYCastNSString(NULL, context, CYJSString(context, arguments[0]));
2659 if (!CYImplements(value, object_getClass(value), @selector(cy$toJSON:inContext:)))
2660 return CYJSUndefined(context);
2661 else if (JSValueRef json = [value cy$toJSON:key inContext:context])
2664 return CYCastJSValue(context, CYJSString(context, [value description]));
2666 } CYCatch(NULL) return /*XXX*/ NULL; }
2668 static JSValueRef Instance_callAsFunction_valueOf(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2669 if (!CYJSValueIsNSObject(context, _this))
2672 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
2673 id value(internal->value_);
2674 _assert(value != nil);
2676 if (![value respondsToSelector:@selector(cy$valueOfInContext:)])
2679 if (JSValueRef result = [value cy$valueOfInContext:context])
2683 } CYCatch(NULL) return /*XXX*/ NULL; }
2685 static JSValueRef Instance_callAsFunction_toPointer(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2686 if (!CYJSValueIsNSObject(context, _this))
2688 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
2689 // XXX: return CYMakePointer(context, internal->value_, sig::Object(class_getName(object_getClass(internal->value_))), NULL, object);
2690 return CYCastJSValue(context, reinterpret_cast<uintptr_t>(internal->value_));
2691 } CYCatch(NULL) return /*XXX*/ NULL; }
2693 static JSValueRef Constructor_callAsFunction_toPointer(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2694 auto internal(CYPrivate<Constructor>::Get(context, object));
2695 // XXX: return CYMakePointer(context, internal->value_, sig::Meta(), NULL, object);
2696 return CYCastJSValue(context, reinterpret_cast<uintptr_t>(internal->value_));
2697 } CYCatch(NULL) return /*XXX*/ NULL; }
2699 static JSValueRef Instance_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2700 if (!CYJSValueIsNSObject(context, _this))
2703 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
2704 id value(internal->value_);
2707 // XXX: this seems like a stupid implementation; what if it crashes? why not use the CYONifier backend?
2708 return CYCastJSValue(context, CYJSString(context, [value description]));
2710 } CYCatch(NULL) return /*XXX*/ NULL; }
2712 static JSValueRef Class_callAsFunction_pointerTo(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2713 if (!CYJSValueIsNSObject(context, _this))
2716 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
2717 id value(internal->value_);
2719 if (!CYIsClass(value))
2720 CYThrow("non-Class object cannot be used as Type");
2722 sig::Object type(class_getName(value));
2723 return CYMakeType(context, type);
2724 } CYCatch(NULL) return /*XXX*/ NULL; }
2726 static JSValueRef Selector_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2727 Selector_privateData *internal(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate(_this)));
2728 return CYCastJSValue(context, sel_getName(internal->value_));
2731 static JSValueRef Selector_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
2732 return Selector_callAsFunction_toString(context, object, _this, count, arguments, exception);
2735 static JSValueRef Selector_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2736 Selector_privateData *internal(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate(_this)));
2737 const char *name(sel_getName(internal->value_));
2740 NSString *string([NSString stringWithFormat:@"@selector(%s)", name]);
2741 return CYCastJSValue(context, CYJSString(context, string));
2743 } CYCatch(NULL) return /*XXX*/ NULL; }
2745 static JSValueRef Selector_callAsFunction_type(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2747 throw CYJSError(context, "incorrect number of arguments to Selector.type");
2750 Selector_privateData *internal(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate(_this)));
2751 SEL sel(internal->value_);
2753 Class _class(_require(CYCastClass(pool, context, arguments[0])));
2754 objc_method *method(_require(class_getInstanceMethod(_class, sel)));
2755 const char *encoding(method_getTypeEncoding(method));
2757 sig::Function type(false);
2758 sig::Parse(pool, &type.signature, encoding, &Structor_);
2759 return CYMakeType(context, type);
2762 static JSStaticValue Selector_staticValues[2] = {
2763 {"$cyt", &Selector_getProperty_$cyt, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2764 {NULL, NULL, NULL, 0}
2767 static JSStaticValue Instance_staticValues[3] = {
2768 {"$cyt", &Instance_getProperty_$cyt, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2769 // XXX: this is sadly duplicated in FunctionInstance_staticValues
2770 {"constructor", &Instance_getProperty_constructor, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2771 {NULL, NULL, NULL, 0}
2774 static JSStaticValue FunctionInstance_staticValues[3] = {
2775 {"$cyt", &FunctionInstance_getProperty_$cyt, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2776 // XXX: this is sadly a duplicate of Instance_staticValues
2777 {"constructor", &Instance_getProperty_constructor, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2778 {NULL, NULL, NULL, 0}
2781 static JSStaticFunction Instance_staticFunctions[7] = {
2782 {"cy$complete", &Instance_complete_callAsFunction, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2783 {"toCYON", &Instance_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2784 {"toJSON", &Instance_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2785 {"valueOf", &Instance_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2786 {"toPointer", &Instance_callAsFunction_toPointer, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2787 {"toString", &Instance_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2791 static JSStaticFunction Messages_staticFunctions[2] = {
2792 {"cy$complete", &Messages_complete_callAsFunction, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2796 static JSStaticValue Constructor_staticValues[5] = {
2797 {"$cyi", &Constructor_getProperty_$cyi, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2798 {"$cyt", &Constructor_getProperty_$cyt, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2799 {"constructor", &Constructor_getProperty_constructor, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2800 {"prototype", &Constructor_getProperty_prototype, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2801 {NULL, NULL, NULL, 0}
2804 static JSStaticFunction Constructor_staticFunctions[5] = {
2805 {"pointerTo", &Class_callAsFunction_pointerTo, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2806 {"toCYON", &Constructor_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2807 {"toPointer", &Constructor_callAsFunction_toPointer, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2811 static JSStaticFunction Interior_staticFunctions[2] = {
2812 {"$cya", &Interior_callAsFunction_$cya, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2816 static JSStaticFunction Selector_staticFunctions[5] = {
2817 {"toCYON", &Selector_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2818 {"toJSON", &Selector_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2819 {"toString", &Selector_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2820 {"type", &Selector_callAsFunction_type, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2825 JSValueRef NSCFType$cy$toJSON$inContext$(id self, SEL sel, JSValueRef key, JSContextRef context) { CYObjectiveTry_ {
2826 return CYCastJSValue(context, [(NSString *) CFCopyDescription((CFTypeRef) self) autorelease]);
2827 } CYObjectiveCatch }
2830 void CYObjectiveC_Initialize() { /*XXX*/ JSContextRef context(NULL); CYPoolTry {
2831 NSArray_ = objc_getClass("NSArray");
2832 NSBlock_ = objc_getClass("NSBlock");
2833 NSDictionary_ = objc_getClass("NSDictionary");
2834 NSNumber_ = objc_getClass("NSNumber");
2835 NSString_ = objc_getClass("NSString");
2836 Object_ = objc_getClass("Object");
2839 __NSMallocBlock__ = objc_getClass("__NSMallocBlock__");
2841 // XXX: apparently, iOS now has both of these
2842 NSCFBoolean_ = objc_getClass("__NSCFBoolean");
2843 if (NSCFBoolean_ == nil)
2844 NSCFBoolean_ = objc_getClass("NSCFBoolean");
2846 NSCFType_ = objc_getClass("NSCFType");
2848 NSZombie_ = objc_getClass("_NSZombie_");
2850 NSBoolNumber_ = objc_getClass("NSBoolNumber");
2851 NSZombie_ = objc_getClass("NSZombie");
2854 JSClassDefinition definition;
2856 definition = kJSClassDefinitionEmpty;
2857 definition.attributes = kJSClassAttributeNoAutomaticPrototype;
2858 definition.className = "Messages";
2859 definition.staticFunctions = Messages_staticFunctions;
2860 definition.hasProperty = &Messages_hasProperty;
2861 definition.getProperty = &Messages_getProperty;
2862 definition.setProperty = &Messages_setProperty;
2863 CYPrivate<Messages>::Class_ = JSClassCreate(&definition);
2865 definition = kJSClassDefinitionEmpty;
2866 definition.className = "Constructor";
2867 definition.parentClass = CYPrivate<Messages>::Class_;
2868 definition.staticValues = Constructor_staticValues;
2869 definition.staticFunctions = Constructor_staticFunctions;
2870 definition.hasInstance = &Constructor_hasInstance;
2871 definition.hasProperty = &Constructor_hasProperty;
2872 definition.getProperty = &Constructor_getProperty;
2873 definition.callAsConstructor = &Constructor_callAsConstructor;
2874 definition.finalize = &CYFinalize;
2875 CYPrivate<Constructor>::Class_ = JSClassCreate(&definition);
2877 definition = kJSClassDefinitionEmpty;
2878 definition.className = "Instance";
2879 definition.staticValues = Instance_staticValues;
2880 definition.staticFunctions = Instance_staticFunctions;
2881 definition.hasProperty = &Instance_hasProperty;
2882 definition.getProperty = &Instance_getProperty;
2883 definition.setProperty = &Instance_setProperty;
2884 definition.deleteProperty = &Instance_deleteProperty;
2885 definition.getPropertyNames = &Instance_getPropertyNames;
2886 definition.finalize = &CYFinalize;
2887 Instance::Class_ = JSClassCreate(&definition);
2889 definition.className = "ArrayInstance";
2890 ArrayInstance_ = JSClassCreate(&definition);
2892 definition.className = "BooleanInstance";
2893 BooleanInstance_ = JSClassCreate(&definition);
2895 definition.className = "NumberInstance";
2896 NumberInstance_ = JSClassCreate(&definition);
2898 definition.className = "ObjectInstance";
2899 ObjectInstance_ = JSClassCreate(&definition);
2901 definition.className = "StringInstance";
2902 StringInstance_ = JSClassCreate(&definition);
2904 definition.className = "FunctionInstance";
2905 definition.staticValues = FunctionInstance_staticValues;
2906 definition.callAsFunction = &FunctionInstance_callAsFunction;
2907 FunctionInstance_ = JSClassCreate(&definition);
2909 definition = kJSClassDefinitionEmpty;
2910 definition.className = "Interior";
2911 definition.staticFunctions = Interior_staticFunctions;
2912 definition.hasProperty = &Interior_hasProperty;
2913 definition.getProperty = &Interior_getProperty;
2914 definition.setProperty = &Interior_setProperty;
2915 definition.getPropertyNames = &Interior_getPropertyNames;
2916 definition.finalize = &CYFinalize;
2917 CYPrivate<Interior>::Class_ = JSClassCreate(&definition);
2919 definition = kJSClassDefinitionEmpty;
2920 definition.className = "Message";
2921 definition.staticFunctions = cy::Functor::StaticFunctions;
2922 definition.staticValues = cy::Functor::StaticValues;
2923 definition.callAsFunction = &Message_callAsFunction;
2924 definition.finalize = &CYFinalize;
2925 Message_privateData::Class_ = JSClassCreate(&definition);
2927 definition = kJSClassDefinitionEmpty;
2928 definition.attributes = kJSClassAttributeNoAutomaticPrototype;
2929 definition.className = "Prototype";
2930 definition.parentClass = CYPrivate<Messages>::Class_;
2931 definition.finalize = &CYFinalize;
2932 CYPrivate<Prototype>::Class_ = JSClassCreate(&definition);
2934 definition = kJSClassDefinitionEmpty;
2935 definition.className = "Selector";
2936 definition.staticValues = Selector_staticValues;
2937 definition.staticFunctions = Selector_staticFunctions;
2938 definition.callAsFunction = &Selector_callAsFunction;
2939 definition.finalize = &CYFinalize;
2940 CYPrivate<Selector_privateData>::Class_ = JSClassCreate(&definition);
2942 definition = kJSClassDefinitionEmpty;
2943 definition.className = "Super";
2944 definition.finalize = &CYFinalize;
2945 CYPrivate<cy::Super>::Class_ = JSClassCreate(&definition);
2947 definition = kJSClassDefinitionEmpty;
2948 definition.className = "ObjectiveC::Classes";
2949 definition.hasProperty = &ObjectiveC_Classes_hasProperty;
2950 definition.getProperty = &ObjectiveC_Classes_getProperty;
2951 definition.getPropertyNames = &ObjectiveC_Classes_getPropertyNames;
2952 ObjectiveC_Classes_ = JSClassCreate(&definition);
2954 definition = kJSClassDefinitionEmpty;
2955 definition.className = "ObjectiveC::Constants";
2956 definition.getProperty = &ObjectiveC_Constants_getProperty;
2957 definition.getPropertyNames = &ObjectiveC_Constants_getPropertyNames;
2958 ObjectiveC_Constants_ = JSClassCreate(&definition);
2961 definition = kJSClassDefinitionEmpty;
2962 definition.className = "ObjectiveC::Images";
2963 definition.getProperty = &ObjectiveC_Images_getProperty;
2964 definition.getPropertyNames = &ObjectiveC_Images_getPropertyNames;
2965 ObjectiveC_Images_ = JSClassCreate(&definition);
2967 definition = kJSClassDefinitionEmpty;
2968 definition.className = "ObjectiveC::Image::Classes";
2969 definition.getProperty = &ObjectiveC_Image_Classes_getProperty;
2970 definition.getPropertyNames = &ObjectiveC_Image_Classes_getPropertyNames;
2971 ObjectiveC_Image_Classes_ = JSClassCreate(&definition);
2974 definition = kJSClassDefinitionEmpty;
2975 definition.className = "ObjectiveC::Protocols";
2976 definition.getProperty = &ObjectiveC_Protocols_getProperty;
2977 definition.getPropertyNames = &ObjectiveC_Protocols_getPropertyNames;
2978 ObjectiveC_Protocols_ = JSClassCreate(&definition);
2981 class_addMethod(NSCFType_, @selector(cy$toJSON:inContext:), reinterpret_cast<IMP>(&NSCFType$cy$toJSON$inContext$),
2982 // XXX: this is horrible; there has to be a better way to do this
2984 "^{OpaqueJSValue=}32@0:8@16^{OpaqueJSContext=}24"
2986 "^{OpaqueJSValue=}16@0:4@8^{OpaqueJSContext=}12"
2992 void CYObjectiveC_SetupContext(JSContextRef context) { CYPoolTry {
2993 JSObjectRef global(CYGetGlobalObject(context));
2994 JSObjectRef cy(CYCastJSObject(context, CYGetProperty(context, global, cy_s)));
2995 JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
2996 JSObjectRef all(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("all"))));
2997 JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls"))));
2999 JSObjectRef ObjectiveC(JSObjectMake(context, NULL, NULL));
3000 CYSetProperty(context, cycript, CYJSString("ObjectiveC"), ObjectiveC);
3002 JSObjectRef protocols(JSObjectMake(context, ObjectiveC_Protocols_, NULL));
3003 CYSetProperty(context, ObjectiveC, CYJSString("protocols"), protocols);
3004 CYArrayPush(context, alls, protocols);
3006 JSObjectRef classes(JSObjectMake(context, ObjectiveC_Classes_, NULL));
3007 CYSetProperty(context, ObjectiveC, CYJSString("classes"), classes);
3008 CYArrayPush(context, alls, classes);
3010 JSObjectRef constants(JSObjectMake(context, ObjectiveC_Constants_, NULL));
3011 CYSetProperty(context, ObjectiveC, CYJSString("constants"), constants);
3012 CYArrayPush(context, alls, constants);
3015 CYSetProperty(context, ObjectiveC, CYJSString("images"), JSObjectMake(context, ObjectiveC_Images_, NULL));
3018 JSObjectRef Message(JSObjectMakeConstructor(context, Message_privateData::Class_, NULL));
3019 JSObjectRef Selector(JSObjectMakeConstructor(context, CYPrivate<Selector_privateData>::Class_, &Selector_new));
3020 JSObjectRef Super(JSObjectMakeConstructor(context, CYPrivate<cy::Super>::Class_, &Super_new));
3022 JSObjectRef Instance(JSObjectMakeConstructor(context, Instance::Class_, &Instance_new));
3023 JSObjectRef Instance_prototype(CYCastJSObject(context, CYGetProperty(context, Instance, prototype_s)));
3024 CYSetProperty(context, cy, CYJSString("Instance_prototype"), Instance_prototype);
3026 JSObjectRef Constructor(JSObjectMakeConstructor(context, CYPrivate<::Constructor>::Class_, NULL));
3027 JSObjectRef Constructor_prototype(CYCastJSObject(context, CYGetProperty(context, Constructor, prototype_s)));
3028 CYSetProperty(context, cy, CYJSString("Constructor_prototype"), Constructor_prototype);
3030 JSObjectRef ArrayInstance(JSObjectMakeConstructor(context, ArrayInstance_, NULL));
3031 JSObjectRef ArrayInstance_prototype(CYCastJSObject(context, CYGetProperty(context, ArrayInstance, prototype_s)));
3032 CYSetProperty(context, cy, CYJSString("ArrayInstance_prototype"), ArrayInstance_prototype);
3033 JSObjectRef Array_prototype(CYGetCachedObject(context, CYJSString("Array_prototype")));
3034 CYSetPrototype(context, ArrayInstance_prototype, Array_prototype);
3036 JSObjectRef BooleanInstance(JSObjectMakeConstructor(context, BooleanInstance_, NULL));
3037 JSObjectRef BooleanInstance_prototype(CYCastJSObject(context, CYGetProperty(context, BooleanInstance, prototype_s)));
3038 CYSetProperty(context, cy, CYJSString("BooleanInstance_prototype"), BooleanInstance_prototype);
3039 JSObjectRef Boolean_prototype(CYGetCachedObject(context, CYJSString("Boolean_prototype")));
3040 CYSetPrototype(context, BooleanInstance_prototype, Boolean_prototype);
3042 JSObjectRef FunctionInstance(JSObjectMakeConstructor(context, FunctionInstance_, NULL));
3043 JSObjectRef FunctionInstance_prototype(CYCastJSObject(context, CYGetProperty(context, FunctionInstance, prototype_s)));
3044 CYSetProperty(context, cy, CYJSString("FunctionInstance_prototype"), FunctionInstance_prototype);
3045 JSObjectRef Function_prototype(CYGetCachedObject(context, CYJSString("Function_prototype")));
3046 CYSetPrototype(context, FunctionInstance_prototype, Function_prototype);
3048 JSObjectRef NumberInstance(JSObjectMakeConstructor(context, NumberInstance_, NULL));
3049 JSObjectRef NumberInstance_prototype(CYCastJSObject(context, CYGetProperty(context, NumberInstance, prototype_s)));
3050 CYSetProperty(context, cy, CYJSString("NumberInstance_prototype"), NumberInstance_prototype);
3051 JSObjectRef Number_prototype(CYGetCachedObject(context, CYJSString("Number_prototype")));
3052 CYSetPrototype(context, NumberInstance_prototype, Number_prototype);
3054 JSObjectRef ObjectInstance(JSObjectMakeConstructor(context, ObjectInstance_, NULL));
3055 JSObjectRef ObjectInstance_prototype(CYCastJSObject(context, CYGetProperty(context, ObjectInstance, prototype_s)));
3056 CYSetProperty(context, cy, CYJSString("ObjectInstance_prototype"), ObjectInstance_prototype);
3057 JSObjectRef Object_prototype(CYGetCachedObject(context, CYJSString("Object_prototype")));
3058 CYSetPrototype(context, ObjectInstance_prototype, Object_prototype);
3060 JSObjectRef StringInstance(JSObjectMakeConstructor(context, StringInstance_, NULL));
3061 JSObjectRef StringInstance_prototype(CYCastJSObject(context, CYGetProperty(context, StringInstance, prototype_s)));
3062 CYSetProperty(context, cy, CYJSString("StringInstance_prototype"), StringInstance_prototype);
3063 JSObjectRef String_prototype(CYGetCachedObject(context, CYJSString("String_prototype")));
3064 CYSetPrototype(context, StringInstance_prototype, String_prototype);
3066 CYSetProperty(context, cycript, CYJSString("Instance"), Instance);
3067 CYSetProperty(context, cycript, CYJSString("Message"), Message);
3068 CYSetProperty(context, cycript, CYJSString("Selector"), Selector);
3069 CYSetProperty(context, cycript, CYJSString("objc_super"), Super);
3071 JSObjectRef box(JSObjectMakeFunctionWithCallback(context, CYJSString("box"), &Instance_box_callAsFunction));
3072 CYSetProperty(context, Instance, CYJSString("box"), box, kJSPropertyAttributeDontEnum);
3075 CYSetProperty(context, all, CYJSString("choose"), &choose, kJSPropertyAttributeDontEnum);
3078 CYSetProperty(context, all, CYJSString("objc_msgSend"), &$objc_msgSend, kJSPropertyAttributeDontEnum);
3080 CYSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Message, prototype_s)), Function_prototype);
3081 CYSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Selector, prototype_s)), Function_prototype);
3083 JSObjectRef cache(CYGetCachedObject(context, CYJSString("cache")));
3084 CYSetProperty(context, cache, CYJSString("YES"), JSValueMakeBoolean(context, true), kJSPropertyAttributeDontEnum);
3085 CYSetProperty(context, cache, CYJSString("NO"), JSValueMakeBoolean(context, false), kJSPropertyAttributeDontEnum);
3086 CYSetProperty(context, cache, CYJSString("id"), CYMakeType(context, sig::Object()), kJSPropertyAttributeDontEnum);
3087 CYSetProperty(context, cache, CYJSString("Class"), CYMakeType(context, sig::Meta()), kJSPropertyAttributeDontEnum);
3088 CYSetProperty(context, cache, CYJSString("SEL"), CYMakeType(context, sig::Selector()), kJSPropertyAttributeDontEnum);
3090 CYSetProperty(context, cy, CYJSString("cydget"), CYCastJSValue(context, false));
3093 static void *CYObjectiveC_CastSymbol(const char *name) {
3095 #ifdef __GNU_LIBOBJC__
3096 else if (strcmp(name, "object_getClass") == 0)
3097 return reinterpret_cast<void *>(&object_getClass);
3102 static CYHook CYObjectiveCHook = {
3103 &CYObjectiveC_ExecuteStart,
3104 &CYObjectiveC_ExecuteEnd,
3105 &CYObjectiveC_CallFunction,
3106 &CYObjectiveC_Initialize,
3107 &CYObjectiveC_SetupContext,
3108 &CYObjectiveC_CastSymbol,
3111 CYRegisterHook CYObjectiveC(&CYObjectiveCHook);
3113 _extern void CydgetSetupContext(JSGlobalContextRef context) { CYObjectiveTry_ {
3114 CYSetupContext(context);
3115 JSObjectRef global(CYGetGlobalObject(context));
3116 JSObjectRef cy(CYCastJSObject(context, CYGetProperty(context, global, cy_s)));
3117 CYSetProperty(context, cy, CYJSString("cydget"), CYCastJSValue(context, true));
3118 } CYObjectiveCatch }
3120 _extern void CydgetMemoryParse(const uint16_t **data, size_t *size) { try {
3123 CYUTF8String utf8(CYPoolUTF8String(pool, CYUTF16String(*data, *size)));
3124 utf8 = CYPoolCode(pool, utf8);
3126 CYUTF16String utf16(CYPoolUTF16String(pool, CYUTF8String(utf8.data, utf8.size)));
3127 size_t bytes(utf16.size * sizeof(uint16_t));
3128 uint16_t *copy(reinterpret_cast<uint16_t *>(malloc(bytes)));
3129 memcpy(copy, utf16.data, bytes);
3133 } catch (const CYException &exception) {
3135 @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"%s", exception.PoolCString(pool)] userInfo:nil];