From b09da87b6557610325d46e3294ea0b6aba69ebf0 Mon Sep 17 00:00:00 2001
From: "Jay Freeman (saurik)" <saurik@saurik.com>
Date: Thu, 8 Oct 2009 00:50:58 +0000
Subject: [PATCH] Drastic improvements to memory management, handle many more
 minimization corner cases via CYFlags (like NoIn), added support for @class,
 implemented Selector.type, and support execution of script files.

---
 Application.mm | 118 +++++++++++---
 Bridge.def     |   3 +
 Cycript.l      |   2 +
 Cycript.y      |  82 +++++++++-
 Library.mm     | 415 +++++++++++++++++++++++++++++++++++++++----------
 Output.cpp     | 341 ++++++++++++++++++++++++++++------------
 Parser.hpp     | 229 ++++++++++++++++++---------
 cycript.hpp    |   7 +-
 documents.txt  |   7 +-
 makefile       |  27 ++--
 10 files changed, 925 insertions(+), 306 deletions(-)

diff --git a/Application.mm b/Application.mm
index 7b58023..aaf1d5e 100644
--- a/Application.mm
+++ b/Application.mm
@@ -11,6 +11,15 @@
 #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_;
@@ -19,7 +28,39 @@ void sigint(int) {
     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);
 
@@ -114,40 +155,69 @@ int main(int argc, const char *argv[]) {
         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;
 }
diff --git a/Bridge.def b/Bridge.def
index 26870d7..cea2284 100644
--- a/Bridge.def
+++ b/Bridge.def
@@ -49,6 +49,7 @@ F method_getReturnType v^{objc_method=}^cL
 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
@@ -505,3 +506,5 @@ C MKPinAnnotationColorPurple 2
 # MKCoordinateRegionMake
 # MKCoordinateRegionMakeWithDistance
 # MKCoordinateSpanMake
