}
};
-struct Instance_privateData :
+struct Instance :
Pointer_privateData
{
- bool transient_;
+ enum Flags {
+ None = 0,
+ Transient = (1 << 0),
+ Uninitialized = (1 << 1),
+ };
- Instance_privateData(id value, bool transient) :
- Pointer_privateData(value)
+ Flags flags_;
+
+ Instance(id value, Flags flags) :
+ Pointer_privateData(value),
+ flags_(flags)
{
}
- virtual ~Instance_privateData() {
- if (!transient_)
+ virtual ~Instance() {
+ if ((flags_ & Transient) == 0)
[GetValue() release];
}
+ static JSObjectRef Make(JSContextRef context, id object, Flags flags) {
+ return JSObjectMake(context, Instance_, new Instance(object, flags));
+ }
+
id GetValue() const {
return reinterpret_cast<id>(value_);
}
+
+ bool IsUninitialized() const {
+ return (flags_ & Uninitialized) != 0;
+ }
};
namespace sig {
}
void Structor_(apr_pool_t *pool, const char *name, const char *types, sig::Type *type) {
+ if (name == NULL)
+ return;
+
CYPoolTry {
if (NSMutableArray *entry = [[Bridge_ objectAtIndex:2] objectForKey:[NSString stringWithUTF8String:name]]) {
switch ([[entry objectAtIndex:0] intValue]) {
}
};
-JSObjectRef CYMakeInstance(JSContextRef context, id object, bool transient) {
- if (!transient)
+JSValueRef CYMakeInstance(JSContextRef context, id object, bool transient) {
+ Instance::Flags flags;
+
+ if (transient)
+ flags = Instance::Transient;
+ else {
+ flags = Instance::None;
object = [object retain];
- Instance_privateData *data(new Instance_privateData(object, transient));
- return JSObjectMake(context, Instance_, data);
+ }
+
+ return Instance::Make(context, object, flags);
}
const char *CYPoolCString(apr_pool_t *pool, NSString *value) {
return JSValueMakeUndefined(context);
}
+size_t CYCastIndex(const char *value) {
+ if (value[0] == '0') {
+ if (value[1] == '\0')
+ return 0;
+ } else {
+ char *end;
+ size_t index(strtoul(value, &end, 10));
+ if (value + strlen(value) == end)
+ return index;
+ }
+
+ return _not(size_t);
+}
+
+size_t CYCastIndex(NSString *value) {
+ return CYCastIndex([value UTF8String]);
+}
+
@interface NSMethodSignature (Cycript)
- (NSString *) _typeString;
@end
- (NSString *) cy$toCYON;
- (NSString *) cy$toKey;
-- (JSValueRef) cy$JSValueInContext:(JSContextRef)context transient:(bool)transient;
+- (JSValueRef) cy$JSValueInContext:(JSContextRef)context;
- (NSObject *) cy$getProperty:(NSString *)name;
- (bool) cy$setProperty:(NSString *)name to:(NSObject *)value;
return [self cy$toCYON];
}
-- (JSValueRef) cy$JSValueInContext:(JSContextRef)context transient:(bool)transient {
- return CYMakeInstance(context, self, transient);
+- (JSValueRef) cy$JSValueInContext:(JSContextRef)context {
+ return CYMakeInstance(context, self, false);
}
- (NSObject *) cy$getProperty:(NSString *)name {
return @"undefined";
}
-- (JSValueRef) cy$JSValueInContext:(JSContextRef)context transient:(bool)transient {
+- (JSValueRef) cy$JSValueInContext:(JSContextRef)context {
return CYJSUndefined(context);
}
if ([name isEqualToString:@"length"])
return [NSNumber numberWithUnsignedInteger:[self count]];
- int index([name intValue]);
- if (index < 0 || index >= static_cast<int>([self count]))
+ size_t index(CYCastIndex(name));
+ if (index == _not(size_t) || index >= [self count])
return [super cy$getProperty:name];
else
return [self objectAtIndex:index];
@implementation NSMutableArray (Cycript)
- (bool) cy$setProperty:(NSString *)name to:(NSObject *)value {
- int index([name intValue]);
- if (index < 0 || index >= static_cast<int>([self count]))
+ size_t index(CYCastIndex(name));
+ if (index == _not(size_t) || index >= [self count])
return [super cy$setProperty:name to:value];
else {
[self replaceObjectAtIndex:index withObject:(value ?: [NSNull null])];
}
- (bool) cy$deleteProperty:(NSString *)name {
- int index([name intValue]);
- if (index < 0 || index >= static_cast<int>([self count]))
+ size_t index(CYCastIndex(name));
+ if (index == _not(size_t) || index >= [self count])
return [super cy$deleteProperty:name];
else {
[self removeObjectAtIndex:index];
return [self cy$JSType] != kJSTypeBoolean ? [self stringValue] : [self boolValue] ? @"true" : @"false";
}
-- (JSValueRef) cy$JSValueInContext:(JSContextRef)context transient:(bool)transient {
+- (JSValueRef) cy$JSValueInContext:(JSContextRef)context {
return [self cy$JSType] != kJSTypeBoolean ? CYCastJSValue(context, [self doubleValue]) : CYCastJSValue(context, [self boolValue]);
}
const char *value([self UTF8String]);
size_t size(strlen(value));
- if (size == 0 || !WordStartRange_[value[0]])
+ if (size == 0)
goto cyon;
- for (size_t i(1); i != size; ++i)
- if (!WordEndRange_[value[i]])
+
+ if (DigitRange_[value[0]]) {
+ if (CYCastIndex(self) == _not(size_t))
goto cyon;
+ } else {
+ if (!WordStartRange_[value[0]])
+ goto cyon;
+ for (size_t i(1); i != size; ++i)
+ if (!WordEndRange_[value[i]])
+ goto cyon;
+ }
+
return self;
cyon:
@end
-CYRange WordStartRange_(0x1000000000LLU,0x7fffffe87fffffeLLU); // A-Za-z_$
-CYRange WordEndRange_(0x3ff001000000000LLU,0x7fffffe87fffffeLLU); // A-Za-z_$0-9
+CYRange DigitRange_ (0x3ff000000000000LLU, 0x000000000000000LLU); // 0-9
+CYRange WordStartRange_(0x000001000000000LLU, 0x7fffffe87fffffeLLU); // A-Za-z_$
+CYRange WordEndRange_ (0x3ff001000000000LLU, 0x7fffffe87fffffeLLU); // A-Za-z_$0-9
JSGlobalContextRef CYGetJSContext() {
return Context_;
return (CFTypeRef) CYPoolRelease(pool, (id) object);
}
-id CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSObjectRef object) {
- if (JSValueIsObjectOfClass(context, object, Instance_)) {
- Instance_privateData *data(reinterpret_cast<Instance_privateData *>(JSObjectGetPrivate(object)));
- return data->GetValue();
- }
-
+id CYCastNSObject_(apr_pool_t *pool, JSContextRef context, JSObjectRef object) {
JSValueRef exception(NULL);
bool array(JSValueIsInstanceOfConstructor(context, object, Array_, &exception));
CYThrow(context, exception);
return CYPoolRelease(pool, [value initWithJSObject:object inContext:context]);
}
+id CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSObjectRef object) {
+ if (!JSValueIsObjectOfClass(context, object, Instance_))
+ return CYCastNSObject_(pool, context, object);
+ else {
+ Instance *data(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
+ return data->GetValue();
+ }
+}
+
JSStringRef CYCopyJSString(id value) {
return value == NULL ? NULL : JSStringCreateWithCFString(reinterpret_cast<CFStringRef>([value description]));
}
JSStringRef string_;
void Clear_() {
- JSStringRelease(string_);
+ if (string_ != NULL)
+ JSStringRelease(string_);
}
public:
return CYCastJSValue(context, CYJSString(value));
}
-JSValueRef CYCastJSValue(JSContextRef context, id value, bool transient = true) {
- return value == nil ? CYJSNull(context) : [value cy$JSValueInContext:context transient:transient];
+JSValueRef CYCastJSValue(JSContextRef context, id value) {
+ return value == nil ? CYJSNull(context) : [value cy$JSValueInContext:context];
}
JSObjectRef CYCastJSObject(JSContextRef context, JSValueRef value) {
- (void) removeObjectForKey:(id)key {
JSValueRef exception(NULL);
- // XXX: this returns a bool... throw exception, or ignore?
- JSObjectDeleteProperty(context_, object_, CYJSString(key), &exception);
+ (void) JSObjectDeleteProperty(context_, object_, CYJSString(key), &exception);
CYThrow(context_, exception);
}
if (objc_property_t property = class_getProperty(object_getClass(self), [name UTF8String])) {
PropertyAttributes attributes(property);
SEL sel(sel_registerName(attributes.Getter()));
- return CYSendMessage(pool, context, self, sel, 0, NULL, exception);
+ return CYSendMessage(pool, context, self, sel, 0, NULL, false, exception);
}
return NULL;
if (const char *setter = attributes.Setter()) {
SEL sel(sel_registerName(setter));
JSValueRef arguments[1] = {value};
- CYSendMessage(pool, context, self, sel, 1, arguments, exception);
+ CYSendMessage(pool, context, self, sel, 1, arguments, false, exception);
return true;
}
}
static JSObjectRef Instance_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
CYTry {
- Instance_privateData *data(reinterpret_cast<Instance_privateData *>(JSObjectGetPrivate(object)));
- return CYMakeInstance(context, [data->GetValue() alloc], true);
+ Instance *data(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
+ JSObjectRef value(Instance::Make(context, [data->GetValue() alloc], Instance::Uninitialized));
+ return value;
} CYCatch
}
else {
rhs = CYGetProperty(context, aggregate, index);
if (JSValueIsUndefined(context, rhs)) {
- rhs = CYGetProperty(context, aggregate, CYJSString(element->name));
- if (JSValueIsUndefined(context, rhs))
+ if (element->name != NULL)
+ rhs = CYGetProperty(context, aggregate, CYJSString(element->name));
+ else
+ goto undefined;
+ if (JSValueIsUndefined(context, rhs)) undefined:
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"unable to extract structure value" userInfo:nil];
}
}
}
}
-JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, JSObjectRef owner = NULL) {
+JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner = NULL) {
JSValueRef value;
switch (type->primitive) {
CYFromFFI_(float, float)
CYFromFFI_(double, double)
- case sig::object_P:
- value = CYCastJSValue(context, *reinterpret_cast<id *>(data));
- break;
+ case sig::object_P: {
+ if (id object = *reinterpret_cast<id *>(data)) {
+ value = CYCastJSValue(context, object);
+ if (initialize)
+ [object release];
+ } else goto null;
+ } break;
case sig::typename_P:
value = CYMakeInstance(context, *reinterpret_cast<Class *>(data), true);
sig::Element *elements(typical->type_.data.signature.elements);
- for (size_t local(0); local != count; ++local)
- if (strcmp(name, elements[local].name) == 0) {
+ for (size_t local(0); local != count; ++local) {
+ sig::Element *element(&elements[local]);
+ if (element->name != NULL && strcmp(name, element->name) == 0) {
index = local;
goto base;
}
+ }
return false;
} else {
return NULL;
CYTry {
- return CYFromFFI(context, typical->type_.data.signature.elements[index].type, typical->ffi_.elements[index], base, object);
+ return CYFromFFI(context, typical->type_.data.signature.elements[index].type, typical->ffi_.elements[index], base, false, object);
} CYCatch
}
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));
+ char number[32];
+
+ for (size_t index(0); index != count; ++index) {
+ const char *name;
+ name = elements[index].name;
+
+ if (name == NULL) {
+ sprintf(number, "%lu", index);
+ name = number;
+ }
+
+ JSPropertyNameAccumulatorAddName(names, CYJSString(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)()) {
+JSValueRef CYCallFunction(apr_pool_t *pool, JSContextRef context, size_t setups, void *setup[], size_t count, const JSValueRef arguments[], bool initialize, JSValueRef *exception, sig::Signature *signature, ffi_cif *cif, void (*function)()) {
CYTry {
if (setups + count != signature->count - 1)
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to ffi function" userInfo:nil];
uint8_t value[cif->rtype->size];
ffi_call(cif, function, value, values);
- return CYFromFFI(context, signature->elements[0].type, cif->rtype, value);
+ return CYFromFFI(context, signature->elements[0].type, cif->rtype, value, initialize);
} CYCatch
}
JSValueRef values[count];
for (size_t index(0); index != count; ++index)
- values[index] = CYFromFFI(context, data->signature_.elements[1 + index].type, data->cif_.arg_types[index], arguments[index]);
+ values[index] = CYFromFFI(context, data->signature_.elements[1 + index].type, data->cif_.arg_types[index], arguments[index], false);
JSValueRef value(CYCallAsFunction(context, data->function_, NULL, count, values));
CYPoolFFI(NULL, context, data->signature_.elements[0].type, data->cif_.rtype, result, value);
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]);
+ return CYFromFFI(context, signature.elements[0].type, cif.rtype, [name cy$symbol], false);
}
return NULL;
} CYCatch
static JSValueRef CYApplicationMain(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
CYTry {
CYPool pool;
- NSString *name(CYCastNSObject(pool, context, arguments[0]));
- int argc(*_NSGetArgc());
- char **argv(*_NSGetArgv());
+
+ int argc(CYCastDouble(context, arguments[0]));
+ char **argv(CYCastPointer<char **>(context, arguments[1]));
+ NSString *principal(CYCastNSObject(pool, context, arguments[2]));
+ NSString *delegate(CYCastNSObject(pool, context, arguments[3]));
+
+ argc = *_NSGetArgc() - 1;
+ argv = *_NSGetArgv() + 1;
for (int i(0); i != argc; ++i)
NSLog(@"argv[%i]=%s", i, argv[i]);
+
_pooled
- return CYCastJSValue(context, UIApplicationMain(argc, argv, name, name));
+ return CYCastJSValue(context, UIApplicationMain(argc, argv, principal, delegate));
} CYCatch
}
-JSValueRef CYSendMessage(apr_pool_t *pool, JSContextRef context, id self, SEL _cmd, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+JSValueRef CYSendMessage(apr_pool_t *pool, JSContextRef context, id self, SEL _cmd, size_t count, const JSValueRef arguments[], bool initialize, JSValueRef *exception) {
const char *type;
Class _class(object_getClass(self));
sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif);
void (*function)() = stret(cif.rtype) ? reinterpret_cast<void (*)()>(&objc_msgSend_stret) : reinterpret_cast<void (*)()>(&objc_msgSend);
- return CYCallFunction(pool, context, 2, setup, count, arguments, exception, &signature, &cif, function);
+ return CYCallFunction(pool, context, 2, setup, count, arguments, initialize, exception, &signature, &cif, function);
}
static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
CYPool pool;
+ bool uninitialized;
+
id self;
SEL _cmd;
if (count < 2)
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"too few arguments to objc_msgSend" userInfo:nil];
- self = CYCastNSObject(pool, context, arguments[0]);
+ if (JSValueIsObjectOfClass(context, arguments[0], Instance_)) {
+ Instance *data(reinterpret_cast<Instance *>(JSObjectGetPrivate((JSObjectRef) arguments[0])));
+ self = data->GetValue();
+ uninitialized = data->IsUninitialized();
+ if (uninitialized)
+ data->value_ = nil;
+ } else {
+ self = CYCastNSObject(pool, context, arguments[0]);
+ uninitialized = false;
+ }
+
if (self == nil)
return CYJSNull(context);
_cmd = CYCastSEL(context, arguments[1]);
} CYCatch
- return CYSendMessage(pool, context, self, _cmd, count - 2, arguments + 2, exception);
+ return CYSendMessage(pool, context, self, _cmd, count - 2, arguments + 2, uninitialized, exception);
}
static JSValueRef Selector_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
static JSValueRef Functor_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
CYPool pool;
Functor_privateData *data(reinterpret_cast<Functor_privateData *>(JSObjectGetPrivate(object)));
- return CYCallFunction(pool, context, 0, NULL, count, arguments, exception, &data->signature_, &data->cif_, reinterpret_cast<void (*)()>(data->value_));
+ return CYCallFunction(pool, context, 0, NULL, count, arguments, false, exception, &data->signature_, &data->cif_, reinterpret_cast<void (*)()>(data->value_));
}
JSObjectRef Selector_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
static JSValueRef Instance_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
CYTry {
- Instance_privateData *data(reinterpret_cast<Instance_privateData *>(JSObjectGetPrivate(_this)));
+ Instance *data(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
CYPoolTry {
return CYCastJSValue(context, CYJSString([data->GetValue() cy$toCYON]));
} CYPoolCatch(NULL)
static JSValueRef Instance_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
CYTry {
- Instance_privateData *data(reinterpret_cast<Instance_privateData *>(JSObjectGetPrivate(_this)));
+ Instance *data(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
CYPoolTry {
NSString *key(count == 0 ? nil : CYCastNSString(NULL, CYJSString(context, arguments[0])));
return CYCastJSValue(context, CYJSString([data->GetValue() cy$toJSON:key]));
static JSValueRef Instance_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
CYTry {
- Instance_privateData *data(reinterpret_cast<Instance_privateData *>(JSObjectGetPrivate(_this)));
+ Instance *data(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
CYPoolTry {
return CYCastJSValue(context, CYJSString([data->GetValue() description]));
} CYPoolCatch(NULL)