1 /* Cyrker - Remove Execution Server and Disassembler
 
   2  * Copyright (C) 2009  Jay Freeman (saurik)
 
   5 /* Modified BSD License {{{ */
 
   7  *        Redistribution and use in source and binary
 
   8  * forms, with or without modification, are permitted
 
   9  * provided that the following conditions are met:
 
  11  * 1. Redistributions of source code must retain the
 
  12  *    above copyright notice, this list of conditions
 
  13  *    and the following disclaimer.
 
  14  * 2. Redistributions in binary form must reproduce the
 
  15  *    above copyright notice, this list of conditions
 
  16  *    and the following disclaimer in the documentation
 
  17  *    and/or other materials provided with the
 
  19  * 3. The name of the author may not be used to endorse
 
  20  *    or promote products derived from this software
 
  21  *    without specific prior written permission.
 
  23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
 
  24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 
  25  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 
  26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
  27  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
 
  28  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
  29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
  30  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 
  31  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
  32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 
  33  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 
  34  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 
  35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
  36  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  42 #include <substrate.h>
 
  43 #include "cycript.hpp"
 
  45 #include "sig/parse.hpp"
 
  46 #include "sig/ffi_type.hpp"
 
  48 #include "Pooling.hpp"
 
  53 #include <CoreFoundation/CoreFoundation.h>
 
  54 #include <CoreFoundation/CFLogUtilities.h>
 
  56 #include <CFNetwork/CFNetwork.h>
 
  58 #include <WebKit/WebScriptObject.h>
 
  60 #include <sys/types.h>
 
  61 #include <sys/socket.h>
 
  62 #include <netinet/in.h>
 
  66 #include <ext/stdio_filebuf.h>
 
  71 #include "Cycript.tab.hh"
 
  76 #define _assert(test) do { \
 
  78         @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"_assert(%s):%s(%u):%s", #test, __FILE__, __LINE__, __FUNCTION__] userInfo:nil]; \
 
  81 #define _trace() do { \
 
  82     CFLog(kCFLogLevelNotice, CFSTR("_trace():%u"), __LINE__); \
 
  85 static JSContextRef Context_;
 
  86 static JSObjectRef System_;
 
  88 static JSClassRef Functor_;
 
  89 static JSClassRef Instance_;
 
  90 static JSClassRef Pointer_;
 
  91 static JSClassRef Selector_;
 
  93 static JSObjectRef Array_;
 
  94 static JSObjectRef Function_;
 
  96 static JSStringRef name_;
 
  97 static JSStringRef message_;
 
  98 static JSStringRef length_;
 
 100 static Class NSCFBoolean_;
 
 102 static NSMutableDictionary *Bridge_;
 
 105     CFHTTPMessageRef message_;
 
 109 JSObjectRef CYMakeInstance(JSContextRef context, id object) {
 
 110     return JSObjectMake(context, Instance_, object);
 
 113 JSValueRef CYCastJSValue(JSContextRef context, bool value) {
 
 114     return JSValueMakeBoolean(context, value);
 
 117 JSValueRef CYCastJSValue(JSContextRef context, double value) {
 
 118     return JSValueMakeNumber(context, value);
 
 121 #define CYCastJSValue_(Type_) \
 
 122     JSValueRef CYCastJSValue(JSContextRef context, Type_ value) { \
 
 123         return JSValueMakeNumber(context, static_cast<double>(value)); \
 
 127 CYCastJSValue_(unsigned int)
 
 128 CYCastJSValue_(long int)
 
 129 CYCastJSValue_(long unsigned int)
 
 130 CYCastJSValue_(long long int)
 
 131 CYCastJSValue_(long long unsigned int)
 
 133 JSValueRef CYJSUndefined(JSContextRef context) {
 
 134     return JSValueMakeUndefined(context);
 
 137 @interface NSMethodSignature (Cycript)
 
 138 - (NSString *) _typeString;
 
 141 @interface NSObject (Cycript)
 
 142 - (bool) cy$isUndefined;
 
 143 - (NSString *) cy$toJSON;
 
 144 - (JSValueRef) cy$JSValueInContext:(JSContextRef)context;
 
 147 @interface NSString (Cycript)
 
 148 - (void *) cy$symbol;
 
 151 @interface NSNumber (Cycript)
 
 152 - (void *) cy$symbol;
 
 155 @implementation NSObject (Cycript)
 
 157 - (bool) cy$isUndefined {
 
 161 - (NSString *) cy$toJSON {
 
 162     return [self description];
 
 165 - (JSValueRef) cy$JSValueInContext:(JSContextRef)context {
 
 166     return CYMakeInstance(context, self);
 
 171 @implementation WebUndefined (Cycript)
 
 173 - (bool) cy$isUndefined {
 
 177 - (NSString *) cy$toJSON {
 
 181 - (JSValueRef) cy$JSValueInContext:(JSContextRef)context {
 
 182     return CYJSUndefined(context);
 
 187 @implementation NSArray (Cycript)
 
 189 - (NSString *) cy$toJSON {
 
 190     NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
 
 191     [json appendString:@"["];
 
 194     for (id object in self) {
 
 196             [json appendString:@","];
 
 199         if (![object cy$isUndefined])
 
 200             [json appendString:[object cy$toJSON]];
 
 202             [json appendString:@","];
 
 207     [json appendString:@"]"];
 
 213 @implementation NSDictionary (Cycript)
 
 215 - (NSString *) cy$toJSON {
 
 216     NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
 
 217     [json appendString:@"({"];
 
 220     for (id key in self) {
 
 222             [json appendString:@","];
 
 225         [json appendString:[key cy$toJSON]];
 
 226         [json appendString:@":"];
 
 227         NSObject *object([self objectForKey:key]);
 
 228         [json appendString:[object cy$toJSON]];
 
 231     [json appendString:@"})"];
 
 237 @implementation NSNumber (Cycript)
 
 239 - (NSString *) cy$toJSON {
 
 240     return [self class] != NSCFBoolean_ ? [self stringValue] : [self boolValue] ? @"true" : @"false";
 
 243 - (JSValueRef) cy$JSValueInContext:(JSContextRef)context {
 
 244     return [self class] != NSCFBoolean_ ? CYCastJSValue(context, [self doubleValue]) : CYCastJSValue(context, [self boolValue]);
 
 247 - (void *) cy$symbol {
 
 248     return [self pointerValue];
 
 253 @implementation NSString (Cycript)
 
 255 - (NSString *) cy$toJSON {
 
 256     CFMutableStringRef json(CFStringCreateMutableCopy(kCFAllocatorDefault, 0, (CFStringRef) self));
 
 258     CFStringFindAndReplace(json, CFSTR("\\"), CFSTR("\\\\"), CFRangeMake(0, CFStringGetLength(json)), 0);
 
 259     CFStringFindAndReplace(json, CFSTR("\""), CFSTR("\\\""), CFRangeMake(0, CFStringGetLength(json)), 0);
 
 260     CFStringFindAndReplace(json, CFSTR("\t"), CFSTR("\\t"), CFRangeMake(0, CFStringGetLength(json)), 0);
 
 261     CFStringFindAndReplace(json, CFSTR("\r"), CFSTR("\\r"), CFRangeMake(0, CFStringGetLength(json)), 0);
 
 262     CFStringFindAndReplace(json, CFSTR("\n"), CFSTR("\\n"), CFRangeMake(0, CFStringGetLength(json)), 0);
 
 264     CFStringInsert(json, 0, CFSTR("\""));
 
 265     CFStringAppend(json, CFSTR("\""));
 
 267     return [reinterpret_cast<const NSString *>(json) autorelease];
 
 270 - (void *) cy$symbol {
 
 271     return dlsym(RTLD_DEFAULT, [self UTF8String]);
 
 276 @interface CYJSObject : NSDictionary {
 
 278     JSContextRef context_;
 
 281 - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context;
 
 283 - (NSUInteger) count;
 
 284 - (id) objectForKey:(id)key;
 
 285 - (NSEnumerator *) keyEnumerator;
 
 286 - (void) setObject:(id)object forKey:(id)key;
 
 287 - (void) removeObjectForKey:(id)key;
 
 291 @interface CYJSArray : NSArray {
 
 293     JSContextRef context_;
 
 296 - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context;
 
 298 - (NSUInteger) count;
 
 299 - (id) objectAtIndex:(NSUInteger)index;
 
 303 CYRange WordStartRange_(0x1000000000LLU,0x7fffffe87fffffeLLU); // A-Za-z_$
 
 304 CYRange WordEndRange_(0x3ff001000000000LLU,0x7fffffe87fffffeLLU); // A-Za-z_$0-9
 
 306 JSContextRef CYGetJSContext() {
 
 311     @catch (id error) { \
 
 312         NSLog(@"e:%@", error); \
 
 313         CYThrow(context, error, exception); \
 
 317 void CYThrow(JSContextRef context, JSValueRef value);
 
 319 apr_status_t CYPoolRelease_(void *data) {
 
 320     id object(reinterpret_cast<id>(data));
 
 325 id CYPoolRelease(apr_pool_t *pool, id object) {
 
 327         return [object autorelease];
 
 329         apr_pool_cleanup_register(pool, object, &CYPoolRelease_, &apr_pool_cleanup_null);
 
 334 id CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSObjectRef object) {
 
 335     if (JSValueIsObjectOfClass(context, object, Instance_))
 
 336         return reinterpret_cast<id>(JSObjectGetPrivate(object));
 
 337     JSValueRef exception(NULL);
 
 338     bool array(JSValueIsInstanceOfConstructor(context, object, Array_, &exception));
 
 339     CYThrow(context, exception);
 
 340     id value(array ? [CYJSArray alloc] : [CYJSObject alloc]);
 
 341     return CYPoolRelease(pool, [value initWithJSObject:object inContext:context]);
 
 344 JSStringRef CYCopyJSString(id value) {
 
 345     return value == NULL ? NULL : JSStringCreateWithCFString(reinterpret_cast<CFStringRef>([value description]));
 
 348 JSStringRef CYCopyJSString(const char *value) {
 
 349     return value == NULL ? NULL : JSStringCreateWithUTF8CString(value);
 
 352 JSStringRef CYCopyJSString(JSStringRef value) {
 
 353     return value == NULL ? NULL : JSStringRetain(value);
 
 356 JSStringRef CYCopyJSString(JSContextRef context, JSValueRef value) {
 
 357     if (JSValueIsNull(context, value))
 
 359     JSValueRef exception(NULL);
 
 360     JSStringRef string(JSValueToStringCopy(context, value, &exception));
 
 361     CYThrow(context, exception);
 
 370         JSStringRelease(string_);
 
 374     CYJSString(const CYJSString &rhs) :
 
 375         string_(CYCopyJSString(rhs.string_))
 
 379     template <typename Arg0_>
 
 380     CYJSString(Arg0_ arg0) :
 
 381         string_(CYCopyJSString(arg0))
 
 385     template <typename Arg0_, typename Arg1_>
 
 386     CYJSString(Arg0_ arg0, Arg1_ arg1) :
 
 387         string_(CYCopyJSString(arg0, arg1))
 
 391     CYJSString &operator =(const CYJSString &rhs) {
 
 393         string_ = CYCopyJSString(rhs.string_);
 
 406     operator JSStringRef() const {
 
 411 CFStringRef CYCopyCFString(JSStringRef value) {
 
 412     return JSStringCopyCFString(kCFAllocatorDefault, value);
 
 415 CFStringRef CYCopyCFString(JSContextRef context, JSValueRef value) {
 
 416     return CYCopyCFString(CYJSString(context, value));
 
 419 double CYCastDouble(JSContextRef context, JSValueRef value) {
 
 420     JSValueRef exception(NULL);
 
 421     double number(JSValueToNumber(context, value, &exception));
 
 422     CYThrow(context, exception);
 
 426 CFNumberRef CYCopyCFNumber(JSContextRef context, JSValueRef value) {
 
 427     double number(CYCastDouble(context, value));
 
 428     return CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &number);
 
 431 NSString *CYCastNSString(apr_pool_t *pool, JSStringRef value) {
 
 432     return CYPoolRelease(pool, reinterpret_cast<const NSString *>(CYCopyCFString(value)));
 
 435 bool CYCastBool(JSContextRef context, JSValueRef value) {
 
 436     return JSValueToBoolean(context, value);
 
 439 CFTypeRef CYCFType(apr_pool_t *pool, JSContextRef context, JSValueRef value, bool cast) {
 
 443     switch (JSType type = JSValueGetType(context, value)) {
 
 444         case kJSTypeUndefined:
 
 445             object = [WebUndefined undefined];
 
 454             object = CYCastBool(context, value) ? kCFBooleanTrue : kCFBooleanFalse;
 
 459             object = CYCopyCFNumber(context, value);
 
 464             object = CYCopyCFString(context, value);
 
 469             // XXX: this might could be more efficient
 
 470             object = (CFTypeRef) CYCastNSObject(pool, context, (JSObjectRef) value);
 
 475             @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"JSValueGetType() == 0x%x", type] userInfo:nil];
 
 482         return CYPoolRelease(pool, (id) object);
 
 484         return CFRetain(object);
 
 487 CFTypeRef CYCastCFType(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
 
 488     return CYCFType(pool, context, value, true);
 
 491 CFTypeRef CYCopyCFType(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
 
 492     return CYCFType(pool, context, value, false);
 
 495 NSArray *CYCastNSArray(JSPropertyNameArrayRef names) {
 
 497     size_t size(JSPropertyNameArrayGetCount(names));
 
 498     NSMutableArray *array([NSMutableArray arrayWithCapacity:size]);
 
 499     for (size_t index(0); index != size; ++index)
 
 500         [array addObject:CYCastNSString(pool, JSPropertyNameArrayGetNameAtIndex(names, index))];
 
 504 id CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
 
 505     return reinterpret_cast<const NSObject *>(CYCastCFType(pool, context, value));
 
 508 void CYThrow(JSContextRef context, JSValueRef value) {
 
 511     @throw CYCastNSObject(NULL, context, value);
 
 514 JSValueRef CYJSNull(JSContextRef context) {
 
 515     return JSValueMakeNull(context);
 
 518 JSValueRef CYCastJSValue(JSContextRef context, JSStringRef value) {
 
 519     return value == NULL ? CYJSNull(context) : JSValueMakeString(context, value);
 
 522 JSValueRef CYCastJSValue(JSContextRef context, const char *value) {
 
 523     return CYCastJSValue(context, CYJSString(value));
 
 526 JSValueRef CYCastJSValue(JSContextRef context, id value) {
 
 527     return value == nil ? CYJSNull(context) : [value cy$JSValueInContext:context];
 
 530 JSObjectRef CYCastJSObject(JSContextRef context, JSValueRef value) {
 
 531     JSValueRef exception(NULL);
 
 532     JSObjectRef object(JSValueToObject(context, value, &exception));
 
 533     CYThrow(context, exception);
 
 537 JSValueRef CYGetProperty(JSContextRef context, JSObjectRef object, JSStringRef name) {
 
 538     JSValueRef exception(NULL);
 
 539     JSValueRef value(JSObjectGetProperty(context, object, name, &exception));
 
 540     CYThrow(context, exception);
 
 544 void CYSetProperty(JSContextRef context, JSObjectRef object, JSStringRef name, JSValueRef value) {
 
 545     JSValueRef exception(NULL);
 
 546     JSObjectSetProperty(context, object, name, value, kJSPropertyAttributeNone, &exception);
 
 547     CYThrow(context, exception);
 
 550 void CYThrow(JSContextRef context, id error, JSValueRef *exception) {
 
 551     *exception = CYCastJSValue(context, error);
 
 554 @implementation CYJSObject
 
 556 - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context {
 
 557     if ((self = [super init]) != nil) {
 
 563 - (NSUInteger) count {
 
 564     JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context_, object_));
 
 565     size_t size(JSPropertyNameArrayGetCount(names));
 
 566     JSPropertyNameArrayRelease(names);
 
 570 - (id) objectForKey:(id)key {
 
 571     return CYCastNSObject(NULL, context_, CYGetProperty(context_, object_, CYJSString(key)));
 
 574 - (NSEnumerator *) keyEnumerator {
 
 575     JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context_, object_));
 
 576     NSEnumerator *enumerator([CYCastNSArray(names) objectEnumerator]);
 
 577     JSPropertyNameArrayRelease(names);
 
 581 - (void) setObject:(id)object forKey:(id)key {
 
 582     CYSetProperty(context_, object_, CYJSString(key), CYCastJSValue(context_, object));
 
 585 - (void) removeObjectForKey:(id)key {
 
 586     JSValueRef exception(NULL);
 
 587     // XXX: this returns a bool... throw exception, or ignore?
 
 588     JSObjectDeleteProperty(context_, object_, CYJSString(key), &exception);
 
 589     CYThrow(context_, exception);
 
 594 @implementation CYJSArray
 
 596 - (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context {
 
 597     if ((self = [super init]) != nil) {
 
 603 - (NSUInteger) count {
 
 604     return CYCastDouble(context_, CYGetProperty(context_, object_, length_));
 
 607 - (id) objectAtIndex:(NSUInteger)index {
 
 608     JSValueRef exception(NULL);
 
 609     JSValueRef value(JSObjectGetPropertyAtIndex(context_, object_, index, &exception));
 
 610     CYThrow(context_, exception);
 
 611     id object(CYCastNSObject(NULL, context_, value));
 
 612     return object == nil ? [NSNull null] : object;
 
 617 CFStringRef CYCopyJSONString(JSContextRef context, JSValueRef value) {
 
 618     id object(CYCastNSObject(NULL, context, value));
 
 619     return reinterpret_cast<CFStringRef>([(object == nil ? @"null" : [object cy$toJSON]) retain]);
 
 622 static void OnData(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *value, void *info) {
 
 624         case kCFSocketDataCallBack:
 
 625             CFDataRef data(reinterpret_cast<CFDataRef>(value));
 
 626             Client *client(reinterpret_cast<Client *>(info));
 
 628             if (client->message_ == NULL)
 
 629                 client->message_ = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, TRUE);
 
 631             if (!CFHTTPMessageAppendBytes(client->message_, CFDataGetBytePtr(data), CFDataGetLength(data)))
 
 632                 CFLog(kCFLogLevelError, CFSTR("CFHTTPMessageAppendBytes()"));
 
 633             else if (CFHTTPMessageIsHeaderComplete(client->message_)) {
 
 634                 CFURLRef url(CFHTTPMessageCopyRequestURL(client->message_));
 
 636                 CFStringRef path(CFURLCopyStrictPath(url, &absolute));
 
 637                 CFRelease(client->message_);
 
 639                 CFStringRef code(CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault, path, CFSTR("")));
 
 642                 JSStringRef script(JSStringCreateWithCFString(code));
 
 645                 JSValueRef result(JSEvaluateScript(CYGetJSContext(), script, NULL, NULL, 0, NULL));
 
 646                 JSStringRelease(script);
 
 648                 CFHTTPMessageRef response(CFHTTPMessageCreateResponse(kCFAllocatorDefault, 200, NULL, kCFHTTPVersion1_1));
 
 649                 CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Type"), CFSTR("application/json; charset=utf-8"));
 
 651                 CFStringRef json(CYCopyJSONString(CYGetJSContext(), result));
 
 652                 CFDataRef body(CFStringCreateExternalRepresentation(kCFAllocatorDefault, json, kCFStringEncodingUTF8, NULL));
 
 655                 CFStringRef length(CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), CFDataGetLength(body)));
 
 656                 CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Length"), length);
 
 659                 CFHTTPMessageSetBody(response, body);
 
 662                 CFDataRef serialized(CFHTTPMessageCopySerializedMessage(response));
 
 665                 CFSocketSendData(socket, NULL, serialized, 0);
 
 666                 CFRelease(serialized);
 
 674 static void OnAccept(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *value, void *info) {
 
 676         case kCFSocketAcceptCallBack:
 
 677             Client *client(new Client());
 
 679             client->message_ = NULL;
 
 681             CFSocketContext context;
 
 683             context.info = client;
 
 684             context.retain = NULL;
 
 685             context.release = NULL;
 
 686             context.copyDescription = NULL;
 
 688             client->socket_ = CFSocketCreateWithNative(kCFAllocatorDefault, *reinterpret_cast<const CFSocketNativeHandle *>(value), kCFSocketDataCallBack, &OnData, &context);
 
 690             CFRunLoopAddSource(CFRunLoopGetCurrent(), CFSocketCreateRunLoopSource(kCFAllocatorDefault, client->socket_, 0), kCFRunLoopDefaultMode);
 
 695 static JSValueRef Instance_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
 
 698         NSString *name(CYCastNSString(pool, property));
 
 699         NSLog(@"get:%@", name);
 
 704 static bool Instance_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) {
 
 707         NSString *name(CYCastNSString(pool, property));
 
 708         NSLog(@"set:%@", name);
 
 713 static bool Instance_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
 
 716         NSString *name(CYCastNSString(pool, property));
 
 717         NSLog(@"delete:%@", name);
 
 724 static JSObjectRef Instance_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
 
 726         id data(reinterpret_cast<jocData>(JSObjectGetPrivate(object)));
 
 727         return CYMakeInstance(context, [data alloc]);
 
 736     void *operator new(size_t size) {
 
 738         apr_pool_create(&pool, NULL);
 
 739         void *data(apr_palloc(pool, size));
 
 740         reinterpret_cast<ptrData *>(data)->pool_ = pool;
 
 744     ptrData(void *value) :
 
 750 struct ffiData : ptrData {
 
 751     sig::Signature signature_;
 
 754     ffiData(const char *type, void (*value)() = NULL) :
 
 755         ptrData(reinterpret_cast<void *>(value))
 
 757         sig::Parse(pool_, &signature_, type);
 
 758         sig::sig_ffi_cif(pool_, &sig::ObjectiveC, &signature_, &cif_);
 
 762 struct selData : ptrData {
 
 768     SEL GetValue() const {
 
 769         return reinterpret_cast<SEL>(value_);
 
 773 JSObjectRef CYMakeSelector(JSContextRef context, SEL sel) {
 
 774     selData *data(new selData(sel));
 
 775     return JSObjectMake(context, Selector_, data);
 
 778 JSObjectRef CYMakePointer(JSContextRef context, void *pointer) {
 
 779     ptrData *data(new ptrData(pointer));
 
 780     return JSObjectMake(context, Pointer_, data);
 
 783 static void Pointer_finalize(JSObjectRef object) {
 
 784     ptrData *data(reinterpret_cast<ptrData *>(JSObjectGetPrivate(object)));
 
 785     apr_pool_destroy(data->pool_);
 
 788 /*static void Instance_finalize(JSObjectRef object) {
 
 789     id data(reinterpret_cast<jocData>(JSObjectGetPrivate(object)));
 
 792 JSObjectRef CYMakeFunctor(JSContextRef context, void (*function)(), const char *type) {
 
 793     ffiData *data(new ffiData(type, function));
 
 794     return JSObjectMake(context, Functor_, data);
 
 797 void Closure_(ffi_cif *cif, void *result, void **arguments, void *arg) {
 
 800 JSObjectRef CYMakeFunctor(JSContextRef context, JSObjectRef function, const char *type) {
 
 801     // XXX: in case of exceptions this will leak
 
 802     ffiData *data(new ffiData(type));
 
 804     ffi_closure *closure;
 
 805     _syscall(closure = (ffi_closure *) mmap(
 
 806         NULL, sizeof(ffi_closure),
 
 807         PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
 
 811     ffi_status status(ffi_prep_closure(closure, &data->cif_, &Closure_, data));
 
 812     _assert(status == FFI_OK);
 
 814     _syscall(mprotect(closure, sizeof(*closure), PROT_READ | PROT_EXEC));
 
 816     return JSObjectMake(context, Functor_, data);
 
 819 char *CYPoolCString(apr_pool_t *pool, JSStringRef value) {
 
 820     size_t size(JSStringGetMaximumUTF8CStringSize(value));
 
 821     char *string(new(pool) char[size]);
 
 822     JSStringGetUTF8CString(value, string, size);
 
 826 char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
 
 827     if (JSValueIsNull(context, value))
 
 829     return CYPoolCString(pool, CYJSString(context, value));
 
 832 // XXX: this macro is unhygenic
 
 833 #define CYCastCString(context, value) ({ \
 
 838         JSStringRef string(CYCopyJSString(context, value)); \
 
 839         size_t size(JSStringGetMaximumUTF8CStringSize(string)); \
 
 840         utf8 = reinterpret_cast<char *>(alloca(size)); \
 
 841         JSStringGetUTF8CString(string, utf8, size); \
 
 842         JSStringRelease(string); \
 
 847 SEL CYCastSEL(JSContextRef context, JSValueRef value) {
 
 848     if (JSValueIsNull(context, value))
 
 850     else if (JSValueIsObjectOfClass(context, value, Selector_)) {
 
 851         selData *data(reinterpret_cast<selData *>(JSObjectGetPrivate((JSObjectRef) value)));
 
 852         return reinterpret_cast<SEL>(data->value_);
 
 854         return sel_registerName(CYCastCString(context, value));
 
 857 void *CYCastPointer_(JSContextRef context, JSValueRef value) {
 
 858     switch (JSValueGetType(context, value)) {
 
 862             return dlsym(RTLD_DEFAULT, CYCastCString(context, value));
 
 864             if (JSValueIsObjectOfClass(context, value, Pointer_)) {
 
 865                 ptrData *data(reinterpret_cast<ptrData *>(JSObjectGetPrivate((JSObjectRef) value)));
 
 869             return reinterpret_cast<void *>(static_cast<uintptr_t>(CYCastDouble(context, value)));
 
 873 template <typename Type_>
 
 874 _finline Type_ CYCastPointer(JSContextRef context, JSValueRef value) {
 
 875     return reinterpret_cast<Type_>(CYCastPointer_(context, value));
 
 878 void CYPoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, void *data, JSValueRef value) {
 
 879     switch (type->primitive) {
 
 881             *reinterpret_cast<bool *>(data) = JSValueToBoolean(context, value);
 
 884 #define CYPoolFFI_(primitive, native) \
 
 885         case sig::primitive ## _P: \
 
 886             *reinterpret_cast<native *>(data) = CYCastDouble(context, value); \
 
 889         CYPoolFFI_(uchar, unsigned char)
 
 890         CYPoolFFI_(char, char)
 
 891         CYPoolFFI_(ushort, unsigned short)
 
 892         CYPoolFFI_(short, short)
 
 893         CYPoolFFI_(ulong, unsigned long)
 
 894         CYPoolFFI_(long, long)
 
 895         CYPoolFFI_(uint, unsigned int)
 
 897         CYPoolFFI_(ulonglong, unsigned long long)
 
 898         CYPoolFFI_(longlong, long long)
 
 899         CYPoolFFI_(float, float)
 
 900         CYPoolFFI_(double, double)
 
 903         case sig::typename_P:
 
 904             *reinterpret_cast<id *>(data) = CYCastNSObject(pool, context, value);
 
 907         case sig::selector_P:
 
 908             *reinterpret_cast<SEL *>(data) = CYCastSEL(context, value);
 
 912             *reinterpret_cast<void **>(data) = CYCastPointer<void *>(context, value);
 
 916             *reinterpret_cast<char **>(data) = CYPoolCString(pool, context, value);
 
 926             NSLog(@"CYPoolFFI(%c)\n", type->primitive);
 
 931 JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, void *data) {
 
 934     switch (type->primitive) {
 
 936             value = CYCastJSValue(context, *reinterpret_cast<bool *>(data));
 
 939 #define CYFromFFI_(primitive, native) \
 
 940         case sig::primitive ## _P: \
 
 941             value = CYCastJSValue(context, *reinterpret_cast<native *>(data)); \
 
 944         CYFromFFI_(uchar, unsigned char)
 
 945         CYFromFFI_(char, char)
 
 946         CYFromFFI_(ushort, unsigned short)
 
 947         CYFromFFI_(short, short)
 
 948         CYFromFFI_(ulong, unsigned long)
 
 949         CYFromFFI_(long, long)
 
 950         CYFromFFI_(uint, unsigned int)
 
 952         CYFromFFI_(ulonglong, unsigned long long)
 
 953         CYFromFFI_(longlong, long long)
 
 954         CYFromFFI_(float, float)
 
 955         CYFromFFI_(double, double)
 
 958             value = CYCastJSValue(context, *reinterpret_cast<id *>(data));
 
 961         case sig::typename_P:
 
 962             value = CYMakeInstance(context, *reinterpret_cast<Class *>(data));
 
 965         case sig::selector_P:
 
 966             if (SEL sel = *reinterpret_cast<SEL *>(data))
 
 967                 value = CYMakeSelector(context, sel);
 
 972             if (void *pointer = *reinterpret_cast<void **>(data))
 
 973                 value = CYMakePointer(context, pointer);
 
 978             if (char *utf8 = *reinterpret_cast<char **>(data))
 
 979                 value = CYCastJSValue(context, utf8);
 
 987             value = CYJSUndefined(context);
 
 991             value = CYJSNull(context);
 
 995             NSLog(@"CYFromFFI(%c)\n", type->primitive);
 
1002 static JSValueRef CYCallFunction(JSContextRef context, size_t count, const JSValueRef *arguments, JSValueRef *exception, sig::Signature *signature, ffi_cif *cif, void (*function)()) {
 
1004         if (count != signature->count - 1)
 
1005             @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to ffi function" userInfo:nil];
 
1008         void *values[count];
 
1010         for (unsigned index(0); index != count; ++index) {
 
1011             sig::Element *element(&signature->elements[index + 1]);
 
1013             values[index] = new(pool) uint8_t[cif->arg_types[index]->size];
 
1014             CYPoolFFI(pool, context, element->type, values[index], arguments[index]);
 
1017         uint8_t value[cif->rtype->size];
 
1018         ffi_call(cif, function, value, values);
 
1020         return CYFromFFI(context, signature->elements[0].type, value);
 
1024 static JSValueRef Global_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
 
1027         NSString *name(CYCastNSString(pool, property));
 
1028         if (Class _class = NSClassFromString(name))
 
1029             return CYMakeInstance(context, _class);
 
1030         if (NSMutableArray *entry = [Bridge_ objectForKey:name])
 
1031             switch ([[entry objectAtIndex:0] intValue]) {
 
1033                     return JSEvaluateScript(CYGetJSContext(), CYJSString([entry objectAtIndex:1]), NULL, NULL, 0, NULL);
 
1035                     return CYMakeFunctor(context, reinterpret_cast<void (*)()>([name cy$symbol]), [[entry objectAtIndex:1] UTF8String]);
 
1038                     sig::Signature signature;
 
1039                     sig::Parse(pool, &signature, [[entry objectAtIndex:1] UTF8String]);
 
1040                     return CYFromFFI(context, signature.elements[0].type, [name cy$symbol]);
 
1046 bool stret(ffi_type *ffi_type) {
 
1047     return ffi_type->type == FFI_TYPE_STRUCT && (
 
1048         ffi_type->size > OBJC_MAX_STRUCT_BY_VALUE ||
 
1049         struct_forward_array[ffi_type->size] != 0
 
1054     int *_NSGetArgc(void);
 
1055     char ***_NSGetArgv(void);
 
1056     int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);
 
1059 static JSValueRef System_print(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
 
1061         NSLog(@"%s", CYCastCString(context, arguments[0]));
 
1062         return CYJSUndefined(context);
 
1066 static JSValueRef CYApplicationMain(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
 
1069         NSString *name(CYCastNSObject(pool, context, arguments[0]));
 
1070         int argc(*_NSGetArgc() - 1);
 
1071         char **argv(*_NSGetArgv() + 1);
 
1072         for (int i(0); i != argc; ++i)
 
1073             NSLog(@"argv[%i]=%s", i, argv[i]);
 
1074         return CYCastJSValue(context, UIApplicationMain(argc, argv, name, name));
 
1078 static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
 
1083             @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"too few arguments to objc_msgSend" userInfo:nil];
 
1087         id self(CYCastNSObject(pool, context, arguments[0]));
 
1089             return CYJSNull(context);
 
1091         SEL _cmd(CYCastSEL(context, arguments[1]));
 
1092         NSMethodSignature *method([self methodSignatureForSelector:_cmd]);
 
1094             @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"unrecognized selector %s sent to object %p", sel_getName(_cmd), self] userInfo:nil];
 
1096         type = [[method _typeString] UTF8String];
 
1101     sig::Signature signature;
 
1102     sig::Parse(pool, &signature, type);
 
1105     sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif);
 
1107     void (*function)() = stret(cif.rtype) ? reinterpret_cast<void (*)()>(&objc_msgSend_stret) : reinterpret_cast<void (*)()>(&objc_msgSend);
 
1108     return CYCallFunction(context, count, arguments, exception, &signature, &cif, function);
 
1111 static JSValueRef Selector_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
 
1112     JSValueRef setup[count + 2];
 
1115     memmove(setup + 2, arguments, sizeof(JSValueRef) * count);
 
1116     return $objc_msgSend(context, NULL, NULL, count + 2, setup, exception);
 
1119 static JSValueRef Functor_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
 
1120     ffiData *data(reinterpret_cast<ffiData *>(JSObjectGetPrivate(object)));
 
1121     return CYCallFunction(context, count, arguments, exception, &data->signature_, &data->cif_, reinterpret_cast<void (*)()>(data->value_));
 
1124 JSObjectRef Selector_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
 
1127             @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to Selector constructor" userInfo:nil];
 
1128         const char *name(CYCastCString(context, arguments[0]));
 
1129         return CYMakeSelector(context, sel_registerName(name));
 
1133 JSObjectRef Functor_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
 
1136             @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to Functor constructor" userInfo:nil];
 
1137         const char *type(CYCastCString(context, arguments[1]));
 
1138         JSValueRef exception(NULL);
 
1139         if (JSValueIsInstanceOfConstructor(context, arguments[0], Function_, &exception)) {
 
1140             JSObjectRef function(CYCastJSObject(context, arguments[0]));
 
1141             return CYMakeFunctor(context, function, type);
 
1142         } else if (exception != NULL) {
 
1145             void (*function)()(CYCastPointer<void (*)()>(context, arguments[0]));
 
1146             return CYMakeFunctor(context, function, type);
 
1151 JSValueRef Pointer_getProperty_value(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
 
1152     ptrData *data(reinterpret_cast<ptrData *>(JSObjectGetPrivate(object)));
 
1153     return CYCastJSValue(context, reinterpret_cast<uintptr_t>(data->value_));
 
1156 JSValueRef Selector_getProperty_prototype(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
 
1160 static JSValueRef Selector_callAsFunction_type(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
 
1163             @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to Selector.type" userInfo:nil];
 
1165         selData *data(reinterpret_cast<selData *>(JSObjectGetPrivate(_this)));
 
1166         Class _class(CYCastNSObject(pool, context, arguments[0]));
 
1167         bool instance(CYCastBool(context, arguments[1]));
 
1168         SEL sel(data->GetValue());
 
1169         if (Method method = (*(instance ? &class_getInstanceMethod : class_getClassMethod))(_class, sel))
 
1170             return CYCastJSValue(context, method_getTypeEncoding(method));
 
1171         else if (NSString *type = [Bridge_ objectForKey:[NSString stringWithFormat:@":%s", sel_getName(sel)]])
 
1172             return CYCastJSValue(context, CYJSString(type));
 
1174             return CYJSNull(context);
 
1178 static JSStaticValue Pointer_staticValues[2] = {
 
1179     {"value", &Pointer_getProperty_value, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete},
 
1180     {NULL, NULL, NULL, 0}
 
1183 /*static JSStaticValue Selector_staticValues[2] = {
 
1184     {"prototype", &Selector_getProperty_prototype, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete},
 
1185     {NULL, NULL, NULL, 0}
 
1188 static JSStaticFunction Selector_staticFunctions[2] = {
 
1189     {"type", &Selector_callAsFunction_type, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
 
1193 CYDriver::CYDriver(const std::string &filename) :
 
1197     filename_(filename),
 
1203 CYDriver::~CYDriver() {
 
1207 void cy::parser::error(const cy::parser::location_type &location, const std::string &message) {
 
1208     CYDriver::Error error;
 
1209     error.location_ = location;
 
1210     error.message_ = message;
 
1211     driver.errors_.push_back(error);
 
1214 void CYSetArgs(int argc, const char *argv[]) {
 
1215     JSContextRef context(CYGetJSContext());
 
1216     JSValueRef args[argc];
 
1217     for (int i(0); i != argc; ++i)
 
1218         args[i] = CYCastJSValue(context, argv[i]);
 
1219     JSValueRef exception(NULL);
 
1220     JSObjectRef array(JSObjectMakeArray(context, argc, args, &exception));
 
1221     CYThrow(context, exception);
 
1222     CYSetProperty(context, System_, CYJSString("args"), array);
 
1225 MSInitialize { _pooled
 
1228     NSCFBoolean_ = objc_getClass("NSCFBoolean");
 
1230     pid_t pid(getpid());
 
1232     struct sockaddr_in address;
 
1233     address.sin_len = sizeof(address);
 
1234     address.sin_family = AF_INET;
 
1235     address.sin_addr.s_addr = INADDR_ANY;
 
1236     address.sin_port = htons(10000 + pid);
 
1238     CFDataRef data(CFDataCreate(kCFAllocatorDefault, reinterpret_cast<UInt8 *>(&address), sizeof(address)));
 
1240     CFSocketSignature signature;
 
1241     signature.protocolFamily = AF_INET;
 
1242     signature.socketType = SOCK_STREAM;
 
1243     signature.protocol = IPPROTO_TCP;
 
1244     signature.address = data;
 
1246     CFSocketRef socket(CFSocketCreateWithSocketSignature(kCFAllocatorDefault, &signature, kCFSocketAcceptCallBack, &OnAccept, NULL));
 
1247     CFRunLoopAddSource(CFRunLoopGetCurrent(), CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0), kCFRunLoopDefaultMode);
 
1249     JSClassDefinition definition;
 
1251     definition = kJSClassDefinitionEmpty;
 
1252     definition.className = "Pointer";
 
1253     definition.staticValues = Pointer_staticValues;
 
1254     definition.finalize = &Pointer_finalize;
 
1255     Pointer_ = JSClassCreate(&definition);
 
1257     definition = kJSClassDefinitionEmpty;
 
1258     definition.className = "Functor";
 
1259     definition.parentClass = Pointer_;
 
1260     definition.callAsFunction = &Functor_callAsFunction;
 
1261     Functor_ = JSClassCreate(&definition);
 
1263     definition = kJSClassDefinitionEmpty;
 
1264     definition.className = "Selector";
 
1265     definition.parentClass = Pointer_;
 
1266     //definition.staticValues = Selector_staticValues;
 
1267     definition.staticFunctions = Selector_staticFunctions;
 
1268     definition.callAsFunction = &Selector_callAsFunction;
 
1269     Selector_ = JSClassCreate(&definition);
 
1271     definition = kJSClassDefinitionEmpty;
 
1272     definition.className = "Instance";
 
1273     definition.getProperty = &Instance_getProperty;
 
1274     definition.setProperty = &Instance_setProperty;
 
1275     definition.deleteProperty = &Instance_deleteProperty;
 
1276     definition.callAsConstructor = &Instance_callAsConstructor;
 
1277     //definition.finalize = &Instance_finalize;
 
1278     Instance_ = JSClassCreate(&definition);
 
1280     definition = kJSClassDefinitionEmpty;
 
1281     definition.getProperty = &Global_getProperty;
 
1282     JSClassRef Global(JSClassCreate(&definition));
 
1284     JSContextRef context(JSGlobalContextCreate(Global));
 
1287     JSObjectRef global(JSContextGetGlobalObject(context));
 
1289     CYSetProperty(context, global, CYJSString("Selector"), JSObjectMakeConstructor(context, Selector_, &Selector_new));
 
1290     CYSetProperty(context, global, CYJSString("Functor"), JSObjectMakeConstructor(context, Functor_, &Functor_new));
 
1292     CYSetProperty(context, global, CYJSString("CYApplicationMain"), JSObjectMakeFunctionWithCallback(context, CYJSString("CYApplicationMain"), &CYApplicationMain));
 
1293     CYSetProperty(context, global, CYJSString("objc_msgSend"), JSObjectMakeFunctionWithCallback(context, CYJSString("objc_msgSend"), &$objc_msgSend));
 
1295     System_ = JSObjectMake(context, NULL, NULL);
 
1296     CYSetProperty(context, global, CYJSString("system"), System_);
 
1297     CYSetProperty(context, System_, CYJSString("args"), CYJSNull(context));
 
1298     CYSetProperty(context, System_, CYJSString("global"), global);
 
1300     CYSetProperty(context, System_, CYJSString("print"), JSObjectMakeFunctionWithCallback(context, CYJSString("print"), &System_print));
 
1302     Bridge_ = [[NSMutableDictionary dictionaryWithContentsOfFile:@"/usr/lib/libcycript.plist"] retain];
 
1304     name_ = JSStringCreateWithUTF8CString("name");
 
1305     message_ = JSStringCreateWithUTF8CString("message");
 
1306     length_ = JSStringCreateWithUTF8CString("length");
 
1308     Array_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Array")));
 
1309     Function_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Function")));