#include <sstream>
#include <cmath>
-#include "Parser.hpp"
-
+#include "Code.hpp"
#include "Decode.hpp"
#include "Error.hpp"
#include "JavaScript.hpp"
struct CYHooks *hooks_;
/* JavaScript Properties {{{ */
+bool CYHasProperty(JSContextRef context, JSObjectRef object, JSStringRef name) {
+ return JSObjectHasProperty(context, object, name);
+}
+
JSValueRef CYGetProperty(JSContextRef context, JSObjectRef object, size_t index) {
return _jsccall(JSObjectGetPropertyAtIndex, context, object, index);
}
void CYSetProperty(JSContextRef context, JSObjectRef object, JSStringRef name, JSValueRef (*callback)(JSContextRef, JSObjectRef, JSObjectRef, size_t, const JSValueRef[], JSValueRef *), JSPropertyAttributes attributes) {
CYSetProperty(context, object, name, JSObjectMakeFunctionWithCallback(context, name, callback), attributes);
}
+
+void CYSetPrototype(JSContextRef context, JSObjectRef object, JSValueRef value) {
+ JSObjectSetPrototype(context, object, value);
+ _assert(JSObjectGetPrototype(context, object) == value);
+}
/* }}} */
/* JavaScript Strings {{{ */
JSStringRef CYCopyJSString(const char *value) {
return CYJSUndefined(context);
} CYCatch(NULL) }
-const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSValueRef value, JSValueRef *exception) { CYTry {
+const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSValueRef value, std::set<void *> &objects, JSValueRef *exception) { CYTry {
switch (JSType type = JSValueGetType(context, value)) {
case kJSTypeUndefined:
return "undefined";
} break;
case kJSTypeObject:
- return CYPoolCCYON(pool, context, (JSObjectRef) value);
+ return CYPoolCCYON(pool, context, (JSObjectRef) value, objects);
default:
throw CYJSError(context, "JSValueGetType() == 0x%x", type);
}
} CYCatch(NULL) }
-const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSValueRef value) {
- return _jsccall(CYPoolCCYON, pool, context, value);
+const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSValueRef value, std::set<void *> &objects) {
+ return _jsccall(CYPoolCCYON, pool, context, value, objects);
+}
+
+const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSValueRef value, std::set<void *> *objects) {
+ if (objects != NULL)
+ return CYPoolCCYON(pool, context, value, *objects);
+ else {
+ std::set<void *> objects;
+ return CYPoolCCYON(pool, context, value, objects);
+ }
}
-const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSObjectRef object) {
+const char *CYPoolCCYON(CYPool &pool, JSContextRef context, JSObjectRef object, std::set<void *> &objects) {
JSValueRef toCYON(CYGetProperty(context, object, toCYON_s));
if (CYIsCallable(context, toCYON)) {
- JSValueRef value(CYCallAsFunction(context, (JSObjectRef) toCYON, object, 0, NULL));
+ // XXX: this needs to be abstracted behind some kind of function
+ JSValueRef arguments[1] = {CYCastJSValue(context, static_cast<double>(reinterpret_cast<uintptr_t>(&objects)))};
+ JSValueRef value(CYCallAsFunction(context, (JSObjectRef) toCYON, object, 1, arguments));
_assert(value != NULL);
return CYPoolCString(pool, context, value);
}
JSValueRef toJSON(CYGetProperty(context, object, toJSON_s));
if (CYIsCallable(context, toJSON)) {
JSValueRef arguments[1] = {CYCastJSValue(context, CYJSString(""))};
- return _jsccall(CYPoolCCYON, pool, context, CYCallAsFunction(context, (JSObjectRef) toJSON, object, 1, arguments));
+ return _jsccall(CYPoolCCYON, pool, context, CYCallAsFunction(context, (JSObjectRef) toJSON, object, 1, arguments), objects);
}
if (JSObjectIsFunction(context, object)) {
}
}
+ _assert(objects.insert(object).second);
+
std::ostringstream str;
str << '{';
try {
JSValueRef value(CYGetProperty(context, object, name));
- str << CYPoolCCYON(pool, context, value);
+ str << CYPoolCCYON(pool, context, value, objects);
} catch (const CYException &error) {
str << "@error";
}
return pool.strmemdup(string.c_str(), string.size());
}
+std::set<void *> *CYCastObjects(JSContextRef context, JSObjectRef _this, size_t count, const JSValueRef arguments[]) {
+ if (count == 0)
+ return NULL;
+ return CYCastPointer<std::set<void *> *>(context, arguments[0]);
+}
+
static JSValueRef Array_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+ std::set<void *> *objects(CYCastObjects(context, _this, count, arguments));
+ // XXX: this is horribly inefficient
+ std::set<void *> backup;
+ if (objects == NULL)
+ objects = &backup;
+
CYPool pool;
std::ostringstream str;
try {
JSValueRef value(CYGetProperty(context, _this, index));
if (!JSValueIsUndefined(context, value))
- str << CYPoolCCYON(pool, context, value);
+ str << CYPoolCCYON(pool, context, value, *objects);
else {
str << ',';
comma = false;
return CYMakeType(context, &type);
}
+static bool All_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
+ JSObjectRef global(CYGetGlobalObject(context));
+ JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
+ JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls"))));
+
+ for (size_t i(0), count(CYArrayLength(context, alls)); i != count; ++i)
+ if (JSObjectRef space = CYCastJSObject(context, CYArrayGet(context, alls, count - i - 1)))
+ if (CYHasProperty(context, space, property))
+ return true;
+
+ CYPool pool;
+ CYUTF8String name(CYPoolUTF8String(pool, context, property));
+
+ size_t length(name.size);
+ char keyed[length + 2];
+ memcpy(keyed + 1, name.data, length + 1);
+
+ static const char *modes = "0124";
+ for (size_t i(0); i != 4; ++i) {
+ keyed[0] = modes[i];
+ if (CYBridgeHash(keyed, length + 1) != NULL)
+ return true;
+ }
+
+ return false;
+}
+
static JSValueRef All_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
JSObjectRef global(CYGetGlobalObject(context));
JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
} CYCatch(NULL) }
static JSValueRef Pointer_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+ std::set<void *> *objects(CYCastObjects(context, _this, count, arguments));
+
Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(_this)));
if (internal->length_ != _not(size_t)) {
JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array_prototype")));
if (JSValueIsUndefined(context, value))
goto pointer;
CYPool pool;
- return CYCastJSValue(context, pool.strcat("&", CYPoolCCYON(pool, context, value), NULL));
+ return CYCastJSValue(context, pool.strcat("&", CYPoolCCYON(pool, context, value, objects), NULL));
} catch (const CYException &e) {
goto pointer;
}
return NULL;
const char *json; try {
- json = CYPoolCCYON(pool, context, result, &exception);
+ std::set<void *> objects;
+ json = CYPoolCCYON(pool, context, result, objects, &exception);
} catch (const char *error) {
return error;
}
definition = kJSClassDefinitionEmpty;
definition.className = "All";
+ definition.hasProperty = &All_hasProperty;
definition.getProperty = &All_getProperty;
definition.getPropertyNames = &All_getPropertyNames;
All_ = JSClassCreate(&definition);
}
const char *CYJSError::PoolCString(CYPool &pool) const {
+ std::set<void *> objects;
// XXX: this used to be CYPoolCString
- return CYPoolCCYON(pool, context_, value_);
+ return CYPoolCCYON(pool, context_, value_, objects);
}
JSValueRef CYJSError::CastJSValue(JSContextRef context) const {
extern "C" bool CydgetMemoryParse(const uint16_t **data, size_t *size);
void *CYMapFile(const char *path, size_t *psize) {
- int fd;
- _syscall(fd = open(path, O_RDONLY));
+ int fd(_syscall_(open(path, O_RDONLY), 1, {ENOENT}));
+ if (fd == -1)
+ return NULL;
struct stat stat;
_syscall(fstat(fd, &stat));
CYJSString property("exports");
JSObjectRef module;
- const char *path(pool.strcat(lib, "/cycript0.9/", CYPoolCString(pool, context, arguments[0]), ".cy", NULL));
+ const char *name(CYPoolCString(pool, context, arguments[0]));
+ const char *path(pool.strcat(lib, "/cycript0.9/", name, ".cy", NULL));
+
CYJSString key(path);
JSObjectRef modules(CYGetCachedObject(context, CYJSString("modules")));
JSValueRef cache(CYGetProperty(context, modules, key));
CYUTF8String code;
code.data = reinterpret_cast<char *>(CYMapFile(path, &code.size));
- std::stringstream wrap;
- wrap << "(function (exports, require, module) { " << code << "\n});";
- code = CYPoolCode(pool, wrap.str().c_str());
+ if (code.data == NULL) {
+ if (strchr(name, '/') == NULL && (
+ dlopen(pool.strcat("/System/Library/Frameworks/", name, ".framework/", name, NULL), RTLD_LAZY | RTLD_GLOBAL) != NULL ||
+ dlopen(pool.strcat("/System/Library/PrivateFrameworks/", name, ".framework/", name, NULL), RTLD_LAZY | RTLD_GLOBAL) != NULL ||
+ false))
+ return CYJSUndefined(NULL);
- JSValueRef value(_jsccall(JSEvaluateScript, context, CYJSString(code), NULL, NULL, 0));
- JSObjectRef function(CYCastJSObject(context, value));
+ CYThrow("Can't find module: %s", name);
+ }
module = JSObjectMake(context, NULL, NULL);
+ CYSetProperty(context, modules, key, module);
+
JSObjectRef exports(JSObjectMake(context, NULL, NULL));
CYSetProperty(context, module, property, exports);
+ std::stringstream wrap;
+ wrap << "(function (exports, require, module) { " << code << "\n});";
+ code = CYPoolCode(pool, wrap);
+
+ JSValueRef value(_jsccall(JSEvaluateScript, context, CYJSString(code), NULL, NULL, 0));
+ JSObjectRef function(CYCastJSObject(context, value));
+
JSValueRef arguments[3] = { exports, JSObjectMakeFunctionWithCallback(context, CYJSString("require"), &require), module };
CYCallAsFunction(context, function, NULL, 3, arguments);
- CYSetProperty(context, modules, key, module);
}
return CYGetProperty(context, module, property);
CYSetProperty(context, cycript, CYJSString("gc"), &Cycript_gc_callAsFunction);
JSObjectRef Functor(JSObjectMakeConstructor(context, Functor_, &Functor_new));
- JSObjectSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Functor, prototype_s)), Function_prototype);
+ CYSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Functor, prototype_s)), Function_prototype);
CYSetProperty(context, cycript, CYJSString("Functor"), Functor);
CYSetProperty(context, cycript, CYJSString("Pointer"), JSObjectMakeConstructor(context, Pointer_, &Pointer_new));
next = JSObjectGetPrototype(context, curr);
}
- JSObjectSetPrototype(context, last, all);
+ CYSetPrototype(context, last, all);
}
CYSetProperty(context, global, CYJSString("$cyq"), &$cyq, kJSPropertyAttributeDontEnum);