JSStringRef toJSON_s;
JSStringRef toPointer_s;
JSStringRef toString_s;
+JSStringRef weak_s;
static JSStringRef Result_;
}
void *CYCastPointer_(JSContextRef context, JSValueRef value) {
- switch (JSValueGetType(context, value)) {
+ if (value == NULL)
+ return NULL;
+ else switch (JSValueGetType(context, value)) {
case kJSTypeNull:
return NULL;
case kJSTypeObject: {
return object;
}
+JSValueRef CYGetCachedValue(JSContextRef context, JSStringRef name) {
+ return CYGetProperty(context, CYCastJSObject(context, CYGetProperty(context, CYGetGlobalObject(context), cy_s)), name);
+}
+
JSObjectRef CYGetCachedObject(JSContextRef context, JSStringRef name) {
- return CYCastJSObject(context, CYGetProperty(context, CYCastJSObject(context, CYGetProperty(context, CYGetGlobalObject(context), cy_s)), name));
+ return CYCastJSObject(context, CYGetCachedValue(context, name));
}
static JSObjectRef CYMakeFunctor(JSContextRef context, JSValueRef value, const sig::Signature &signature) {
toJSON_s = JSStringCreateWithUTF8CString("toJSON");
toPointer_s = JSStringCreateWithUTF8CString("toPointer");
toString_s = JSStringCreateWithUTF8CString("toString");
+ weak_s = JSStringCreateWithUTF8CString("weak");
Result_ = JSStringCreateWithUTF8CString("_");
//CYSetProperty(context, System, CYJSString("global"), global);
CYSetProperty(context, System, CYJSString("print"), &System_print);
+ if (&JSWeakObjectMapCreate != NULL) {
+ JSWeakObjectMapRef weak(JSWeakObjectMapCreate(context, NULL, NULL));
+ CYSetProperty(context, cy, weak_s, CYCastJSValue(context, reinterpret_cast<uintptr_t>(weak)));
+ }
+
if (CYBridgeEntry *entry = CYBridgeHash("1dlerror", 8))
entry->cache_ = new cy::Functor(entry->value_, reinterpret_cast<void (*)()>(&dlerror));
}
};
-JSObjectRef CYMakeInstance(JSContextRef context, id object, bool permanent) {
- Instance::Flags flags;
+JSObjectRef CYMakeInstance(JSContextRef context, id object, Instance::Flags flags = Instance::None) {
+ _assert(object != nil);
- if (permanent)
- flags = Instance::Permanent;
- else {
- flags = Instance::None;
+ JSWeakObjectMapRef weak(CYCastPointer<JSWeakObjectMapRef>(context, CYGetCachedValue(context, weak_s)));
+
+ if (weak != NULL && &JSWeakObjectMapGet != NULL)
+ if (JSObjectRef instance = JSWeakObjectMapGet(context, weak, object))
+ return instance;
+
+ if ((flags & Instance::Permanent) == 0)
object = [object retain];
- }
- return Instance::Make(context, object, flags);
+ JSObjectRef instance(Instance::Make(context, object, flags));
+
+ if (weak != NULL && &JSWeakObjectMapSet != NULL)
+ JSWeakObjectMapSet(context, weak, object, instance);
+
+ return instance;
}
@interface NSMethodSignature (Cycript)
@end
NSString *CYCastNSCYON(id value, bool objective, std::set<void *> &objects) {
- NSString *string;
+ _assert(value != nil);
+
+ Class _class(object_getClass(value));
+
+ if (class_isMetaClass(_class)) {
+ const char *name(class_getName(value));
+ if (class_isMetaClass(value))
+ return [NSString stringWithFormat:@"object_getClass(%s)", name];
+ else
+ return [NSString stringWithUTF8String:name];
+ }
- if (value == nil)
- string = @"nil";
- else {
- Class _class(object_getClass(value));
- SEL sel(@selector(cy$toCYON:inSet:));
-
- if (class_isMetaClass(_class)) {
- const char *name(class_getName(value));
- if (class_isMetaClass(value))
- string = [NSString stringWithFormat:@"object_getClass(%s)", name];
- else
- string = [NSString stringWithUTF8String:name];
- } else if (objc_method *toCYON = class_getInstanceMethod(_class, sel))
- string = reinterpret_cast<NSString *(*)(id, SEL, bool, std::set<void *> &)>(method_getImplementation(toCYON))(value, sel, objective, objects);
- else if (objc_method *methodSignatureForSelector = class_getInstanceMethod(_class, @selector(methodSignatureForSelector:))) {
- if (reinterpret_cast<NSMethodSignature *(*)(id, SEL, SEL)>(method_getImplementation(methodSignatureForSelector))(value, @selector(methodSignatureForSelector:), sel) != nil)
- string = [value cy$toCYON:objective inSet:objects];
- else goto fail;
- } else fail: {
- if (false);
#ifdef __APPLE__
- else if (_class == NSZombie_)
- string = [NSString stringWithFormat:@"<_NSZombie_: %p>", value];
+ if (_class == NSZombie_)
+ return [NSString stringWithFormat:@"<_NSZombie_: %p>", value];
#endif
- else
- string = [NSString stringWithFormat:@"%@", value];
- }
- // XXX: frowny pants
- if (string == nil)
- string = @"undefined";
- }
+ SEL sel(@selector(cy$toCYON:inSet:));
- return string;
+ if (objc_method *toCYON = class_getInstanceMethod(_class, sel))
+ return reinterpret_cast<NSString *(*)(id, SEL, bool, std::set<void *> &)>(method_getImplementation(toCYON))(value, sel, objective, objects);
+ else if (objc_method *methodSignatureForSelector = class_getInstanceMethod(_class, @selector(methodSignatureForSelector:)))
+ if (reinterpret_cast<NSMethodSignature *(*)(id, SEL, SEL)>(method_getImplementation(methodSignatureForSelector))(value, @selector(methodSignatureForSelector:), sel) != nil)
+ return [value cy$toCYON:objective inSet:objects];
+
+ return [NSString stringWithFormat:@"%@", value];
}
NSString *CYCastNSCYON(id value, bool objective, std::set<void *> *objects) {
[json appendString:@","];
else
comma = true;
- if (object == nil || [object cy$JSType] != kJSTypeUndefined)
+ if (object != nil && [object cy$JSType] != kJSTypeUndefined)
[json appendString:CYCastNSCYON(object, true, objects)];
else {
[json appendString:@","];
if (value == nil)
return CYJSNull(context);
else
- return CYMakeInstance(context, value, false);
+ return CYMakeInstance(context, value);
} CYPoolCatch(NULL) return /*XXX*/ NULL; }
@implementation CYJSObject
// XXX: do something epic about blocks
case sig::block_P:
case sig::object_P:
- if (NSObject *object = *reinterpret_cast<NSObject **>(data)) {
- JSValueRef value(CYCastJSValue(context, object));
- if (initialize)
- [object release];
- return value;
+ if (NSObject *value = *reinterpret_cast<NSObject **>(data)) {
+ JSObjectRef object(CYMakeInstance(context, value));
+
+ if (initialize) {
+ Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
+
+ if ((internal->flags_ & Instance::Uninitialized) != 0) {
+ internal->flags_ = static_cast<Instance::Flags>(internal->flags_ & ~Instance::Uninitialized);
+ _assert(internal->value_ == nil);
+ internal->value_ = value;
+ }
+
+ [value release];
+ }
+
+ return object;
} else goto null;
case sig::typename_P:
- return CYMakeInstance(context, *reinterpret_cast<Class *>(data), true);
+ if (Class value = *reinterpret_cast<Class *>(data))
+ return CYMakeInstance(context, value, Instance::Permanent);
+ else goto null;
case sig::selector_P:
- if (SEL sel = *reinterpret_cast<SEL *>(data))
- return CYMakeSelector(context, sel);
+ if (SEL value = *reinterpret_cast<SEL *>(data))
+ return CYMakeSelector(context, value);
else goto null;
null:
static JSObjectRef Instance_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
- JSObjectRef value(Instance::Make(context, [internal->GetValue() alloc], Instance::Uninitialized));
+ JSObjectRef value(CYMakeInstance(context, [internal->GetValue() alloc], Instance::Uninitialized));
return value;
} CYCatch(NULL) }
CYPool pool;
NSString *name(CYCastNSString(&pool, context, property));
if (Class _class = NSClassFromString(name))
- return CYMakeInstance(context, _class, true);
+ return CYMakeInstance(context, _class, Instance::Permanent);
return NULL;
} CYCatch(NULL) }
for (size_t i(0); i != size; ++i)
if (strcmp(name, data[i]) == 0) {
if (Class _class = objc_getClass(name)) {
- value = CYMakeInstance(context, _class, true);
+ value = CYMakeInstance(context, _class, Instance::Permanent);
goto free;
} else
break;
CYPool pool;
const char *name(CYPoolCString(pool, context, property));
if (Protocol *protocol = objc_getProtocol(name))
- return CYMakeInstance(context, protocol, true);
+ return CYMakeInstance(context, protocol, Instance::Permanent);
return NULL;
} CYCatch(NULL) }
CYPool pool;
CYUTF8String name(CYPoolUTF8String(pool, context, property));
if (name == "nil")
- return Instance::Make(context, nil);
+ return CYJSNull(context);
return NULL;
} CYCatch(NULL) }
if (count > 1)
throw CYJSError(context, "incorrect number of arguments to Instance constructor");
id self(count == 0 ? nil : CYCastPointer<id>(context, arguments[0]));
- return CYMakeInstance(context, self, false);
+ return CYMakeInstance(context, self);
} CYCatch(NULL) }
static JSValueRef CYValue_getProperty_value(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
static JSValueRef Instance_getProperty_constructor(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
- return Instance::Make(context, (id) object_getClass(internal->GetValue()));
+ return CYMakeInstance(context, object_getClass(internal->GetValue()), Instance::Permanent);
} CYCatch(NULL) }
static JSValueRef Instance_getProperty_prototype(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
id value(internal->GetValue());
+ _assert(value != nil);
if (![value respondsToSelector:@selector(cy$valueOfInContext:)])
return _this;