X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/db5e284073ce1f951343c5825a7e4d64d159582b..135d950ba2493a5bb0464946551786c832a00df0:/Library.mm?ds=sidebyside diff --git a/Library.mm b/Library.mm index b818ad2..0dceaea 100644 --- a/Library.mm +++ b/Library.mm @@ -40,12 +40,13 @@ #define _GNU_SOURCE #include -#include "Struct.hpp" +#include "cycript.hpp" #include "sig/parse.hpp" #include "sig/ffi_type.hpp" #include "Pooling.hpp" +#include "Struct.hpp" #include @@ -53,14 +54,6 @@ #include #include -#include - -#include -#include -#include -#include -#include -#include #include @@ -72,7 +65,6 @@ #include #include #include -#include #include "Parser.hpp" #include "Cycript.tab.hh" @@ -90,8 +82,6 @@ } while (false) -#define _pooled _H _pool([[NSAutoreleasePool alloc] init], true); - static JSContextRef Context_; static JSClassRef Functor_; @@ -100,6 +90,7 @@ static JSClassRef Pointer_; static JSClassRef Selector_; static JSObjectRef Array_; +static JSObjectRef Function_; static JSStringRef name_; static JSStringRef message_; @@ -123,6 +114,7 @@ JSObjectRef CYMakeObject(JSContextRef context, id object) { @end @interface NSObject (Cycript) +- (bool) cy$isUndefined; - (NSString *) cy$toJSON; - (JSValueRef) cy$JSValueInContext:(JSContextRef)context; @end @@ -137,6 +129,10 @@ JSObjectRef CYMakeObject(JSContextRef context, id object) { @implementation NSObject (Cycript) +- (bool) cy$isUndefined { + return false; +} + - (NSString *) cy$toJSON { return [self description]; } @@ -149,6 +145,10 @@ JSObjectRef CYMakeObject(JSContextRef context, id object) { @implementation WebUndefined (Cycript) +- (bool) cy$isUndefined { + return true; +} + - (NSString *) cy$toJSON { return @"undefined"; } @@ -171,7 +171,12 @@ JSObjectRef CYMakeObject(JSContextRef context, id object) { [json appendString:@","]; else comma = true; - [json appendString:[object cy$toJSON]]; + if (![object cy$isUndefined]) + [json appendString:[object cy$toJSON]]; + else { + [json appendString:@","]; + comma = false; + } } [json appendString:@"]"]; @@ -184,8 +189,7 @@ JSObjectRef CYMakeObject(JSContextRef context, id object) { - (NSString *) cy$toJSON { NSMutableString *json([[[NSMutableString alloc] init] autorelease]); - [json appendString:@"("]; - [json appendString:@"{"]; + [json appendString:@"({"]; bool comma(false); for (id key in self) { @@ -271,7 +275,10 @@ JSObjectRef CYMakeObject(JSContextRef context, id object) { @end -JSContextRef JSGetContext() { +CYRange WordStartRange_(0x1000000000LLU,0x7fffffe87fffffeLLU); // A-Za-z_$ +CYRange WordEndRange_(0x3ff001000000000LLU,0x7fffffe87fffffeLLU); // A-Za-z_$0-9 + +JSContextRef CYGetJSContext() { return Context_; } @@ -404,6 +411,26 @@ JSValueRef CYCastJSValue(JSContextRef context, id value) { return value == nil ? JSValueMakeNull(context) : [value cy$JSValueInContext:context]; } +JSObjectRef CYCastJSObject(JSContextRef context, JSValueRef value) { + JSValueRef exception(NULL); + JSObjectRef object(JSValueToObject(context, value, &exception)); + CYThrow(context, exception); + return object; +} + +JSValueRef CYGetProperty(JSContextRef context, JSObjectRef object, JSStringRef name) { + JSValueRef exception(NULL); + JSValueRef value(JSObjectGetProperty(context, object, name, &exception)); + CYThrow(context, exception); + return value; +} + +void CYSetProperty(JSContextRef context, JSObjectRef object, JSStringRef name, JSValueRef value) { + JSValueRef exception(NULL); + JSObjectSetProperty(context, object, name, value, kJSPropertyAttributeNone, &exception); + CYThrow(context, exception); +} + void CYThrow(JSContextRef context, id error, JSValueRef *exception) { *exception = CYCastJSValue(context, error); } @@ -425,10 +452,7 @@ void CYThrow(JSContextRef context, id error, JSValueRef *exception) { } - (id) objectForKey:(id)key { - JSValueRef exception(NULL); - JSValueRef value(JSObjectGetProperty(context_, object_, CYJSString(key), &exception)); - CYThrow(context_, exception); - return CYCastNSObject(context_, value); + return CYCastNSObject(context_, CYGetProperty(context_, object_, CYJSString(key))); } - (NSEnumerator *) keyEnumerator { @@ -439,9 +463,7 @@ void CYThrow(JSContextRef context, id error, JSValueRef *exception) { } - (void) setObject:(id)object forKey:(id)key { - JSValueRef exception(NULL); - JSObjectSetProperty(context_, object_, CYJSString(key), CYCastJSValue(context_, object), kJSPropertyAttributeNone, &exception); - CYThrow(context_, exception); + CYSetProperty(context_, object_, CYJSString(key), CYCastJSValue(context_, object)); } - (void) removeObjectForKey:(id)key { @@ -463,10 +485,7 @@ void CYThrow(JSContextRef context, id error, JSValueRef *exception) { } - (NSUInteger) count { - JSValueRef exception(NULL); - JSValueRef value(JSObjectGetProperty(context_, object_, length_, &exception)); - CYThrow(context_, exception); - return CYCastDouble(context_, value); + return CYCastDouble(context_, CYGetProperty(context_, object_, length_)); } - (id) objectAtIndex:(NSUInteger)index { @@ -479,7 +498,7 @@ void CYThrow(JSContextRef context, id error, JSValueRef *exception) { @end -CFStringRef JSValueToJSONCopy(JSContextRef context, JSValueRef value) { +CFStringRef CYCopyJSONString(JSContextRef context, JSValueRef value) { id object(CYCastNSObject(context, value)); return reinterpret_cast([(object == nil ? @"null" : [object cy$toJSON]) retain]); } @@ -507,13 +526,13 @@ static void OnData(CFSocketRef socket, CFSocketCallBackType type, CFDataRef addr JSStringRef script(JSStringCreateWithCFString(code)); CFRelease(code); - JSValueRef result(JSEvaluateScript(JSGetContext(), script, NULL, NULL, 0, NULL)); + JSValueRef result(JSEvaluateScript(CYGetJSContext(), script, NULL, NULL, 0, NULL)); JSStringRelease(script); CFHTTPMessageRef response(CFHTTPMessageCreateResponse(kCFAllocatorDefault, 200, NULL, kCFHTTPVersion1_1)); CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Type"), CFSTR("application/json; charset=utf-8")); - CFStringRef json(JSValueToJSONCopy(JSGetContext(), result)); + CFStringRef json(CYCopyJSONString(CYGetJSContext(), result)); CFDataRef body(CFStringCreateExternalRepresentation(kCFAllocatorDefault, json, kCFStringEncodingUTF8, NULL)); CFRelease(json); @@ -612,6 +631,16 @@ struct selData : ptrData { } }; +JSObjectRef CYMakeSelector(JSContextRef context, SEL sel) { + selData *data(new selData(sel)); + return JSObjectMake(context, Selector_, data); +} + +JSObjectRef CYMakePointer(JSContextRef context, void *pointer) { + ptrData *data(new ptrData(pointer)); + return JSObjectMake(context, Pointer_, data); +} + static void Pointer_finalize(JSObjectRef object) { ptrData *data(reinterpret_cast(JSObjectGetPrivate(object))); apr_pool_destroy(data->pool_); @@ -627,17 +656,10 @@ JSObjectRef CYMakeFunction(JSContextRef context, void (*function)(), const char return JSObjectMake(context, Functor_, data); } - JSObjectRef CYMakeFunction(JSContextRef context, void *function, const char *type) { return CYMakeFunction(context, reinterpret_cast(function), type); } -void CYSetProperty(JSContextRef context, JSObjectRef object, const char *name, JSValueRef value) { - JSValueRef exception(NULL); - JSObjectSetProperty(context, object, CYJSString(name), value, kJSPropertyAttributeNone, &exception); - CYThrow(context, exception); -} - char *CYPoolCString(apr_pool_t *pool, JSStringRef value) { size_t size(JSStringGetMaximumUTF8CStringSize(value)); char *string(new(pool) char[size]); @@ -652,9 +674,7 @@ char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSValueRef value) { // XXX: this macro is unhygenic #define CYCastCString(context, value) ({ \ - JSValueRef exception(NULL); \ - JSStringRef string(JSValueToStringCopy(context, value, &exception)); \ - CYThrow(context, exception); \ + JSStringRef string(CYCopyJSString(context, value)); \ size_t size(JSStringGetMaximumUTF8CStringSize(string)); \ char *utf8(reinterpret_cast(alloca(size))); \ JSStringGetUTF8CString(string, utf8, size); \ @@ -768,29 +788,27 @@ JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, void *data) { CYFromFFI_(double, double) case sig::object_P: - case sig::typename_P: { + case sig::typename_P: value = CYCastJSValue(context, *reinterpret_cast(data)); - } break; - - case sig::selector_P: { - if (SEL sel = *reinterpret_cast(data)) { - selData *data(new selData(sel)); - value = JSObjectMake(context, Selector_, data); - } else goto null; - } break; - - case sig::pointer_P: { - if (void *pointer = *reinterpret_cast(data)) { - ptrData *data(new ptrData(pointer)); - value = JSObjectMake(context, Pointer_, data); - } else goto null; - } break; - - case sig::string_P: { + break; + + case sig::selector_P: + if (SEL sel = *reinterpret_cast(data)) + value = CYMakeSelector(context, sel); + else goto null; + break; + + case sig::pointer_P: + if (void *pointer = *reinterpret_cast(data)) + value = CYMakePointer(context, pointer); + else goto null; + break; + + case sig::string_P: if (char *utf8 = *reinterpret_cast(data)) value = JSValueMakeString(context, CYJSString(utf8)); else goto null; - } break; + break; case sig::struct_P: goto fail; @@ -841,7 +859,7 @@ static JSValueRef Global_getProperty(JSContextRef context, JSObjectRef object, J if (NSMutableArray *entry = [Bridge_ objectForKey:name]) switch ([[entry objectAtIndex:0] intValue]) { case 0: - return JSEvaluateScript(JSGetContext(), CYJSString([entry objectAtIndex:1]), NULL, NULL, 0, NULL); + return JSEvaluateScript(CYGetJSContext(), CYJSString([entry objectAtIndex:1]), NULL, NULL, 0, NULL); case 1: return CYMakeFunction(context, [name cy$symbol], [[entry objectAtIndex:1] UTF8String]); case 2: @@ -892,15 +910,32 @@ static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObje return CYCallFunction(context, count, arguments, exception, &signature, &cif, function); } -static JSValueRef ffi_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { +static JSValueRef Selector_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + JSValueRef setup[count + 2]; + setup[0] = _this; + setup[1] = object; + memmove(setup + 2, arguments, sizeof(JSValueRef) * count); + return $objc_msgSend(context, NULL, NULL, count + 2, setup, exception); +} + +static JSValueRef Functor_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { ffiData *data(reinterpret_cast(JSObjectGetPrivate(object))); return CYCallFunction(context, count, arguments, exception, &data->signature_, &data->cif_, reinterpret_cast(data->value_)); } +JSObjectRef sel(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + @try { + if (count != 1) + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to Selector constructor" userInfo:nil]; + const char *name(CYCastCString(context, arguments[0])); + return CYMakeSelector(context, sel_registerName(name)); + } CYCatch +} + JSObjectRef ffi(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { @try { if (count != 2) - @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to ffi constructor" userInfo:nil]; + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to Functor constructor" userInfo:nil]; void *function(CYCastPointer(context, arguments[0])); const char *type(CYCastCString(context, arguments[1])); return CYMakeFunction(context, function, type); @@ -912,13 +947,24 @@ JSValueRef Pointer_getProperty_value(JSContextRef context, JSObjectRef object, J return JSValueMakeNumber(context, reinterpret_cast(data->value_)); } +JSValueRef Selector_getProperty_prototype(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { + return Function_; +} + static JSStaticValue Pointer_staticValues[2] = { {"value", &Pointer_getProperty_value, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete}, {NULL, NULL, NULL, 0} }; +/*static JSStaticValue Selector_staticValues[2] = { + {"prototype", &Selector_getProperty_prototype, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete}, + {NULL, NULL, NULL, 0} +};*/ + CYDriver::CYDriver(const std::string &filename) : state_(CYClear), + data_(NULL), + size_(0), filename_(filename), source_(NULL) { @@ -929,68 +975,11 @@ CYDriver::~CYDriver() { ScannerDestroy(); } -void CYDriver::Clear() { - state_ = CYClear; - source_.clear(); - pool_.Clear(); -} - -extern int cydebug; - -void cy::parser::error(const cy::parser::location_type &loc, const std::string &msg) { - std::cerr << loc << ": " << msg << std::endl; -} - -void CYConsole(FILE *fin, FILE *fout, FILE *ferr) { - //cydebug = 1; - - CYDriver driver(""); - - while (!feof(fin)) { _pooled - driver.Clear(); - - cy::parser parser(driver); - if (parser.parse() != 0) - continue; - - for (std::vector::const_iterator i(driver.source_.begin()); i != driver.source_.end(); ++i) { - CYSource *source(*i); - - std::ostringstream str; - source->Show(str); - - std::string code(str.str()); - std::cout << code << std::endl; - - JSStringRef script(JSStringCreateWithUTF8CString(code.c_str())); - - JSContextRef context(JSGetContext()); - - JSValueRef exception(NULL); - JSValueRef result(JSEvaluateScript(context, script, NULL, NULL, 0, &exception)); - JSStringRelease(script); - - if (exception != NULL) - result = exception; - - if (!JSValueIsUndefined(context, result)) { - CFStringRef json; - - @try { json: - json = JSValueToJSONCopy(context, result); - } @catch (id error) { - CYThrow(context, error, &result); - goto json; - } - - fputs([reinterpret_cast(json) UTF8String], fout); - CFRelease(json); - - fputs("\n", fout); - fflush(fout); - } - } - } +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); } MSInitialize { _pooled @@ -1028,12 +1017,14 @@ MSInitialize { _pooled definition = kJSClassDefinitionEmpty; definition.className = "Functor"; definition.parentClass = Pointer_; - definition.callAsFunction = &ffi_callAsFunction; + definition.callAsFunction = &Functor_callAsFunction; Functor_ = JSClassCreate(&definition); definition = kJSClassDefinitionEmpty; definition.className = "Selector"; definition.parentClass = Pointer_; + //definition.staticValues = Selector_staticValues; + definition.callAsFunction = &Selector_callAsFunction; Selector_ = JSClassCreate(&definition); definition = kJSClassDefinitionEmpty; @@ -1052,9 +1043,10 @@ MSInitialize { _pooled JSObjectRef global(JSContextGetGlobalObject(context)); - CYSetProperty(context, global, "ffi", JSObjectMakeConstructor(context, Functor_, &ffi)); + CYSetProperty(context, global, CYJSString("SEL"), JSObjectMakeConstructor(context, Selector_, &sel)); + CYSetProperty(context, global, CYJSString("ffi"), JSObjectMakeConstructor(context, Functor_, &ffi)); - CYSetProperty(context, global, "objc_msgSend", JSObjectMakeFunctionWithCallback(context, CYJSString("objc_msgSend"), &$objc_msgSend)); + CYSetProperty(context, global, CYJSString("objc_msgSend"), JSObjectMakeFunctionWithCallback(context, CYJSString("objc_msgSend"), &$objc_msgSend)); Bridge_ = [[NSMutableDictionary dictionaryWithContentsOfFile:@"/usr/lib/libcycript.plist"] retain]; @@ -1062,9 +1054,6 @@ MSInitialize { _pooled message_ = JSStringCreateWithUTF8CString("message"); length_ = JSStringCreateWithUTF8CString("length"); - JSValueRef exception(NULL); - JSValueRef value(JSObjectGetProperty(JSGetContext(), global, CYJSString("Array"), &exception)); - CYThrow(context, exception); - Array_ = JSValueToObject(JSGetContext(), value, &exception); - CYThrow(context, exception); + Array_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Array"))); + Function_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Function"))); }