]> git.saurik.com Git - cycript.git/blobdiff - Execute.cpp
Allow extern "C" {} and limit semicolon insertion.
[cycript.git] / Execute.cpp
index 8f36a455181321e2c01691d4984fbfbd83dde4a4..3d9d6c4c4f9a52b0308422d5d509ef48f0ee051a 100644 (file)
@@ -97,8 +97,19 @@ JSStringRef CYCopyJSString(JSStringRef value) {
 }
 
 JSStringRef CYCopyJSString(CYUTF8String value) {
-    // XXX: this is very wrong; it needs to convert to UTF16 and then create from there
-    return CYCopyJSString(value.data);
+    if (memchr(value.data, '\0', value.size) != NULL) {
+        CYPool pool;
+        return CYCopyJSString(pool.memdup(value.data, value.size));
+    } else if (value.data[value.size] != '\0') {
+        CYPool pool;
+        return CYCopyJSString(CYPoolUTF16String(pool, value));
+    } else {
+        return CYCopyJSString(value.data);
+    }
+}
+
+JSStringRef CYCopyJSString(CYUTF16String value) {
+    return JSStringCreateWithCharacters(value.data, value.size);
 }
 
 JSStringRef CYCopyJSString(JSContextRef context, JSValueRef value) {
@@ -133,6 +144,7 @@ size_t CYGetIndex(CYPool &pool, JSContextRef context, JSStringRef value) {
 
 static JSClassRef All_;
 static JSClassRef Context_;
+static JSClassRef CString_;
 JSClassRef Functor_;
 static JSClassRef Global_;
 static JSClassRef Pointer_;
@@ -215,6 +227,15 @@ struct Context :
     }
 };
 
