#include <sys/mman.h>
#include <sys/stat.h>
+#include <sqlite3.h>
+
#include "sig/parse.hpp"
#include "sig/ffi_type.hpp"
#include "Pooling.hpp"
#include "String.hpp"
+const char *sqlite3_column_string(sqlite3_stmt *stmt, int n) {
+ return reinterpret_cast<const char *>(sqlite3_column_text(stmt, n));
+}
+
+char *sqlite3_column_pooled(CYPool &pool, sqlite3_stmt *stmt, int n) {
+ if (const char *value = sqlite3_column_string(stmt, n))
+ return pool.strdup(value);
+ else return NULL;
+}
+
static std::vector<CYHook *> &GetHooks() {
static std::vector<CYHook *> hooks;
return hooks;
}
/* }}} */
+static JSObjectRef (*JSObjectMakeArray$)(JSContextRef, size_t, const JSValueRef[], JSValueRef *);
+
+static JSObjectRef CYObjectMakeArray(JSContextRef context, size_t length, const JSValueRef values[]) {
+ if (JSObjectMakeArray$ != NULL)
+ return _jsccall(*JSObjectMakeArray$, context, length, values);
+ else {
+ JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array")));
+ JSValueRef value(CYCallAsFunction(context, Array, NULL, length, values));
+ return CYCastJSObject(context, value);
+ }
+}
+
static JSClassRef All_;
static JSClassRef Context_;
static JSClassRef CString_;
JSStringRef toString_s;
JSStringRef weak_s;
+static sqlite3 *database_;
+
static JSStringRef Result_;
void CYFinalize(JSObjectRef object) {
if (type->primitive != sig::struct_P || type->name == NULL)
return;
- size_t length(strlen(type->name));
- char keyed[length + 2];
- memcpy(keyed + 1, type->name, length + 1);
-
- static const char *modes = "34";
- for (size_t i(0); i != 2; ++i) {
- char mode(modes[i]);
- keyed[0] = mode;
-
- if (CYBridgeEntry *entry = CYBridgeHash(keyed, length + 1))
- switch (mode) {
- case '3':
- sig::Parse(pool, &type->data.signature, entry->value_, &Structor_);
- break;
-
- case '4': {
- sig::Signature signature;
- sig::Parse(pool, &signature, entry->value_, &Structor_);
- type = signature.elements[0].type;
- } break;
- }
- }
+ //_assert(false);
}
JSClassRef Type_privateData::Class_;
length_(length)
{
}
+
+ Pointer(void *value, JSContextRef context, JSObjectRef owner, size_t length, const char *encoding) :
+ CYOwned(value, context, owner),
+ type_(new(*pool_) Type_privateData(encoding)),
+ length_(length)
+ {
+ }
};
struct Struct_privateData :
return _jsccall(JSObjectGetPropertyAtIndex, context, array, index);
}
-void CYArrayPush(JSContextRef context, JSObjectRef array, JSValueRef value) {
- JSValueRef arguments[1];
- arguments[0] = value;
+void CYArrayPush(JSContextRef context, JSObjectRef array, size_t length, const JSValueRef arguments[]) {
JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array_prototype")));
- _jsccall(JSObjectCallAsFunction, context, CYCastJSObject(context, CYGetProperty(context, Array, push_s)), array, 1, arguments);
+ _jsccall(JSObjectCallAsFunction, context, CYCastJSObject(context, CYGetProperty(context, Array, push_s)), array, length, arguments);
+}
+
+void CYArrayPush(JSContextRef context, JSObjectRef array, JSValueRef value) {
+ return CYArrayPush(context, array, 1, &value);
}
+template <size_t Size_>
+class CYArrayBuilder {
+ private:
+ JSContextRef context_;
+ JSObjectRef &array_;
+ size_t size_;
+ JSValueRef values_[Size_];
+
+ void flush() {
+ if (array_ == NULL)
+ array_ = CYObjectMakeArray(context_, size_, values_);
+ else
+ CYArrayPush(context_, array_, size_, values_);
+ }
+
+ public:
+ CYArrayBuilder(JSContextRef context, JSObjectRef &array) :
+ context_(context),
+ array_(array),
+ size_(0)
+ {
+ }
+
+ ~CYArrayBuilder() {
+ flush();
+ }
+
+ void operator ()(JSValueRef value) {
+ if (size_ == Size_) {
+ flush();
+ size_ = 0;
+ }
+
+ values_[size_++] = value;
+ }
+};
+
static JSValueRef System_print(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
FILE *file(stdout);
return JSObjectMake(context, Pointer_, internal);
}
+JSObjectRef CYMakePointer(JSContextRef context, void *pointer, size_t length, const char *encoding, JSObjectRef owner) {
+ Pointer *internal(new Pointer(pointer, context, owner, length, encoding));
+ 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);
return JSObjectMake(context, Functor_, new cy::Functor(signature, function));
}
-static JSObjectRef CYMakeFunctor(JSContextRef context, const char *symbol, const char *encoding, void **cache) {
- cy::Functor *internal;
- if (*cache != NULL)
- internal = reinterpret_cast<cy::Functor *>(*cache);
- else {
- void (*function)()(reinterpret_cast<void (*)()>(CYCastSymbol(symbol)));
- if (function == NULL)
- return NULL;
-
- internal = new cy::Functor(encoding, function);
- *cache = internal;
- }
+static JSObjectRef CYMakeFunctor(JSContextRef context, const char *symbol, const char *encoding) {
+ void (*function)()(reinterpret_cast<void (*)()>(CYCastSymbol(symbol)));
+ if (function == NULL)
+ return NULL;
+ cy::Functor *internal(new cy::Functor(encoding, function));
++internal->count_;
return JSObjectMake(context, Functor_, internal);
}
break;
CYPoolFFI_(uchar, unsigned char)
- CYPoolFFI_(char, char)
+ CYPoolFFI_(schar, signed char)
CYPoolFFI_(ushort, unsigned short)
CYPoolFFI_(short, short)
CYPoolFFI_(ulong, unsigned long)
case sig::void_P:
break;
+ // XXX: implement a conversion from a single character string?
+ CYPoolFFI_(char, char)
+
default:
for (CYHook *hook : GetHooks())
if (hook->PoolFFI != NULL)
return CYCastJSValue(context, *reinterpret_cast<native *>(data)); \
CYFromFFI_(uchar, unsigned char)
- CYFromFFI_(char, char)
+ CYFromFFI_(schar, signed char)
CYFromFFI_(ushort, unsigned short)
CYFromFFI_(short, short)
CYFromFFI_(ulong, unsigned long)
case sig::void_P:
return CYJSUndefined(context);
+ CYFromFFI_(char, char)
+
null:
return CYJSNull(context);
default:
base:
ffi_type **elements(typical->GetFFI()->elements);
- base = reinterpret_cast<uint8_t *>(internal->value_);
- for (ssize_t local(0); local != index; ++local)
- base += elements[local]->size;
+ size_t offset(0);
+ for (ssize_t local(0); local != index; ++local) {
+ offset += elements[local]->size;
+ CYAlign(offset, elements[local + 1]->alignment);
+ }
+ base = reinterpret_cast<uint8_t *>(internal->value_) + offset;
return true;
}
return CYCallAsFunction(context, functor, _this, count, arguments);
} CYCatch(NULL) }
-JSObjectRef CYMakeType(JSContextRef context, const char *encoding) {
- Type_privateData *internal(new Type_privateData(encoding));
+JSObjectRef CYMakeType(JSContextRef context, sig::Primitive primitive) {
+ Type_privateData *internal(new Type_privateData(primitive));
return JSObjectMake(context, Type_privateData::Class_, internal);
}
return CYMakeType(context, &type);
}
+extern "C" bool CYBridgeHash(CYPool &pool, CYUTF8String name, const char *&code, unsigned &flags) {
+ sqlite3_stmt *statement;
+
+ _sqlcall(sqlite3_prepare(database_,
+ "select "
+ "\"cache\".\"code\", "
+ "\"cache\".\"flags\" "
+ "from \"cache\" "
+ "where"
+ " \"cache\".\"system\" & " CY_SYSTEM " == " CY_SYSTEM " and"
+ " \"cache\".\"name\" = ?"
+ " limit 1"
+ , -1, &statement, NULL));
+
+ _sqlcall(sqlite3_bind_text(statement, 1, name.data, name.size, SQLITE_STATIC));
+
+ bool success;
+ if (_sqlcall(sqlite3_step(statement)) == SQLITE_DONE)
+ success = false;
+ else {
+ success = true;
+ code = sqlite3_column_pooled(pool, statement, 0);
+ flags = sqlite3_column_int(statement, 1);
+ }
+
+ _sqlcall(sqlite3_finalize(statement));
+ return success;
+}
+
static bool All_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
+ if (JSStringIsEqualToUTF8CString(property, "errno"))
+ return true;
+
JSObjectRef global(CYGetGlobalObject(context));
JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls"))));
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;
- }
+ const char *code;
+ unsigned flags;
+ if (CYBridgeHash(pool, CYPoolUTF8String(pool, context, property), code, flags))
+ return true;
return false;
}
static JSValueRef All_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
+ if (JSStringIsEqualToUTF8CString(property, "errno"))
+ return CYCastJSValue(context, errno);
+
JSObjectRef global(CYGetGlobalObject(context));
JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls"))));
return value;
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) {
- char mode(modes[i]);
- keyed[0] = mode;
-
- if (CYBridgeEntry *entry = CYBridgeHash(keyed, length + 1))
- switch (mode) {
- case '0':
- return JSEvaluateScript(CYGetJSContext(context), CYJSString(entry->value_), NULL, NULL, 0, NULL);
-
- case '1':
- return CYMakeFunctor(context, name.data, entry->value_, &entry->cache_);
-
- case '2':
- if (void *symbol = CYCastSymbol(name.data)) {
- // XXX: this is horrendously inefficient
- sig::Signature signature;
- sig::Parse(pool, &signature, entry->value_, &Structor_);
- ffi_cif cif;
- sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif);
- return CYFromFFI(context, signature.elements[0].type, cif.rtype, symbol);
- } else return NULL;
-
- // XXX: implement case 3
- case '4':
- return CYMakeType(context, entry->value_);
- }
+ const char *code;
+ unsigned flags;
+ if (CYBridgeHash(pool, CYPoolUTF8String(pool, context, property), code, flags)) {
+ CYUTF8String parsed;
+
+ try {
+ parsed = CYPoolCode(pool, code);
+ } catch (const CYException &error) {
+ CYThrow("%s", pool.strcat("error caching ", CYPoolCString(pool, context, property), ": ", error.PoolCString(pool), NULL));
+ }
+
+ JSValueRef result(_jsccall(JSEvaluateScript, context, CYJSString(parsed), NULL, NULL, 0));
+
+ if (flags == 0) {
+ JSObjectRef cache(CYGetCachedObject(context, CYJSString("cache")));
+ CYSetProperty(context, cache, property, result);
+ }
+
+ return result;
}
return NULL;
} CYCatch(NULL) }
+static JSValueRef All_complete_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+ _assert(count == 1);
+ CYPool pool;
+ CYUTF8String prefix(CYPoolUTF8String(pool, context, CYJSString(context, arguments[0])));
+
+ JSObjectRef array(NULL);
+
+ {
+ CYArrayBuilder<1024> values(context, array);
+
+ sqlite3_stmt *statement;
+
+ if (prefix.size == 0)
+ _sqlcall(sqlite3_prepare(database_,
+ "select "
+ "\"cache\".\"name\" "
+ "from \"cache\" "
+ "where"
+ " \"cache\".\"system\" & " CY_SYSTEM " == " CY_SYSTEM
+ , -1, &statement, NULL));
+ else {
+ _sqlcall(sqlite3_prepare(database_,
+ "select "
+ "\"cache\".\"name\" "
+ "from \"cache\" "
+ "where"
+ " \"cache\".\"name\" >= ? and \"cache\".\"name\" < ? and "
+ " \"cache\".\"system\" & " CY_SYSTEM " == " CY_SYSTEM
+ , -1, &statement, NULL));
+
+ _sqlcall(sqlite3_bind_text(statement, 1, prefix.data, prefix.size, SQLITE_STATIC));
+
+ char *after(pool.strndup(prefix.data, prefix.size));
+ ++after[prefix.size - 1];
+ _sqlcall(sqlite3_bind_text(statement, 2, after, prefix.size, SQLITE_STATIC));
+ }
+
+ while (_sqlcall(sqlite3_step(statement)) != SQLITE_DONE)
+ values(CYCastJSValue(context, CYJSString(sqlite3_column_string(statement, 0))));
+
+ _sqlcall(sqlite3_finalize(statement));
+ }
+
+ return array;
+} CYCatch(NULL) }
+
static void All_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
JSObjectRef global(CYGetGlobalObject(context));
JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
if (false) {
} else if (count == 1) {
- const char *type(CYPoolCString(pool, context, arguments[0]));
- return CYMakeType(context, type);
+ const char *encoding(CYPoolCString(pool, context, arguments[0]));
+ sig::Signature signature;
+ sig::Parse(pool, &signature, encoding, &Structor_);
+ return CYMakeType(context, signature.elements[0].type);
} else if (count == 2) {
JSObjectRef types(CYCastJSObject(context, arguments[0]));
size_t count(CYArrayLength(context, types));
sig::Type type(*internal->type_);
switch (type.primitive) {
- case sig::char_P: case sig::uchar_P: type.primitive = sig::char_P; break;
+ case sig::char_P: case sig::schar_P: case sig::uchar_P: type.primitive = sig::schar_P; break;
case sig::short_P: case sig::ushort_P: type.primitive = sig::short_P; break;
case sig::int_P: case sig::uint_P: type.primitive = sig::int_P; break;
case sig::long_P: case sig::ulong_P: type.primitive = sig::long_P; break;
sig::Type type(*internal->type_);
switch (type.primitive) {
- case sig::char_P: case sig::uchar_P: type.primitive = sig::uchar_P; break;
+ case sig::char_P: case sig::schar_P: case sig::uchar_P: type.primitive = sig::uchar_P; break;
case sig::short_P: case sig::ushort_P: type.primitive = sig::ushort_P; break;
case sig::int_P: case sig::uint_P: type.primitive = sig::uint_P; break;
case sig::long_P: case sig::ulong_P: type.primitive = sig::ulong_P; break;
return Type_callAsFunction_toString(context, object, _this, count, arguments, exception);
}
+static JSStaticFunction All_staticFunctions[2] = {
+ {"cy$complete", &All_complete_callAsFunction, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+ {NULL, NULL, 0}
+};
+
static JSStaticFunction CString_staticFunctions[6] = {
{"toCYON", &CString_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"toJSON", &CYValue_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{NULL, NULL, 0}
};
-static JSObjectRef (*JSObjectMakeArray$)(JSContextRef, size_t, const JSValueRef[], JSValueRef *);
-
_visible void CYSetArgs(int argc, const char *argv[]) {
JSContextRef context(CYGetJSContext());
JSValueRef args[argc];
for (int i(0); i != argc; ++i)
args[i] = CYCastJSValue(context, argv[i]);
- JSObjectRef array;
- if (JSObjectMakeArray$ != NULL)
- array = _jsccall(*JSObjectMakeArray$, context, argc, args);
- else {
- JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array")));
- JSValueRef value(CYCallAsFunction(context, Array, NULL, argc, args));
- array = CYCastJSObject(context, value);
- }
-
+ JSObjectRef array(CYObjectMakeArray(context, argc, args));
JSObjectRef System(CYGetCachedObject(context, CYJSString("System")));
CYSetProperty(context, System, CYJSString("args"), array);
}
cancel_ = true;
}
+static const char *CYPoolLibraryPath(CYPool &pool);
+
static bool initialized_ = false;
void CYInitializeDynamic() {
initialized_ = true;
else return;
+ CYPool pool;
+ const char *db(pool.strcat(CYPoolLibraryPath(pool), "/libcycript.db", NULL));
+ _sqlcall(sqlite3_open_v2(db, &database_, SQLITE_OPEN_READONLY, NULL));
+
JSObjectMakeArray$ = reinterpret_cast<JSObjectRef (*)(JSContextRef, size_t, const JSValueRef[], JSValueRef *)>(dlsym(RTLD_DEFAULT, "JSObjectMakeArray"));
JSSynchronousGarbageCollectForDebugging$ = reinterpret_cast<void (*)(JSContextRef)>(dlsym(RTLD_DEFAULT, "JSSynchronousGarbageCollectForDebugging"));
definition = kJSClassDefinitionEmpty;
definition.className = "All";
+ definition.staticFunctions = All_staticFunctions;
definition.hasProperty = &All_hasProperty;
definition.getProperty = &All_getProperty;
definition.getPropertyNames = &All_getPropertyNames;
return reinterpret_cast<Context *>(JSObjectGetPrivate(CYCastJSObject(context, CYGetProperty(context, CYGetGlobalObject(context), cy_s))))->context_;
}
-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;
-
- 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));
-
- CYFile *file(new (pool) CYFile(base, size));
- pool.atexit(&CYFileExit, file);
-
- _syscall(close(fd));
- return base;
-}
-
-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 *>(&CYPoolLibraryPath), &addr) != 0);
_assert(slash != NULL);
*slash = '\0';
+ slash = strrchr(lib, '/');
+ if (slash != NULL && strcmp(slash, "/.libs") == 0)
+ *slash = '\0';
+
return lib;
}
static bool CYRunScript(JSGlobalContextRef context, const char *path) {
CYPool pool;
- CYUTF8String code(CYPoolFileUTF8String(pool, path));
+ CYUTF8String code(CYPoolFileUTF8String(pool, pool.strcat(CYPoolLibraryPath(pool), path, NULL)));
if (code.data == NULL)
return false;
- CYStream stream(code.data, code.data + code.size);
- code = CYPoolCode(pool, stream);
+ code = CYPoolCode(pool, code);
_jsccall(JSEvaluateScript, context, CYJSString(code), NULL, NULL, 0);
return true;
}
JSObjectRef all(JSObjectMake(context, All_, NULL));
CYSetProperty(context, cycript, CYJSString("all"), all);
+ JSObjectRef cache(JSObjectMake(context, NULL, NULL));
+ CYSetProperty(context, cy, CYJSString("cache"), cache);
+ CYSetPrototype(context, cache, all);
+
JSObjectRef alls(_jsccall(JSObjectCallAsConstructor, context, Array, 0, NULL));
CYSetProperty(context, cycript, CYJSString("alls"), alls);
next = JSObjectGetPrototype(context, curr);
}
- CYSetPrototype(context, last, all);
+ CYSetPrototype(context, last, cache);
}
JSObjectRef System(JSObjectMake(context, NULL, NULL));
CYSetProperty(context, cy, CYJSString("System"), System);
- CYSetProperty(context, all, CYJSString("require"), &require_callAsFunction, kJSPropertyAttributeDontEnum);
+ CYSetProperty(context, global, CYJSString("require"), &require_callAsFunction, kJSPropertyAttributeDontEnum);
CYSetProperty(context, global, CYJSString("system"), System);
CYSetProperty(context, System, CYJSString("args"), CYJSNull(context));
}
#endif
- if (CYBridgeEntry *entry = CYBridgeHash("1dlerror", 8))
- entry->cache_ = new cy::Functor(entry->value_, reinterpret_cast<void (*)()>(&dlerror));
+ CYSetProperty(context, cache, CYJSString("dlerror"), CYMakeFunctor(context, "dlerror", "*"), kJSPropertyAttributeDontEnum);
+ CYSetProperty(context, cache, CYJSString("RTLD_DEFAULT"), CYCastJSValue(context, reinterpret_cast<intptr_t>(RTLD_DEFAULT)), kJSPropertyAttributeDontEnum);
+ CYSetProperty(context, cache, CYJSString("dlsym"), CYMakeFunctor(context, "dlsym", "^v^v*"), kJSPropertyAttributeDontEnum);
- CYRunScript(context, "libcycript.cy");
+ CYSetProperty(context, cache, CYJSString("NULL"), CYJSNull(context), kJSPropertyAttributeDontEnum);
+
+ CYSetProperty(context, cache, CYJSString("bool"), CYMakeType(context, sig::boolean_P), kJSPropertyAttributeDontEnum);
+ CYSetProperty(context, cache, CYJSString("char"), CYMakeType(context, sig::char_P), kJSPropertyAttributeDontEnum);
+ CYSetProperty(context, cache, CYJSString("short"), CYMakeType(context, sig::short_P), kJSPropertyAttributeDontEnum);
+ CYSetProperty(context, cache, CYJSString("int"), CYMakeType(context, sig::int_P), kJSPropertyAttributeDontEnum);
+ CYSetProperty(context, cache, CYJSString("long"), CYMakeType(context, sig::long_P), kJSPropertyAttributeDontEnum);
+ CYSetProperty(context, cache, CYJSString("float"), CYMakeType(context, sig::float_P), kJSPropertyAttributeDontEnum);
+ CYSetProperty(context, cache, CYJSString("double"), CYMakeType(context, sig::double_P), kJSPropertyAttributeDontEnum);
for (CYHook *hook : GetHooks())
if (hook->SetupContext != NULL)
(*hook->SetupContext)(context);
CYArrayPush(context, alls, cycript);
+
+ CYRunScript(context, "/libcycript.cy");
}
static JSGlobalContextRef context_;