]> git.saurik.com Git - cycript.git/blob - Library.cpp
Removed make.sh: why not?
[cycript.git] / Library.cpp
1 /* Cycript - Inlining/Optimizing JavaScript Compiler
2 * Copyright (C) 2009 Jay Freeman (saurik)
3 */
4
5 /* Modified BSD License {{{ */
6 /*
7 * Redistribution and use in source and binary
8 * forms, with or without modification, are permitted
9 * provided that the following conditions are met:
10 *
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
18 * distribution.
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.
22 *
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.
37 */
38 /* }}} */
39
40 #include <sqlite3.h>
41
42 #include "Internal.hpp"
43
44 #include <dlfcn.h>
45 #include <iconv.h>
46
47 #include "cycript.hpp"
48
49 #include "sig/parse.hpp"
50 #include "sig/ffi_type.hpp"
51
52 #include "Pooling.hpp"
53
54 #include <sys/mman.h>
55
56 #include <iostream>
57 #include <ext/stdio_filebuf.h>
58 #include <set>
59 #include <map>
60 #include <iomanip>
61 #include <sstream>
62 #include <cmath>
63
64 #include "Parser.hpp"
65 #include "Cycript.tab.hh"
66
67 #include "Error.hpp"
68 #include "JavaScript.hpp"
69 #include "String.hpp"
70
71 #ifdef __OBJC__
72 #define CYCatch_ \
73 catch (NSException *error) { \
74 CYThrow(context, error, exception); \
75 return NULL; \
76 }
77 #else
78 #define CYCatch_
79 #endif
80
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);
84 else return NULL;
85 }
86
87 struct CYHooks *hooks_;
88
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);
94 return value;
95 }
96
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);
101 return value;
102 }
103
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);
108 }
109
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);
114 }
115 /* }}} */
116 /* JavaScript Strings {{{ */
117 JSStringRef CYCopyJSString(const char *value) {
118 return value == NULL ? NULL : JSStringCreateWithUTF8CString(value);
119 }
120
121 JSStringRef CYCopyJSString(JSStringRef value) {
122 return value == NULL ? NULL : JSStringRetain(value);
123 }
124
125 JSStringRef CYCopyJSString(CYUTF8String value) {
126 // XXX: this is very wrong
127 return CYCopyJSString(value.data);
128 }
129
130 JSStringRef CYCopyJSString(JSContextRef context, JSValueRef value) {
131 if (JSValueIsNull(context, value))
132 return NULL;
133 JSValueRef exception(NULL);
134 JSStringRef string(JSValueToStringCopy(context, value, &exception));
135 CYThrow(context, exception);
136 return string;
137 }
138
139 static CYUTF16String CYCastUTF16String(JSStringRef value) {
140 return CYUTF16String(JSStringGetCharactersPtr(value), JSStringGetLength(value));
141 }
142
143 static CYUTF8String CYPoolUTF8String(apr_pool_t *pool, JSContextRef context, JSStringRef value) {
144 _assert(pool != NULL);
145
146 CYUTF16String utf16(CYCastUTF16String(value));
147 const char *in(reinterpret_cast<const char *>(utf16.data));
148
149 iconv_t conversion(_syscall(iconv_open("UTF-8", "UCS-2-INTERNAL")));
150
151 size_t size(JSStringGetMaximumUTF8CStringSize(value));
152 char *out(new(pool) char[size]);
153 CYUTF8String utf8(out, size);
154
155 size = utf16.size * 2;
156 _syscall(iconv(conversion, const_cast<char **>(&in), &size, &out, &utf8.size));
157
158 *out = '\0';
159 utf8.size = out - utf8.data;
160
161 _syscall(iconv_close(conversion));
162
163 return utf8;
164 }
165
166 const char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSStringRef value) {
167 CYUTF8String utf8(CYPoolUTF8String(pool, context, value));
168 _assert(memchr(utf8.data, '\0', utf8.size) == NULL);
169 return utf8.data;
170 }
171
172 const char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
173 return JSValueIsNull(context, value) ? NULL : CYPoolCString(pool, context, CYJSString(context, value));
174 }
175 /* }}} */
176
177 /* Index Offsets {{{ */
178 size_t CYGetIndex(const CYUTF8String &value) {
179 if (value.data[0] != '0') {
180 char *end;
181 size_t index(strtoul(value.data, &end, 10));
182 if (value.data + value.size == end)
183 return index;
184 } else if (value.data[1] == '\0')
185 return 0;
186 return _not(size_t);
187 }
188
189 size_t CYGetIndex(apr_pool_t *pool, JSContextRef context, JSStringRef value) {
190 return CYGetIndex(CYPoolUTF8String(pool, context, value));
191 }
192
193 bool CYGetOffset(const char *value, ssize_t &index) {
194 if (value[0] != '0') {
195 char *end;
196 index = strtol(value, &end, 10);
197 if (value + strlen(value) == end)
198 return true;
199 } else if (value[1] == '\0') {
200 index = 0;
201 return true;
202 }
203
204 return false;
205 }
206 /* }}} */
207
208 /* JavaScript *ify {{{ */
209 void CYStringify(std::ostringstream &str, const char *data, size_t size) {
210 unsigned quot(0), apos(0);
211 for (const char *value(data), *end(data + size); value != end; ++value)
212 if (*value == '"')
213 ++quot;
214 else if (*value == '\'')
215 ++apos;
216
217 bool single(quot > apos);
218
219 str << (single ? '\'' : '"');
220
221 for (const char *value(data), *end(data + size); value != end; ++value)
222 switch (*value) {
223 case '\\': str << "\\\\"; break;
224 case '\b': str << "\\b"; break;
225 case '\f': str << "\\f"; break;
226 case '\n': str << "\\n"; break;
227 case '\r': str << "\\r"; break;
228 case '\t': str << "\\t"; break;
229 case '\v': str << "\\v"; break;
230
231 case '"':
232 if (!single)
233 str << "\\\"";
234 else goto simple;
235 break;
236
237 case '\'':
238 if (single)
239 str << "\\'";
240 else goto simple;
241 break;
242
243 default:
244 if (*value < 0x20 || *value >= 0x7f)
245 str << "\\x" << std::setbase(16) << std::setw(2) << std::setfill('0') << unsigned(*value);
246 else simple:
247 str << *value;
248 }
249
250 str << (single ? '\'' : '"');
251 }
252
253 void CYNumerify(std::ostringstream &str, double value) {
254 char string[32];
255 // XXX: I want this to print 1e3 rather than 1000
256 sprintf(string, "%.17g", value);
257 str << string;
258 }
259
260 bool CYIsKey(CYUTF8String value) {
261 const char *data(value.data);
262 size_t size(value.size);
263
264 if (size == 0)
265 return false;
266
267 if (DigitRange_[data[0]]) {
268 size_t index(CYGetIndex(value));
269 if (index == _not(size_t))
270 return false;
271 } else {
272 if (!WordStartRange_[data[0]])
273 return false;
274 for (size_t i(1); i != size; ++i)
275 if (!WordEndRange_[data[i]])
276 return false;
277 }
278
279 return true;
280 }
281 /* }}} */
282
283 static JSGlobalContextRef Context_;
284 static JSObjectRef System_;
285
286 static JSClassRef Functor_;
287 static JSClassRef Pointer_;
288 static JSClassRef Runtime_;
289 static JSClassRef Struct_;
290
291 static JSStringRef Result_;
292
293 JSObjectRef Array_;
294 JSObjectRef Error_;
295 JSObjectRef Function_;
296 JSObjectRef String_;
297
298 JSStringRef length_;
299 JSStringRef message_;
300 JSStringRef name_;
301 JSStringRef prototype_;
302 JSStringRef toCYON_;
303 JSStringRef toJSON_;
304
305 JSObjectRef Object_prototype_;
306 JSObjectRef Function_prototype_;
307
308 JSObjectRef Array_prototype_;
309 JSObjectRef Array_pop_;
310 JSObjectRef Array_push_;
311 JSObjectRef Array_splice_;
312
313 sqlite3 *Bridge_;
314
315 void CYFinalize(JSObjectRef object) {
316 delete reinterpret_cast<CYData *>(JSObjectGetPrivate(object));
317 }
318
319 struct CStringMapLess :
320 std::binary_function<const char *, const char *, bool>
321 {
322 _finline bool operator ()(const char *lhs, const char *rhs) const {
323 return strcmp(lhs, rhs) < 0;
324 }
325 };
326
327 void Structor_(apr_pool_t *pool, const char *name, const char *types, sig::Type *&type) {
328 if (name == NULL)
329 return;
330
331 sqlite3_stmt *statement;
332
333 _sqlcall(sqlite3_prepare(Bridge_,
334 "select "
335 "\"bridge\".\"mode\", "
336 "\"bridge\".\"value\" "
337 "from \"bridge\" "
338 "where"
339 " \"bridge\".\"mode\" in (3, 4) and"
340 " \"bridge\".\"name\" = ?"
341 " limit 1"
342 , -1, &statement, NULL));
343
344 _sqlcall(sqlite3_bind_text(statement, 1, name, -1, SQLITE_STATIC));
345
346 int mode;
347 const char *value;
348
349 if (_sqlcall(sqlite3_step(statement)) == SQLITE_DONE) {
350 mode = -1;
351 value = NULL;
352 } else {
353 mode = sqlite3_column_int(statement, 0);
354 value = sqlite3_column_pooled(pool, statement, 1);
355 }
356
357 _sqlcall(sqlite3_finalize(statement));
358
359 switch (mode) {
360 default:
361 _assert(false);
362 case -1:
363 break;
364
365 case 3: {
366 sig::Parse(pool, &type->data.signature, value, &Structor_);
367 } break;
368
369 case 4: {
370 sig::Signature signature;
371 sig::Parse(pool, &signature, value, &Structor_);
372 type = signature.elements[0].type;
373 } break;
374 }
375 }
376
377 JSClassRef Type_privateData::Class_;
378
379 struct Pointer :
380 CYOwned
381 {
382 Type_privateData *type_;
383
384 Pointer(void *value, JSContextRef context, JSObjectRef owner, sig::Type *type) :
385 CYOwned(value, context, owner),
386 type_(new(pool_) Type_privateData(type))
387 {
388 }
389 };
390
391 struct Struct_privateData :
392 CYOwned
393 {
394 Type_privateData *type_;
395
396 Struct_privateData(JSContextRef context, JSObjectRef owner) :
397 CYOwned(NULL, context, owner)
398 {
399 }
400 };
401
402 typedef std::map<const char *, Type_privateData *, CStringMapLess> TypeMap;
403 static TypeMap Types_;
404
405 JSObjectRef CYMakeStruct(JSContextRef context, void *data, sig::Type *type, ffi_type *ffi, JSObjectRef owner) {
406 Struct_privateData *internal(new Struct_privateData(context, owner));
407 apr_pool_t *pool(internal->pool_);
408 Type_privateData *typical(new(pool) Type_privateData(type, ffi));
409 internal->type_ = typical;
410
411 if (owner != NULL)
412 internal->value_ = data;
413 else {
414 size_t size(typical->GetFFI()->size);
415 void *copy(apr_palloc(internal->pool_, size));
416 memcpy(copy, data, size);
417 internal->value_ = copy;
418 }
419
420 return JSObjectMake(context, Struct_, internal);
421 }
422
423 JSValueRef CYCastJSValue(JSContextRef context, bool value) {
424 return JSValueMakeBoolean(context, value);
425 }
426
427 JSValueRef CYCastJSValue(JSContextRef context, double value) {
428 return JSValueMakeNumber(context, value);
429 }
430
431 #define CYCastJSValue_(Type_) \
432 JSValueRef CYCastJSValue(JSContextRef context, Type_ value) { \
433 return JSValueMakeNumber(context, static_cast<double>(value)); \
434 }
435
436 CYCastJSValue_(int)
437 CYCastJSValue_(unsigned int)
438 CYCastJSValue_(long int)
439 CYCastJSValue_(long unsigned int)
440 CYCastJSValue_(long long int)
441 CYCastJSValue_(long long unsigned int)
442
443 JSValueRef CYJSUndefined(JSContextRef context) {
444 return JSValueMakeUndefined(context);
445 }
446
447 double CYCastDouble(const char *value, size_t size) {
448 char *end;
449 double number(strtod(value, &end));
450 if (end != value + size)
451 return NAN;
452 return number;
453 }
454
455 double CYCastDouble(const char *value) {
456 return CYCastDouble(value, strlen(value));
457 }
458
459 double CYCastDouble(JSContextRef context, JSValueRef value) {
460 JSValueRef exception(NULL);
461 double number(JSValueToNumber(context, value, &exception));
462 CYThrow(context, exception);
463 return number;
464 }
465
466 bool CYCastBool(JSContextRef context, JSValueRef value) {
467 return JSValueToBoolean(context, value);
468 }
469
470 JSValueRef CYJSNull(JSContextRef context) {
471 return JSValueMakeNull(context);
472 }
473
474 JSValueRef CYCastJSValue(JSContextRef context, JSStringRef value) {
475 return value == NULL ? CYJSNull(context) : JSValueMakeString(context, value);
476 }
477
478 JSValueRef CYCastJSValue(JSContextRef context, const char *value) {
479 return CYCastJSValue(context, CYJSString(value));
480 }
481
482 JSObjectRef CYCastJSObject(JSContextRef context, JSValueRef value) {
483 JSValueRef exception(NULL);
484 JSObjectRef object(JSValueToObject(context, value, &exception));
485 CYThrow(context, exception);
486 return object;
487 }
488
489 JSValueRef CYCallAsFunction(JSContextRef context, JSObjectRef function, JSObjectRef _this, size_t count, JSValueRef arguments[]) {
490 JSValueRef exception(NULL);
491 JSValueRef value(JSObjectCallAsFunction(context, function, _this, count, arguments, &exception));
492 CYThrow(context, exception);
493 return value;
494 }
495
496 bool CYIsCallable(JSContextRef context, JSValueRef value) {
497 return value != NULL && JSValueIsObject(context, value) && JSObjectIsFunction(context, (JSObjectRef) value);
498 }
499
500 static JSValueRef System_print(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
501 if (count == 0)
502 printf("\n");
503 else {
504 CYPool pool;
505 printf("%s\n", CYPoolCString(pool, context, arguments[0]));
506 }
507
508 return CYJSUndefined(context);
509 } CYCatch }
510
511 static size_t Nonce_(0);
512
513 static JSValueRef $cyq(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
514 CYPool pool;
515 const char *name(apr_psprintf(pool, "%s%zu", CYPoolCString(pool, context, arguments[0]), Nonce_++));
516 return CYCastJSValue(context, name);
517 }
518
519 static JSValueRef Cycript_gc_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
520 JSGarbageCollect(context);
521 return CYJSUndefined(context);
522 }
523
524 const char *CYPoolCCYON(apr_pool_t *pool, JSContextRef context, JSValueRef value, JSValueRef *exception) { CYTry {
525 switch (JSType type = JSValueGetType(context, value)) {
526 case kJSTypeUndefined:
527 return "undefined";
528 case kJSTypeNull:
529 return "null";
530 case kJSTypeBoolean:
531 return CYCastBool(context, value) ? "true" : "false";
532
533 case kJSTypeNumber: {
534 std::ostringstream str;
535 CYNumerify(str, CYCastDouble(context, value));
536 std::string value(str.str());
537 return apr_pstrmemdup(pool, value.c_str(), value.size());
538 } break;
539
540 case kJSTypeString: {
541 std::ostringstream str;
542 CYUTF8String string(CYPoolUTF8String(pool, context, CYJSString(context, value)));
543 CYStringify(str, string.data, string.size);
544 std::string value(str.str());
545 return apr_pstrmemdup(pool, value.c_str(), value.size());
546 } break;
547
548 case kJSTypeObject:
549 return CYPoolCCYON(pool, context, (JSObjectRef) value);
550 default:
551 throw CYJSError(context, "JSValueGetType() == 0x%x", type);
552 }
553 } CYCatch }
554
555 const char *CYPoolCCYON(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
556 JSValueRef exception(NULL);
557 const char *cyon(CYPoolCCYON(pool, context, value, &exception));
558 CYThrow(context, exception);
559 return cyon;
560 }
561
562 const char *CYPoolCCYON(apr_pool_t *pool, JSContextRef context, JSObjectRef object) {
563 JSValueRef toCYON(CYGetProperty(context, object, toCYON_));
564 if (CYIsCallable(context, toCYON)) {
565 JSValueRef value(CYCallAsFunction(context, (JSObjectRef) toCYON, object, 0, NULL));
566 return CYPoolCString(pool, context, value);
567 }
568
569 JSValueRef toJSON(CYGetProperty(context, object, toJSON_));
570 if (CYIsCallable(context, toJSON)) {
571 JSValueRef arguments[1] = {CYCastJSValue(context, CYJSString(""))};
572 JSValueRef exception(NULL);
573 const char *cyon(CYPoolCCYON(pool, context, CYCallAsFunction(context, (JSObjectRef) toJSON, object, 1, arguments), &exception));
574 CYThrow(context, exception);
575 return cyon;
576 }
577
578 std::ostringstream str;
579
580 str << '{';
581
582 // XXX: this is, sadly, going to leak
583 JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context, object));
584
585 bool comma(false);
586
587 for (size_t index(0), count(JSPropertyNameArrayGetCount(names)); index != count; ++index) {
588 JSStringRef name(JSPropertyNameArrayGetNameAtIndex(names, index));
589 JSValueRef value(CYGetProperty(context, object, name));
590
591 if (comma)
592 str << ',';
593 else
594 comma = true;
595
596 CYUTF8String string(CYPoolUTF8String(pool, context, name));
597 if (CYIsKey(string))
598 str << string.data;
599 else
600 CYStringify(str, string.data, string.size);
601
602 str << ':' << CYPoolCCYON(pool, context, value);
603 }
604
605 str << '}';
606
607 JSPropertyNameArrayRelease(names);
608
609 std::string string(str.str());
610 return apr_pstrmemdup(pool, string.c_str(), string.size());
611 }
612
613 static JSValueRef Array_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
614 CYPool pool;
615 std::ostringstream str;
616
617 str << '[';
618
619 JSValueRef length(CYGetProperty(context, _this, length_));
620 bool comma(false);
621
622 for (size_t index(0), count(CYCastDouble(context, length)); index != count; ++index) {
623 JSValueRef value(CYGetProperty(context, _this, index));
624
625 if (comma)
626 str << ',';
627 else
628 comma = true;
629
630 if (!JSValueIsUndefined(context, value))
631 str << CYPoolCCYON(pool, context, value);
632 else {
633 str << ',';
634 comma = false;
635 }
636 }
637
638 str << ']';
639
640 std::string value(str.str());
641 return CYCastJSValue(context, CYJSString(CYUTF8String(value.c_str(), value.size())));
642 } CYCatch }
643
644 JSObjectRef CYMakePointer(JSContextRef context, void *pointer, sig::Type *type, ffi_type *ffi, JSObjectRef owner) {
645 Pointer *internal(new Pointer(pointer, context, owner, type));
646 return JSObjectMake(context, Pointer_, internal);
647 }
648
649 static JSObjectRef CYMakeFunctor(JSContextRef context, void (*function)(), const char *type) {
650 cy::Functor *internal(new cy::Functor(type, function));
651 return JSObjectMake(context, Functor_, internal);
652 }
653
654 static bool CYGetOffset(apr_pool_t *pool, JSContextRef context, JSStringRef value, ssize_t &index) {
655 return CYGetOffset(CYPoolCString(pool, context, value), index);
656 }
657
658 void *CYCastPointer_(JSContextRef context, JSValueRef value) {
659 switch (JSValueGetType(context, value)) {
660 case kJSTypeNull:
661 return NULL;
662 /*case kJSTypeObject:
663 if (JSValueIsObjectOfClass(context, value, Pointer_)) {
664 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate((JSObjectRef) value)));
665 return internal->value_;
666 }*/
667 default:
668 double number(CYCastDouble(context, value));
669 if (std::isnan(number))
670 throw CYJSError(context, "cannot convert value to pointer");
671 return reinterpret_cast<void *>(static_cast<uintptr_t>(static_cast<long long>(number)));
672 }
673 }
674
675 void CYPoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, JSValueRef value) {
676 switch (type->primitive) {
677 case sig::boolean_P:
678 *reinterpret_cast<bool *>(data) = JSValueToBoolean(context, value);
679 break;
680
681 #define CYPoolFFI_(primitive, native) \
682 case sig::primitive ## _P: \
683 *reinterpret_cast<native *>(data) = CYCastDouble(context, value); \
684 break;
685
686 CYPoolFFI_(uchar, unsigned char)
687 CYPoolFFI_(char, char)
688 CYPoolFFI_(ushort, unsigned short)
689 CYPoolFFI_(short, short)
690 CYPoolFFI_(ulong, unsigned long)
691 CYPoolFFI_(long, long)
692 CYPoolFFI_(uint, unsigned int)
693 CYPoolFFI_(int, int)
694 CYPoolFFI_(ulonglong, unsigned long long)
695 CYPoolFFI_(longlong, long long)
696 CYPoolFFI_(float, float)
697 CYPoolFFI_(double, double)
698
699 case sig::pointer_P:
700 *reinterpret_cast<void **>(data) = CYCastPointer<void *>(context, value);
701 break;
702
703 case sig::string_P:
704 *reinterpret_cast<const char **>(data) = CYPoolCString(pool, context, value);
705 break;
706
707 case sig::struct_P: {
708 uint8_t *base(reinterpret_cast<uint8_t *>(data));
709 JSObjectRef aggregate(JSValueIsObject(context, value) ? (JSObjectRef) value : NULL);
710 for (size_t index(0); index != type->data.signature.count; ++index) {
711 sig::Element *element(&type->data.signature.elements[index]);
712 ffi_type *field(ffi->elements[index]);
713
714 JSValueRef rhs;
715 if (aggregate == NULL)
716 rhs = value;
717 else {
718 rhs = CYGetProperty(context, aggregate, index);
719 if (JSValueIsUndefined(context, rhs)) {
720 if (element->name != NULL)
721 rhs = CYGetProperty(context, aggregate, CYJSString(element->name));
722 else
723 goto undefined;
724 if (JSValueIsUndefined(context, rhs)) undefined:
725 throw CYJSError(context, "unable to extract structure value");
726 }
727 }
728
729 CYPoolFFI(pool, context, element->type, field, base, rhs);
730 // XXX: alignment?
731 base += field->size;
732 }
733 } break;
734
735 case sig::void_P:
736 break;
737
738 default:
739 if (hooks_ != NULL && hooks_->PoolFFI != NULL)
740 if ((*hooks_->PoolFFI)(pool, context, type, ffi, data, value))
741 return;
742
743 fprintf(stderr, "CYPoolFFI(%c)\n", type->primitive);
744 _assert(false);
745 }
746 }
747
748 JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) {
749 switch (type->primitive) {
750 case sig::boolean_P:
751 return CYCastJSValue(context, *reinterpret_cast<bool *>(data));
752
753 #define CYFromFFI_(primitive, native) \
754 case sig::primitive ## _P: \
755 return CYCastJSValue(context, *reinterpret_cast<native *>(data)); \
756
757 CYFromFFI_(uchar, unsigned char)
758 CYFromFFI_(char, char)
759 CYFromFFI_(ushort, unsigned short)
760 CYFromFFI_(short, short)
761 CYFromFFI_(ulong, unsigned long)
762 CYFromFFI_(long, long)
763 CYFromFFI_(uint, unsigned int)
764 CYFromFFI_(int, int)
765 CYFromFFI_(ulonglong, unsigned long long)
766 CYFromFFI_(longlong, long long)
767 CYFromFFI_(float, float)
768 CYFromFFI_(double, double)
769
770 case sig::pointer_P:
771 if (void *pointer = *reinterpret_cast<void **>(data))
772 return CYMakePointer(context, pointer, type->data.data.type, ffi, owner);
773 else goto null;
774
775 case sig::string_P:
776 if (char *utf8 = *reinterpret_cast<char **>(data))
777 return CYCastJSValue(context, utf8);
778 else goto null;
779
780 case sig::struct_P:
781 return CYMakeStruct(context, data, type, ffi, owner);
782 case sig::void_P:
783 return CYJSUndefined(context);
784
785 null:
786 return CYJSNull(context);
787 default:
788 if (hooks_ != NULL && hooks_->FromFFI != NULL)
789 if (JSValueRef value = (*hooks_->FromFFI)(context, type, ffi, data, initialize, owner))
790 return value;
791
792 fprintf(stderr, "CYFromFFI(%c)\n", type->primitive);
793 _assert(false);
794 }
795 }
796
797 static void FunctionClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) {
798 Closure_privateData *internal(reinterpret_cast<Closure_privateData *>(arg));
799
800 JSContextRef context(internal->context_);
801
802 size_t count(internal->cif_.nargs);
803 JSValueRef values[count];
804
805 for (size_t index(0); index != count; ++index)
806 values[index] = CYFromFFI(context, internal->signature_.elements[1 + index].type, internal->cif_.arg_types[index], arguments[index]);
807
808 JSValueRef value(CYCallAsFunction(context, internal->function_, NULL, count, values));
809 CYPoolFFI(NULL, context, internal->signature_.elements[0].type, internal->cif_.rtype, result, value);
810 }
811
812 Closure_privateData *CYMakeFunctor_(JSContextRef context, JSObjectRef function, const char *type, void (*callback)(ffi_cif *, void *, void **, void *)) {
813 // XXX: in case of exceptions this will leak
814 // XXX: in point of fact, this may /need/ to leak :(
815 Closure_privateData *internal(new Closure_privateData(CYGetJSContext(), function, type));
816
817 ffi_closure *closure((ffi_closure *) _syscall(mmap(
818 NULL, sizeof(ffi_closure),
819 PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
820 -1, 0
821 )));
822
823 ffi_status status(ffi_prep_closure(closure, &internal->cif_, callback, internal));
824 _assert(status == FFI_OK);
825
826 _syscall(mprotect(closure, sizeof(*closure), PROT_READ | PROT_EXEC));
827
828 internal->value_ = closure;
829
830 return internal;
831 }
832
833 static JSObjectRef CYMakeFunctor(JSContextRef context, JSObjectRef function, const char *type) {
834 Closure_privateData *internal(CYMakeFunctor_(context, function, type, &FunctionClosure_));
835 return JSObjectMake(context, Functor_, internal);
836 }
837
838 static JSObjectRef CYMakeFunctor(JSContextRef context, JSValueRef value, const char *type) {
839 JSValueRef exception(NULL);
840 bool function(JSValueIsInstanceOfConstructor(context, value, Function_, &exception));
841 CYThrow(context, exception);
842
843 if (function) {
844 JSObjectRef function(CYCastJSObject(context, value));
845 return CYMakeFunctor(context, function, type);
846 } else {
847 void (*function)()(CYCastPointer<void (*)()>(context, value));
848 return CYMakeFunctor(context, function, type);
849 }
850 }
851
852 static bool Index_(apr_pool_t *pool, JSContextRef context, Struct_privateData *internal, JSStringRef property, ssize_t &index, uint8_t *&base) {
853 Type_privateData *typical(internal->type_);
854 sig::Type *type(typical->type_);
855 if (type == NULL)
856 return false;
857
858 const char *name(CYPoolCString(pool, context, property));
859 size_t length(strlen(name));
860 double number(CYCastDouble(name, length));
861
862 size_t count(type->data.signature.count);
863
864 if (std::isnan(number)) {
865 if (property == NULL)
866 return false;
867
868 sig::Element *elements(type->data.signature.elements);
869
870 for (size_t local(0); local != count; ++local) {
871 sig::Element *element(&elements[local]);
872 if (element->name != NULL && strcmp(name, element->name) == 0) {
873 index = local;
874 goto base;
875 }
876 }
877
878 return false;
879 } else {
880 index = static_cast<ssize_t>(number);
881 if (index != number || index < 0 || static_cast<size_t>(index) >= count)
882 return false;
883 }
884
885 base:
886 ffi_type **elements(typical->GetFFI()->elements);
887
888 base = reinterpret_cast<uint8_t *>(internal->value_);
889 for (ssize_t local(0); local != index; ++local)
890 base += elements[local]->size;
891
892 return true;
893 }
894
895 static JSValueRef Pointer_getIndex(JSContextRef context, JSObjectRef object, size_t index, JSValueRef *exception) { CYTry {
896 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
897 Type_privateData *typical(internal->type_);
898
899 ffi_type *ffi(typical->GetFFI());
900
901 uint8_t *base(reinterpret_cast<uint8_t *>(internal->value_));
902 base += ffi->size * index;
903
904 JSObjectRef owner(internal->GetOwner() ?: object);
905 return CYFromFFI(context, typical->type_, ffi, base, false, owner);
906 } CYCatch }
907
908 static JSValueRef Pointer_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
909 CYPool pool;
910 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
911 Type_privateData *typical(internal->type_);
912
913 if (typical->type_ == NULL)
914 return NULL;
915
916 ssize_t offset;
917 if (!CYGetOffset(pool, context, property, offset))
918 return NULL;
919
920 return Pointer_getIndex(context, object, offset, exception);
921 }
922
923 static JSValueRef Pointer_getProperty_$cyi(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
924 return Pointer_getIndex(context, object, 0, exception);
925 }
926
927 static bool Pointer_setIndex(JSContextRef context, JSObjectRef object, size_t index, JSValueRef value, JSValueRef *exception) { CYTry {
928 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
929 Type_privateData *typical(internal->type_);
930
931 ffi_type *ffi(typical->GetFFI());
932
933 uint8_t *base(reinterpret_cast<uint8_t *>(internal->value_));
934 base += ffi->size * index;
935
936 CYPoolFFI(NULL, context, typical->type_, ffi, base, value);
937 return true;
938 } CYCatch }
939
940 static bool Pointer_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) {
941 CYPool pool;
942 Pointer *internal(reinterpret_cast<Pointer *>(JSObjectGetPrivate(object)));
943 Type_privateData *typical(internal->type_);
944
945 if (typical->type_ == NULL)
946 return NULL;
947
948 ssize_t offset;
949 if (!CYGetOffset(pool, context, property, offset))
950 return NULL;
951
952 return Pointer_setIndex(context, object, offset, value, exception);
953 }
954
955 static bool Pointer_setProperty_$cyi(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) {
956 return Pointer_setIndex(context, object, 0, value, exception);
957 }
958
959 static JSValueRef Struct_callAsFunction_$cya(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
960 Struct_privateData *internal(reinterpret_cast<Struct_privateData *>(JSObjectGetPrivate(_this)));
961 Type_privateData *typical(internal->type_);
962 return CYMakePointer(context, internal->value_, typical->type_, typical->ffi_, _this);
963 }
964
965 static JSValueRef Struct_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
966 CYPool pool;
967 Struct_privateData *internal(reinterpret_cast<Struct_privateData *>(JSObjectGetPrivate(object)));
968 Type_privateData *typical(internal->type_);
969
970 ssize_t index;
971 uint8_t *base;
972
973 if (!Index_(pool, context, internal, property, index, base))
974 return NULL;
975
976 JSObjectRef owner(internal->GetOwner() ?: object);
977
978 return CYFromFFI(context, typical->type_->data.signature.elements[index].type, typical->GetFFI()->elements[index], base, false, owner);
979 } CYCatch }
980
981 static bool Struct_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
982 CYPool pool;
983 Struct_privateData *internal(reinterpret_cast<Struct_privateData *>(JSObjectGetPrivate(object)));
984 Type_privateData *typical(internal->type_);
985
986 ssize_t index;
987 uint8_t *base;
988
989 if (!Index_(pool, context, internal, property, index, base))
990 return false;
991
992 CYPoolFFI(NULL, context, typical->type_->data.signature.elements[index].type, typical->GetFFI()->elements[index], base, value);
993 return true;
994 } CYCatch }
995
996 static void Struct_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
997 Struct_privateData *internal(reinterpret_cast<Struct_privateData *>(JSObjectGetPrivate(object)));
998 Type_privateData *typical(internal->type_);
999 sig::Type *type(typical->type_);
1000
1001 if (type == NULL)
1002 return;
1003
1004 size_t count(type->data.signature.count);
1005 sig::Element *elements(type->data.signature.elements);
1006
1007 char number[32];
1008
1009 for (size_t index(0); index != count; ++index) {
1010 const char *name;
1011 name = elements[index].name;
1012
1013 if (name == NULL) {
1014 sprintf(number, "%lu", index);
1015 name = number;
1016 }
1017
1018 JSPropertyNameAccumulatorAddName(names, CYJSString(name));
1019 }
1020 }
1021
1022 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 {
1023 if (setups + count != signature->count - 1)
1024 throw CYJSError(context, "incorrect number of arguments to ffi function");
1025
1026 size_t size(setups + count);
1027 void *values[size];
1028 memcpy(values, setup, sizeof(void *) * setups);
1029
1030 for (size_t index(setups); index != size; ++index) {
1031 sig::Element *element(&signature->elements[index + 1]);
1032 ffi_type *ffi(cif->arg_types[index]);
1033 // XXX: alignment?
1034 values[index] = new(pool) uint8_t[ffi->size];
1035 CYPoolFFI(pool, context, element->type, ffi, values[index], arguments[index - setups]);
1036 }
1037
1038 uint8_t value[cif->rtype->size];
1039 ffi_call(cif, function, value, values);
1040
1041 return CYFromFFI(context, signature->elements[0].type, cif->rtype, value, initialize);
1042 } CYCatch }
1043
1044 static JSValueRef Functor_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
1045 CYPool pool;
1046 cy::Functor *internal(reinterpret_cast<cy::Functor *>(JSObjectGetPrivate(object)));
1047 return CYCallFunction(pool, context, 0, NULL, count, arguments, false, exception, &internal->signature_, &internal->cif_, internal->GetValue());
1048 }
1049
1050 static JSObjectRef CYMakeType(JSContextRef context, const char *type) {
1051 Type_privateData *internal(new Type_privateData(NULL, type));
1052 return JSObjectMake(context, Type_privateData::Class_, internal);
1053 }
1054
1055 static JSObjectRef CYMakeType(JSContextRef context, sig::Type *type) {
1056 Type_privateData *internal(new Type_privateData(type));
1057 return JSObjectMake(context, Type_privateData::Class_, internal);
1058 }
1059
1060 static void *CYCastSymbol(const char *name) {
1061 return dlsym(RTLD_DEFAULT, name);
1062 }
1063
1064 static JSValueRef Runtime_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1065 CYPool pool;
1066 CYUTF8String name(CYPoolUTF8String(pool, context, property));
1067
1068 if (hooks_ != NULL && hooks_->RuntimeProperty != NULL)
1069 if (JSValueRef value = (*hooks_->RuntimeProperty)(context, name))
1070 return value;
1071
1072 sqlite3_stmt *statement;
1073
1074 _sqlcall(sqlite3_prepare(Bridge_,
1075 "select "
1076 "\"bridge\".\"mode\", "
1077 "\"bridge\".\"value\" "
1078 "from \"bridge\" "
1079 "where"
1080 " \"bridge\".\"name\" = ?"
1081 " limit 1"
1082 , -1, &statement, NULL));
1083
1084 _sqlcall(sqlite3_bind_text(statement, 1, name.data, name.size, SQLITE_STATIC));
1085
1086 int mode;
1087 const char *value;
1088
1089 if (_sqlcall(sqlite3_step(statement)) == SQLITE_DONE) {
1090 mode = -1;
1091 value = NULL;
1092 } else {
1093 mode = sqlite3_column_int(statement, 0);
1094 value = sqlite3_column_pooled(pool, statement, 1);
1095 }
1096
1097 _sqlcall(sqlite3_finalize(statement));
1098
1099 switch (mode) {
1100 default:
1101 _assert(false);
1102 case -1:
1103 return NULL;
1104
1105 case 0:
1106 return JSEvaluateScript(CYGetJSContext(), CYJSString(value), NULL, NULL, 0, NULL);
1107 case 1:
1108 return CYMakeFunctor(context, reinterpret_cast<void (*)()>(CYCastSymbol(name.data)), value);
1109
1110 case 2: {
1111 // XXX: this is horrendously inefficient
1112 sig::Signature signature;
1113 sig::Parse(pool, &signature, value, &Structor_);
1114 ffi_cif cif;
1115 sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif);
1116 return CYFromFFI(context, signature.elements[0].type, cif.rtype, CYCastSymbol(name.data));
1117 }
1118
1119 // XXX: implement case 3
1120 case 4:
1121 return CYMakeType(context, value);
1122 }
1123 } CYCatch }
1124
1125 static JSObjectRef Pointer_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1126 if (count != 2)
1127 throw CYJSError(context, "incorrect number of arguments to Functor constructor");
1128
1129 CYPool pool;
1130
1131 void *value(CYCastPointer<void *>(context, arguments[0]));
1132 const char *type(CYPoolCString(pool, context, arguments[1]));
1133
1134 sig::Signature signature;
1135 sig::Parse(pool, &signature, type, &Structor_);
1136
1137 return CYMakePointer(context, value, signature.elements[0].type, NULL, NULL);
1138 } CYCatch }
1139
1140 static JSObjectRef Type_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1141 if (count != 1)
1142 throw CYJSError(context, "incorrect number of arguments to Type constructor");
1143 CYPool pool;
1144 const char *type(CYPoolCString(pool, context, arguments[0]));
1145 return CYMakeType(context, type);
1146 } CYCatch }
1147
1148 static JSValueRef Type_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1149 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1150
1151 sig::Type type;
1152
1153 if (JSStringIsEqualToUTF8CString(property, "$cyi")) {
1154 type.primitive = sig::pointer_P;
1155 type.data.data.size = 0;
1156 } else {
1157 CYPool pool;
1158 size_t index(CYGetIndex(pool, context, property));
1159 if (index == _not(size_t))
1160 return NULL;
1161 type.primitive = sig::array_P;
1162 type.data.data.size = index;
1163 }
1164
1165 type.name = NULL;
1166 type.flags = 0;
1167
1168 type.data.data.type = internal->type_;
1169
1170 return CYMakeType(context, &type);
1171 } CYCatch }
1172
1173 static JSValueRef Type_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1174 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1175
1176 if (count != 1)
1177 throw CYJSError(context, "incorrect number of arguments to type cast function");
1178 sig::Type *type(internal->type_);
1179 ffi_type *ffi(internal->GetFFI());
1180 // XXX: alignment?
1181 uint8_t value[ffi->size];
1182 CYPool pool;
1183 CYPoolFFI(pool, context, type, ffi, value, arguments[0]);
1184 return CYFromFFI(context, type, ffi, value);
1185 } CYCatch }
1186
1187 static JSObjectRef Type_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1188 if (count != 0)
1189 throw CYJSError(context, "incorrect number of arguments to type cast function");
1190 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(object)));
1191
1192 sig::Type *type(internal->type_);
1193 size_t size;
1194
1195 if (type->primitive != sig::array_P)
1196 size = 0;
1197 else {
1198 size = type->data.data.size;
1199 type = type->data.data.type;
1200 }
1201
1202 void *value(malloc(internal->GetFFI()->size));
1203 return CYMakePointer(context, value, type, NULL, NULL);
1204 } CYCatch }
1205
1206 static JSObjectRef Functor_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1207 if (count != 2)
1208 throw CYJSError(context, "incorrect number of arguments to Functor constructor");
1209 CYPool pool;
1210 const char *type(CYPoolCString(pool, context, arguments[1]));
1211 return CYMakeFunctor(context, arguments[0], type);
1212 } CYCatch }
1213
1214 static JSValueRef CYValue_callAsFunction_valueOf(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1215 CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this)));
1216 return CYCastJSValue(context, reinterpret_cast<uintptr_t>(internal->value_));
1217 } CYCatch }
1218
1219 static JSValueRef CYValue_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
1220 return CYValue_callAsFunction_valueOf(context, object, _this, count, arguments, exception);
1221 }
1222
1223 static JSValueRef CYValue_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1224 CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this)));
1225 char string[32];
1226 sprintf(string, "%p", internal->value_);
1227
1228 return CYCastJSValue(context, string);
1229 } CYCatch }
1230
1231 static JSValueRef Type_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1232 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1233 CYPool pool;
1234 const char *type(sig::Unparse(pool, internal->type_));
1235 return CYCastJSValue(context, CYJSString(type));
1236 } CYCatch }
1237
1238 static JSValueRef Type_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
1239 Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
1240 CYPool pool;
1241 const char *type(sig::Unparse(pool, internal->type_));
1242 size_t size(strlen(type));
1243 char *cyon(new(pool) char[12 + size + 1]);
1244 memcpy(cyon, "new Type(\"", 10);
1245 cyon[12 + size] = '\0';
1246 cyon[12 + size - 2] = '"';
1247 cyon[12 + size - 1] = ')';
1248 memcpy(cyon + 10, type, size);
1249 return CYCastJSValue(context, CYJSString(cyon));
1250 } CYCatch }
1251
1252 static JSValueRef Type_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
1253 return Type_callAsFunction_toString(context, object, _this, count, arguments, exception);
1254 }
1255
1256 static JSStaticValue Pointer_staticValues[2] = {
1257 {"$cyi", &Pointer_getProperty_$cyi, &Pointer_setProperty_$cyi, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1258 {NULL, NULL, NULL, 0}
1259 };
1260
1261 static JSStaticFunction Pointer_staticFunctions[4] = {
1262 {"toCYON", &CYValue_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1263 {"toJSON", &CYValue_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1264 {"valueOf", &CYValue_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1265 {NULL, NULL, 0}
1266 };
1267
1268 static JSStaticFunction Struct_staticFunctions[2] = {
1269 {"$cya", &Struct_callAsFunction_$cya, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1270 {NULL, NULL, 0}
1271 };
1272
1273 static JSStaticFunction Functor_staticFunctions[4] = {
1274 {"toCYON", &CYValue_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1275 {"toJSON", &CYValue_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1276 {"valueOf", &CYValue_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1277 {NULL, NULL, 0}
1278 };
1279
1280 namespace cy {
1281 JSStaticFunction const * const Functor::StaticFunctions = Functor_staticFunctions;
1282 }
1283
1284 static JSStaticFunction Type_staticFunctions[4] = {
1285 {"toCYON", &Type_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1286 {"toJSON", &Type_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1287 {"toString", &Type_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1288 {NULL, NULL, 0}
1289 };
1290
1291 void CYSetArgs(int argc, const char *argv[]) {
1292 JSContextRef context(CYGetJSContext());
1293 JSValueRef args[argc];
1294 for (int i(0); i != argc; ++i)
1295 args[i] = CYCastJSValue(context, argv[i]);
1296 JSValueRef exception(NULL);
1297 JSObjectRef array(JSObjectMakeArray(context, argc, args, &exception));
1298 CYThrow(context, exception);
1299 CYSetProperty(context, System_, CYJSString("args"), array);
1300 }
1301
1302 JSObjectRef CYGetGlobalObject(JSContextRef context) {
1303 return JSContextGetGlobalObject(context);
1304 }
1305
1306 const char *CYExecute(apr_pool_t *pool, const char *code) {
1307 JSContextRef context(CYGetJSContext());
1308 JSValueRef exception(NULL), result;
1309
1310 void *handle;
1311 if (hooks_ != NULL && hooks_->ExecuteStart != NULL)
1312 handle = (*hooks_->ExecuteStart)();
1313 else
1314 handle = NULL;
1315
1316 const char *json;
1317
1318 try {
1319 result = JSEvaluateScript(context, CYJSString(code), NULL, NULL, 0, &exception);
1320 } catch (const char *error) {
1321 return error;
1322 }
1323
1324 if (exception != NULL) { error:
1325 result = exception;
1326 exception = NULL;
1327 }
1328
1329 if (JSValueIsUndefined(context, result))
1330 return NULL;
1331
1332 try {
1333 json = CYPoolCCYON(pool, context, result, &exception);
1334 } catch (const char *error) {
1335 return error;
1336 }
1337
1338 if (exception != NULL)
1339 goto error;
1340
1341 CYSetProperty(context, CYGetGlobalObject(context), Result_, result);
1342
1343 if (hooks_ != NULL && hooks_->ExecuteEnd != NULL)
1344 (*hooks_->ExecuteEnd)(handle);
1345 return json;
1346 }
1347
1348 static apr_pool_t *Pool_;
1349
1350 static bool initialized_;
1351
1352 void CYInitialize() {
1353 if (!initialized_)
1354 initialized_ = true;
1355 else return;
1356
1357 _aprcall(apr_initialize());
1358 _aprcall(apr_pool_create(&Pool_, NULL));
1359 _sqlcall(sqlite3_open("/usr/lib/libcycript.db", &Bridge_));
1360 }
1361
1362 apr_pool_t *CYGetGlobalPool() {
1363 CYInitialize();
1364 return Pool_;
1365 }
1366
1367 void CYThrow(JSContextRef context, JSValueRef value) {
1368 if (value != NULL)
1369 throw CYJSError(context, value);
1370 }
1371
1372 const char *CYJSError::PoolCString(apr_pool_t *pool) const {
1373 return CYPoolCString(pool, context_, value_);
1374 }
1375
1376 JSValueRef CYJSError::CastJSValue(JSContextRef context) const {
1377 // XXX: what if the context is different?
1378 return value_;
1379 }
1380
1381 void CYThrow(const char *format, ...) {
1382 va_list args;
1383 va_start (args, format);
1384 throw CYPoolError(format, args);
1385 // XXX: does this matter? :(
1386 va_end (args);
1387 }
1388
1389 const char *CYPoolError::PoolCString(apr_pool_t *pool) const {
1390 return apr_pstrdup(pool, message_);
1391 }
1392
1393 CYPoolError::CYPoolError(const char *format, ...) {
1394 va_list args;
1395 va_start (args, format);
1396 message_ = apr_pvsprintf(pool_, format, args);
1397 va_end (args);
1398 }
1399
1400 CYPoolError::CYPoolError(const char *format, va_list args) {
1401 message_ = apr_pvsprintf(pool_, format, args);
1402 }
1403
1404 JSValueRef CYPoolError::CastJSValue(JSContextRef context) const {
1405 return CYCastJSValue(context, message_);
1406 }
1407
1408 CYJSError::CYJSError(JSContextRef context, const char *format, ...) {
1409 if (context == NULL)
1410 context = CYGetJSContext();
1411
1412 CYPool pool;
1413
1414 va_list args;
1415 va_start (args, format);
1416 const char *message(apr_pvsprintf(pool, format, args));
1417 va_end (args);
1418
1419 JSValueRef arguments[1] = {CYCastJSValue(context, CYJSString(message))};
1420
1421 JSValueRef exception(NULL);
1422 value_ = JSObjectCallAsConstructor(context, Error_, 1, arguments, &exception);
1423 CYThrow(context, exception);
1424 }
1425
1426 void CYObjectiveC(JSContextRef context, JSObjectRef global);
1427
1428 JSGlobalContextRef CYGetJSContext() {
1429 CYInitialize();
1430
1431 if (Context_ == NULL) {
1432 JSClassDefinition definition;
1433
1434 definition = kJSClassDefinitionEmpty;
1435 definition.className = "Functor";
1436 definition.staticFunctions = cy::Functor::StaticFunctions;
1437 definition.callAsFunction = &Functor_callAsFunction;
1438 definition.finalize = &CYFinalize;
1439 Functor_ = JSClassCreate(&definition);
1440
1441 definition = kJSClassDefinitionEmpty;
1442 definition.className = "Pointer";
1443 definition.staticValues = Pointer_staticValues;
1444 definition.staticFunctions = Pointer_staticFunctions;
1445 definition.getProperty = &Pointer_getProperty;
1446 definition.setProperty = &Pointer_setProperty;
1447 definition.finalize = &CYFinalize;
1448 Pointer_ = JSClassCreate(&definition);
1449
1450 definition = kJSClassDefinitionEmpty;
1451 definition.className = "Struct";
1452 definition.staticFunctions = Struct_staticFunctions;
1453 definition.getProperty = &Struct_getProperty;
1454 definition.setProperty = &Struct_setProperty;
1455 definition.getPropertyNames = &Struct_getPropertyNames;
1456 definition.finalize = &CYFinalize;
1457 Struct_ = JSClassCreate(&definition);
1458
1459 definition = kJSClassDefinitionEmpty;
1460 definition.className = "Type";
1461 definition.staticFunctions = Type_staticFunctions;
1462 definition.getProperty = &Type_getProperty;
1463 definition.callAsFunction = &Type_callAsFunction;
1464 definition.callAsConstructor = &Type_callAsConstructor;
1465 definition.finalize = &CYFinalize;
1466 Type_privateData::Class_ = JSClassCreate(&definition);
1467
1468 definition = kJSClassDefinitionEmpty;
1469 definition.className = "Runtime";
1470 definition.getProperty = &Runtime_getProperty;
1471 Runtime_ = JSClassCreate(&definition);
1472
1473 definition = kJSClassDefinitionEmpty;
1474 //definition.getProperty = &Global_getProperty;
1475 JSClassRef Global(JSClassCreate(&definition));
1476
1477 JSGlobalContextRef context(JSGlobalContextCreate(Global));
1478 Context_ = context;
1479 JSObjectRef global(CYGetGlobalObject(context));
1480
1481 JSObjectSetPrototype(context, global, JSObjectMake(context, Runtime_, NULL));
1482
1483 Array_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Array")));
1484 JSValueProtect(context, Array_);
1485
1486 Error_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Error")));
1487 JSValueProtect(context, Error_);
1488
1489 Function_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Function")));
1490 JSValueProtect(context, Function_);
1491
1492 String_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("String")));
1493 JSValueProtect(context, String_);
1494
1495 length_ = JSStringCreateWithUTF8CString("length");
1496 message_ = JSStringCreateWithUTF8CString("message");
1497 name_ = JSStringCreateWithUTF8CString("name");
1498 prototype_ = JSStringCreateWithUTF8CString("prototype");
1499 toCYON_ = JSStringCreateWithUTF8CString("toCYON");
1500 toJSON_ = JSStringCreateWithUTF8CString("toJSON");
1501
1502 JSObjectRef Object(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Object"))));
1503 Object_prototype_ = CYCastJSObject(context, CYGetProperty(context, Object, prototype_));
1504 JSValueProtect(context, Object_prototype_);
1505
1506 Array_prototype_ = CYCastJSObject(context, CYGetProperty(context, Array_, prototype_));
1507 Array_pop_ = CYCastJSObject(context, CYGetProperty(context, Array_prototype_, CYJSString("pop")));
1508 Array_push_ = CYCastJSObject(context, CYGetProperty(context, Array_prototype_, CYJSString("push")));
1509 Array_splice_ = CYCastJSObject(context, CYGetProperty(context, Array_prototype_, CYJSString("splice")));
1510
1511 CYSetProperty(context, Array_prototype_, toCYON_, JSObjectMakeFunctionWithCallback(context, toCYON_, &Array_callAsFunction_toCYON), kJSPropertyAttributeDontEnum);
1512
1513 JSValueProtect(context, Array_prototype_);
1514 JSValueProtect(context, Array_pop_);
1515 JSValueProtect(context, Array_push_);
1516 JSValueProtect(context, Array_splice_);
1517
1518 JSObjectRef Functor(JSObjectMakeConstructor(context, Functor_, &Functor_new));
1519
1520 Function_prototype_ = (JSObjectRef) CYGetProperty(context, Function_, prototype_);
1521 JSValueProtect(context, Function_prototype_);
1522
1523 JSObjectSetPrototype(context, (JSObjectRef) CYGetProperty(context, Functor, prototype_), Function_prototype_);
1524
1525 CYSetProperty(context, global, CYJSString("Functor"), Functor);
1526 CYSetProperty(context, global, CYJSString("Pointer"), JSObjectMakeConstructor(context, Pointer_, &Pointer_new));
1527 CYSetProperty(context, global, CYJSString("Type"), JSObjectMakeConstructor(context, Type_privateData::Class_, &Type_new));
1528
1529 JSObjectRef cycript(JSObjectMake(context, NULL, NULL));
1530 CYSetProperty(context, global, CYJSString("Cycript"), cycript);
1531 CYSetProperty(context, cycript, CYJSString("gc"), JSObjectMakeFunctionWithCallback(context, CYJSString("gc"), &Cycript_gc_callAsFunction));
1532
1533 CYSetProperty(context, global, CYJSString("$cyq"), JSObjectMakeFunctionWithCallback(context, CYJSString("$cyq"), &$cyq));
1534
1535 System_ = JSObjectMake(context, NULL, NULL);
1536 JSValueProtect(context, System_);
1537
1538 CYSetProperty(context, global, CYJSString("system"), System_);
1539 CYSetProperty(context, System_, CYJSString("args"), CYJSNull(context));
1540 //CYSetProperty(context, System_, CYJSString("global"), global);
1541
1542 CYSetProperty(context, System_, CYJSString("print"), JSObjectMakeFunctionWithCallback(context, CYJSString("print"), &System_print));
1543
1544 Result_ = JSStringCreateWithUTF8CString("_");
1545
1546 CYObjectiveC(context, global);
1547 }
1548
1549 return Context_;
1550 }