]> git.saurik.com Git - cycript.git/blobdiff - Execute.cpp
Disallow void values and support (void) arguments.
[cycript.git] / Execute.cpp
index bb337ba79a62728221794fd128f157563bcd7739..1f40626421d78f19366eb6ad874f584443fbe2e6 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
 {
@@ -369,7 +390,7 @@ _visible void CYGarbageCollect(JSContextRef context) {
 static JSValueRef Cycript_compile_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
     CYPool pool;
     CYUTF8String before(CYPoolUTF8String(pool, context, CYJSString(context, arguments[0])));
-    std::stringstream value(std::string(before.data, before.size));
+    std::stringbuf value(std::string(before.data, before.size));
     CYUTF8String after(CYPoolCode(pool, value));
     return CYCastJSValue(context, CYJSString(after));
 } CYCatch_(NULL, "SyntaxError") }
@@ -538,21 +559,6 @@ static JSValueRef Array_callAsFunction_toCYON(JSContextRef context, JSObjectRef
     return CYCastJSValue(context, CYJSString(CYUTF8String(value.c_str(), value.size())));
 } CYCatch(NULL) }
 
-static JSValueRef Error_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
-    CYPool pool;
-    std::ostringstream str;
-
-    str << "new " << CYPoolUTF8String(pool, context, CYJSString(context, CYGetProperty(context, _this, name_s))) << "(";
-
-    CYUTF8String string(CYPoolUTF8String(pool, context, CYJSString(context, CYGetProperty(context, _this, message_s))));
-    CYStringify(str, string.data, string.size);
-
-    str << ")";
-
-    std::string value(str.str());
-    return CYCastJSValue(context, CYJSString(CYUTF8String(value.c_str(), value.size())));
-} CYCatch(NULL) }
-
 static JSValueRef String_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
     CYPool pool;
     std::ostringstream str;
@@ -569,6 +575,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));
 }
@@ -602,6 +613,10 @@ void *CYCastPointer_(JSContextRef context, JSValueRef value) {
             return NULL;
         case kJSTypeObject: {
             JSObjectRef object((JSObjectRef) value);
+            if (JSValueIsObjectOfClass(context, value, CString_)) {
+                CString *internal(reinterpret_cast<CString *>(JSObjectGetPrivate(object)));
+                return internal->value_;
+            }
             if (JSValueIsObjectOfClass(context, value, Pointer_)) {
                 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
                 return internal->value_;
@@ -748,8 +763,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:
@@ -848,6 +863,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_);
@@ -1159,6 +1200,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");
@@ -1175,11 +1223,46 @@ static JSObjectRef Pointer_new(JSContextRef context, JSObjectRef object, size_t
 } CYCatch(NULL) }
 
 static JSObjectRef Type_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 Type constructor");
     CYPool pool;
-    const char *type(CYPoolCString(pool, context, arguments[0]));
-    return CYMakeType(context, type);
+
+    if (false) {
+    } else if (count == 1) {
+        const char *type(CYPoolCString(pool, context, arguments[0]));
+        return CYMakeType(context, type);
+    } else if (count == 2) {
+        JSObjectRef types(CYCastJSObject(context, arguments[0]));
+        size_t count(CYArrayLength(context, types));
+
+        JSObjectRef names(CYCastJSObject(context, arguments[1]));
+
+        sig::Type type;
+        type.name = NULL;
+        type.flags = 0;
+
+        type.primitive = sig::struct_P;
+        type.data.signature.elements = new(pool) sig::Element[count];
+        type.data.signature.count = count;
+
+        for (size_t i(0); i != count; ++i) {
+            sig::Element &element(type.data.signature.elements[i]);
+            element.offset = _not(size_t);
+
+            JSValueRef name(CYArrayGet(context, names, i));
+            if (JSValueIsUndefined(context, name))
+                element.name = NULL;
+            else
+                element.name = CYPoolCString(pool, context, name);
+
+            JSObjectRef object(CYCastJSObject(context, CYArrayGet(context, types, i)));
+            _assert(JSValueIsObjectOfClass(context, object, Type_privateData::Class_));
+            Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
+            element.type = internal->type_;
+        }
+
+        return CYMakeType(context, &type);
+    } else {
+        throw CYJSError(context, "incorrect number of arguments to Type constructor");
+    }
 } CYCatch(NULL) }
 
 static JSValueRef Type_callAsFunction_$With(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], sig::Primitive primitive, JSValueRef *exception) { CYTry {
@@ -1432,10 +1515,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;
@@ -1446,11 +1544,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));
+    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_);
@@ -1492,6 +1624,20 @@ static JSValueRef Type_callAsFunction_toJSON(JSContextRef context, JSObjectRef o
     return Type_callAsFunction_toString(context, object, _this, count, arguments, exception);
 }
 
