X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/4e39dc0b33914636c16dbe0940a0876ada8a40fc..b53b30c1f3aefb8e3847195b429d7e143590fbfa:/Library.mm diff --git a/Library.mm b/Library.mm index 66c7523..fa99de7 100644 --- a/Library.mm +++ b/Library.mm @@ -1,4 +1,4 @@ -/* Cycript - Remove Execution Server and Disassembler +/* Cycript - Remote Execution Server and Disassembler * Copyright (C) 2009 Jay Freeman (saurik) */ @@ -37,8 +37,6 @@ */ /* }}} */ -#define _GNU_SOURCE - #include #include "cycript.hpp" @@ -48,10 +46,14 @@ #include "Pooling.hpp" #include "Struct.hpp" +#ifdef __APPLE__ #include #include - +#include #include +#endif + +#include #include @@ -66,7 +68,7 @@ #include "Parser.hpp" #include "Cycript.tab.hh" -#include +#include #undef _assert #undef _trace @@ -77,7 +79,7 @@ } while (false) #define _trace() do { \ - CFLog(kCFLogLevelNotice, CFSTR("_trace():%u"), __LINE__); \ + fprintf(stderr, "_trace():%u\n", __LINE__); \ } while (false) #define CYPoolTry { \ @@ -98,6 +100,14 @@ void CYThrow(JSContextRef context, JSValueRef value); +const char *CYPoolCCYON(apr_pool_t *pool, JSContextRef context, JSValueRef value, JSValueRef *exception); +JSStringRef CYCopyJSString(const char *value); + +void CYSetProperty(JSContextRef context, JSObjectRef object, JSStringRef name, JSValueRef value); + +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)()); +JSValueRef CYSendMessage(apr_pool_t *pool, JSContextRef context, id self, SEL _cmd, size_t count, const JSValueRef arguments[], bool initialize, JSValueRef *exception); + /* JavaScript Properties {{{ */ JSValueRef CYGetProperty(JSContextRef context, JSObjectRef object, size_t index) { JSValueRef exception(NULL); @@ -126,11 +136,6 @@ void CYSetProperty(JSContextRef context, JSObjectRef object, JSStringRef name, J } /* }}} */ /* JavaScript Strings {{{ */ -JSStringRef CYCopyJSString(id value) { - // XXX: this definition scares me; is anyone using this?! - return value == NULL ? NULL : JSStringCreateWithCFString(reinterpret_cast([value description])); -} - JSStringRef CYCopyJSString(const char *value) { return value == NULL ? NULL : JSStringCreateWithUTF8CString(value); } @@ -194,7 +199,38 @@ class CYJSString { return string_; } }; +/* }}} */ +/* Objective-C Strings {{{ */ +const char *CYPoolCString(apr_pool_t *pool, NSString *value) { + if (pool == NULL) + return [value UTF8String]; + else { + size_t size([value maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1); + char *string(new(pool) char[size]); + if (![value getCString:string maxLength:size encoding:NSUTF8StringEncoding]) + @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"[NSString getCString:maxLength:encoding:] == NO" userInfo:nil]; + return string; + } +} + +JSStringRef CYCopyJSString_(NSString *value) { +#ifdef __APPLE__ + return JSStringCreateWithCFString(reinterpret_cast(value)); +#else + CYPool pool; + return CYCopyJSString(CYPoolCString(pool, value)); +#endif +} + +JSStringRef CYCopyJSString(id value) { + if (value == nil) + return NULL; + // XXX: this definition scares me; is anyone using this?! + NSString *string([value description]); + return CYCopyJSString_(string); +} +#ifdef __APPLE__ CFStringRef CYCopyCFString(JSStringRef value) { return JSStringCopyCFString(kCFAllocatorDefault, value); } @@ -202,7 +238,7 @@ CFStringRef CYCopyCFString(JSStringRef value) { CFStringRef CYCopyCFString(JSContextRef context, JSValueRef value) { return CYCopyCFString(CYJSString(context, value)); } - +#endif /* }}} */ static JSGlobalContextRef Context_; @@ -219,7 +255,6 @@ static JSClassRef Pointer_; static JSClassRef Runtime_; static JSClassRef Selector_; static JSClassRef Struct_; -static JSClassRef Type_; static JSClassRef ObjectiveC_Classes_; static JSClassRef ObjectiveC_Image_Classes_; @@ -247,9 +282,12 @@ static JSObjectRef Array_pop_; static JSObjectRef Array_push_; static JSObjectRef Array_splice_; -static Class NSArray_; +#ifdef __APPLE__ static Class NSCFBoolean_; static Class NSCFType_; +#endif + +static Class NSArray_; static Class NSDictionary_; static Class NSMessageBuilder_; static Class NSZombie_; @@ -271,8 +309,8 @@ struct CYValue : CYValue() { } - CYValue(void *value) : - value_(value) + CYValue(const void *value) : + value_(const_cast(value)) { } @@ -307,7 +345,7 @@ JSValueRef CYGetClassPrototype(JSContextRef context, id self) { return Instance_prototype_; // XXX: I need to think through multi-context - typedef std::map CacheMap; + typedef std::map CacheMap; static CacheMap cache_; JSValueRef &value(cache_[self]); @@ -352,6 +390,7 @@ struct Instance : virtual ~Instance() { if ((flags_ & Transient) == 0) // XXX: does this handle background threads correctly? + // XXX: this simply does not work on the console because I'm stupid [GetValue() performSelector:@selector(release) withObject:nil afterDelay:0]; } @@ -469,9 +508,14 @@ void Copy(apr_pool_t *pool, Type &lhs, Type &rhs) { if (sig::IsAggregate(rhs.primitive)) Copy(pool, lhs.data.signature, rhs.data.signature); else { - if (rhs.data.data.type != NULL) { - lhs.data.data.type = new(pool) Type; - Copy(pool, *lhs.data.data.type, *rhs.data.data.type); + sig::Type *&lht(lhs.data.data.type); + sig::Type *&rht(rhs.data.data.type); + + if (rht == NULL) + lht = NULL; + else { + lht = new(pool) Type; + Copy(pool, *lht, *rht); } lhs.data.data.size = rhs.data.data.size; @@ -537,6 +581,8 @@ struct Type_privateData : static Type_privateData *Object; static Type_privateData *Selector; + static JSClassRef Class_; + ffi_type *ffi_; sig::Type *type_; @@ -591,6 +637,7 @@ struct Type_privateData : } }; +JSClassRef Type_privateData::Class_; Type_privateData *Type_privateData::Object; Type_privateData *Type_privateData::Selector; @@ -709,18 +756,6 @@ JSObjectRef CYMakeInstance(JSContextRef context, id object, bool transient) { return Instance::Make(context, object, flags); } -const char *CYPoolCString(apr_pool_t *pool, NSString *value) { - if (pool == NULL) - return [value UTF8String]; - else { - size_t size([value maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1); - char *string(new(pool) char[size]); - if (![value getCString:string maxLength:size encoding:NSUTF8StringEncoding]) - @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"[NSString getCString:maxLength:encoding:] == NO" userInfo:nil]; - return string; - } -} - JSValueRef CYCastJSValue(JSContextRef context, bool value) { return JSValueMakeBoolean(context, value); } @@ -756,10 +791,17 @@ size_t CYGetIndex(const char *value) { return _not(size_t); } +// XXX: fix this +static const char *CYPoolCString(apr_pool_t *pool, JSStringRef value); + size_t CYGetIndex(apr_pool_t *pool, NSString *value) { return CYGetIndex(CYPoolCString(pool, value)); } +size_t CYGetIndex(apr_pool_t *pool, JSStringRef value) { + return CYGetIndex(CYPoolCString(pool, value)); +} + bool CYGetOffset(const char *value, ssize_t &index) { if (value[0] != '0') { char *end; @@ -808,6 +850,7 @@ NSString *CYPoolNSCYON(apr_pool_t *pool, id value); - (void *) cy$symbol; @end +#ifdef __APPLE__ struct PropertyAttributes { CYPool pool_; @@ -893,10 +936,33 @@ struct PropertyAttributes { } }; +#endif -NSString *NSCFType$cy$toJSON(id self, SEL sel, NSString *key) { +#ifdef __APPLE__ +NSObject *NSCFType$cy$toJSON(id self, SEL sel, NSString *key) { return [(NSString *) CFCopyDescription((CFTypeRef) self) autorelease]; } +#endif + +#ifndef __APPLE__ +@interface CYWebUndefined : NSObject { +} + ++ (CYWebUndefined *) undefined; + +@end + +@implementation CYWebUndefined + ++ (CYWebUndefined *) undefined { + static CYWebUndefined *instance_([[CYWebUndefined alloc] init]); + return instance_; +} + +@end + +#define WebUndefined CYWebUndefined +#endif /* Bridge: NSArray {{{ */ @implementation NSArray (Cycript) @@ -906,7 +972,13 @@ NSString *NSCFType$cy$toJSON(id self, SEL sel, NSString *key) { [json appendString:@"["]; bool comma(false); +#ifdef __APPLE__ for (id object in self) { +#else + id object; + for (size_t index(0), count([self count]); index != count; ++index) { + object = [self objectAtIndex:index]; +#endif if (comma) [json appendString:@","]; else @@ -935,8 +1007,14 @@ NSString *NSCFType$cy$toJSON(id self, SEL sel, NSString *key) { } - (NSObject *) cy$getProperty:(NSString *)name { - if ([name isEqualToString:@"length"]) - return [NSNumber numberWithUnsignedInteger:[self count]]; + if ([name isEqualToString:@"length"]) { + NSUInteger count([self count]); +#ifdef __APPLE__ + return [NSNumber numberWithUnsignedInteger:count]; +#else + return [NSNumber numberWithUnsignedInt:count]; +#endif + } size_t index(CYGetIndex(NULL, name)); if (index == _not(size_t) || index >= [self count]) @@ -955,7 +1033,12 @@ NSString *NSCFType$cy$toJSON(id self, SEL sel, NSString *key) { [json appendString:@"{"]; bool comma(false); +#ifdef __APPLE__ for (id key in self) { +#else + NSEnumerator *keys([self keyEnumerator]); + while (id key = [keys nextObject]) { +#endif if (comma) [json appendString:@","]; else @@ -986,7 +1069,12 @@ NSString *NSCFType$cy$toJSON(id self, SEL sel, NSString *key) { - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value { if ([name isEqualToString:@"length"]) { // XXX: is this not intelligent? - NSUInteger size([(NSNumber *)value unsignedIntegerValue]); + NSNumber *number(reinterpret_cast(value)); +#ifdef __APPLE__ + NSUInteger size([number unsignedIntegerValue]); +#else + NSUInteger size([number unsignedIntValue]); +#endif NSUInteger count([self count]); if (size < count) [self removeObjectsInRange:NSMakeRange(size, count - size)]; @@ -1053,8 +1141,12 @@ NSString *NSCFType$cy$toJSON(id self, SEL sel, NSString *key) { @implementation NSNumber (Cycript) - (JSType) cy$JSType { +#ifdef __APPLE__ // XXX: this just seems stupid - return [self class] == NSCFBoolean_ ? kJSTypeBoolean : kJSTypeNumber; + if ([self class] == NSCFBoolean_) + return kJSTypeBoolean; +#endif + return kJSTypeNumber; } - (NSObject *) cy$toJSON:(NSString *)key { @@ -1155,18 +1247,19 @@ NSString *NSCFType$cy$toJSON(id self, SEL sel, NSString *key) { - (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); - CFStringFindAndReplace(json, CFSTR("\""), CFSTR("\\\""), CFRangeMake(0, CFStringGetLength(json)), 0); - CFStringFindAndReplace(json, CFSTR("\t"), CFSTR("\\t"), CFRangeMake(0, CFStringGetLength(json)), 0); - CFStringFindAndReplace(json, CFSTR("\r"), CFSTR("\\r"), CFRangeMake(0, CFStringGetLength(json)), 0); - CFStringFindAndReplace(json, CFSTR("\n"), CFSTR("\\n"), CFRangeMake(0, CFStringGetLength(json)), 0); + NSMutableString *json([self mutableCopy]); + + [json replaceOccurrencesOfString:@"\\" withString:@"\\\\" options:NSLiteralSearch range:NSMakeRange(0, [json length])]; + [json replaceOccurrencesOfString:@"\"" withString:@"\\\"" options:NSLiteralSearch range:NSMakeRange(0, [json length])]; + [json replaceOccurrencesOfString:@"\t" withString:@"\\t" options:NSLiteralSearch range:NSMakeRange(0, [json length])]; + [json replaceOccurrencesOfString:@"\r" withString:@"\\r" options:NSLiteralSearch range:NSMakeRange(0, [json length])]; + [json replaceOccurrencesOfString:@"\n" withString:@"\\n" options:NSLiteralSearch range:NSMakeRange(0, [json length])]; - CFStringInsert(json, 0, CFSTR("\"")); - CFStringAppend(json, CFSTR("\"")); + [json appendString:@"\""]; + [json insertString:@"\"" atIndex:0]; - return [reinterpret_cast(json) autorelease]; + return json; } - (NSString *) cy$toKey { @@ -1223,6 +1316,7 @@ NSString *NSCFType$cy$toJSON(id self, SEL sel, NSString *key) { @end /* }}} */ +/* Bridge: CYJSObject {{{ */ @interface CYJSObject : NSMutableDictionary { JSObjectRef object_; JSContextRef context_; @@ -1230,7 +1324,7 @@ NSString *NSCFType$cy$toJSON(id self, SEL sel, NSString *key) { - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context; -- (NSString *) cy$toJSON:(NSString *)key; +- (NSObject *) cy$toJSON:(NSString *)key; - (NSUInteger) count; - (id) objectForKey:(id)key; @@ -1239,7 +1333,8 @@ NSString *NSCFType$cy$toJSON(id self, SEL sel, NSString *key) { - (void) removeObjectForKey:(id)key; @end - +/* }}} */ +/* Bridge: CYJSArray {{{ */ @interface CYJSArray : NSMutableArray { JSObjectRef object_; JSContextRef context_; @@ -1257,10 +1352,7 @@ NSString *NSCFType$cy$toJSON(id self, SEL sel, NSString *key) { - (void) replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject; @end - -CYRange DigitRange_ (0x3ff000000000000LLU, 0x000000000000000LLU); // 0-9 -CYRange WordStartRange_(0x000001000000000LLU, 0x7fffffe87fffffeLLU); // A-Za-z_$ -CYRange WordEndRange_ (0x3ff001000000000LLU, 0x7fffffe87fffffeLLU); // A-Za-z_$0-9 +/* }}} */ #define CYTry \ @try @@ -1276,7 +1368,7 @@ apr_status_t CYPoolRelease_(void *data) { return APR_SUCCESS; } -id CYPoolRelease(apr_pool_t *pool, id object) { +id CYPoolRelease_(apr_pool_t *pool, id object) { if (object == nil) return nil; else if (pool == NULL) @@ -1287,8 +1379,9 @@ id CYPoolRelease(apr_pool_t *pool, id object) { } } -CFTypeRef CYPoolRelease(apr_pool_t *pool, CFTypeRef object) { - return (CFTypeRef) CYPoolRelease(pool, (id) object); +template +Type_ CYPoolRelease(apr_pool_t *pool, Type_ object) { + return (Type_) CYPoolRelease_(pool, (id) object); } id CYCastNSObject_(apr_pool_t *pool, JSContextRef context, JSObjectRef object) { @@ -1327,6 +1420,7 @@ double CYCastDouble(JSContextRef context, JSValueRef value) { return number; } +#ifdef __APPLE__ CFNumberRef CYCopyCFNumber(JSContextRef context, JSValueRef value) { double number(CYCastDouble(context, value)); return CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &number); @@ -1336,18 +1430,30 @@ CFStringRef CYCopyCFString(const char *value) { return CFStringCreateWithCString(kCFAllocatorDefault, value, kCFStringEncodingUTF8); } -NSString *CYCastNSString(apr_pool_t *pool, const char *value) { - return (NSString *) CYPoolRelease(pool, CYCopyCFString(value)); +template +NSString *CYCopyNSString(Type_ value) { + return (NSString *) CYCopyCFString(value); +} +#else +NSString *CYCopyNSString(const char *value { + return [NSString stringWithUTF8String:value]; } -NSString *CYCastNSString(apr_pool_t *pool, JSStringRef value) { - return (NSString *) CYPoolRelease(pool, CYCopyCFString(value)); +NSString *CYCopyNSString(JSStringRef value) { + return CYCopyNSString(CYCastCString_(value)); +} +#endif + +template +NSString *CYCastNSString(apr_pool_t *pool, Type_ value) { + return CYPoolRelease(pool, CYCopyNSString(value)); } bool CYCastBool(JSContextRef context, JSValueRef value) { return JSValueToBoolean(context, value); } +#ifdef __APPLE__ CFTypeRef CYCFType(apr_pool_t *pool, JSContextRef context, JSValueRef value, bool cast) { CFTypeRef object; bool copy; @@ -1403,6 +1509,7 @@ CFTypeRef CYCastCFType(apr_pool_t *pool, JSContextRef context, JSValueRef value) CFTypeRef CYCopyCFType(apr_pool_t *pool, JSContextRef context, JSValueRef value) { return CYCFType(pool, context, value, false); } +#endif NSArray *CYCastNSArray(JSPropertyNameArrayRef names) { CYPool pool; @@ -1475,9 +1582,15 @@ bool CYIsCallable(JSContextRef context, JSValueRef value) { if ((self = [super init]) != nil) { object_ = object; context_ = context; + JSValueProtect(context_, object_); } return self; } +- (void) dealloc { + JSValueUnprotect(context_, object_); + [super dealloc]; +} + - (NSObject *) cy$toJSON:(NSString *)key { JSValueRef toJSON(CYGetProperty(context_, object_, toJSON_)); if (!CYIsCallable(context_, toJSON)) @@ -1538,9 +1651,15 @@ bool CYIsCallable(JSContextRef context, JSValueRef value) { if ((self = [super init]) != nil) { object_ = object; context_ = context; + JSValueProtect(context_, object_); } return self; } +- (void) dealloc { + JSValueUnprotect(context_, object_); + [super dealloc]; +} + - (NSUInteger) count { return CYCastDouble(context_, CYGetProperty(context_, object_, length_)); } @@ -1718,23 +1837,24 @@ struct CYInternal : } }; -JSObjectRef CYMakeSelector(JSContextRef context, SEL sel) { +static JSObjectRef CYMakeSelector(JSContextRef context, SEL sel) { Selector_privateData *internal(new Selector_privateData(sel)); return JSObjectMake(context, Selector_, internal); } -JSObjectRef CYMakePointer(JSContextRef context, void *pointer, sig::Type *type, ffi_type *ffi, JSObjectRef owner) { +static JSObjectRef CYMakePointer(JSContextRef context, void *pointer, sig::Type *type, ffi_type *ffi, JSObjectRef owner) { Pointer *internal(new Pointer(pointer, context, owner, type)); return JSObjectMake(context, Pointer_, internal); } -JSObjectRef CYMakeFunctor(JSContextRef context, void (*function)(), const char *type) { +static JSObjectRef CYMakeFunctor(JSContextRef context, void (*function)(), const char *type) { Functor_privateData *internal(new Functor_privateData(type, function)); return JSObjectMake(context, Functor_, internal); } -const char *CYPoolCString(apr_pool_t *pool, JSStringRef value) { +static const char *CYPoolCString(apr_pool_t *pool, JSStringRef value) { if (pool == NULL) { + // XXX: this could be much more efficient const char *string([CYCastNSString(NULL, value) UTF8String]); return string; } else { @@ -1745,30 +1865,41 @@ const char *CYPoolCString(apr_pool_t *pool, JSStringRef value) { } } -const char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSValueRef value) { +static const char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSValueRef value) { return JSValueIsNull(context, value) ? NULL : CYPoolCString(pool, CYJSString(context, value)); } -bool CYGetOffset(apr_pool_t *pool, JSStringRef value, ssize_t &index) { +static bool CYGetOffset(apr_pool_t *pool, JSStringRef value, ssize_t &index) { return CYGetOffset(CYPoolCString(pool, value), index); } // XXX: this macro is unhygenic -#define CYCastCString(context, value) ({ \ +#define CYCastCString_(string) ({ \ char *utf8; \ - if (value == NULL) \ + if (string == NULL) \ utf8 = NULL; \ - else if (JSStringRef string = CYCopyJSString(context, value)) { \ + else { \ size_t size(JSStringGetMaximumUTF8CStringSize(string)); \ utf8 = reinterpret_cast(alloca(size)); \ JSStringGetUTF8CString(string, utf8, size); \ + } \ + utf8; \ +}) + +// XXX: this macro is unhygenic +#define CYCastCString(context, value) ({ \ + char *utf8; \ + if (value == NULL) \ + utf8 = NULL; \ + else if (JSStringRef string = CYCopyJSString(context, value)) { \ + utf8 = CYCastCString_(string); \ JSStringRelease(string); \ } else \ utf8 = NULL; \ utf8; \ }) -void *CYCastPointer_(JSContextRef context, JSValueRef value) { +static void *CYCastPointer_(JSContextRef context, JSValueRef value) { switch (JSValueGetType(context, value)) { case kJSTypeNull: return NULL; @@ -1788,11 +1919,11 @@ void *CYCastPointer_(JSContextRef context, JSValueRef value) { } template -_finline Type_ CYCastPointer(JSContextRef context, JSValueRef value) { +static _finline Type_ CYCastPointer(JSContextRef context, JSValueRef value) { return reinterpret_cast(CYCastPointer_(context, value)); } -SEL CYCastSEL(JSContextRef context, JSValueRef value) { +static SEL CYCastSEL(JSContextRef context, JSValueRef value) { if (JSValueIsObjectOfClass(context, value, Selector_)) { Selector_privateData *internal(reinterpret_cast(JSObjectGetPrivate((JSObjectRef) value))); return reinterpret_cast(internal->value_); @@ -1800,7 +1931,7 @@ SEL CYCastSEL(JSContextRef context, JSValueRef value) { return CYCastPointer(context, value); } -void CYPoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, JSValueRef value) { +static 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: *reinterpret_cast(data) = JSValueToBoolean(context, value); @@ -1878,7 +2009,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, bool initialize = false, JSObjectRef owner = NULL) { +static JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, bool initialize = false, JSObjectRef owner = NULL) { JSValueRef value; switch (type->primitive) { @@ -1968,7 +2099,7 @@ static bool CYImplements(id object, Class _class, SEL selector, bool devoid) { return false; } -const char *CYPoolTypeEncoding(apr_pool_t *pool, Class _class, SEL sel, Method method) { +static const char *CYPoolTypeEncoding(apr_pool_t *pool, Class _class, SEL sel, Method method) { if (method != NULL) return method_getTypeEncoding(method); else if (NSString *type = [[Bridge_ objectAtIndex:1] objectForKey:CYCastNSString(pool, sel_getName(sel))]) @@ -1977,7 +2108,7 @@ const char *CYPoolTypeEncoding(apr_pool_t *pool, Class _class, SEL sel, Method m return NULL; } -void FunctionClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) { +static void FunctionClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) { Closure_privateData *internal(reinterpret_cast(arg)); JSContextRef context(internal->context_); @@ -1992,7 +2123,7 @@ void FunctionClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) { CYPoolFFI(NULL, context, internal->signature_.elements[0].type, internal->cif_.rtype, result, value); } -void MessageClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) { +static void MessageClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) { Closure_privateData *internal(reinterpret_cast(arg)); JSContextRef context(internal->context_); @@ -2009,7 +2140,7 @@ void MessageClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) { CYPoolFFI(NULL, context, internal->signature_.elements[0].type, internal->cif_.rtype, result, value); } -Closure_privateData *CYMakeFunctor_(JSContextRef context, JSObjectRef function, const char *type, void (*callback)(ffi_cif *, void *, void **, void *)) { +static Closure_privateData *CYMakeFunctor_(JSContextRef context, JSObjectRef function, const char *type, void (*callback)(ffi_cif *, void *, void **, void *)) { // XXX: in case of exceptions this will leak // XXX: in point of fact, this may /need/ to leak :( Closure_privateData *internal(new Closure_privateData(CYGetJSContext(), function, type)); @@ -2030,7 +2161,7 @@ Closure_privateData *CYMakeFunctor_(JSContextRef context, JSObjectRef function, return internal; } -JSObjectRef CYMakeFunctor(JSContextRef context, JSObjectRef function, const char *type) { +static JSObjectRef CYMakeFunctor(JSContextRef context, JSObjectRef function, const char *type) { Closure_privateData *internal(CYMakeFunctor_(context, function, type, &FunctionClosure_)); return JSObjectMake(context, Functor_, internal); } @@ -2207,11 +2338,13 @@ static JSValueRef Instance_getProperty(JSContextRef context, JSObjectRef object, const char *string(CYPoolCString(pool, name)); Class _class(object_getClass(self)); +#ifdef __APPLE__ if (objc_property_t property = class_getProperty(_class, string)) { PropertyAttributes attributes(property); SEL sel(sel_registerName(attributes.Getter())); return CYSendMessage(pool, context, self, sel, 0, NULL, false, exception); } +#endif if (SEL sel = sel_getUid(string)) if (CYImplements(self, _class, sel, true)) @@ -2239,6 +2372,7 @@ static bool Instance_setProperty(JSContextRef context, JSObjectRef object, JSStr const char *string(CYPoolCString(pool, name)); Class _class(object_getClass(self)); +#ifdef __APPLE__ if (objc_property_t property = class_getProperty(_class, string)) { PropertyAttributes attributes(property); if (const char *setter = attributes.Setter()) { @@ -2248,6 +2382,7 @@ static bool Instance_setProperty(JSContextRef context, JSObjectRef object, JSStr return true; } } +#endif size_t length(strlen(string)); @@ -2316,7 +2451,7 @@ static JSObjectRef Instance_callAsConstructor(JSContextRef context, JSObjectRef } CYCatch } -bool CYIsClass(id self) { +static bool CYIsClass(id self) { // XXX: this is a lame object_isClass return class_getInstanceMethod(object_getClass(self), @selector(alloc)) != NULL; } @@ -2412,7 +2547,7 @@ static JSValueRef Internal_callAsFunction_$cya(JSContextRef context, JSObjectRef return internal->GetOwner(); } -bool Index_(apr_pool_t *pool, Struct_privateData *internal, JSStringRef property, ssize_t &index, uint8_t *&base) { +static bool Index_(apr_pool_t *pool, Struct_privateData *internal, JSStringRef property, ssize_t &index, uint8_t *&base) { Type_privateData *typical(internal->type_); sig::Type *type(typical->type_); if (type == NULL) @@ -2727,6 +2862,16 @@ static void ObjectiveC_Protocols_getPropertyNames(JSContextRef context, JSObject free(data); } +static JSObjectRef CYMakeType(JSContextRef context, const char *type) { + Type_privateData *internal(new Type_privateData(NULL, type)); + return JSObjectMake(context, Type_privateData::Class_, internal); +} + +static JSObjectRef CYMakeType(JSContextRef context, sig::Type *type) { + Type_privateData *internal(new Type_privateData(type)); + return JSObjectMake(context, Type_privateData::Class_, internal); +} + static JSValueRef Runtime_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { if (JSStringIsEqualToUTF8CString(property, "nil")) return Instance::Make(context, nil); @@ -2750,11 +2895,17 @@ static JSValueRef Runtime_getProperty(JSContextRef context, JSObjectRef object, sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif); return CYFromFFI(context, signature.elements[0].type, cif.rtype, [name cy$symbol]); } + if (NSMutableArray *entry = [[Bridge_ objectAtIndex:2] objectForKey:name]) + switch ([[entry objectAtIndex:0] intValue]) { + // XXX: implement case 0 + case 1: + return CYMakeType(context, CYPoolCString(pool, [entry objectAtIndex:1])); + } return NULL; } CYCatch } -bool stret(ffi_type *ffi_type) { +static bool stret(ffi_type *ffi_type) { return ffi_type->type == FFI_TYPE_STRUCT && ( ffi_type->size > OBJC_MAX_STRUCT_BY_VALUE || struct_forward_array[ffi_type->size] != 0 @@ -2764,12 +2915,14 @@ bool stret(ffi_type *ffi_type) { extern "C" { int *_NSGetArgc(void); char ***_NSGetArgv(void); - int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName); } static JSValueRef System_print(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { - NSLog(@"%s", CYCastCString(context, arguments[0])); + if (count == 0) + NSLog(@""); + else + NSLog(@"%s", CYCastCString(context, arguments[0])); return CYJSUndefined(context); } CYCatch } @@ -2878,6 +3031,11 @@ static JSValueRef objc_registerClassPair_(JSContextRef context, JSObjectRef obje } /* }}} */ +static JSValueRef Cycript_gc_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + JSGarbageCollect(context); + return CYJSUndefined(context); +} + 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; @@ -2906,7 +3064,7 @@ static JSValueRef Functor_callAsFunction(JSContextRef context, JSObjectRef objec return CYCallFunction(pool, context, 0, NULL, count, arguments, false, exception, &internal->signature_, &internal->cif_, internal->GetValue()); } -JSObjectRef Selector_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { +static JSObjectRef Selector_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { if (count != 1) @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to Selector constructor" userInfo:nil]; @@ -2915,7 +3073,7 @@ JSObjectRef Selector_new(JSContextRef context, JSObjectRef object, size_t count, } CYCatch } -JSObjectRef Pointer_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { +static JSObjectRef Pointer_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { if (count != 2) @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to Functor constructor" userInfo:nil]; @@ -2932,25 +3090,47 @@ JSObjectRef Pointer_new(JSContextRef context, JSObjectRef object, size_t count, } CYCatch } -JSObjectRef CYMakeType(JSContextRef context, JSObjectRef object, const char *type) { - Type_privateData *internal(new Type_privateData(NULL, type)); - return JSObjectMake(context, Type_, internal); -} - -JSObjectRef Type_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { +static JSObjectRef Type_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { if (count != 1) @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to Type constructor" userInfo:nil]; const char *type(CYCastCString(context, arguments[0])); - return CYMakeType(context, object, type); + return CYMakeType(context, type); + } CYCatch +} + +static JSValueRef Type_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { + Type_privateData *internal(reinterpret_cast(JSObjectGetPrivate(object))); + + CYTry { + sig::Type type; + + if (JSStringIsEqualToUTF8CString(property, "$cyi")) { + type.primitive = sig::pointer_P; + type.data.data.size = 0; + } else { + size_t index(CYGetIndex(NULL, property)); + if (index == _not(size_t)) + return NULL; + type.primitive = sig::array_P; + type.data.data.size = index; + } + + type.name = NULL; + type.flags = 0; + + type.data.data.type = internal->type_; + + return CYMakeType(context, &type); } CYCatch } static JSValueRef Type_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + Type_privateData *internal(reinterpret_cast(JSObjectGetPrivate(object))); + CYTry { if (count != 1) @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to type cast function" userInfo:nil]; - Type_privateData *internal(reinterpret_cast(JSObjectGetPrivate(object))); sig::Type *type(internal->type_); ffi_type *ffi(internal->GetFFI()); // XXX: alignment? @@ -2963,17 +3143,26 @@ static JSValueRef Type_callAsFunction(JSContextRef context, JSObjectRef object, static JSObjectRef Type_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { - if (count > 1) + if (count != 0) @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to type cast function" userInfo:nil]; Type_privateData *internal(reinterpret_cast(JSObjectGetPrivate(object))); - size_t size(count == 0 ? 0 : CYCastDouble(context, arguments[0])); - // XXX: alignment? - void *value(malloc(internal->GetFFI()->size * size)); - return CYMakePointer(context, value, internal->type_, internal->ffi_, NULL); + + sig::Type *type(internal->type_); + size_t size; + + if (type->primitive != sig::array_P) + size = 0; + else { + size = type->data.data.size; + type = type->data.data.type; + } + + void *value(malloc(internal->GetFFI()->size)); + return CYMakePointer(context, value, type, NULL, NULL); } CYCatch } -JSObjectRef Instance_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { +static JSObjectRef Instance_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { if (count > 1) @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to Instance constructor" userInfo:nil]; @@ -2982,7 +3171,7 @@ JSObjectRef Instance_new(JSContextRef context, JSObjectRef object, size_t count, } CYCatch } -JSObjectRef Functor_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { +static JSObjectRef Functor_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { if (count != 2) @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to Functor constructor" userInfo:nil]; @@ -2991,7 +3180,7 @@ JSObjectRef Functor_new(JSContextRef context, JSObjectRef object, size_t count, } CYCatch } -JSValueRef CYValue_getProperty_value(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { +static JSValueRef CYValue_getProperty_value(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYValue *internal(reinterpret_cast(JSObjectGetPrivate(object))); return CYCastJSValue(context, reinterpret_cast(internal->value_)); } @@ -3228,28 +3417,6 @@ static JSStaticFunction Type_staticFunctions[4] = { {NULL, NULL, 0} }; -CYDriver::CYDriver(const std::string &filename) : - state_(CYClear), - data_(NULL), - size_(0), - file_(NULL), - filename_(filename), - source_(NULL) -{ - ScannerInit(); -} - -CYDriver::~CYDriver() { - ScannerDestroy(); -} - -void cy::parser::error(const cy::parser::location_type &location, const std::string &message) { - CYDriver::Error error; - error.location_ = location; - error.message_ = message; - driver.errors_.push_back(error); -} - void CYSetArgs(int argc, const char *argv[]) { JSContextRef context(CYGetJSContext()); JSValueRef args[argc]; @@ -3298,25 +3465,7 @@ const char *CYExecute(apr_pool_t *pool, const char *code) { _pooled return json; } -bool CYRecvAll_(int socket, uint8_t *data, size_t size) { - while (size != 0) if (size_t writ = _syscall(recv(socket, data, size, 0))) { - data += writ; - size -= writ; - } else - return false; - return true; -} - -bool CYSendAll_(int socket, const uint8_t *data, size_t size) { - while (size != 0) if (size_t writ = _syscall(send(socket, data, size, 0))) { - data += writ; - size -= writ; - } else - return false; - return true; -} - -apr_pool_t *Pool_; +static apr_pool_t *Pool_; struct CYExecute_ { apr_pool_t *pool_; @@ -3382,8 +3531,11 @@ struct CYClient : json = NULL; size = _not(size_t); } else { + CYContext context(driver.pool_); + driver.program_->Replace(context); std::ostringstream str; - driver.source_->Show(str); + CYOutput out(str); + out << *driver.program_; std::string code(str.str()); CYExecute_ execute = {pool, code.c_str()}; [client performSelectorOnMainThread:@selector(execute:) withObject:[NSValue valueWithPointer:&execute] waitUntilDone:YES]; @@ -3423,9 +3575,12 @@ MSInitialize { _pooled Bridge_ = [[NSMutableArray arrayWithContentsOfFile:@"/usr/lib/libcycript.plist"] retain]; - NSArray_ = objc_getClass("NSArray"); +#ifdef __APPLE__ NSCFBoolean_ = objc_getClass("NSCFBoolean"); NSCFType_ = objc_getClass("NSCFType"); +#endif + + NSArray_ = objc_getClass("NSArray"); NSDictionary_ = objc_getClass("NSDictonary"); NSMessageBuilder_ = objc_getClass("NSMessageBuilder"); NSZombie_ = objc_getClass("_NSZombie_"); @@ -3524,11 +3679,11 @@ JSGlobalContextRef CYGetJSContext() { definition = kJSClassDefinitionEmpty; definition.className = "Type"; definition.staticFunctions = Type_staticFunctions; - //definition.getProperty = &Type_getProperty; + definition.getProperty = &Type_getProperty; definition.callAsFunction = &Type_callAsFunction; definition.callAsConstructor = &Type_callAsConstructor; definition.finalize = &Finalize; - Type_ = JSClassCreate(&definition); + Type_privateData::Class_ = JSClassCreate(&definition); definition = kJSClassDefinitionEmpty; definition.className = "Runtime"; @@ -3611,11 +3766,17 @@ JSGlobalContextRef CYGetJSContext() { CYSetProperty(context, global, CYJSString("Instance"), Instance); CYSetProperty(context, global, CYJSString("Pointer"), JSObjectMakeConstructor(context, Pointer_, &Pointer_new)); CYSetProperty(context, global, CYJSString("Selector"), Selector); - CYSetProperty(context, global, CYJSString("Type"), JSObjectMakeConstructor(context, Type_, &Type_new)); + CYSetProperty(context, global, CYJSString("Type"), JSObjectMakeConstructor(context, Type_privateData::Class_, &Type_new)); MSHookFunction(&objc_registerClassPair, MSHake(objc_registerClassPair)); +#ifdef __APPLE__ class_addMethod(NSCFType_, @selector(cy$toJSON:), reinterpret_cast(&NSCFType$cy$toJSON), "@12@0:4@8"); +#endif + + JSObjectRef cycript(JSObjectMake(context, NULL, NULL)); + CYSetProperty(context, global, CYJSString("Cycript"), cycript); + CYSetProperty(context, cycript, CYJSString("gc"), JSObjectMakeFunctionWithCallback(context, CYJSString("gc"), &Cycript_gc_callAsFunction)); CYSetProperty(context, global, CYJSString("objc_registerClassPair"), JSObjectMakeFunctionWithCallback(context, CYJSString("objc_registerClassPair"), &objc_registerClassPair_)); CYSetProperty(context, global, CYJSString("objc_msgSend"), JSObjectMakeFunctionWithCallback(context, CYJSString("objc_msgSend"), &$objc_msgSend));