+struct CString :
+    CYOwned
+{
+    CString(char *value, JSContextRef context, JSObjectRef owner) :
+        CYOwned(value, context, owner)
+    {
+    }
+};
+
 struct Pointer :
     CYOwned
 {
@@ -276,6 +297,7 @@ JSValueRef CYCastJSValue(JSContextRef context, double value) {
 
 #define CYCastJSValue_(Type_) \
     JSValueRef CYCastJSValue(JSContextRef context, Type_ value) { \
+        _assert(static_cast<Type_>(static_cast<double>(value)) == value); \
         return JSValueMakeNumber(context, static_cast<double>(value)); \
     }
 
@@ -554,6 +576,11 @@ JSObjectRef CYMakePointer(JSContextRef context, void *pointer, size_t length, si
     return JSObjectMake(context, Pointer_, internal);
 }
 
+JSObjectRef CYMakeCString(JSContextRef context, char *pointer, JSObjectRef owner) {
+    CString *internal(new CString(pointer, context, owner));
+    return JSObjectMake(context, CString_, internal);
+}
+
 static JSObjectRef CYMakeFunctor(JSContextRef context, void (*function)(), const sig::Signature &signature) {
     return JSObjectMake(context, Functor_, new cy::Functor(signature, function));
 }
@@ -579,7 +606,7 @@ static bool CYGetOffset(CYPool &pool, JSContextRef context, JSStringRef value, s
     return CYGetOffset(CYPoolCString(pool, context, value), index);
 }
 
-void *CYCastPointer_(JSContextRef context, JSValueRef value) {
+void *CYCastPointer_(JSContextRef context, JSValueRef value, bool *guess) {
     if (value == NULL)
         return NULL;
     else switch (JSValueGetType(context, value)) {
@@ -595,13 +622,21 @@ void *CYCastPointer_(JSContextRef context, JSValueRef value) {
             if (CYIsCallable(context, toPointer)) {
                 JSValueRef value(CYCallAsFunction(context, (JSObjectRef) toPointer, object, 0, NULL));
                 _assert(value != NULL);
-                return CYCastPointer_(context, value);
+                return CYCastPointer_(context, value, guess);
             }
         } default:
+            if (guess != NULL)
+                *guess = true;
+        case kJSTypeNumber:
             double number(CYCastDouble(context, value));
-            if (std::isnan(number))
+            if (!std::isnan(number))
+                return reinterpret_cast<void *>(static_cast<uintptr_t>(static_cast<long long>(number)));
+            if (guess == NULL)
                 throw CYJSError(context, "cannot convert value to pointer");
-            return reinterpret_cast<void *>(static_cast<uintptr_t>(static_cast<long long>(number)));
+            else {
+                *guess = true;
+                return NULL;
+            }
     }
 }
 
@@ -654,10 +689,12 @@ void CYPoolFFI(CYPool *pool, JSContextRef context, sig::Type *type, ffi_type *ff
             *reinterpret_cast<void **>(data) = CYCastPointer<void *>(context, value);
         break;
 
-        case sig::string_P:
-            _assert(pool != NULL);
-            *reinterpret_cast<const char **>(data) = CYPoolCString(*pool, context, value);
-        break;
+        case sig::string_P: {
+            bool guess(false);
+            *reinterpret_cast<const char **>(data) = CYCastPointer<const char *>(context, value, &guess);
+            if (guess && pool != NULL)
+                *reinterpret_cast<const char **>(data) = CYPoolCString(*pool, context, value);
+        } break;
 
         case sig::struct_P: {
             uint8_t *base(reinterpret_cast<uint8_t *>(data));
@@ -733,8 +770,8 @@ JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void
             else goto null;
 
         case sig::string_P:
-            if (char *utf8 = *reinterpret_cast<char **>(data))
-                return CYCastJSValue(context, utf8);
+            if (char *pointer = *reinterpret_cast<char **>(data))
+                return CYMakeCString(context, pointer, owner);
             else goto null;
 
         case sig::struct_P:
@@ -833,6 +870,32 @@ static JSObjectRef CYMakeFunctor(JSContextRef context, JSValueRef value, const s
     }
 }
 
+static JSValueRef CString_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
+    CYPool pool;
+    CString *internal(reinterpret_cast<CString *>(JSObjectGetPrivate(object)));
+    char *string(static_cast<char *>(internal->value_));
+
+    ssize_t offset;
+    if (!CYGetOffset(pool, context, property, offset))
+        return NULL;
+
+    return CYCastJSValue(context, CYJSString(CYUTF8String(&string[offset], 1)));
+} CYCatch(NULL) }
+
+static bool CString_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
+    CYPool pool;
+    CString *internal(reinterpret_cast<CString *>(JSObjectGetPrivate(object)));
+    char *string(static_cast<char *>(internal->value_));
+
+    ssize_t offset;
+    if (!CYGetOffset(pool, context, property, offset))
+        return false;
+
+    const char *data(CYPoolCString(pool, context, value));
+    string[offset] = *data;
+    return true;
+} CYCatch(false) }
+
 static bool Index_(CYPool &pool, JSContextRef context, Struct_privateData *internal, JSStringRef property, ssize_t &index, uint8_t *&base) {
     Type_privateData *typical(internal->type_);
     sig::Type *type(typical->type_);
@@ -1030,6 +1093,14 @@ static JSValueRef Functor_callAsFunction(JSContextRef context, JSObjectRef objec
     return CYCallFunction(pool, context, 0, NULL, count, arguments, false, &internal->signature_, &internal->cif_, internal->GetValue());
 } CYCatch(NULL) }
 
+static JSValueRef Pointer_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+    Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
+    if (internal->type_->type_->primitive != sig::function_P)
+        throw CYJSError(context, "cannot call a pointer to non-function");
+    JSObjectRef functor(CYCastJSObject(context, CYGetProperty(context, object, cyi_s)));
+    return CYCallAsFunction(context, functor, _this, count, arguments);
+} CYCatch(NULL) }
+
 JSObjectRef CYMakeType(JSContextRef context, const char *encoding) {
     Type_privateData *internal(new Type_privateData(encoding));
     return JSObjectMake(context, Type_privateData::Class_, internal);
@@ -1144,6 +1215,13 @@ static void All_getPropertyNames(JSContextRef context, JSObjectRef object, JSPro
         }
 }
 
+static JSObjectRef CString_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+    if (count != 1)
+        throw CYJSError(context, "incorrect number of arguments to CString constructor");
+    char *value(CYCastPointer<char *>(context, arguments[0]));
+    return CYMakeCString(context, value, NULL);
+} CYCatch(NULL) }
+
 static JSObjectRef Pointer_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
     if (count != 2)
         throw CYJSError(context, "incorrect number of arguments to Pointer constructor");
@@ -1427,6 +1505,38 @@ static JSObjectRef Functor_new(JSContextRef context, JSObjectRef object, size_t
     return CYMakeFunctor(context, arguments[0], signature);
 } CYCatch(NULL) }
 
