From: Jay Freeman (saurik) Date: Sat, 10 Oct 2009 19:10:58 +0000 (+0000) Subject: Implemented structure field names, removed parentheses from NSDictionary CYON, and... X-Git-Tag: v0.9.432~361 X-Git-Url: https://git.saurik.com/cycript.git/commitdiff_plain/f33b048af6516bdeff373d3eb709f3d445233dc4 Implemented structure field names, removed parentheses from NSDictionary CYON, and made quotations around propery name CYON optional. --- diff --git a/Library.mm b/Library.mm index bc4a6c7..7b25442 100644 --- a/Library.mm +++ b/Library.mm @@ -157,32 +157,6 @@ struct Pointer_privateData : } }; -struct Functor_privateData : - Pointer_privateData -{ - sig::Signature signature_; - ffi_cif cif_; - - Functor_privateData(const char *type, void (*value)()) : - Pointer_privateData(reinterpret_cast(value)) - { - sig::Parse(pool_, &signature_, type); - sig::sig_ffi_cif(pool_, &sig::ObjectiveC, &signature_, &cif_); - } -}; - -struct ffoData : - Functor_privateData -{ - JSContextRef context_; - JSObjectRef function_; - - ffoData(const char *type) : - Functor_privateData(type, NULL) - { - } -}; - struct Selector_privateData : Pointer_privateData { Selector_privateData(SEL value) : Pointer_privateData(value) @@ -279,6 +253,14 @@ void Copy(apr_pool_t *pool, ffi_type &lhs, ffi_type &rhs) { } +struct CStringMapLess : + std::binary_function +{ + _finline bool operator ()(const char *lhs, const char *rhs) const { + return strcmp(lhs, rhs) < 0; + } +}; + struct Type_privateData { sig::Type type_; ffi_type ffi_; @@ -299,14 +281,6 @@ struct Struct_privateData : } }; -struct CStringMapLess : - std::binary_function -{ - _finline bool operator ()(const char *lhs, const char *rhs) const { - return strcmp(lhs, rhs) < 0; - } -}; - typedef std::map TypeMap; static TypeMap Types_; @@ -331,6 +305,45 @@ JSObjectRef CYMakeStruct(JSContextRef context, void *data, sig::Type *type, ffi_ return JSObjectMake(context, Struct_, internal); } +void Structor_(apr_pool_t *pool, const char *name, const char *types, sig::Type *type) { + CYPoolTry { + if (NSMutableArray *entry = [[Bridge_ objectAtIndex:2] objectForKey:[NSString stringWithUTF8String:name]]) { + switch ([[entry objectAtIndex:0] intValue]) { + case 0: + static CYPool Pool_; + sig::Parse(Pool_, &type->data.signature, [[entry objectAtIndex:1] UTF8String], &Structor_); + break; + } + } + } CYPoolCatch() +} + +struct Functor_privateData : + Pointer_privateData +{ + sig::Signature signature_; + ffi_cif cif_; + + Functor_privateData(const char *type, void (*value)()) : + Pointer_privateData(reinterpret_cast(value)) + { + sig::Parse(pool_, &signature_, type, &Structor_); + sig::sig_ffi_cif(pool_, &sig::ObjectiveC, &signature_, &cif_); + } +}; + +struct ffoData : + Functor_privateData +{ + JSContextRef context_; + JSObjectRef function_; + + ffoData(const char *type) : + Functor_privateData(type, NULL) + { + } +}; + JSObjectRef CYMakeInstance(JSContextRef context, id object, bool transient) { if (!transient) object = [object retain]; @@ -384,6 +397,7 @@ JSValueRef CYJSUndefined(JSContextRef context) { - (NSObject *) cy$toJSON:(NSString *)key; - (NSString *) cy$toCYON; +- (NSString *) cy$toKey; - (JSValueRef) cy$JSValueInContext:(JSContextRef)context transient:(bool)transient; @@ -501,6 +515,10 @@ struct PropertyAttributes { return [[self cy$toJSON:@""] cy$toCYON]; } +- (NSString *) cy$toKey { + return [self cy$toCYON]; +} + - (JSValueRef) cy$JSValueInContext:(JSContextRef)context transient:(bool)transient { return CYMakeInstance(context, self, transient); } @@ -624,7 +642,7 @@ struct PropertyAttributes { - (NSString *) cy$toCYON { NSMutableString *json([[[NSMutableString alloc] init] autorelease]); - [json appendString:@"({"]; + [json appendString:@"{"]; bool comma(false); for (id key in self) { @@ -632,13 +650,13 @@ struct PropertyAttributes { [json appendString:@","]; else comma = true; - [json appendString:[key cy$toCYON]]; + [json appendString:[key cy$toKey]]; [json appendString:@":"]; NSObject *object([self objectForKey:key]); [json appendString:[object cy$toCYON]]; } - [json appendString:@"})"]; + [json appendString:@"}"]; return json; } @@ -702,6 +720,7 @@ struct PropertyAttributes { } - (NSString *) cy$toCYON { + // XXX: this should use the better code from Output.cpp CFMutableStringRef json(CFStringCreateMutableCopy(kCFAllocatorDefault, 0, (CFStringRef) self)); CFStringFindAndReplace(json, CFSTR("\\"), CFSTR("\\\\"), CFRangeMake(0, CFStringGetLength(json)), 0); @@ -716,6 +735,21 @@ struct PropertyAttributes { return [reinterpret_cast(json) autorelease]; } +- (NSString *) cy$toKey { + const char *value([self UTF8String]); + size_t size(strlen(value)); + + if (size == 0 || !WordStartRange_[value[0]]) + goto cyon; + for (size_t i(1); i != size; ++i) + if (!WordEndRange_[value[i]]) + goto cyon; + return self; + + cyon: + return [self cy$toCYON]; +} + - (void *) cy$symbol { CYPool pool; return dlsym(RTLD_DEFAULT, CYPoolCString(pool, self)); @@ -1353,13 +1387,26 @@ void CYPoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, ffi_type case sig::struct_P: { uint8_t *base(reinterpret_cast(data)); - bool aggregate(JSValueIsObject(context, value)); + JSObjectRef aggregate(JSValueIsObject(context, value) ? (JSObjectRef) value : NULL); for (size_t index(0); index != type->data.signature.count; ++index) { - ffi_type *element(ffi->elements[index]); - JSValueRef rhs(aggregate ? CYGetProperty(context, (JSObjectRef) value, index) : value); - CYPoolFFI(pool, context, type->data.signature.elements[index].type, element, base, rhs); + sig::Element *element(&type->data.signature.elements[index]); + ffi_type *field(ffi->elements[index]); + + JSValueRef rhs; + if (aggregate == NULL) + rhs = value; + else { + rhs = CYGetProperty(context, aggregate, index); + if (JSValueIsUndefined(context, rhs)) { + rhs = CYGetProperty(context, aggregate, CYJSString(element->name)); + if (JSValueIsUndefined(context, rhs)) + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"unable to extract structure value" userInfo:nil]; + } + } + + CYPoolFFI(pool, context, element->type, field, base, rhs); // XXX: alignment? - base += element->size; + base += field->size; } } break; @@ -1451,18 +1498,28 @@ bool Index_(apr_pool_t *pool, Struct_privateData *internal, JSStringRef property const char *name(CYPoolCString(pool, property, &length)); double number(CYCastDouble(name, length)); + size_t count(typical->type_.data.signature.count); + if (std::isnan(number)) { if (property == NULL) return false; - // XXX: implement! + sig::Element *elements(typical->type_.data.signature.elements); + + for (size_t local(0); local != count; ++local) + if (strcmp(name, elements[local].name) == 0) { + index = local; + goto base; + } + return false; } else { index = static_cast(number); - if (index != number || index < 0 || static_cast(index) >= typical->type_.data.signature.count) + if (index != number || index < 0 || static_cast(index) >= count) return false; } + base: base = reinterpret_cast(internal->value_); for (ssize_t local(0); local != index; ++local) base += typical->ffi_.elements[local]->size; @@ -1471,38 +1528,49 @@ bool Index_(apr_pool_t *pool, Struct_privateData *internal, JSStringRef property } static JSValueRef Struct_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { - CYTry { - CYPool pool; - Struct_privateData *internal(reinterpret_cast(JSObjectGetPrivate(object))); - Type_privateData *typical(internal->type_); + CYPool pool; + Struct_privateData *internal(reinterpret_cast(JSObjectGetPrivate(object))); + Type_privateData *typical(internal->type_); - ssize_t index; - uint8_t *base; + ssize_t index; + uint8_t *base; - if (!Index_(pool, internal, property, index, base)) - return NULL; + if (!Index_(pool, internal, property, index, base)) + return NULL; + CYTry { return CYFromFFI(context, typical->type_.data.signature.elements[index].type, typical->ffi_.elements[index], base, object); } CYCatch } static bool Struct_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { - CYTry { - CYPool pool; - Struct_privateData *internal(reinterpret_cast(JSObjectGetPrivate(object))); - Type_privateData *typical(internal->type_); + CYPool pool; + Struct_privateData *internal(reinterpret_cast(JSObjectGetPrivate(object))); + Type_privateData *typical(internal->type_); - ssize_t index; - uint8_t *base; + ssize_t index; + uint8_t *base; - if (!Index_(pool, internal, property, index, base)) - return false; + if (!Index_(pool, internal, property, index, base)) + return false; + CYTry { CYPoolFFI(NULL, context, typical->type_.data.signature.elements[index].type, typical->ffi_.elements[index], base, value); return true; } CYCatch } +static void Struct_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) { + Struct_privateData *internal(reinterpret_cast(JSObjectGetPrivate(object))); + Type_privateData *typical(internal->type_); + + size_t count(typical->type_.data.signature.count); + sig::Element *elements(typical->type_.data.signature.elements); + + for (size_t index(0); index != count; ++index) + JSPropertyNameAccumulatorAddName(names, CYJSString(elements[index].name)); +} + JSValueRef CYCallFunction(apr_pool_t *pool, JSContextRef context, size_t setups, void *setup[], size_t count, const JSValueRef *arguments, JSValueRef *exception, sig::Signature *signature, ffi_cif *cif, void (*function)()) { CYTry { if (setups + count != signature->count - 1) @@ -1581,7 +1649,7 @@ static JSValueRef Runtime_getProperty(JSContextRef context, JSObjectRef object, case 2: // XXX: this is horrendously inefficient sig::Signature signature; - sig::Parse(pool, &signature, CYPoolCString(pool, [entry objectAtIndex:1])); + sig::Parse(pool, &signature, CYPoolCString(pool, [entry objectAtIndex:1]), &Structor_); ffi_cif cif; sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif); return CYFromFFI(context, signature.elements[0].type, cif.rtype, [name cy$symbol]); @@ -1643,7 +1711,7 @@ JSValueRef CYSendMessage(apr_pool_t *pool, JSContextRef context, id self, SEL _c setup[1] = &_cmd; sig::Signature signature; - sig::Parse(pool, &signature, type); + sig::Parse(pool, &signature, type, &Structor_); ffi_cif cif; sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif); @@ -1905,6 +1973,7 @@ MSInitialize { _pooled definition.className = "Struct"; definition.getProperty = &Struct_getProperty; definition.setProperty = &Struct_setProperty; + definition.getPropertyNames = &Struct_getPropertyNames; definition.finalize = &CYData::Finalize; Struct_ = JSClassCreate(&definition); diff --git a/makefile b/makefile index 69a8c15..3b3229d 100644 --- a/makefile +++ b/makefile @@ -20,18 +20,20 @@ clean: libcycript.plist: Bridge.def { \ echo '({'; \ - sed -e 's/^C/0/;s/^F/1/;s/^V/2/' Bridge.def | while read -r line; do \ + grep '^[CFV]' Bridge.def | sed -e 's/^C/0/;s/^F/1/;s/^V/2/' | while read -r line; do \ if [[ $$line == '' ]]; then \ continue; \ fi; \ set $$line; \ - if [[ $$1 =~ [#fl:] ]]; then \ - continue; \ - fi; \ echo "$$2 = ($$1, \"$${3//\"/\\\"}\");"; \ done; \ echo '},{'; \ - grep ^: Bridge.def | sed -e 's/^: \([^ ]*\) \(.*\)/"\1" = "\2";/'; \ + grep '^:' Bridge.def | sed -e 's/^: \([^ ]*\) \(.*\)/"\1" = "\2";/'; \ + echo '},{'; \ + grep '^S' Bridge.def | sed -e 's/^S/0/' | while read -r line; do \ + set $$line; \ + echo "$$2 = ($$1, \"$${3//\"/\\\"}\");"; \ + done; \ echo '})'; \ } >$@ diff --git a/sig/parse.cpp b/sig/parse.cpp index 5dcfd4f..1c0ec23 100644 --- a/sig/parse.cpp +++ b/sig/parse.cpp @@ -51,10 +51,8 @@ namespace sig { -void (*sig_aggregate)(apr_pool_t *pool, enum Primitive primitive, const char *name, struct Signature *signature, const char *types) = NULL; - -void Parse_(apr_pool_t *pool, struct Signature *signature, const char **name, char eos); -struct Type *Parse_(apr_pool_t *pool, const char **name, char eos, bool named); +void Parse_(apr_pool_t *pool, struct Signature *signature, const char **name, char eos, Callback callback); +struct Type *Parse_(apr_pool_t *pool, const char **name, char eos, bool named, Callback callback); /* XXX: I really screwed up this time */ @@ -64,10 +62,11 @@ void *prealloc_(apr_pool_t *pool, void *odata, size_t osize, size_t nsize) { return ndata; } -void Parse_(apr_pool_t *pool, struct Signature *signature, const char **name, char eos) { +void Parse_(apr_pool_t *pool, struct Signature *signature, const char **name, char eos, Callback callback) { _assert(*name != NULL); - bool named = **name == '"'; + // XXX: this is just a stupid check :( + bool named(**name == '"'); signature->elements = NULL; signature->count = 0; @@ -91,7 +90,7 @@ void Parse_(apr_pool_t *pool, struct Signature *signature, const char **name, ch *name = quote + 1; } - element->type = Parse_(pool, name, eos, named); + element->type = Parse_(pool, name, eos, named, callback); if (**name < '0' || **name > '9') element->offset = _not(size_t); @@ -105,7 +104,7 @@ void Parse_(apr_pool_t *pool, struct Signature *signature, const char **name, ch } } -struct Type *Parse_(apr_pool_t *pool, const char **name, char eos, bool named) { +struct Type *Parse_(apr_pool_t *pool, const char **name, char eos, bool named, Callback callback) { char next = *(*name)++; if (next == '?') return NULL; @@ -148,7 +147,7 @@ struct Type *Parse_(apr_pool_t *pool, const char **name, char eos, bool named) { case '[': type->primitive = array_P; type->data.data.size = strtoul(*name, (char **) name, 10); - type->data.data.type = Parse_(pool, name, eos, false); + type->data.data.type = Parse_(pool, name, eos, false, callback); if (**name != ']') { printf("']' != \"%s\"\n", *name); _assert(false); @@ -164,7 +163,7 @@ struct Type *Parse_(apr_pool_t *pool, const char **name, char eos, bool named) { } else if (**name == '"') { type->data.data.type = NULL; } else { - type->data.data.type = Parse_(pool, name, eos, named); + type->data.data.type = Parse_(pool, name, eos, named, callback); } break; @@ -201,24 +200,19 @@ struct Type *Parse_(apr_pool_t *pool, const char **name, char eos, bool named) { else type->name = NULL; + // XXX: this types thing is a throwback to JocStrap + char *types; - if (next != '=') + if (next != '=') { types = NULL; - else { - const char *temp = *name; - Parse_(pool, &type->data.signature, name, end); + } else { + const char *temp(*name); + Parse_(pool, &type->data.signature, name, end, callback); types = (char *) apr_pstrmemdup(pool, temp, *name - temp - 1); } - if (type->name != NULL && sig_aggregate != NULL) { - char *angle = strchr(type->name, '<'); - if (angle == NULL) - (*sig_aggregate)(pool, type->primitive, type->name, &type->data.signature, types); - else { - angle = (char *) apr_pstrmemdup(pool, type->name, angle - type->name); - (*sig_aggregate)(pool, type->primitive, angle, &type->data.signature, types); - } - } + if (callback != NULL) + (*callback)(pool, type->name, types, type); } break; case 'N': type->flags |= JOC_TYPE_INOUT; goto next; @@ -242,9 +236,9 @@ struct Type *Parse_(apr_pool_t *pool, const char **name, char eos, bool named) { return type; } -void Parse(apr_pool_t *pool, struct Signature *signature, const char *name) { +void Parse(apr_pool_t *pool, struct Signature *signature, const char *name, Callback callback) { const char *temp = name; - Parse_(pool, signature, &temp, '\0'); + Parse_(pool, signature, &temp, '\0', callback); _assert(temp[-1] == '\0'); } diff --git a/sig/parse.hpp b/sig/parse.hpp index 4557591..230d9b6 100644 --- a/sig/parse.hpp +++ b/sig/parse.hpp @@ -46,9 +46,8 @@ namespace sig { -extern void (*sig_aggregate)(apr_pool_t *pool, enum Primitive primitive, const char *name, struct Signature *signature, const char *types); - -void Parse(apr_pool_t *pool, struct Signature *signature, const char *name); +typedef void (*Callback)(apr_pool_t *pool, const char *name, const char *types, Type *type); +void Parse(apr_pool_t *pool, struct Signature *signature, const char *name, Callback callback); const char *Unparse(apr_pool_t *pool, struct Signature *signature); const char *Unparse(apr_pool_t *pool, struct Type *type); diff --git a/todo.txt b/todo.txt index 7691577..1f746c9 100644 --- a/todo.txt +++ b/todo.txt @@ -1,6 +1,5 @@ labelled statements don't get labelled blocks and empty statements are poorly factored -property labels should get minimized functors use both ffiData and ffoData... rename "data" variables to "internal" unicode identifier support (native and \u)