]> git.saurik.com Git - cycript.git/commitdiff
Further memory management improvements, fixed some weird vtable bugs with CYThis...
authorJay Freeman (saurik) <saurik@saurik.com>
Thu, 8 Oct 2009 19:44:38 +0000 (19:44 +0000)
committerJay Freeman (saurik) <saurik@saurik.com>
Thu, 8 Oct 2009 19:44:38 +0000 (19:44 +0000)
Application.cpp [new file with mode: 0644]
Application.mm [deleted file]
Bridge.def
Library.mm
Output.cpp
Parser.hpp
cycript.hpp
makefile

diff --git a/Application.cpp b/Application.cpp
new file mode 100644 (file)
index 0000000..ae638a6
--- /dev/null
@@ -0,0 +1,217 @@
+#define _GNU_SOURCE
+
+#include <substrate.h>
+#include "cycript.hpp"
+
+#include <cstdio>
+#include <sstream>
+
+#include <setjmp.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include <sys/mman.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "Cycript.tab.hh"
+
+static jmp_buf ctrlc_;
+
+void sigint(int) {
+    longjmp(ctrlc_, 1);
+}
+
+void Run(const char *code, FILE *fout) {
+    JSStringRef script(JSStringCreateWithUTF8CString(code));
+
+    JSContextRef context(CYGetJSContext());
+
+    JSValueRef exception(NULL);
+    JSValueRef result(JSEvaluateScript(context, script, NULL, NULL, 0, &exception));
+    JSStringRelease(script);
+
+    if (exception != NULL)
+        result = exception;
+
+    if (!JSValueIsUndefined(context, result)) {
+        CYPool pool;
+        const char *json;
+
+        json = CYPoolJSONString(pool, context, result);
+
+        if (fout != NULL) {
+            fputs(json, fout);
+            fputs("\n", fout);
+            fflush(fout);
+        }
+    }
+}
+
+void Console() {
+    bool bypass(false);
+    bool debug(false);
+
+    FILE *fout(stdout);
+
+    rl_bind_key('\t', rl_insert);
+
+    struct sigaction action;
+    sigemptyset(&action.sa_mask);
+    action.sa_handler = &sigint;
+    action.sa_flags = 0;
+    sigaction(SIGINT, &action, NULL);
+
+    restart: for (;;) {
+        std::string command;
+        std::vector<std::string> lines;
+
+        bool extra(false);
+        const char *prompt("cy# ");
+
+        if (setjmp(ctrlc_) != 0) {
+            fputs("\n", fout);
+            fflush(fout);
+            goto restart;
+        }
+
+      read:
+        char *line(readline(prompt));
+        if (line == NULL)
+            break;
+
+        if (!extra) {
+            extra = true;
+            if (line[0] == '\\') {
+                std::string data(line + 1);
+                if (data == "bypass") {
+                    bypass = !bypass;
+                    fprintf(fout, "bypass == %s\n", bypass ? "true" : "false");
+                    fflush(fout);
+                } else if (data == "debug") {
+                    debug = !debug;
+                    fprintf(fout, "debug == %s\n", debug ? "true" : "false");
+                    fflush(fout);
+                }
+                add_history(line);
+                goto restart;
+            }
+        }
+
+        lines.push_back(line);
+        command += line;
+        free(line);
+
+        std::string code;
+
+        if (bypass)
+            code = command;
+        else {
+            CYDriver driver("");
+            cy::parser parser(driver);
+
+            driver.data_ = command.c_str();
+            driver.size_ = command.size();
+
+            if (parser.parse() != 0 || !driver.errors_.empty()) {
+                for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i) {
+                    cy::position begin(i->location_.begin);
+                    if (begin.line != lines.size() || begin.column - 1 != lines.back().size()) {
+                        std::cerr << i->message_ << std::endl;
+                        add_history(command.c_str());
+                        goto restart;
+                    }
+                }
+
+                driver.errors_.clear();
+
+                command += '\n';
+                prompt = "cy> ";
+                goto read;
+            }
+
+            if (driver.source_ == NULL)
+                goto restart;
+
+            std::ostringstream str;
+            driver.source_->Show(str);
+            code = str.str();
+        }
+
+        add_history(command.c_str());
+
+        if (debug)
+            std::cout << code << std::endl;
+
+        Run(code.c_str(), fout);
+    }
+
+    fputs("\n", fout);
+    fflush(fout);
+}
+
+void *Map(const char *path, size_t *psize) {
+    int fd;
+    _syscall(fd = open(path, O_RDONLY));
+
+    struct stat stat;
+    _syscall(fstat(fd, &stat));
+    size_t size(stat.st_size);
+
+    *psize = size;
+
+    void *base;
+    _syscall(base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0));
+
+    _syscall(close(fd));
+    return base;
+}
+
+int main(int argc, const char *argv[]) {
+    const char *script;
+
+    if (argc == 1)
+        script = NULL;
+    else {
+        CYSetArgs(argc - 1, argv + 1);
+        script = argv[1];
+    }
+
+    if (script == NULL || strcmp(script, "-") == 0)
+        Console();
+    else {
+        CYDriver driver(script);
+        cy::parser parser(driver);
+
+        size_t size;
+        char *start(reinterpret_cast<char *>(Map(script, &size)));
+        char *end(start + size);
+
+        if (size >= 2 && start[0] == '#' && start[1] == '!') {
+            start += 2;
+            while (start != end && *start++ != '\n');
+        }
+
+        driver.data_ = start;
+        driver.size_ = end - start;
+
+        if (parser.parse() != 0 || !driver.errors_.empty()) {
+            for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i)
+                std::cerr << i->location_.begin << ": " << i->message_ << std::endl;
+        } else if (driver.source_ != NULL) {
+            std::ostringstream str;
+            driver.source_->Show(str);
+            std::string code(str.str());
+            std::cout << code << std::endl;
+            Run(code.c_str(), stdout);
+        }
+    }
+
+    return 0;
+}
diff --git a/Application.mm b/Application.mm
deleted file mode 100644 (file)
index aaf1d5e..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-#define _GNU_SOURCE
-
-#include <substrate.h>
-#include "cycript.hpp"
-
-#include <cstdio>
-#include <sstream>
-
-#include <setjmp.h>
-
-#include <readline/readline.h>
-#include <readline/history.h>
-
-#include <sys/mman.h>
-
-#include <errno.h>
-#include <unistd.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "Cycript.tab.hh"
-
-static jmp_buf ctrlc_;
-
-void sigint(int) {
-    longjmp(ctrlc_, 1);
-}
-
-void Run(const char *code, FILE *fout) { _pooled
-    JSStringRef script(JSStringCreateWithUTF8CString(code));
-
-    JSContextRef context(CYGetJSContext());
-
-    JSValueRef exception(NULL);
-    JSValueRef result(JSEvaluateScript(context, script, NULL, NULL, 0, &exception));
-    JSStringRelease(script);
-
-    if (exception != NULL)
-        result = exception;
-
-    if (!JSValueIsUndefined(context, result)) {
-        CFStringRef json;
-
-        @try { json:
-            json = CYCopyJSONString(context, result);
-        } @catch (id error) {
-            CYThrow(context, error, &result);
-            goto json;
-        }
-
-        if (fout != NULL) {
-            fputs([reinterpret_cast<const NSString *>(json) UTF8String], fout);
-            fputs("\n", fout);
-            fflush(fout);
-        }
-
-        CFRelease(json);
-    }
-}
-
-void Console() {
-    bool bypass(false);
-    bool debug(false);
-
-    FILE *fout(stdout);
-
-    rl_bind_key('\t', rl_insert);
-
-    struct sigaction action;
-    sigemptyset(&action.sa_mask);
-    action.sa_handler = &sigint;
-    action.sa_flags = 0;
-    sigaction(SIGINT, &action, NULL);
-
-    restart: for (;;) {
-        std::string command;
-        std::vector<std::string> lines;
-
-        bool extra(false);
-        const char *prompt("cy# ");
-
-        if (setjmp(ctrlc_) != 0) {
-            fputs("\n", fout);
-            fflush(fout);
-            goto restart;
-        }
-
-      read:
-        char *line(readline(prompt));
-        if (line == NULL)
-            break;
-
-        if (!extra) {
-            extra = true;
-            if (line[0] == '\\') {
-                std::string data(line + 1);
-                if (data == "bypass") {
-                    bypass = !bypass;
-                    fprintf(fout, "bypass == %s\n", bypass ? "true" : "false");
-                    fflush(fout);
-                } else if (data == "debug") {
-                    debug = !debug;
-                    fprintf(fout, "debug == %s\n", debug ? "true" : "false");
-                    fflush(fout);
-                }
-                add_history(line);
-                goto restart;
-            }
-        }
-
-        lines.push_back(line);
-        command += line;
-        free(line);
-
-        std::string code;
-
-        if (bypass)
-            code = command;
-        else {
-            CYDriver driver("");
-            cy::parser parser(driver);
-
-            driver.data_ = command.c_str();
-            driver.size_ = command.size();
-
-            if (parser.parse() != 0 || !driver.errors_.empty()) {
-                for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i) {
-                    cy::position begin(i->location_.begin);
-                    if (begin.line != lines.size() || begin.column - 1 != lines.back().size()) {
-                        std::cerr << i->message_ << std::endl;
-                        add_history(command.c_str());
-                        goto restart;
-                    }
-                }
-
-                driver.errors_.clear();
-
-                command += '\n';
-                prompt = "cy> ";
-                goto read;
-            }
-
-            if (driver.source_ == NULL)
-                goto restart;
-
-            std::ostringstream str;
-            driver.source_->Show(str);
-            code = str.str();
-        }
-
-        add_history(command.c_str());
-
-        if (debug)
-            std::cout << code << std::endl;
-
-        Run(code.c_str(), fout);
-    }
-
-    fputs("\n", fout);
-    fflush(fout);
-}
-
-void *Map(const char *path, size_t *psize) {
-    int fd;
-    _syscall(fd = open(path, O_RDONLY));
-
-    struct stat stat;
-    _syscall(fstat(fd, &stat));
-    size_t size(stat.st_size);
-
-    *psize = size;
-
-    void *base;
-    _syscall(base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0));
-
-    _syscall(close(fd));
-    return base;
-}
-
-int main(int argc, const char *argv[]) {
-    const char *script;
-
-    if (argc == 1)
-        script = NULL;
-    else {
-        CYSetArgs(argc - 1, argv + 1);
-        script = argv[1];
-    }
-
-    if (script == NULL || strcmp(script, "-") == 0)
-        Console();
-    else {
-        CYDriver driver(script);
-        cy::parser parser(driver);
-
-        size_t size;
-        char *start(reinterpret_cast<char *>(Map(script, &size)));
-        char *end(start + size);
-
-        if (size >= 2 && start[0] == '#' && start[1] == '!') {
-            start += 2;
-            while (start != end && *start++ != '\n');
-        }
-
-        driver.data_ = start;
-        driver.size_ = end - start;
-
-        if (parser.parse() != 0 || !driver.errors_.empty()) {
-            for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i)
-                std::cerr << i->location_.begin << ": " << i->message_ << std::endl;
-        } else if (driver.source_ != NULL) {
-            std::ostringstream str;
-            driver.source_->Show(str);
-            std::string code(str.str());
-            std::cout << code << std::endl;
-            Run(code.c_str(), stdout);
-        }
-    }
-
-    return 0;
-}
index cea22845261efdd6e62554993a6799c7d51377d6..5dea275336b69366a5d825e5e0446bd3f03c70a1 100644 (file)
@@ -507,4 +507,4 @@ C MKPinAnnotationColorPurple 2
 # MKCoordinateRegionMakeWithDistance
 # MKCoordinateSpanMake
 
