X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/aabea98c2f0415ea5882dad2b9ff9fc3b1d5c97c..ea840434d0f2b6127e0b7ee303605f87366e9e94:/Library.cpp?ds=sidebyside diff --git a/Library.cpp b/Library.cpp index dbb86f2..f95cf9e 100644 --- a/Library.cpp +++ b/Library.cpp @@ -86,6 +86,65 @@ char *sqlite3_column_pooled(apr_pool_t *pool, sqlite3_stmt *stmt, int n) { struct CYHooks *hooks_; +/* C Strings {{{ */ +template +_finline size_t iconv_(size_t (*iconv)(iconv_t, Type_, size_t *, char **, size_t *), iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { + return iconv(cd, const_cast(inbuf), inbytesleft, outbuf, outbytesleft); +} + +#ifdef __GLIBC__ +#define UCS_2_INTERNAL "UCS-2" +#else +#define UCS_2_INTERNAL "UCS-2-INTERNAL" +#endif + +CYUTF8String CYPoolUTF8String(apr_pool_t *pool, CYUTF16String utf16) { + _assert(pool != NULL); + + const char *in(reinterpret_cast(utf16.data)); + + iconv_t conversion(_syscall(iconv_open("UTF-8", UCS_2_INTERNAL))); + + // XXX: this is wrong + size_t size(utf16.size * 5); + char *out(new(pool) char[size]); + CYUTF8String utf8(out, size); + + size = utf16.size * 2; + _syscall(iconv_(&iconv, conversion, const_cast(&in), &size, &out, &utf8.size)); + + *out = '\0'; + utf8.size = out - utf8.data; + + _syscall(iconv_close(conversion)); + + return utf8; +} + +CYUTF16String CYPoolUTF16String(apr_pool_t *pool, CYUTF8String utf8) { + _assert(pool != NULL); + + const char *in(utf8.data); + + iconv_t conversion(_syscall(iconv_open(UCS_2_INTERNAL, "UTF-8"))); + + // XXX: this is wrong + size_t size(utf8.size * 5); + uint16_t *temp(new (pool) uint16_t[size]); + CYUTF16String utf16(temp, size * 2); + char *out(reinterpret_cast(temp)); + + size = utf8.size; + _syscall(iconv_(&iconv, conversion, const_cast(&in), &size, &out, &utf16.size)); + + utf16.size = reinterpret_cast(out) - utf16.data; + temp[utf16.size] = 0; + + _syscall(iconv_close(conversion)); + + return utf16; +} +/* }}} */ /* JavaScript Properties {{{ */ JSValueRef CYGetProperty(JSContextRef context, JSObjectRef object, size_t index) { JSValueRef exception(NULL); @@ -112,6 +171,10 @@ void CYSetProperty(JSContextRef context, JSObjectRef object, JSStringRef name, J JSObjectSetProperty(context, object, name, value, attributes, &exception); CYThrow(context, exception); } + +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); +} /* }}} */ /* JavaScript Strings {{{ */ JSStringRef CYCopyJSString(const char *value) { @@ -123,7 +186,7 @@ JSStringRef CYCopyJSString(JSStringRef value) { } JSStringRef CYCopyJSString(CYUTF8String value) { - // XXX: this is very wrong + // XXX: this is very wrong; it needs to convert to UTF16 and then create from there return CYCopyJSString(value.data); } @@ -140,36 +203,8 @@ static CYUTF16String CYCastUTF16String(JSStringRef value) { return CYUTF16String(JSStringGetCharactersPtr(value), JSStringGetLength(value)); } -template -_finline size_t iconv_(size_t (*iconv)(iconv_t, Type_, size_t *, char **, size_t *), iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { - return iconv(cd, const_cast(inbuf), inbytesleft, outbuf, outbytesleft); -} - CYUTF8String CYPoolUTF8String(apr_pool_t *pool, JSContextRef context, JSStringRef value) { - _assert(pool != NULL); - - CYUTF16String utf16(CYCastUTF16String(value)); - const char *in(reinterpret_cast(utf16.data)); - -#ifdef __GLIBC__ - iconv_t conversion(_syscall(iconv_open("UTF-8", "UCS-2"))); -#else - iconv_t conversion(_syscall(iconv_open("UTF-8", "UCS-2-INTERNAL"))); -#endif - - size_t size(JSStringGetMaximumUTF8CStringSize(value)); - char *out(new(pool) char[size]); - CYUTF8String utf8(out, size); - - size = utf16.size * 2; - _syscall(iconv_(&iconv, conversion, const_cast(&in), &size, &out, &utf8.size)); - - *out = '\0'; - utf8.size = out - utf8.data; - - _syscall(iconv_close(conversion)); - - return utf8; + return CYPoolUTF8String(pool, CYCastUTF16String(value)); } const char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSStringRef value) { @@ -186,19 +221,25 @@ const char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSValueRef val /* Index Offsets {{{ */ size_t CYGetIndex(const CYUTF8String &value) { if (value.data[0] != '0') { - char *end; - size_t index(strtoul(value.data, &end, 10)); - if (value.data + value.size == end) - return index; - } else if (value.data[1] == '\0') + size_t index(0); + for (size_t i(0); i != value.size; ++i) { + if (!DigitRange_[value.data[i]]) + return _not(size_t); + index *= 10; + index += value.data[i] - '0'; + } + return index; + } else if (value.size == 1) return 0; - return _not(size_t); + else + return _not(size_t); } size_t CYGetIndex(apr_pool_t *pool, JSContextRef context, JSStringRef value) { return CYGetIndex(CYPoolUTF8String(pool, context, value)); } +// XXX: this isn't actually right bool CYGetOffset(const char *value, ssize_t &index) { if (value[0] != '0') { char *end; @@ -250,7 +291,7 @@ void CYStringify(std::ostringstream &str, const char *data, size_t size) { break; default: - // this test is designed to be "awewsome", generating neither warnings nor incorrect results + // this test is designed to be "awesome", generating neither warnings nor incorrect results if (*value < 0x20 || *value >= 0x7f) str << "\\x" << std::setbase(16) << std::setw(2) << std::setfill('0') << unsigned(uint8_t(*value)); else simple: @@ -290,35 +331,26 @@ bool CYIsKey(CYUTF8String value) { } /* }}} */ -static JSGlobalContextRef Context_; -static JSObjectRef System_; - +static JSClassRef All_; +static JSClassRef Context_; static JSClassRef Functor_; +static JSClassRef Global_; static JSClassRef Pointer_; -static JSClassRef Runtime_; static JSClassRef Struct_; -static JSStringRef Result_; - -JSObjectRef Array_; -JSObjectRef Error_; -JSObjectRef Function_; -JSObjectRef String_; +JSStringRef Array_s; +JSStringRef cy_s; +JSStringRef length_s; +JSStringRef message_s; +JSStringRef name_s; +JSStringRef pop_s; +JSStringRef prototype_s; +JSStringRef push_s; +JSStringRef splice_s; +JSStringRef toCYON_s; +JSStringRef toJSON_s; -JSStringRef length_; -JSStringRef message_; -JSStringRef name_; -JSStringRef prototype_; -JSStringRef toCYON_; -JSStringRef toJSON_; - -JSObjectRef Object_prototype_; -JSObjectRef Function_prototype_; - -JSObjectRef Array_prototype_; -JSObjectRef Array_pop_; -JSObjectRef Array_push_; -JSObjectRef Array_splice_; +static JSStringRef Result_; sqlite3 *Bridge_; @@ -334,8 +366,19 @@ struct CStringMapLess : } }; -void Structor_(apr_pool_t *pool, const char *name, const char *types, sig::Type *&type) { - if (name == NULL) +void Structor_(apr_pool_t *pool, sig::Type *&type) { + if ( + type->primitive == sig::pointer_P && + type->data.data.type != NULL && + type->data.data.type->primitive == sig::struct_P && + strcmp(type->data.data.type->name, "_objc_class") == 0 + ) { + type->primitive = sig::typename_P; + type->data.data.type = NULL; + return; + } + + if (type->primitive != sig::struct_P || type->name == NULL) return; sqlite3_stmt *statement; @@ -351,7 +394,7 @@ void Structor_(apr_pool_t *pool, const char *name, const char *types, sig::Type " limit 1" , -1, &statement, NULL)); - _sqlcall(sqlite3_bind_text(statement, 1, name, -1, SQLITE_STATIC)); + _sqlcall(sqlite3_bind_text(statement, 1, type->name, -1, SQLITE_STATIC)); int mode; const char *value; @@ -386,14 +429,27 @@ void Structor_(apr_pool_t *pool, const char *name, const char *types, sig::Type JSClassRef Type_privateData::Class_; +struct Context : + CYData +{ + JSGlobalContextRef context_; + + Context(JSGlobalContextRef context) : + context_(context) + { + } +}; + struct Pointer : CYOwned { Type_privateData *type_; + size_t length_; - Pointer(void *value, JSContextRef context, JSObjectRef owner, sig::Type *type) : + Pointer(void *value, JSContextRef context, JSObjectRef owner, size_t length, sig::Type *type) : CYOwned(value, context, owner), - type_(new(pool_) Type_privateData(type)) + type_(new(pool_) Type_privateData(type)), + length_(length) { } }; @@ -496,7 +552,7 @@ JSObjectRef CYCastJSObject(JSContextRef context, JSValueRef value) { return object; } -JSValueRef CYCallAsFunction(JSContextRef context, JSObjectRef function, JSObjectRef _this, size_t count, JSValueRef arguments[]) { +JSValueRef CYCallAsFunction(JSContextRef context, JSObjectRef function, JSObjectRef _this, size_t count, const JSValueRef arguments[]) { JSValueRef exception(NULL); JSValueRef value(JSObjectCallAsFunction(context, function, _this, count, arguments, &exception)); CYThrow(context, exception); @@ -522,7 +578,7 @@ static size_t Nonce_(0); static JSValueRef $cyq(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYPool pool; - const char *name(apr_psprintf(pool, "%s%zu", CYPoolCString(pool, context, arguments[0]), Nonce_++)); + const char *name(apr_psprintf(pool, "%s%"APR_SIZE_T_FMT"", CYPoolCString(pool, context, arguments[0]), Nonce_++)); return CYCastJSValue(context, name); } @@ -570,13 +626,14 @@ const char *CYPoolCCYON(apr_pool_t *pool, JSContextRef context, JSValueRef value } const char *CYPoolCCYON(apr_pool_t *pool, JSContextRef context, JSObjectRef object) { - JSValueRef toCYON(CYGetProperty(context, object, toCYON_)); + JSValueRef toCYON(CYGetProperty(context, object, toCYON_s)); if (CYIsCallable(context, toCYON)) { JSValueRef value(CYCallAsFunction(context, (JSObjectRef) toCYON, object, 0, NULL)); + _assert(value != NULL); return CYPoolCString(pool, context, value); } - JSValueRef toJSON(CYGetProperty(context, object, toJSON_)); + JSValueRef toJSON(CYGetProperty(context, object, toJSON_s)); if (CYIsCallable(context, toJSON)) { JSValueRef arguments[1] = {CYCastJSValue(context, CYJSString(""))}; JSValueRef exception(NULL); @@ -626,7 +683,7 @@ static JSValueRef Array_callAsFunction_toCYON(JSContextRef context, JSObjectRef str << '['; - JSValueRef length(CYGetProperty(context, _this, length_)); + JSValueRef length(CYGetProperty(context, _this, length_s)); bool comma(false); for (size_t index(0), count(CYCastDouble(context, length)); index != count; ++index) { @@ -651,8 +708,8 @@ static JSValueRef Array_callAsFunction_toCYON(JSContextRef context, JSObjectRef return CYCastJSValue(context, CYJSString(CYUTF8String(value.c_str(), value.size()))); } CYCatch } -JSObjectRef CYMakePointer(JSContextRef context, void *pointer, sig::Type *type, ffi_type *ffi, JSObjectRef owner) { - Pointer *internal(new Pointer(pointer, context, owner, type)); +JSObjectRef CYMakePointer(JSContextRef context, void *pointer, size_t length, sig::Type *type, ffi_type *ffi, JSObjectRef owner) { + Pointer *internal(new Pointer(pointer, context, owner, length, type)); return JSObjectMake(context, Pointer_, internal); } @@ -706,6 +763,27 @@ void CYPoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, ffi_type CYPoolFFI_(float, float) CYPoolFFI_(double, double) + case sig::array_P: { + uint8_t *base(reinterpret_cast(data)); + JSObjectRef aggregate(JSValueIsObject(context, value) ? (JSObjectRef) value : NULL); + for (size_t index(0); index != type->data.data.size; ++index) { + ffi_type *field(ffi->elements[index]); + + JSValueRef rhs; + if (aggregate == NULL) + rhs = value; + else { + rhs = CYGetProperty(context, aggregate, index); + if (JSValueIsUndefined(context, rhs)) + throw CYJSError(context, "unable to extract array value"); + } + + CYPoolFFI(pool, context, type->data.data.type, field, base, rhs); + // XXX: alignment? + base += field->size; + } + } break; + case sig::pointer_P: *reinterpret_cast(data) = CYCastPointer(context, value); break; @@ -750,8 +828,7 @@ void CYPoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, ffi_type if ((*hooks_->PoolFFI)(pool, context, type, ffi, data, value)) return; - fprintf(stderr, "CYPoolFFI(%c)\n", type->primitive); - _assert(false); + CYThrow("unimplemented signature code: '%c''\n", type->primitive); } } @@ -777,9 +854,14 @@ JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void CYFromFFI_(float, float) CYFromFFI_(double, double) + case sig::array_P: + if (void *pointer = data) + return CYMakePointer(context, pointer, type->data.data.size, type->data.data.type, NULL, owner); + else goto null; + case sig::pointer_P: if (void *pointer = *reinterpret_cast(data)) - return CYMakePointer(context, pointer, type->data.data.type, ffi, owner); + return CYMakePointer(context, pointer, _not(size_t), type->data.data.type, NULL, owner); else goto null; case sig::string_P: @@ -799,8 +881,7 @@ JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void if (JSValueRef value = (*hooks_->FromFFI)(context, type, ffi, data, initialize, owner)) return value; - fprintf(stderr, "CYFromFFI(%c)\n", type->primitive); - _assert(false); + CYThrow("unimplemented signature code: '%c''\n", type->primitive); } } @@ -822,7 +903,7 @@ static void FunctionClosure_(ffi_cif *cif, void *result, void **arguments, void Closure_privateData *CYMakeFunctor_(JSContextRef context, JSObjectRef function, const char *type, void (*callback)(ffi_cif *, void *, void **, void *)) { // XXX: in case of exceptions this will leak // XXX: in point of fact, this may /need/ to leak :( - Closure_privateData *internal(new Closure_privateData(CYGetJSContext(), function, type)); + Closure_privateData *internal(new Closure_privateData(context, function, type)); ffi_closure *closure((ffi_closure *) _syscall(mmap( NULL, sizeof(ffi_closure), @@ -842,12 +923,21 @@ Closure_privateData *CYMakeFunctor_(JSContextRef context, JSObjectRef function, static JSObjectRef CYMakeFunctor(JSContextRef context, JSObjectRef function, const char *type) { Closure_privateData *internal(CYMakeFunctor_(context, function, type, &FunctionClosure_)); - return JSObjectMake(context, Functor_, internal); + JSObjectRef object(JSObjectMake(context, Functor_, internal)); + // XXX: see above notes about needing to leak + JSValueProtect(CYGetJSContext(context), object); + return object; +} + +JSObjectRef CYGetCachedObject(JSContextRef context, JSStringRef name) { + return CYCastJSObject(context, CYGetProperty(context, CYCastJSObject(context, CYGetProperty(context, CYGetGlobalObject(context), cy_s)), name)); } static JSObjectRef CYMakeFunctor(JSContextRef context, JSValueRef value, const char *type) { + JSObjectRef Function(CYGetCachedObject(context, CYJSString("Function"))); + JSValueRef exception(NULL); - bool function(JSValueIsInstanceOfConstructor(context, value, Function_, &exception)); + bool function(JSValueIsInstanceOfConstructor(context, value, Function, &exception)); CYThrow(context, exception); if (function) { @@ -902,52 +992,34 @@ static bool Index_(apr_pool_t *pool, JSContextRef context, Struct_privateData *i return true; } -static JSValueRef Pointer_getIndex(JSContextRef context, JSObjectRef object, size_t index, JSValueRef *exception) { CYTry { +static JSValueRef Pointer_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry { + CYPool pool; Pointer *internal(reinterpret_cast(JSObjectGetPrivate(object))); - Type_privateData *typical(internal->type_); - - ffi_type *ffi(typical->GetFFI()); - - uint8_t *base(reinterpret_cast(internal->value_)); - base += ffi->size * index; - JSObjectRef owner(internal->GetOwner() ?: object); - return CYFromFFI(context, typical->type_, ffi, base, false, owner); -} CYCatch } + if (JSStringIsEqual(property, length_s)) + return internal->length_ == _not(size_t) ? CYJSUndefined(context) : CYCastJSValue(context, internal->length_); -static JSValueRef Pointer_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { - CYPool pool; - Pointer *internal(reinterpret_cast(JSObjectGetPrivate(object))); Type_privateData *typical(internal->type_); if (typical->type_ == NULL) return NULL; ssize_t offset; - if (!CYGetOffset(pool, context, property, offset)) + if (JSStringIsEqualToUTF8CString(property, "$cyi")) + offset = 0; + else if (!CYGetOffset(pool, context, property, offset)) return NULL; - return Pointer_getIndex(context, object, offset, exception); -} - -static JSValueRef Pointer_getProperty_$cyi(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { - return Pointer_getIndex(context, object, 0, exception); -} - -static bool Pointer_setIndex(JSContextRef context, JSObjectRef object, size_t index, JSValueRef value, JSValueRef *exception) { CYTry { - Pointer *internal(reinterpret_cast(JSObjectGetPrivate(object))); - Type_privateData *typical(internal->type_); - ffi_type *ffi(typical->GetFFI()); uint8_t *base(reinterpret_cast(internal->value_)); - base += ffi->size * index; + base += ffi->size * offset; - CYPoolFFI(NULL, context, typical->type_, ffi, base, value); - return true; + JSObjectRef owner(internal->GetOwner() ?: object); + return CYFromFFI(context, typical->type_, ffi, base, false, owner); } CYCatch } -static bool Pointer_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { +static bool Pointer_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry { CYPool pool; Pointer *internal(reinterpret_cast(JSObjectGetPrivate(object))); Type_privateData *typical(internal->type_); @@ -956,20 +1028,24 @@ static bool Pointer_setProperty(JSContextRef context, JSObjectRef object, JSStri return NULL; ssize_t offset; - if (!CYGetOffset(pool, context, property, offset)) + if (JSStringIsEqualToUTF8CString(property, "$cyi")) + offset = 0; + else if (!CYGetOffset(pool, context, property, offset)) return NULL; - return Pointer_setIndex(context, object, offset, value, exception); -} + ffi_type *ffi(typical->GetFFI()); -static bool Pointer_setProperty_$cyi(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { - return Pointer_setIndex(context, object, 0, value, exception); -} + uint8_t *base(reinterpret_cast(internal->value_)); + base += ffi->size * offset; + + CYPoolFFI(NULL, context, typical->type_, ffi, base, value); + return true; +} CYCatch } static JSValueRef Struct_callAsFunction_$cya(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { Struct_privateData *internal(reinterpret_cast(JSObjectGetPrivate(_this))); Type_privateData *typical(internal->type_); - return CYMakePointer(context, internal->value_, typical->type_, typical->ffi_, _this); + return CYMakePointer(context, internal->value_, _not(size_t), typical->type_, typical->ffi_, _this); } static JSValueRef Struct_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry { @@ -1021,7 +1097,7 @@ static void Struct_getPropertyNames(JSContextRef context, JSObjectRef object, JS name = elements[index].name; if (name == NULL) { - sprintf(number, "%lu", index); + sprintf(number, "%zu", index); name = number; } @@ -1062,7 +1138,7 @@ static JSValueRef Functor_callAsFunction(JSContextRef context, JSObjectRef objec } static JSObjectRef CYMakeType(JSContextRef context, const char *type) { - Type_privateData *internal(new Type_privateData(NULL, type)); + Type_privateData *internal(new Type_privateData(type)); return JSObjectMake(context, Type_privateData::Class_, internal); } @@ -1075,7 +1151,13 @@ static void *CYCastSymbol(const char *name) { return dlsym(RTLD_DEFAULT, name); } -static JSValueRef Runtime_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry { +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")))); + if (JSValueRef value = CYGetProperty(context, cycript, property)) + if (!JSValueIsUndefined(context, value)) + return value; + CYPool pool; CYUTF8String name(CYPoolUTF8String(pool, context, property)); @@ -1117,18 +1199,22 @@ static JSValueRef Runtime_getProperty(JSContextRef context, JSObjectRef object, return NULL; case 0: - return JSEvaluateScript(CYGetJSContext(), CYJSString(value), NULL, NULL, 0, NULL); - case 1: - return CYMakeFunctor(context, reinterpret_cast(CYCastSymbol(name.data)), value); + return JSEvaluateScript(CYGetJSContext(context), CYJSString(value), NULL, NULL, 0, NULL); - case 2: { - // XXX: this is horrendously inefficient - sig::Signature signature; - sig::Parse(pool, &signature, value, &Structor_); - ffi_cif cif; - sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif); - return CYFromFFI(context, signature.elements[0].type, cif.rtype, CYCastSymbol(name.data)); - } + case 1: + if (void (*symbol)() = reinterpret_cast(CYCastSymbol(name.data))) + return CYMakeFunctor(context, symbol, value); + else return NULL; + + case 2: + if (void *symbol = CYCastSymbol(name.data)) { + // XXX: this is horrendously inefficient + sig::Signature signature; + sig::Parse(pool, &signature, 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: @@ -1148,7 +1234,7 @@ static JSObjectRef Pointer_new(JSContextRef context, JSObjectRef object, size_t sig::Signature signature; sig::Parse(pool, &signature, type, &Structor_); - return CYMakePointer(context, value, signature.elements[0].type, NULL, NULL); + return CYMakePointer(context, value, _not(size_t), signature.elements[0].type, NULL, NULL); } CYCatch } static JSObjectRef Type_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { @@ -1204,17 +1290,17 @@ static JSObjectRef Type_callAsConstructor(JSContextRef context, JSObjectRef obje Type_privateData *internal(reinterpret_cast(JSObjectGetPrivate(object))); sig::Type *type(internal->type_); - size_t size; + size_t length; if (type->primitive != sig::array_P) - size = 0; + length = _not(size_t); else { - size = type->data.data.size; + length = type->data.data.size; type = type->data.data.type; } void *value(malloc(internal->GetFFI()->size)); - return CYMakePointer(context, value, type, NULL, NULL); + return CYMakePointer(context, value, length, type, NULL, NULL); } CYCatch } static JSObjectRef Functor_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { @@ -1235,13 +1321,25 @@ 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(JSObjectGetPrivate(_this))); + CYValue *internal(reinterpret_cast(JSObjectGetPrivate(_this))); char string[32]; sprintf(string, "%p", internal->value_); - return CYCastJSValue(context, string); } CYCatch } +static JSValueRef Pointer_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { + Pointer *internal(reinterpret_cast(JSObjectGetPrivate(_this))); + if (internal->length_ != _not(size_t)) { + JSObjectRef Array(CYGetCachedObject(context, Array_s)); + JSObjectRef toCYON(CYCastJSObject(context, CYGetProperty(context, Array, toCYON_s))); + return CYCallAsFunction(context, toCYON, _this, count, arguments); + } else { + char string[32]; + sprintf(string, "%p", internal->value_); + return CYCastJSValue(context, string); + } +} CYCatch } + static JSValueRef Type_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { Type_privateData *internal(reinterpret_cast(JSObjectGetPrivate(_this))); CYPool pool; @@ -1267,13 +1365,8 @@ static JSValueRef Type_callAsFunction_toJSON(JSContextRef context, JSObjectRef o return Type_callAsFunction_toString(context, object, _this, count, arguments, exception); } -static JSStaticValue Pointer_staticValues[2] = { - {"$cyi", &Pointer_getProperty_$cyi, &Pointer_setProperty_$cyi, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, - {NULL, NULL, NULL, 0} -}; - static JSStaticFunction Pointer_staticFunctions[4] = { - {"toCYON", &CYValue_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, + {"toCYON", &Pointer_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {"toJSON", &CYValue_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {"valueOf", &CYValue_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {NULL, NULL, 0} @@ -1302,7 +1395,7 @@ static JSStaticFunction Type_staticFunctions[4] = { {NULL, NULL, 0} }; -static JSObjectRef (*$JSObjectMakeArray)(JSContextRef, size_t, const JSValueRef[], JSValueRef *); +static JSObjectRef (*JSObjectMakeArray$)(JSContextRef, size_t, const JSValueRef[], JSValueRef *); void CYSetArgs(int argc, const char *argv[]) { JSContextRef context(CYGetJSContext()); @@ -1311,16 +1404,18 @@ void CYSetArgs(int argc, const char *argv[]) { args[i] = CYCastJSValue(context, argv[i]); JSObjectRef array; - if ($JSObjectMakeArray != NULL) { + if (JSObjectMakeArray$ != NULL) { JSValueRef exception(NULL); - array = (*$JSObjectMakeArray)(context, argc, args, &exception); + array = (*JSObjectMakeArray$)(context, argc, args, &exception); CYThrow(context, exception); } else { - JSValueRef value(CYCallAsFunction(context, Array_, NULL, argc, args)); + JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array"))); + JSValueRef value(CYCallAsFunction(context, Array, NULL, argc, args)); array = CYCastJSObject(context, value); } - CYSetProperty(context, System_, CYJSString("args"), array); + JSObjectRef System(CYGetCachedObject(context, CYJSString("System"))); + CYSetProperty(context, System, CYJSString("args"), array); } JSObjectRef CYGetGlobalObject(JSContextRef context) { @@ -1369,6 +1464,35 @@ const char *CYExecute(apr_pool_t *pool, const char *code) { return json; } +extern "C" void CydgetSetupContext(JSGlobalContextRef context) { + CYSetupContext(context); +} + +extern "C" void CydgetPoolParse(apr_pool_t *pool, const uint16_t **data, size_t *size) { + CYDriver driver(""); + cy::parser parser(driver); + + CYUTF8String utf8(CYPoolUTF8String(pool, CYUTF16String(*data, *size))); + + driver.data_ = utf8.data; + driver.size_ = utf8.size; + + if (parser.parse() != 0 || !driver.errors_.empty()) + return; + + CYContext context(driver.pool_); + driver.program_->Replace(context); + std::ostringstream str; + CYOutput out(str); + out << *driver.program_; + std::string code(str.str()); + + CYUTF16String utf16(CYPoolUTF16String(pool, CYUTF8String(code.c_str(), code.size()))); + + *data = utf16.data; + *size = utf16.size; +} + static apr_pool_t *Pool_; static bool initialized_; @@ -1382,7 +1506,73 @@ void CYInitialize() { _aprcall(apr_pool_create(&Pool_, NULL)); _sqlcall(sqlite3_open("/usr/lib/libcycript.db", &Bridge_)); - $JSObjectMakeArray = reinterpret_cast(dlsym(RTLD_DEFAULT, "JSObjectMakeArray")); + JSObjectMakeArray$ = reinterpret_cast(dlsym(RTLD_DEFAULT, "JSObjectMakeArray")); + + JSClassDefinition definition; + + definition = kJSClassDefinitionEmpty; + definition.className = "All"; + definition.getProperty = &All_getProperty; + All_ = JSClassCreate(&definition); + + definition = kJSClassDefinitionEmpty; + definition.className = "Context"; + definition.finalize = &CYFinalize; + Context_ = JSClassCreate(&definition); + + definition = kJSClassDefinitionEmpty; + definition.className = "Functor"; + definition.staticFunctions = cy::Functor::StaticFunctions; + definition.callAsFunction = &Functor_callAsFunction; + definition.finalize = &CYFinalize; + Functor_ = JSClassCreate(&definition); + + definition = kJSClassDefinitionEmpty; + definition.className = "Pointer"; + definition.staticFunctions = Pointer_staticFunctions; + definition.getProperty = &Pointer_getProperty; + definition.setProperty = &Pointer_setProperty; + definition.finalize = &CYFinalize; + Pointer_ = JSClassCreate(&definition); + + definition = kJSClassDefinitionEmpty; + definition.className = "Struct"; + definition.staticFunctions = Struct_staticFunctions; + definition.getProperty = &Struct_getProperty; + definition.setProperty = &Struct_setProperty; + definition.getPropertyNames = &Struct_getPropertyNames; + definition.finalize = &CYFinalize; + Struct_ = JSClassCreate(&definition); + + definition = kJSClassDefinitionEmpty; + definition.className = "Type"; + definition.staticFunctions = Type_staticFunctions; + definition.getProperty = &Type_getProperty; + definition.callAsFunction = &Type_callAsFunction; + definition.callAsConstructor = &Type_callAsConstructor; + definition.finalize = &CYFinalize; + Type_privateData::Class_ = JSClassCreate(&definition); + + definition = kJSClassDefinitionEmpty; + //definition.getProperty = &Global_getProperty; + Global_ = JSClassCreate(&definition); + + Array_s = JSStringCreateWithUTF8CString("Array"); + cy_s = JSStringCreateWithUTF8CString("$cy"); + length_s = JSStringCreateWithUTF8CString("length"); + message_s = JSStringCreateWithUTF8CString("message"); + name_s = JSStringCreateWithUTF8CString("name"); + pop_s = JSStringCreateWithUTF8CString("pop"); + prototype_s = JSStringCreateWithUTF8CString("prototype"); + push_s = JSStringCreateWithUTF8CString("push"); + splice_s = JSStringCreateWithUTF8CString("splice"); + toCYON_s = JSStringCreateWithUTF8CString("toCYON"); + toJSON_s = JSStringCreateWithUTF8CString("toJSON"); + + Result_ = JSStringCreateWithUTF8CString("_"); + + if (hooks_ != NULL && hooks_->Initialize != NULL) + (*hooks_->Initialize)(); } apr_pool_t *CYGetGlobalPool() { @@ -1396,7 +1586,8 @@ void CYThrow(JSContextRef context, JSValueRef value) { } const char *CYJSError::PoolCString(apr_pool_t *pool) const { - return CYPoolCString(pool, context_, value_); + // XXX: this used to be CYPoolCString + return CYPoolCCYON(pool, context_, value_); } JSValueRef CYJSError::CastJSValue(JSContextRef context) const { @@ -1406,10 +1597,10 @@ JSValueRef CYJSError::CastJSValue(JSContextRef context) const { void CYThrow(const char *format, ...) { va_list args; - va_start (args, format); + va_start(args, format); throw CYPoolError(format, args); // XXX: does this matter? :( - va_end (args); + va_end(args); } const char *CYPoolError::PoolCString(apr_pool_t *pool) const { @@ -1418,162 +1609,134 @@ const char *CYPoolError::PoolCString(apr_pool_t *pool) const { CYPoolError::CYPoolError(const char *format, ...) { va_list args; - va_start (args, format); + va_start(args, format); message_ = apr_pvsprintf(pool_, format, args); - va_end (args); + va_end(args); } CYPoolError::CYPoolError(const char *format, va_list args) { message_ = apr_pvsprintf(pool_, format, args); } +JSValueRef CYCastJSError(JSContextRef context, const char *message) { + JSObjectRef Error(CYGetCachedObject(context, CYJSString("Error"))); + + JSValueRef arguments[1] = {CYCastJSValue(context, message)}; + + JSValueRef exception(NULL); + JSValueRef value(JSObjectCallAsConstructor(context, Error, 1, arguments, &exception)); + CYThrow(context, exception); + + return value; +} + JSValueRef CYPoolError::CastJSValue(JSContextRef context) const { - return CYCastJSValue(context, message_); + return CYCastJSError(context, message_); } CYJSError::CYJSError(JSContextRef context, const char *format, ...) { - if (context == NULL) - context = CYGetJSContext(); + _assert(context != NULL); CYPool pool; va_list args; - va_start (args, format); + va_start(args, format); const char *message(apr_pvsprintf(pool, format, args)); - va_end (args); + va_end(args); - JSValueRef arguments[1] = {CYCastJSValue(context, CYJSString(message))}; - - JSValueRef exception(NULL); - value_ = JSObjectCallAsConstructor(context, Error_, 1, arguments, &exception); - CYThrow(context, exception); + value_ = CYCastJSError(context, message); } -void CYObjectiveC(JSContextRef context, JSObjectRef global); +JSGlobalContextRef CYGetJSContext(JSContextRef context) { + return reinterpret_cast(JSObjectGetPrivate(CYCastJSObject(context, CYGetProperty(context, CYGetGlobalObject(context), cy_s))))->context_; +} -JSGlobalContextRef CYGetJSContext() { +extern "C" void CYSetupContext(JSGlobalContextRef context) { CYInitialize(); - if (Context_ == NULL) { - JSClassDefinition definition; - - definition = kJSClassDefinitionEmpty; - definition.className = "Functor"; - definition.staticFunctions = cy::Functor::StaticFunctions; - definition.callAsFunction = &Functor_callAsFunction; - definition.finalize = &CYFinalize; - Functor_ = JSClassCreate(&definition); - - definition = kJSClassDefinitionEmpty; - definition.className = "Pointer"; - definition.staticValues = Pointer_staticValues; - definition.staticFunctions = Pointer_staticFunctions; - definition.getProperty = &Pointer_getProperty; - definition.setProperty = &Pointer_setProperty; - definition.finalize = &CYFinalize; - Pointer_ = JSClassCreate(&definition); + JSObjectRef global(CYGetGlobalObject(context)); - definition = kJSClassDefinitionEmpty; - definition.className = "Struct"; - definition.staticFunctions = Struct_staticFunctions; - definition.getProperty = &Struct_getProperty; - definition.setProperty = &Struct_setProperty; - definition.getPropertyNames = &Struct_getPropertyNames; - definition.finalize = &CYFinalize; - Struct_ = JSClassCreate(&definition); + JSObjectRef cy(JSObjectMake(context, Context_, new Context(context))); + CYSetProperty(context, global, cy_s, cy, kJSPropertyAttributeDontEnum); - definition = kJSClassDefinitionEmpty; - definition.className = "Type"; - definition.staticFunctions = Type_staticFunctions; - definition.getProperty = &Type_getProperty; - definition.callAsFunction = &Type_callAsFunction; - definition.callAsConstructor = &Type_callAsConstructor; - definition.finalize = &CYFinalize; - Type_privateData::Class_ = JSClassCreate(&definition); +/* Cache Globals {{{ */ + JSObjectRef Array(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Array")))); + CYSetProperty(context, cy, CYJSString("Array"), Array); - definition = kJSClassDefinitionEmpty; - definition.className = "Runtime"; - definition.getProperty = &Runtime_getProperty; - Runtime_ = JSClassCreate(&definition); + JSObjectRef Array_prototype(CYCastJSObject(context, CYGetProperty(context, Array, prototype_s))); + CYSetProperty(context, cy, CYJSString("Array_prototype"), Array_prototype); - definition = kJSClassDefinitionEmpty; - //definition.getProperty = &Global_getProperty; - JSClassRef Global(JSClassCreate(&definition)); + JSObjectRef Error(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Error")))); + CYSetProperty(context, cy, CYJSString("Error"), Error); - JSGlobalContextRef context(JSGlobalContextCreate(Global)); - Context_ = context; - JSObjectRef global(CYGetGlobalObject(context)); + JSObjectRef Function(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Function")))); + CYSetProperty(context, cy, CYJSString("Function"), Function); - JSObjectSetPrototype(context, global, JSObjectMake(context, Runtime_, NULL)); + JSObjectRef Function_prototype(CYCastJSObject(context, CYGetProperty(context, Function, prototype_s))); + CYSetProperty(context, cy, CYJSString("Function_prototype"), Function_prototype); - Array_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Array"))); - JSValueProtect(context, Array_); + JSObjectRef Object(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Object")))); + CYSetProperty(context, cy, CYJSString("Object"), Object); - Error_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Error"))); - JSValueProtect(context, Error_); + JSObjectRef Object_prototype(CYCastJSObject(context, CYGetProperty(context, Object, prototype_s))); + CYSetProperty(context, cy, CYJSString("Object_prototype"), Object_prototype); - Function_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Function"))); - JSValueProtect(context, Function_); + JSObjectRef String(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("String")))); + CYSetProperty(context, cy, CYJSString("String"), String); +/* }}} */ - String_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("String"))); - JSValueProtect(context, String_); + CYSetProperty(context, Array_prototype, toCYON_s, &Array_callAsFunction_toCYON, kJSPropertyAttributeDontEnum); - length_ = JSStringCreateWithUTF8CString("length"); - message_ = JSStringCreateWithUTF8CString("message"); - name_ = JSStringCreateWithUTF8CString("name"); - prototype_ = JSStringCreateWithUTF8CString("prototype"); - toCYON_ = JSStringCreateWithUTF8CString("toCYON"); - toJSON_ = JSStringCreateWithUTF8CString("toJSON"); + JSObjectRef cycript(JSObjectMake(context, NULL, NULL)); + CYSetProperty(context, global, CYJSString("Cycript"), cycript); + CYSetProperty(context, cycript, CYJSString("gc"), &Cycript_gc_callAsFunction); - JSObjectRef Object(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Object")))); - Object_prototype_ = CYCastJSObject(context, CYGetProperty(context, Object, prototype_)); - JSValueProtect(context, Object_prototype_); + JSObjectRef Functor(JSObjectMakeConstructor(context, Functor_, &Functor_new)); + JSObjectSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Functor, prototype_s)), Function_prototype); + CYSetProperty(context, cycript, CYJSString("Functor"), Functor); - Array_prototype_ = CYCastJSObject(context, CYGetProperty(context, Array_, prototype_)); - Array_pop_ = CYCastJSObject(context, CYGetProperty(context, Array_prototype_, CYJSString("pop"))); - Array_push_ = CYCastJSObject(context, CYGetProperty(context, Array_prototype_, CYJSString("push"))); - Array_splice_ = CYCastJSObject(context, CYGetProperty(context, Array_prototype_, CYJSString("splice"))); + CYSetProperty(context, cycript, CYJSString("Pointer"), JSObjectMakeConstructor(context, Pointer_, &Pointer_new)); + CYSetProperty(context, cycript, CYJSString("Type"), JSObjectMakeConstructor(context, Type_privateData::Class_, &Type_new)); - CYSetProperty(context, Array_prototype_, toCYON_, JSObjectMakeFunctionWithCallback(context, toCYON_, &Array_callAsFunction_toCYON), kJSPropertyAttributeDontEnum); + JSObjectRef all(JSObjectMake(context, All_, NULL)); + CYSetProperty(context, cycript, CYJSString("all"), all); - JSValueProtect(context, Array_prototype_); - JSValueProtect(context, Array_pop_); - JSValueProtect(context, Array_push_); - JSValueProtect(context, Array_splice_); + JSObjectRef last(NULL), curr(global); - JSObjectRef Functor(JSObjectMakeConstructor(context, Functor_, &Functor_new)); + goto next; for (JSValueRef next;;) { + if (JSValueIsNull(context, next)) + break; + last = curr; + curr = CYCastJSObject(context, next); + next: + next = JSObjectGetPrototype(context, curr); + } - Function_prototype_ = (JSObjectRef) CYGetProperty(context, Function_, prototype_); - JSValueProtect(context, Function_prototype_); + JSObjectSetPrototype(context, last, all); - JSObjectSetPrototype(context, (JSObjectRef) CYGetProperty(context, Functor, prototype_), Function_prototype_); + CYSetProperty(context, global, CYJSString("$cyq"), &$cyq); - CYSetProperty(context, global, CYJSString("Functor"), Functor); - CYSetProperty(context, global, CYJSString("Pointer"), JSObjectMakeConstructor(context, Pointer_, &Pointer_new)); - CYSetProperty(context, global, CYJSString("Type"), JSObjectMakeConstructor(context, Type_privateData::Class_, &Type_new)); + JSObjectRef System(JSObjectMake(context, NULL, NULL)); + CYSetProperty(context, cy, CYJSString("System"), Function); - JSObjectRef cycript(JSObjectMake(context, NULL, NULL)); - CYSetProperty(context, global, CYJSString("Cycript"), cycript); - CYSetProperty(context, cycript, CYJSString("gc"), JSObjectMakeFunctionWithCallback(context, CYJSString("gc"), &Cycript_gc_callAsFunction)); - - CYSetProperty(context, global, CYJSString("$cyq"), JSObjectMakeFunctionWithCallback(context, CYJSString("$cyq"), &$cyq)); - - System_ = JSObjectMake(context, NULL, NULL); - JSValueProtect(context, System_); - - CYSetProperty(context, global, CYJSString("system"), System_); - CYSetProperty(context, System_, CYJSString("args"), CYJSNull(context)); - //CYSetProperty(context, System_, CYJSString("global"), global); - - CYSetProperty(context, System_, CYJSString("print"), JSObjectMakeFunctionWithCallback(context, CYJSString("print"), &System_print)); + CYSetProperty(context, global, CYJSString("system"), System); + CYSetProperty(context, System, CYJSString("args"), CYJSNull(context)); + //CYSetProperty(context, System, CYJSString("global"), global); + CYSetProperty(context, System, CYJSString("print"), &System_print); - Result_ = JSStringCreateWithUTF8CString("_"); + if (hooks_ != NULL && hooks_->SetupContext != NULL) + (*hooks_->SetupContext)(context); +} -// XXX: this is very wrong and sad -#ifdef __APPLE__ - CYObjectiveC(context, global); -#endif +JSGlobalContextRef CYGetJSContext() { + CYInitialize(); + + static JSGlobalContextRef context_; + + if (context_ == NULL) { + context_ = JSGlobalContextCreate(Global_); + CYSetupContext(context_); } - return Context_; + return context_; }