]> git.saurik.com Git - cycript.git/blob - ObjectiveC/Library.mm
051f9b2453e07d24d1c3e809e4e7aa23001a404c
[cycript.git] / ObjectiveC / Library.mm
1 /* Cycript - The Truly Universal Scripting Language
2 * Copyright (C) 2009-2016 Jay Freeman (saurik)
3 */
4
5 /* GNU Affero General Public License, Version 3 {{{ */
6 /*
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 #include "cycript.hpp"
23
24 #include <cmath>
25
26 #include <map>
27 #include <set>
28
29 #include <dlfcn.h>
30
31 #ifdef __APPLE__
32 #include <malloc/malloc.h>
33 #include <mach/mach.h>
34 #endif
35
36 #include <objc/message.h>
37 #include <objc/runtime.h>
38
39 #ifdef __APPLE__
40 #include <CoreFoundation/CoreFoundation.h>
41 #include <JavaScriptCore/JSStringRefCF.h>
42 #endif
43
44 #include <Foundation/Foundation.h>
45
46 #include "Code.hpp"
47 #include "Decode.hpp"
48 #include "Error.hpp"
49 #include "Functor.hpp"
50 #include "JavaScript.hpp"
51 #include "String.hpp"
52 #include "Execute.hpp"
53
54 #include "ObjectiveC/Internal.hpp"
55 #include "ObjectiveC/Syntax.hpp"
56
57 #define CYObjectiveTry_ { \
58 try
59 #define CYObjectiveTry { \
60 JSContextRef context(context_); \
61 try
62 #define CYObjectiveCatch \
63 catch (const CYException &error) { \
64 @throw CYCastNSObject(NULL, context, error.CastJSValue(context, "Error")); \
65 } \
66 }
67
68 #define CYPoolTry { \
69 id _saved(nil); \
70 NSAutoreleasePool *_pool([[NSAutoreleasePool alloc] init]); \
71 @try
72 #define CYPoolCatch(value) \
73 @catch (NSException *error) { \
74 _saved = [error retain]; \
75 throw CYJSError(context, CYCastJSValue(context, error)); \
76 return value; \
77 } @finally { \
78 [_pool release]; \
79 if (_saved != nil) \
80 [_saved autorelease]; \
81 } \
82 }
83
84 #define CYSadTry { \
85 @try
86 #define CYSadCatch(value) \
87 @catch (NSException *error ) { \
88 throw CYJSError(context, CYCastJSValue(context, error)); \
89 } return value; \
90 }
91
92 #define _oassert(test) \
93 if (!(test)) \
94 @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"_assert(" #test ")" userInfo:nil];
95
96 @class NSBlock;
97
98 struct BlockLiteral {
99 Class isa;
100 int flags;
101 int reserved;
102 void (*invoke)(void *, ...);
103 void *descriptor;
104 };
105
106 struct BlockDescriptor1 {
107 unsigned long int reserved;
108 unsigned long int size;
109 };
110
111 struct BlockDescriptor2 {
112 void (*copy_helper)(BlockLiteral *dst, BlockLiteral *src);
113 void (*dispose_helper)(BlockLiteral *src);
114 };
115
116 struct BlockDescriptor3 {
117 const char *signature;
118 const char *layout;
119 };
120
121 enum {
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,
131 };
132
133 static bool CYIsClass(id self) {
134 return class_isMetaClass(object_getClass(self));
135 }
136
137 JSValueRef CYSendMessage(CYPool &pool, JSContextRef context, id self, Class super, SEL _cmd, size_t count, const JSValueRef arguments[], bool initialize);
138
139 /* Objective-C Pool Release {{{ */
140 void CYPoolRelease_(void *data) {
141 id object(reinterpret_cast<id>(data));
142 [object release];
143 }
144
145 id CYPoolRelease_(CYPool *pool, id object) {
146 if (object == nil)
147 return nil;
148 else if (pool == NULL)
149 return [object autorelease];
150 else {
151 pool->atexit(CYPoolRelease_);
152 return object;
153 }
154 }
155
156 template <typename Type_>
157 Type_ CYPoolRelease(CYPool *pool, Type_ object) {
158 return (Type_) CYPoolRelease_(pool, (id) object);
159 }
160 /* }}} */
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]);
168 }
169
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);
173 return utf8.data;
174 }
175
176 #ifdef __clang__
177 JSStringRef CYCopyJSString(JSContextRef context, NSString *value) {
178 return JSStringCreateWithCFString(reinterpret_cast<CFStringRef>(value));
179 }
180 #endif
181
182 JSStringRef CYCopyJSString(JSContextRef context, NSObject *value) {
183 if (value == nil)
184 return NULL;
185 // XXX: this definition scares me; is anyone using this?!
186 NSString *string([value description]);
187 #ifdef __clang__
188 return CYCopyJSString(context, string);
189 #else
190 CYPool pool;
191 return CYCopyJSString(CYPoolUTF8String(pool, context, string));
192 #endif
193 }
194
195 NSString *CYCopyNSString(const CYUTF8String &value) {
196 #ifdef __APPLE__
197 return (NSString *) CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(value.data), value.size, kCFStringEncodingUTF8, true);
198 #else
199 return [[NSString alloc] initWithBytes:value.data length:value.size encoding:NSUTF8StringEncoding];
200 #endif
201 }
202
203 NSString *CYCopyNSString(JSContextRef context, JSStringRef value) {
204 #ifdef __APPLE__
205 return (NSString *) JSStringCopyCFString(kCFAllocatorDefault, value);
206 #else
207 CYPool pool;
208 return CYCopyNSString(CYPoolUTF8String(pool, context, value));
209 #endif
210 }
211
212 NSString *CYCopyNSString(JSContextRef context, JSValueRef value) {
213 return CYCopyNSString(context, CYJSString(context, value));
214 }
215
216 NSString *CYCastNSString(CYPool *pool, const CYUTF8String &value) {
217 return CYPoolRelease(pool, CYCopyNSString(value));
218 }
219
220 NSString *CYCastNSString(CYPool *pool, SEL sel) {
221 const char *name(sel_getName(sel));
222 return CYPoolRelease(pool, CYCopyNSString(CYUTF8String(name, strlen(name))));
223 }
224
225 NSString *CYCastNSString(CYPool *pool, JSContextRef context, JSStringRef value) {
226 return CYPoolRelease(pool, CYCopyNSString(context, value));
227 }
228
229 CYUTF8String CYCastUTF8String(NSString *value) {
230 NSData *data([value dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO]);
231 return CYUTF8String(reinterpret_cast<const char *>([data bytes]), [data length]);
232 }
233 /* }}} */
234
235 JSValueRef CYCastJSValue(JSContextRef context, NSObject *value);
236
237 void CYThrow(JSContextRef context, NSException *error, JSValueRef *exception) {
238 if (exception == NULL)
239 throw error;
240 *exception = CYCastJSValue(context, error);
241 }
242
243 size_t CYGetIndex(NSString *value) {
244 return CYGetIndex(CYCastUTF8String(value));
245 }
246
247 bool CYGetOffset(CYPool &pool, JSContextRef context, NSString *value, ssize_t &index) {
248 return CYGetOffset(CYPoolCString(pool, context, value), index);
249 }
250
251 static JSClassRef ArrayInstance_;
252 static JSClassRef BooleanInstance_;
253 static JSClassRef FunctionInstance_;
254 static JSClassRef NumberInstance_;
255 static JSClassRef ObjectInstance_;
256 static JSClassRef StringInstance_;
257
258 static JSClassRef ObjectiveC_Classes_;
259 static JSClassRef ObjectiveC_Constants_;
260 static JSClassRef ObjectiveC_Protocols_;
261
262 #ifdef __APPLE__
263 static JSClassRef ObjectiveC_Image_Classes_;
264 static JSClassRef ObjectiveC_Images_;
265 #endif
266
267 #ifdef __APPLE__
268 static Class __NSMallocBlock__;
269 static Class NSCFBoolean_;
270 static Class NSCFType_;
271 static Class NSGenericDeallocHandler_;
272 #else
273 static Class NSBoolNumber_;
274 #endif
275
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_;
283
284 static JSValueRef Instance_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception);
285
286 JSValueRef Prototype::GetPrototype(JSContextRef context) const {
287 #ifdef __APPLE__
288 if (value_ == NSCFBoolean_)
289 #else
290 if (value_ == NSBoolNumber_)
291 #endif
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"));
303
304 if (Class super = class_getSuperclass(value_))
305 return CYPrivate<Prototype>::Cache(context, super);
306 return CYGetCachedObject(context, CYJSString("Instance_prototype"));
307 }
308
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"));
313 }
314
315 bool CYIsKindOfClass(id object, Class _class) {
316 for (Class isa(object_getClass(object)); isa != NULL; isa = class_getSuperclass(isa))
317 if (isa == _class)
318 return true;
319 return false;
320 }
321
322 JSValueRef Instance::GetPrototype(JSContextRef context) const {
323 return CYPrivate<Prototype>::Cache(context, object_getClass(value_));
324 }
325
326 JSClassRef Instance::GetClass(id object, Flags flags) {
327 return CYIsKindOfClass(object, NSBlock_) ? FunctionInstance_ : Instance::Class_;
328 }
329
330 Instance::Instance(id value, Flags flags) :
331 value_(value),
332 flags_(flags)
333 {
334 if (IsPermanent());
335 /*else if ([value retainCount] == NSUInteger(-1))
336 flags_ |= Instance::Permanent;*/
337 else
338 value_ = [value_ retain];
339 }
340
341 Instance::~Instance() {
342 if (!IsPermanent())
343 [value_ release];
344 }
345
346 struct Message_privateData :
347 cy::Functor
348 {
349 static JSClassRef Class_;
350
351 SEL sel_;
352
353 Message_privateData(SEL sel, const char *type, IMP value) :
354 cy::Functor(reinterpret_cast<void (*)()>(value), type),
355 sel_(sel)
356 {
357 }
358
359 static JSObjectRef Make(JSContextRef context, SEL sel, const char *type, IMP value);
360 };
361
362 JSClassRef Message_privateData::Class_;
363
364 JSObjectRef CYMakeInstance(JSContextRef context, id object, Instance::Flags flags = Instance::None) {
365 _assert(object != nil);
366
367 #ifdef __APPLE__
368 JSWeakObjectMapRef weak(CYCastPointer<JSWeakObjectMapRef>(context, CYGetCachedValue(context, weak_s)));
369
370 if (weak != NULL && &JSWeakObjectMapGet != NULL)
371 if (JSObjectRef instance = JSWeakObjectMapGet(context, weak, object))
372 return instance;
373 #endif
374
375 JSObjectRef instance;
376 if (CYIsClass(object) && !class_isMetaClass(object))
377 instance = CYPrivate<Constructor>::Cache(context, object);
378 else
379 instance = Instance::Make(context, object, flags);
380
381 #ifdef __APPLE__
382 if (weak != NULL && &JSWeakObjectMapSet != NULL)
383 JSWeakObjectMapSet(context, weak, object, instance);
384 #endif
385
386 return instance;
387 }
388
389 @interface NSMethodSignature (Cycript)
390 - (NSString *) _typeString;
391 @end
392
393 @interface NSObject (Cycript)
394
395 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context;
396 - (JSType) cy$JSType;
397
398 - (JSValueRef) cy$toJSON:(NSString *)key inContext:(JSContextRef)context;
399 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects;
400
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;
407
408 + (bool) cy$hasImplicitProperties;
409
410 @end
411
412 @protocol Cycript
413 - (id) cy$box;
414 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context;
415 @end
416
417 NSString *CYCastNSCYON(id value, bool objective, std::set<void *> &objects) {
418 _assert(value != nil);
419
420 Class _class(object_getClass(value));
421
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];
426 else
427 return [NSString stringWithUTF8String:name];
428 }
429
430 if (_class == NSZombie_)
431 return [NSString stringWithFormat:@"<_NSZombie_: %p>", value];
432
433 SEL sel(@selector(cy$toCYON:inSet:));
434
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];
440
441 return [NSString stringWithFormat:@"%@", value];
442 }
443
444 NSString *CYCastNSCYON(id value, bool objective, std::set<void *> *objects) {
445 if (objects != NULL)
446 return CYCastNSCYON(value, objective, *objects);
447 else {
448 std::set<void *> objects;
449 return CYCastNSCYON(value, objective, objects);
450 }
451 }
452
453 struct PropertyAttributes {
454 CYPool pool_;
455
456 const char *name;
457
458 const char *variable;
459
460 const char *getter_;
461 const char *setter_;
462
463 bool readonly;
464 bool copy;
465 bool retain;
466 bool nonatomic;
467 bool dynamic;
468 bool weak;
469 bool garbage;
470
471 PropertyAttributes(objc_property_t property) :
472 variable(NULL),
473 getter_(NULL),
474 setter_(NULL),
475 readonly(false),
476 copy(false),
477 retain(false),
478 nonatomic(false),
479 dynamic(false),
480 weak(false),
481 garbage(false)
482 {
483 name = property_getName(property);
484 const char *attributes(property_getAttributes(property));
485
486 for (char *token(pool_.strdup(attributes)), *next; token != NULL; token = next) {
487 if ((next = strchr(token, ',')) != NULL)
488 *next++ = '\0';
489 switch (*token) {
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;
497 }
498 }
499
500 /*if (variable == NULL) {
501 variable = property_getName(property);
502 size_t size(strlen(variable));
503 char *name(new(pool_) char[size + 2]);
504 name[0] = '_';
505 memcpy(name + 1, variable, size);
506 name[size + 1] = '\0';
507 variable = name;
508 }*/
509 }
510
511 const char *Getter() {
512 if (getter_ == NULL)
513 getter_ = pool_.strdup(name);
514 return getter_;
515 }
516
517 const char *Setter() {
518 if (setter_ == NULL && !readonly) {
519 size_t length(strlen(name));
520
521 char *temp(new(pool_) char[length + 5]);
522 temp[0] = 's';
523 temp[1] = 'e';
524 temp[2] = 't';
525
526 if (length != 0) {
527 temp[3] = toupper(name[0]);
528 memcpy(temp + 4, name + 1, length - 1);
529 }
530
531 temp[length + 3] = ':';
532 temp[length + 4] = '\0';
533 setter_ = temp;
534 }
535
536 return setter_;
537 }
538
539 };
540
541 @interface CYWebUndefined : NSObject {
542 }
543
544 + (CYWebUndefined *) undefined;
545
546 @end
547
548 @implementation CYWebUndefined
549
550 + (CYWebUndefined *) undefined {
551 static CYWebUndefined *instance_([[CYWebUndefined alloc] init]);
552 return instance_;
553 }
554
555 @end
556
557 #define WebUndefined CYWebUndefined
558
559 /* Bridge: CYJSObject {{{ */
560 @interface CYJSObject : NSMutableDictionary {
561 JSObjectRef object_;
562 JSGlobalContextRef context_;
563 }
564
565 - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context;
566
567 - (NSUInteger) count;
568 - (id) objectForKey:(id)key;
569 - (NSEnumerator *) keyEnumerator;
570 - (void) setObject:(id)object forKey:(id)key;
571 - (void) removeObjectForKey:(id)key;
572
573 @end
574 /* }}} */
575 /* Bridge: CYJSArray {{{ */
576 @interface CYJSArray : NSMutableArray {
577 JSObjectRef object_;
578 JSGlobalContextRef context_;
579 }
580
581 - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context;
582
583 - (NSUInteger) count;
584 - (id) objectAtIndex:(NSUInteger)index;
585
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;
591
592 @end
593 /* }}} */
594
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_);
597 }
598
599 _finline bool CYJSValueIsInstanceOfCachedConstructor(JSContextRef context, JSValueRef value, JSStringRef cache) {
600 return _jsccall(JSValueIsInstanceOfConstructor, context, value, CYGetCachedObject(context, cache));
601 }
602
603 #ifdef __APPLE__
604 struct CYBlockDescriptor {
605 struct {
606 BlockDescriptor1 one_;
607 BlockDescriptor2 two_;
608 BlockDescriptor3 three_;
609 } d_;
610
611 Closure_privateData *internal_;
612 };
613
614 void CYDisposeBlock(BlockLiteral *literal) {
615 delete reinterpret_cast<CYBlockDescriptor *>(literal->descriptor)->internal_;
616 }
617
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);
621 }
622
623 NSBlock *CYMakeBlock(JSContextRef context, JSObjectRef function, sig::Signature &signature) {
624 _assert(__NSMallocBlock__ != Nil);
625 BlockLiteral *literal(reinterpret_cast<BlockLiteral *>(malloc(sizeof(BlockLiteral))));
626
627 CYBlockDescriptor *descriptor(new CYBlockDescriptor);
628 memset(&descriptor->d_, 0, sizeof(descriptor->d_));
629
630 descriptor->internal_ = CYMakeFunctor_(context, function, signature, &BlockAdapter_);
631 literal->invoke = reinterpret_cast<void (*)(void *, ...)>(descriptor->internal_->value_);
632
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;
637
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);
641
642 return reinterpret_cast<NSBlock *>(literal);
643 }
644 #endif
645
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_;
650 }
651
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]);
655 }
656
657 NSNumber *CYCopyNSNumber(JSContextRef context, JSValueRef value) {
658 return [[NSNumber alloc] initWithDouble:CYCastDouble(context, value)];
659 }
660
661 #ifndef __APPLE__
662 @interface NSBoolNumber : NSNumber {
663 }
664 @end
665 #endif
666
667 id CYNSObject(CYPool *pool, JSContextRef context, JSValueRef value, bool cast) {
668 id object;
669 bool copy;
670
671 switch (JSType type = JSValueGetType(context, value)) {
672 case kJSTypeUndefined:
673 object = [WebUndefined undefined];
674 copy = false;
675 break;
676
677 case kJSTypeNull:
678 return NULL;
679 break;
680
681 case kJSTypeBoolean:
682 #ifdef __APPLE__
683 object = (id) (CYCastBool(context, value) ? kCFBooleanTrue : kCFBooleanFalse);
684 copy = false;
685 #else
686 object = [[NSBoolNumber alloc] initWithBool:CYCastBool(context, value)];
687 copy = true;
688 #endif
689 break;
690
691 case kJSTypeNumber:
692 object = CYCopyNSNumber(context, value);
693 copy = true;
694 break;
695
696 case kJSTypeString:
697 object = CYCopyNSString(context, value);
698 copy = true;
699 break;
700
701 case kJSTypeObject:
702 // XXX: this might could be more efficient
703 object = CYCastNSObject(pool, context, (JSObjectRef) value);
704 copy = false;
705 break;
706
707 default:
708 throw CYJSError(context, "JSValueGetType() == 0x%x", type);
709 break;
710 }
711
712 if (cast != copy)
713 return object;
714 else if (copy)
715 return CYPoolRelease(pool, object);
716 else
717 return [object retain];
718 }
719
720 NSObject *CYCastNSObject(CYPool *pool, JSContextRef context, JSValueRef value) {
721 return CYNSObject(pool, context, value, true);
722 }
723
724 NSObject *CYCopyNSObject(CYPool &pool, JSContextRef context, JSValueRef value) {
725 return CYNSObject(&pool, context, value, false);
726 }
727
728 /* Bridge: NSArray {{{ */
729 @implementation NSArray (Cycript)
730
731 - (id) cy$box {
732 return [[self mutableCopy] autorelease];
733 }
734
735 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
736 _oassert(objects.insert(self).second);
737
738 NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
739 [json appendString:@"@["];
740
741 bool comma(false);
742 #ifdef __clang__
743 for (id object in self) {
744 #else
745 for (size_t index(0), count([self count]); index != count; ++index) {
746 id object([self objectAtIndex:index]);
747 #endif
748 if (comma)
749 [json appendString:@","];
750 else
751 comma = true;
752 if (object != nil && [object cy$JSType] != kJSTypeUndefined)
753 [json appendString:CYCastNSCYON(object, true, objects)];
754 else {
755 [json appendString:@","];
756 comma = false;
757 }
758 }
759
760 [json appendString:@"]"];
761 return json;
762 }
763
764 - (bool) cy$hasProperty:(NSString *)name {
765 if ([name isEqualToString:@"length"])
766 return true;
767
768 size_t index(CYGetIndex(name));
769 if (index == _not(size_t) || index >= [self count])
770 return [super cy$hasProperty:name];
771 else
772 return true;
773 }
774
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];
779 else
780 return [self objectAtIndex:index];
781 }
782
783 - (JSValueRef) cy$getProperty:(NSString *)name inContext:(JSContextRef)context {
784 CYObjectiveTry_ {
785 if ([name isEqualToString:@"length"])
786 return CYCastJSValue(context, [self count]);
787 } CYObjectiveCatch
788
789 return [super cy$getProperty:name inContext:context];
790 }
791
792 - (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
793 [super cy$getPropertyNames:names inContext:context];
794
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) {
798 char name[32];
799 sprintf(name, "%zu", index);
800 JSPropertyNameAccumulatorAddName(names, CYJSString(name));
801 }
802 }
803 }
804
805 + (bool) cy$hasImplicitProperties {
806 return false;
807 }
808
809 @end
810 /* }}} */
811 /* Bridge: NSBlock {{{ */
812 #ifdef __APPLE__
813 @interface NSBlock : NSObject
814 - (void) invoke;
815 @end
816
817 static const char *CYBlockEncoding(NSBlock *self);
818 static bool CYBlockSignature(CYPool &pool, NSBlock *self, sig::Signature &signature);
819
820 @implementation NSBlock (Cycript)
821
822 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
823 CYLocalPool pool;
824
825 sig::Block type;
826 if (!CYBlockSignature(pool, self, type.signature))
827 return [super cy$toCYON:objective inSet:objects];
828 _oassert(objects.insert(self).second);
829
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));
835 modifier = NULL;
836
837 std::ostringstream str;
838 CYOptions options;
839 CYOutput out(*str.rdbuf(), options);
840 block->Output(out, CYNoFlags);
841
842 std::string value(str.str());
843 return CYCastNSString(NULL, CYUTF8String(value.c_str(), value.size()));
844 }
845
846 @end
847 #endif
848 /* }}} */
849 /* Bridge: NSBoolNumber {{{ */
850 #ifndef __APPLE__
851 @implementation NSBoolNumber (Cycript)
852
853 - (JSType) cy$JSType {
854 return kJSTypeBoolean;
855 }
856
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];
860 }
861
862 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
863 return CYCastJSValue(context, (bool) [self boolValue]);
864 } CYObjectiveCatch }
865
866 @end
867 #endif
868 /* }}} */
869 /* Bridge: NSDictionary {{{ */
870 @implementation NSDictionary (Cycript)
871
872 - (id) cy$box {
873 return [[self mutableCopy] autorelease];
874 }
875
876 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
877 _oassert(objects.insert(self).second);
878
879 NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
880 [json appendString:@"@{"];
881
882 bool comma(false);
883 #ifdef __clang__
884 for (NSObject *key in self) {
885 #else
886 NSEnumerator *keys([self keyEnumerator]);
887 while (NSObject *key = [keys nextObject]) {
888 #endif
889 if (comma)
890 [json appendString:@","];
891 else
892 comma = true;
893 [json appendString:CYCastNSCYON(key, true, objects)];
894 [json appendString:@":"];
895 NSObject *object([self objectForKey:key]);
896 [json appendString:CYCastNSCYON(object, true, objects)];
897 }
898
899 [json appendString:@"}"];
900 return json;
901 }
902
903 - (bool) cy$hasProperty:(NSString *)name {
904 return [self objectForKey:name] != nil;
905 }
906
907 - (NSObject *) cy$getProperty:(NSString *)name {
908 return [self objectForKey:name];
909 }
910
911 - (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
912 [super cy$getPropertyNames:names inContext:context];
913
914 #ifdef __clang__
915 for (NSObject *key in self) {
916 #else
917 NSEnumerator *keys([self keyEnumerator]);
918 while (NSObject *key = [keys nextObject]) {
919 #endif
920 JSPropertyNameAccumulatorAddName(names, CYJSString(context, key));
921 }
922 }
923
924 + (bool) cy$hasImplicitProperties {
925 return false;
926 }
927
928 @end
929 /* }}} */
930 /* Bridge: NSMutableArray {{{ */
931 @implementation NSMutableArray (Cycript)
932
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]);
939 if (size < 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];
945 }
946 return true;
947 }
948
949 size_t index(CYGetIndex(name));
950 if (index == _not(size_t))
951 return [super cy$setProperty:name to:value];
952
953 id object(value ?: [NSNull null]);
954
955 size_t count([self count]);
956 if (index < count)
957 [self replaceObjectAtIndex:index withObject:object];
958 else {
959 if (index != count) {
960 WebUndefined *undefined([WebUndefined undefined]);
961 for (size_t i(count); i != index; ++i)
962 [self addObject:undefined];
963 }
964
965 [self addObject:object];
966 }
967
968 return true;
969 }
970
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]];
976 return true;
977 }
978
979 @end
980 /* }}} */
981 /* Bridge: NSMutableDictionary {{{ */
982 @implementation NSMutableDictionary (Cycript)
983
984 - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value {
985 [self setObject:(value ?: [NSNull null]) forKey:name];
986 return true;
987 }
988
989 - (bool) cy$deleteProperty:(NSString *)name {
990 if ([self objectForKey:name] == nil)
991 return false;
992 else {
993 [self removeObjectForKey:name];
994 return true;
995 }
996 }
997
998 @end
999 /* }}} */
1000 /* Bridge: NSNumber {{{ */
1001 @implementation NSNumber (Cycript)
1002
1003 - (JSType) cy$JSType {
1004 #ifdef __APPLE__
1005 // XXX: this just seems stupid
1006 if ([self class] == NSCFBoolean_)
1007 return kJSTypeBoolean;
1008 #endif
1009 return kJSTypeNumber;
1010 }
1011
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];
1015 }
1016
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 }
1020
1021 @end
1022 /* }}} */
1023 /* Bridge: NSNull {{{ */
1024 @implementation NSNull (Cycript)
1025
1026 - (JSType) cy$JSType {
1027 return kJSTypeNull;
1028 }
1029
1030 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
1031 NSString *value(@"null");
1032 return objective ? value : [NSString stringWithFormat:@"@%@", value];
1033 }
1034
1035 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
1036 return CYJSNull(context);
1037 } CYObjectiveCatch }
1038
1039 @end
1040 /* }}} */
1041 /* Bridge: NSObject {{{ */
1042 @implementation NSObject (Cycript)
1043
1044 - (id) cy$box {
1045 return self;
1046 }
1047
1048 - (JSValueRef) cy$toJSON:(NSString *)key inContext:(JSContextRef)context {
1049 return [self cy$valueOfInContext:context];
1050 }
1051
1052 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
1053 return NULL;
1054 } CYObjectiveCatch }
1055
1056 - (JSType) cy$JSType {
1057 return kJSTypeObject;
1058 }
1059
1060 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
1061 return [@"#" stringByAppendingString:[[self description] cy$toCYON:true inSet:objects]];
1062 }
1063
1064 - (bool) cy$hasProperty:(NSString *)name {
1065 return false;
1066 }
1067
1068 - (NSObject *) cy$getProperty:(NSString *)name {
1069 return nil;
1070 }
1071
1072 - (JSValueRef) cy$getProperty:(NSString *)name inContext:(JSContextRef)context { CYObjectiveTry_ {
1073 if (NSObject *value = [self cy$getProperty:name])
1074 return CYCastJSValue(context, value);
1075 return NULL;
1076 } CYObjectiveCatch }
1077
1078 - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value {
1079 return false;
1080 }
1081
1082 - (bool) cy$deleteProperty:(NSString *)name {
1083 return false;
1084 }
1085
1086 - (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
1087 }
1088
1089 + (bool) cy$hasImplicitProperties {
1090 return true;
1091 }
1092
1093 @end
1094 /* }}} */
1095 /* Bridge: NSOrderedSet {{{ */
1096 #ifdef __APPLE__
1097 @implementation NSOrderedSet (Cycript)
1098
1099 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
1100 _oassert(objects.insert(self).second);
1101
1102 NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
1103 [json appendString:@"[NSOrderedSet orderedSetWithArray:"];
1104 [json appendString:CYCastNSCYON([self array], true, objects)];
1105 [json appendString:@"]]"];
1106 return json;
1107 }
1108
1109 @end
1110 #endif
1111 /* }}} */
1112 /* Bridge: NSProxy {{{ */
1113 @implementation NSProxy (Cycript)
1114
1115 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
1116 return [[self description] cy$toCYON:objective inSet:objects];
1117 }
1118
1119 @end
1120 /* }}} */
1121 /* Bridge: NSSet {{{ */
1122 @implementation NSSet (Cycript)
1123
1124 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
1125 _oassert(objects.insert(self).second);
1126
1127 NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
1128 [json appendString:@"[NSSet setWithArray:"];
1129 [json appendString:CYCastNSCYON([self allObjects], true, objects)];
1130 [json appendString:@"]]"];
1131 return json;
1132 }
1133
1134 @end
1135 /* }}} */
1136 /* Bridge: NSString {{{ */
1137 @implementation NSString (Cycript)
1138
1139 - (id) cy$box {
1140 return [[self copy] autorelease];
1141 }
1142
1143 - (JSType) cy$JSType {
1144 return kJSTypeString;
1145 }
1146
1147 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects {
1148 std::ostringstream str;
1149 if (!objective)
1150 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()));
1155 }
1156
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];
1161 else
1162 return true;
1163 }
1164
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];
1169 else
1170 return [self substringWithRange:NSMakeRange(index, 1)];
1171 }
1172
1173 - (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
1174 [super cy$getPropertyNames:names inContext:context];
1175
1176 for (size_t index(0), length([self length]); index != length; ++index) {
1177 char name[32];
1178 sprintf(name, "%zu", index);
1179 JSPropertyNameAccumulatorAddName(names, CYJSString(name));
1180 }
1181 }
1182
1183 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
1184 return CYCastJSValue(context, CYJSString(context, self));
1185 } CYObjectiveCatch }
1186
1187 @end
1188 /* }}} */
1189 /* Bridge: WebUndefined {{{ */
1190 @implementation WebUndefined (Cycript)
1191
1192 - (JSType) cy$JSType {
1193 return kJSTypeUndefined;
1194 }
1195
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];
1200 }
1201
1202 - (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_ {
1203 return CYJSUndefined(context);
1204 } CYObjectiveCatch }
1205
1206 @end
1207 /* }}} */
1208
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");
1214 return NULL;
1215 }
1216
1217 NSArray *CYCastNSArray(JSContextRef context, JSPropertyNameArrayRef names) {
1218 CYPool pool;
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))];
1223 return array;
1224 }
1225
1226 JSValueRef CYCastJSValue(JSContextRef context, NSObject *value) {
1227 if (value == nil)
1228 return CYJSNull(context);
1229 return CYMakeInstance(context, value);
1230 }
1231
1232 @implementation CYJSObject
1233
1234 - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context { CYObjectiveTry_ {
1235 if ((self = [super init]) != nil) {
1236 object_ = object;
1237 context_ = CYGetJSContext(context);
1238 JSGlobalContextRetain(context_);
1239 JSValueProtect(context_, object_);
1240 } return self;
1241 } CYObjectiveCatch }
1242
1243 - (void) dealloc { CYObjectiveTry {
1244 JSValueUnprotect(context_, object_);
1245 JSGlobalContextRelease(context_);
1246 [super dealloc];
1247 } CYObjectiveCatch }
1248
1249 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects { CYObjectiveTry {
1250 CYPool pool;
1251 const char *cyon(CYPoolCCYON(pool, context, object_, objects));
1252 if (cyon == NULL)
1253 return [super cy$toCYON:objective inSet:objects];
1254 else
1255 return [NSString stringWithUTF8String:cyon];
1256 } CYObjectiveCatch }
1257
1258 - (NSUInteger) count { CYObjectiveTry {
1259 JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context, object_));
1260 size_t size(JSPropertyNameArrayGetCount(names));
1261 JSPropertyNameArrayRelease(names);
1262 return size;
1263 } CYObjectiveCatch }
1264
1265 - (id) objectForKey:(id)key { CYObjectiveTry {
1266 JSValueRef value(CYGetProperty(context, object_, CYJSString(context, (NSObject *) key)));
1267 if (JSValueIsUndefined(context, value))
1268 return nil;
1269 return CYCastNSObject(NULL, context, value) ?: [NSNull null];
1270 } CYObjectiveCatch }
1271
1272 - (NSEnumerator *) keyEnumerator { CYObjectiveTry {
1273 JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context, object_));
1274 NSEnumerator *enumerator([CYCastNSArray(context, names) objectEnumerator]);
1275 JSPropertyNameArrayRelease(names);
1276 return enumerator;
1277 } CYObjectiveCatch }
1278
1279 - (void) setObject:(id)object forKey:(id)key { CYObjectiveTry {
1280 CYSetProperty(context, object_, CYJSString(context, (NSObject *) key), CYCastJSValue(context, (NSString *) object));
1281 } CYObjectiveCatch }
1282
1283 - (void) removeObjectForKey:(id)key { CYObjectiveTry {
1284 (void) _jsccall(JSObjectDeleteProperty, context, object_, CYJSString(context, (NSObject *) key));
1285 } CYObjectiveCatch }
1286
1287 @end
1288
1289 @implementation CYJSArray
1290
1291 - (NSString *) cy$toCYON:(bool)objective inSet:(std::set<void *> &)objects { CYObjectiveTry {
1292 CYPool pool;
1293 return [NSString stringWithUTF8String:CYPoolCCYON(pool, context, object_, objects)];
1294 } CYObjectiveCatch }
1295
1296 - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context { CYObjectiveTry_ {
1297 if ((self = [super init]) != nil) {
1298 object_ = object;
1299 context_ = CYGetJSContext(context);
1300 JSGlobalContextRetain(context_);
1301 JSValueProtect(context_, object_);
1302 } return self;
1303 } CYObjectiveCatch }
1304
1305 - (void) dealloc { CYObjectiveTry {
1306 JSValueUnprotect(context_, object_);
1307 JSGlobalContextRelease(context_);
1308 [super dealloc];
1309 } CYObjectiveCatch }
1310
1311 - (NSUInteger) count { CYObjectiveTry {
1312 return CYArrayLength(context, object_);
1313 } CYObjectiveCatch }
1314
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 }
1322
1323 - (void) addObject:(id)object { CYObjectiveTry {
1324 CYArrayPush(context, object_, CYCastJSValue(context, (NSObject *) object));
1325 } CYObjectiveCatch }
1326
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 }
1338
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 }
1343
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 }
1354
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 }
1361
1362 @end
1363
1364 // XXX: inherit from or replace with CYJSObject
1365 @interface CYInternal : NSObject {
1366 JSGlobalContextRef context_;
1367 JSObjectRef object_;
1368 }
1369
1370 @end
1371
1372 @implementation CYInternal
1373
1374 - (void) dealloc { CYObjectiveTry {
1375 JSValueUnprotect(context_, object_);
1376 JSGlobalContextRelease(context_);
1377 [super dealloc];
1378 } CYObjectiveCatch }
1379
1380 - (id) initInContext:(JSContextRef)context { CYObjectiveTry_ {
1381 if ((self = [super init]) != nil) {
1382 context_ = CYGetJSContext(context);
1383 JSGlobalContextRetain(context_);
1384 } return self;
1385 } CYObjectiveCatch }
1386
1387 - (bool) hasProperty:(JSStringRef)name inContext:(JSContextRef)context {
1388 if (object_ == NULL)
1389 return false;
1390
1391 return JSObjectHasProperty(context, object_, name);
1392 }
1393
1394 - (JSValueRef) getProperty:(JSStringRef)name inContext:(JSContextRef)context {
1395 if (object_ == NULL)
1396 return NULL;
1397
1398 return CYGetProperty(context, object_, name);
1399 }
1400
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_);
1406 }
1407 }
1408
1409 CYSetProperty(context, object_, name, value);
1410 }
1411
1412 + (CYInternal *) get:(id)object {
1413 #ifdef __APPLE__
1414 if (&objc_getAssociatedObject == NULL)
1415 return nil;
1416
1417 @synchronized (object) {
1418 if (CYInternal *internal = objc_getAssociatedObject(object, @selector(cy$internal)))
1419 return internal;
1420 }
1421 #endif
1422
1423 return nil;
1424 }
1425
1426 + (CYInternal *) set:(id)object inContext:(JSContextRef)context {
1427 #ifdef __APPLE__
1428 if (&objc_getAssociatedObject == NULL)
1429 return nil;
1430
1431 @synchronized (object) {
1432 if (CYInternal *internal = objc_getAssociatedObject(object, @selector(cy$internal)))
1433 return internal;
1434
1435 if (&objc_setAssociatedObject == NULL)
1436 return nil;
1437
1438 CYInternal *internal([[[CYInternal alloc] initInContext:context] autorelease]);
1439 objc_setAssociatedObject(object, @selector(cy$internal), internal, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1440 return internal;
1441 }
1442 #endif
1443
1444 return nil;
1445 }
1446
1447 @end
1448
1449 static JSValueRef CYCastJSValue(JSContextRef context, SEL sel) {
1450 if (sel == NULL)
1451 return CYJSNull(context);
1452 return CYPrivate<Selector_privateData>::Make(context, sel);
1453 }
1454
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_);
1459 } else {
1460 CYPool pool;
1461 return sel_registerName(CYPoolCString(pool, context, value));
1462 }
1463 }
1464
1465 void *CYObjectiveC_ExecuteStart(JSContextRef context) { CYSadTry {
1466 return (void *) [[NSAutoreleasePool alloc] init];
1467 } CYSadCatch(NULL) }
1468
1469 void CYObjectiveC_ExecuteEnd(JSContextRef context, void *handle) { CYSadTry {
1470 return [(NSAutoreleasePool *) handle release];
1471 } CYSadCatch() }
1472
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);
1475 } CYSadCatch() }
1476
1477 static NSBlock *CYCastNSBlock(CYPool &pool, JSContextRef context, JSValueRef value, const sig::Signature *signature) {
1478 #ifdef __APPLE__
1479 if (JSValueIsNull(context, value))
1480 return nil;
1481 JSObjectRef object(CYCastJSObject(context, value));
1482
1483 if (JSValueIsObjectOfClass(context, object, FunctionInstance_))
1484 return reinterpret_cast<Instance *>(JSObjectGetPrivate(object))->value_;
1485
1486 if (JSValueIsObjectOfClass(context, object, Instance::Class_)) {
1487 _assert(reinterpret_cast<Instance *>(JSObjectGetPrivate(object))->value_ == nil);
1488 return nil;
1489 }
1490
1491 _assert(JSObjectIsFunction(context, object));
1492
1493 _assert(signature != NULL);
1494 _assert(signature->count != 0);
1495
1496 sig::Signature modified;
1497 modified.count = signature->count + 1;
1498 modified.elements = new(pool) sig::Element[modified.count];
1499
1500 modified.elements[0] = signature->elements[0];
1501 memcpy(modified.elements + 2, signature->elements + 1, sizeof(sig::Element) * (signature->count - 1));
1502
1503 modified.elements[1].name = NULL;
1504 modified.elements[1].type = new(pool) sig::Object();
1505 modified.elements[1].offset = _not(size_t);
1506
1507 return CYMakeBlock(context, object, modified);
1508 #else
1509 _assert(false);
1510 #endif
1511 }
1512
1513 namespace sig {
1514
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);
1519 }
1520
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);
1524 }
1525
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);
1528 }
1529
1530 void Selector::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const {
1531 *reinterpret_cast<SEL *>(data) = CYCastSEL(context, value);
1532 }
1533
1534 JSValueRef Object::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
1535 NSObject *value(*reinterpret_cast<NSObject **>(data));
1536 if (value == NULL)
1537 return CYJSNull(context);
1538 JSObjectRef object(CYMakeInstance(context, value));
1539
1540 if (initialize) {
1541 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
1542
1543 if (internal->IsUninitialized()) {
1544 internal->flags_ &= ~Instance::Uninitialized;
1545 if (internal->value_ == nil)
1546 internal->value_ = value;
1547 else
1548 _assert(internal->value_ == value);
1549 }
1550
1551 [value release];
1552 }
1553
1554 return object;
1555 }
1556
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);
1561 }
1562
1563 JSValueRef Selector::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
1564 return CYCastJSValue(context, *reinterpret_cast<SEL *>(data));
1565 }
1566
1567 JSValueRef Block::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
1568 return CYCastJSValue(context, *reinterpret_cast<NSObject **>(data));
1569 }
1570
1571 }
1572
1573 static bool CYImplements(id object, Class _class, SEL selector, bool devoid = false) {
1574 if (objc_method *method = class_getInstanceMethod(_class, selector)) {
1575 if (!devoid)
1576 return true;
1577 char type[16];
1578 method_getReturnType(method, type, sizeof(type));
1579 if (type[0] != 'v')
1580 return true;
1581 }
1582
1583 // XXX: possibly use a more "awesome" check?
1584 return false;
1585 }
1586
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);
1590 }
1591
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);
1595 }
1596
1597 static IMP CYMakeMessage(JSContextRef context, JSValueRef value, const char *encoding) {
1598 JSObjectRef function(CYCastJSObject(context, value));
1599 CYPool pool;
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_);
1605 }
1606
1607 static bool Messages_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
1608 auto internal(CYPrivate<Messages>::Get(context, object));
1609 Class _class(internal->GetClass());
1610
1611 CYPool pool;
1612 const char *name(CYPoolCString(pool, context, property));
1613
1614 if (SEL sel = sel_getUid(name))
1615 if (class_getInstanceMethod(_class, sel) != NULL)
1616 return true;
1617
1618 return false;
1619 }
1620
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());
1624
1625 CYPool pool;
1626 const char *name(CYPoolCString(pool, context, property));
1627
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));
1631
1632 return NULL;
1633 } CYCatch(NULL) }
1634
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());
1638
1639 CYPool pool;
1640 const char *name(CYPoolCString(pool, context, property));
1641 SEL sel(sel_registerName(name));
1642
1643 const char *type;
1644 IMP imp;
1645
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;
1654
1655 objc_method *method(NULL);
1656 unsigned int size;
1657 objc_method **methods(class_copyMethodList(_class, &size));
1658 pool.atexit(free, methods);
1659
1660 for (size_t i(0); i != size; ++i)
1661 if (sel_isEqual(method_getName(methods[i]), sel)) {
1662 method = methods[i];
1663 break;
1664 }
1665
1666 if (method != NULL)
1667 method_setImplementation(method, imp);
1668 else
1669 class_addMethod(_class, sel, imp, type);
1670
1671 return true;
1672 } CYCatch(false) }
1673
1674 static JSValueRef Messages_complete_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1675 if (count == 2) {
1676 if (!CYCastBool(context, arguments[1]))
1677 return CYObjectMakeArray(context, 0, NULL);
1678 count = 1;
1679 }
1680
1681 _assert(count == 1);
1682 CYPool pool;
1683 CYUTF8String prefix(CYPoolUTF8String(pool, context, CYJSString(context, arguments[0])));
1684
1685 auto internal(CYPrivate<Messages>::Get(context, _this));
1686 Class _class(internal->GetClass());
1687
1688 unsigned int size;
1689 objc_method **data(class_copyMethodList(_class, &size));
1690 pool.atexit(free, data);
1691
1692 JSObjectRef array(NULL); {
1693 CYArrayBuilder<1024> values(context, array);
1694
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)));
1699 }
1700 } return array;
1701 } CYCatch(NULL) }
1702
1703 static bool CYHasImplicitProperties(JSContextRef context, Class _class) {
1704 if (!CYCastBool(context, CYGetCachedValue(context, CYJSString("cydget"))))
1705 return false;
1706 // XXX: this is an evil hack to deal with NSProxy; fix elsewhere
1707 if (!CYImplements(_class, object_getClass(_class), @selector(cy$hasImplicitProperties)))
1708 return true;
1709 return [_class cy$hasImplicitProperties];
1710 }
1711
1712 static objc_property_t CYFindProperty(CYPool &pool, Class _class, const char *name) {
1713 if (_class == Nil)
1714 return NULL;
1715 if (objc_property_t property = class_getProperty(_class, name))
1716 return property;
1717 return NULL;
1718
1719 /* // XXX: I don't think any of this is required
1720 unsigned int count;
1721 Protocol **protocols(class_copyProtocolList(_class, &count));
1722 // XXX: just implement a scope guard already :/
1723 pool.atexit(free, protocols);
1724
1725 for (unsigned int i(0); i != count; ++i)
1726 if (objc_property_t property = protocol_getProperty(protocols[i], name, true, true))
1727 return property;
1728
1729 return CYFindProperty(pool, class_getSuperclass(_class), name); */
1730 }
1731
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);
1735 } CYCatch(NULL) }
1736
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))
1741 return false;
1742 CYPool pool;
1743 if (SEL sel = sel_getUid(CYPoolCString(pool, context, property)))
1744 if (CYImplements(internal->value_, _class, sel, true))
1745 return true;
1746 return false;
1747 }
1748
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))
1753 return NULL;
1754 CYPool pool;
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);
1758 return NULL;
1759 } CYCatch(NULL) }
1760
1761 static bool Instance_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
1762 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
1763 id self(internal->value_);
1764
1765 if (JSStringIsEqualToUTF8CString(property, "$cyi"))
1766 return true;
1767
1768 CYPool pool;
1769 NSString *name(CYCastNSString(&pool, context, property));
1770
1771 if (CYInternal *internal = [CYInternal get:self])
1772 if ([internal hasProperty:property inContext:context])
1773 return true;
1774
1775 Class _class(object_getClass(self));
1776
1777 CYPoolTry {
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])
1781 return true;
1782 } CYPoolCatch(false)
1783
1784 const char *string(CYPoolCString(pool, context, name));
1785
1786 if (CYFindProperty(pool, _class, string) != NULL)
1787 return true;
1788
1789 if (CYHasImplicitProperties(context, _class))
1790 if (SEL sel = sel_getUid(string))
1791 if (CYImplements(self, _class, sel, true))
1792 return true;
1793
1794 return false;
1795 }
1796
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_);
1800
1801 if (JSStringIsEqualToUTF8CString(property, "$cyi"))
1802 return CYPrivate<Interior>::Make(context, self, context, object);
1803
1804 CYPool pool;
1805 NSString *name(CYCastNSString(&pool, context, property));
1806
1807 if (CYInternal *internal = [CYInternal get:self])
1808 if (JSValueRef value = [internal getProperty:property inContext:context])
1809 return value;
1810
1811 CYPoolTry {
1812 if (JSValueRef value = [self cy$getProperty:name inContext:context])
1813 return value;
1814 } CYPoolCatch(NULL)
1815
1816 const char *string(CYPoolCString(pool, context, name));
1817 Class _class(object_getClass(self));
1818
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);
1823 }
1824
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);
1829
1830 return NULL;
1831 } CYCatch(NULL) }
1832
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_);
1836
1837 CYPool pool;
1838
1839 NSString *name(CYCastNSString(&pool, context, property));
1840 NSObject *data(CYCastNSObject(&pool, context, value));
1841
1842 CYPoolTry {
1843 if ([self cy$setProperty:name to:data])
1844 return true;
1845 } CYPoolCatch(false)
1846
1847 const char *string(CYPoolCString(pool, context, name));
1848 Class _class(object_getClass(self));
1849
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);
1856 return true;
1857 }
1858 }
1859
1860 size_t length(strlen(string));
1861
1862 char set[length + 5];
1863
1864 set[0] = 's';
1865 set[1] = 'e';
1866 set[2] = 't';
1867
1868 if (string[0] != '\0') {
1869 set[3] = toupper(string[0]);
1870 memcpy(set + 4, string + 1, length - 1);
1871 }
1872
1873 set[length + 3] = ':';
1874 set[length + 4] = '\0';
1875
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);
1880 return true;
1881 }
1882
1883 if (CYInternal *internal = [CYInternal set:self inContext:context]) {
1884 [internal setProperty:property toValue:value inContext:context];
1885 return true;
1886 }
1887
1888 return false;
1889 } CYCatch(false) }
1890
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_);
1894
1895 CYPoolTry {
1896 NSString *name(CYCastNSString(NULL, context, property));
1897 return [self cy$deleteProperty:name];
1898 } CYPoolCatch(false)
1899 } CYCatch(false) return /*XXX*/ false; }
1900
1901 static void CYForEachProperty(CYPool &pool, Class _class, const Functor<void (objc_method *, const char *)> &code) {
1902 for (; _class != Nil; _class = class_getSuperclass(_class)) {
1903 unsigned int size;
1904 objc_method **data(class_copyMethodList(_class, &size));
1905 pool.atexit(free, data);
1906
1907 for (size_t i(0); i != size; ++i) {
1908 objc_method *method(data[i]);
1909
1910 const char *name(sel_getName(method_getName(method)));
1911 if (strchr(name, ':') != NULL)
1912 continue;
1913
1914 code(method, name);
1915 }
1916 }
1917 }
1918
1919 static void Instance_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
1920 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
1921 id self(internal->value_);
1922
1923 CYPool pool;
1924 Class _class(object_getClass(self));
1925
1926 for (Class current(_class); current != Nil; current = class_getSuperclass(current)) {
1927 unsigned int size;
1928 objc_property_t *data(class_copyPropertyList(current, &size));
1929 pool.atexit(free, data);
1930
1931 for (size_t i(0); i != size; ++i)
1932 JSPropertyNameAccumulatorAddName(names, CYJSString(property_getName(data[i])));
1933 }
1934
1935 if (CYHasImplicitProperties(context, _class))
1936 CYForEachProperty(pool, _class, fun([&](objc_method *method, const char *name) {
1937 JSPropertyNameAccumulatorAddName(names, CYJSString(name));
1938 }));
1939
1940 CYPoolTry {
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];
1944 } CYPoolCatch()
1945 }
1946
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);
1950
1951 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
1952 id self(internal->value_);
1953
1954 _assert(count == 1 || count == 2);
1955 CYPool pool;
1956 Class _class(object_getClass(self));
1957
1958 CYUTF8String prefix(CYPoolUTF8String(pool, context, CYJSString(context, arguments[0])));
1959
1960 JSObjectRef array(NULL); {
1961 CYArrayBuilder<1024> values(context, array);
1962
1963 CYForEachProperty(pool, _class, fun([&](objc_method *method, const char *name) {
1964 if (!CYStartsWith(name, prefix))
1965 return;
1966 const char *type(method_getTypeEncoding(method));
1967 if (type == NULL || *type == '\0' || *type == 'v')
1968 return;
1969 if (class_getProperty(_class, name) != NULL)
1970 return;
1971 values(CYCastJSValue(context, CYJSString(pool.strcat(name, "()", NULL))));
1972 }));
1973 } return array;
1974 } CYCatch(NULL) }
1975
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));
1979 return value;
1980 } CYCatch(NULL) }
1981
1982 static const char *CYBlockEncoding(NSBlock *self) {
1983 BlockLiteral *literal(reinterpret_cast<BlockLiteral *>(self));
1984 if ((literal->flags & BLOCK_HAS_SIGNATURE) == 0)
1985 return NULL;
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;
1992 }
1993
1994 static bool CYBlockSignature(CYPool &pool, NSBlock *self, sig::Signature &signature) {
1995 const char *encoding(CYBlockEncoding(self));
1996 if (encoding == NULL)
1997 return false;
1998
1999 sig::Parse(pool, &signature, encoding, &Structor_);
2000 _assert(signature.count >= 2);
2001
2002 _assert(dynamic_cast<sig::Object *>(signature.elements[1].type) != NULL);
2003 signature.elements[1] = signature.elements[0];
2004
2005 ++signature.elements;
2006 --signature.count;
2007
2008 return true;
2009 }
2010
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_);
2014
2015 if (const char *encoding = CYBlockEncoding(self)) {
2016 CYPool pool;
2017
2018 void *setup[1];
2019 setup[0] = &self;
2020
2021 sig::Signature signature;
2022 sig::Parse(pool, &signature, encoding, &Structor_);
2023
2024 ffi_cif cif;
2025 sig::sig_ffi_cif(pool, 0, signature, &cif);
2026
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);
2030 }
2031
2032 if (count != 0)
2033 CYThrow("NSBlock without signature field passed arguments");
2034
2035 CYPoolTry {
2036 [self invoke];
2037 } CYPoolCatch(NULL);
2038
2039 return NULL;
2040 } CYCatch(NULL) }
2041
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_);
2045
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];
2050 }
2051
2052 return false;
2053 } CYCatch(false) }
2054
2055 static JSValueRef Instance_box_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2056 if (count == 0)
2057 throw CYJSError(context, "incorrect number of arguments to Instance");
2058 CYPool pool;
2059 id value(CYCastNSObject(&pool, context, arguments[0]));
2060 if (value == nil)
2061 value = [NSNull null];
2062 return CYCastJSValue(context, [value cy$box]);
2063 } CYCatch(NULL) }
2064
2065 static bool Interior_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
2066 Interior *internal(reinterpret_cast<Interior *>(JSObjectGetPrivate(object)));
2067 CYPool pool;
2068
2069 id self(internal->value_);
2070 const char *name(CYPoolCString(pool, context, property));
2071
2072 if (object_getInstanceVariable(self, name, NULL) != NULL)
2073 return true;
2074
2075 return false;
2076 }
2077
2078 static void CYBitField(CYPool &pool, unsigned &length, unsigned &shift, id self, Ivar ivar, const char *encoding, unsigned offset) {
2079 length = CYCastDouble(encoding + 1);
2080 shift = 0;
2081
2082 unsigned int size;
2083 objc_ivar **ivars(class_copyIvarList(object_getClass(self), &size));
2084 pool.atexit(free, ivars);
2085
2086 for (size_t i(0); i != size; ++i)
2087 if (ivars[i] == ivar)
2088 break;
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);
2094 }
2095 }
2096
2097 static JSValueRef Interior_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2098 Interior *internal(reinterpret_cast<Interior *>(JSObjectGetPrivate(object)));
2099 CYPool pool;
2100
2101 id self(internal->value_);
2102 const char *name(CYPoolCString(pool, context, property));
2103
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);
2107
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);
2118 } else {
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));
2123 #endif
2124
2125 auto type(new(pool) Type_privateData(encoding));
2126 return type->type_->FromFFI(context, type->GetFFI(), data);
2127 }
2128 }
2129
2130 return NULL;
2131 } CYCatch(NULL) }
2132
2133 static bool Interior_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
2134 Interior *internal(reinterpret_cast<Interior *>(JSObjectGetPrivate(object)));
2135 CYPool pool;
2136
2137 id self(internal->value_);
2138 const char *name(CYPoolCString(pool, context, property));
2139
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);
2143
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;
2153 } else {
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);
2156 return true;
2157 }
2158 }
2159
2160 return false;
2161 } CYCatch(false) }
2162
2163 static void Interior_getPropertyNames_(CYPool &pool, Class _class, JSPropertyNameAccumulatorRef names) {
2164 if (Class super = class_getSuperclass(_class))
2165 Interior_getPropertyNames_(pool, super, names);
2166
2167 unsigned int size;
2168 objc_ivar **data(class_copyIvarList(_class, &size));
2169 pool.atexit(free, data);
2170
2171 for (size_t i(0); i != size; ++i)
2172 JSPropertyNameAccumulatorAddName(names, CYJSString(ivar_getName(data[i])));
2173 }
2174
2175 static void Interior_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
2176 Interior *internal(reinterpret_cast<Interior *>(JSObjectGetPrivate(object)));
2177 CYPool pool;
2178
2179 id self(internal->value_);
2180 Class _class(object_getClass(self));
2181
2182 Interior_getPropertyNames_(pool, _class, names);
2183 }
2184
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_;
2188 } CYCatch(NULL) }
2189
2190 static bool ObjectiveC_Classes_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
2191 CYPool pool;
2192 return objc_getClass(CYPoolCString(pool, context, property)) != Nil;
2193 }
2194
2195 static JSValueRef ObjectiveC_Classes_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2196 CYPool pool;
2197 NSString *name(CYCastNSString(&pool, context, property));
2198 if (Class _class = NSClassFromString(name))
2199 return CYMakeInstance(context, _class, Instance::Permanent);
2200 return NULL;
2201 } CYCatch(NULL) }
2202
2203 static Class *CYCopyClassList(size_t &size) {
2204 size = objc_getClassList(NULL, 0);
2205 Class *data(reinterpret_cast<Class *>(malloc(sizeof(Class) * size)));
2206
2207 for (;;) {
2208 size_t writ(objc_getClassList(data, size));
2209 if (writ <= size) {
2210 size = writ;
2211 return data;
2212 }
2213
2214 Class *copy(reinterpret_cast<Class *>(realloc(data, sizeof(Class) * writ)));
2215 if (copy == NULL) {
2216 free(data);
2217 return NULL;
2218 }
2219
2220 data = copy;
2221 size = writ;
2222 }
2223 }
2224
2225 static void ObjectiveC_Classes_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
2226 CYPool pool;
2227
2228 size_t size;
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])));
2233 }
2234 }
2235
2236 #ifdef __APPLE__
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)));
2239
2240 CYPool pool;
2241 const char *name(CYPoolCString(pool, context, property));
2242
2243 unsigned int size;
2244 const char **data(objc_copyClassNamesForImage(internal, &size));
2245 pool.atexit(free, data);
2246
2247 JSValueRef value;
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);
2252 else
2253 return NULL;
2254 }
2255
2256 return NULL;
2257 } CYCatch(NULL) }
2258
2259 static void ObjectiveC_Image_Classes_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
2260 const char *internal(reinterpret_cast<const char *>(JSObjectGetPrivate(object)));
2261 CYPool pool;
2262
2263 unsigned int size;
2264 const char **data(objc_copyClassNamesForImage(internal, &size));
2265 pool.atexit(free, data);
2266
2267 for (size_t i(0); i != size; ++i)
2268 JSPropertyNameAccumulatorAddName(names, CYJSString(data[i]));
2269 }
2270
2271 static JSValueRef ObjectiveC_Images_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2272 CYPool pool;
2273 CYUTF8String name(CYPoolUTF8String(pool, context, property));
2274
2275 unsigned int size;
2276 const char **data(objc_copyImageNames(&size));
2277 pool.atexit(free, data);
2278
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])));
2283 return value;
2284 }
2285
2286 return NULL;
2287 } CYCatch(NULL) }
2288
2289 static void ObjectiveC_Images_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
2290 CYPool pool;
2291
2292 unsigned int size;
2293 const char **data(objc_copyImageNames(&size));
2294 pool.atexit(free, data);
2295
2296 for (size_t i(0); i != size; ++i)
2297 JSPropertyNameAccumulatorAddName(names, CYJSString(data[i]));
2298 }
2299 #endif
2300
2301 static JSValueRef ObjectiveC_Protocols_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2302 CYPool pool;
2303 const char *name(CYPoolCString(pool, context, property));
2304 if (Protocol *protocol = objc_getProtocol(name))
2305 return CYMakeInstance(context, protocol, Instance::Permanent);
2306 return NULL;
2307 } CYCatch(NULL) }
2308
2309 static void ObjectiveC_Protocols_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
2310 CYPool pool;
2311
2312 unsigned int size;
2313 Protocol **data(objc_copyProtocolList(&size));
2314 pool.atexit(free, data);
2315
2316 for (size_t i(0); i != size; ++i)
2317 JSPropertyNameAccumulatorAddName(names, CYJSString(protocol_getName(data[i])));
2318 }
2319
2320 static JSValueRef ObjectiveC_Constants_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2321 CYPool pool;
2322 CYUTF8String name(CYPoolUTF8String(pool, context, property));
2323 if (name == "nil")
2324 return CYJSNull(context);
2325 return NULL;
2326 } CYCatch(NULL) }
2327
2328 static void ObjectiveC_Constants_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
2329 JSPropertyNameAccumulatorAddName(names, CYJSString("nil"));
2330 }
2331
2332 #ifdef __APPLE__
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;
2336 }
2337
2338 struct CYChoice {
2339 std::set<Class> query_;
2340 JSContextRef context_;
2341 JSObjectRef results_;
2342 };
2343
2344 struct CYObjectStruct {
2345 Class isa_;
2346 };
2347
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_);
2351
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);
2356
2357 if (size < sizeof(CYObjectStruct))
2358 continue;
2359
2360 uintptr_t *pointers(reinterpret_cast<uintptr_t *>(data));
2361 #if defined(__APPLE__) && defined(__LP64__)
2362 Class isa(reinterpret_cast<Class>(pointers[0] & 0x1fffffff8));
2363 #else
2364 Class isa(reinterpret_cast<Class>(pointers[0]));
2365 #endif
2366
2367 std::set<Class>::const_iterator result(choice->query_.find(isa));
2368 if (result == choice->query_.end())
2369 continue;
2370
2371 size_t needed(class_getInstanceSize(*result));
2372 // XXX: if (size < needed)
2373
2374 size_t boundary(496);
2375 #ifdef __LP64__
2376 boundary *= 2;
2377 #endif
2378 if (needed <= boundary && (needed + 15) / 16 * 16 != size || needed > boundary && (needed + 511) / 512 * 512 != size)
2379 continue;
2380 CYArrayPush(context, choice->results_, CYCastJSValue(context, reinterpret_cast<id>(data)));
2381 }
2382 }
2383
2384 static JSValueRef choose(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2385 if (count != 1)
2386 throw CYJSError(context, "choose() takes a class argument");
2387
2388 CYGarbageCollect(context);
2389
2390 CYPool pool;
2391 id _class(CYCastNSObject(&pool, context, arguments[0]));
2392
2393 vm_address_t *zones(NULL);
2394 unsigned size(0);
2395 kern_return_t error(malloc_get_all_zones(0, &CYReadMemory, &zones, &size));
2396 _assert(error == KERN_SUCCESS);
2397
2398 JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array")));
2399 JSObjectRef results(_jsccall(JSObjectCallAsConstructor, context, Array, 0, NULL));
2400
2401 CYChoice choice;
2402 choice.context_ = context;
2403 choice.results_ = results;
2404
2405 size_t number;
2406 Class *classes(CYCopyClassList(number));
2407 _assert(classes != NULL);
2408 pool.atexit(free, classes);
2409
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]);
2414 break;
2415 }
2416
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)
2420 continue;
2421
2422 zone->introspect->enumerator(mach_task_self(), &choice, MALLOC_PTR_IN_USE_RANGE_TYPE, zones[i], &CYReadMemory, &choose_);
2423 }
2424
2425 return results;
2426 } CYCatch(NULL) }
2427 #endif
2428
2429 #ifdef __APPLE__
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[] = {
2437 0, 0 };
2438 #elif defined(__arm64__)
2439 #define CY_NO_STRET
2440 #else
2441 #error missing objc-runtime-info
2442 #endif
2443
2444 #ifndef CY_NO_STRET
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
2449 );
2450 }
2451 #endif
2452 #else
2453 #define CY_NO_STRET
2454 #endif
2455
2456 JSValueRef CYSendMessage(CYPool &pool, JSContextRef context, id self, Class _class, SEL _cmd, size_t count, const JSValueRef arguments[], bool initialize) {
2457 const char *type;
2458
2459 if (_class == NULL)
2460 _class = object_getClass(self);
2461
2462 IMP imp;
2463
2464 if (objc_method *method = class_getInstanceMethod(_class, _cmd)) {
2465 imp = method_getImplementation(method);
2466 type = method_getTypeEncoding(method);
2467 } else {
2468 imp = NULL;
2469
2470 CYPoolTry {
2471 if (NSMethodSignature *method = [self methodSignatureForSelector:_cmd])
2472 type = CYPoolCString(pool, context, [method _typeString]);
2473 else
2474 type = NULL;
2475 } CYPoolCatch(NULL)
2476
2477 if (type == NULL)
2478 throw CYJSError(context, "unrecognized selector %s sent to object %p", sel_getName(_cmd), self);
2479 }
2480
2481 void *setup[2];
2482 setup[0] = &self;
2483 setup[1] = &_cmd;
2484
2485 sig::Signature signature;
2486 sig::Parse(pool, &signature, type, &Structor_);
2487
2488 ffi_cif cif;
2489 sig::sig_ffi_cif(pool, 0, signature, &cif);
2490
2491 if (imp == NULL) {
2492 #ifndef CY_NO_STRET
2493 if (stret(cif.rtype))
2494 imp = class_getMethodImplementation_stret(_class, _cmd);
2495 else
2496 #endif
2497 imp = class_getMethodImplementation(_class, _cmd);
2498 }
2499
2500 void (*function)() = reinterpret_cast<void (*)()>(imp);
2501 return CYCallFunction(pool, context, 2, setup, count, arguments, initialize, true, signature, &cif, function);
2502 }
2503
2504 static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[]) {
2505 if (count < 2)
2506 throw CYJSError(context, "too few arguments to objc_msgSend");
2507
2508 CYPool pool;
2509
2510 bool uninitialized;
2511
2512 id self;
2513 SEL _cmd;
2514 Class _class;
2515
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_;
2524 _class = nil;
2525 uninitialized = internal->IsUninitialized();
2526 if (uninitialized && [internal->value_ retainCount] != NSUInteger(-1))
2527 internal->value_ = nil;
2528 } else {
2529 self = CYCastNSObject(&pool, context, arguments[0]);
2530 _class = nil;
2531 uninitialized = false;
2532 }
2533
2534 if (self == nil)
2535 return CYJSNull(context);
2536
2537 _cmd = CYCastSEL(context, arguments[1]);
2538
2539 return CYSendMessage(pool, context, self, _class, _cmd, count - 2, arguments + 2, uninitialized);
2540 }
2541
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);
2544 } CYCatch(NULL) }
2545
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];
2548 setup[0] = _this;
2549 setup[1] = object;
2550 memcpy(setup + 2, arguments, sizeof(JSValueRef) * count);
2551 return $objc_msgSend(context, NULL, NULL, count + 2, setup);
2552 } CYCatch(NULL) }
2553
2554 static JSValueRef Message_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2555 CYPool pool;
2556 Message_privateData *internal(reinterpret_cast<Message_privateData *>(JSObjectGetPrivate(object)));
2557
2558 // XXX: handle Instance::Uninitialized?
2559 id self(CYCastNSObject(&pool, context, _this));
2560
2561 void *setup[2];
2562 setup[0] = &self;
2563 setup[1] = &internal->sel_;
2564
2565 return CYCallFunction(pool, context, 2, setup, count, arguments, false, true, internal->signature_, &internal->cif_, internal->value_);
2566 } CYCatch(NULL) }
2567
2568 static JSObjectRef Super_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2569 if (count != 2)
2570 throw CYJSError(context, "incorrect number of arguments to objc_super constructor");
2571 CYPool pool;
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);
2575 } CYCatch(NULL) }
2576
2577 static JSObjectRef Selector_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2578 if (count != 1)
2579 throw CYJSError(context, "incorrect number of arguments to Selector constructor");
2580 CYPool pool;
2581 const char *name(CYPoolCString(pool, context, arguments[0]));
2582 return CYPrivate<Selector_privateData>::Make(context, sel_registerName(name));
2583 } CYCatch(NULL) }
2584
2585 static JSObjectRef Instance_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2586 if (count != 1)
2587 throw CYJSError(context, "incorrect number of arguments to Instance constructor");
2588 return CYMakeInstance(context, CYCastPointer<id>(context, arguments[0]));
2589 } CYCatch(NULL) }
2590
2591 static JSValueRef Selector_getProperty_$cyt(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2592 return CYMakeType(context, sig::Selector());
2593 } CYCatch(NULL) }
2594
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))));
2599 } CYCatch(NULL) }
2600
2601 static JSValueRef FunctionInstance_getProperty_$cyt(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2602 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
2603 CYPool pool;
2604 sig::Block type;
2605 if (!CYBlockSignature(pool, internal->value_, type.signature))
2606 return CYJSNull(context);
2607 return CYMakeType(context, type);
2608 } CYCatch(NULL) }
2609
2610 static JSValueRef Constructor_getProperty_$cyt(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
2611 return CYMakeType(context, sig::Meta());
2612 } CYCatch(NULL) }
2613
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);
2617 } CYCatch(NULL) }
2618
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);
2622 } CYCatch(NULL) }
2623
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);
2628 } CYCatch(NULL) }
2629
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));
2632
2633 if (!CYJSValueIsNSObject(context, _this))
2634 return NULL;
2635
2636 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
2637 return CYCastJSValue(context, CYJSString(context, CYCastNSCYON(internal->value_, false, objects)));
2638 } CYCatch(NULL) }
2639
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_)));
2643 } CYCatch(NULL) }
2644
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))
2647 return NULL;
2648
2649 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
2650 id value(internal->value_);
2651
2652 CYPoolTry {
2653 NSString *key;
2654 if (count == 0)
2655 key = nil;
2656 else
2657 key = CYCastNSString(NULL, context, CYJSString(context, arguments[0]));
2658
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])
2662 return json;
2663 else
2664 return CYCastJSValue(context, CYJSString(context, [value description]));
2665 } CYPoolCatch(NULL)
2666 } CYCatch(NULL) return /*XXX*/ NULL; }
2667
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))
2670 return NULL;
2671
2672 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
2673 id value(internal->value_);
2674 _assert(value != nil);
2675
2676 if (![value respondsToSelector:@selector(cy$valueOfInContext:)])
2677 return _this;
2678
2679 if (JSValueRef result = [value cy$valueOfInContext:context])
2680 return result;
2681
2682 return _this;
2683 } CYCatch(NULL) return /*XXX*/ NULL; }
2684
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))
2687 return NULL;
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; }
2692
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; }
2698
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))
2701 return NULL;
2702
2703 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
2704 id value(internal->value_);
2705
2706 CYPoolTry {
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]));
2709 } CYPoolCatch(NULL)
2710 } CYCatch(NULL) return /*XXX*/ NULL; }
2711
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))
2714 return NULL;
2715
2716 Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
2717 id value(internal->value_);
2718
2719 if (!CYIsClass(value))
2720 CYThrow("non-Class object cannot be used as Type");
2721
2722 sig::Object type(class_getName(value));
2723 return CYMakeType(context, type);
2724 } CYCatch(NULL) return /*XXX*/ NULL; }
2725
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_));
2729 } CYCatch(NULL) }
2730
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);
2733 }
2734
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_));
2738
2739 CYPoolTry {
2740 NSString *string([NSString stringWithFormat:@"@selector(%s)", name]);
2741 return CYCastJSValue(context, CYJSString(context, string));
2742 } CYPoolCatch(NULL)
2743 } CYCatch(NULL) return /*XXX*/ NULL; }
2744
2745 static JSValueRef Selector_callAsFunction_type(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
2746 if (count != 1)
2747 throw CYJSError(context, "incorrect number of arguments to Selector.type");
2748
2749 CYPool pool;
2750 Selector_privateData *internal(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate(_this)));
2751 SEL sel(internal->value_);
2752
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));
2756
2757 sig::Function type(false);
2758 sig::Parse(pool, &type.signature, encoding, &Structor_);
2759 return CYMakeType(context, type);
2760 } CYCatch(NULL) }
2761
2762 static JSStaticValue Selector_staticValues[2] = {
2763 {"$cyt", &Selector_getProperty_$cyt, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2764 {NULL, NULL, NULL, 0}
2765 };
2766
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}
2772 };
2773
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}
2779 };
2780
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},
2788 {NULL, NULL, 0}
2789 };
2790
2791 static JSStaticFunction Messages_staticFunctions[2] = {
2792 {"cy$complete", &Messages_complete_callAsFunction, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2793 {NULL, NULL, 0}
2794 };
2795
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}
2802 };
2803
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},
2808 {NULL, NULL, 0}
2809 };
2810
2811 static JSStaticFunction Interior_staticFunctions[2] = {
2812 {"$cya", &Interior_callAsFunction_$cya, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
2813 {NULL, NULL, 0}
2814 };
2815
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},
2821 {NULL, NULL, 0}
2822 };
2823
2824 #ifdef __APPLE__
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 }
2828 #endif
2829
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");
2837
2838 #ifdef __APPLE__
2839 __NSMallocBlock__ = objc_getClass("__NSMallocBlock__");
2840
2841 // XXX: apparently, iOS now has both of these
2842 NSCFBoolean_ = objc_getClass("__NSCFBoolean");
2843 if (NSCFBoolean_ == nil)
2844 NSCFBoolean_ = objc_getClass("NSCFBoolean");
2845
2846 NSCFType_ = objc_getClass("NSCFType");
2847
2848 NSZombie_ = objc_getClass("_NSZombie_");
2849 #else
2850 NSBoolNumber_ = objc_getClass("NSBoolNumber");
2851 NSZombie_ = objc_getClass("NSZombie");
2852 #endif
2853
2854 JSClassDefinition definition;
2855
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);
2864
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);
2876
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);
2888
2889 definition.className = "ArrayInstance";
2890 ArrayInstance_ = JSClassCreate(&definition);
2891
2892 definition.className = "BooleanInstance";
2893 BooleanInstance_ = JSClassCreate(&definition);
2894
2895 definition.className = "NumberInstance";
2896 NumberInstance_ = JSClassCreate(&definition);
2897
2898 definition.className = "ObjectInstance";
2899 ObjectInstance_ = JSClassCreate(&definition);
2900
2901 definition.className = "StringInstance";
2902 StringInstance_ = JSClassCreate(&definition);
2903
2904 definition.className = "FunctionInstance";
2905 definition.staticValues = FunctionInstance_staticValues;
2906 definition.callAsFunction = &FunctionInstance_callAsFunction;
2907 FunctionInstance_ = JSClassCreate(&definition);
2908
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);
2918
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);
2926
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);
2933
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);
2941
2942 definition = kJSClassDefinitionEmpty;
2943 definition.className = "Super";
2944 definition.finalize = &CYFinalize;
2945 CYPrivate<cy::Super>::Class_ = JSClassCreate(&definition);
2946
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);
2953
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);
2959
2960 #ifdef __APPLE__
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);
2966
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);
2972 #endif
2973
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);
2979
2980 #ifdef __APPLE__
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
2983 #ifdef __LP64__
2984 "^{OpaqueJSValue=}32@0:8@16^{OpaqueJSContext=}24"
2985 #else
2986 "^{OpaqueJSValue=}16@0:4@8^{OpaqueJSContext=}12"
2987 #endif
2988 );
2989 #endif
2990 } CYPoolCatch() }
2991
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"))));
2998
2999 JSObjectRef ObjectiveC(JSObjectMake(context, NULL, NULL));
3000 CYSetProperty(context, cycript, CYJSString("ObjectiveC"), ObjectiveC);
3001
3002 JSObjectRef protocols(JSObjectMake(context, ObjectiveC_Protocols_, NULL));
3003 CYSetProperty(context, ObjectiveC, CYJSString("protocols"), protocols);
3004 CYArrayPush(context, alls, protocols);
3005
3006 JSObjectRef classes(JSObjectMake(context, ObjectiveC_Classes_, NULL));
3007 CYSetProperty(context, ObjectiveC, CYJSString("classes"), classes);
3008 CYArrayPush(context, alls, classes);
3009
3010 JSObjectRef constants(JSObjectMake(context, ObjectiveC_Constants_, NULL));
3011 CYSetProperty(context, ObjectiveC, CYJSString("constants"), constants);
3012 CYArrayPush(context, alls, constants);
3013
3014 #ifdef __APPLE__
3015 CYSetProperty(context, ObjectiveC, CYJSString("images"), JSObjectMake(context, ObjectiveC_Images_, NULL));
3016 #endif
3017
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));
3021
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);
3025
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);
3029
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);
3035
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);
3041
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);
3047
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);
3053
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);
3059
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);
3065
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);
3070
3071 JSObjectRef box(JSObjectMakeFunctionWithCallback(context, CYJSString("box"), &Instance_box_callAsFunction));
3072 CYSetProperty(context, Instance, CYJSString("box"), box, kJSPropertyAttributeDontEnum);
3073
3074 #ifdef __APPLE__
3075 CYSetProperty(context, all, CYJSString("choose"), &choose, kJSPropertyAttributeDontEnum);
3076 #endif
3077
3078 CYSetProperty(context, all, CYJSString("objc_msgSend"), &$objc_msgSend, kJSPropertyAttributeDontEnum);
3079
3080 CYSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Message, prototype_s)), Function_prototype);
3081 CYSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Selector, prototype_s)), Function_prototype);
3082
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);
3089
3090 CYSetProperty(context, cy, CYJSString("cydget"), CYCastJSValue(context, false));
3091 } CYPoolCatch() }
3092
3093 static void *CYObjectiveC_CastSymbol(const char *name) {
3094 if (false);
3095 #ifdef __GNU_LIBOBJC__
3096 else if (strcmp(name, "object_getClass") == 0)
3097 return reinterpret_cast<void *>(&object_getClass);
3098 #endif
3099 return NULL;
3100 }
3101
3102 static CYHook CYObjectiveCHook = {
3103 &CYObjectiveC_ExecuteStart,
3104 &CYObjectiveC_ExecuteEnd,
3105 &CYObjectiveC_CallFunction,
3106 &CYObjectiveC_Initialize,
3107 &CYObjectiveC_SetupContext,
3108 &CYObjectiveC_CastSymbol,
3109 };
3110
3111 CYRegisterHook CYObjectiveC(&CYObjectiveCHook);
3112
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 }
3119
3120 _extern void CydgetMemoryParse(const uint16_t **data, size_t *size) { try {
3121 CYPool pool;
3122
3123 CYUTF8String utf8(CYPoolUTF8String(pool, CYUTF16String(*data, *size)));
3124 utf8 = CYPoolCode(pool, utf8);
3125
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);
3130
3131 *data = copy;
3132 *size = utf16.size;
3133 } catch (const CYException &exception) {
3134 CYPool pool;
3135 @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"%s", exception.PoolCString(pool)] userInfo:nil];
3136 } }