+static JSValueRef CString_callAsFunction_toPointer(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+    CString *internal(reinterpret_cast<CString *>(JSObjectGetPrivate(_this)));
+
+    sig::Type type;
+    type.name = NULL;
+    type.flags = 0;
+
+    type.primitive = sig::char_P;
+    type.data.data.type = NULL;
+    type.data.data.size = 0;
+
+    return CYMakePointer(context, internal->value_, _not(size_t), &type, NULL, NULL);
+} CYCatch(NULL) }
+
+static JSValueRef Functor_callAsFunction_$cya(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+    CYPool pool;
+    cy::Functor *internal(reinterpret_cast<cy::Functor *>(JSObjectGetPrivate(_this)));
+
+    sig::Type type;
+    type.name = NULL;
+    type.flags = 0;
+
+    type.primitive = sig::function_P;
+    sig::Copy(pool, type.data.signature, internal->signature_);
+
+    return CYMakePointer(context, internal->value_, _not(size_t), &type, NULL, NULL);
+} CYCatch(NULL) }
+
+static JSValueRef Pointer_callAsFunction_toPointer(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+    return _this;
+} CYCatch(NULL) }
+
 static JSValueRef CYValue_callAsFunction_valueOf(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
     CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this)));
     return CYCastJSValue(context, reinterpret_cast<uintptr_t>(internal->value_));
@@ -1438,9 +1548,20 @@ static JSValueRef CYValue_callAsFunction_toJSON(JSContextRef context, JSObjectRe
 
 static JSValueRef CYValue_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
     CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this)));
-    char string[32];
-    sprintf(string, "%p", internal->value_);
-    return CYCastJSValue(context, string);
+    std::ostringstream str;
+    Dl_info info;
+    if (internal->value_ == NULL)
+        str << "NULL";
+    else if (dladdr(internal->value_, &info) == 0)
+        str << internal->value_;
+    else {
+        str << info.dli_sname;
+        off_t offset(static_cast<char *>(internal->value_) - static_cast<char *>(info.dli_saddr));
+        if (offset != 0)
+            str << "+0x" << std::hex << offset;
+    }
+    std::string value(str.str());
+    return CYCastJSValue(context, CYJSString(CYUTF8String(value.c_str(), value.size())));
 } CYCatch(NULL) }
 
 static JSValueRef Pointer_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
@@ -1452,10 +1573,25 @@ static JSValueRef Pointer_callAsFunction_toCYON(JSContextRef context, JSObjectRe
         JSObjectRef toCYON(CYCastJSObject(context, CYGetProperty(context, Array, toCYON_s)));
         return CYCallAsFunction(context, toCYON, _this, count, arguments);
     } else if (internal->type_->type_ == NULL) pointer: {
-        char string[32];
-        sprintf(string, "%p", internal->value_);
-        return CYCastJSValue(context, string);
-    } try {
+        CYLocalPool pool;
+        std::ostringstream str;
+
+        sig::Type type;
+        type.name = NULL;
+        type.flags = 0;
+
+        type.primitive = sig::pointer_P;
+        type.data.data.type = internal->type_->type_;
+        type.data.data.size = 0;
+
+        CYOptions options;
+        CYOutput output(*str.rdbuf(), options);
+        (new(pool) CYTypeExpression(Decode(pool, &type)))->Output(output, CYNoFlags);
+
+        str << "(" << internal->value_ << ")";
+        std::string value(str.str());
+        return CYCastJSValue(context, CYJSString(CYUTF8String(value.c_str(), value.size())));
+    } else try {
         JSValueRef value(CYGetProperty(context, _this, cyi_s));
         if (JSValueIsUndefined(context, value))
             goto pointer;
@@ -1466,11 +1602,45 @@ static JSValueRef Pointer_callAsFunction_toCYON(JSContextRef context, JSObjectRe
     }
 } CYCatch(NULL) }
 
+static JSValueRef CString_getProperty_length(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
+    CString *internal(reinterpret_cast<CString *>(JSObjectGetPrivate(object)));
+    char *string(static_cast<char *>(internal->value_));
+    return CYCastJSValue(context, strlen(string));
+} CYCatch(NULL) }
+
+static JSValueRef CString_getProperty_type(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
+    sig::Type type;
+    type.name = NULL;
+    type.flags = 0;
+
+    type.primitive = sig::char_P;
+    type.data.data.type = NULL;
+    type.data.data.size = 0;
+
+    return CYMakeType(context, &type);
+} CYCatch(NULL) }
+
 static JSValueRef Pointer_getProperty_type(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
     Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
     return CYMakeType(context, internal->type_->type_);
 } CYCatch(NULL) }
 
