#define _GNU_SOURCE
#include <substrate.h>
-#include "Struct.hpp"
+#include "cycript.hpp"
#include "sig/parse.hpp"
#include "sig/ffi_type.hpp"
#include "Pooling.hpp"
+#include "Struct.hpp"
#include <unistd.h>
#include <CoreFoundation/CFLogUtilities.h>
#include <CFNetwork/CFNetwork.h>
-#include <Foundation/Foundation.h>
-
-#include <JavaScriptCore/JSBase.h>
-#include <JavaScriptCore/JSValueRef.h>
-#include <JavaScriptCore/JSObjectRef.h>
-#include <JavaScriptCore/JSContextRef.h>
-#include <JavaScriptCore/JSStringRef.h>
-#include <JavaScriptCore/JSStringRefCF.h>
#include <WebKit/WebScriptObject.h>
#include <ext/stdio_filebuf.h>
#include <set>
#include <map>
-#include <sstream>
#include "Parser.hpp"
#include "Cycript.tab.hh"
} while (false)
-#define _pooled _H<NSAutoreleasePool> _pool([[NSAutoreleasePool alloc] init], true);
-
static JSContextRef Context_;
static JSClassRef Functor_;
static JSClassRef Selector_;
static JSObjectRef Array_;
+static JSObjectRef Function_;
static JSStringRef name_;
static JSStringRef message_;
@end
@interface NSObject (Cycript)
+- (bool) cy$isUndefined;
- (NSString *) cy$toJSON;
- (JSValueRef) cy$JSValueInContext:(JSContextRef)context;
@end
@implementation NSObject (Cycript)
+- (bool) cy$isUndefined {
+ return false;
+}
+
- (NSString *) cy$toJSON {
return [self description];
}
@implementation WebUndefined (Cycript)
+- (bool) cy$isUndefined {
+ return true;
+}
+
- (NSString *) cy$toJSON {
return @"undefined";
}
[json appendString:@","];
else
comma = true;
- [json appendString:[object cy$toJSON]];
+ if (![object cy$isUndefined])
+ [json appendString:[object cy$toJSON]];
+ else {
+ [json appendString:@","];
+ comma = false;
+ }
}
[json appendString:@"]"];
- (NSString *) cy$toJSON {
NSMutableString *json([[[NSMutableString alloc] init] autorelease]);
- [json appendString:@"("];
- [json appendString:@"{"];
+ [json appendString:@"({"];
bool comma(false);
for (id key in self) {
@end
-JSContextRef JSGetContext() {
+CYRange WordStartRange_(0x1000000000LLU,0x7fffffe87fffffeLLU); // A-Za-z_$
+CYRange WordEndRange_(0x3ff001000000000LLU,0x7fffffe87fffffeLLU); // A-Za-z_$0-9
+
+JSContextRef CYGetJSContext() {
return Context_;
}
return value == nil ? JSValueMakeNull(context) : [value cy$JSValueInContext:context];
}
+JSObjectRef CYCastJSObject(JSContextRef context, JSValueRef value) {
+ JSValueRef exception(NULL);
+ JSObjectRef object(JSValueToObject(context, value, &exception));
+ CYThrow(context, exception);
+ return object;
+}
+
+JSValueRef CYGetProperty(JSContextRef context, JSObjectRef object, JSStringRef name) {
+ JSValueRef exception(NULL);
+ JSValueRef value(JSObjectGetProperty(context, object, name, &exception));
+ CYThrow(context, exception);
+ return value;
+}
+
+void CYSetProperty(JSContextRef context, JSObjectRef object, JSStringRef name, JSValueRef value) {
+ JSValueRef exception(NULL);
+ JSObjectSetProperty(context, object, name, value, kJSPropertyAttributeNone, &exception);
+ CYThrow(context, exception);
+}
+
void CYThrow(JSContextRef context, id error, JSValueRef *exception) {
*exception = CYCastJSValue(context, error);
}
}
- (id) objectForKey:(id)key {
- JSValueRef exception(NULL);
- JSValueRef value(JSObjectGetProperty(context_, object_, CYJSString(key), &exception));
- CYThrow(context_, exception);
- return CYCastNSObject(context_, value);
+ return CYCastNSObject(context_, CYGetProperty(context_, object_, CYJSString(key)));
}
- (NSEnumerator *) keyEnumerator {
}
- (void) setObject:(id)object forKey:(id)key {
- JSValueRef exception(NULL);
- JSObjectSetProperty(context_, object_, CYJSString(key), CYCastJSValue(context_, object), kJSPropertyAttributeNone, &exception);
- CYThrow(context_, exception);
+ CYSetProperty(context_, object_, CYJSString(key), CYCastJSValue(context_, object));
}
- (void) removeObjectForKey:(id)key {
}
- (NSUInteger) count {
- JSValueRef exception(NULL);
- JSValueRef value(JSObjectGetProperty(context_, object_, length_, &exception));
- CYThrow(context_, exception);
- return CYCastDouble(context_, value);
+ return CYCastDouble(context_, CYGetProperty(context_, object_, length_));
}
- (id) objectAtIndex:(NSUInteger)index {
@end
-CFStringRef JSValueToJSONCopy(JSContextRef context, JSValueRef value) {
+CFStringRef CYCopyJSONString(JSContextRef context, JSValueRef value) {
id object(CYCastNSObject(context, value));
return reinterpret_cast<CFStringRef>([(object == nil ? @"null" : [object cy$toJSON]) retain]);
}
JSStringRef script(JSStringCreateWithCFString(code));
CFRelease(code);
- JSValueRef result(JSEvaluateScript(JSGetContext(), script, NULL, NULL, 0, NULL));
+ JSValueRef result(JSEvaluateScript(CYGetJSContext(), script, NULL, NULL, 0, NULL));
JSStringRelease(script);
CFHTTPMessageRef response(CFHTTPMessageCreateResponse(kCFAllocatorDefault, 200, NULL, kCFHTTPVersion1_1));
CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Type"), CFSTR("application/json; charset=utf-8"));
- CFStringRef json(JSValueToJSONCopy(JSGetContext(), result));
+ CFStringRef json(CYCopyJSONString(CYGetJSContext(), result));
CFDataRef body(CFStringCreateExternalRepresentation(kCFAllocatorDefault, json, kCFStringEncodingUTF8, NULL));
CFRelease(json);
}
};
+JSObjectRef CYMakeSelector(JSContextRef context, SEL sel) {
+ selData *data(new selData(sel));
+ return JSObjectMake(context, Selector_, data);
+}
+
+JSObjectRef CYMakePointer(JSContextRef context, void *pointer) {
+ ptrData *data(new ptrData(pointer));
+ return JSObjectMake(context, Pointer_, data);
+}
+
static void Pointer_finalize(JSObjectRef object) {
ptrData *data(reinterpret_cast<ptrData *>(JSObjectGetPrivate(object)));
apr_pool_destroy(data->pool_);
return JSObjectMake(context, Functor_, data);
}
-
JSObjectRef CYMakeFunction(JSContextRef context, void *function, const char *type) {
return CYMakeFunction(context, reinterpret_cast<void (*)()>(function), type);
}
-void CYSetProperty(JSContextRef context, JSObjectRef object, const char *name, JSValueRef value) {
- JSValueRef exception(NULL);
- JSObjectSetProperty(context, object, CYJSString(name), value, kJSPropertyAttributeNone, &exception);
- CYThrow(context, exception);
-}
-
char *CYPoolCString(apr_pool_t *pool, JSStringRef value) {
size_t size(JSStringGetMaximumUTF8CStringSize(value));
char *string(new(pool) char[size]);
// XXX: this macro is unhygenic
#define CYCastCString(context, value) ({ \
- JSValueRef exception(NULL); \
- JSStringRef string(JSValueToStringCopy(context, value, &exception)); \
- CYThrow(context, exception); \
+ JSStringRef string(CYCopyJSString(context, value)); \
size_t size(JSStringGetMaximumUTF8CStringSize(string)); \
char *utf8(reinterpret_cast<char *>(alloca(size))); \
JSStringGetUTF8CString(string, utf8, size); \
CYFromFFI_(double, double)
case sig::object_P:
- case sig::typename_P: {
+ case sig::typename_P:
value = CYCastJSValue(context, *reinterpret_cast<id *>(data));
- } break;
-
- case sig::selector_P: {
- if (SEL sel = *reinterpret_cast<SEL *>(data)) {
- selData *data(new selData(sel));
- value = JSObjectMake(context, Selector_, data);
- } else goto null;
- } break;
-
- case sig::pointer_P: {
- if (void *pointer = *reinterpret_cast<void **>(data)) {
- ptrData *data(new ptrData(pointer));
- value = JSObjectMake(context, Pointer_, data);
- } else goto null;
- } break;
-
- case sig::string_P: {
+ break;
+
+ case sig::selector_P:
+ if (SEL sel = *reinterpret_cast<SEL *>(data))
+ value = CYMakeSelector(context, sel);
+ else goto null;
+ break;
+
+ case sig::pointer_P:
+ if (void *pointer = *reinterpret_cast<void **>(data))
+ value = CYMakePointer(context, pointer);
+ else goto null;
+ break;
+
+ case sig::string_P:
if (char *utf8 = *reinterpret_cast<char **>(data))
value = JSValueMakeString(context, CYJSString(utf8));
else goto null;
- } break;
+ break;
case sig::struct_P:
goto fail;
if (NSMutableArray *entry = [Bridge_ objectForKey:name])
switch ([[entry objectAtIndex:0] intValue]) {
case 0:
- return JSEvaluateScript(JSGetContext(), CYJSString([entry objectAtIndex:1]), NULL, NULL, 0, NULL);
+ return JSEvaluateScript(CYGetJSContext(), CYJSString([entry objectAtIndex:1]), NULL, NULL, 0, NULL);
case 1:
return CYMakeFunction(context, [name cy$symbol], [[entry objectAtIndex:1] UTF8String]);
case 2:
return CYCallFunction(context, count, arguments, exception, &signature, &cif, function);
}
-static JSValueRef ffi_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+static JSValueRef Selector_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+ JSValueRef setup[count + 2];
+ setup[0] = _this;
+ setup[1] = object;
+ memmove(setup + 2, arguments, sizeof(JSValueRef) * count);
+ return $objc_msgSend(context, NULL, NULL, count + 2, setup, exception);
+}
+
+static JSValueRef Functor_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
ffiData *data(reinterpret_cast<ffiData *>(JSObjectGetPrivate(object)));
return CYCallFunction(context, count, arguments, exception, &data->signature_, &data->cif_, reinterpret_cast<void (*)()>(data->value_));
}
+JSObjectRef sel(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+ @try {
+ if (count != 1)
+ @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to Selector constructor" userInfo:nil];
+ const char *name(CYCastCString(context, arguments[0]));
+ return CYMakeSelector(context, sel_registerName(name));
+ } CYCatch
+}
+
JSObjectRef ffi(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
@try {
if (count != 2)
- @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to ffi constructor" userInfo:nil];
+ @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to Functor constructor" userInfo:nil];
void *function(CYCastPointer(context, arguments[0]));
const char *type(CYCastCString(context, arguments[1]));
return CYMakeFunction(context, function, type);
return JSValueMakeNumber(context, reinterpret_cast<uintptr_t>(data->value_));
}
+JSValueRef Selector_getProperty_prototype(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
+ return Function_;
+}
+
static JSStaticValue Pointer_staticValues[2] = {
{"value", &Pointer_getProperty_value, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete},
{NULL, NULL, NULL, 0}
};
+/*static JSStaticValue Selector_staticValues[2] = {
+ {"prototype", &Selector_getProperty_prototype, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete},
+ {NULL, NULL, NULL, 0}
+};*/
+
CYDriver::CYDriver(const std::string &filename) :
+ state_(CYClear),
+ data_(NULL),
+ size_(0),
filename_(filename),
source_(NULL)
{
ScannerDestroy();
}
-extern int cydebug;
-
-void cy::parser::error(const cy::parser::location_type &loc, const std::string &msg) {
- std::cerr << loc << ": " << msg << std::endl;
-}
-
-void CYConsole(FILE *fin, FILE *fout, FILE *ferr) {
- //cydebug = 1;
-
- for (;;) { _pooled
- CYDriver driver("<stdin>");
- cy::parser parser(driver);
- if (parser.parse() != 0)
- continue;
-
- if (driver.source_ == NULL) {
- fputs("driver.source == NULL\n", fout);
- break;
- }
-
- std::ostringstream str;
- driver.source_->Part(str);
-
- JSStringRef script(JSStringCreateWithUTF8CString(str.str().c_str()));
-
- JSContextRef context(JSGetContext());
-
- JSValueRef exception(NULL);
- JSValueRef result(JSEvaluateScript(context, script, NULL, NULL, 0, &exception));
- JSStringRelease(script);
-
- if (exception != NULL)
- result = exception;
-
- if (!JSValueIsUndefined(context, result)) {
- CFStringRef json;
-
- @try { json:
- json = JSValueToJSONCopy(context, result);
- } @catch (id error) {
- CYThrow(context, error, &result);
- goto json;
- }
-
- fputs([reinterpret_cast<const NSString *>(json) UTF8String], fout);
- CFRelease(json);
-
- fputs("\n", fout);
- fflush(fout);
- }
- }
+void cy::parser::error(const cy::parser::location_type &location, const std::string &message) {
+ CYDriver::Error error;
+ error.location_ = location;
+ error.message_ = message;
+ driver.errors_.push_back(error);
}
MSInitialize { _pooled
definition = kJSClassDefinitionEmpty;
definition.className = "Functor";
definition.parentClass = Pointer_;
- definition.callAsFunction = &ffi_callAsFunction;
+ definition.callAsFunction = &Functor_callAsFunction;
Functor_ = JSClassCreate(&definition);
definition = kJSClassDefinitionEmpty;
definition.className = "Selector";
definition.parentClass = Pointer_;
+ //definition.staticValues = Selector_staticValues;
+ definition.callAsFunction = &Selector_callAsFunction;
Selector_ = JSClassCreate(&definition);
definition = kJSClassDefinitionEmpty;
JSObjectRef global(JSContextGetGlobalObject(context));
- CYSetProperty(context, global, "ffi", JSObjectMakeConstructor(context, Functor_, &ffi));
+ CYSetProperty(context, global, CYJSString("SEL"), JSObjectMakeConstructor(context, Selector_, &sel));
+ CYSetProperty(context, global, CYJSString("ffi"), JSObjectMakeConstructor(context, Functor_, &ffi));
- CYSetProperty(context, global, "objc_msgSend", JSObjectMakeFunctionWithCallback(context, CYJSString("objc_msgSend"), &$objc_msgSend));
+ CYSetProperty(context, global, CYJSString("objc_msgSend"), JSObjectMakeFunctionWithCallback(context, CYJSString("objc_msgSend"), &$objc_msgSend));
Bridge_ = [[NSMutableDictionary dictionaryWithContentsOfFile:@"/usr/lib/libcycript.plist"] retain];
message_ = JSStringCreateWithUTF8CString("message");
length_ = JSStringCreateWithUTF8CString("length");
- JSValueRef exception(NULL);
- JSValueRef value(JSObjectGetProperty(JSGetContext(), global, CYJSString("Array"), &exception));
- CYThrow(context, exception);
- Array_ = JSValueToObject(JSGetContext(), value, &exception);
- CYThrow(context, exception);
+ Array_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Array")));
+ Function_ = CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Function")));
}