-/* Cycript - Inlining/Optimizing JavaScript Compiler
- * Copyright (C) 2009 Jay Freeman (saurik)
+/* Cycript - Optimizing JavaScript Compiler/Runtime
+ * Copyright (C) 2009-2010 Jay Freeman (saurik)
*/
-/* Modified BSD License {{{ */
+/* GNU Lesser General Public License, Version 3 {{{ */
/*
- * Redistribution and use in source and binary
- * forms, with or without modification, are permitted
- * provided that the following conditions are met:
+ * Cycript is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
*
- * 1. Redistributions of source code must retain the
- * above copyright notice, this list of conditions
- * and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the
- * above copyright notice, this list of conditions
- * and the following disclaimer in the documentation
- * and/or other materials provided with the
- * distribution.
- * 3. The name of the author may not be used to endorse
- * or promote products derived from this software
- * without specific prior written permission.
+ * Cycript is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Cycript. If not, see <http://www.gnu.org/licenses/>.
+**/
/* }}} */
-#if defined(__APPLE__) && defined(__arm__)
-#include <substrate.h>
-#else
-#include <objc/objc-api.h>
-#endif
-
#ifdef __APPLE__
#include "Struct.hpp"
#endif
#include "ObjectiveC/Internal.hpp"
-#include <objc/Protocol.h>
+#include <objc/objc-api.h>
#include "cycript.hpp"
#include <CoreFoundation/CoreFoundation.h>
#include <JavaScriptCore/JSStringRefCF.h>
#include <WebKit/WebScriptObject.h>
+#include <objc/runtime.h>
#endif
#include "Error.hpp"
#define object_getInstanceVariable(object, name, value) ({ \
objc_ivar *ivar(class_getInstanceVariable(object_getClass(object), name)); \
+ _assert(value != NULL); \
if (ivar != NULL) \
GSObjCGetVariable(object, ivar_getOffset(ivar), sizeof(void *), value); \
ivar; \
static JSClassRef Message_;
static JSClassRef Messages_;
static JSClassRef Selector_;
+static JSClassRef StringInstance_;
static JSClassRef Super_;
static JSClassRef ObjectiveC_Classes_;
#ifdef __APPLE__
static Class NSCFBoolean_;
static Class NSCFType_;
+static Class NSGenericDeallocHandler_;
static Class NSMessageBuilder_;
static Class NSZombie_;
#else
static Class NSArray_;
static Class NSDictionary_;
+static Class NSString_;
static Class Object_;
static Type_privateData *Object_type;
return Selector_type;
}
+static JSValueRef Instance_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception);
+
JSValueRef CYGetClassPrototype(JSContextRef context, id self) {
if (self == nil)
return CYGetCachedObject(context, CYJSString("Instance_prototype"));
prototype = CYGetCachedObject(context, CYJSString("Array_prototype"));
else if (self == NSDictionary_)
prototype = CYGetCachedObject(context, CYJSString("Object_prototype"));
+ else if (self == NSString_)
+ prototype = CYGetCachedObject(context, CYJSString("StringInstance_prototype"));
else
prototype = CYGetClassPrototype(context, class_getSuperclass(self));
JSObjectRef object(JSObjectMake(context, _class, NULL));
JSObjectSetPrototype(context, object, prototype);
CYSetProperty(context, cy, name, object);
+
return object;
}
else if (_class == NSZombie_)
string = [NSString stringWithFormat:@"<_NSZombie_: %p>", value];
// XXX: frowny /in/ the pants
- else if (value == NSMessageBuilder_ || value == Object_)
+ else if (value == NSGenericDeallocHandler_ || value == NSMessageBuilder_ || value == Object_)
string = nil;
#endif
else
return [self cy$toCYON];
}
+- (bool) cy$hasProperty:(NSString *)name {
+ if ([name isEqualToString:@"length"])
+ return true;
+
+ size_t index(CYGetIndex(name));
+ if (index == _not(size_t) || index >= [self length])
+ return [super cy$hasProperty:name];
+ else
+ return true;
+}
+
+- (NSObject *) cy$getProperty:(NSString *)name {
+ if ([name isEqualToString:@"length"]) {
+ NSUInteger count([self length]);
+#ifdef __APPLE__
+ return [NSNumber numberWithUnsignedInteger:count];
+#else
+ return [NSNumber numberWithUnsignedInt:count];
+#endif
+ }
+
+ size_t index(CYGetIndex(name));
+ if (index == _not(size_t) || index >= [self length])
+ return [super cy$getProperty:name];
+ else
+ return [self substringWithRange:NSMakeRange(index, 1)];
+}
+
+- (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context {
+ [super cy$getPropertyNames:names inContext:context];
+
+ for (size_t index(0), length([self length]); index != length; ++index) {
+ char name[32];
+ sprintf(name, "%zu", index);
+ JSPropertyNameAccumulatorAddName(names, CYJSString(name));
+ }
+}
+
+// XXX: this might be overly restrictive for NSString; I think I need a half-way between /injecting/ implicit properties and /accepting/ implicit properties
++ (bool) cy$hasImplicitProperties {
+ return false;
+}
+
@end
/* }}} */
/* Bridge: WebUndefined {{{ */
} CYCatch }
/* Hook: objc_registerClassPair {{{ */
-#if defined(__APPLE__) && defined(__arm__)
+#if defined(__APPLE__) && defined(__arm__) && 0
// XXX: replace this with associated objects
MSHook(void, CYDealloc, id self, SEL sel) {
return Instance::Make(context, (id) object_getClass(internal->GetValue()));
}
-static JSValueRef Instance_getProperty_protocol(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
+static JSValueRef Instance_getProperty_prototype(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
id self(internal->GetValue());
if (!CYIsClass(self))
static JSStaticValue Instance_staticValues[5] = {
{"constructor", &Instance_getProperty_constructor, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"messages", &Instance_getProperty_messages, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
- {"prototype", &Instance_getProperty_protocol, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+ {"prototype", &Instance_getProperty_prototype, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"value", &CYValue_getProperty_value, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{NULL, NULL, NULL, 0}
};
{NULL, NULL, 0}
};
+static JSStaticFunction StringInstance_staticFunctions[2] = {
+ //{"valueOf", &Instance_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+ {"toString", &Instance_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+ {NULL, NULL, 0}
+};
+
void CYObjectiveC_Initialize() { /*XXX*/ JSContextRef context(NULL); CYPoolTry {
apr_pool_t *pool(CYGetGlobalPool());
#ifdef __APPLE__
NSCFBoolean_ = objc_getClass("NSCFBoolean");
NSCFType_ = objc_getClass("NSCFType");
+ NSGenericDeallocHandler_ = objc_getClass("__NSGenericDeallocHandler");
NSMessageBuilder_ = objc_getClass("NSMessageBuilder");
NSZombie_ = objc_getClass("_NSZombie_");
#else
NSArray_ = objc_getClass("NSArray");
NSDictionary_ = objc_getClass("NSDictionary");
+ NSString_ = objc_getClass("NSString");
Object_ = objc_getClass("Object");
JSClassDefinition definition;
definition.finalize = &CYFinalize;
Selector_ = JSClassCreate(&definition);
+ definition = kJSClassDefinitionEmpty;
+ definition.className = "StringInstance";
+ definition.staticFunctions = StringInstance_staticFunctions;
+ StringInstance_ = JSClassCreate(&definition);
+
definition = kJSClassDefinitionEmpty;
definition.className = "Super";
definition.staticFunctions = Internal_staticFunctions;
definition.getPropertyNames = &ObjectiveC_Protocols_getPropertyNames;
ObjectiveC_Protocols_ = JSClassCreate(&definition);
-#if defined(__APPLE__) && defined(__arm__)
+#if defined(__APPLE__) && defined(__arm__) && 0
MSHookFunction(&objc_registerClassPair, MSHake(objc_registerClassPair));
#endif
JSObjectRef Instance(JSObjectMakeConstructor(context, Instance_, &Instance_new));
JSObjectRef Message(JSObjectMakeConstructor(context, Message_, NULL));
JSObjectRef Selector(JSObjectMakeConstructor(context, Selector_, &Selector_new));
+ JSObjectRef StringInstance(JSObjectMakeConstructor(context, StringInstance_, NULL));
JSObjectRef Super(JSObjectMakeConstructor(context, Super_, &Super_new));
JSObjectRef Instance_prototype(CYCastJSObject(context, CYGetProperty(context, Instance, prototype_s)));
CYSetProperty(context, cy, CYJSString("Instance_prototype"), Instance_prototype);
+ JSObjectRef StringInstance_prototype(CYCastJSObject(context, CYGetProperty(context, StringInstance, prototype_s)));
+ CYSetProperty(context, cy, CYJSString("StringInstance_prototype"), StringInstance_prototype);
+
+ JSObjectRef String_prototype(CYGetCachedObject(context, CYJSString("String_prototype")));
+ JSObjectSetPrototype(context, StringInstance_prototype, String_prototype);
+
CYSetProperty(context, cycript, CYJSString("Instance"), Instance);
CYSetProperty(context, cycript, CYJSString("Selector"), Selector);
CYSetProperty(context, cycript, CYJSString("Super"), Super);
-#if defined(__APPLE__) && defined(__arm__)
+#if defined(__APPLE__) && defined(__arm__) && 0
CYSetProperty(context, all, CYJSString("objc_registerClassPair"), &objc_registerClassPair_, kJSPropertyAttributeDontEnum);
#endif