+static JSStaticFunction CString_staticFunctions[5] = {
+    {"toCYON", &CString_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {"toJSON", &CYValue_callAsFunction_toJSON, 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[4] = {
     {"toCYON", &Pointer_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {"toJSON", &CYValue_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
@@ -1663,6 +1809,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;
@@ -1770,7 +1925,23 @@ JSGlobalContextRef CYGetJSContext(JSContextRef context) {
     return reinterpret_cast<Context *>(JSObjectGetPrivate(CYCastJSObject(context, CYGetProperty(context, CYGetGlobalObject(context), cy_s))))->context_;
 }
 
-void *CYMapFile(const char *path, size_t *psize) {
+struct CYFile {
+    void *data_;
+    size_t size_;
+
+    CYFile(void *data, size_t size) :
+        data_(data),
+        size_(size)
+    {
+    }
+};
+
+static void CYFileExit(void *data) {
+    CYFile *file(reinterpret_cast<CYFile *>(data));
+    _syscall(munmap(file->data_, file->size_));
+}
+
+static void *CYPoolFile(CYPool &pool, const char *path, size_t *psize) {
     int fd(_syscall_(open(path, O_RDONLY), 1, ENOENT));
     if (fd == -1)
         return NULL;
@@ -1784,22 +1955,37 @@ void *CYMapFile(const char *path, size_t *psize) {
     void *base;
     _syscall(base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0));
 
+    CYFile *file(new (pool) CYFile(base, size));
+    pool.atexit(&CYFileExit, file);
+
     _syscall(close(fd));
     return base;
 }
 
-static JSValueRef require(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
-    _assert(count == 1);
-    CYPool pool;
+static CYUTF8String CYPoolFileUTF8String(CYPool &pool, const char *path) {
+    CYUTF8String data;
+    data.data = reinterpret_cast<char *>(CYPoolFile(pool, path, &data.size));
+    return data;
+}
 
+static const char *CYPoolLibraryPath(CYPool &pool) {
     Dl_info addr;
-    _assert(dladdr(reinterpret_cast<void *>(&require), &addr) != 0);
+    _assert(dladdr(reinterpret_cast<void *>(&CYPoolLibraryPath), &addr) != 0);
     char *lib(pool.strdup(addr.dli_fname));
 
     char *slash(strrchr(lib, '/'));
     _assert(slash != NULL);
     *slash = '\0';
 
+    return lib;
+}
+
+static JSValueRef require(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+    _assert(count == 1);
+    CYPool pool;
+
+    const char *lib(CYPoolLibraryPath(pool));
+
     CYJSString property("exports");
     JSObjectRef module;
 
@@ -1813,8 +1999,7 @@ static JSValueRef require(JSContextRef context, JSObjectRef object, JSObjectRef
     if (!JSValueIsUndefined(context, cache))
         module = CYCastJSObject(context, cache);
     else {
-        CYUTF8String code;
-        code.data = reinterpret_cast<char *>(CYMapFile(path, &code.size));
+        CYUTF8String code(CYPoolFileUTF8String(pool, path));
 
         if (code.data == NULL) {
             if (strchr(name, '/') == NULL && (
@@ -1836,7 +2021,7 @@ static JSValueRef require(JSContextRef context, JSObjectRef object, JSObjectRef
 
         std::stringstream wrap;
         wrap << "(function (exports, require, module) { " << code << "\n});";
-        code = CYPoolCode(pool, wrap);
+        code = CYPoolCode(pool, *wrap.rdbuf());
 
         JSValueRef value(_jsccall(JSEvaluateScript, context, CYJSString(code), NULL, NULL, 0));
         JSObjectRef function(CYCastJSObject(context, value));
@@ -1848,6 +2033,18 @@ static JSValueRef require(JSContextRef context, JSObjectRef object, JSObjectRef
     return CYGetProperty(context, module, property);
 } CYCatch(NULL) }
 
+static bool CYRunScript(JSGlobalContextRef context, const char *path) {
+    CYPool pool;
+    CYUTF8String code(CYPoolFileUTF8String(pool, path));
+    if (code.data == NULL)
+        return false;
+
+    CYStream stream(code.data, code.data + code.size);
+    code = CYPoolCode(pool, stream);
+    _jsccall(JSEvaluateScript, context, CYJSString(code), NULL, NULL, 0);
+    return true;
+}
+
 extern "C" void CYDestroyWeak(JSWeakObjectMapRef weak, void *data) {
 }
 
@@ -1875,9 +2072,6 @@ extern "C" void CYSetupContext(JSGlobalContextRef context) {
     JSObjectRef Error(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Error"))));
     CYSetProperty(context, cy, CYJSString("Error"), Error);
 
-    JSObjectRef Error_prototype(CYCastJSObject(context, CYGetProperty(context, Error, prototype_s)));
-    CYSetProperty(context, cy, CYJSString("Error_prototype"), Error_prototype);
-
     JSObjectRef Function(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Function"))));
     CYSetProperty(context, cy, CYJSString("Function"), Function);
 
@@ -1907,7 +2101,6 @@ extern "C" void CYSetupContext(JSGlobalContextRef context) {
 /* }}} */
 
     CYSetProperty(context, Array_prototype, toCYON_s, &Array_callAsFunction_toCYON, kJSPropertyAttributeDontEnum);
-    CYSetProperty(context, Error_prototype, toCYON_s, &Error_callAsFunction_toCYON, kJSPropertyAttributeDontEnum);
     CYSetProperty(context, String_prototype, toCYON_s, &String_callAsFunction_toCYON, kJSPropertyAttributeDontEnum);
 
     JSObjectRef cycript(JSObjectMake(context, NULL, NULL));
@@ -1915,6 +2108,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);
@@ -1966,6 +2163,8 @@ extern "C" void CYSetupContext(JSGlobalContextRef context) {
     if (CYBridgeEntry *entry = CYBridgeHash("1dlerror", 8))
         entry->cache_ = new cy::Functor(entry->value_, reinterpret_cast<void (*)()>(&dlerror));
 
+    CYRunScript(context, "libcycript.cy");
+
     for (CYHook *hook : GetHooks())
         if (hook->SetupContext != NULL)
             (*hook->SetupContext)(context);