+
+: applicationDidFinishLaunching: v@
diff --git a/Cycript.l b/Cycript.l
index b1ff59a..43c9285 100644
--- a/Cycript.l
+++ b/Cycript.l
@@ -119,6 +119,8 @@ Escape   \\[\\'"bfnrtv]|\\0|\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}
 "["    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;
diff --git a/Cycript.y b/Cycript.y
index 4b90f42..e51a0ec 100644
--- a/Cycript.y
+++ b/Cycript.y
@@ -11,6 +11,8 @@ typedef struct {
     bool newline_;
 
     union {
+        bool bool_;
+
         CYArgument *argument_;
         CYBoolean *boolean_;
         CYClause *clause_;
@@ -21,14 +23,17 @@ typedef struct {
         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_;
@@ -120,8 +125,8 @@ int cylex(YYSTYPE *lvalp, cy::location *llocp, void *scanner);
 %token OpenBracket "["
 %token CloseBracket "]"
 
+%token AtClass "@class"
 %token AtSelector "@selector"
-%token AtImplementation "@implementation"
 %token AtEnd "@end"
 
 %token <word_> Break "break"
@@ -217,6 +222,11 @@ int cylex(YYSTYPE *lvalp, cy::location *llocp, void *scanner);
 %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
@@ -245,8 +255,8 @@ int cylex(YYSTYPE *lvalp, cy::location *llocp, void *scanner);
 %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
@@ -271,6 +281,11 @@ int cylex(YYSTYPE *lvalp, cy::location *llocp, void *scanner);
 %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
@@ -305,6 +320,7 @@ int cylex(YYSTYPE *lvalp, cy::location *llocp, void *scanner);
 %type <statement_> SwitchStatement
 %type <statement_> ThrowStatement
 %type <statement_> TryStatement
+%type <expression_> TypeOpt
 %type <expression_> UnaryExpression
 %type <expression_> UnaryExpression_
 %type <expression_> UnaryExpressionNoBF
@@ -1103,7 +1119,7 @@ FormalParameterList_
     ;
 
 FormalParameterList
-    : Identifier FormalParameterList_ { $$ = new(driver.pool_) CYParameter($1, $2); }
+    : Identifier FormalParameterList_ { $$ = new(driver.pool_) CYFunctionParameter($1, $2); }
     | { $$ = NULL; }
     ;
 
@@ -1126,6 +1142,60 @@ SourceElement
     ;
 
 /* 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; }
@@ -1146,7 +1216,7 @@ SelectorList
     ;
 
 MessageExpression
-    : "[" AssignmentExpression SelectorList "]" { $$ = new(driver.pool_) CYMessage($2, $3); }
+    : "[" AssignmentExpression SelectorList "]" { $$ = new(driver.pool_) CYSend($2, $3); }
     ;
 
 SelectorExpressionOpt
diff --git a/Library.mm b/Library.mm
index 0dceaea..574d944 100644
--- a/Library.mm
+++ b/Library.mm
@@ -60,6 +60,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <sys/mman.h>
 
 #include <iostream>
 #include <ext/stdio_filebuf.h>
@@ -81,8 +82,8 @@
     CFLog(kCFLogLevelNotice, CFSTR("_trace():%u"), __LINE__); \
 } while (false)
 
-
 static JSContextRef Context_;
+static JSObjectRef System_;
 
 static JSClassRef Functor_;
 static JSClassRef Instance_;
@@ -105,8 +106,32 @@ struct Client {
     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)
@@ -138,7 +163,7 @@ JSObjectRef CYMakeObject(JSContextRef context, id object) {
 }
 
 - (JSValueRef) cy$JSValueInContext:(JSContextRef)context {
-    return CYMakeObject(context, self);
+    return CYMakeInstance(context, self);
 }
 
 @end
@@ -154,7 +179,7 @@ JSObjectRef CYMakeObject(JSContextRef context, id object) {
 }
 
 - (JSValueRef) cy$JSValueInContext:(JSContextRef)context {
-    return JSValueMakeUndefined(context);
+    return CYJSUndefined(context);
 }
 
 @end
@@ -216,7 +241,7 @@ JSObjectRef CYMakeObject(JSContextRef context, id object) {
 }
 
 - (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 {
@@ -284,60 +309,98 @@ JSContextRef CYGetJSContext() {
 
 #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 {
@@ -365,50 +428,103 @@ CFNumberRef CYCopyCFNumber(JSContextRef context, JSValueRef value) {
     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) {
@@ -452,7 +568,7 @@ void CYThrow(JSContextRef context, id error, JSValueRef *exception) {
 }
 
 - (id) objectForKey:(id)key {
-    return CYCastNSObject(context_, CYGetProperty(context_, object_, CYJSString(key)));
+    return CYCastNSObject(NULL, context_, CYGetProperty(context_, object_, CYJSString(key)));
 }
 
 - (NSEnumerator *) keyEnumerator {
@@ -492,14 +608,14 @@ void CYThrow(JSContextRef context, id error, JSValueRef *exception) {
     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]);
 }
 
@@ -576,20 +692,39 @@ static void OnAccept(CFSocketRef socket, CFSocketCallBackType type, CFDataRef ad
     }
 }
 
-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
 }
 
@@ -616,7 +751,7 @@ struct ffiData : ptrData {
     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);
@@ -629,6 +764,10 @@ struct selData : ptrData {
         ptrData(value)
     {
     }
+
+    SEL GetValue() const {
+        return reinterpret_cast<SEL>(value_);
+    }
 };
 
 JSObjectRef CYMakeSelector(JSContextRef context, SEL sel) {
@@ -646,39 +785,62 @@ static void Pointer_finalize(JSObjectRef object) {
     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; \
 })
 
@@ -692,7 +854,7 @@ SEL CYCastSEL(JSContextRef context, JSValueRef value) {
         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;
@@ -708,6 +870,11 @@ void *CYCastPointer(JSContextRef context, JSValueRef value) {
     }
 }
 
+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:
@@ -734,7 +901,7 @@ void CYPoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, void *da
 
         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:
@@ -742,7 +909,7 @@ void CYPoolFFI(apr_pool_t *pool, JSContextRef context, sig::Type *type, void *da
         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:
@@ -766,12 +933,12 @@ JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, void *data) {
 
     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)
@@ -788,10 +955,13 @@ JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, void *data) {
         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);
@@ -806,7 +976,7 @@ JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, void *data) {
 
         case sig::string_P:
             if (char *utf8 = *reinterpret_cast<char **>(data))
-                value = JSValueMakeString(context, CYJSString(utf8));
+                value = CYCastJSValue(context, utf8);
             else goto null;
         break;
 
@@ -814,11 +984,11 @@ JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, void *data) {
             goto fail;
 
         case sig::void_P:
-            value = JSValueMakeUndefined(context);
+            value = CYJSUndefined(context);
         break;
 
         null:
-            value = JSValueMakeNull(context);
+            value = CYJSNull(context);
         break;
 
         default: fail:
@@ -829,7 +999,7 @@ JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, void *data) {
     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];
@@ -851,17 +1021,18 @@ static JSValueRef CYCallFunction(JSContextRef context, size_t count, const JSVal
     } 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;
@@ -879,16 +1050,43 @@ bool stret(ffi_type *ffi_type) {
     );
 }
 
-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]);
@@ -923,7 +1121,7 @@ static JSValueRef Functor_callAsFunction(JSContextRef context, JSObjectRef objec
     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];
@@ -932,25 +1130,51 @@ JSObjectRef sel(JSContextRef context, JSObjectRef object, size_t count, const JS
     } 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}
@@ -961,6 +1185,11 @@ static JSStaticValue Pointer_staticValues[2] = {
     {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),
@@ -982,6 +1211,17 @@ void cy::parser::error(const cy::parser::location_type &location, const std::str
     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();
 
@@ -1024,14 +1264,17 @@ MSInitialize { _pooled
     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;
@@ -1043,11 +1286,19 @@ MSInitialize { _pooled
 
     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");
diff --git a/Output.cpp b/Output.cpp
index 5471620..a35ab81 100644
--- a/Output.cpp
+++ b/Output.cpp
@@ -3,10 +3,46 @@
 #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 << ".$()";
 }
 
@@ -17,7 +53,7 @@ void CYArgument::Output(std::ostream &out) const {
             out << ":";
     }
     if (value_ != NULL)
-        value_->Output(out, false);
+        value_->Output(out, CYPA, CYNoFlags);
     if (next_ != NULL) {
         if (next_->name_ == NULL)
             out << ',';
@@ -27,21 +63,25 @@ void CYArgument::Output(std::ostream &out) const {
     }
 }
 
-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 {
@@ -51,8 +91,8 @@ 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);
@@ -64,13 +104,30 @@ void CYCatch::Output(std::ostream &out) const {
     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 {
@@ -83,7 +140,7 @@ 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 << ':';
@@ -92,6 +149,7 @@ void CYClause::Output(std::ostream &out) const {
     out << *next_;
 }
 
+// XXX: deal with NoIn
 void CYDeclaration::Part(std::ostream &out) const {
     out << "var ";
     Output(out);
@@ -101,10 +159,11 @@ void CYDeclaration::Output(std::ostream &out) const {
     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 ";
 
@@ -125,16 +184,17 @@ void CYDeclarations::Output(std::ostream &out) const {
 }
 
 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)
@@ -153,34 +213,42 @@ void CYEmpty::Output(std::ostream &out, bool block) const {
 }
 
 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 {
@@ -189,10 +257,10 @@ 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);
 }
@@ -200,19 +268,29 @@ void CYFor::Output(std::ostream &out) const {
 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) {
@@ -221,106 +299,141 @@ void CYIf::Output(std::ostream &out) const {
     }
 }
 
-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);
@@ -329,15 +442,13 @@ void CYProperty::Output(std::ostream &out) const {
 
 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 << "\")";
@@ -352,9 +463,28 @@ void CYSelectorPart::Output(std::ostream &out) const {
         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 {
@@ -367,7 +497,7 @@ 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) {
@@ -391,23 +521,25 @@ void CYString::Output(std::ostream &out) const {
 
 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 << ';';
 }
 
@@ -422,20 +554,25 @@ void CYTry::Output(std::ostream &out) const {
     }
 }
 
-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);
 }
diff --git a/Parser.hpp b/Parser.hpp
index 643833f..9daf63e 100644
--- a/Parser.hpp
+++ b/Parser.hpp
@@ -153,6 +153,15 @@ struct CYForInInitialiser :
 {
 };
 
+enum CYFlags {
+    CYNoFlags,
+    CYNoBrace,
+    CYNoFunction,
+    CYNoLeader,
+    CYNoTrailer,
+    CYNoIn
+};
+
 struct CYExpression :
     CYNext<CYExpression>,
     CYForInitialiser,
@@ -160,14 +169,19 @@ struct CYExpression :
 {
     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; \
@@ -193,7 +207,7 @@ struct CYCompound :
 
     CYPrecedence(17)
 
-    void Output(std::ostream &out) const;
+    void Output(std::ostream &out, CYFlags flags) const;
 };
 
 struct CYLiteral :
@@ -230,7 +244,7 @@ struct CYSelector :
 
     CYPrecedence(1)
 
-    virtual void Output(std::ostream &out) const;
+    virtual void Output(std::ostream &out, CYFlags flags) const;
 };
 
 struct CYRange {
@@ -292,7 +306,11 @@ struct CYString :
         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 :
@@ -314,7 +332,11 @@ 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 :
@@ -326,7 +348,7 @@ struct CYNull :
     {
     }
 
-    virtual void Output(std::ostream &out) const;
+    virtual void Output(std::ostream &out, CYFlags flags) const;
 };
 
 struct CYThis :
@@ -340,14 +362,14 @@ 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 :
@@ -359,9 +381,7 @@ struct CYFalse :
     {
     }
 
-    virtual bool Value() const {
-        return false;
-    }
+    virtual bool Value() const;
 };
 
 struct CYTrue :
@@ -373,9 +393,7 @@ struct CYTrue :
     {
     }
 
-    virtual bool Value() const {
-        return true;
-    }
+    virtual bool Value() const;
 };
 
 struct CYVariable :
@@ -390,7 +408,7 @@ struct CYVariable :
 
     CYPrecedence(0)
 
-    virtual void Output(std::ostream &out) const;
+    virtual void Output(std::ostream &out, CYFlags flags) const;
 };
 
 struct CYPrefix :
@@ -403,9 +421,10 @@ 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 :
@@ -420,9 +439,10 @@ 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 :
@@ -437,7 +457,7 @@ 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 :
@@ -454,7 +474,7 @@ 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 :
@@ -522,7 +542,7 @@ struct CYArray :
     {
     }
 
-    virtual void Output(std::ostream &out) const;
+    virtual void Output(std::ostream &out, CYFlags flags) const;
 };
 
 struct CYDeclaration :
@@ -559,14 +579,73 @@ struct CYDeclarations :
     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)
     {
     }
@@ -636,7 +715,7 @@ struct CYObject :
     {
     }
 
-    void Output(std::ostream &out) const;
+    void Output(std::ostream &out, CYFlags flags) const;
 };
 
 struct CYCatch :
@@ -654,13 +733,13 @@ 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)
     {
@@ -668,7 +747,7 @@ struct CYMessage :
 
     CYPrecedence(0)
 
-    virtual void Output(std::ostream &out) const;
+    virtual void Output(std::ostream &out, CYFlags flags) const;
 };
 
 struct CYMember :
@@ -685,7 +764,7 @@ struct CYMember :
 
     CYPrecedence(1)
 
-    virtual void Output(std::ostream &out) const;
+    virtual void Output(std::ostream &out, CYFlags flags) const;
 };
 
 struct CYNew :
@@ -702,7 +781,7 @@ struct CYNew :
 
     CYPrecedence(1)
 
-    virtual void Output(std::ostream &out) const;
+    virtual void Output(std::ostream &out, CYFlags flags) const;
 };
 
 struct CYCall :
@@ -719,7 +798,7 @@ struct CYCall :
 
     CYPrecedence(2)
 
-    virtual void Output(std::ostream &out) const;
+    virtual void Output(std::ostream &out, CYFlags flags) const;
 };
 
 struct CYIf :
@@ -773,10 +852,10 @@ struct CYLambda :
     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)
@@ -785,14 +864,14 @@ struct CYLambda :
 
     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)
     {
     }
@@ -935,7 +1014,7 @@ struct CYCondition :
 
     CYPrecedence(15)
 
-    virtual void Output(std::ostream &out) const;
+    virtual void Output(std::ostream &out, CYFlags flags) const;
 };
 
 struct CYAddressOf :
@@ -950,9 +1029,10 @@ 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 :
@@ -967,9 +1047,10 @@ 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) \
@@ -988,7 +1069,7 @@ struct CYIndirect :
         } \
     };
 
-#define CYPrefix_(op, name) \
+#define CYPrefix_(alphabetic, op, name) \
     struct CY ## name : \
         CYPrefix \
     { \
@@ -997,6 +1078,7 @@ struct CYIndirect :
         { \
         } \
     \
+        CYAlphabetic(alphabetic) \
         CYPrecedence(4) \
     \
         virtual const char *Operator() const { \
@@ -1004,7 +1086,7 @@ struct CYIndirect :
         } \
     };
 
-#define CYInfix_(precedence, op, name) \
+#define CYInfix_(alphabetic, precedence, op, name) \
     struct CY ## name : \
         CYInfix \
     { \
@@ -1013,6 +1095,7 @@ struct CYIndirect :
         { \
         } \
     \
+        CYAlphabetic(alphabetic) \
         CYPrecedence(precedence) \
     \
         virtual const char *Operator() const { \
@@ -1039,38 +1122,38 @@ struct CYIndirect :
 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)
diff --git a/cycript.hpp b/cycript.hpp
index 7fd159c..2edea84 100644
--- a/cycript.hpp
+++ b/cycript.hpp
@@ -5,15 +5,12 @@
 #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);
diff --git a/documents.txt b/documents.txt
index 5371ac8..2d31216 100644
--- a/documents.txt
+++ b/documents.txt
@@ -1,3 +1,6 @@
 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
diff --git a/makefile b/makefile
index d178765..1eb6f99 100644
--- a/makefile
+++ b/makefile
@@ -15,16 +15,19 @@ clean:
 	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 $<
@@ -57,7 +60,7 @@ Application.o: Application.mm Cycript.tab.hh Parser.hpp Pooling.hpp cycript.hpp
 	$(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
@@ -85,6 +88,6 @@ package: all
 
 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
-- 
2.50.0

