1 /* Cycript - Inlining/Optimizing JavaScript Compiler
2 * Copyright (C) 2009 Jay Freeman (saurik)
5 /* Modified BSD License {{{ */
7 * Redistribution and use in source and binary
8 * forms, with or without modification, are permitted
9 * provided that the following conditions are met:
11 * 1. Redistributions of source code must retain the
12 * above copyright notice, this list of conditions
13 * and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the
15 * above copyright notice, this list of conditions
16 * and the following disclaimer in the documentation
17 * and/or other materials provided with the
19 * 3. The name of the author may not be used to endorse
20 * or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
25 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
34 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
36 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 #include "Internal.hpp"
47 #include "cycript.hpp"
49 #include "sig/parse.hpp"
50 #include "sig/ffi_type.hpp"
52 #include "Pooling.hpp"
57 #include <ext/stdio_filebuf.h>
65 #include "Cycript.tab.hh"
68 #include "JavaScript.hpp"
73 catch (NSException *error) { \
74 CYThrow(context, error, exception); \
81 char *sqlite3_column_pooled(apr_pool_t
*pool
, sqlite3_stmt
*stmt
, int n
) {
82 if (const unsigned char *value
= sqlite3_column_text(stmt
, n
))
83 return apr_pstrdup(pool
, (const char *) value
);
87 struct CYHooks
*hooks_
;
89 /* JavaScript Properties {{{ */
90 JSValueRef
CYGetProperty(JSContextRef context
, JSObjectRef object
, size_t index
) {
91 JSValueRef
exception(NULL
);
92 JSValueRef
value(JSObjectGetPropertyAtIndex(context
, object
, index
, &exception
));
93 CYThrow(context
, exception
);
97 JSValueRef
CYGetProperty(JSContextRef context
, JSObjectRef object
, JSStringRef name
) {
98 JSValueRef
exception(NULL
);
99 JSValueRef
value(JSObjectGetProperty(context
, object
, name
, &exception
));
100 CYThrow(context
, exception
);
104 void CYSetProperty(JSContextRef context
, JSObjectRef object
, size_t index
, JSValueRef value
) {
105 JSValueRef
exception(NULL
);
106 JSObjectSetPropertyAtIndex(context
, object
, index
, value
, &exception
);
107 CYThrow(context
, exception
);
110 void CYSetProperty(JSContextRef context
, JSObjectRef object
, JSStringRef name
, JSValueRef value
, JSPropertyAttributes attributes
) {
111 JSValueRef
exception(NULL
);
112 JSObjectSetProperty(context
, object
, name
, value
, attributes
, &exception
);
113 CYThrow(context
, exception
);
116 /* JavaScript Strings {{{ */
117 JSStringRef
CYCopyJSString(const char *value
) {
118 return value
== NULL
? NULL
: JSStringCreateWithUTF8CString(value
);
121 JSStringRef
CYCopyJSString(JSStringRef value
) {
122 return value
== NULL
? NULL
: JSStringRetain(value
);
125 JSStringRef
CYCopyJSString(CYUTF8String value
) {
126 // XXX: this is very wrong
127 return CYCopyJSString(value
.data
);
130 JSStringRef
CYCopyJSString(JSContextRef context
, JSValueRef value
) {
131 if (JSValueIsNull(context
, value
))
133 JSValueRef
exception(NULL
);
134 JSStringRef
string(JSValueToStringCopy(context
, value
, &exception
));
135 CYThrow(context
, exception
);
139 static CYUTF16String
CYCastUTF16String(JSStringRef value
) {
140 return CYUTF16String(JSStringGetCharactersPtr(value
), JSStringGetLength(value
));
143 template <typename Type_
>
144 _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
) {
145 return iconv(cd
, const_cast<Type_
>(inbuf
), inbytesleft
, outbuf
, outbytesleft
);
148 static CYUTF8String
CYPoolUTF8String(apr_pool_t
*pool
, JSContextRef context
, JSStringRef value
) {
149 _assert(pool
!= NULL
);
151 CYUTF16String
utf16(CYCastUTF16String(value
));
152 const char *in(reinterpret_cast<const char *>(utf16
.data
));
155 iconv_t
conversion(_syscall(iconv_open("UTF-8", "UCS-2-INTERNAL")));
157 iconv_t
conversion(_syscall(iconv_open("UTF-8", "UCS-2")));
160 size_t size(JSStringGetMaximumUTF8CStringSize(value
));
161 char *out(new(pool
) char[size
]);
162 CYUTF8String
utf8(out
, size
);
164 size
= utf16
.size
* 2;
165 _syscall(iconv_(&iconv
, conversion
, const_cast<char **>(&in
), &size
, &out
, &utf8
.size
));
168 utf8
.size
= out
- utf8
.data
;
170 _syscall(iconv_close(conversion
));
175 const char *CYPoolCString(apr_pool_t
*pool
, JSContextRef context
, JSStringRef value
) {
176 CYUTF8String
utf8(CYPoolUTF8String(pool
, context
, value
));
177 _assert(memchr(utf8
.data
, '\0', utf8
.size
) == NULL
);
181 const char *CYPoolCString(apr_pool_t
*pool
, JSContextRef context
, JSValueRef value
) {
182 return JSValueIsNull(context
, value
) ? NULL
: CYPoolCString(pool
, context
, CYJSString(context
, value
));
186 /* Index Offsets {{{ */
187 size_t CYGetIndex(const CYUTF8String
&value
) {
188 if (value
.data
[0] != '0') {
190 size_t index(strtoul(value
.data
, &end
, 10));
191 if (value
.data
+ value
.size
== end
)
193 } else if (value
.data
[1] == '\0')
198 size_t CYGetIndex(apr_pool_t
*pool
, JSContextRef context
, JSStringRef value
) {
199 return CYGetIndex(CYPoolUTF8String(pool
, context
, value
));
202 bool CYGetOffset(const char *value
, ssize_t
&index
) {
203 if (value
[0] != '0') {
205 index
= strtol(value
, &end
, 10);
206 if (value
+ strlen(value
) == end
)
208 } else if (value
[1] == '\0') {
217 /* JavaScript *ify {{{ */
218 void CYStringify(std::ostringstream
&str
, const char *data
, size_t size
) {
219 unsigned quot(0), apos(0);
220 for (const char *value(data
), *end(data
+ size
); value
!= end
; ++value
)
223 else if (*value
== '\'')
226 bool single(quot
> apos
);
228 str
<< (single
? '\'' : '"');
230 for (const char *value(data
), *end(data
+ size
); value
!= end
; ++value
)
232 case '\\': str
<< "\\\\"; break;
233 case '\b': str
<< "\\b"; break;
234 case '\f': str
<< "\\f"; break;
235 case '\n': str
<< "\\n"; break;
236 case '\r': str
<< "\\r"; break;
237 case '\t': str
<< "\\t"; break;
238 case '\v': str
<< "\\v"; break;
253 if (*value
< 0x20 || *value
>= 0x7f)
254 str
<< "\\x" << std::setbase(16) << std::setw(2) << std::setfill('0') << unsigned(*value
);
259 str
<< (single
? '\'' : '"');
262 void CYNumerify(std::ostringstream
&str
, double value
) {
264 // XXX: I want this to print 1e3 rather than 1000
265 sprintf(string
, "%.17g", value
);
269 bool CYIsKey(CYUTF8String value
) {
270 const char *data(value
.data
);
271 size_t size(value
.size
);
276 if (DigitRange_
[data
[0]]) {
277 size_t index(CYGetIndex(value
));
278 if (index
== _not(size_t))
281 if (!WordStartRange_
[data
[0]])
283 for (size_t i(1); i
!= size
; ++i
)
284 if (!WordEndRange_
[data
[i
]])
292 static JSGlobalContextRef Context_
;
293 static JSObjectRef System_
;
295 static JSClassRef Functor_
;
296 static JSClassRef Pointer_
;
297 static JSClassRef Runtime_
;
298 static JSClassRef Struct_
;
300 static JSStringRef Result_
;
304 JSObjectRef Function_
;
308 JSStringRef message_
;
310 JSStringRef prototype_
;
314 JSObjectRef Object_prototype_
;
315 JSObjectRef Function_prototype_
;
317 JSObjectRef Array_prototype_
;
318 JSObjectRef Array_pop_
;
319 JSObjectRef Array_push_
;
320 JSObjectRef Array_splice_
;
324 void CYFinalize(JSObjectRef object
) {
325 delete reinterpret_cast<CYData
*>(JSObjectGetPrivate(object
));
328 struct CStringMapLess
:
329 std::binary_function
<const char *, const char *, bool>
331 _finline
bool operator ()(const char *lhs
, const char *rhs
) const {
332 return strcmp(lhs
, rhs
) < 0;
336 void Structor_(apr_pool_t
*pool
, const char *name
, const char *types
, sig::Type
*&type
) {
340 sqlite3_stmt
*statement
;
342 _sqlcall(sqlite3_prepare(Bridge_
,
344 "\"bridge\".\"mode\", "
345 "\"bridge\".\"value\" "
348 " \"bridge\".\"mode\" in (3, 4) and"
349 " \"bridge\".\"name\" = ?"
351 , -1, &statement
, NULL
));
353 _sqlcall(sqlite3_bind_text(statement
, 1, name
, -1, SQLITE_STATIC
));
358 if (_sqlcall(sqlite3_step(statement
)) == SQLITE_DONE
) {
362 mode
= sqlite3_column_int(statement
, 0);
363 value
= sqlite3_column_pooled(pool
, statement
, 1);
366 _sqlcall(sqlite3_finalize(statement
));
375 sig::Parse(pool
, &type
->data
.signature
, value
, &Structor_
);
379 sig::Signature signature
;
380 sig::Parse(pool
, &signature
, value
, &Structor_
);
381 type
= signature
.elements
[0].type
;
386 JSClassRef
Type_privateData::Class_
;
391 Type_privateData
*type_
;
393 Pointer(void *value
, JSContextRef context
, JSObjectRef owner
, sig::Type
*type
) :
394 CYOwned(value
, context
, owner
),
395 type_(new(pool_
) Type_privateData(type
))
400 struct Struct_privateData
:
403 Type_privateData
*type_
;
405 Struct_privateData(JSContextRef context
, JSObjectRef owner
) :
406 CYOwned(NULL
, context
, owner
)
411 typedef std::map
<const char *, Type_privateData
*, CStringMapLess
> TypeMap
;
412 static TypeMap Types_
;
414 JSObjectRef
CYMakeStruct(JSContextRef context
, void *data
, sig::Type
*type
, ffi_type
*ffi
, JSObjectRef owner
) {
415 Struct_privateData
*internal(new Struct_privateData(context
, owner
));
416 apr_pool_t
*pool(internal
->pool_
);
417 Type_privateData
*typical(new(pool
) Type_privateData(type
, ffi
));
418 internal
->type_
= typical
;
421 internal
->value_
= data
;
423 size_t size(typical
->GetFFI()->size
);
424 void *copy(apr_palloc(internal
->pool_
, size
));
425 memcpy(copy
, data
, size
);
426 internal
->value_
= copy
;
429 return JSObjectMake(context
, Struct_
, internal
);
432 JSValueRef
CYCastJSValue(JSContextRef context
, bool value
) {
433 return JSValueMakeBoolean(context
, value
);
436 JSValueRef
CYCastJSValue(JSContextRef context
, double value
) {
437 return JSValueMakeNumber(context
, value
);
440 #define CYCastJSValue_(Type_) \
441 JSValueRef CYCastJSValue(JSContextRef context, Type_ value) { \
442 return JSValueMakeNumber(context, static_cast<double>(value)); \
446 CYCastJSValue_(unsigned int)
447 CYCastJSValue_(long int)
448 CYCastJSValue_(long unsigned int)
449 CYCastJSValue_(long long int)
450 CYCastJSValue_(long long unsigned int)
452 JSValueRef
CYJSUndefined(JSContextRef context
) {
453 return JSValueMakeUndefined(context
);
456 double CYCastDouble(const char *value
, size_t size
) {
458 double number(strtod(value
, &end
));
459 if (end
!= value
+ size
)
464 double CYCastDouble(const char *value
) {
465 return CYCastDouble(value
, strlen(value
));
468 double CYCastDouble(JSContextRef context
, JSValueRef value
) {
469 JSValueRef
exception(NULL
);
470 double number(JSValueToNumber(context
, value
, &exception
));
471 CYThrow(context
, exception
);
475 bool CYCastBool(JSContextRef context
, JSValueRef value
) {
476 return JSValueToBoolean(context
, value
);
479 JSValueRef
CYJSNull(JSContextRef context
) {
480 return JSValueMakeNull(context
);
483 JSValueRef
CYCastJSValue(JSContextRef context
, JSStringRef value
) {
484 return value
== NULL
? CYJSNull(context
) : JSValueMakeString(context
, value
);
487 JSValueRef
CYCastJSValue(JSContextRef context
, const char *value
) {
488 return CYCastJSValue(context
, CYJSString(value
));
491 JSObjectRef
CYCastJSObject(JSContextRef context
, JSValueRef value
) {
492 JSValueRef
exception(NULL
);
493 JSObjectRef
object(JSValueToObject(context
, value
, &exception
));
494 CYThrow(context
, exception
);
498 JSValueRef
CYCallAsFunction(JSContextRef context
, JSObjectRef function
, JSObjectRef _this
, size_t count
, JSValueRef arguments
[]) {
499 JSValueRef
exception(NULL
);
500 JSValueRef
value(JSObjectCallAsFunction(context
, function
, _this
, count
, arguments
, &exception
));
501 CYThrow(context
, exception
);
505 bool CYIsCallable(JSContextRef context
, JSValueRef value
) {
506 return value
!= NULL
&& JSValueIsObject(context
, value
) && JSObjectIsFunction(context
, (JSObjectRef
) value
);
509 static JSValueRef
System_print(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
514 printf("%s\n", CYPoolCString(pool
, context
, arguments
[0]));
517 return CYJSUndefined(context
);
520 static size_t Nonce_(0);
522 static JSValueRef $
cyq(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) {
524 const char *name(apr_psprintf(pool
, "%s%zu", CYPoolCString(pool
, context
, arguments
[0]), Nonce_
++));
525 return CYCastJSValue(context
, name
);
528 static JSValueRef
Cycript_gc_callAsFunction(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) {
529 JSGarbageCollect(context
);
530 return CYJSUndefined(context
);
533 const char *CYPoolCCYON(apr_pool_t
*pool
, JSContextRef context
, JSValueRef value
, JSValueRef
*exception
) { CYTry
{
534 switch (JSType type
= JSValueGetType(context
, value
)) {
535 case kJSTypeUndefined
:
540 return CYCastBool(context
, value
) ? "true" : "false";
542 case kJSTypeNumber
: {
543 std::ostringstream str
;
544 CYNumerify(str
, CYCastDouble(context
, value
));
545 std::string
value(str
.str());
546 return apr_pstrmemdup(pool
, value
.c_str(), value
.size());
549 case kJSTypeString
: {
550 std::ostringstream str
;
551 CYUTF8String
string(CYPoolUTF8String(pool
, context
, CYJSString(context
, value
)));
552 CYStringify(str
, string
.data
, string
.size
);
553 std::string
value(str
.str());
554 return apr_pstrmemdup(pool
, value
.c_str(), value
.size());
558 return CYPoolCCYON(pool
, context
, (JSObjectRef
) value
);
560 throw CYJSError(context
, "JSValueGetType() == 0x%x", type
);
564 const char *CYPoolCCYON(apr_pool_t
*pool
, JSContextRef context
, JSValueRef value
) {
565 JSValueRef
exception(NULL
);
566 const char *cyon(CYPoolCCYON(pool
, context
, value
, &exception
));
567 CYThrow(context
, exception
);
571 const char *CYPoolCCYON(apr_pool_t
*pool
, JSContextRef context
, JSObjectRef object
) {
572 JSValueRef
toCYON(CYGetProperty(context
, object
, toCYON_
));
573 if (CYIsCallable(context
, toCYON
)) {
574 JSValueRef
value(CYCallAsFunction(context
, (JSObjectRef
) toCYON
, object
, 0, NULL
));
575 return CYPoolCString(pool
, context
, value
);
578 JSValueRef
toJSON(CYGetProperty(context
, object
, toJSON_
));
579 if (CYIsCallable(context
, toJSON
)) {
580 JSValueRef arguments
[1] = {CYCastJSValue(context
, CYJSString(""))};
581 JSValueRef
exception(NULL
);
582 const char *cyon(CYPoolCCYON(pool
, context
, CYCallAsFunction(context
, (JSObjectRef
) toJSON
, object
, 1, arguments
), &exception
));
583 CYThrow(context
, exception
);
587 std::ostringstream str
;
591 // XXX: this is, sadly, going to leak
592 JSPropertyNameArrayRef
names(JSObjectCopyPropertyNames(context
, object
));
596 for (size_t index(0), count(JSPropertyNameArrayGetCount(names
)); index
!= count
; ++index
) {
597 JSStringRef
name(JSPropertyNameArrayGetNameAtIndex(names
, index
));
598 JSValueRef
value(CYGetProperty(context
, object
, name
));
605 CYUTF8String
string(CYPoolUTF8String(pool
, context
, name
));
609 CYStringify(str
, string
.data
, string
.size
);
611 str
<< ':' << CYPoolCCYON(pool
, context
, value
);
616 JSPropertyNameArrayRelease(names
);
618 std::string
string(str
.str());
619 return apr_pstrmemdup(pool
, string
.c_str(), string
.size());
622 static JSValueRef
Array_callAsFunction_toCYON(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
624 std::ostringstream str
;
628 JSValueRef
length(CYGetProperty(context
, _this
, length_
));
631 for (size_t index(0), count(CYCastDouble(context
, length
)); index
!= count
; ++index
) {
632 JSValueRef
value(CYGetProperty(context
, _this
, index
));
639 if (!JSValueIsUndefined(context
, value
))
640 str
<< CYPoolCCYON(pool
, context
, value
);
649 std::string
value(str
.str());
650 return CYCastJSValue(context
, CYJSString(CYUTF8String(value
.c_str(), value
.size())));
653 JSObjectRef
CYMakePointer(JSContextRef context
, void *pointer
, sig::Type
*type
, ffi_type
*ffi
, JSObjectRef owner
) {
654 Pointer
*internal(new Pointer(pointer
, context
, owner
, type
));
655 return JSObjectMake(context
, Pointer_
, internal
);
658 static JSObjectRef
CYMakeFunctor(JSContextRef context
, void (*function
)(), const char *type
) {
659 cy::Functor
*internal(new cy::Functor(type
, function
));
660 return JSObjectMake(context
, Functor_
, internal
);
663 static bool CYGetOffset(apr_pool_t
*pool
, JSContextRef context
, JSStringRef value
, ssize_t
&index
) {
664 return CYGetOffset(CYPoolCString(pool
, context
, value
), index
);
667 void *CYCastPointer_(JSContextRef context
, JSValueRef value
) {
668 switch (JSValueGetType(context
, value
)) {
671 /*case kJSTypeObject:
672 if (JSValueIsObjectOfClass(context, value, Pointer_)) {
673 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate((JSObjectRef) value)));
674 return internal->value_;
677 double number(CYCastDouble(context
, value
));
678 if (std::isnan(number
))
679 throw CYJSError(context
, "cannot convert value to pointer");
680 return reinterpret_cast<void *>(static_cast<uintptr_t>(static_cast<long long>(number
)));
684 void CYPoolFFI(apr_pool_t
*pool
, JSContextRef context
, sig::Type
*type
, ffi_type
*ffi
, void *data
, JSValueRef value
) {
685 switch (type
->primitive
) {
687 *reinterpret_cast<bool *>(data
) = JSValueToBoolean(context
, value
);
690 #define CYPoolFFI_(primitive, native) \
691 case sig::primitive ## _P: \
692 *reinterpret_cast<native *>(data) = CYCastDouble(context, value); \
695 CYPoolFFI_(uchar
, unsigned char)
696 CYPoolFFI_(char, char)
697 CYPoolFFI_(ushort
, unsigned short)
698 CYPoolFFI_(short, short)
699 CYPoolFFI_(ulong
, unsigned long)
700 CYPoolFFI_(long, long)
701 CYPoolFFI_(uint
, unsigned int)
703 CYPoolFFI_(ulonglong
, unsigned long long)
704 CYPoolFFI_(longlong
, long long)
705 CYPoolFFI_(float, float)
706 CYPoolFFI_(double, double)
709 *reinterpret_cast<void **>(data
) = CYCastPointer
<void *>(context
, value
);
713 *reinterpret_cast<const char **>(data
) = CYPoolCString(pool
, context
, value
);
716 case sig::struct_P
: {
717 uint8_t *base(reinterpret_cast<uint8_t *>(data
));
718 JSObjectRef
aggregate(JSValueIsObject(context
, value
) ? (JSObjectRef
) value
: NULL
);
719 for (size_t index(0); index
!= type
->data
.signature
.count
; ++index
) {
720 sig::Element
*element(&type
->data
.signature
.elements
[index
]);
721 ffi_type
*field(ffi
->elements
[index
]);
724 if (aggregate
== NULL
)
727 rhs
= CYGetProperty(context
, aggregate
, index
);
728 if (JSValueIsUndefined(context
, rhs
)) {
729 if (element
->name
!= NULL
)
730 rhs
= CYGetProperty(context
, aggregate
, CYJSString(element
->name
));
733 if (JSValueIsUndefined(context
, rhs
)) undefined
:
734 throw CYJSError(context
, "unable to extract structure value");
738 CYPoolFFI(pool
, context
, element
->type
, field
, base
, rhs
);
748 if (hooks_
!= NULL
&& hooks_
->PoolFFI
!= NULL
)
749 if ((*hooks_
->PoolFFI
)(pool
, context
, type
, ffi
, data
, value
))
752 fprintf(stderr
, "CYPoolFFI(%c)\n", type
->primitive
);
757 JSValueRef
CYFromFFI(JSContextRef context
, sig::Type
*type
, ffi_type
*ffi
, void *data
, bool initialize
, JSObjectRef owner
) {
758 switch (type
->primitive
) {
760 return CYCastJSValue(context
, *reinterpret_cast<bool *>(data
));
762 #define CYFromFFI_(primitive, native) \
763 case sig::primitive ## _P: \
764 return CYCastJSValue(context, *reinterpret_cast<native *>(data)); \
766 CYFromFFI_(uchar, unsigned char)
767 CYFromFFI_(char, char)
768 CYFromFFI_(ushort
, unsigned short)
769 CYFromFFI_(short, short)
770 CYFromFFI_(ulong
, unsigned long)
771 CYFromFFI_(long, long)
772 CYFromFFI_(uint
, unsigned int)
774 CYFromFFI_(ulonglong
, unsigned long long)
775 CYFromFFI_(longlong
, long long)
776 CYFromFFI_(float, float)
777 CYFromFFI_(double, double)
780 if (void *pointer
= *reinterpret_cast<void **>(data
))
781 return CYMakePointer(context
, pointer
, type
->data
.data
.type
, ffi
, owner
);
785 if (char *utf8
= *reinterpret_cast<char **>(data
))
786 return CYCastJSValue(context
, utf8
);
790 return CYMakeStruct(context
, data
, type
, ffi
, owner
);
792 return CYJSUndefined(context
);
795 return CYJSNull(context
);
797 if (hooks_
!= NULL
&& hooks_
->FromFFI
!= NULL
)
798 if (JSValueRef value
= (*hooks_
->FromFFI
)(context
, type
, ffi
, data
, initialize
, owner
))
801 fprintf(stderr
, "CYFromFFI(%c)\n", type
->primitive
);
806 static void FunctionClosure_(ffi_cif
*cif
, void *result
, void **arguments
, void *arg
) {
807 Closure_privateData
*internal(reinterpret_cast<Closure_privateData
*>(arg
));
809 JSContextRef
context(internal
->context_
);
811 size_t count(internal
->cif_
.nargs
);
812 JSValueRef values
[count
];
814 for (size_t index(0); index
!= count
; ++index
)
815 values
[index
] = CYFromFFI(context
, internal
->signature_
.elements
[1 + index
].type
, internal
->cif_
.arg_types
[index
], arguments
[index
]);
817 JSValueRef
value(CYCallAsFunction(context
, internal
->function_
, NULL
, count
, values
));
818 CYPoolFFI(NULL
, context
, internal
->signature_
.elements
[0].type
, internal
->cif_
.rtype
, result
, value
);
821 Closure_privateData
*CYMakeFunctor_(JSContextRef context
, JSObjectRef function
, const char *type
, void (*callback
)(ffi_cif
*, void *, void **, void *)) {
822 // XXX: in case of exceptions this will leak
823 // XXX: in point of fact, this may /need/ to leak :(
824 Closure_privateData
*internal(new Closure_privateData(CYGetJSContext(), function
, type
));
826 ffi_closure
*closure((ffi_closure
*) _syscall(mmap(
827 NULL
, sizeof(ffi_closure
),
828 PROT_READ
| PROT_WRITE
, MAP_ANON
| MAP_PRIVATE
,
832 ffi_status
status(ffi_prep_closure(closure
, &internal
->cif_
, callback
, internal
));
833 _assert(status
== FFI_OK
);
835 _syscall(mprotect(closure
, sizeof(*closure
), PROT_READ
| PROT_EXEC
));
837 internal
->value_
= closure
;
842 static JSObjectRef
CYMakeFunctor(JSContextRef context
, JSObjectRef function
, const char *type
) {
843 Closure_privateData
*internal(CYMakeFunctor_(context
, function
, type
, &FunctionClosure_
));
844 return JSObjectMake(context
, Functor_
, internal
);
847 static JSObjectRef
CYMakeFunctor(JSContextRef context
, JSValueRef value
, const char *type
) {
848 JSValueRef
exception(NULL
);
849 bool function(JSValueIsInstanceOfConstructor(context
, value
, Function_
, &exception
));
850 CYThrow(context
, exception
);
853 JSObjectRef
function(CYCastJSObject(context
, value
));
854 return CYMakeFunctor(context
, function
, type
);
856 void (*function
)()(CYCastPointer
<void (*)()>(context
, value
));
857 return CYMakeFunctor(context
, function
, type
);
861 static bool Index_(apr_pool_t
*pool
, JSContextRef context
, Struct_privateData
*internal
, JSStringRef property
, ssize_t
&index
, uint8_t *&base
) {
862 Type_privateData
*typical(internal
->type_
);
863 sig::Type
*type(typical
->type_
);
867 const char *name(CYPoolCString(pool
, context
, property
));
868 size_t length(strlen(name
));
869 double number(CYCastDouble(name
, length
));
871 size_t count(type
->data
.signature
.count
);
873 if (std::isnan(number
)) {
874 if (property
== NULL
)
877 sig::Element
*elements(type
->data
.signature
.elements
);
879 for (size_t local(0); local
!= count
; ++local
) {
880 sig::Element
*element(&elements
[local
]);
881 if (element
->name
!= NULL
&& strcmp(name
, element
->name
) == 0) {
889 index
= static_cast<ssize_t
>(number
);
890 if (index
!= number
|| index
< 0 || static_cast<size_t>(index
) >= count
)
895 ffi_type
**elements(typical
->GetFFI()->elements
);
897 base
= reinterpret_cast<uint8_t *>(internal
->value_
);
898 for (ssize_t
local(0); local
!= index
; ++local
)
899 base
+= elements
[local
]->size
;
904 static JSValueRef
Pointer_getIndex(JSContextRef context
, JSObjectRef object
, size_t index
, JSValueRef
*exception
) { CYTry
{
905 Pointer
*internal(reinterpret_cast<Pointer
*>(JSObjectGetPrivate(object
)));
906 Type_privateData
*typical(internal
->type_
);
908 ffi_type
*ffi(typical
->GetFFI());
910 uint8_t *base(reinterpret_cast<uint8_t *>(internal
->value_
));
911 base
+= ffi
->size
* index
;
913 JSObjectRef
owner(internal
->GetOwner() ?: object
);
914 return CYFromFFI(context
, typical
->type_
, ffi
, base
, false, owner
);
917 static JSValueRef
Pointer_getProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef
*exception
) {
919 Pointer
*internal(reinterpret_cast<Pointer
*>(JSObjectGetPrivate(object
)));
920 Type_privateData
*typical(internal
->type_
);
922 if (typical
->type_
== NULL
)
926 if (!CYGetOffset(pool
, context
, property
, offset
))
929 return Pointer_getIndex(context
, object
, offset
, exception
);
932 static JSValueRef Pointer_getProperty_$
cyi(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef
*exception
) {
933 return Pointer_getIndex(context
, object
, 0, exception
);
936 static bool Pointer_setIndex(JSContextRef context
, JSObjectRef object
, size_t index
, JSValueRef value
, JSValueRef
*exception
) { CYTry
{
937 Pointer
*internal(reinterpret_cast<Pointer
*>(JSObjectGetPrivate(object
)));
938 Type_privateData
*typical(internal
->type_
);
940 ffi_type
*ffi(typical
->GetFFI());
942 uint8_t *base(reinterpret_cast<uint8_t *>(internal
->value_
));
943 base
+= ffi
->size
* index
;
945 CYPoolFFI(NULL
, context
, typical
->type_
, ffi
, base
, value
);
949 static bool Pointer_setProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef value
, JSValueRef
*exception
) {
951 Pointer
*internal(reinterpret_cast<Pointer
*>(JSObjectGetPrivate(object
)));
952 Type_privateData
*typical(internal
->type_
);
954 if (typical
->type_
== NULL
)
958 if (!CYGetOffset(pool
, context
, property
, offset
))
961 return Pointer_setIndex(context
, object
, offset
, value
, exception
);
964 static bool Pointer_setProperty_$
cyi(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef value
, JSValueRef
*exception
) {
965 return Pointer_setIndex(context
, object
, 0, value
, exception
);
968 static JSValueRef Struct_callAsFunction_$
cya(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) {
969 Struct_privateData
*internal(reinterpret_cast<Struct_privateData
*>(JSObjectGetPrivate(_this
)));
970 Type_privateData
*typical(internal
->type_
);
971 return CYMakePointer(context
, internal
->value_
, typical
->type_
, typical
->ffi_
, _this
);
974 static JSValueRef
Struct_getProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef
*exception
) { CYTry
{
976 Struct_privateData
*internal(reinterpret_cast<Struct_privateData
*>(JSObjectGetPrivate(object
)));
977 Type_privateData
*typical(internal
->type_
);
982 if (!Index_(pool
, context
, internal
, property
, index
, base
))
985 JSObjectRef
owner(internal
->GetOwner() ?: object
);
987 return CYFromFFI(context
, typical
->type_
->data
.signature
.elements
[index
].type
, typical
->GetFFI()->elements
[index
], base
, false, owner
);
990 static bool Struct_setProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef value
, JSValueRef
*exception
) { CYTry
{
992 Struct_privateData
*internal(reinterpret_cast<Struct_privateData
*>(JSObjectGetPrivate(object
)));
993 Type_privateData
*typical(internal
->type_
);
998 if (!Index_(pool
, context
, internal
, property
, index
, base
))
1001 CYPoolFFI(NULL
, context
, typical
->type_
->data
.signature
.elements
[index
].type
, typical
->GetFFI()->elements
[index
], base
, value
);
1005 static void Struct_getPropertyNames(JSContextRef context
, JSObjectRef object
, JSPropertyNameAccumulatorRef names
) {
1006 Struct_privateData
*internal(reinterpret_cast<Struct_privateData
*>(JSObjectGetPrivate(object
)));
1007 Type_privateData
*typical(internal
->type_
);
1008 sig::Type
*type(typical
->type_
);
1013 size_t count(type
->data
.signature
.count
);
1014 sig::Element
*elements(type
->data
.signature
.elements
);
1018 for (size_t index(0); index
!= count
; ++index
) {
1020 name
= elements
[index
].name
;
1023 sprintf(number
, "%lu", index
);
1027 JSPropertyNameAccumulatorAddName(names
, CYJSString(name
));
1031 JSValueRef
CYCallFunction(apr_pool_t
*pool
, JSContextRef context
, size_t setups
, void *setup
[], size_t count
, const JSValueRef arguments
[], bool initialize
, JSValueRef
*exception
, sig::Signature
*signature
, ffi_cif
*cif
, void (*function
)()) { CYTry
{
1032 if (setups
+ count
!= signature
->count
- 1)
1033 throw CYJSError(context
, "incorrect number of arguments to ffi function");
1035 size_t size(setups
+ count
);
1037 memcpy(values
, setup
, sizeof(void *) * setups
);
1039 for (size_t index(setups
); index
!= size
; ++index
) {
1040 sig::Element
*element(&signature
->elements
[index
+ 1]);
1041 ffi_type
*ffi(cif
->arg_types
[index
]);
1043 values
[index
] = new(pool
) uint8_t[ffi
->size
];
1044 CYPoolFFI(pool
, context
, element
->type
, ffi
, values
[index
], arguments
[index
- setups
]);
1047 uint8_t value
[cif
->rtype
->size
];
1049 if (hooks_
!= NULL
&& hooks_
->CallFunction
!= NULL
)
1050 (*hooks_
->CallFunction
)(context
, cif
, function
, value
, values
);
1052 ffi_call(cif
, function
, value
, values
);
1054 return CYFromFFI(context
, signature
->elements
[0].type
, cif
->rtype
, value
, initialize
);
1057 static JSValueRef
Functor_callAsFunction(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) {
1059 cy::Functor
*internal(reinterpret_cast<cy::Functor
*>(JSObjectGetPrivate(object
)));
1060 return CYCallFunction(pool
, context
, 0, NULL
, count
, arguments
, false, exception
, &internal
->signature_
, &internal
->cif_
, internal
->GetValue());
1063 static JSObjectRef
CYMakeType(JSContextRef context
, const char *type
) {
1064 Type_privateData
*internal(new Type_privateData(NULL
, type
));
1065 return JSObjectMake(context
, Type_privateData::Class_
, internal
);
1068 static JSObjectRef
CYMakeType(JSContextRef context
, sig::Type
*type
) {
1069 Type_privateData
*internal(new Type_privateData(type
));
1070 return JSObjectMake(context
, Type_privateData::Class_
, internal
);
1073 static void *CYCastSymbol(const char *name
) {
1074 return dlsym(RTLD_DEFAULT
, name
);
1077 static JSValueRef
Runtime_getProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef
*exception
) { CYTry
{
1079 CYUTF8String
name(CYPoolUTF8String(pool
, context
, property
));
1081 if (hooks_
!= NULL
&& hooks_
->RuntimeProperty
!= NULL
)
1082 if (JSValueRef value
= (*hooks_
->RuntimeProperty
)(context
, name
))
1085 sqlite3_stmt
*statement
;
1087 _sqlcall(sqlite3_prepare(Bridge_
,
1089 "\"bridge\".\"mode\", "
1090 "\"bridge\".\"value\" "
1093 " \"bridge\".\"name\" = ?"
1095 , -1, &statement
, NULL
));
1097 _sqlcall(sqlite3_bind_text(statement
, 1, name
.data
, name
.size
, SQLITE_STATIC
));
1102 if (_sqlcall(sqlite3_step(statement
)) == SQLITE_DONE
) {
1106 mode
= sqlite3_column_int(statement
, 0);
1107 value
= sqlite3_column_pooled(pool
, statement
, 1);
1110 _sqlcall(sqlite3_finalize(statement
));
1119 return JSEvaluateScript(CYGetJSContext(), CYJSString(value
), NULL
, NULL
, 0, NULL
);
1121 return CYMakeFunctor(context
, reinterpret_cast<void (*)()>(CYCastSymbol(name
.data
)), value
);
1124 // XXX: this is horrendously inefficient
1125 sig::Signature signature
;
1126 sig::Parse(pool
, &signature
, value
, &Structor_
);
1128 sig::sig_ffi_cif(pool
, &sig::ObjectiveC
, &signature
, &cif
);
1129 return CYFromFFI(context
, signature
.elements
[0].type
, cif
.rtype
, CYCastSymbol(name
.data
));
1132 // XXX: implement case 3
1134 return CYMakeType(context
, value
);
1138 static JSObjectRef
Pointer_new(JSContextRef context
, JSObjectRef object
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
1140 throw CYJSError(context
, "incorrect number of arguments to Functor constructor");
1144 void *value(CYCastPointer
<void *>(context
, arguments
[0]));
1145 const char *type(CYPoolCString(pool
, context
, arguments
[1]));
1147 sig::Signature signature
;
1148 sig::Parse(pool
, &signature
, type
, &Structor_
);
1150 return CYMakePointer(context
, value
, signature
.elements
[0].type
, NULL
, NULL
);
1153 static JSObjectRef
Type_new(JSContextRef context
, JSObjectRef object
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
1155 throw CYJSError(context
, "incorrect number of arguments to Type constructor");
1157 const char *type(CYPoolCString(pool
, context
, arguments
[0]));
1158 return CYMakeType(context
, type
);
1161 static JSValueRef
Type_getProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef
*exception
) { CYTry
{
1162 Type_privateData
*internal(reinterpret_cast<Type_privateData
*>(JSObjectGetPrivate(object
)));
1166 if (JSStringIsEqualToUTF8CString(property
, "$cyi")) {
1167 type
.primitive
= sig::pointer_P
;
1168 type
.data
.data
.size
= 0;
1171 size_t index(CYGetIndex(pool
, context
, property
));
1172 if (index
== _not(size_t))
1174 type
.primitive
= sig::array_P
;
1175 type
.data
.data
.size
= index
;
1181 type
.data
.data
.type
= internal
->type_
;
1183 return CYMakeType(context
, &type
);
1186 static JSValueRef
Type_callAsFunction(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
1187 Type_privateData
*internal(reinterpret_cast<Type_privateData
*>(JSObjectGetPrivate(object
)));
1190 throw CYJSError(context
, "incorrect number of arguments to type cast function");
1191 sig::Type
*type(internal
->type_
);
1192 ffi_type
*ffi(internal
->GetFFI());
1194 uint8_t value
[ffi
->size
];
1196 CYPoolFFI(pool
, context
, type
, ffi
, value
, arguments
[0]);
1197 return CYFromFFI(context
, type
, ffi
, value
);
1200 static JSObjectRef
Type_callAsConstructor(JSContextRef context
, JSObjectRef object
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
1202 throw CYJSError(context
, "incorrect number of arguments to type cast function");
1203 Type_privateData
*internal(reinterpret_cast<Type_privateData
*>(JSObjectGetPrivate(object
)));
1205 sig::Type
*type(internal
->type_
);
1208 if (type
->primitive
!= sig::array_P
)
1211 size
= type
->data
.data
.size
;
1212 type
= type
->data
.data
.type
;
1215 void *value(malloc(internal
->GetFFI()->size
));
1216 return CYMakePointer(context
, value
, type
, NULL
, NULL
);
1219 static JSObjectRef
Functor_new(JSContextRef context
, JSObjectRef object
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
1221 throw CYJSError(context
, "incorrect number of arguments to Functor constructor");
1223 const char *type(CYPoolCString(pool
, context
, arguments
[1]));
1224 return CYMakeFunctor(context
, arguments
[0], type
);
1227 static JSValueRef
CYValue_callAsFunction_valueOf(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
1228 CYValue
*internal(reinterpret_cast<CYValue
*>(JSObjectGetPrivate(_this
)));
1229 return CYCastJSValue(context
, reinterpret_cast<uintptr_t>(internal
->value_
));
1232 static JSValueRef
CYValue_callAsFunction_toJSON(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) {
1233 return CYValue_callAsFunction_valueOf(context
, object
, _this
, count
, arguments
, exception
);
1236 static JSValueRef
CYValue_callAsFunction_toCYON(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
1237 CYValue
*internal(reinterpret_cast<CYValue
*>(JSObjectGetPrivate(_this
)));
1239 sprintf(string
, "%p", internal
->value_
);
1241 return CYCastJSValue(context
, string
);
1244 static JSValueRef
Type_callAsFunction_toString(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
1245 Type_privateData
*internal(reinterpret_cast<Type_privateData
*>(JSObjectGetPrivate(_this
)));
1247 const char *type(sig::Unparse(pool
, internal
->type_
));
1248 return CYCastJSValue(context
, CYJSString(type
));
1251 static JSValueRef
Type_callAsFunction_toCYON(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
1252 Type_privateData
*internal(reinterpret_cast<Type_privateData
*>(JSObjectGetPrivate(_this
)));
1254 const char *type(sig::Unparse(pool
, internal
->type_
));
1255 size_t size(strlen(type
));
1256 char *cyon(new(pool
) char[12 + size
+ 1]);
1257 memcpy(cyon
, "new Type(\"", 10);
1258 cyon
[12 + size
] = '\0';
1259 cyon
[12 + size
- 2] = '"';
1260 cyon
[12 + size
- 1] = ')';
1261 memcpy(cyon
+ 10, type
, size
);
1262 return CYCastJSValue(context
, CYJSString(cyon
));
1265 static JSValueRef
Type_callAsFunction_toJSON(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) {
1266 return Type_callAsFunction_toString(context
, object
, _this
, count
, arguments
, exception
);
1269 static JSStaticValue Pointer_staticValues
[2] = {
1270 {"$cyi", &Pointer_getProperty_$cyi
, &Pointer_setProperty_$cyi
, kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1271 {NULL
, NULL
, NULL
, 0}
1274 static JSStaticFunction Pointer_staticFunctions
[4] = {
1275 {"toCYON", &CYValue_callAsFunction_toCYON
, kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1276 {"toJSON", &CYValue_callAsFunction_toJSON
, kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1277 {"valueOf", &CYValue_callAsFunction_valueOf
, kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1281 static JSStaticFunction Struct_staticFunctions
[2] = {
1282 {"$cya", &Struct_callAsFunction_$cya
, kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1286 static JSStaticFunction Functor_staticFunctions
[4] = {
1287 {"toCYON", &CYValue_callAsFunction_toCYON
, kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1288 {"toJSON", &CYValue_callAsFunction_toJSON
, kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1289 {"valueOf", &CYValue_callAsFunction_valueOf
, kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1294 JSStaticFunction
const * const Functor::StaticFunctions
= Functor_staticFunctions
;
1297 static JSStaticFunction Type_staticFunctions
[4] = {
1298 {"toCYON", &Type_callAsFunction_toCYON
, kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1299 {"toJSON", &Type_callAsFunction_toJSON
, kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1300 {"toString", &Type_callAsFunction_toString
, kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1304 void CYSetArgs(int argc
, const char *argv
[]) {
1305 JSContextRef
context(CYGetJSContext());
1306 JSValueRef args
[argc
];
1307 for (int i(0); i
!= argc
; ++i
)
1308 args
[i
] = CYCastJSValue(context
, argv
[i
]);
1310 JSValueRef
exception(NULL
);
1311 JSObjectRef
array(JSObjectMakeArray(context
, argc
, args
, &exception
));
1312 CYThrow(context
, exception
);
1314 JSValueRef
value(CYCallAsFunction(context
, Array_
, NULL
, argc
, args
));
1315 JSObjectRef
array(CYCastJSObject(context
, value
));
1317 CYSetProperty(context
, System_
, CYJSString("args"), array
);
1320 JSObjectRef
CYGetGlobalObject(JSContextRef context
) {
1321 return JSContextGetGlobalObject(context
);
1324 const char *CYExecute(apr_pool_t
*pool
, const char *code
) {
1325 JSContextRef
context(CYGetJSContext());
1326 JSValueRef
exception(NULL
), result
;
1329 if (hooks_
!= NULL
&& hooks_
->ExecuteStart
!= NULL
)
1330 handle
= (*hooks_
->ExecuteStart
)(context
);
1337 result
= JSEvaluateScript(context
, CYJSString(code
), NULL
, NULL
, 0, &exception
);
1338 } catch (const char *error
) {
1342 if (exception
!= NULL
) { error
:
1347 if (JSValueIsUndefined(context
, result
))
1351 json
= CYPoolCCYON(pool
, context
, result
, &exception
);
1352 } catch (const char *error
) {
1356 if (exception
!= NULL
)
1359 CYSetProperty(context
, CYGetGlobalObject(context
), Result_
, result
);
1361 if (hooks_
!= NULL
&& hooks_
->ExecuteEnd
!= NULL
)
1362 (*hooks_
->ExecuteEnd
)(context
, handle
);
1366 static apr_pool_t
*Pool_
;
1368 static bool initialized_
;
1370 void CYInitialize() {
1372 initialized_
= true;
1375 _aprcall(apr_initialize());
1376 _aprcall(apr_pool_create(&Pool_
, NULL
));
1377 _sqlcall(sqlite3_open("/usr/lib/libcycript.db", &Bridge_
));
1380 apr_pool_t
*CYGetGlobalPool() {
1385 void CYThrow(JSContextRef context
, JSValueRef value
) {
1387 throw CYJSError(context
, value
);
1390 const char *CYJSError::PoolCString(apr_pool_t
*pool
) const {
1391 return CYPoolCString(pool
, context_
, value_
);
1394 JSValueRef
CYJSError::CastJSValue(JSContextRef context
) const {
1395 // XXX: what if the context is different?
1399 void CYThrow(const char *format
, ...) {
1401 va_start (args
, format
);
1402 throw CYPoolError(format
, args
);
1403 // XXX: does this matter? :(
1407 const char *CYPoolError::PoolCString(apr_pool_t
*pool
) const {
1408 return apr_pstrdup(pool
, message_
);
1411 CYPoolError::CYPoolError(const char *format
, ...) {
1413 va_start (args
, format
);
1414 message_
= apr_pvsprintf(pool_
, format
, args
);
1418 CYPoolError::CYPoolError(const char *format
, va_list args
) {
1419 message_
= apr_pvsprintf(pool_
, format
, args
);
1422 JSValueRef
CYPoolError::CastJSValue(JSContextRef context
) const {
1423 return CYCastJSValue(context
, message_
);
1426 CYJSError::CYJSError(JSContextRef context
, const char *format
, ...) {
1427 if (context
== NULL
)
1428 context
= CYGetJSContext();
1433 va_start (args
, format
);
1434 const char *message(apr_pvsprintf(pool
, format
, args
));
1437 JSValueRef arguments
[1] = {CYCastJSValue(context
, CYJSString(message
))};
1439 JSValueRef
exception(NULL
);
1440 value_
= JSObjectCallAsConstructor(context
, Error_
, 1, arguments
, &exception
);
1441 CYThrow(context
, exception
);
1444 void CYObjectiveC(JSContextRef context
, JSObjectRef global
);
1446 JSGlobalContextRef
CYGetJSContext() {
1449 if (Context_
== NULL
) {
1450 JSClassDefinition definition
;
1452 definition
= kJSClassDefinitionEmpty
;
1453 definition
.className
= "Functor";
1454 definition
.staticFunctions
= cy::Functor::StaticFunctions
;
1455 definition
.callAsFunction
= &Functor_callAsFunction
;
1456 definition
.finalize
= &CYFinalize
;
1457 Functor_
= JSClassCreate(&definition
);
1459 definition
= kJSClassDefinitionEmpty
;
1460 definition
.className
= "Pointer";
1461 definition
.staticValues
= Pointer_staticValues
;
1462 definition
.staticFunctions
= Pointer_staticFunctions
;
1463 definition
.getProperty
= &Pointer_getProperty
;
1464 definition
.setProperty
= &Pointer_setProperty
;
1465 definition
.finalize
= &CYFinalize
;
1466 Pointer_
= JSClassCreate(&definition
);
1468 definition
= kJSClassDefinitionEmpty
;
1469 definition
.className
= "Struct";
1470 definition
.staticFunctions
= Struct_staticFunctions
;
1471 definition
.getProperty
= &Struct_getProperty
;
1472 definition
.setProperty
= &Struct_setProperty
;
1473 definition
.getPropertyNames
= &Struct_getPropertyNames
;
1474 definition
.finalize
= &CYFinalize
;
1475 Struct_
= JSClassCreate(&definition
);
1477 definition
= kJSClassDefinitionEmpty
;
1478 definition
.className
= "Type";
1479 definition
.staticFunctions
= Type_staticFunctions
;
1480 definition
.getProperty
= &Type_getProperty
;
1481 definition
.callAsFunction
= &Type_callAsFunction
;
1482 definition
.callAsConstructor
= &Type_callAsConstructor
;
1483 definition
.finalize
= &CYFinalize
;
1484 Type_privateData::Class_
= JSClassCreate(&definition
);
1486 definition
= kJSClassDefinitionEmpty
;
1487 definition
.className
= "Runtime";
1488 definition
.getProperty
= &Runtime_getProperty
;
1489 Runtime_
= JSClassCreate(&definition
);
1491 definition
= kJSClassDefinitionEmpty
;
1492 //definition.getProperty = &Global_getProperty;
1493 JSClassRef
Global(JSClassCreate(&definition
));
1495 JSGlobalContextRef
context(JSGlobalContextCreate(Global
));
1497 JSObjectRef
global(CYGetGlobalObject(context
));
1499 JSObjectSetPrototype(context
, global
, JSObjectMake(context
, Runtime_
, NULL
));
1501 Array_
= CYCastJSObject(context
, CYGetProperty(context
, global
, CYJSString("Array")));
1502 JSValueProtect(context
, Array_
);
1504 Error_
= CYCastJSObject(context
, CYGetProperty(context
, global
, CYJSString("Error")));
1505 JSValueProtect(context
, Error_
);
1507 Function_
= CYCastJSObject(context
, CYGetProperty(context
, global
, CYJSString("Function")));
1508 JSValueProtect(context
, Function_
);
1510 String_
= CYCastJSObject(context
, CYGetProperty(context
, global
, CYJSString("String")));
1511 JSValueProtect(context
, String_
);
1513 length_
= JSStringCreateWithUTF8CString("length");
1514 message_
= JSStringCreateWithUTF8CString("message");
1515 name_
= JSStringCreateWithUTF8CString("name");
1516 prototype_
= JSStringCreateWithUTF8CString("prototype");
1517 toCYON_
= JSStringCreateWithUTF8CString("toCYON");
1518 toJSON_
= JSStringCreateWithUTF8CString("toJSON");
1520 JSObjectRef
Object(CYCastJSObject(context
, CYGetProperty(context
, global
, CYJSString("Object"))));
1521 Object_prototype_
= CYCastJSObject(context
, CYGetProperty(context
, Object
, prototype_
));
1522 JSValueProtect(context
, Object_prototype_
);
1524 Array_prototype_
= CYCastJSObject(context
, CYGetProperty(context
, Array_
, prototype_
));
1525 Array_pop_
= CYCastJSObject(context
, CYGetProperty(context
, Array_prototype_
, CYJSString("pop")));
1526 Array_push_
= CYCastJSObject(context
, CYGetProperty(context
, Array_prototype_
, CYJSString("push")));
1527 Array_splice_
= CYCastJSObject(context
, CYGetProperty(context
, Array_prototype_
, CYJSString("splice")));
1529 CYSetProperty(context
, Array_prototype_
, toCYON_
, JSObjectMakeFunctionWithCallback(context
, toCYON_
, &Array_callAsFunction_toCYON
), kJSPropertyAttributeDontEnum
);
1531 JSValueProtect(context
, Array_prototype_
);
1532 JSValueProtect(context
, Array_pop_
);
1533 JSValueProtect(context
, Array_push_
);
1534 JSValueProtect(context
, Array_splice_
);
1536 JSObjectRef
Functor(JSObjectMakeConstructor(context
, Functor_
, &Functor_new
));
1538 Function_prototype_
= (JSObjectRef
) CYGetProperty(context
, Function_
, prototype_
);
1539 JSValueProtect(context
, Function_prototype_
);
1541 JSObjectSetPrototype(context
, (JSObjectRef
) CYGetProperty(context
, Functor
, prototype_
), Function_prototype_
);
1543 CYSetProperty(context
, global
, CYJSString("Functor"), Functor
);
1544 CYSetProperty(context
, global
, CYJSString("Pointer"), JSObjectMakeConstructor(context
, Pointer_
, &Pointer_new
));
1545 CYSetProperty(context
, global
, CYJSString("Type"), JSObjectMakeConstructor(context
, Type_privateData::Class_
, &Type_new
));
1547 JSObjectRef
cycript(JSObjectMake(context
, NULL
, NULL
));
1548 CYSetProperty(context
, global
, CYJSString("Cycript"), cycript
);
1549 CYSetProperty(context
, cycript
, CYJSString("gc"), JSObjectMakeFunctionWithCallback(context
, CYJSString("gc"), &Cycript_gc_callAsFunction
));
1551 CYSetProperty(context
, global
, CYJSString("$cyq"), JSObjectMakeFunctionWithCallback(context
, CYJSString("$cyq"), &$cyq
));
1553 System_
= JSObjectMake(context
, NULL
, NULL
);
1554 JSValueProtect(context
, System_
);
1556 CYSetProperty(context
, global
, CYJSString("system"), System_
);
1557 CYSetProperty(context
, System_
, CYJSString("args"), CYJSNull(context
));
1558 //CYSetProperty(context, System_, CYJSString("global"), global);
1560 CYSetProperty(context
, System_
, CYJSString("print"), JSObjectMakeFunctionWithCallback(context
, CYJSString("print"), &System_print
));
1562 Result_
= JSStringCreateWithUTF8CString("_");
1564 // XXX: this is very wrong and sad
1566 CYObjectiveC(context
, global
);