]> git.saurik.com Git - cycript.git/blame - Library.mm
Drastic improvements to memory management, handle many more minimization corner cases...
[cycript.git] / Library.mm
CommitLineData
62ca2b82 1/* Cyrker - Remove Execution Server and Disassembler
c1582939
JF
2 * Copyright (C) 2009 Jay Freeman (saurik)
3*/
4
62ca2b82 5/* Modified BSD License {{{ */
c1582939
JF
6/*
7 * Redistribution and use in source and binary
8 * forms, with or without modification, are permitted
9 * provided that the following conditions are met:
10 *
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
18 * distribution.
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.
22 *
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.
37*/
62ca2b82 38/* }}} */
c1582939 39
8d9b5eed
JF
40#define _GNU_SOURCE
41
c1582939 42#include <substrate.h>
30ddc20c 43#include "cycript.hpp"
c1582939 44
ea2d184c
JF
45#include "sig/parse.hpp"
46#include "sig/ffi_type.hpp"
47
5999c315 48#include "Pooling.hpp"
057f943f 49#include "Struct.hpp"
ea2d184c 50
c1582939
JF
51#include <unistd.h>
52
53#include <CoreFoundation/CoreFoundation.h>
54#include <CoreFoundation/CFLogUtilities.h>
55
56#include <CFNetwork/CFNetwork.h>
c1582939
JF
57
58#include <WebKit/WebScriptObject.h>
59
60#include <sys/types.h>
61#include <sys/socket.h>
62#include <netinet/in.h>
b09da87b 63#include <sys/mman.h>
c1582939 64
8d9b5eed
JF
65#include <iostream>
66#include <ext/stdio_filebuf.h>
a2d9403c
JF
67#include <set>
68#include <map>
8d9b5eed 69
e5332278 70#include "Parser.hpp"
63b4c5a8 71#include "Cycript.tab.hh"
e5332278 72
ea2d184c
JF
73#undef _assert
74#undef _trace
75
c1582939 76#define _assert(test) do { \
f5e9be24
JF
77 if (!(test)) \
78 @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"_assert(%s):%s(%u):%s", #test, __FILE__, __LINE__, __FUNCTION__] userInfo:nil]; \
c1582939
JF
79} while (false)
80
81#define _trace() do { \
62ca2b82 82 CFLog(kCFLogLevelNotice, CFSTR("_trace():%u"), __LINE__); \
c1582939
JF
83} while (false)
84
ea2d184c 85static JSContextRef Context_;
b09da87b 86static JSObjectRef System_;
ea2d184c 87
88c977fa
JF
88static JSClassRef Functor_;
89static JSClassRef Instance_;
90static JSClassRef Pointer_;
91static JSClassRef Selector_;
ea2d184c 92
c1582939 93static JSObjectRef Array_;
dea834b0 94static JSObjectRef Function_;
ea2d184c 95
62ca2b82
JF
96static JSStringRef name_;
97static JSStringRef message_;
c1582939 98static JSStringRef length_;
ea2d184c 99
c1582939
JF
100static Class NSCFBoolean_;
101
88c977fa
JF
102static NSMutableDictionary *Bridge_;
103
c1582939
JF
104struct Client {
105 CFHTTPMessageRef message_;
106 CFSocketRef socket_;
107};
108
b09da87b
JF
109JSObjectRef CYMakeInstance(JSContextRef context, id object) {
110 return JSObjectMake(context, Instance_, object);
111}
112
113JSValueRef CYCastJSValue(JSContextRef context, bool value) {
114 return JSValueMakeBoolean(context, value);
115}
116
117JSValueRef CYCastJSValue(JSContextRef context, double value) {
118 return JSValueMakeNumber(context, value);
119}
120
121#define CYCastJSValue_(Type_) \
122 JSValueRef CYCastJSValue(JSContextRef context, Type_ value) { \
123 return JSValueMakeNumber(context, static_cast<double>(value)); \
124 }
125
126CYCastJSValue_(int)
127CYCastJSValue_(unsigned int)
128CYCastJSValue_(long int)
129CYCastJSValue_(long unsigned int)
130CYCastJSValue_(long long int)
131CYCastJSValue_(long long unsigned int)
132
133JSValueRef CYJSUndefined(JSContextRef context) {
134 return JSValueMakeUndefined(context);
0c862573
JF
135}
136
107e3ed0 137@interface NSMethodSignature (Cycript)
7ba62cfd
JF
138- (NSString *) _typeString;
139@end
140
107e3ed0 141@interface NSObject (Cycript)
6b8a9500 142- (bool) cy$isUndefined;
c1582939 143- (NSString *) cy$toJSON;
ea2d184c 144- (JSValueRef) cy$JSValueInContext:(JSContextRef)context;
c1582939
JF
145@end
146
107e3ed0 147@interface NSString (Cycript)
88c977fa
JF
148- (void *) cy$symbol;
149@end
150
107e3ed0 151@interface NSNumber (Cycript)
88c977fa
JF
152- (void *) cy$symbol;
153@end
154
107e3ed0 155@implementation NSObject (Cycript)
62ca2b82 156
6b8a9500
JF
157- (bool) cy$isUndefined {
158 return false;
159}
160
c1582939 161- (NSString *) cy$toJSON {
62ca2b82
JF
162 return [self description];
163}
164
ea2d184c 165- (JSValueRef) cy$JSValueInContext:(JSContextRef)context {
b09da87b 166 return CYMakeInstance(context, self);
ea2d184c
JF
167}
168
62ca2b82 169@end
c1582939 170
107e3ed0 171@implementation WebUndefined (Cycript)
62ca2b82 172
6b8a9500
JF
173- (bool) cy$isUndefined {
174 return true;
175}
176
c1582939
JF
177- (NSString *) cy$toJSON {
178 return @"undefined";
62ca2b82
JF
179}
180
181- (JSValueRef) cy$JSValueInContext:(JSContextRef)context {
b09da87b 182 return CYJSUndefined(context);
62ca2b82
JF
183}
184
185@end
c1582939 186
107e3ed0 187@implementation NSArray (Cycript)
62ca2b82 188
c1582939
JF
189- (NSString *) cy$toJSON {
190 NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
191 [json appendString:@"["];
192
193 bool comma(false);
62ca2b82 194 for (id object in self) {
c1582939
JF
195 if (comma)
196 [json appendString:@","];
197 else
198 comma = true;
6b8a9500
JF
199 if (![object cy$isUndefined])
200 [json appendString:[object cy$toJSON]];
201 else {
202 [json appendString:@","];
203 comma = false;
204 }
c1582939
JF
205 }
206
207 [json appendString:@"]"];
208 return json;
62ca2b82
JF
209}
210
211@end
212
107e3ed0 213@implementation NSDictionary (Cycript)
62ca2b82
JF
214
215- (NSString *) cy$toJSON {
216 NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
d35a3b07 217 [json appendString:@"({"];
62ca2b82
JF
218
219 bool comma(false);
220 for (id key in self) {
221 if (comma)
222 [json appendString:@","];
223 else
224 comma = true;
225 [json appendString:[key cy$toJSON]];
226 [json appendString:@":"];
227 NSObject *object([self objectForKey:key]);
228 [json appendString:[object cy$toJSON]];
229 }
230
231 [json appendString:@"})"];
232 return json;
233}
234
235@end
c1582939 236
107e3ed0 237@implementation NSNumber (Cycript)
62ca2b82 238
c1582939
JF
239- (NSString *) cy$toJSON {
240 return [self class] != NSCFBoolean_ ? [self stringValue] : [self boolValue] ? @"true" : @"false";
62ca2b82
JF
241}
242
243- (JSValueRef) cy$JSValueInContext:(JSContextRef)context {
b09da87b 244 return [self class] != NSCFBoolean_ ? CYCastJSValue(context, [self doubleValue]) : CYCastJSValue(context, [self boolValue]);
62ca2b82
JF
245}
246
88c977fa
JF
247- (void *) cy$symbol {
248 return [self pointerValue];
249}
250
62ca2b82 251@end
c1582939 252
107e3ed0 253@implementation NSString (Cycript)
62ca2b82 254
c1582939
JF
255- (NSString *) cy$toJSON {
256 CFMutableStringRef json(CFStringCreateMutableCopy(kCFAllocatorDefault, 0, (CFStringRef) self));
257
c1582939
JF
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);
263
264 CFStringInsert(json, 0, CFSTR("\""));
265 CFStringAppend(json, CFSTR("\""));
266
62ca2b82
JF
267 return [reinterpret_cast<const NSString *>(json) autorelease];
268}
269
88c977fa
JF
270- (void *) cy$symbol {
271 return dlsym(RTLD_DEFAULT, [self UTF8String]);
272}
273
62ca2b82
JF
274@end
275
b21525c7 276@interface CYJSObject : NSDictionary {
62ca2b82
JF
277 JSObjectRef object_;
278 JSContextRef context_;
279}
280
281- (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context;
282
283- (NSUInteger) count;
284- (id) objectForKey:(id)key;
285- (NSEnumerator *) keyEnumerator;
286- (void) setObject:(id)object forKey:(id)key;
287- (void) removeObjectForKey:(id)key;
288
289@end
c1582939 290
b21525c7 291@interface CYJSArray : NSArray {
c1582939
JF
292 JSObjectRef object_;
293 JSContextRef context_;
294}
295
296- (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context;
297
298- (NSUInteger) count;
299- (id) objectAtIndex:(NSUInteger)index;
300
301@end
302
dea834b0
JF
303CYRange WordStartRange_(0x1000000000LLU,0x7fffffe87fffffeLLU); // A-Za-z_$
304CYRange WordEndRange_(0x3ff001000000000LLU,0x7fffffe87fffffeLLU); // A-Za-z_$0-9
305
30ddc20c 306JSContextRef CYGetJSContext() {
ea2d184c 307 return Context_;
62ca2b82
JF
308}
309
0c862573
JF
310#define CYCatch \
311 @catch (id error) { \
b09da87b 312 NSLog(@"e:%@", error); \
0c862573
JF
313 CYThrow(context, error, exception); \
314 return NULL; \
315 }
316
ea2d184c
JF
317void CYThrow(JSContextRef context, JSValueRef value);
318
b09da87b
JF
319apr_status_t CYPoolRelease_(void *data) {
320 id object(reinterpret_cast<id>(data));
321 [object release];
322 return APR_SUCCESS;
323}
324
325id CYPoolRelease(apr_pool_t *pool, id object) {
326 if (pool == NULL)
327 return [object autorelease];
328 else {
329 apr_pool_cleanup_register(pool, object, &CYPoolRelease_, &apr_pool_cleanup_null);
330 return object;
331 }
332}
333
334id CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSObjectRef object) {
88c977fa 335 if (JSValueIsObjectOfClass(context, object, Instance_))
c1582939 336 return reinterpret_cast<id>(JSObjectGetPrivate(object));
ea2d184c
JF
337 JSValueRef exception(NULL);
338 bool array(JSValueIsInstanceOfConstructor(context, object, Array_, &exception));
339 CYThrow(context, exception);
b09da87b
JF
340 id value(array ? [CYJSArray alloc] : [CYJSObject alloc]);
341 return CYPoolRelease(pool, [value initWithJSObject:object inContext:context]);
62ca2b82
JF
342}
343
77e87a6c 344JSStringRef CYCopyJSString(id value) {
b09da87b 345 return value == NULL ? NULL : JSStringCreateWithCFString(reinterpret_cast<CFStringRef>([value description]));
62ca2b82
JF
346}
347
77e87a6c 348JSStringRef CYCopyJSString(const char *value) {
b09da87b 349 return value == NULL ? NULL : JSStringCreateWithUTF8CString(value);
77e87a6c
JF
350}
351
352JSStringRef CYCopyJSString(JSStringRef value) {
b09da87b 353 return value == NULL ? NULL : JSStringRetain(value);
77e87a6c
JF
354}
355
356JSStringRef CYCopyJSString(JSContextRef context, JSValueRef value) {
b09da87b
JF
357 if (JSValueIsNull(context, value))
358 return NULL;
62ca2b82 359 JSValueRef exception(NULL);
ea2d184c
JF
360 JSStringRef string(JSValueToStringCopy(context, value, &exception));
361 CYThrow(context, exception);
77e87a6c
JF
362 return string;
363}
364
cf7d4c69 365class CYJSString {
77e87a6c
JF
366 private:
367 JSStringRef string_;
368
b09da87b
JF
369 void Clear_() {
370 JSStringRelease(string_);
371 }
372
77e87a6c 373 public:
b09da87b
JF
374 CYJSString(const CYJSString &rhs) :
375 string_(CYCopyJSString(rhs.string_))
376 {
377 }
378
77e87a6c 379 template <typename Arg0_>
b09da87b
JF
380 CYJSString(Arg0_ arg0) :
381 string_(CYCopyJSString(arg0))
382 {
77e87a6c
JF
383 }
384
385 template <typename Arg0_, typename Arg1_>
b09da87b
JF
386 CYJSString(Arg0_ arg0, Arg1_ arg1) :
387 string_(CYCopyJSString(arg0, arg1))
388 {
389 }
390
391 CYJSString &operator =(const CYJSString &rhs) {
392 Clear_();
393 string_ = CYCopyJSString(rhs.string_);
394 return *this;
77e87a6c
JF
395 }
396
cf7d4c69 397 ~CYJSString() {
b09da87b
JF
398 Clear_();
399 }
400
401 void Clear() {
402 Clear_();
403 string_ = NULL;
77e87a6c
JF
404 }
405
406 operator JSStringRef() const {
407 return string_;
408 }
409};
410
411CFStringRef CYCopyCFString(JSStringRef value) {
412 return JSStringCopyCFString(kCFAllocatorDefault, value);
413}
414
415CFStringRef CYCopyCFString(JSContextRef context, JSValueRef value) {
cf7d4c69 416 return CYCopyCFString(CYJSString(context, value));
c1582939
JF
417}
418
f610e1a0 419double CYCastDouble(JSContextRef context, JSValueRef value) {
0c862573
JF
420 JSValueRef exception(NULL);
421 double number(JSValueToNumber(context, value, &exception));
422 CYThrow(context, exception);
f610e1a0
JF
423 return number;
424}
425
426CFNumberRef CYCopyCFNumber(JSContextRef context, JSValueRef value) {
427 double number(CYCastDouble(context, value));
0c862573
JF
428 return CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &number);
429}
430
b09da87b
JF
431NSString *CYCastNSString(apr_pool_t *pool, JSStringRef value) {
432 return CYPoolRelease(pool, reinterpret_cast<const NSString *>(CYCopyCFString(value)));
433}
434
435bool CYCastBool(JSContextRef context, JSValueRef value) {
436 return JSValueToBoolean(context, value);
62ca2b82
JF
437}
438
b09da87b
JF
439CFTypeRef CYCFType(apr_pool_t *pool, JSContextRef context, JSValueRef value, bool cast) {
440 CFTypeRef object;
441 bool copy;
442
f610e1a0 443 switch (JSType type = JSValueGetType(context, value)) {
c1582939 444 case kJSTypeUndefined:
b09da87b
JF
445 object = [WebUndefined undefined];
446 copy = false;
447 break;
448
c1582939 449 case kJSTypeNull:
b09da87b
JF
450 return NULL;
451 break;
452
c1582939 453 case kJSTypeBoolean:
b09da87b
JF
454 object = CYCastBool(context, value) ? kCFBooleanTrue : kCFBooleanFalse;
455 copy = false;
456 break;
457
0c862573 458 case kJSTypeNumber:
b09da87b
JF
459 object = CYCopyCFNumber(context, value);
460 copy = true;
461 break;
462
62ca2b82 463 case kJSTypeString:
b09da87b
JF
464 object = CYCopyCFString(context, value);
465 copy = true;
466 break;
467
c1582939 468 case kJSTypeObject:
b09da87b
JF
469 // XXX: this might could be more efficient
470 object = (CFTypeRef) CYCastNSObject(pool, context, (JSObjectRef) value);
471 copy = false;
472 break;
473
c1582939 474 default:
f5e9be24 475 @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"JSValueGetType() == 0x%x", type] userInfo:nil];
b09da87b 476 break;
c1582939 477 }
b09da87b
JF
478
479 if (cast != copy)
480 return object;
481 else if (copy)
482 return CYPoolRelease(pool, (id) object);
483 else
484 return CFRetain(object);
485}
486
487CFTypeRef CYCastCFType(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
488 return CYCFType(pool, context, value, true);
489}
490
491CFTypeRef CYCopyCFType(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
492 return CYCFType(pool, context, value, false);
c1582939
JF
493}
494
62ca2b82 495NSArray *CYCastNSArray(JSPropertyNameArrayRef names) {
b09da87b 496 CYPool pool;
62ca2b82
JF
497 size_t size(JSPropertyNameArrayGetCount(names));
498 NSMutableArray *array([NSMutableArray arrayWithCapacity:size]);
499 for (size_t index(0); index != size; ++index)
b09da87b 500 [array addObject:CYCastNSString(pool, JSPropertyNameArrayGetNameAtIndex(names, index))];
62ca2b82
JF
501 return array;
502}
503
b09da87b
JF
504id CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
505 return reinterpret_cast<const NSObject *>(CYCastCFType(pool, context, value));
c1582939
JF
506}
507
ea2d184c 508void CYThrow(JSContextRef context, JSValueRef value) {
62ca2b82
JF
509 if (value == NULL)
510 return;
b09da87b
JF
511 @throw CYCastNSObject(NULL, context, value);
512}
513
514JSValueRef CYJSNull(JSContextRef context) {
515 return JSValueMakeNull(context);
516}
517
518JSValueRef CYCastJSValue(JSContextRef context, JSStringRef value) {
519 return value == NULL ? CYJSNull(context) : JSValueMakeString(context, value);
520}
521
522JSValueRef CYCastJSValue(JSContextRef context, const char *value) {
523 return CYCastJSValue(context, CYJSString(value));
62ca2b82
JF
524}
525
ea2d184c 526JSValueRef CYCastJSValue(JSContextRef context, id value) {
b09da87b 527 return value == nil ? CYJSNull(context) : [value cy$JSValueInContext:context];
62ca2b82
JF
528}
529
dea834b0
JF
530JSObjectRef CYCastJSObject(JSContextRef context, JSValueRef value) {
531 JSValueRef exception(NULL);
532 JSObjectRef object(JSValueToObject(context, value, &exception));
533 CYThrow(context, exception);
534 return object;
535}
536
537JSValueRef CYGetProperty(JSContextRef context, JSObjectRef object, JSStringRef name) {
538 JSValueRef exception(NULL);
539 JSValueRef value(JSObjectGetProperty(context, object, name, &exception));
540 CYThrow(context, exception);
541 return value;
542}
543
544void 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);
548}
549
30ddc20c 550void CYThrow(JSContextRef context, id error, JSValueRef *exception) {
7ba62cfd
JF
551 *exception = CYCastJSValue(context, error);
552}
553
b21525c7 554@implementation CYJSObject
62ca2b82
JF
555
556- (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context {
557 if ((self = [super init]) != nil) {
558 object_ = object;
559 context_ = context;
560 } return self;
561}
562
563- (NSUInteger) count {
564 JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context_, object_));
565 size_t size(JSPropertyNameArrayGetCount(names));
566 JSPropertyNameArrayRelease(names);
567 return size;
568}
569
570- (id) objectForKey:(id)key {
b09da87b 571 return CYCastNSObject(NULL, context_, CYGetProperty(context_, object_, CYJSString(key)));
62ca2b82
JF
572}
573
574- (NSEnumerator *) keyEnumerator {
575 JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context_, object_));
576 NSEnumerator *enumerator([CYCastNSArray(names) objectEnumerator]);
577 JSPropertyNameArrayRelease(names);
578 return enumerator;
579}
580
581- (void) setObject:(id)object forKey:(id)key {
dea834b0 582 CYSetProperty(context_, object_, CYJSString(key), CYCastJSValue(context_, object));
62ca2b82
JF
583}
584
585- (void) removeObjectForKey:(id)key {
586 JSValueRef exception(NULL);
f610e1a0 587 // XXX: this returns a bool... throw exception, or ignore?
cf7d4c69 588 JSObjectDeleteProperty(context_, object_, CYJSString(key), &exception);
62ca2b82
JF
589 CYThrow(context_, exception);
590}
591
592@end
593
b21525c7 594@implementation CYJSArray
c1582939
JF
595
596- (id) initWithJSObject:(JSObjectRef)object inContext:(JSContextRef)context {
597 if ((self = [super init]) != nil) {
598 object_ = object;
599 context_ = context;
600 } return self;
601}
602
603- (NSUInteger) count {
dea834b0 604 return CYCastDouble(context_, CYGetProperty(context_, object_, length_));
c1582939
JF
605}
606
607- (id) objectAtIndex:(NSUInteger)index {
62ca2b82
JF
608 JSValueRef exception(NULL);
609 JSValueRef value(JSObjectGetPropertyAtIndex(context_, object_, index, &exception));
610 CYThrow(context_, exception);
b09da87b 611 id object(CYCastNSObject(NULL, context_, value));
c1582939
JF
612 return object == nil ? [NSNull null] : object;
613}
614
615@end
616
30ddc20c 617CFStringRef CYCopyJSONString(JSContextRef context, JSValueRef value) {
b09da87b 618 id object(CYCastNSObject(NULL, context, value));
62ca2b82 619 return reinterpret_cast<CFStringRef>([(object == nil ? @"null" : [object cy$toJSON]) retain]);
c1582939
JF
620}
621
622static void OnData(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *value, void *info) {
623 switch (type) {
624 case kCFSocketDataCallBack:
625 CFDataRef data(reinterpret_cast<CFDataRef>(value));
626 Client *client(reinterpret_cast<Client *>(info));
627
628 if (client->message_ == NULL)
629 client->message_ = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, TRUE);
630
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_));
635 Boolean absolute;
636 CFStringRef path(CFURLCopyStrictPath(url, &absolute));
637 CFRelease(client->message_);
638
639 CFStringRef code(CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault, path, CFSTR("")));
640 CFRelease(path);
641
642 JSStringRef script(JSStringCreateWithCFString(code));
643 CFRelease(code);
644
057f943f 645 JSValueRef result(JSEvaluateScript(CYGetJSContext(), script, NULL, NULL, 0, NULL));
c1582939
JF
646 JSStringRelease(script);
647
648 CFHTTPMessageRef response(CFHTTPMessageCreateResponse(kCFAllocatorDefault, 200, NULL, kCFHTTPVersion1_1));
649 CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Type"), CFSTR("application/json; charset=utf-8"));
650
057f943f 651 CFStringRef json(CYCopyJSONString(CYGetJSContext(), result));
c1582939
JF
652 CFDataRef body(CFStringCreateExternalRepresentation(kCFAllocatorDefault, json, kCFStringEncodingUTF8, NULL));
653 CFRelease(json);
654
655 CFStringRef length(CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), CFDataGetLength(body)));
656 CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Length"), length);
657 CFRelease(length);
658
659 CFHTTPMessageSetBody(response, body);
660 CFRelease(body);
661
662 CFDataRef serialized(CFHTTPMessageCopySerializedMessage(response));
663 CFRelease(response);
664
665 CFSocketSendData(socket, NULL, serialized, 0);
666 CFRelease(serialized);
667
668 CFRelease(url);
669 }
670 break;
671 }
672}
673
674static void OnAccept(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *value, void *info) {
675 switch (type) {
676 case kCFSocketAcceptCallBack:
677 Client *client(new Client());
678
679 client->message_ = NULL;
680
681 CFSocketContext context;
682 context.version = 0;
683 context.info = client;
684 context.retain = NULL;
685 context.release = NULL;
686 context.copyDescription = NULL;
687
688 client->socket_ = CFSocketCreateWithNative(kCFAllocatorDefault, *reinterpret_cast<const CFSocketNativeHandle *>(value), kCFSocketDataCallBack, &OnData, &context);
689
690 CFRunLoopAddSource(CFRunLoopGetCurrent(), CFSocketCreateRunLoopSource(kCFAllocatorDefault, client->socket_, 0), kCFRunLoopDefaultMode);
691 break;
692 }
693}
694
b09da87b 695static JSValueRef Instance_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
f610e1a0 696 @try {
b09da87b
JF
697 CYPool pool;
698 NSString *name(CYCastNSString(pool, property));
699 NSLog(@"get:%@", name);
f610e1a0
JF
700 return NULL;
701 } CYCatch
c1582939
JF
702}
703
b09da87b
JF
704static bool Instance_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) {
705 @try {
706 CYPool pool;
707 NSString *name(CYCastNSString(pool, property));
708 NSLog(@"set:%@", name);
709 return false;
710 } CYCatch
711}
712
713static bool Instance_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
714 @try {
715 CYPool pool;
716 NSString *name(CYCastNSString(pool, property));
717 NSLog(@"delete:%@", name);
718 return false;
719 } CYCatch
720}
721
ea2d184c
JF
722typedef id jocData;
723
b09da87b 724static JSObjectRef Instance_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
0c862573
JF
725 @try {
726 id data(reinterpret_cast<jocData>(JSObjectGetPrivate(object)));
b09da87b 727 return CYMakeInstance(context, [data alloc]);
0c862573
JF
728 } CYCatch
729}
730
04450da0 731struct ptrData {
b21525c7 732 apr_pool_t *pool_;
04450da0 733 void *value_;
b21525c7 734 sig::Type type_;
77e87a6c
JF
735
736 void *operator new(size_t size) {
737 apr_pool_t *pool;
738 apr_pool_create(&pool, NULL);
739 void *data(apr_palloc(pool, size));
740 reinterpret_cast<ptrData *>(data)->pool_ = pool;
741 return data;;
742 }
743
744 ptrData(void *value) :
745 value_(value)
746 {
747 }
748};
749
750struct ffiData : ptrData {
751 sig::Signature signature_;
752 ffi_cif cif_;
753
b09da87b 754 ffiData(const char *type, void (*value)() = NULL) :
77e87a6c
JF
755 ptrData(reinterpret_cast<void *>(value))
756 {
757 sig::Parse(pool_, &signature_, type);
758 sig::sig_ffi_cif(pool_, &sig::ObjectiveC, &signature_, &cif_);
759 }
760};
761
762struct selData : ptrData {
763 selData(SEL value) :
764 ptrData(value)
765 {
766 }
b09da87b
JF
767
768 SEL GetValue() const {
769 return reinterpret_cast<SEL>(value_);
770 }
04450da0
JF
771};
772
dea834b0
JF
773JSObjectRef CYMakeSelector(JSContextRef context, SEL sel) {
774 selData *data(new selData(sel));
775 return JSObjectMake(context, Selector_, data);
776}
777
778JSObjectRef CYMakePointer(JSContextRef context, void *pointer) {
779 ptrData *data(new ptrData(pointer));
780 return JSObjectMake(context, Pointer_, data);
781}
782
88c977fa 783static void Pointer_finalize(JSObjectRef object) {
04450da0 784 ptrData *data(reinterpret_cast<ptrData *>(JSObjectGetPrivate(object)));
b21525c7 785 apr_pool_destroy(data->pool_);
04450da0
JF
786}
787
b09da87b 788/*static void Instance_finalize(JSObjectRef object) {
ea2d184c 789 id data(reinterpret_cast<jocData>(JSObjectGetPrivate(object)));
b09da87b 790}*/
ea2d184c 791
b09da87b
JF
792JSObjectRef CYMakeFunctor(JSContextRef context, void (*function)(), const char *type) {
793 ffiData *data(new ffiData(type, function));
88c977fa
JF
794 return JSObjectMake(context, Functor_, data);
795}
796
b09da87b
JF
797void Closure_(ffi_cif *cif, void *result, void **arguments, void *arg) {
798}
799
800JSObjectRef CYMakeFunctor(JSContextRef context, JSObjectRef function, const char *type) {
801 // XXX: in case of exceptions this will leak
802 ffiData *data(new ffiData(type));
803
804 ffi_closure *closure;
805 _syscall(closure = (ffi_closure *) mmap(
806 NULL, sizeof(ffi_closure),
807 PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
808 -1, 0
809 ));
810
811 ffi_status status(ffi_prep_closure(closure, &data->cif_, &Closure_, data));
812 _assert(status == FFI_OK);
813
814 _syscall(mprotect(closure, sizeof(*closure), PROT_READ | PROT_EXEC));
815
816 return JSObjectMake(context, Functor_, data);
88c977fa
JF
817}
818
7ba62cfd
JF
819char *CYPoolCString(apr_pool_t *pool, JSStringRef value) {
820 size_t size(JSStringGetMaximumUTF8CStringSize(value));
b21525c7 821 char *string(new(pool) char[size]);
7ba62cfd 822 JSStringGetUTF8CString(value, string, size);
7ba62cfd
JF
823 return string;
824}
825
77e87a6c 826char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
b09da87b
JF
827 if (JSValueIsNull(context, value))
828 return NULL;
cf7d4c69 829 return CYPoolCString(pool, CYJSString(context, value));
77e87a6c
JF
830}
831
f610e1a0 832// XXX: this macro is unhygenic
b21525c7 833#define CYCastCString(context, value) ({ \
b09da87b
JF
834 char *utf8; \
835 if (value == NULL) \
836 utf8 = NULL; \
837 else { \
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); \
843 } \
b21525c7
JF
844 utf8; \
845})
846
7ba62cfd
JF
847SEL CYCastSEL(JSContextRef context, JSValueRef value) {
848 if (JSValueIsNull(context, value))
849 return NULL;
88c977fa 850 else if (JSValueIsObjectOfClass(context, value, Selector_)) {
77e87a6c
JF
851 selData *data(reinterpret_cast<selData *>(JSObjectGetPrivate((JSObjectRef) value)));
852 return reinterpret_cast<SEL>(data->value_);
853 } else
b21525c7
JF
854 return sel_registerName(CYCastCString(context, value));
855}
856
b09da87b 857void *CYCastPointer_(JSContextRef context, JSValueRef value) {
b21525c7
JF
858 switch (JSValueGetType(context, value)) {
859 case kJSTypeNull:
860 return NULL;
b21525c7
JF
861 case kJSTypeString:
862 return dlsym(RTLD_DEFAULT, CYCastCString(context, value));
b21525c7 863 case kJSTypeObject:
88c977fa 864 if (JSValueIsObjectOfClass(context, value, Pointer_)) {
b21525c7
JF
865 ptrData *data(reinterpret_cast<ptrData *>(JSObjectGetPrivate((JSObjectRef) value)));
866 return data->value_;
867 }
868 default:
f610e1a0 869 return reinterpret_cast<void *>(static_cast<uintptr_t>(CYCastDouble(context, value)));
7ba62cfd
JF
870 }
871}
872
b09da87b
JF
873template <typename Type_>
874_finline Type_ CYCastPointer(JSContextRef context, JSValueRef value) {
875 return reinterpret_cast<Type_>(CYCastPointer_(context, value));
876}
877
43cb3d68 878void CYPoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, void *data, JSValueRef value) {
ea2d184c
JF
879 switch (type->primitive) {
880 case sig::boolean_P:
881 *reinterpret_cast<bool *>(data) = JSValueToBoolean(context, value);
882 break;
883
43cb3d68 884#define CYPoolFFI_(primitive, native) \
f610e1a0
JF
885 case sig::primitive ## _P: \
886 *reinterpret_cast<native *>(data) = CYCastDouble(context, value); \
887 break;
ea2d184c 888
43cb3d68
JF
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)
896 CYPoolFFI_(int, int)
897 CYPoolFFI_(ulonglong, unsigned long long)
898 CYPoolFFI_(longlong, long long)
899 CYPoolFFI_(float, float)
900 CYPoolFFI_(double, double)
ea2d184c
JF
901
902 case sig::object_P:
903 case sig::typename_P:
b09da87b 904 *reinterpret_cast<id *>(data) = CYCastNSObject(pool, context, value);
7ba62cfd
JF
905 break;
906
ea2d184c 907 case sig::selector_P:
7ba62cfd
JF
908 *reinterpret_cast<SEL *>(data) = CYCastSEL(context, value);
909 break;
ea2d184c 910
b21525c7 911 case sig::pointer_P:
b09da87b 912 *reinterpret_cast<void **>(data) = CYCastPointer<void *>(context, value);
b21525c7 913 break;
ea2d184c 914
77e87a6c
JF
915 case sig::string_P:
916 *reinterpret_cast<char **>(data) = CYPoolCString(pool, context, value);
917 break;
7ba62cfd 918
ea2d184c
JF
919 case sig::struct_P:
920 goto fail;
921
922 case sig::void_P:
923 break;
924
925 default: fail:
43cb3d68 926 NSLog(@"CYPoolFFI(%c)\n", type->primitive);
ea2d184c
JF
927 _assert(false);
928 }
929}
930
43cb3d68 931JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, void *data) {
ea2d184c
JF
932 JSValueRef value;
933
934 switch (type->primitive) {
935 case sig::boolean_P:
b09da87b 936 value = CYCastJSValue(context, *reinterpret_cast<bool *>(data));
ea2d184c
JF
937 break;
938
939#define CYFromFFI_(primitive, native) \
940 case sig::primitive ## _P: \
b09da87b 941 value = CYCastJSValue(context, *reinterpret_cast<native *>(data)); \
ea2d184c
JF
942 break;
943
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)
951 CYFromFFI_(int, int)
952 CYFromFFI_(ulonglong, unsigned long long)
953 CYFromFFI_(longlong, long long)
954 CYFromFFI_(float, float)
955 CYFromFFI_(double, double)
956
957 case sig::object_P:
ea2d184c 958 value = CYCastJSValue(context, *reinterpret_cast<id *>(data));
dea834b0
JF
959 break;
960
b09da87b
JF
961 case sig::typename_P:
962 value = CYMakeInstance(context, *reinterpret_cast<Class *>(data));
963 break;
964
dea834b0
JF
965 case sig::selector_P:
966 if (SEL sel = *reinterpret_cast<SEL *>(data))
967 value = CYMakeSelector(context, sel);
968 else goto null;
969 break;
970
971 case sig::pointer_P:
972 if (void *pointer = *reinterpret_cast<void **>(data))
973 value = CYMakePointer(context, pointer);
974 else goto null;
975 break;
976
977 case sig::string_P:
f610e1a0 978 if (char *utf8 = *reinterpret_cast<char **>(data))
b09da87b 979 value = CYCastJSValue(context, utf8);
f610e1a0 980 else goto null;
dea834b0 981 break;
ea2d184c
JF
982
983 case sig::struct_P:
984 goto fail;
985
986 case sig::void_P:
b09da87b 987 value = CYJSUndefined(context);
f610e1a0
JF
988 break;
989
990 null:
b09da87b 991 value = CYJSNull(context);
ea2d184c
JF
992 break;
993
994 default: fail:
995 NSLog(@"CYFromFFI(%c)\n", type->primitive);
996 _assert(false);
997 }
998
999 return value;
1000}
1001
b09da87b 1002static JSValueRef CYCallFunction(JSContextRef context, size_t count, const JSValueRef *arguments, JSValueRef *exception, sig::Signature *signature, ffi_cif *cif, void (*function)()) {
7ba62cfd 1003 @try {
85a33bf5 1004 if (count != signature->count - 1)
f5e9be24 1005 @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to ffi function" userInfo:nil];
85a33bf5 1006
7ba62cfd
JF
1007 CYPool pool;
1008 void *values[count];
ea2d184c 1009
7ba62cfd
JF
1010 for (unsigned index(0); index != count; ++index) {
1011 sig::Element *element(&signature->elements[index + 1]);
77e87a6c 1012 // XXX: alignment?
b21525c7 1013 values[index] = new(pool) uint8_t[cif->arg_types[index]->size];
43cb3d68 1014 CYPoolFFI(pool, context, element->type, values[index], arguments[index]);
7ba62cfd 1015 }
ea2d184c 1016
7ba62cfd
JF
1017 uint8_t value[cif->rtype->size];
1018 ffi_call(cif, function, value, values);
1019
43cb3d68 1020 return CYFromFFI(context, signature->elements[0].type, value);
0c862573 1021 } CYCatch
7ba62cfd 1022}
ea2d184c 1023
b09da87b 1024static JSValueRef Global_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
707bcb93 1025 @try {
b09da87b
JF
1026 CYPool pool;
1027 NSString *name(CYCastNSString(pool, property));
f610e1a0 1028 if (Class _class = NSClassFromString(name))
b09da87b 1029 return CYMakeInstance(context, _class);
f610e1a0 1030 if (NSMutableArray *entry = [Bridge_ objectForKey:name])
707bcb93
JF
1031 switch ([[entry objectAtIndex:0] intValue]) {
1032 case 0:
057f943f 1033 return JSEvaluateScript(CYGetJSContext(), CYJSString([entry objectAtIndex:1]), NULL, NULL, 0, NULL);
707bcb93 1034 case 1:
b09da87b 1035 return CYMakeFunctor(context, reinterpret_cast<void (*)()>([name cy$symbol]), [[entry objectAtIndex:1] UTF8String]);
707bcb93
JF
1036 case 2:
1037 CYPool pool;
1038 sig::Signature signature;
1039 sig::Parse(pool, &signature, [[entry objectAtIndex:1] UTF8String]);
f610e1a0 1040 return CYFromFFI(context, signature.elements[0].type, [name cy$symbol]);
707bcb93
JF
1041 }
1042 return NULL;
1043 } CYCatch
1044}
1045
04450da0
JF
1046bool 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
1050 );
1051}
1052
b09da87b
JF
1053extern "C" {
1054 int *_NSGetArgc(void);
1055 char ***_NSGetArgv(void);
1056 int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);
1057}
1058
1059static JSValueRef System_print(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
1060 @try {
1061 NSLog(@"%s", CYCastCString(context, arguments[0]));
1062 return CYJSUndefined(context);
1063 } CYCatch
1064}
1065
1066static JSValueRef CYApplicationMain(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
1067 @try {
1068 CYPool pool;
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));
1075 } CYCatch
1076}
1077
1078static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
7ba62cfd 1079 const char *type;
ea2d184c
JF
1080
1081 @try {
85a33bf5 1082 if (count < 2)
f5e9be24 1083 @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"too few arguments to objc_msgSend" userInfo:nil];
85a33bf5 1084
b09da87b
JF
1085 CYPool pool;
1086
1087 id self(CYCastNSObject(pool, context, arguments[0]));
7ba62cfd 1088 if (self == nil)
b09da87b 1089 return CYJSNull(context);
7ba62cfd 1090
85a33bf5 1091 SEL _cmd(CYCastSEL(context, arguments[1]));
7ba62cfd 1092 NSMethodSignature *method([self methodSignatureForSelector:_cmd]);
85a33bf5 1093 if (method == nil)
f5e9be24 1094 @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"unrecognized selector %s sent to object %p", sel_getName(_cmd), self] userInfo:nil];
7ba62cfd
JF
1095
1096 type = [[method _typeString] UTF8String];
0c862573 1097 } CYCatch
ea2d184c 1098
7ba62cfd
JF
1099 CYPool pool;
1100
1101 sig::Signature signature;
1102 sig::Parse(pool, &signature, type);
ea2d184c 1103
7ba62cfd 1104 ffi_cif cif;
b21525c7 1105 sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif);
7ba62cfd 1106
04450da0 1107 void (*function)() = stret(cif.rtype) ? reinterpret_cast<void (*)()>(&objc_msgSend_stret) : reinterpret_cast<void (*)()>(&objc_msgSend);
7ba62cfd
JF
1108 return CYCallFunction(context, count, arguments, exception, &signature, &cif, function);
1109}
1110
dea834b0
JF
1111static JSValueRef Selector_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
1112 JSValueRef setup[count + 2];
1113 setup[0] = _this;
1114 setup[1] = object;
1115 memmove(setup + 2, arguments, sizeof(JSValueRef) * count);
1116 return $objc_msgSend(context, NULL, NULL, count + 2, setup, exception);
1117}
1118
1119static JSValueRef Functor_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
7ba62cfd 1120 ffiData *data(reinterpret_cast<ffiData *>(JSObjectGetPrivate(object)));
77e87a6c 1121 return CYCallFunction(context, count, arguments, exception, &data->signature_, &data->cif_, reinterpret_cast<void (*)()>(data->value_));
ea2d184c
JF
1122}
1123
b09da87b 1124JSObjectRef Selector_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
dea834b0
JF
1125 @try {
1126 if (count != 1)
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));
1130 } CYCatch
1131}
1132
b09da87b 1133JSObjectRef Functor_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
b21525c7
JF
1134 @try {
1135 if (count != 2)
dea834b0 1136 @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to Functor constructor" userInfo:nil];
b21525c7 1137 const char *type(CYCastCString(context, arguments[1]));
b09da87b
JF
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) {
1143 return NULL;
1144 } else {
1145 void (*function)()(CYCastPointer<void (*)()>(context, arguments[0]));
1146 return CYMakeFunctor(context, function, type);
1147 }
0c862573 1148 } CYCatch
ea2d184c
JF
1149}
1150
f610e1a0 1151JSValueRef Pointer_getProperty_value(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
04450da0 1152 ptrData *data(reinterpret_cast<ptrData *>(JSObjectGetPrivate(object)));
b09da87b 1153 return CYCastJSValue(context, reinterpret_cast<uintptr_t>(data->value_));
04450da0
JF
1154}
1155
dea834b0
JF
1156JSValueRef Selector_getProperty_prototype(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
1157 return Function_;
1158}
1159
b09da87b
JF
1160static JSValueRef Selector_callAsFunction_type(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
1161 @try {
1162 if (count != 2)
1163 @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to Selector.type" userInfo:nil];
1164 CYPool pool;
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));
1173 else
1174 return CYJSNull(context);
1175 } CYCatch
1176}
1177
88c977fa
JF
1178static JSStaticValue Pointer_staticValues[2] = {
1179 {"value", &Pointer_getProperty_value, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete},
04450da0
JF
1180 {NULL, NULL, NULL, 0}
1181};
1182
dea834b0
JF
1183/*static JSStaticValue Selector_staticValues[2] = {
1184 {"prototype", &Selector_getProperty_prototype, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete},
1185 {NULL, NULL, NULL, 0}
1186};*/
1187
b09da87b
JF
1188static JSStaticFunction Selector_staticFunctions[2] = {
1189 {"type", &Selector_callAsFunction_type, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1190 {NULL, NULL, 0}
1191};
1192
5999c315 1193CYDriver::CYDriver(const std::string &filename) :
db5e2840 1194 state_(CYClear),
e7ed5354
JF
1195 data_(NULL),
1196 size_(0),
5999c315
JF
1197 filename_(filename),
1198 source_(NULL)
1199{
924f67b2
JF
1200 ScannerInit();
1201}
1202
5999c315 1203CYDriver::~CYDriver() {
924f67b2
JF
1204 ScannerDestroy();
1205}
1206
5befe15e
JF
1207void 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);
63b4c5a8
JF
1212}
1213
b09da87b
JF
1214void 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);
1223}
1224
7ba62cfd 1225MSInitialize { _pooled
ea2d184c
JF
1226 apr_initialize();
1227
c1582939
JF
1228 NSCFBoolean_ = objc_getClass("NSCFBoolean");
1229
1230 pid_t pid(getpid());
1231
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);
1237
1238 CFDataRef data(CFDataCreate(kCFAllocatorDefault, reinterpret_cast<UInt8 *>(&address), sizeof(address)));
1239
1240 CFSocketSignature signature;
1241 signature.protocolFamily = AF_INET;
1242 signature.socketType = SOCK_STREAM;
1243 signature.protocol = IPPROTO_TCP;
1244 signature.address = data;
1245
1246 CFSocketRef socket(CFSocketCreateWithSocketSignature(kCFAllocatorDefault, &signature, kCFSocketAcceptCallBack, &OnAccept, NULL));
1247 CFRunLoopAddSource(CFRunLoopGetCurrent(), CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0), kCFRunLoopDefaultMode);
1248
1249 JSClassDefinition definition;
1250
1251 definition = kJSClassDefinitionEmpty;
88c977fa
JF
1252 definition.className = "Pointer";
1253 definition.staticValues = Pointer_staticValues;
1254 definition.finalize = &Pointer_finalize;
1255 Pointer_ = JSClassCreate(&definition);
c1582939
JF
1256
1257 definition = kJSClassDefinitionEmpty;
88c977fa
JF
1258 definition.className = "Functor";
1259 definition.parentClass = Pointer_;
dea834b0 1260 definition.callAsFunction = &Functor_callAsFunction;
88c977fa 1261 Functor_ = JSClassCreate(&definition);
7ba62cfd 1262
77e87a6c 1263 definition = kJSClassDefinitionEmpty;
88c977fa
JF
1264 definition.className = "Selector";
1265 definition.parentClass = Pointer_;
dea834b0 1266 //definition.staticValues = Selector_staticValues;
b09da87b 1267 definition.staticFunctions = Selector_staticFunctions;
dea834b0 1268 definition.callAsFunction = &Selector_callAsFunction;
88c977fa 1269 Selector_ = JSClassCreate(&definition);
77e87a6c 1270
7ba62cfd 1271 definition = kJSClassDefinitionEmpty;
b09da87b 1272 definition.className = "Instance";
88c977fa 1273 definition.getProperty = &Instance_getProperty;
b09da87b
JF
1274 definition.setProperty = &Instance_setProperty;
1275 definition.deleteProperty = &Instance_deleteProperty;
88c977fa 1276 definition.callAsConstructor = &Instance_callAsConstructor;
b09da87b 1277 //definition.finalize = &Instance_finalize;
88c977fa 1278 Instance_ = JSClassCreate(&definition);
7ba62cfd
JF
1279
1280 definition = kJSClassDefinitionEmpty;
88c977fa
JF
1281 definition.getProperty = &Global_getProperty;
1282 JSClassRef Global(JSClassCreate(&definition));
c1582939 1283
88c977fa 1284 JSContextRef context(JSGlobalContextCreate(Global));
ea2d184c
JF
1285 Context_ = context;
1286
1287 JSObjectRef global(JSContextGetGlobalObject(context));
c1582939 1288
b09da87b
JF
1289 CYSetProperty(context, global, CYJSString("Selector"), JSObjectMakeConstructor(context, Selector_, &Selector_new));
1290 CYSetProperty(context, global, CYJSString("Functor"), JSObjectMakeConstructor(context, Functor_, &Functor_new));
7ba62cfd 1291
b09da87b 1292 CYSetProperty(context, global, CYJSString("CYApplicationMain"), JSObjectMakeFunctionWithCallback(context, CYJSString("CYApplicationMain"), &CYApplicationMain));
dea834b0 1293 CYSetProperty(context, global, CYJSString("objc_msgSend"), JSObjectMakeFunctionWithCallback(context, CYJSString("objc_msgSend"), &$objc_msgSend));
7ba62cfd 1294
b09da87b
JF
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);
1299
1300 CYSetProperty(context, System_, CYJSString("print"), JSObjectMakeFunctionWithCallback(context, CYJSString("print"), &System_print));
1301
107e3ed0 1302 Bridge_ = [[NSMutableDictionary dictionaryWithContentsOfFile:@"/usr/lib/libcycript.plist"] retain];
c1582939 1303
62ca2b82
JF
1304 name_ = JSStringCreateWithUTF8CString("name");
1305 message_ = JSStringCreateWithUTF8CString("message");
c1582939
JF
1306 length_ = JSStringCreateWithUTF8CString("length");
1307
dea834b0
JF
1308 Array_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Array")));
1309 Function_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Function")));
c1582939 1310}