X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/4e8c99fb09f51a009d1091d0a1a01ca73d7d4c85..2b52f27e85ea028573d6f280196e257b0204cb8a:/Library.mm diff --git a/Library.mm b/Library.mm index e5a2082..46fff44 100644 --- a/Library.mm +++ b/Library.mm @@ -1,4 +1,4 @@ -/* Cyrker - Remove Execution Server and Disassembler +/* Cycript - Remove Execution Server and Disassembler * Copyright (C) 2009 Jay Freeman (saurik) */ @@ -53,8 +53,6 @@ #include #include -#include - #include #include @@ -113,19 +111,16 @@ static JSClassRef Struct_; static JSObjectRef Array_; static JSObjectRef Function_; -static JSStringRef name_; -static JSStringRef message_; static JSStringRef length_; +static JSStringRef message_; +static JSStringRef name_; +static JSStringRef toCYON_; +static JSStringRef toJSON_; static Class NSCFBoolean_; static NSArray *Bridge_; -struct Client { - CFHTTPMessageRef message_; - CFSocketRef socket_; -}; - struct CYData { apr_pool_t *pool_; @@ -162,32 +157,6 @@ struct Pointer_privateData : } }; -struct Functor_privateData : - Pointer_privateData -{ - sig::Signature signature_; - ffi_cif cif_; - - Functor_privateData(const char *type, void (*value)()) : - Pointer_privateData(reinterpret_cast(value)) - { - sig::Parse(pool_, &signature_, type); - sig::sig_ffi_cif(pool_, &sig::ObjectiveC, &signature_, &cif_); - } -}; - -struct ffoData : - Functor_privateData -{ - JSContextRef context_; - JSObjectRef function_; - - ffoData(const char *type) : - Functor_privateData(type, NULL) - { - } -}; - struct Selector_privateData : Pointer_privateData { Selector_privateData(SEL value) : Pointer_privateData(value) @@ -199,24 +168,39 @@ struct Selector_privateData : Pointer_privateData { } }; -struct Instance_privateData : +struct Instance : Pointer_privateData { - bool transient_; + enum Flags { + None = 0, + Transient = (1 << 0), + Uninitialized = (1 << 1), + }; - Instance_privateData(id value, bool transient) : - Pointer_privateData(value) + Flags flags_; + + Instance(id value, Flags flags) : + Pointer_privateData(value), + flags_(flags) { } - virtual ~Instance_privateData() { - if (!transient_) + virtual ~Instance() { + if ((flags_ & Transient) == 0) [GetValue() release]; } + static JSObjectRef Make(JSContextRef context, id object, Flags flags) { + return JSObjectMake(context, Instance_, new Instance(object, flags)); + } + id GetValue() const { return reinterpret_cast(value_); } + + bool IsUninitialized() const { + return (flags_ & Uninitialized) != 0; + } }; namespace sig { @@ -284,36 +268,21 @@ void Copy(apr_pool_t *pool, ffi_type &lhs, ffi_type &rhs) { } +struct CStringMapLess : + std::binary_function +{ + _finline bool operator ()(const char *lhs, const char *rhs) const { + return strcmp(lhs, rhs) < 0; + } +}; + struct Type_privateData { sig::Type type_; ffi_type ffi_; - //size_t count_; Type_privateData(apr_pool_t *pool, sig::Type *type, ffi_type *ffi) { sig::Copy(pool, type_, *type); sig::Copy(pool, ffi_, *ffi); - - /*sig::Element element; - element.name = NULL; - element.type = type; - element.offset = 0; - - sig::Signature signature; - signature.elements = &element; - signature.count = 1; - - ffi_cif cif; - sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif); - ffi_ = *cif.rtype;*/ - - /*if (type_->type != FFI_TYPE_STRUCT) - count_ = 0; - else { - size_t count(0); - while (type_->elements[count] != NULL) - ++count; - count_ = count; - }*/ } }; @@ -327,14 +296,6 @@ struct Struct_privateData : } }; -struct CStringMapLess : - std::binary_function -{ - _finline bool operator ()(const char *lhs, const char *rhs) const { - return strcmp(lhs, rhs) < 0; - } -}; - typedef std::map TypeMap; static TypeMap Types_; @@ -359,11 +320,59 @@ JSObjectRef CYMakeStruct(JSContextRef context, void *data, sig::Type *type, ffi_ return JSObjectMake(context, Struct_, internal); } -JSObjectRef CYMakeInstance(JSContextRef context, id object, bool transient) { - if (!transient) +void Structor_(apr_pool_t *pool, const char *name, const char *types, sig::Type *type) { + if (name == NULL) + return; + + CYPoolTry { + if (NSMutableArray *entry = [[Bridge_ objectAtIndex:2] objectForKey:[NSString stringWithUTF8String:name]]) { + switch ([[entry objectAtIndex:0] intValue]) { + case 0: + static CYPool Pool_; + sig::Parse(Pool_, &type->data.signature, [[entry objectAtIndex:1] UTF8String], &Structor_); + break; + } + } + } CYPoolCatch() +} + +struct Functor_privateData : + Pointer_privateData +{ + sig::Signature signature_; + ffi_cif cif_; + + Functor_privateData(const char *type, void (*value)()) : + Pointer_privateData(reinterpret_cast(value)) + { + sig::Parse(pool_, &signature_, type, &Structor_); + sig::sig_ffi_cif(pool_, &sig::ObjectiveC, &signature_, &cif_); + } +}; + +struct ffoData : + Functor_privateData +{ + JSContextRef context_; + JSObjectRef function_; + + ffoData(const char *type) : + Functor_privateData(type, NULL) + { + } +}; + +JSValueRef CYMakeInstance(JSContextRef context, id object, bool transient) { + Instance::Flags flags; + + if (transient) + flags = Instance::Transient; + else { + flags = Instance::None; object = [object retain]; - Instance_privateData *data(new Instance_privateData(object, transient)); - return JSObjectMake(context, Instance_, data); + } + + return Instance::Make(context, object, flags); } const char *CYPoolCString(apr_pool_t *pool, NSString *value) { @@ -373,7 +382,7 @@ const char *CYPoolCString(apr_pool_t *pool, NSString *value) { size_t size([value maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1); char *string(new(pool) char[size]); if (![value getCString:string maxLength:size encoding:NSUTF8StringEncoding]) - @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"[NSString getCString:maxLength:encoding:] == NO" userInfo:nil]; + @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"[NSString getCString:maxLength:encoding:] == NO" userInfo:nil]; return string; } } @@ -402,17 +411,42 @@ JSValueRef CYJSUndefined(JSContextRef context) { return JSValueMakeUndefined(context); } +size_t CYCastIndex(const char *value) { + if (value[0] == '0') { + if (value[1] == '\0') + return 0; + } else { + char *end; + size_t index(strtoul(value, &end, 10)); + if (value + strlen(value) == end) + return index; + } + + return _not(size_t); +} + +size_t CYCastIndex(NSString *value) { + return CYCastIndex([value UTF8String]); +} + @interface NSMethodSignature (Cycript) - (NSString *) _typeString; @end @interface NSObject (Cycript) -- (bool) cy$isUndefined; -- (NSString *) cy$toJSON; -- (JSValueRef) cy$JSValueInContext:(JSContextRef)context transient:(bool)transient; + +- (JSType) cy$JSType; + +- (NSObject *) cy$toJSON:(NSString *)key; +- (NSString *) cy$toCYON; +- (NSString *) cy$toKey; + +- (JSValueRef) cy$JSValueInContext:(JSContextRef)context; + - (NSObject *) cy$getProperty:(NSString *)name; - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value; - (bool) cy$deleteProperty:(NSString *)name; + @end @interface NSString (Cycript) @@ -423,33 +457,127 @@ JSValueRef CYJSUndefined(JSContextRef context) { - (void *) cy$symbol; @end +struct PropertyAttributes { + CYPool pool_; + + const char *name; + + const char *variable; + + const char *getter_; + const char *setter_; + + bool readonly; + bool copy; + bool retain; + bool nonatomic; + bool dynamic; + bool weak; + bool garbage; + + PropertyAttributes(objc_property_t property) : + variable(NULL), + getter_(NULL), + setter_(NULL), + readonly(false), + copy(false), + retain(false), + nonatomic(false), + dynamic(false), + weak(false), + garbage(false) + { + name = property_getName(property); + const char *attributes(property_getAttributes(property)); + + for (char *state, *token(apr_strtok(apr_pstrdup(pool_, attributes), ",", &state)); token != NULL; token = apr_strtok(NULL, ",", &state)) { + switch (*token) { + case 'R': readonly = true; break; + case 'C': copy = true; break; + case '&': retain = true; break; + case 'N': nonatomic = true; break; + case 'G': getter_ = token + 1; break; + case 'S': setter_ = token + 1; break; + case 'V': variable = token + 1; break; + } + } + + /*if (variable == NULL) { + variable = property_getName(property); + size_t size(strlen(variable)); + char *name(new(pool_) char[size + 2]); + name[0] = '_'; + memcpy(name + 1, variable, size); + name[size + 1] = '\0'; + variable = name; + }*/ + } + + const char *Getter() { + if (getter_ == NULL) + getter_ = apr_pstrdup(pool_, name); + return getter_; + } + + const char *Setter() { + if (setter_ == NULL && !readonly) { + size_t length(strlen(name)); + + char *temp(new(pool_) char[length + 5]); + temp[0] = 's'; + temp[1] = 'e'; + temp[2] = 't'; + + if (length != 0) { + temp[3] = toupper(name[0]); + memcpy(temp + 4, name + 1, length - 1); + } + + temp[length + 3] = ':'; + temp[length + 4] = '\0'; + setter_ = temp; + } + + return setter_; + } + +}; + @implementation NSObject (Cycript) -- (bool) cy$isUndefined { - return false; +- (JSType) cy$JSType { + return kJSTypeObject; } -- (NSString *) cy$toJSON { +- (NSObject *) cy$toJSON:(NSString *)key { return [self description]; } -- (JSValueRef) cy$JSValueInContext:(JSContextRef)context transient:(bool)transient { - return CYMakeInstance(context, self, transient); +- (NSString *) cy$toCYON { + return [[self cy$toJSON:@""] cy$toCYON]; +} + +- (NSString *) cy$toKey { + return [self cy$toCYON]; +} + +- (JSValueRef) cy$JSValueInContext:(JSContextRef)context { + return CYMakeInstance(context, self, false); } - (NSObject *) cy$getProperty:(NSString *)name { - if (![name isEqualToString:@"prototype"]) - NSLog(@"get:%@", name); + /*if (![name isEqualToString:@"prototype"]) + NSLog(@"get:%@", name);*/ return nil; } - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value { - NSLog(@"set:%@", name); + //NSLog(@"set:%@", name); return false; } - (bool) cy$deleteProperty:(NSString *)name { - NSLog(@"delete:%@", name); + //NSLog(@"delete:%@", name); return false; } @@ -457,15 +585,19 @@ JSValueRef CYJSUndefined(JSContextRef context) { @implementation WebUndefined (Cycript) -- (bool) cy$isUndefined { - return true; +- (JSType) cy$JSType { + return kJSTypeUndefined; +} + +- (NSObject *) cy$toJSON:(NSString *)key { + return self; } -- (NSString *) cy$toJSON { +- (NSString *) cy$toCYON { return @"undefined"; } -- (JSValueRef) cy$JSValueInContext:(JSContextRef)context transient:(bool)transient { +- (JSValueRef) cy$JSValueInContext:(JSContextRef)context { return CYJSUndefined(context); } @@ -473,7 +605,15 @@ JSValueRef CYJSUndefined(JSContextRef context) { @implementation NSNull (Cycript) -- (NSString *) cy$toJSON { +- (JSType) cy$JSType { + return kJSTypeNull; +} + +- (NSObject *) cy$toJSON:(NSString *)key { + return self; +} + +- (NSString *) cy$toCYON { return @"null"; } @@ -481,7 +621,7 @@ JSValueRef CYJSUndefined(JSContextRef context) { @implementation NSArray (Cycript) -- (NSString *) cy$toJSON { +- (NSString *) cy$toCYON { NSMutableString *json([[[NSMutableString alloc] init] autorelease]); [json appendString:@"["]; @@ -491,8 +631,8 @@ JSValueRef CYJSUndefined(JSContextRef context) { [json appendString:@","]; else comma = true; - if (![object cy$isUndefined]) - [json appendString:[object cy$toJSON]]; + if ([object cy$JSType] != kJSTypeUndefined) + [json appendString:[object cy$toCYON]]; else { [json appendString:@","]; comma = false; @@ -504,8 +644,11 @@ JSValueRef CYJSUndefined(JSContextRef context) { } - (NSObject *) cy$getProperty:(NSString *)name { - int index([name intValue]); - if (index < 0 || index >= static_cast([self count])) + if ([name isEqualToString:@"length"]) + return [NSNumber numberWithUnsignedInteger:[self count]]; + + size_t index(CYCastIndex(name)); + if (index == _not(size_t) || index >= [self count]) return [super cy$getProperty:name]; else return [self objectAtIndex:index]; @@ -516,8 +659,8 @@ JSValueRef CYJSUndefined(JSContextRef context) { @implementation NSMutableArray (Cycript) - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value { - int index([name intValue]); - if (index < 0 || index >= static_cast([self count])) + size_t index(CYCastIndex(name)); + if (index == _not(size_t) || index >= [self count]) return [super cy$setProperty:name to:value]; else { [self replaceObjectAtIndex:index withObject:(value ?: [NSNull null])]; @@ -526,8 +669,8 @@ JSValueRef CYJSUndefined(JSContextRef context) { } - (bool) cy$deleteProperty:(NSString *)name { - int index([name intValue]); - if (index < 0 || index >= static_cast([self count])) + size_t index(CYCastIndex(name)); + if (index == _not(size_t) || index >= [self count]) return [super cy$deleteProperty:name]; else { [self removeObjectAtIndex:index]; @@ -539,9 +682,9 @@ JSValueRef CYJSUndefined(JSContextRef context) { @implementation NSDictionary (Cycript) -- (NSString *) cy$toJSON { +- (NSString *) cy$toCYON { NSMutableString *json([[[NSMutableString alloc] init] autorelease]); - [json appendString:@"({"]; + [json appendString:@"{"]; bool comma(false); for (id key in self) { @@ -549,13 +692,13 @@ JSValueRef CYJSUndefined(JSContextRef context) { [json appendString:@","]; else comma = true; - [json appendString:[key cy$toJSON]]; + [json appendString:[key cy$toKey]]; [json appendString:@":"]; NSObject *object([self objectForKey:key]); - [json appendString:[object cy$toJSON]]; + [json appendString:[object cy$toCYON]]; } - [json appendString:@"})"]; + [json appendString:@"}"]; return json; } @@ -585,12 +728,21 @@ JSValueRef CYJSUndefined(JSContextRef context) { @implementation NSNumber (Cycript) -- (NSString *) cy$toJSON { - return [self class] != NSCFBoolean_ ? [self stringValue] : [self boolValue] ? @"true" : @"false"; +- (JSType) cy$JSType { + // XXX: this just seems stupid + return [self class] == NSCFBoolean_ ? kJSTypeBoolean : kJSTypeNumber; +} + +- (NSObject *) cy$toJSON:(NSString *)key { + return self; +} + +- (NSString *) cy$toCYON { + return [self cy$JSType] != kJSTypeBoolean ? [self stringValue] : [self boolValue] ? @"true" : @"false"; } -- (JSValueRef) cy$JSValueInContext:(JSContextRef)context transient:(bool)transient { - return [self class] != NSCFBoolean_ ? CYCastJSValue(context, [self doubleValue]) : CYCastJSValue(context, [self boolValue]); +- (JSValueRef) cy$JSValueInContext:(JSContextRef)context { + return [self cy$JSType] != kJSTypeBoolean ? CYCastJSValue(context, [self doubleValue]) : CYCastJSValue(context, [self boolValue]); } - (void *) cy$symbol { @@ -601,7 +753,16 @@ JSValueRef CYJSUndefined(JSContextRef context) { @implementation NSString (Cycript) -- (NSString *) cy$toJSON { +- (JSType) cy$JSType { + return kJSTypeString; +} + +- (NSObject *) cy$toJSON:(NSString *)key { + return self; +} + +- (NSString *) cy$toCYON { + // XXX: this should use the better code from Output.cpp CFMutableStringRef json(CFStringCreateMutableCopy(kCFAllocatorDefault, 0, (CFStringRef) self)); CFStringFindAndReplace(json, CFSTR("\\"), CFSTR("\\\\"), CFRangeMake(0, CFStringGetLength(json)), 0); @@ -616,6 +777,30 @@ JSValueRef CYJSUndefined(JSContextRef context) { return [reinterpret_cast(json) autorelease]; } +- (NSString *) cy$toKey { + const char *value([self UTF8String]); + size_t size(strlen(value)); + + if (size == 0) + goto cyon; + + if (DigitRange_[value[0]]) { + if (CYCastIndex(self) == _not(size_t)) + goto cyon; + } else { + if (!WordStartRange_[value[0]]) + goto cyon; + for (size_t i(1); i != size; ++i) + if (!WordEndRange_[value[i]]) + goto cyon; + } + + return self; + + cyon: + return [self cy$toCYON]; +} + - (void *) cy$symbol { CYPool pool; return dlsym(RTLD_DEFAULT, CYPoolCString(pool, self)); @@ -630,6 +815,8 @@ JSValueRef CYJSUndefined(JSContextRef context) { - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context; +- (NSString *) cy$toJSON:(NSString *)key; + - (NSUInteger) count; - (id) objectForKey:(id)key; - (NSEnumerator *) keyEnumerator; @@ -650,8 +837,9 @@ JSValueRef CYJSUndefined(JSContextRef context) { @end -CYRange WordStartRange_(0x1000000000LLU,0x7fffffe87fffffeLLU); // A-Za-z_$ -CYRange WordEndRange_(0x3ff001000000000LLU,0x7fffffe87fffffeLLU); // A-Za-z_$0-9 +CYRange DigitRange_ (0x3ff000000000000LLU, 0x000000000000000LLU); // 0-9 +CYRange WordStartRange_(0x000001000000000LLU, 0x7fffffe87fffffeLLU); // A-Za-z_$ +CYRange WordEndRange_ (0x3ff001000000000LLU, 0x7fffffe87fffffeLLU); // A-Za-z_$0-9 JSGlobalContextRef CYGetJSContext() { return Context_; @@ -661,7 +849,6 @@ JSGlobalContextRef CYGetJSContext() { @try #define CYCatch \ @catch (id error) { \ - NSLog(@"e:%@", error); \ CYThrow(context, error, exception); \ return NULL; \ } @@ -675,7 +862,9 @@ apr_status_t CYPoolRelease_(void *data) { } id CYPoolRelease(apr_pool_t *pool, id object) { - if (pool == NULL) + if (object == nil) + return nil; + else if (pool == NULL) return [object autorelease]; else { apr_pool_cleanup_register(pool, object, &CYPoolRelease_, &apr_pool_cleanup_null); @@ -687,12 +876,7 @@ CFTypeRef CYPoolRelease(apr_pool_t *pool, CFTypeRef object) { return (CFTypeRef) CYPoolRelease(pool, (id) object); } -id CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSObjectRef object) { - if (JSValueIsObjectOfClass(context, object, Instance_)) { - Instance_privateData *data(reinterpret_cast(JSObjectGetPrivate(object))); - return data->GetValue(); - } - +id CYCastNSObject_(apr_pool_t *pool, JSContextRef context, JSObjectRef object) { JSValueRef exception(NULL); bool array(JSValueIsInstanceOfConstructor(context, object, Array_, &exception)); CYThrow(context, exception); @@ -700,6 +884,15 @@ id CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSObjectRef object) { return CYPoolRelease(pool, [value initWithJSObject:object inContext:context]); } +id CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSObjectRef object) { + if (!JSValueIsObjectOfClass(context, object, Instance_)) + return CYCastNSObject_(pool, context, object); + else { + Instance *data(reinterpret_cast(JSObjectGetPrivate(object))); + return data->GetValue(); + } +} + JSStringRef CYCopyJSString(id value) { return value == NULL ? NULL : JSStringCreateWithCFString(reinterpret_cast([value description])); } @@ -726,7 +919,8 @@ class CYJSString { JSStringRef string_; void Clear_() { - JSStringRelease(string_); + if (string_ != NULL) + JSStringRelease(string_); } public: @@ -902,8 +1096,8 @@ JSValueRef CYCastJSValue(JSContextRef context, const char *value) { return CYCastJSValue(context, CYJSString(value)); } -JSValueRef CYCastJSValue(JSContextRef context, id value, bool transient = true) { - return value == nil ? CYJSNull(context) : [value cy$JSValueInContext:context transient:transient]; +JSValueRef CYCastJSValue(JSContextRef context, id value) { + return value == nil ? CYJSNull(context) : [value cy$JSValueInContext:context]; } JSObjectRef CYCastJSObject(JSContextRef context, JSValueRef value) { @@ -939,6 +1133,18 @@ void CYThrow(JSContextRef context, id error, JSValueRef *exception) { *exception = CYCastJSValue(context, error); } +JSValueRef CYCallAsFunction(JSContextRef context, JSObjectRef function, JSObjectRef _this, size_t count, JSValueRef arguments[]) { + JSValueRef exception(NULL); + JSValueRef value(JSObjectCallAsFunction(context, function, _this, count, arguments, &exception)); + CYThrow(context, exception); + return value; +} + +bool CYIsCallable(JSContextRef context, JSValueRef value) { + // XXX: this isn't actually correct + return value != NULL && JSValueIsObject(context, value); +} + @implementation CYJSObject - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context { @@ -948,6 +1154,28 @@ void CYThrow(JSContextRef context, id error, JSValueRef *exception) { } return self; } +- (NSObject *) cy$toJSON:(NSString *)key { + JSValueRef toJSON(CYGetProperty(context_, object_, toJSON_)); + if (!CYIsCallable(context_, toJSON)) + return [super cy$toJSON:key]; + else { + JSValueRef arguments[1] = {CYCastJSValue(context_, key)}; + JSValueRef value(CYCallAsFunction(context_, (JSObjectRef) toJSON, object_, 1, arguments)); + // XXX: do I really want an NSNull here?! + return CYCastNSObject(NULL, context_, value) ?: [NSNull null]; + } +} + +- (NSString *) cy$toCYON { + JSValueRef toCYON(CYGetProperty(context_, object_, toCYON_)); + if (!CYIsCallable(context_, toCYON)) + return [super cy$toCYON]; + else { + JSValueRef value(CYCallAsFunction(context_, (JSObjectRef) toCYON, object_, 0, NULL)); + return CYCastNSString(NULL, CYJSString(context_, value)); + } +} + - (NSUInteger) count { JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context_, object_)); size_t size(JSPropertyNameArrayGetCount(names)); @@ -972,8 +1200,7 @@ void CYThrow(JSContextRef context, id error, JSValueRef *exception) { - (void) removeObjectForKey:(id)key { JSValueRef exception(NULL); - // XXX: this returns a bool... throw exception, or ignore? - JSObjectDeleteProperty(context_, object_, CYJSString(key), &exception); + (void) JSObjectDeleteProperty(context_, object_, CYJSString(key), &exception); CYThrow(context_, exception); } @@ -1001,129 +1228,87 @@ void CYThrow(JSContextRef context, id error, JSValueRef *exception) { @end -CFStringRef CYCopyJSONString(JSContextRef context, JSValueRef value, JSValueRef *exception) { +CFStringRef CYCopyCYONString(JSContextRef context, JSValueRef value, JSValueRef *exception) { CYTry { CYPoolTry { - id object(CYCastNSObject(NULL, context, value)); - return reinterpret_cast([(object == nil ? @"null" : [object cy$toJSON]) retain]); + id object(CYCastNSObject(NULL, context, value) ?: [NSNull null]); + return reinterpret_cast([[object cy$toCYON] retain]); } CYPoolCatch(NULL) } CYCatch } -const char *CYPoolJSONString(apr_pool_t *pool, JSContextRef context, JSValueRef value, JSValueRef *exception) { - if (NSString *json = (NSString *) CYCopyJSONString(context, value, exception)) { +const char *CYPoolCYONString(apr_pool_t *pool, JSContextRef context, JSValueRef value, JSValueRef *exception) { + if (NSString *json = (NSString *) CYCopyCYONString(context, value, exception)) { const char *string(CYPoolCString(pool, json)); [json release]; return string; } else return NULL; } -static void OnData(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *value, void *info) { - switch (type) { - case kCFSocketDataCallBack: - CFDataRef data(reinterpret_cast(value)); - Client *client(reinterpret_cast(info)); - - if (client->message_ == NULL) - client->message_ = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, TRUE); - - if (!CFHTTPMessageAppendBytes(client->message_, CFDataGetBytePtr(data), CFDataGetLength(data))) - CFLog(kCFLogLevelError, CFSTR("CFHTTPMessageAppendBytes()")); - else if (CFHTTPMessageIsHeaderComplete(client->message_)) { - CFURLRef url(CFHTTPMessageCopyRequestURL(client->message_)); - Boolean absolute; - CFStringRef path(CFURLCopyStrictPath(url, &absolute)); - CFRelease(client->message_); - - CFStringRef code(CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault, path, CFSTR(""))); - CFRelease(path); - - JSStringRef script(JSStringCreateWithCFString(code)); - CFRelease(code); - - JSValueRef result(JSEvaluateScript(CYGetJSContext(), script, NULL, NULL, 0, NULL)); - JSStringRelease(script); - - CFHTTPMessageRef response(CFHTTPMessageCreateResponse(kCFAllocatorDefault, 200, NULL, kCFHTTPVersion1_1)); - CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Type"), CFSTR("application/json; charset=utf-8")); - - CFStringRef json(CYCopyJSONString(CYGetJSContext(), result, NULL)); - CFDataRef body(CFStringCreateExternalRepresentation(kCFAllocatorDefault, json, kCFStringEncodingUTF8, NULL)); - CFRelease(json); - - CFStringRef length(CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), CFDataGetLength(body))); - CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Length"), length); - CFRelease(length); - - CFHTTPMessageSetBody(response, body); - CFRelease(body); - - CFDataRef serialized(CFHTTPMessageCopySerializedMessage(response)); - CFRelease(response); - - CFSocketSendData(socket, NULL, serialized, 0); - CFRelease(serialized); - - CFRelease(url); - } - break; - } -} - -static void OnAccept(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *value, void *info) { - switch (type) { - case kCFSocketAcceptCallBack: - Client *client(new Client()); - - client->message_ = NULL; - - CFSocketContext context; - context.version = 0; - context.info = client; - context.retain = NULL; - context.release = NULL; - context.copyDescription = NULL; - - client->socket_ = CFSocketCreateWithNative(kCFAllocatorDefault, *reinterpret_cast(value), kCFSocketDataCallBack, &OnData, &context); - - CFRunLoopAddSource(CFRunLoopGetCurrent(), CFSocketCreateRunLoopSource(kCFAllocatorDefault, client->socket_, 0), kCFRunLoopDefaultMode); - break; - } -} - static JSValueRef Instance_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { + CYPool pool; + CYTry { - CYPool pool; NSString *self(CYCastNSObject(pool, context, object)); NSString *name(CYCastNSString(pool, property)); - NSObject *data([self cy$getProperty:name]); - return data == nil ? NULL : CYCastJSValue(context, data); + + CYPoolTry { + if (NSObject *data = [self cy$getProperty:name]) + return CYCastJSValue(context, data); + } CYPoolCatch(NULL) + + if (objc_property_t property = class_getProperty(object_getClass(self), [name UTF8String])) { + PropertyAttributes attributes(property); + SEL sel(sel_registerName(attributes.Getter())); + return CYSendMessage(pool, context, self, sel, 0, NULL, false, exception); + } + + return NULL; } CYCatch } static bool Instance_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { + CYPool pool; + CYTry { - CYPool pool; NSString *self(CYCastNSObject(pool, context, object)); NSString *name(CYCastNSString(pool, property)); NSString *data(CYCastNSObject(pool, context, value)); - return [self cy$setProperty:name to:data]; + + CYPoolTry { + if ([self cy$setProperty:name to:data]) + return true; + } CYPoolCatch(NULL) + + if (objc_property_t property = class_getProperty(object_getClass(self), [name UTF8String])) { + PropertyAttributes attributes(property); + if (const char *setter = attributes.Setter()) { + SEL sel(sel_registerName(setter)); + JSValueRef arguments[1] = {value}; + CYSendMessage(pool, context, self, sel, 1, arguments, false, exception); + return true; + } + } + + return false; } CYCatch } static bool Instance_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry { - CYPool pool; - NSString *self(CYCastNSObject(pool, context, object)); - NSString *name(CYCastNSString(pool, property)); - return [self cy$deleteProperty:name]; + CYPoolTry { + NSString *self(CYCastNSObject(NULL, context, object)); + NSString *name(CYCastNSString(NULL, property)); + return [self cy$deleteProperty:name]; + } CYPoolCatch(NULL) } CYCatch } static JSObjectRef Instance_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { - Instance_privateData *data(reinterpret_cast(JSObjectGetPrivate(object))); - return CYMakeInstance(context, [data->GetValue() alloc], true); + Instance *data(reinterpret_cast(JSObjectGetPrivate(object))); + JSObjectRef value(Instance::Make(context, [data->GetValue() alloc], Instance::Uninitialized)); + return value; } CYCatch } @@ -1184,16 +1369,6 @@ const char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSValueRef val utf8; \ }) -SEL CYCastSEL(JSContextRef context, JSValueRef value) { - if (JSValueIsNull(context, value)) - return NULL; - else if (JSValueIsObjectOfClass(context, value, Selector_)) { - Selector_privateData *data(reinterpret_cast(JSObjectGetPrivate((JSObjectRef) value))); - return reinterpret_cast(data->value_); - } else - return sel_registerName(CYCastCString(context, value)); -} - void *CYCastPointer_(JSContextRef context, JSValueRef value) { switch (JSValueGetType(context, value)) { case kJSTypeNull: @@ -1218,6 +1393,14 @@ _finline Type_ CYCastPointer(JSContextRef context, JSValueRef value) { return reinterpret_cast(CYCastPointer_(context, value)); } +SEL CYCastSEL(JSContextRef context, JSValueRef value) { + if (JSValueIsObjectOfClass(context, value, Selector_)) { + Selector_privateData *data(reinterpret_cast(JSObjectGetPrivate((JSObjectRef) value))); + return reinterpret_cast(data->value_); + } else + return CYCastPointer(context, value); +} + void CYPoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, JSValueRef value) { switch (type->primitive) { case sig::boolean_P: @@ -1261,13 +1444,29 @@ void CYPoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, ffi_type case sig::struct_P: { uint8_t *base(reinterpret_cast(data)); - bool aggregate(JSValueIsObject(context, value)); + JSObjectRef aggregate(JSValueIsObject(context, value) ? (JSObjectRef) value : NULL); for (size_t index(0); index != type->data.signature.count; ++index) { - ffi_type *element(ffi->elements[index]); - JSValueRef rhs(aggregate ? CYGetProperty(context, (JSObjectRef) value, index) : value); - CYPoolFFI(pool, context, type->data.signature.elements[index].type, element, base, rhs); + sig::Element *element(&type->data.signature.elements[index]); + ffi_type *field(ffi->elements[index]); + + JSValueRef rhs; + if (aggregate == NULL) + rhs = value; + else { + rhs = CYGetProperty(context, aggregate, index); + if (JSValueIsUndefined(context, rhs)) { + if (element->name != NULL) + rhs = CYGetProperty(context, aggregate, CYJSString(element->name)); + else + goto undefined; + if (JSValueIsUndefined(context, rhs)) undefined: + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"unable to extract structure value" userInfo:nil]; + } + } + + CYPoolFFI(pool, context, element->type, field, base, rhs); // XXX: alignment? - base += element->size; + base += field->size; } } break; @@ -1280,7 +1479,7 @@ void CYPoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, ffi_type } } -JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, JSObjectRef owner = NULL) { +JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner = NULL) { JSValueRef value; switch (type->primitive) { @@ -1306,9 +1505,13 @@ JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void CYFromFFI_(float, float) CYFromFFI_(double, double) - case sig::object_P: - value = CYCastJSValue(context, *reinterpret_cast(data)); - break; + case sig::object_P: { + if (id object = *reinterpret_cast(data)) { + value = CYCastJSValue(context, object); + if (initialize) + [object release]; + } else goto null; + } break; case sig::typename_P: value = CYMakeInstance(context, *reinterpret_cast(data), true); @@ -1352,92 +1555,120 @@ JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void return value; } -void Index_(Struct_privateData *internal, double number, ssize_t &index, uint8_t *&base) { +bool Index_(apr_pool_t *pool, Struct_privateData *internal, JSStringRef property, ssize_t &index, uint8_t *&base) { Type_privateData *typical(internal->type_); - index = static_cast(number); - if (index != number) - @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"struct index non-integral" userInfo:nil]; - if (index < 0) - @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"struct index negative" userInfo:nil]; + size_t length; + const char *name(CYPoolCString(pool, property, &length)); + double number(CYCastDouble(name, length)); + + size_t count(typical->type_.data.signature.count); + + if (std::isnan(number)) { + if (property == NULL) + return false; + + sig::Element *elements(typical->type_.data.signature.elements); + for (size_t local(0); local != count; ++local) { + sig::Element *element(&elements[local]); + if (element->name != NULL && strcmp(name, element->name) == 0) { + index = local; + goto base; + } + } + + return false; + } else { + index = static_cast(number); + if (index != number || index < 0 || static_cast(index) >= count) + return false; + } + + base: base = reinterpret_cast(internal->value_); for (ssize_t local(0); local != index; ++local) - if (ffi_type *element = typical->ffi_.elements[local]) - base += element->size; - else - @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"struct index out-of-range" userInfo:nil]; + base += typical->ffi_.elements[local]->size; + + return true; } static JSValueRef Struct_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { - CYTry { - CYPool pool; - Struct_privateData *internal(reinterpret_cast(JSObjectGetPrivate(object))); - Type_privateData *typical(internal->type_); - - size_t length; - const char *name(CYPoolCString(pool, property, &length)); - double number(CYCastDouble(name, length)); - - if (std::isnan(number)) { - // XXX: implement! - return NULL; - } + CYPool pool; + Struct_privateData *internal(reinterpret_cast(JSObjectGetPrivate(object))); + Type_privateData *typical(internal->type_); - ssize_t index; - uint8_t *base; + ssize_t index; + uint8_t *base; - Index_(internal, number, index, base); + if (!Index_(pool, internal, property, index, base)) + return NULL; - return CYFromFFI(context, typical->type_.data.signature.elements[index].type, typical->ffi_.elements[index], base, object); + CYTry { + return CYFromFFI(context, typical->type_.data.signature.elements[index].type, typical->ffi_.elements[index], base, false, object); } CYCatch } static bool Struct_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { - CYTry { - CYPool pool; - Struct_privateData *internal(reinterpret_cast(JSObjectGetPrivate(object))); - Type_privateData *typical(internal->type_); - - size_t length; - const char *name(CYPoolCString(pool, property, &length)); - double number(CYCastDouble(name, length)); - - if (std::isnan(number)) { - // XXX: implement! - return false; - } + CYPool pool; + Struct_privateData *internal(reinterpret_cast(JSObjectGetPrivate(object))); + Type_privateData *typical(internal->type_); - ssize_t index; - uint8_t *base; + ssize_t index; + uint8_t *base; - Index_(internal, number, index, base); + if (!Index_(pool, internal, property, index, base)) + return false; + CYTry { CYPoolFFI(NULL, context, typical->type_.data.signature.elements[index].type, typical->ffi_.elements[index], base, value); return true; } CYCatch } -static JSValueRef CYCallFunction(JSContextRef context, size_t count, const JSValueRef *arguments, JSValueRef *exception, sig::Signature *signature, ffi_cif *cif, void (*function)()) { +static void Struct_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) { + Struct_privateData *internal(reinterpret_cast(JSObjectGetPrivate(object))); + Type_privateData *typical(internal->type_); + + size_t count(typical->type_.data.signature.count); + sig::Element *elements(typical->type_.data.signature.elements); + + char number[32]; + + for (size_t index(0); index != count; ++index) { + const char *name; + name = elements[index].name; + + if (name == NULL) { + sprintf(number, "%lu", index); + name = number; + } + + JSPropertyNameAccumulatorAddName(names, CYJSString(name)); + } +} + +JSValueRef CYCallFunction(apr_pool_t *pool, JSContextRef context, size_t setups, void *setup[], size_t count, const JSValueRef arguments[], bool initialize, JSValueRef *exception, sig::Signature *signature, ffi_cif *cif, void (*function)()) { CYTry { - if (count != signature->count - 1) + if (setups + count != signature->count - 1) @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to ffi function" userInfo:nil]; - CYPool pool; - void *values[count]; + size_t size(setups + count); + void *values[size]; + memcpy(values, setup, sizeof(void *) * setups); - for (unsigned index(0); index != count; ++index) { + for (size_t index(setups); index != size; ++index) { sig::Element *element(&signature->elements[index + 1]); ffi_type *ffi(cif->arg_types[index]); // XXX: alignment? values[index] = new(pool) uint8_t[ffi->size]; - CYPoolFFI(pool, context, element->type, ffi, values[index], arguments[index]); + CYPoolFFI(pool, context, element->type, ffi, values[index], arguments[index - setups]); } uint8_t value[cif->rtype->size]; ffi_call(cif, function, value, values); - return CYFromFFI(context, signature->elements[0].type, cif->rtype, value); + return CYFromFFI(context, signature->elements[0].type, cif->rtype, value, initialize); } CYCatch } @@ -1450,12 +1681,9 @@ void Closure_(ffi_cif *cif, void *result, void **arguments, void *arg) { JSValueRef values[count]; for (size_t index(0); index != count; ++index) - values[index] = CYFromFFI(context, data->signature_.elements[1 + index].type, data->cif_.arg_types[index], arguments[index]); - - JSValueRef exception(NULL); - JSValueRef value(JSObjectCallAsFunction(context, data->function_, NULL, count, values, &exception)); - CYThrow(context, exception); + values[index] = CYFromFFI(context, data->signature_.elements[1 + index].type, data->cif_.arg_types[index], arguments[index], false); + JSValueRef value(CYCallAsFunction(context, data->function_, NULL, count, values)); CYPoolFFI(NULL, context, data->signature_.elements[0].type, data->cif_.rtype, result, value); } @@ -1498,10 +1726,10 @@ static JSValueRef Runtime_getProperty(JSContextRef context, JSObjectRef object, case 2: // XXX: this is horrendously inefficient sig::Signature signature; - sig::Parse(pool, &signature, CYPoolCString(pool, [entry objectAtIndex:1])); + sig::Parse(pool, &signature, CYPoolCString(pool, [entry objectAtIndex:1]), &Structor_); ffi_cif cif; sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif); - return CYFromFFI(context, signature.elements[0].type, cif.rtype, [name cy$symbol]); + return CYFromFFI(context, signature.elements[0].type, cif.rtype, [name cy$symbol], false); } return NULL; } CYCatch @@ -1530,65 +1758,95 @@ static JSValueRef System_print(JSContextRef context, JSObjectRef object, JSObjec static JSValueRef CYApplicationMain(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { CYPool pool; - NSString *name(CYCastNSObject(pool, context, arguments[0])); - int argc(*_NSGetArgc()); - char **argv(*_NSGetArgv()); + + int argc(CYCastDouble(context, arguments[0])); + char **argv(CYCastPointer(context, arguments[1])); + NSString *principal(CYCastNSObject(pool, context, arguments[2])); + NSString *delegate(CYCastNSObject(pool, context, arguments[3])); + + argc = *_NSGetArgc() - 1; + argv = *_NSGetArgv() + 1; for (int i(0); i != argc; ++i) NSLog(@"argv[%i]=%s", i, argv[i]); + _pooled - return CYCastJSValue(context, UIApplicationMain(argc, argv, name, name)); + return CYCastJSValue(context, UIApplicationMain(argc, argv, principal, delegate)); } CYCatch } -static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { +JSValueRef CYSendMessage(apr_pool_t *pool, JSContextRef context, id self, SEL _cmd, size_t count, const JSValueRef arguments[], bool initialize, JSValueRef *exception) { const char *type; + Class _class(object_getClass(self)); + if (Method method = class_getInstanceMethod(_class, _cmd)) + type = method_getTypeEncoding(method); + else { + CYPoolTry { + NSMethodSignature *method([self methodSignatureForSelector:_cmd]); + if (method == nil) + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"unrecognized selector %s sent to object %p", sel_getName(_cmd), self] userInfo:nil]; + type = CYPoolCString(pool, [method _typeString]); + } CYPoolCatch(NULL) + } + + void *setup[2]; + setup[0] = &self; + setup[1] = &_cmd; + + sig::Signature signature; + sig::Parse(pool, &signature, type, &Structor_); + + ffi_cif cif; + sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif); + + void (*function)() = stret(cif.rtype) ? reinterpret_cast(&objc_msgSend_stret) : reinterpret_cast(&objc_msgSend); + return CYCallFunction(pool, context, 2, setup, count, arguments, initialize, exception, &signature, &cif, function); +} + +static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYPool pool; + bool uninitialized; + + id self; + SEL _cmd; + CYTry { if (count < 2) @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"too few arguments to objc_msgSend" userInfo:nil]; - id self(CYCastNSObject(pool, context, arguments[0])); + if (JSValueIsObjectOfClass(context, arguments[0], Instance_)) { + Instance *data(reinterpret_cast(JSObjectGetPrivate((JSObjectRef) arguments[0]))); + self = data->GetValue(); + uninitialized = data->IsUninitialized(); + if (uninitialized) + data->value_ = nil; + } else { + self = CYCastNSObject(pool, context, arguments[0]); + uninitialized = false; + } + if (self == nil) return CYJSNull(context); - SEL _cmd(CYCastSEL(context, arguments[1])); - - Class _class(object_getClass(self)); - if (Method method = class_getInstanceMethod(_class, _cmd)) - type = method_getTypeEncoding(method); - else { - CYPoolTry { - NSMethodSignature *method([self methodSignatureForSelector:_cmd]); - if (method == nil) - @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"unrecognized selector %s sent to object %p", sel_getName(_cmd), self] userInfo:nil]; - type = CYPoolCString(pool, [method _typeString]); - } CYPoolCatch(NULL) - } + _cmd = CYCastSEL(context, arguments[1]); } CYCatch - sig::Signature signature; - sig::Parse(pool, &signature, type); - - ffi_cif cif; - sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif); - - void (*function)() = stret(cif.rtype) ? reinterpret_cast(&objc_msgSend_stret) : reinterpret_cast(&objc_msgSend); - return CYCallFunction(context, count, arguments, exception, &signature, &cif, function); + return CYSendMessage(pool, context, self, _cmd, count - 2, arguments + 2, uninitialized, exception); } static JSValueRef Selector_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { JSValueRef setup[count + 2]; setup[0] = _this; setup[1] = object; - memmove(setup + 2, arguments, sizeof(JSValueRef) * count); + memcpy(setup + 2, arguments, sizeof(JSValueRef) * count); return $objc_msgSend(context, NULL, NULL, count + 2, setup, exception); } static JSValueRef Functor_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + CYPool pool; Functor_privateData *data(reinterpret_cast(JSObjectGetPrivate(object))); - return CYCallFunction(context, count, arguments, exception, &data->signature_, &data->cif_, reinterpret_cast(data->value_)); + return CYCallFunction(pool, context, 0, NULL, count, arguments, false, exception, &data->signature_, &data->cif_, reinterpret_cast(data->value_)); } JSObjectRef Selector_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { @@ -1634,9 +1892,41 @@ static JSValueRef Pointer_callAsFunction_valueOf(JSContextRef context, JSObjectR } CYCatch } +static JSValueRef Pointer_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + return Pointer_callAsFunction_valueOf(context, object, _this, count, arguments, exception); +} + +static JSValueRef Pointer_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + CYTry { + Pointer_privateData *data(reinterpret_cast(JSObjectGetPrivate(_this))); + char string[32]; + sprintf(string, "%p", data->value_); + return CYCastJSValue(context, string); + } CYCatch +} + +static JSValueRef Instance_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + CYTry { + Instance *data(reinterpret_cast(JSObjectGetPrivate(_this))); + CYPoolTry { + return CYCastJSValue(context, CYJSString([data->GetValue() cy$toCYON])); + } CYPoolCatch(NULL) + } CYCatch +} + +static JSValueRef Instance_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + CYTry { + Instance *data(reinterpret_cast(JSObjectGetPrivate(_this))); + CYPoolTry { + NSString *key(count == 0 ? nil : CYCastNSString(NULL, CYJSString(context, arguments[0]))); + return CYCastJSValue(context, CYJSString([data->GetValue() cy$toJSON:key])); + } CYPoolCatch(NULL) + } CYCatch +} + static JSValueRef Instance_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { - Instance_privateData *data(reinterpret_cast(JSObjectGetPrivate(_this))); + Instance *data(reinterpret_cast(JSObjectGetPrivate(_this))); CYPoolTry { return CYCastJSValue(context, CYJSString([data->GetValue() description])); } CYPoolCatch(NULL) @@ -1650,6 +1940,20 @@ static JSValueRef Selector_callAsFunction_toString(JSContextRef context, JSObjec } CYCatch } +static JSValueRef Selector_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + return Selector_callAsFunction_toString(context, object, _this, count, arguments, exception); +} + +static JSValueRef Selector_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + CYTry { + Selector_privateData *data(reinterpret_cast(JSObjectGetPrivate(_this))); + const char *name(sel_getName(data->GetValue())); + CYPoolTry { + return CYCastJSValue(context, CYJSString([NSString stringWithFormat:@"@selector(%s)", name])); + } CYPoolCatch(NULL) + } CYCatch +} + static JSValueRef Selector_callAsFunction_type(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { if (count != 2) @@ -1673,7 +1977,9 @@ static JSStaticValue Pointer_staticValues[2] = { {NULL, NULL, NULL, 0} }; -static JSStaticFunction Pointer_staticFunctions[2] = { +static JSStaticFunction Pointer_staticFunctions[4] = { + {"toCYON", &Pointer_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, + {"toJSON", &Pointer_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {"valueOf", &Pointer_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {NULL, NULL, 0} }; @@ -1683,12 +1989,16 @@ static JSStaticFunction Pointer_staticFunctions[2] = { {NULL, NULL, NULL, 0} };*/ -static JSStaticFunction Instance_staticFunctions[2] = { +static JSStaticFunction Instance_staticFunctions[4] = { + {"toCYON", &Instance_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, + {"toJSON", &Instance_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {"toString", &Instance_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {NULL, NULL, 0} }; -static JSStaticFunction Selector_staticFunctions[3] = { +static JSStaticFunction Selector_staticFunctions[5] = { + {"toCYON", &Selector_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, + {"toJSON", &Selector_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {"toString", &Selector_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {"type", &Selector_callAsFunction_type, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {NULL, NULL, 0} @@ -1726,6 +2036,10 @@ void CYSetArgs(int argc, const char *argv[]) { CYSetProperty(context, System_, CYJSString("args"), array); } +JSObjectRef CYGetGlobalObject(JSContextRef context) { + return JSContextGetGlobalObject(context); +} + MSInitialize { _pooled apr_initialize(); @@ -1733,25 +2047,6 @@ MSInitialize { _pooled NSCFBoolean_ = objc_getClass("NSCFBoolean"); - pid_t pid(getpid()); - - struct sockaddr_in address; - address.sin_len = sizeof(address); - address.sin_family = AF_INET; - address.sin_addr.s_addr = INADDR_ANY; - address.sin_port = htons(10000 + pid); - - CFDataRef data(CFDataCreate(kCFAllocatorDefault, reinterpret_cast(&address), sizeof(address))); - - CFSocketSignature signature; - signature.protocolFamily = AF_INET; - signature.socketType = SOCK_STREAM; - signature.protocol = IPPROTO_TCP; - signature.address = data; - - CFSocketRef socket(CFSocketCreateWithSocketSignature(kCFAllocatorDefault, &signature, kCFSocketAcceptCallBack, &OnAccept, NULL)); - CFRunLoopAddSource(CFRunLoopGetCurrent(), CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0), kCFRunLoopDefaultMode); - JSClassDefinition definition; definition = kJSClassDefinitionEmpty; @@ -1773,6 +2068,7 @@ MSInitialize { _pooled definition.className = "Struct"; definition.getProperty = &Struct_getProperty; definition.setProperty = &Struct_setProperty; + definition.getPropertyNames = &Struct_getPropertyNames; definition.finalize = &CYData::Finalize; Struct_ = JSClassCreate(&definition); @@ -1808,10 +2104,10 @@ MSInitialize { _pooled JSGlobalContextRef context(JSGlobalContextCreate(Global)); Context_ = context; - JSObjectRef global(JSContextGetGlobalObject(context)); + JSObjectRef global(CYGetGlobalObject(context)); JSObjectSetPrototype(context, global, JSObjectMake(context, Runtime_, NULL)); - CYSetProperty(context, global, CYJSString("obc"), JSObjectMake(context, Runtime_, NULL)); + CYSetProperty(context, global, CYJSString("ObjectiveC"), JSObjectMake(context, Runtime_, NULL)); CYSetProperty(context, global, CYJSString("Selector"), JSObjectMakeConstructor(context, Selector_, &Selector_new)); CYSetProperty(context, global, CYJSString("Functor"), JSObjectMakeConstructor(context, Functor_, &Functor_new)); @@ -1822,13 +2118,15 @@ MSInitialize { _pooled System_ = JSObjectMake(context, NULL, NULL); CYSetProperty(context, global, CYJSString("system"), System_); CYSetProperty(context, System_, CYJSString("args"), CYJSNull(context)); - CYSetProperty(context, System_, CYJSString("global"), global); + //CYSetProperty(context, System_, CYJSString("global"), global); CYSetProperty(context, System_, CYJSString("print"), JSObjectMakeFunctionWithCallback(context, CYJSString("print"), &System_print)); - name_ = JSStringCreateWithUTF8CString("name"); - message_ = JSStringCreateWithUTF8CString("message"); length_ = JSStringCreateWithUTF8CString("length"); + message_ = JSStringCreateWithUTF8CString("message"); + name_ = JSStringCreateWithUTF8CString("name"); + toCYON_ = JSStringCreateWithUTF8CString("toCYON"); + toJSON_ = JSStringCreateWithUTF8CString("toJSON"); Array_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Array"))); Function_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Function")));