#include <readline/readline.h>
#include <readline/history.h>
+#include <sys/mman.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
#include "Cycript.tab.hh"
static jmp_buf ctrlc_;
longjmp(ctrlc_, 1);
}
-int main(int argc, const char *argv[]) {
+void Run(const char *code, FILE *fout) { _pooled
+ JSStringRef script(JSStringCreateWithUTF8CString(code));
+
+ JSContextRef context(CYGetJSContext());
+
+ 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 = CYCopyJSONString(context, result);
+ } @catch (id error) {
+ CYThrow(context, error, &result);
+ goto json;
+ }
+
+ if (fout != NULL) {
+ fputs([reinterpret_cast<const NSString *>(json) UTF8String], fout);
+ fputs("\n", fout);
+ fflush(fout);
+ }
+
+ CFRelease(json);
+ }
+}
+
+void Console() {
bool bypass(false);
bool debug(false);
if (debug)
std::cout << code << std::endl;
- _pooled
+ Run(code.c_str(), fout);
+ }
- JSStringRef script(JSStringCreateWithUTF8CString(code.c_str()));
+ fputs("\n", fout);
+ fflush(fout);
+}
- JSContextRef context(CYGetJSContext());
+void *Map(const char *path, size_t *psize) {
+ int fd;
+ _syscall(fd = open(path, O_RDONLY));
- JSValueRef exception(NULL);
- JSValueRef result(JSEvaluateScript(context, script, NULL, NULL, 0, &exception));
- JSStringRelease(script);
+ struct stat stat;
+ _syscall(fstat(fd, &stat));
+ size_t size(stat.st_size);
- if (exception != NULL)
- result = exception;
+ *psize = size;
- if (JSValueIsUndefined(context, result))
- goto restart;
+ void *base;
+ _syscall(base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0));
- CFStringRef json;
+ _syscall(close(fd));
+ return base;
+}
- @try { json:
- json = CYCopyJSONString(context, result);
- } @catch (id error) {
- CYThrow(context, error, &result);
- goto json;
+int main(int argc, const char *argv[]) {
+ const char *script;
+
+ if (argc == 1)
+ script = NULL;
+ else {
+ CYSetArgs(argc - 1, argv + 1);
+ script = argv[1];
+ }
+
+ if (script == NULL || strcmp(script, "-") == 0)
+ Console();
+ else {
+ CYDriver driver(script);
+ cy::parser parser(driver);
+
+ size_t size;
+ char *start(reinterpret_cast<char *>(Map(script, &size)));
+ char *end(start + size);
+
+ if (size >= 2 && start[0] == '#' && start[1] == '!') {
+ start += 2;
+ while (start != end && *start++ != '\n');
}
- fputs([reinterpret_cast<const NSString *>(json) UTF8String], fout);
- CFRelease(json);
+ driver.data_ = start;
+ driver.size_ = end - start;
- fputs("\n", fout);
- fflush(fout);
+ if (parser.parse() != 0 || !driver.errors_.empty()) {
+ for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i)
+ std::cerr << i->location_.begin << ": " << i->message_ << std::endl;
+ } else if (driver.source_ != NULL) {
+ std::ostringstream str;
+ driver.source_->Show(str);
+ std::string code(str.str());
+ std::cout << code << std::endl;
+ Run(code.c_str(), stdout);
+ }
}
- fputs("\n", fout);
- fflush(fout);
-
return 0;
}
F method_getTypeEncoding *^{objc_method=}
F method_setImplementation ^?^{objc_method=}^?
+# this should return # or ^v ?
F objc_allocateClassPair ##*L
F objc_copyProtocolList ^@^I
F objc_duplicateClass ##*L
# MKCoordinateRegionMake
# MKCoordinateRegionMakeWithDistance
# MKCoordinateSpanMake
+
+: applicationDidFinishLaunching: v@
"[" L C return tk::OpenBracket;
"]" L C return tk::CloseBracket;
+"@class" L C return tk::AtClass;
+"@end" L C return tk::AtEnd;
"@selector" L C return tk::AtSelector;
"break" L R yylval->word_ = new CYWord("break"); return tk::Break;
bool newline_;
union {
+ bool bool_;
+
CYArgument *argument_;
CYBoolean *boolean_;
CYClause *clause_;
CYElement *element_;
CYExpression *expression_;
CYFalse *false_;
+ CYField *field_;
CYForInitialiser *for_;
CYForInInitialiser *forin_;
+ CYFunctionParameter *functionParameter_;
CYIdentifier *identifier_;
CYLiteral *literal_;
+ CYMessage *message_;
+ CYMessageParameter *messageParameter_;
CYName *name_;
CYNull *null_;
CYNumber *number_;
- CYParameter *parameter_;
CYProperty *property_;
CYSelectorPart *selector_;
CYSource *source_;
%token OpenBracket "["
%token CloseBracket "]"
+%token AtClass "@class"
%token AtSelector "@selector"
-%token AtImplementation "@implementation"
%token AtEnd "@end"
%token <word_> Break "break"
%type <clause_> CaseClause
%type <clause_> CaseClausesOpt
%type <catch_> CatchOpt
+%type <source_> ClassDeclaration
+%type <message_> ClassMessageDeclaration
+%type <message_> ClassMessageDeclarationListOpt
+%type <expression_> ClassSuperOpt
+%type <field_> ClassFieldList
%type <expression_> ConditionalExpression
%type <expression_> ConditionalExpressionNoBF
%type <expression_> ConditionalExpressionNoIn
%type <for_> ForStatementInitialiser
%type <statement_> ForInStatement
%type <forin_> ForInStatementInitialiser
-%type <parameter_> FormalParameterList
-%type <parameter_> FormalParameterList_
+%type <functionParameter_> FormalParameterList
+%type <functionParameter_> FormalParameterList_
%type <source_> FunctionBody
%type <source_> FunctionDeclaration
%type <expression_> FunctionExpression
%type <expression_> MemberExpression
%type <expression_> MemberExpression_
%type <expression_> MemberExpressionNoBF
+%type <messageParameter_> MessageParameter
+%type <messageParameter_> MessageParameters
+%type <messageParameter_> MessageParameterList
+%type <messageParameter_> MessageParameterListOpt
+%type <bool_> MessageScope
%type <expression_> MultiplicativeExpression
%type <expression_> MultiplicativeExpressionNoBF
%type <expression_> NewExpression
%type <statement_> SwitchStatement
%type <statement_> ThrowStatement
%type <statement_> TryStatement
+%type <expression_> TypeOpt
%type <expression_> UnaryExpression
%type <expression_> UnaryExpression_
%type <expression_> UnaryExpressionNoBF
;
FormalParameterList
- : Identifier FormalParameterList_ { $$ = new(driver.pool_) CYParameter($1, $2); }
+ : Identifier FormalParameterList_ { $$ = new(driver.pool_) CYFunctionParameter($1, $2); }
| { $$ = NULL; }
;
;
/* Objective-C Extensions {{{ */
+ClassSuperOpt
+ : ":" MemberExpressionNoBF { $$ = $2; }
+ | { $$ = NULL; }
+ ;
+
+ClassFieldList
+ : "{" "}" { $$ = NULL; }
+ ;
+
+MessageScope
+ : "+" { $$ = false; }
+ | "-" { $$ = true; }
+ ;
+
+TypeOpt
+ : "(" Expression ")" { $$ = $2; }
+ | { $$ = NULL; }
+ ;
+
+MessageParameter
+ : Word ":" TypeOpt Identifier { $$ = new CYMessageParameter($1, $3, $4); }
+ ;
+
+MessageParameterListOpt
+ : MessageParameterList { $$ = $1; }
+ | { $$ = NULL; }
+ ;
+
+MessageParameterList
+ : MessageParameter MessageParameterListOpt { $1->SetNext($2); $$ = $1; }
+ ;
+
+MessageParameters
+ : MessageParameterList { $$ = $1; }
+ | Word { $$ = new CYMessageParameter($1, NULL, NULL); }
+ ;
+
+ClassMessageDeclaration
+ : MessageScope TypeOpt MessageParameters "{" FunctionBody "}" { $$ = new CYMessage($1, $2, $3, $5); }
+ ;
+
+ClassMessageDeclarationListOpt
+ : ClassMessageDeclarationListOpt ClassMessageDeclaration { if ($1) { $1->SetNext($2); $$ = $1; } else $$ = $2; }
+ | { $$ = NULL; }
+ ;
+
+ClassDeclaration
+ : "@class" Identifier ClassSuperOpt ClassFieldList ClassMessageDeclarationListOpt "@end" { $$ = new CYClass($2, $3, $4, $5); }
+ ;
+
+SourceElement
+ : ClassDeclaration { $$ = $1; }
+ ;
+
VariadicCall
: "," AssignmentExpression VariadicCall { $$ = new(driver.pool_) CYArgument(NULL, $2, $3); }
| { $$ = NULL; }
;
MessageExpression
- : "[" AssignmentExpression SelectorList "]" { $$ = new(driver.pool_) CYMessage($2, $3); }
+ : "[" AssignmentExpression SelectorList "]" { $$ = new(driver.pool_) CYSend($2, $3); }
;
SelectorExpressionOpt
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <sys/mman.h>
#include <iostream>
#include <ext/stdio_filebuf.h>
CFLog(kCFLogLevelNotice, CFSTR("_trace():%u"), __LINE__); \
} while (false)
-
static JSContextRef Context_;
+static JSObjectRef System_;
static JSClassRef Functor_;
static JSClassRef Instance_;
CFSocketRef socket_;
};
-JSObjectRef CYMakeObject(JSContextRef context, id object) {
- return JSObjectMake(context, Instance_, [object retain]);
+JSObjectRef CYMakeInstance(JSContextRef context, id object) {
+ return JSObjectMake(context, Instance_, object);
+}
+
+JSValueRef CYCastJSValue(JSContextRef context, bool value) {
+ return JSValueMakeBoolean(context, value);
+}
+
+JSValueRef CYCastJSValue(JSContextRef context, double value) {
+ return JSValueMakeNumber(context, value);
+}
+
+#define CYCastJSValue_(Type_) \
+ JSValueRef CYCastJSValue(JSContextRef context, Type_ value) { \
+ return JSValueMakeNumber(context, static_cast<double>(value)); \
+ }
+
+CYCastJSValue_(int)
+CYCastJSValue_(unsigned int)
+CYCastJSValue_(long int)
+CYCastJSValue_(long unsigned int)
+CYCastJSValue_(long long int)
+CYCastJSValue_(long long unsigned int)
+
+JSValueRef CYJSUndefined(JSContextRef context) {
+ return JSValueMakeUndefined(context);
}
@interface NSMethodSignature (Cycript)
}
- (JSValueRef) cy$JSValueInContext:(JSContextRef)context {
- return CYMakeObject(context, self);
+ return CYMakeInstance(context, self);
}
@end
}
- (JSValueRef) cy$JSValueInContext:(JSContextRef)context {
- return JSValueMakeUndefined(context);
+ return CYJSUndefined(context);
}
@end
}
- (JSValueRef) cy$JSValueInContext:(JSContextRef)context {
- return [self class] != NSCFBoolean_ ? JSValueMakeNumber(context, [self doubleValue]) : JSValueMakeBoolean(context, [self boolValue]);
+ return [self class] != NSCFBoolean_ ? CYCastJSValue(context, [self doubleValue]) : CYCastJSValue(context, [self boolValue]);
}
- (void *) cy$symbol {
#define CYCatch \
@catch (id error) { \
+ NSLog(@"e:%@", error); \
CYThrow(context, error, exception); \
return NULL; \
}
void CYThrow(JSContextRef context, JSValueRef value);
-id CYCastNSObject(JSContextRef context, JSObjectRef object) {
+apr_status_t CYPoolRelease_(void *data) {
+ id object(reinterpret_cast<id>(data));
+ [object release];
+ return APR_SUCCESS;
+}
+
+id CYPoolRelease(apr_pool_t *pool, id object) {
+ if (pool == NULL)
+ return [object autorelease];
+ else {
+ apr_pool_cleanup_register(pool, object, &CYPoolRelease_, &apr_pool_cleanup_null);
+ return object;
+ }
+}
+
+id CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSObjectRef object) {
if (JSValueIsObjectOfClass(context, object, Instance_))
return reinterpret_cast<id>(JSObjectGetPrivate(object));
JSValueRef exception(NULL);
bool array(JSValueIsInstanceOfConstructor(context, object, Array_, &exception));
CYThrow(context, exception);
- if (array)
- return [[[CYJSArray alloc] initWithJSObject:object inContext:context] autorelease];
- return [[[CYJSObject alloc] initWithJSObject:object inContext:context] autorelease];
+ id value(array ? [CYJSArray alloc] : [CYJSObject alloc]);
+ return CYPoolRelease(pool, [value initWithJSObject:object inContext:context]);
}
JSStringRef CYCopyJSString(id value) {
- return JSStringCreateWithCFString(reinterpret_cast<CFStringRef>([value description]));
+ return value == NULL ? NULL : JSStringCreateWithCFString(reinterpret_cast<CFStringRef>([value description]));
}
JSStringRef CYCopyJSString(const char *value) {
- return JSStringCreateWithUTF8CString(value);
+ return value == NULL ? NULL : JSStringCreateWithUTF8CString(value);
}
JSStringRef CYCopyJSString(JSStringRef value) {
- return JSStringRetain(value);
+ return value == NULL ? NULL : JSStringRetain(value);
}
JSStringRef CYCopyJSString(JSContextRef context, JSValueRef value) {
+ if (JSValueIsNull(context, value))
+ return NULL;
JSValueRef exception(NULL);
JSStringRef string(JSValueToStringCopy(context, value, &exception));
CYThrow(context, exception);
return string;
}
-// XXX: this is not a safe handle
class CYJSString {
private:
JSStringRef string_;
+ void Clear_() {
+ JSStringRelease(string_);
+ }
+
public:
+ CYJSString(const CYJSString &rhs) :
+ string_(CYCopyJSString(rhs.string_))
+ {
+ }
+
template <typename Arg0_>
- CYJSString(Arg0_ arg0) {
- string_ = CYCopyJSString(arg0);
+ CYJSString(Arg0_ arg0) :
+ string_(CYCopyJSString(arg0))
+ {
}
template <typename Arg0_, typename Arg1_>
- CYJSString(Arg0_ arg0, Arg1_ arg1) {
- string_ = CYCopyJSString(arg0, arg1);
+ CYJSString(Arg0_ arg0, Arg1_ arg1) :
+ string_(CYCopyJSString(arg0, arg1))
+ {
+ }
+
+ CYJSString &operator =(const CYJSString &rhs) {
+ Clear_();
+ string_ = CYCopyJSString(rhs.string_);
+ return *this;
}
~CYJSString() {
- JSStringRelease(string_);
+ Clear_();
+ }
+
+ void Clear() {
+ Clear_();
+ string_ = NULL;
}
operator JSStringRef() const {
return CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &number);
}
-NSString *CYCastNSString(JSStringRef value) {
- return [reinterpret_cast<const NSString *>(CYCopyCFString(value)) autorelease];
+NSString *CYCastNSString(apr_pool_t *pool, JSStringRef value) {
+ return CYPoolRelease(pool, reinterpret_cast<const NSString *>(CYCopyCFString(value)));
+}
+
+bool CYCastBool(JSContextRef context, JSValueRef value) {
+ return JSValueToBoolean(context, value);
}
-CFTypeRef CYCopyCFType(JSContextRef context, JSValueRef value) {
+CFTypeRef CYCFType(apr_pool_t *pool, JSContextRef context, JSValueRef value, bool cast) {
+ CFTypeRef object;
+ bool copy;
+
switch (JSType type = JSValueGetType(context, value)) {
case kJSTypeUndefined:
- return CFRetain([WebUndefined undefined]);
+ object = [WebUndefined undefined];
+ copy = false;
+ break;
+
case kJSTypeNull:
- return nil;
+ return NULL;
+ break;
+
case kJSTypeBoolean:
- return CFRetain(JSValueToBoolean(context, value) ? kCFBooleanTrue : kCFBooleanFalse);
+ object = CYCastBool(context, value) ? kCFBooleanTrue : kCFBooleanFalse;
+ copy = false;
+ break;
+
case kJSTypeNumber:
- return CYCopyCFNumber(context, value);
+ object = CYCopyCFNumber(context, value);
+ copy = true;
+ break;
+
case kJSTypeString:
- return CYCopyCFString(context, value);
+ object = CYCopyCFString(context, value);
+ copy = true;
+ break;
+
case kJSTypeObject:
- return CFRetain((CFTypeRef) CYCastNSObject(context, (JSObjectRef) value));
+ // XXX: this might could be more efficient
+ object = (CFTypeRef) CYCastNSObject(pool, context, (JSObjectRef) value);
+ copy = false;
+ break;
+
default:
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"JSValueGetType() == 0x%x", type] userInfo:nil];
+ break;
}
+
+ if (cast != copy)
+ return object;
+ else if (copy)
+ return CYPoolRelease(pool, (id) object);
+ else
+ return CFRetain(object);
+}
+
+CFTypeRef CYCastCFType(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
+ return CYCFType(pool, context, value, true);
+}
+
+CFTypeRef CYCopyCFType(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
+ return CYCFType(pool, context, value, false);
}
NSArray *CYCastNSArray(JSPropertyNameArrayRef names) {
+ CYPool pool;
size_t size(JSPropertyNameArrayGetCount(names));
NSMutableArray *array([NSMutableArray arrayWithCapacity:size]);
for (size_t index(0); index != size; ++index)
- [array addObject:CYCastNSString(JSPropertyNameArrayGetNameAtIndex(names, index))];
+ [array addObject:CYCastNSString(pool, JSPropertyNameArrayGetNameAtIndex(names, index))];
return array;
}
-id CYCastNSObject(JSContextRef context, JSValueRef value) {
- const NSObject *object(reinterpret_cast<const NSObject *>(CYCopyCFType(context, value)));
- return object == nil ? nil : [object autorelease];
+id CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
+ return reinterpret_cast<const NSObject *>(CYCastCFType(pool, context, value));
}
void CYThrow(JSContextRef context, JSValueRef value) {
if (value == NULL)
return;
- @throw CYCastNSObject(context, value);
+ @throw CYCastNSObject(NULL, context, value);
+}
+
+JSValueRef CYJSNull(JSContextRef context) {
+ return JSValueMakeNull(context);
+}
+
+JSValueRef CYCastJSValue(JSContextRef context, JSStringRef value) {
+ return value == NULL ? CYJSNull(context) : JSValueMakeString(context, value);
+}
+
+JSValueRef CYCastJSValue(JSContextRef context, const char *value) {
+ return CYCastJSValue(context, CYJSString(value));
}
JSValueRef CYCastJSValue(JSContextRef context, id value) {
- return value == nil ? JSValueMakeNull(context) : [value cy$JSValueInContext:context];
+ return value == nil ? CYJSNull(context) : [value cy$JSValueInContext:context];
}
JSObjectRef CYCastJSObject(JSContextRef context, JSValueRef value) {
}
- (id) objectForKey:(id)key {
- return CYCastNSObject(context_, CYGetProperty(context_, object_, CYJSString(key)));
+ return CYCastNSObject(NULL, context_, CYGetProperty(context_, object_, CYJSString(key)));
}
- (NSEnumerator *) keyEnumerator {
JSValueRef exception(NULL);
JSValueRef value(JSObjectGetPropertyAtIndex(context_, object_, index, &exception));
CYThrow(context_, exception);
- id object(CYCastNSObject(context_, value));
+ id object(CYCastNSObject(NULL, context_, value));
return object == nil ? [NSNull null] : object;
}
@end
CFStringRef CYCopyJSONString(JSContextRef context, JSValueRef value) {
- id object(CYCastNSObject(context, value));
+ id object(CYCastNSObject(NULL, context, value));
return reinterpret_cast<CFStringRef>([(object == nil ? @"null" : [object cy$toJSON]) retain]);
}
}
}
-static JSValueRef Instance_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { _pooled
+static JSValueRef Instance_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
@try {
- NSString *name(CYCastNSString(property));
- NSLog(@"%@", name);
+ CYPool pool;
+ NSString *name(CYCastNSString(pool, property));
+ NSLog(@"get:%@", name);
return NULL;
} CYCatch
}
+static bool Instance_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) {
+ @try {
+ CYPool pool;
+ NSString *name(CYCastNSString(pool, property));
+ NSLog(@"set:%@", name);
+ return false;
+ } CYCatch
+}
+
+static bool Instance_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
+ @try {
+ CYPool pool;
+ NSString *name(CYCastNSString(pool, property));
+ NSLog(@"delete:%@", name);
+ return false;
+ } CYCatch
+}
+
typedef id jocData;
-static JSObjectRef Instance_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { _pooled
+static JSObjectRef Instance_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
@try {
id data(reinterpret_cast<jocData>(JSObjectGetPrivate(object)));
- return CYMakeObject(context, [[data alloc] autorelease]);
+ return CYMakeInstance(context, [data alloc]);
} CYCatch
}
sig::Signature signature_;
ffi_cif cif_;
- ffiData(void (*value)(), const char *type) :
+ ffiData(const char *type, void (*value)() = NULL) :
ptrData(reinterpret_cast<void *>(value))
{
sig::Parse(pool_, &signature_, type);
ptrData(value)
{
}
+
+ SEL GetValue() const {
+ return reinterpret_cast<SEL>(value_);
+ }
};
JSObjectRef CYMakeSelector(JSContextRef context, SEL sel) {
apr_pool_destroy(data->pool_);
}
-static void Instance_finalize(JSObjectRef object) {
+/*static void Instance_finalize(JSObjectRef object) {
id data(reinterpret_cast<jocData>(JSObjectGetPrivate(object)));
- [data release];
-}
+}*/
-JSObjectRef CYMakeFunction(JSContextRef context, void (*function)(), const char *type) {
- ffiData *data(new ffiData(function, type));
+JSObjectRef CYMakeFunctor(JSContextRef context, void (*function)(), const char *type) {
+ ffiData *data(new ffiData(type, function));
return JSObjectMake(context, Functor_, data);
}
-JSObjectRef CYMakeFunction(JSContextRef context, void *function, const char *type) {
- return CYMakeFunction(context, reinterpret_cast<void (*)()>(function), type);
+void Closure_(ffi_cif *cif, void *result, void **arguments, void *arg) {
+}
+
+JSObjectRef CYMakeFunctor(JSContextRef context, JSObjectRef function, const char *type) {
+ // XXX: in case of exceptions this will leak
+ ffiData *data(new ffiData(type));
+
+ ffi_closure *closure;
+ _syscall(closure = (ffi_closure *) mmap(
+ NULL, sizeof(ffi_closure),
+ PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
+ -1, 0
+ ));
+
+ ffi_status status(ffi_prep_closure(closure, &data->cif_, &Closure_, data));
+ _assert(status == FFI_OK);
+
+ _syscall(mprotect(closure, sizeof(*closure), PROT_READ | PROT_EXEC));
+
+ return JSObjectMake(context, Functor_, data);
}
char *CYPoolCString(apr_pool_t *pool, JSStringRef value) {
size_t size(JSStringGetMaximumUTF8CStringSize(value));
char *string(new(pool) char[size]);
JSStringGetUTF8CString(value, string, size);
- JSStringRelease(value);
return string;
}
char *CYPoolCString(apr_pool_t *pool, JSContextRef context, JSValueRef value) {
+ if (JSValueIsNull(context, value))
+ return NULL;
return CYPoolCString(pool, CYJSString(context, value));
}
// XXX: this macro is unhygenic
#define CYCastCString(context, value) ({ \
- JSStringRef string(CYCopyJSString(context, value)); \
- size_t size(JSStringGetMaximumUTF8CStringSize(string)); \
- char *utf8(reinterpret_cast<char *>(alloca(size))); \
- JSStringGetUTF8CString(string, utf8, size); \
- JSStringRelease(string); \
+ char *utf8; \
+ if (value == NULL) \
+ utf8 = NULL; \
+ else { \
+ JSStringRef string(CYCopyJSString(context, value)); \
+ size_t size(JSStringGetMaximumUTF8CStringSize(string)); \
+ utf8 = reinterpret_cast<char *>(alloca(size)); \
+ JSStringGetUTF8CString(string, utf8, size); \
+ JSStringRelease(string); \
+ } \
utf8; \
})
return sel_registerName(CYCastCString(context, value));
}
-void *CYCastPointer(JSContextRef context, JSValueRef value) {
+void *CYCastPointer_(JSContextRef context, JSValueRef value) {
switch (JSValueGetType(context, value)) {
case kJSTypeNull:
return NULL;
}
}
+template <typename Type_>
+_finline Type_ CYCastPointer(JSContextRef context, JSValueRef value) {
+ return reinterpret_cast<Type_>(CYCastPointer_(context, value));
+}
+
void CYPoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, void *data, JSValueRef value) {
switch (type->primitive) {
case sig::boolean_P:
case sig::object_P:
case sig::typename_P:
- *reinterpret_cast<id *>(data) = CYCastNSObject(context, value);
+ *reinterpret_cast<id *>(data) = CYCastNSObject(pool, context, value);
break;
case sig::selector_P:
break;
case sig::pointer_P:
- *reinterpret_cast<void **>(data) = CYCastPointer(context, value);
+ *reinterpret_cast<void **>(data) = CYCastPointer<void *>(context, value);
break;
case sig::string_P:
switch (type->primitive) {
case sig::boolean_P:
- value = JSValueMakeBoolean(context, *reinterpret_cast<bool *>(data));
+ value = CYCastJSValue(context, *reinterpret_cast<bool *>(data));
break;
#define CYFromFFI_(primitive, native) \
case sig::primitive ## _P: \
- value = JSValueMakeNumber(context, *reinterpret_cast<native *>(data)); \
+ value = CYCastJSValue(context, *reinterpret_cast<native *>(data)); \
break;
CYFromFFI_(uchar, unsigned char)
CYFromFFI_(double, double)
case sig::object_P:
- case sig::typename_P:
value = CYCastJSValue(context, *reinterpret_cast<id *>(data));
break;
+ case sig::typename_P:
+ value = CYMakeInstance(context, *reinterpret_cast<Class *>(data));
+ break;
+
case sig::selector_P:
if (SEL sel = *reinterpret_cast<SEL *>(data))
value = CYMakeSelector(context, sel);
case sig::string_P:
if (char *utf8 = *reinterpret_cast<char **>(data))
- value = JSValueMakeString(context, CYJSString(utf8));
+ value = CYCastJSValue(context, utf8);
else goto null;
break;
goto fail;
case sig::void_P:
- value = JSValueMakeUndefined(context);
+ value = CYJSUndefined(context);
break;
null:
- value = JSValueMakeNull(context);
+ value = CYJSNull(context);
break;
default: fail:
return value;
}
-static JSValueRef CYCallFunction(JSContextRef context, size_t count, const JSValueRef *arguments, JSValueRef *exception, sig::Signature *signature, ffi_cif *cif, void (*function)()) { _pooled
+static JSValueRef CYCallFunction(JSContextRef context, size_t count, const JSValueRef *arguments, JSValueRef *exception, sig::Signature *signature, ffi_cif *cif, void (*function)()) {
@try {
if (count != signature->count - 1)
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to ffi function" userInfo:nil];
} CYCatch
}
-static JSValueRef Global_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { _pooled
+static JSValueRef Global_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
@try {
- NSString *name(CYCastNSString(property));
+ CYPool pool;
+ NSString *name(CYCastNSString(pool, property));
if (Class _class = NSClassFromString(name))
- return CYMakeObject(context, _class);
+ return CYMakeInstance(context, _class);
if (NSMutableArray *entry = [Bridge_ objectForKey:name])
switch ([[entry objectAtIndex:0] intValue]) {
case 0:
return JSEvaluateScript(CYGetJSContext(), CYJSString([entry objectAtIndex:1]), NULL, NULL, 0, NULL);
case 1:
- return CYMakeFunction(context, [name cy$symbol], [[entry objectAtIndex:1] UTF8String]);
+ return CYMakeFunctor(context, reinterpret_cast<void (*)()>([name cy$symbol]), [[entry objectAtIndex:1] UTF8String]);
case 2:
CYPool pool;
sig::Signature signature;
);
}
-static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { _pooled
+extern "C" {
+ int *_NSGetArgc(void);
+ char ***_NSGetArgv(void);
+ int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);
+}
+
+static JSValueRef System_print(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+ @try {
+ NSLog(@"%s", CYCastCString(context, arguments[0]));
+ return CYJSUndefined(context);
+ } CYCatch
+}
+
+static JSValueRef CYApplicationMain(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+ @try {
+ CYPool pool;
+ NSString *name(CYCastNSObject(pool, context, arguments[0]));
+ int argc(*_NSGetArgc() - 1);
+ char **argv(*_NSGetArgv() + 1);
+ for (int i(0); i != argc; ++i)
+ NSLog(@"argv[%i]=%s", i, argv[i]);
+ return CYCastJSValue(context, UIApplicationMain(argc, argv, name, name));
+ } CYCatch
+}
+
+static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
const char *type;
@try {
if (count < 2)
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"too few arguments to objc_msgSend" userInfo:nil];
- id self(CYCastNSObject(context, arguments[0]));
+ CYPool pool;
+
+ id self(CYCastNSObject(pool, context, arguments[0]));
if (self == nil)
- return JSValueMakeNull(context);
+ return CYJSNull(context);
SEL _cmd(CYCastSEL(context, arguments[1]));
NSMethodSignature *method([self methodSignatureForSelector:_cmd]);
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) {
+JSObjectRef Selector_new(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];
} CYCatch
}
-JSObjectRef ffi(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+JSObjectRef Functor_new(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 Functor constructor" userInfo:nil];
- void *function(CYCastPointer(context, arguments[0]));
const char *type(CYCastCString(context, arguments[1]));
- return CYMakeFunction(context, function, type);
+ JSValueRef exception(NULL);
+ if (JSValueIsInstanceOfConstructor(context, arguments[0], Function_, &exception)) {
+ JSObjectRef function(CYCastJSObject(context, arguments[0]));
+ return CYMakeFunctor(context, function, type);
+ } else if (exception != NULL) {
+ return NULL;
+ } else {
+ void (*function)()(CYCastPointer<void (*)()>(context, arguments[0]));
+ return CYMakeFunctor(context, function, type);
+ }
} CYCatch
}
JSValueRef Pointer_getProperty_value(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
ptrData *data(reinterpret_cast<ptrData *>(JSObjectGetPrivate(object)));
- return JSValueMakeNumber(context, reinterpret_cast<uintptr_t>(data->value_));
+ return CYCastJSValue(context, reinterpret_cast<uintptr_t>(data->value_));
}
JSValueRef Selector_getProperty_prototype(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) {
return Function_;
}
+static JSValueRef Selector_callAsFunction_type(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
+ @try {
+ if (count != 2)
+ @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to Selector.type" userInfo:nil];
+ CYPool pool;
+ selData *data(reinterpret_cast<selData *>(JSObjectGetPrivate(_this)));
+ Class _class(CYCastNSObject(pool, context, arguments[0]));
+ bool instance(CYCastBool(context, arguments[1]));
+ SEL sel(data->GetValue());
+ if (Method method = (*(instance ? &class_getInstanceMethod : class_getClassMethod))(_class, sel))
+ return CYCastJSValue(context, method_getTypeEncoding(method));
+ else if (NSString *type = [Bridge_ objectForKey:[NSString stringWithFormat:@":%s", sel_getName(sel)]])
+ return CYCastJSValue(context, CYJSString(type));
+ else
+ return CYJSNull(context);
+ } CYCatch
+}
+
static JSStaticValue Pointer_staticValues[2] = {
{"value", &Pointer_getProperty_value, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete},
{NULL, NULL, NULL, 0}
{NULL, NULL, NULL, 0}
};*/
+static JSStaticFunction Selector_staticFunctions[2] = {
+ {"type", &Selector_callAsFunction_type, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+ {NULL, NULL, 0}
+};
+
CYDriver::CYDriver(const std::string &filename) :
state_(CYClear),
data_(NULL),
driver.errors_.push_back(error);
}
+void CYSetArgs(int argc, const char *argv[]) {
+ JSContextRef context(CYGetJSContext());
+ JSValueRef args[argc];
+ for (int i(0); i != argc; ++i)
+ args[i] = CYCastJSValue(context, argv[i]);
+ JSValueRef exception(NULL);
+ JSObjectRef array(JSObjectMakeArray(context, argc, args, &exception));
+ CYThrow(context, exception);
+ CYSetProperty(context, System_, CYJSString("args"), array);
+}
+
MSInitialize { _pooled
apr_initialize();
definition.className = "Selector";
definition.parentClass = Pointer_;
//definition.staticValues = Selector_staticValues;
+ definition.staticFunctions = Selector_staticFunctions;
definition.callAsFunction = &Selector_callAsFunction;
Selector_ = JSClassCreate(&definition);
definition = kJSClassDefinitionEmpty;
- definition.className = "Instance_";
+ definition.className = "Instance";
definition.getProperty = &Instance_getProperty;
+ definition.setProperty = &Instance_setProperty;
+ definition.deleteProperty = &Instance_deleteProperty;
definition.callAsConstructor = &Instance_callAsConstructor;
- definition.finalize = &Instance_finalize;
+ //definition.finalize = &Instance_finalize;
Instance_ = JSClassCreate(&definition);
definition = kJSClassDefinitionEmpty;
JSObjectRef global(JSContextGetGlobalObject(context));
- CYSetProperty(context, global, CYJSString("SEL"), JSObjectMakeConstructor(context, Selector_, &sel));
- CYSetProperty(context, global, CYJSString("ffi"), JSObjectMakeConstructor(context, Functor_, &ffi));
+ CYSetProperty(context, global, CYJSString("Selector"), JSObjectMakeConstructor(context, Selector_, &Selector_new));
+ CYSetProperty(context, global, CYJSString("Functor"), JSObjectMakeConstructor(context, Functor_, &Functor_new));
+ CYSetProperty(context, global, CYJSString("CYApplicationMain"), JSObjectMakeFunctionWithCallback(context, CYJSString("CYApplicationMain"), &CYApplicationMain));
CYSetProperty(context, global, CYJSString("objc_msgSend"), JSObjectMakeFunctionWithCallback(context, CYJSString("objc_msgSend"), &$objc_msgSend));
+ System_ = JSObjectMake(context, NULL, NULL);
+ CYSetProperty(context, global, CYJSString("system"), System_);
+ CYSetProperty(context, System_, CYJSString("args"), CYJSNull(context));
+ CYSetProperty(context, System_, CYJSString("global"), global);
+
+ CYSetProperty(context, System_, CYJSString("print"), JSObjectMakeFunctionWithCallback(context, CYJSString("print"), &System_print));
+
Bridge_ = [[NSMutableDictionary dictionaryWithContentsOfFile:@"/usr/lib/libcycript.plist"] retain];
name_ = JSStringCreateWithUTF8CString("name");
#include <iostream>
#include <iomanip>
+_finline CYFlags operator ~(CYFlags rhs) {
+ return static_cast<CYFlags>(~static_cast<unsigned>(rhs));
+}
+
+_finline CYFlags operator &(CYFlags lhs, CYFlags rhs) {
+ return static_cast<CYFlags>(static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs));
+}
+
+_finline CYFlags operator |(CYFlags lhs, CYFlags rhs) {
+ return static_cast<CYFlags>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs));
+}
+
+_finline CYFlags &operator |=(CYFlags &lhs, CYFlags rhs) {
+ return lhs = lhs | rhs;
+}
+
+_finline CYFlags CYLeft(CYFlags flags) {
+ return flags & ~CYNoTrailer;
+}
+
+_finline CYFlags CYCenter(CYFlags flags) {
+ return flags & CYNoIn;
+}
+
+_finline CYFlags CYRight(CYFlags flags) {
+ return flags & (CYNoIn | CYNoTrailer);
+}
+
+bool CYFalse::Value() const {
+ return false;
+}
+
+bool CYTrue::Value() const {
+ return true;
+}
+
#define CYPA 16
-void CYAddressOf::Output(std::ostream &out) const {
- rhs_->Output(out, 1);
+void CYAddressOf::Output(std::ostream &out, CYFlags flags) const {
+ rhs_->Output(out, 1, CYLeft(flags));
out << ".$()";
}
out << ":";
}
if (value_ != NULL)
- value_->Output(out, false);
+ value_->Output(out, CYPA, CYNoFlags);
if (next_ != NULL) {
if (next_->name_ == NULL)
out << ',';
}
}
-void CYArray::Output(std::ostream &out) const {
+void CYArray::Output(std::ostream &out, CYFlags flags) const {
out << '[';
if (elements_ != NULL)
elements_->Output(out);
out << ']';
}
-void CYAssignment::Output(std::ostream &out) const {
- lhs_->Output(out, Precedence() - 1);
+void CYAssignment::Output(std::ostream &out, CYFlags flags) const {
+ lhs_->Output(out, Precedence() - 1, CYLeft(flags));
out << Operator();
- rhs_->Output(out, Precedence());
+ rhs_->Output(out, Precedence(), CYRight(flags));
}
-void CYBoolean::Output(std::ostream &out) const {
+void CYBoolean::Output(std::ostream &out, CYFlags flags) const {
+ if ((flags & CYNoLeader) != 0)
+ out << ' ';
out << (Value() ? "true" : "false");
+ if ((flags & CYNoTrailer) != 0)
+ out << ' ';
}
void CYBreak::Output(std::ostream &out) const {
out << ';';
}
-void CYCall::Output(std::ostream &out) const {
- function_->Output(out, Precedence());
+void CYCall::Output(std::ostream &out, CYFlags flags) const {
+ function_->Output(out, Precedence(), CYLeft(flags));
out << '(';
if (arguments_ != NULL)
arguments_->Output(out);
code_->Output(out, true);
}
-void CYCondition::Output(std::ostream &out) const {
- test_->Output(out, Precedence() - 1);
+void CYClass::Output(std::ostream &out) const {
+ out << "(function($cys,$cyc,$cym,$cyn,$cyt){";
+ out << "$cyc=objc_allocateClassPair($cys,\"" << *name_ << "\",0);";
+ out << "$cym=object_getClass($cyc);";
+ if (fields_ != NULL)
+ fields_->Output(out);
+ if (messages_ != NULL)
+ messages_->Output(out);
+ out << "objc_registerClassPair($cyc);";
+ out << "})(";
+ if (super_ != NULL)
+ super_->Output(out, CYPA, CYNoFlags);
+ else
+ out << "null";
+ out << ");";
+}
+
+void CYCondition::Output(std::ostream &out, CYFlags flags) const {
+ test_->Output(out, Precedence() - 1, CYLeft(flags));
out << '?';
if (true_ != NULL)
- true_->Output(out, CYPA);
+ true_->Output(out, CYPA, CYNoFlags);
out << ':';
- false_->Output(out, CYPA);
+ false_->Output(out, CYPA, CYRight(flags));
}
void CYContinue::Output(std::ostream &out) const {
void CYClause::Output(std::ostream &out) const {
if (case_ != NULL) {
out << "case";
- case_->Output(out);
+ case_->Output(out, CYNoFlags);
} else
out << "default";
out << ':';
out << *next_;
}
+// XXX: deal with NoIn
void CYDeclaration::Part(std::ostream &out) const {
out << "var ";
Output(out);
out << *identifier_;
if (initialiser_ != NULL) {
out << '=';
- initialiser_->Output(out, CYPA);
+ initialiser_->Output(out, CYPA, CYNoFlags);
}
}
+// XXX: deal with NoIn
void CYDeclarations::Part(std::ostream &out) const {
out << "var ";
}
void CYDoWhile::Output(std::ostream &out) const {
+ // XXX: extra space character!
out << "do ";
code_->Output(out, false);
out << "while(";
- test_->Output(out);
- out << ';';
+ test_->Output(out, CYNoFlags);
+ out << ')';
}
void CYElement::Output(std::ostream &out) const {
if (value_ != NULL)
- value_->Output(out, CYPA);
+ value_->Output(out, CYPA, CYNoFlags);
if (next_ != NULL || value_ == NULL)
out << ',';
if (next_ != NULL)
}
void CYExpress::Output(std::ostream &out) const {
- expression_->Output(out);
+ expression_->Output(out, CYNoFunction | CYNoBrace);
out << ';';
}
void CYExpression::Part(std::ostream &out) const {
- // XXX: this should notice "in" expressions
// XXX: this should handle LeftHandSideExpression
- Output(out);
+ Output(out, CYNoIn);
}
-void CYCompound::Output(std::ostream &out) const {
+void CYCompound::Output(std::ostream &out, CYFlags flags) const {
if (CYExpression *expression = expressions_)
- for (;;) {
- expression->Output(out);
- expression = expression->next_;
- if (expression == NULL)
- break;
- out << ',';
+ if (CYExpression *next = expression->next_)
+ expression->Output(out, flags);
+ else {
+ expression->Output(out, CYLeft(flags));
+ CYFlags center(CYCenter(flags));
+ while (next != NULL) {
+ out << ',';
+ next = expression->next_;
+ CYFlags right(next != NULL ? center : CYRight(flags));
+ expression->Output(out, right);
+ }
}
}
-void CYExpression::Output(std::ostream &out, unsigned precedence) const {
- bool protect(precedence < Precedence());
- if (protect)
+void CYExpression::Output(std::ostream &out, unsigned precedence, CYFlags flags) const {
+ if (precedence < Precedence()) {
out << '(';
- Output(out);
- if (protect)
+ Output(out, CYNoFlags);
out << ')';
+ } else
+ Output(out, flags);
+}
+
+void CYField::Output(std::ostream &out) const {
+ // XXX: implement!
}
void CYFor::Output(std::ostream &out) const {
initialiser_->Part(out);
out << ';';
if (test_ != NULL)
- test_->Output(out);
+ test_->Output(out, CYNoFlags);
out << ';';
if (increment_ != NULL)
- increment_->Output(out);
+ increment_->Output(out, CYNoFlags);
out << ')';
code_->Output(out, false);
}
void CYForIn::Output(std::ostream &out) const {
out << "for(";
initialiser_->Part(out);
- out << " in ";
- set_->Output(out);
+ // XXX: deal with this space character!
+ out << ' ';
+ out << "in";
+ set_->Output(out, CYNoLeader);
out << ')';
code_->Output(out, false);
}
void CYFunction::Output(std::ostream &out) const {
- CYLambda::Output(out);
+ CYLambda::Output(out, CYNoFlags);
+}
+
+void CYFunctionParameter::Output(std::ostream &out) const {
+ out << *name_;
+ if (next_ != NULL) {
+ out << ',';
+ out << *next_;
+ }
}
void CYIf::Output(std::ostream &out) const {
out << "if(";
- test_->Output(out);
+ test_->Output(out, CYNoFlags);
out << ')';
true_->Output(out, true);
if (false_ != NULL) {
}
}
-void CYIndirect::Output(std::ostream &out) const {
- rhs_->Output(out, 1);
+void CYIndirect::Output(std::ostream &out, CYFlags flags) const {
+ rhs_->Output(out, 1, CYLeft(flags));
out << "[0]";
}
-void CYInfix::Output(std::ostream &out) const {
- lhs_->Output(out, Precedence());
- out << Operator();
- rhs_->Output(out, Precedence() - 1);
+void CYInfix::Output(std::ostream &out, CYFlags flags) const {
+ const char *name(Operator());
+ bool protect((flags & CYNoIn) != 0 && strcmp(name, "in"));
+ if (protect)
+ out << '(';
+ bool alphabetic(Alphabetic());
+ CYFlags left(protect ? CYNoFlags : CYLeft(flags));
+ if (alphabetic)
+ left |= CYNoTrailer;
+ lhs_->Output(out, Precedence(), left);
+ out << name;
+ CYFlags right(protect ? CYNoFlags : CYRight(flags));
+ if (alphabetic)
+ right |= CYNoLeader;
+ rhs_->Output(out, Precedence() - 1, right);
+ if (protect)
+ out << ')';
}
-void CYLambda::Output(std::ostream &out) const {
+void CYLambda::Output(std::ostream &out, CYFlags flags) const {
+ bool protect((flags & CYNoFunction) != 0);
+ if (protect)
+ out << '(';
out << "function";
if (name_ != NULL)
out << ' ' << *name_;
out << '(';
if (parameters_ != NULL)
out << *parameters_;
- out << ')';
- body_->Output(out, true);
+ out << "){";
+ if (body_ != NULL)
+ body_->Show(out);
+ out << '}';
+ if (protect)
+ out << ')';
}
-void CYMember::Output(std::ostream &out) const {
- object_->Output(out, Precedence());
+void CYMember::Output(std::ostream &out, CYFlags flags) const {
+ object_->Output(out, Precedence(), CYLeft(flags));
if (const char *word = property_->Word())
out << '.' << word;
else {
out << '[';
- property_->Output(out);
+ property_->Output(out, CYNoFlags);
out << ']';
}
}
void CYMessage::Output(std::ostream &out) const {
- out << "objc_msgSend(";
- self_->Output(out, CYPA);
- out << ",\"";
- for (CYArgument *argument(arguments_); argument != NULL; argument = argument->next_)
- if (argument->name_ != NULL) {
- out << *argument->name_;
- if (argument->value_ != NULL)
+ out << "$cyn=new Selector(\"";
+ for (CYMessageParameter *parameter(parameter_); parameter != NULL; parameter = parameter->next_)
+ if (parameter->tag_ != NULL) {
+ out << *parameter->tag_;
+ if (parameter->name_ != NULL)
out << ':';
}
- out << "\"";
- for (CYArgument *argument(arguments_); argument != NULL; argument = argument->next_)
- if (argument->value_ != NULL) {
- out << ",";
- argument->value_->Output(out, CYPA);
+ out << "\");";
+ out << "$cyt=$cyn.type($cys," << (instance_ ? "true" : "false") << ");";
+ out << "class_addMethod($cy" << (instance_ ? 'c' : 'm') << ",$cyn,";
+ out << "new Functor(function(";
+ bool comma(false);
+ for (CYMessageParameter *parameter(parameter_); parameter != NULL; parameter = parameter->next_)
+ if (parameter->name_ != NULL) {
+ if (comma)
+ out << ',';
+ else
+ comma = true;
+ out << *parameter->name_;
}
- out << ')';
+ out << "){";
+ if (body_ != NULL)
+ body_->Show(out);
+ out << "},$cyt),$cyt);";
}
-void CYNew::Output(std::ostream &out) const {
+void CYNew::Output(std::ostream &out, CYFlags flags) const {
out << "new";
- // XXX: I don't /always/ need this character
- out << ' ';
- constructor_->Output(out, Precedence());
+ constructor_->Output(out, Precedence(), CYCenter(flags) | CYNoLeader);
out << '(';
if (arguments_ != NULL)
arguments_->Output(out);
out << ')';
}
-void CYNull::Output(std::ostream &out) const {
+void CYNull::Output(std::ostream &out, CYFlags flags) const {
+ if ((flags & CYNoLeader) != 0)
+ out << ' ';
CYWord::Output(out);
+ if ((flags & CYNoTrailer) != 0)
+ out << ' ';
}
-void CYNumber::Output(std::ostream &out) const {
+void CYNumber::Output(std::ostream &out, CYFlags flags) const {
+ if ((flags & CYNoLeader) != 0)
+ out << ' ';
// XXX: this is not a useful formatting
out << Value();
+ if ((flags & CYNoTrailer) != 0)
+ out << ' ';
}
-void CYObject::Output(std::ostream &out) const {
+void CYObject::Output(std::ostream &out, CYFlags flags) const {
+ bool protect((flags & CYNoBrace) != 0);
+ if (protect)
+ out << '(';
out << '{';
if (property_ != NULL)
property_->Output(out);
out << '}';
+ if (protect)
+ out << ')';
}
-void CYParameter::Output(std::ostream &out) const {
- out << *name_;
- if (next_ != NULL) {
- out << ',';
- out << *next_;
- }
-}
-
-void CYPostfix::Output(std::ostream &out) const {
- lhs_->Output(out, Precedence());
+void CYPostfix::Output(std::ostream &out, CYFlags flags) const {
+ lhs_->Output(out, Precedence(), CYLeft(flags));
out << Operator();
}
-void CYPrefix::Output(std::ostream &out) const {
+void CYPrefix::Output(std::ostream &out, CYFlags flags) const {
+ bool alphabetic(Alphabetic());
out << Operator();
- rhs_->Output(out, Precedence());
+ CYFlags right(CYRight(flags));
+ if (alphabetic)
+ right |= CYNoLeader;
+ rhs_->Output(out, Precedence(), right);
}
void CYProperty::Output(std::ostream &out) const {
out << *name_ << ':';
- value_->Output(out, CYPA);
+ value_->Output(out, CYPA, CYNoFlags);
if (next_ != NULL) {
out << ',';
next_->Output(out);
void CYReturn::Output(std::ostream &out) const {
out << "return";
- if (value_ != NULL) {
- out << ' ';
- value_->Output(out);
- }
+ if (value_ != NULL)
+ value_->Output(out, CYNoLeader);
out << ';';
}
-void CYSelector::Output(std::ostream &out) const {
- out << "new SEL(\"";
+void CYSelector::Output(std::ostream &out, CYFlags flags) const {
+ out << "new Selector(\"";
if (name_ != NULL)
name_->Output(out);
out << "\")";
next_->Output(out);
}
+void CYSend::Output(std::ostream &out, CYFlags flags) const {
+ out << "objc_msgSend(";
+ self_->Output(out, CYPA, CYNoFlags);
+ out << ",\"";
+ for (CYArgument *argument(arguments_); argument != NULL; argument = argument->next_)
+ if (argument->name_ != NULL) {
+ out << *argument->name_;
+ if (argument->value_ != NULL)
+ out << ':';
+ }
+ out << "\"";
+ for (CYArgument *argument(arguments_); argument != NULL; argument = argument->next_)
+ if (argument->value_ != NULL) {
+ out << ",";
+ argument->value_->Output(out, CYPA, CYNoFlags);
+ }
+ out << ')';
+}
+
void CYSource::Show(std::ostream &out) const {
for (const CYSource *next(this); next != NULL; next = next->next_)
- next->Output(out, false);
+ next->Output(out);
}
void CYSource::Output(std::ostream &out, bool block) const {
}
}
-void CYString::Output(std::ostream &out) const {
+void CYString::Output(std::ostream &out, CYFlags flags) const {
out << '\"';
for (const char *value(value_), *end(value_ + size_); value != end; ++value)
switch (*value) {
void CYSwitch::Output(std::ostream &out) const {
out << "switch(";
- value_->Output(out);
+ value_->Output(out, CYNoFlags);
out << "){";
if (clauses_ != NULL)
out << *clauses_;
out << '}';
}
-void CYThis::Output(std::ostream &out) const {
+void CYThis::Output(std::ostream &out, CYFlags flags) const {
+ if ((flags & CYNoLeader) != 0)
+ out << ' ';
CYWord::Output(out);
+ if ((flags & CYNoTrailer) != 0)
+ out << ' ';
}
void CYThrow::Output(std::ostream &out) const {
out << "throw";
- if (value_ != NULL) {
- out << ' ';
- value_->Output(out);
- }
+ if (value_ != NULL)
+ value_->Output(out, CYNoLeader);
out << ';';
}
}
}
-void CYVariable::Output(std::ostream &out) const {
+void CYVariable::Output(std::ostream &out, CYFlags flags) const {
+ bool protect((flags & CYNoLeader) != 0);
+ if (protect)
+ out << '(';
out << *name_;
+ if (protect)
+ out << ')';
}
void CYWhile::Output(std::ostream &out) const {
out << "while(";
- test_->Output(out);
+ test_->Output(out, CYNoFlags);
out << ')';
code_->Output(out, false);
}
void CYWith::Output(std::ostream &out) const {
out << "with(";
- scope_->Output(out);
+ scope_->Output(out, CYNoFlags);
out << ')';
code_->Output(out, false);
}
{
};
+enum CYFlags {
+ CYNoFlags,
+ CYNoBrace,
+ CYNoFunction,
+ CYNoLeader,
+ CYNoTrailer,
+ CYNoIn
+};
+
struct CYExpression :
CYNext<CYExpression>,
CYForInitialiser,
{
virtual unsigned Precedence() const = 0;
virtual void Part(std::ostream &out) const;
- virtual void Output(std::ostream &out) const = 0;
- void Output(std::ostream &out, unsigned precedence) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const = 0;
+ void Output(std::ostream &out, unsigned precedence, CYFlags flags) const;
virtual const char *Word() const {
return NULL;
}
};
+#define CYAlphabetic(value) \
+ virtual bool Alphabetic() const { \
+ return value; \
+ }
+
#define CYPrecedence(value) \
virtual unsigned Precedence() const { \
return value; \
CYPrecedence(17)
- void Output(std::ostream &out) const;
+ void Output(std::ostream &out, CYFlags flags) const;
};
struct CYLiteral :
CYPrecedence(1)
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYRange {
return Value();
}
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out) const {
+ return Output(out, CYNoFlags);
+ }
+
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYNumber :
throw;
}
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out) const {
+ return Output(out, CYNoFlags);
+ }
+
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYNull :
{
}
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYThis :
CYPrecedence(0)
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYBoolean :
CYLiteral
{
virtual bool Value() const = 0;
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYFalse :
{
}
- virtual bool Value() const {
- return false;
- }
+ virtual bool Value() const;
};
struct CYTrue :
{
}
- virtual bool Value() const {
- return true;
- }
+ virtual bool Value() const;
};
struct CYVariable :
CYPrecedence(0)
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYPrefix :
{
}
+ virtual bool Alphabetic() const = 0;
virtual const char *Operator() const = 0;
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYInfix :
{
}
+ virtual bool Alphabetic() const = 0;
virtual const char *Operator() const = 0;
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYPostfix :
virtual const char *Operator() const = 0;
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYAssignment :
virtual const char *Operator() const = 0;
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYArgument :
{
}
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYDeclaration :
virtual void Output(std::ostream &out) const;
};
-struct CYParameter :
- CYNext<CYParameter>,
+struct CYField :
+ CYNext<CYField>
+{
+ virtual void Output(std::ostream &out) const;
+};
+
+struct CYMessageParameter :
+ CYNext<CYMessageParameter>
+{
+ CYWord *tag_;
+ CYExpression *type_;
+ CYIdentifier *name_;
+
+ CYMessageParameter(CYWord *tag, CYExpression *type, CYIdentifier *name) :
+ tag_(tag),
+ type_(type),
+ name_(name)
+ {
+ }
+};
+
+struct CYMessage :
+ CYSource
+{
+ bool instance_;
+ CYExpression *type_;
+ CYMessageParameter *parameter_;
+ CYSource *body_;
+
+ CYMessage(bool instance, CYExpression *type, CYMessageParameter *parameter, CYSource *body) :
+ instance_(instance),
+ type_(type),
+ parameter_(parameter),
+ body_(body)
+ {
+ }
+
+ virtual void Output(std::ostream &out) const;
+};
+
+struct CYClass :
+ CYSource
+{
+ CYIdentifier *name_;
+ CYExpression *super_;
+ CYField *fields_;
+ CYMessage *messages_;
+
+ CYClass(CYIdentifier *name, CYExpression *super, CYField *fields, CYMessage *messages) :
+ name_(name),
+ super_(super),
+ fields_(fields),
+ messages_(messages)
+ {
+ }
+
+ virtual void Output(std::ostream &out) const;
+};
+
+struct CYFunctionParameter :
+ CYNext<CYFunctionParameter>,
CYThing
{
CYIdentifier *name_;
- CYParameter(CYIdentifier *name, CYParameter *next) :
- CYNext<CYParameter>(next),
+ CYFunctionParameter(CYIdentifier *name, CYFunctionParameter *next) :
+ CYNext<CYFunctionParameter>(next),
name_(name)
{
}
{
}
- void Output(std::ostream &out) const;
+ void Output(std::ostream &out, CYFlags flags) const;
};
struct CYCatch :
virtual void Output(std::ostream &out) const;
};
-struct CYMessage :
+struct CYSend :
CYExpression
{
CYExpression *self_;
CYArgument *arguments_;
- CYMessage(CYExpression *self, CYArgument *arguments) :
+ CYSend(CYExpression *self, CYArgument *arguments) :
self_(self),
arguments_(arguments)
{
CYPrecedence(0)
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYMember :
CYPrecedence(1)
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYNew :
CYPrecedence(1)
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYCall :
CYPrecedence(2)
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYIf :
CYExpression
{
CYIdentifier *name_;
- CYParameter *parameters_;
+ CYFunctionParameter *parameters_;
CYSource *body_;
- CYLambda(CYIdentifier *name, CYParameter *parameters, CYSource *body) :
+ CYLambda(CYIdentifier *name, CYFunctionParameter *parameters, CYSource *body) :
name_(name),
parameters_(parameters),
body_(body)
CYPrecedence(0)
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYFunction :
CYLambda,
CYSource
{
- CYFunction(CYIdentifier *name, CYParameter *parameters, CYSource *body) :
+ CYFunction(CYIdentifier *name, CYFunctionParameter *parameters, CYSource *body) :
CYLambda(name, parameters, body)
{
}
CYPrecedence(15)
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYAddressOf :
return "&";
}
+ CYAlphabetic(false)
CYPrecedence(2)
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
struct CYIndirect :
return "*";
}
+ CYAlphabetic(false)
CYPrecedence(1)
- virtual void Output(std::ostream &out) const;
+ virtual void Output(std::ostream &out, CYFlags flags) const;
};
#define CYPostfix_(op, name) \
} \
};
-#define CYPrefix_(op, name) \
+#define CYPrefix_(alphabetic, op, name) \
struct CY ## name : \
CYPrefix \
{ \
{ \
} \
\
+ CYAlphabetic(alphabetic) \
CYPrecedence(4) \
\
virtual const char *Operator() const { \
} \
};
-#define CYInfix_(precedence, op, name) \
+#define CYInfix_(alphabetic, precedence, op, name) \
struct CY ## name : \
CYInfix \
{ \
{ \
} \
\
+ CYAlphabetic(alphabetic) \
CYPrecedence(precedence) \
\
virtual const char *Operator() const { \
CYPostfix_("++", PostIncrement)
CYPostfix_("--", PostDecrement)
-CYPrefix_("delete", Delete)
-CYPrefix_("void", Void)
-CYPrefix_("typeof", TypeOf)
-CYPrefix_("++", PreIncrement)
-CYPrefix_("--", PreDecrement)
-CYPrefix_("-", Negate)
-CYPrefix_("~", BitwiseNot)
-CYPrefix_("!", LogicalNot)
-
-CYInfix_(5, "*", Multiply)
-CYInfix_(5, "/", Divide)
-CYInfix_(5, "%", Modulus)
-CYInfix_(6, "+", Add)
-CYInfix_(6, "-", Subtract)
-CYInfix_(7, "<<", ShiftLeft)
-CYInfix_(7, ">>", ShiftRightSigned)
-CYInfix_(7, ">>>", ShiftRightUnsigned)
-CYInfix_(8, "<", Less)
-CYInfix_(8, ">", Greater)
-CYInfix_(8, "<=", LessOrEqual)
-CYInfix_(8, ">=", GreaterOrEqual)
-CYInfix_(8, "instanceof", InstanceOf)
-CYInfix_(8, "in", In)
-CYInfix_(9, "==", Equal)
-CYInfix_(9, "!=", NotEqual)
-CYInfix_(9, "===", Identical)
-CYInfix_(9, "!==", NotIdentical)
-CYInfix_(10, "&", BitwiseAnd)
-CYInfix_(11, "^", BitwiseXOr)
-CYInfix_(12, "|", BitwiseOr)
-CYInfix_(13, "&&", LogicalAnd)
-CYInfix_(14, "||", LogicalOr)
+CYPrefix_(true, "delete", Delete)
+CYPrefix_(true, "void", Void)
+CYPrefix_(true, "typeof", TypeOf)
+CYPrefix_(false, "++", PreIncrement)
+CYPrefix_(false, "--", PreDecrement)
+CYPrefix_(false, "-", Negate)
+CYPrefix_(false, "~", BitwiseNot)
+CYPrefix_(false, "!", LogicalNot)
+
+CYInfix_(false, 5, "*", Multiply)
+CYInfix_(false, 5, "/", Divide)
+CYInfix_(false, 5, "%", Modulus)
+CYInfix_(false, 6, "+", Add)
+CYInfix_(false, 6, "-", Subtract)
+CYInfix_(false, 7, "<<", ShiftLeft)
+CYInfix_(false, 7, ">>", ShiftRightSigned)
+CYInfix_(false, 7, ">>>", ShiftRightUnsigned)
+CYInfix_(false, 8, "<", Less)
+CYInfix_(false, 8, ">", Greater)
+CYInfix_(false, 8, "<=", LessOrEqual)
+CYInfix_(false, 8, ">=", GreaterOrEqual)
+CYInfix_(true, 8, "instanceof", InstanceOf)
+CYInfix_(true, 8, "in", In)
+CYInfix_(false, 9, "==", Equal)
+CYInfix_(false, 9, "!=", NotEqual)
+CYInfix_(false, 9, "===", Identical)
+CYInfix_(false, 9, "!==", NotIdentical)
+CYInfix_(false, 10, "&", BitwiseAnd)
+CYInfix_(false, 11, "^", BitwiseXOr)
+CYInfix_(false, 12, "|", BitwiseOr)
+CYInfix_(false, 13, "&&", LogicalAnd)
+CYInfix_(false, 14, "||", LogicalOr)
CYAssignment_("=", )
CYAssignment_("*=", Multiply)
#include <Foundation/Foundation.h>
#endif
-#include <JavaScriptCore/JSBase.h>
-#include <JavaScriptCore/JSValueRef.h>
-#include <JavaScriptCore/JSObjectRef.h>
-#include <JavaScriptCore/JSContextRef.h>
-#include <JavaScriptCore/JSStringRef.h>
+#include <JavaScriptCore/JavaScript.h>
#include <JavaScriptCore/JSStringRefCF.h>
JSContextRef CYGetJSContext();
CFStringRef CYCopyJSONString(JSContextRef context, JSValueRef value);
+void CYSetArgs(int argc, const char *argv[]);
#ifdef __OBJC__
void CYThrow(JSContextRef context, id error, JSValueRef *exception);
http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html
- http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
- http://www.webweavertech.com/ovidiu/Objective-C/objc-features_3.html
+http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
+http://www.webweavertech.com/ovidiu/Objective-C/objc-features_3.html
+
+http://www.mail-archive.com/es-discuss@mozilla.org/msg00999.html
+http://www.mail-archive.com/es-discuss@mozilla.org/msg01025.html
rm -f *.o libcycript.dylib cycript libcycript.plist Struct.hpp lex.cy.c Cycript.tab.cc Cycript.tab.hh location.hh position.hh stack.hh
libcycript.plist: Bridge.def
- sed -e 's/^C/0/;s/^F/1/;s/^V/2/' Bridge.def | while read -r line; do \
- if [[ $$line == '' ]]; then \
- continue; \
- fi; \
- set $$line; \
- if [[ $$1 =~ [#fl] ]]; then \
- continue; \
- fi; \
- echo "$$2 = ($$1, \"$$3\");"; \
- done >$@
+ { \
+ sed -e 's/^C/0/;s/^F/1/;s/^V/2/' Bridge.def | while read -r line; do \
+ if [[ $$line == '' ]]; then \
+ continue; \
+ fi; \
+ set $$line; \
+ if [[ $$1 =~ [#fl:] ]]; then \
+ continue; \
+ fi; \
+ echo "$$2 = ($$1, \"$$3\");"; \
+ done; \
+ grep ^: Bridge.def | sed -e 's/^: \([^ ]*\) \(.*\)/":\1" = "\2";/'; \
+ } >$@
Cycript.tab.cc Cycript.tab.hh location.hh position.hh: Cycript.y
bison -v --report=state $<
$(target)g++ $(flags) -c -o $@ $<
libcycript.dylib: ffi_type.o parse.o Output.o Cycript.tab.o lex.cy.o Library.o
- $(target)g++ $(flags) -dynamiclib -o $@ $(filter %.o,$^) -lobjc -framework CFNetwork -framework JavaScriptCore -framework WebCore -install_name /usr/lib/libcycript.dylib -framework CoreFoundation -framework Foundation -L$(menes)/mobilesubstrate -lsubstrate -lapr-1 -lffi
+ $(target)g++ $(flags) -dynamiclib -o $@ $(filter %.o,$^) -lobjc -framework CFNetwork -framework JavaScriptCore -framework WebCore -install_name /usr/lib/libcycript.dylib -framework CoreFoundation -framework Foundation -L$(menes)/mobilesubstrate -lsubstrate -lapr-1 -lffi -framework UIKit
ldid -S $@
cycript: Application.o libcycript.dylib
test: package
dpkg -i $(shell grep ^Package: control | cut -d ' ' -f 2-)_$(shell grep ^Version: control | cut -d ' ' -f 2)_iphoneos-arm.deb
- cycript
+ cycript /Applications/HelloCycript.app/HelloCycript
.PHONY: all clean extra package