-: applicationDidFinishLaunching: v@
+: applicationDidFinishLaunching: v@:@
index 574d944a8e03881910002045ce861daf8b6eb8d1..4213e5bc34a39123ab6aa851c985098ecb07df0c 100644 (file)
@@ -82,7 +82,7 @@
     CFLog(kCFLogLevelNotice, CFSTR("_trace():%u"), __LINE__); \
 } while (false)
 
-static JSContextRef Context_;
+static JSGlobalContextRef Context_;
 static JSObjectRef System_;
 
 static JSClassRef Functor_;
@@ -106,8 +106,96 @@ struct Client {
     CFSocketRef socket_;
 };
 
-JSObjectRef CYMakeInstance(JSContextRef context, id object) {
-    return JSObjectMake(context, Instance_, object);
+struct ptrData {
+    apr_pool_t *pool_;
+    void *value_;
+    sig::Type type_;
+
+    void *operator new(size_t size) {
+        apr_pool_t *pool;
+        apr_pool_create(&pool, NULL);
+        void *data(apr_palloc(pool, size));
+        reinterpret_cast<ptrData *>(data)->pool_ = pool;
+        return data;;
+    }
+
+    ptrData(void *value) :
+        value_(value)
+    {
+    }
+
+    virtual ~ptrData() {
+    }
+};
+
+struct ffiData : ptrData {
+    sig::Signature signature_;
+    ffi_cif cif_;
+
+    ffiData(const char *type, void (*value)()) :
+        ptrData(reinterpret_cast<void *>(value))
+    {
+        sig::Parse(pool_, &signature_, type);
+        sig::sig_ffi_cif(pool_, &sig::ObjectiveC, &signature_, &cif_);
+    }
+};
+
+struct ffoData : ffiData {
+    JSContextRef context_;
+    JSObjectRef function_;
+
+    ffoData(const char *type) :
+        ffiData(type, NULL)
+    {
+    }
+};
+
+struct selData : ptrData {
+    selData(SEL value) :
+        ptrData(value)
+    {
+    }
+
+    SEL GetValue() const {
+        return reinterpret_cast<SEL>(value_);
+    }
+};
+
+struct jocData : ptrData {
+    bool transient_;
+
+    jocData(id value, bool transient) :
+        ptrData(value)
+    {
+    }
+
+    virtual ~jocData() {
+        if (!transient_)
+            [GetValue() release];
+    }
+
+    id GetValue() const {
+        return reinterpret_cast<id>(value_);
+    }
+};
+
+JSObjectRef CYMakeInstance(JSContextRef context, id object, bool transient = true) {
+    if (!transient)
+        object = [object retain];
+    jocData *data(new jocData(object, transient));
+    return JSObjectMake(context, Instance_, data);
+}
+
+const char *CYPoolCString(apr_pool_t *pool, NSString *value) {
+    if (pool == NULL)
+        return [value UTF8String];
+    else {
+        size_t size([value maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1);
+        char *string(new(pool) char[size]);
+        if (![value getCString:string maxLength:size encoding:NSUTF8StringEncoding])
+            @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"[NSString getCString:maxLength:encoding:] == NO" userInfo:nil];
+        return string;
+    }
 }
 
 JSValueRef CYCastJSValue(JSContextRef context, bool value) {
@@ -184,6 +272,14 @@ JSValueRef CYJSUndefined(JSContextRef context) {
 
 @end
 
+@implementation NSNull (Cycript)
+
+- (NSString *) cy$toJSON {
+    return @"null";
+}
+
+@end
+
 @implementation NSArray (Cycript)
 
 - (NSString *) cy$toJSON {
@@ -268,7 +364,8 @@ JSValueRef CYJSUndefined(JSContextRef context) {
 }
 
 - (void *) cy$symbol {
-    return dlsym(RTLD_DEFAULT, [self UTF8String]);
+    CYPool pool;
+    return dlsym(RTLD_DEFAULT, CYPoolCString(pool, self));
 }
 
 @end
@@ -303,7 +400,7 @@ JSValueRef CYJSUndefined(JSContextRef context) {
 CYRange WordStartRange_(0x1000000000LLU,0x7fffffe87fffffeLLU); // A-Za-z_$
 CYRange WordEndRange_(0x3ff001000000000LLU,0x7fffffe87fffffeLLU); // A-Za-z_$0-9
 
-JSContextRef CYGetJSContext() {
+JSGlobalContextRef CYGetJSContext() {
     return Context_;
 }
 
@@ -332,8 +429,11 @@ id CYPoolRelease(apr_pool_t *pool, id object) {
 }
 
 id CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSObjectRef object) {
-    if (JSValueIsObjectOfClass(context, object, Instance_))
-        return reinterpret_cast<id>(JSObjectGetPrivate(object));
+    if (JSValueIsObjectOfClass(context, object, Instance_)) {
+        jocData *data(reinterpret_cast<jocData *>(JSObjectGetPrivate(object)));
+        return data->GetValue();
+    }
+
     JSValueRef exception(NULL);
     bool array(JSValueIsInstanceOfConstructor(context, object, Array_, &exception));
     CYThrow(context, exception);
@@ -568,7 +668,7 @@ void CYThrow(JSContextRef context, id error, JSValueRef *exception) {
 }
 
 - (id) objectForKey:(id)key {
-    return CYCastNSObject(NULL, context_, CYGetProperty(context_, object_, CYJSString(key)));
+    return CYCastNSObject(NULL, context_, CYGetProperty(context_, object_, CYJSString(key))) ?: [NSNull null];
 }
 
 - (NSEnumerator *) keyEnumerator {
@@ -608,17 +708,23 @@ void CYThrow(JSContextRef context, id error, JSValueRef *exception) {
     JSValueRef exception(NULL);
     JSValueRef value(JSObjectGetPropertyAtIndex(context_, object_, index, &exception));
     CYThrow(context_, exception);
-    id object(CYCastNSObject(NULL, context_, value));
-    return object == nil ? [NSNull null] : object;
+    return CYCastNSObject(NULL, context_, value) ?: [NSNull null];
 }
 
 @end
 
-CFStringRef CYCopyJSONString(JSContextRef context, JSValueRef value) {
+CFStringRef CYCopyJSONString(JSContextRef context, JSValueRef value) { _pooled
     id object(CYCastNSObject(NULL, context, value));
     return reinterpret_cast<CFStringRef>([(object == nil ? @"null" : [object cy$toJSON]) retain]);
 }
 
+const char *CYPoolJSONString(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
+    NSString *json((NSString *) CYCopyJSONString(context, value));
+    const char *string(CYPoolCString(pool, json));
+    [json release];
+    return string;
+}
+
 static void OnData(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *value, void *info) {
     switch (type) {
         case kCFSocketDataCallBack:
@@ -719,57 +825,13 @@ static bool Instance_deleteProperty(JSContextRef context, JSObjectRef object, JS
     } CYCatch
 }
 
-typedef id jocData;
-
 static JSObjectRef Instance_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
     @try {
-        id data(reinterpret_cast<jocData>(JSObjectGetPrivate(object)));
-        return CYMakeInstance(context, [data alloc]);
+        jocData *data(reinterpret_cast<jocData *>(JSObjectGetPrivate(object)));
+        return CYMakeInstance(context, [data->GetValue() alloc]);
     } CYCatch
 }
 
-struct ptrData {
-    apr_pool_t *pool_;
-    void *value_;
-    sig::Type type_;
-
-    void *operator new(size_t size) {
-        apr_pool_t *pool;
-        apr_pool_create(&pool, NULL);
-        void *data(apr_palloc(pool, size));
-        reinterpret_cast<ptrData *>(data)->pool_ = pool;
-        return data;;
-    }
-
-    ptrData(void *value) :
-        value_(value)
-    {
-    }
-};
-
-struct ffiData : ptrData {
-    sig::Signature signature_;
-    ffi_cif cif_;
-
-    ffiData(const char *type, void (*value)() = NULL) :
-        ptrData(reinterpret_cast<void *>(value))
-    {
-        sig::Parse(pool_, &signature_, type);
-        sig::sig_ffi_cif(pool_, &sig::ObjectiveC, &signature_, &cif_);
-    }
-};
-
-struct selData : ptrData {
-    selData(SEL value) :
-        ptrData(value)
-    {
-    }
-
-    SEL GetValue() const {
-        return reinterpret_cast<SEL>(value_);
-    }
-};
-
 JSObjectRef CYMakeSelector(JSContextRef context, SEL sel) {
     selData *data(new selData(sel));
     return JSObjectMake(context, Selector_, data);
@@ -782,48 +844,27 @@ JSObjectRef CYMakePointer(JSContextRef context, void *pointer) {
 
 static void Pointer_finalize(JSObjectRef object) {
     ptrData *data(reinterpret_cast<ptrData *>(JSObjectGetPrivate(object)));
+    data->~ptrData();
     apr_pool_destroy(data->pool_);
 }
 
-/*static void Instance_finalize(JSObjectRef object) {
-    id data(reinterpret_cast<jocData>(JSObjectGetPrivate(object)));
-}*/
-
 JSObjectRef CYMakeFunctor(JSContextRef context, void (*function)(), const char *type) {
     ffiData *data(new ffiData(type, function));
     return JSObjectMake(context, Functor_, data);
 }
 
-void Closure_(ffi_cif *cif, void *result, void **arguments, void *arg) {
-}
-
-JSObjectRef CYMakeFunctor(JSContextRef context, JSObjectRef function, const char *type) {
-    // XXX: in case of exceptions this will leak
-    ffiData *data(new ffiData(type));
-
-    ffi_closure *closure;
-    _syscall(closure = (ffi_closure *) mmap(
-        NULL, sizeof(ffi_closure),
-        PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
-        -1, 0
-    ));
-
-    ffi_status status(ffi_prep_closure(closure, &data->cif_, &Closure_, data));
-    _assert(status == FFI_OK);
-
-    _syscall(mprotect(closure, sizeof(*closure), PROT_READ | PROT_EXEC));
-
-    return JSObjectMake(context, Functor_, data);
-}
-
-char *CYPoolCString(apr_pool_t *pool, JSStringRef value) {
-    size_t size(JSStringGetMaximumUTF8CStringSize(value));
-    char *string(new(pool) char[size]);
-    JSStringGetUTF8CString(value, string, size);
-    return string;
+const char *CYPoolCString(apr_pool_t *pool, JSStringRef value) {
+    if (pool == NULL)
+        return [CYCastNSString(NULL, value) UTF8String];
+    else {
+        size_t size(JSStringGetMaximumUTF8CStringSize(value));
+        char *string(new(pool) char[size]);
+        JSStringGetUTF8CString(value, string, size);
+        return string;
+    }
 }
 
-char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
+const char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
     if (JSValueIsNull(context, value))
         return NULL;
     return CYPoolCString(pool, CYJSString(context, value));
@@ -834,13 +875,13 @@ char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
     char *utf8; \
     if (value == NULL) \
         utf8 = NULL; \
-    else { \
-        JSStringRef string(CYCopyJSString(context, value)); \
+    else if (JSStringRef string = CYCopyJSString(context, value)) { \
         size_t size(JSStringGetMaximumUTF8CStringSize(string)); \
         utf8 = reinterpret_cast<char *>(alloca(size)); \
         JSStringGetUTF8CString(string, utf8, size); \
         JSStringRelease(string); \
-    } \
+    } else \
+        utf8 = NULL; \
     utf8; \
 })
 
@@ -913,7 +954,7 @@ void CYPoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, void *da
         break;
 
         case sig::string_P:
-            *reinterpret_cast<char **>(data) = CYPoolCString(pool, context, value);
+            *reinterpret_cast<const char **>(data) = CYPoolCString(pool, context, value);
         break;
 
         case sig::struct_P:
@@ -1021,6 +1062,49 @@ static JSValueRef CYCallFunction(JSContextRef context, size_t count, const JSVal
     } CYCatch
 }
 
+void Closure_(ffi_cif *cif, void *result, void **arguments, void *arg) {
+    NSLog(@"Closure()");
+    ffoData *data(reinterpret_cast<ffoData *>(arg));
+
+    JSContextRef context(data->context_);
+
+    size_t count(data->cif_.nargs);
+    JSValueRef values[count];
+
+    for (size_t index(0); index != count; ++index)
+        values[index] = CYFromFFI(context, data->signature_.elements[1 + index].type, arguments[index]);
+
+    JSValueRef exception(NULL);
+    JSValueRef value(JSObjectCallAsFunction(context, data->function_, NULL, count, values, &exception));
+    CYThrow(context, exception);
+
+    CYPoolFFI(NULL, context, data->signature_.elements[0].type, result, value);
+}
+
+JSObjectRef CYMakeFunctor(JSContextRef context, JSObjectRef function, const char *type) {
+    // XXX: in case of exceptions this will leak
+    ffoData *data(new ffoData(type));
+
+    ffi_closure *closure;
+    _syscall(closure = (ffi_closure *) mmap(
+        NULL, sizeof(ffi_closure),
+        PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
+        -1, 0
+    ));
+
+    ffi_status status(ffi_prep_closure(closure, &data->cif_, &Closure_, data));
+    _assert(status == FFI_OK);
+
+    _syscall(mprotect(closure, sizeof(*closure), PROT_READ | PROT_EXEC));
+
+    data->value_ = closure;
+
+    data->context_ = CYGetJSContext();
+    data->function_ = function;
+
+    return JSObjectMake(context, Functor_, data);
+}
+
 static JSValueRef Global_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
     @try {
         CYPool pool;
@@ -1032,11 +1116,10 @@ static JSValueRef Global_getProperty(JSContextRef context, JSObjectRef object, J
                 case 0:
                     return JSEvaluateScript(CYGetJSContext(), CYJSString([entry objectAtIndex:1]), NULL, NULL, 0, NULL);
                 case 1:
-                    return CYMakeFunctor(context, reinterpret_cast<void (*)()>([name cy$symbol]), [[entry objectAtIndex:1] UTF8String]);
+                    return CYMakeFunctor(context, reinterpret_cast<void (*)()>([name cy$symbol]), CYPoolCString(pool, [entry objectAtIndex:1]));
                 case 2:
-                    CYPool pool;
                     sig::Signature signature;
-                    sig::Parse(pool, &signature, [[entry objectAtIndex:1] UTF8String]);
+                    sig::Parse(pool, &signature, CYPoolCString(pool, [entry objectAtIndex:1]));
                     return CYFromFFI(context, signature.elements[0].type, [name cy$symbol]);
             }
         return NULL;
@@ -1067,10 +1150,11 @@ static JSValueRef CYApplicationMain(JSContextRef context, JSObjectRef object, JS
     @try {
         CYPool pool;
         NSString *name(CYCastNSObject(pool, context, arguments[0]));
-        int argc(*_NSGetArgc() - 1);
-        char **argv(*_NSGetArgv() + 1);
+        int argc(*_NSGetArgc());
+        char **argv(*_NSGetArgv());
         for (int i(0); i != argc; ++i)
             NSLog(@"argv[%i]=%s", i, argv[i]);
+        _pooled
         return CYCastJSValue(context, UIApplicationMain(argc, argv, name, name));
     } CYCatch
 }
@@ -1078,26 +1162,29 @@ static JSValueRef CYApplicationMain(JSContextRef context, JSObjectRef object, JS
 static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
     const char *type;
 
+    CYPool pool;
+
     @try {
         if (count < 2)
             @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"too few arguments to objc_msgSend" userInfo:nil];
 
-        CYPool pool;
-
         id self(CYCastNSObject(pool, context, arguments[0]));
         if (self == nil)
             return CYJSNull(context);
 
         SEL _cmd(CYCastSEL(context, arguments[1]));
-        NSMethodSignature *method([self methodSignatureForSelector:_cmd]);
-        if (method == nil)
-            @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"unrecognized selector %s sent to object %p", sel_getName(_cmd), self] userInfo:nil];
 
-        type = [[method _typeString] UTF8String];
+        Class _class(object_getClass(self));
+        if (Method method = class_getInstanceMethod(_class, _cmd))
+            type = method_getTypeEncoding(method);
+        else { _pooled
+            NSMethodSignature *method([self methodSignatureForSelector:_cmd]);
+            if (method == nil)
+                @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"unrecognized selector %s sent to object %p", sel_getName(_cmd), self] userInfo:nil];
+            type = CYPoolCString(pool, [method _typeString]);
+        }
     } CYCatch
 
-    CYPool pool;
-
     sig::Signature signature;
     sig::Parse(pool, &signature, type);
 
@@ -1157,6 +1244,20 @@ JSValueRef Selector_getProperty_prototype(JSContextRef context, JSObjectRef obje
     return Function_;
 }
 
+static JSValueRef Instance_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { _pooled
+    @try {
+        jocData *data(reinterpret_cast<jocData *>(JSObjectGetPrivate(_this)));
+        return CYCastJSValue(context, CYJSString([data->GetValue() description]));
+    } CYCatch
+}
+
+static JSValueRef Selector_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+    @try {
+        selData *data(reinterpret_cast<selData *>(JSObjectGetPrivate(_this)));
+        return CYCastJSValue(context, sel_getName(data->GetValue()));
+    } CYCatch
+}
+
 static JSValueRef Selector_callAsFunction_type(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
     @try {
         if (count != 2)
@@ -1168,7 +1269,7 @@ static JSValueRef Selector_callAsFunction_type(JSContextRef context, JSObjectRef
         SEL sel(data->GetValue());
         if (Method method = (*(instance ? &class_getInstanceMethod : class_getClassMethod))(_class, sel))
             return CYCastJSValue(context, method_getTypeEncoding(method));
-        else if (NSString *type = [Bridge_ objectForKey:[NSString stringWithFormat:@":%s", sel_getName(sel)]])
+        else if (NSString *type = [Bridge_ objectForKey:CYPoolRelease(pool, [[NSString alloc] initWithFormat:@":%s", sel_getName(sel)])])
             return CYCastJSValue(context, CYJSString(type));
         else
             return CYJSNull(context);
@@ -1185,7 +1286,13 @@ static JSStaticValue Pointer_staticValues[2] = {
     {NULL, NULL, NULL, 0}
 };*/
 
-static JSStaticFunction Selector_staticFunctions[2] = {
+static JSStaticFunction Instance_staticFunctions[2] = {
+    {"toString", &Instance_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+    {NULL, NULL, 0}
+};
+
+static JSStaticFunction Selector_staticFunctions[3] = {
+    {"toString", &Selector_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {"type", &Selector_callAsFunction_type, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {NULL, NULL, 0}
 };
@@ -1270,18 +1377,19 @@ MSInitialize { _pooled
 
     definition = kJSClassDefinitionEmpty;
     definition.className = "Instance";
+    definition.parentClass = Pointer_;
+    definition.staticFunctions = Instance_staticFunctions;
     definition.getProperty = &Instance_getProperty;
     definition.setProperty = &Instance_setProperty;
     definition.deleteProperty = &Instance_deleteProperty;
     definition.callAsConstructor = &Instance_callAsConstructor;
-    //definition.finalize = &Instance_finalize;
     Instance_ = JSClassCreate(&definition);
 
     definition = kJSClassDefinitionEmpty;
     definition.getProperty = &Global_getProperty;
     JSClassRef Global(JSClassCreate(&definition));
 
-    JSContextRef context(JSGlobalContextCreate(Global));
+    JSGlobalContextRef context(JSGlobalContextCreate(Global));
     Context_ = context;
 
     JSObjectRef global(JSContextGetGlobalObject(context));
index a35ab818232858c3ca9958f3cf4bc4c24ff419e2..5e0d6ef9c9e90a415a7b1bd713fd5a837159f007 100644 (file)
@@ -224,18 +224,18 @@ void CYExpression::Part(std::ostream &out) const {
 
 void CYCompound::Output(std::ostream &out, CYFlags flags) const {
     if (CYExpression *expression = expressions_)
-        if (CYExpression *next = expression->next_)
-            expression->Output(out, flags);
-        else {
+        if (CYExpression *next = expression->next_) {
             expression->Output(out, CYLeft(flags));
             CYFlags center(CYCenter(flags));
             while (next != NULL) {
+                expression = next;
                 out << ',';
                 next = expression->next_;
                 CYFlags right(next != NULL ? center : CYRight(flags));
                 expression->Output(out, right);
             }
-        }
+        } else
+            expression->Output(out, flags);
 }
 
 void CYExpression::Output(std::ostream &out, unsigned precedence, CYFlags flags) const {
@@ -363,20 +363,14 @@ void CYMessage::Output(std::ostream &out) const {
     out << "\");";
     out << "$cyt=$cyn.type($cys," << (instance_ ? "true" : "false") << ");";
     out << "class_addMethod($cy" << (instance_ ? 'c' : 'm') << ",$cyn,";
-    out << "new Functor(function(";
-    bool comma(false);
+    out << "new Functor(function(self,_cmd";
     for (CYMessageParameter *parameter(parameter_); parameter != NULL; parameter = parameter->next_)
-        if (parameter->name_ != NULL) {
-            if (comma)
-                out << ',';
-            else
-                comma = true;
-            out << *parameter->name_;
-        }
-    out << "){";
+        if (parameter->name_ != NULL)
+            out << ',' << *parameter->name_;
+    out << "){return function(){";
     if (body_ != NULL)
         body_->Show(out);
-    out << "},$cyt),$cyt);";
+    out << "}.call(self);},$cyt),$cyt);";
 }
 
 void CYNew::Output(std::ostream &out, CYFlags flags) const {
@@ -555,12 +549,11 @@ void CYTry::Output(std::ostream &out) const {
 }
 
 void CYVariable::Output(std::ostream &out, CYFlags flags) const {
-    bool protect((flags & CYNoLeader) != 0);
-    if (protect)
-        out << '(';
+    if ((flags & CYNoLeader) != 0)
+        out << ' ';
     out << *name_;
-    if (protect)
-        out << ')';
+    if ((flags & CYNoTrailer) != 0)
+        out << ' ';
 }
 
 void CYWhile::Output(std::ostream &out) const {
index 9daf63e993535a3af09ebcf4e43d681abd2c0c29..1599959cbc977b9d971a41b149dbd2971f3f990e 100644 (file)
@@ -154,12 +154,12 @@ struct CYForInInitialiser :
 };
 
 enum CYFlags {
-    CYNoFlags,
-    CYNoBrace,
-    CYNoFunction,
-    CYNoLeader,
-    CYNoTrailer,
-    CYNoIn
+    CYNoFlags =    0,
+    CYNoBrace =    (1 << 0),
+    CYNoFunction = (1 << 1),
+    CYNoLeader =   (1 << 2),
+    CYNoTrailer =  (1 << 3),
+    CYNoIn =       (1 << 4),
 };
 
 struct CYExpression :
@@ -216,6 +216,12 @@ struct CYLiteral :
     CYPrecedence(0)
 };
 
+struct CYMagic :
+    CYExpression
+{
+    CYPrecedence(0)
+};
+
 struct CYSelectorPart :
     CYNext<CYSelectorPart>
 {
@@ -353,15 +359,13 @@ struct CYNull :
 
 struct CYThis :
     CYWord,
-    CYExpression
+    CYMagic
 {
     CYThis() :
         CYWord("this")
     {
     }
 
-    CYPrecedence(0)
-
     virtual void Output(std::ostream &out, CYFlags flags) const;
 };
 
index 2edea84b4e6d44c45c661c2643f3b9066bc74b97..1096ac1e93191711caf17b51937df9290ab36fb6 100644 (file)
@@ -8,12 +8,10 @@
 #include <JavaScriptCore/JavaScript.h>
 #include <JavaScriptCore/JSStringRefCF.h>
 
-JSContextRef CYGetJSContext();
-CFStringRef CYCopyJSONString(JSContextRef context, JSValueRef value);
-void CYSetArgs(int argc, const char *argv[]);
+#include <apr-1/apr_pools.h>
 
-#ifdef __OBJC__
-void CYThrow(JSContextRef context, id error, JSValueRef *exception);
-#endif
+JSGlobalContextRef CYGetJSContext();
+const char *CYPoolJSONString(apr_pool_t *pool, JSContextRef context, JSValueRef value);
+void CYSetArgs(int argc, const char *argv[]);
 
 #endif/*CYCRIPT_HPP*/
index 1eb6f997c6041bbb1d05a8e18d484431a55db802..c89396704997039b4aee9423ccc3c37d70a9d33c 100644 (file)
--- a/makefile
+++ b/makefile
@@ -56,7 +56,7 @@ Output.o: Output.cpp Parser.hpp Pooling.hpp
 Library.o: Library.mm Cycript.tab.hh Parser.hpp Pooling.hpp Struct.hpp cycript.hpp
        $(target)g++ $(flags) -c -o $@ $<
 
-Application.o: Application.mm Cycript.tab.hh Parser.hpp Pooling.hpp cycript.hpp
+Application.o: Application.cpp Cycript.tab.hh Parser.hpp Pooling.hpp cycript.hpp
        $(target)g++ $(flags) -c -o $@ $<
 
 libcycript.dylib: ffi_type.o parse.o Output.o Cycript.tab.o lex.cy.o Library.o
@@ -64,7 +64,7 @@ libcycript.dylib: ffi_type.o parse.o Output.o Cycript.tab.o lex.cy.o Library.o
        ldid -S $@
 
 cycript: Application.o libcycript.dylib
-       $(target)g++ $(flags) -o $@ $(filter %.o,$^) -framework UIKit -framework Foundation -framework CoreFoundation -lobjc libcycript.dylib -lreadline -framework JavaScriptCore
+       $(target)g++ $(flags) -o $@ $(filter %.o,$^) -framework UIKit -framework Foundation -framework CoreFoundation -lobjc libcycript.dylib -lreadline -framework JavaScriptCore -lapr-1
        ldid -S cycript
 
 package: all