+static JSValueRef CString_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+    Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(_this)));
+    const char *string(static_cast<const char *>(internal->value_));
+    std::ostringstream str;
+    str << "&";
+    CYStringify(str, string, strlen(string), true);
+    std::string value(str.str());
+    return CYCastJSValue(context, CYJSString(CYUTF8String(value.c_str(), value.size())));
+} CYCatch(NULL) }
+
+static JSValueRef CString_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+    Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(_this)));
+    const char *string(static_cast<const char *>(internal->value_));
+    return CYCastJSValue(context, string);
+} CYCatch(NULL) }
+
 static JSValueRef Functor_getProperty_type(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
     cy::Functor *internal(reinterpret_cast<cy::Functor *>(JSObjectGetPrivate(object)));
     return CYMakeType(context, &internal->signature_);
@@ -1512,9 +1682,25 @@ static JSValueRef Type_callAsFunction_toJSON(JSContextRef context, JSObjectRef o
     return Type_callAsFunction_toString(context, object, _this, count, arguments, exception);
 }
 
-static JSStaticFunction Pointer_staticFunctions[4] = {
+static JSStaticFunction CString_staticFunctions[6] = {
+    {"toCYON", &CString_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"toJSON", &CYValue_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"toPointer", &CString_callAsFunction_toPointer, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"toString", &CString_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"valueOf", &CString_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {NULL, NULL, 0}
+};
+
+static JSStaticValue CString_staticValues[3] = {
+    {"length", &CString_getProperty_length, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"type", &CString_getProperty_type, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {NULL, NULL, NULL, 0}
+};
+
+static JSStaticFunction Pointer_staticFunctions[5] = {
     {"toCYON", &Pointer_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {"toJSON", &CYValue_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"toPointer", &Pointer_callAsFunction_toPointer, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {"valueOf", &CYValue_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {NULL, NULL, 0}
 };
@@ -1529,7 +1715,8 @@ static JSStaticFunction Struct_staticFunctions[2] = {
     {NULL, NULL, 0}
 };
 
-static JSStaticFunction Functor_staticFunctions[4] = {
+static JSStaticFunction Functor_staticFunctions[5] = {
+    {"$cya", &Functor_callAsFunction_$cya, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {"toCYON", &CYValue_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {"toJSON", &CYValue_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {"valueOf", &CYValue_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
@@ -1683,6 +1870,15 @@ void CYInitializeDynamic() {
     definition.finalize = &CYFinalize;
     Context_ = JSClassCreate(&definition);
 
+    definition = kJSClassDefinitionEmpty;
+    definition.className = "CString";
+    definition.staticFunctions = CString_staticFunctions;
+    definition.staticValues = CString_staticValues;
+    definition.getProperty = &CString_getProperty;
+    definition.setProperty = &CString_setProperty;
+    definition.finalize = &CYFinalize;
+    CString_ = JSClassCreate(&definition);
+
     definition = kJSClassDefinitionEmpty;
     definition.className = "Functor";
     definition.staticFunctions = cy::Functor::StaticFunctions;
@@ -1695,6 +1891,7 @@ void CYInitializeDynamic() {
     definition.className = "Pointer";
     definition.staticFunctions = Pointer_staticFunctions;
     definition.staticValues = Pointer_staticValues;
+    definition.callAsFunction = &Pointer_callAsFunction;
     definition.getProperty = &Pointer_getProperty;
     definition.setProperty = &Pointer_setProperty;
     definition.finalize = &CYFinalize;
@@ -1973,6 +2170,10 @@ extern "C" void CYSetupContext(JSGlobalContextRef context) {
     CYSetProperty(context, cycript, CYJSString("compile"), &Cycript_compile_callAsFunction);
     CYSetProperty(context, cycript, CYJSString("gc"), &Cycript_gc_callAsFunction);
 
+    JSObjectRef CString(JSObjectMakeConstructor(context, CString_, &CString_new));
+    CYSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, CString, prototype_s)), String_prototype);
+    CYSetProperty(context, cycript, CYJSString("CString"), CString);
+
     JSObjectRef Functor(JSObjectMakeConstructor(context, Functor_, &Functor_new));
     CYSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Functor, prototype_s)), Function_prototype);
     CYSetProperty(context, cycript, CYJSString("Functor"), Functor);