]> git.saurik.com Git - cycript.git/blobdiff - Replace.cpp
Simplify command return by avoiding extra newline.
[cycript.git] / Replace.cpp
index bcaffca8cd39ad9e3376c3ff0c43a3907ea55e7c..ac673adefd204c04966a66d0a51f0f93b01cce0e 100644 (file)
 **/
 /* }}} */
 
-#include "Parser.hpp"
-#include "Replace.hpp"
-
 #include <iomanip>
 
+#include "Replace.hpp"
+#include "Syntax.hpp"
+
 CYFunctionExpression *CYNonLocalize(CYContext &context, CYFunctionExpression *function) {
     function->nonlocal_ = context.nextlocal_;
     return function;
 }
 
+CYFunctionExpression *CYSuperize(CYContext &context, CYFunctionExpression *function) {
+    function->super_ = context.super_;
+    return function;
+}
+
+CYStatement *CYDefineProperty(CYExpression *object, CYExpression *name, bool configurable, bool enumerable, CYProperty *descriptor) {
+    return $E($C3($M($V("Object"), $S("defineProperty")), object, name, $ CYObject(CYList<CYProperty>()
+        ->* (configurable ? $ CYPropertyValue($S("configurable"), $ CYTrue()) : NULL)
+        ->* (enumerable ? $ CYPropertyValue($S("enumerable"), $ CYTrue()) : NULL)
+        ->* descriptor)));
+}
+
+static void CYImplicitReturn(CYStatement *&code) {
+    if (CYStatement *&last = CYGetLast(code))
+        last = last->Return();
+}
+
 CYExpression *CYAdd::Replace(CYContext &context) {
     CYInfix::Replace(context);
 
@@ -75,14 +92,15 @@ CYArgument *CYArgument::Replace(CYContext &context) { $T(NULL)
 }
 
 CYExpression *CYArray::Replace(CYContext &context) {
-    elements_->Replace(context);
+    if (elements_ != NULL)
+        elements_->Replace(context);
     return this;
 }
 
 CYExpression *CYArrayComprehension::Replace(CYContext &context) {
     CYVariable *cyv($V("$cyv"));
 
-    return $C0($F(NULL, $P1($L("$cyv"), comprehensions_->Parameters(context)), $$->*
+    return $C0($F(NULL, $P1($L($I("$cyv")), comprehensions_->Parameters(context)), $$->*
         $E($ CYAssign(cyv, $ CYArray()))->*
         comprehensions_->Replace(context, $E($C1($M(cyv, $S("push")), expression_)))->*
         $ CYReturn(cyv)
@@ -95,9 +113,14 @@ CYExpression *CYAssignment::Replace(CYContext &context) {
     return this;
 }
 
+CYStatement *CYBlock::Return() {
+    CYImplicitReturn(code_);
+    return this;
+}
+
 CYStatement *CYBlock::Replace(CYContext &context) {
-    context.ReplaceAll(statements_);
-    if (statements_ == NULL)
+    context.ReplaceAll(code_);
+    if (code_ == NULL)
         return $ CYEmpty();
     return this;
 }
@@ -124,31 +147,63 @@ namespace cy {
 namespace Syntax {
 
 void Catch::Replace(CYContext &context) { $T()
-    CYScope scope(true, context, code_.statements_);
+    CYScope scope(true, context);
 
     context.Replace(name_);
     context.scope_->Declare(context, name_, CYIdentifierCatch);
 
-    code_.Replace(context);
-    scope.Close();
+    context.ReplaceAll(code_);
+    scope.Close(context, code_);
 }
 
 } }
 
+CYExpression *CYClassExpression::Replace(CYContext &context) {
+    CYBuilder builder;
+
+    CYIdentifier *super(context.Unique());
+
+    CYIdentifier *old(context.super_);
+    context.super_ = super;
+
+    CYIdentifier *constructor(context.Unique());
+    CYForEach (member, tail_->static_)
+        member->Replace(context, builder, $V(constructor), true);
+
+    CYIdentifier *prototype(context.Unique());
+    CYForEach (member, tail_->instance_)
+        member->Replace(context, builder, $V(prototype), true);
+
+    if (tail_->constructor_ == NULL)
+        tail_->constructor_ = $ CYFunctionExpression(NULL, NULL, NULL);
+    tail_->constructor_ = CYSuperize(context, tail_->constructor_);
+
+    context.super_ = old;
+
+    return $C1($ CYFunctionExpression(NULL, $P($L(super)), $$
+        ->* $ CYVar($L1($L(constructor, tail_->constructor_)))
+        ->* $ CYVar($L1($L(prototype, $ CYFunctionExpression(NULL, NULL, NULL))))
+        ->* $E($ CYAssign($M($V(prototype), $S("prototype")), $M($V(super), $S("prototype"))))
+        ->* $E($ CYAssign($V(prototype), $N($V(prototype))))
+        ->* CYDefineProperty($V(prototype), $S("constructor"), false, false, $ CYPropertyValue($S("value"), $V(constructor)))
+        ->* $ CYVar(builder.declarations_)
+        ->* builder.statements_
+        ->* CYDefineProperty($V(constructor), $S("prototype"), false, false, $ CYPropertyValue($S("value"), $V(prototype)))
+        ->* $ CYReturn($V(constructor))
+    ), tail_->extends_ ?: $V($I("Object")));
+}
+
+CYStatement *CYClassStatement::Replace(CYContext &context) {
+    return $ CYVar($L1($L(name_, $ CYClassExpression(name_, tail_))));
+}
+
 void CYClause::Replace(CYContext &context) { $T()
     context.Replace(case_);
-    context.ReplaceAll(statements_);
+    context.ReplaceAll(code_);
     next_->Replace(context);
 }
 
-CYStatement *CYComment::Replace(CYContext &context) {
-    return this;
-}
-
 CYExpression *CYCompound::Replace(CYContext &context) {
-    if (next_ == NULL)
-        return expression_;
-
     context.Replace(expression_);
     context.Replace(next_);
 
@@ -162,22 +217,10 @@ CYExpression *CYCompound::Replace(CYContext &context) {
     return this;
 }
 
-CYExpression *CYCompound::Primitive(CYContext &context) {
-    CYExpression *expression(expression_);
-    if (expression == NULL || next_ != NULL)
+CYFunctionParameter *CYCompound::Parameter() const {
+    CYFunctionParameter *next(next_->Parameter());
+    if (next == NULL)
         return NULL;
-    return expression->Primitive(context);
-}
-
-CYFunctionParameter *CYCompound::Parameters() const {
-    CYFunctionParameter *next;
-    if (next_ == NULL)
-        next = NULL;
-    else {
-        next = next_->Parameters();
-        if (next == NULL)
-            return NULL;
-    }
 
     CYFunctionParameter *parameter(expression_->Parameter());
     if (parameter == NULL)
@@ -200,6 +243,10 @@ CYStatement *CYComprehension::Replace(CYContext &context, CYStatement *statement
     return next_ == NULL ? statement : next_->Replace(context, statement);
 }
 
+CYExpression *CYComputed::PropertyName(CYContext &context) {
+    return expression_;
+}
+
 CYExpression *CYCondition::Replace(CYContext &context) {
     context.Replace(test_);
     context.Replace(true_);
@@ -215,7 +262,7 @@ void CYContext::NonLocal(CYStatement *&statements) {
         CYIdentifier *unique(nextlocal_->identifier_->Replace(context));
 
         CYStatement *declare(
-            $ CYVar($L1($ CYDeclaration(unique, $ CYObject()))));
+            $ CYVar($L1($L(unique, $ CYObject()))));
 
         cy::Syntax::Catch *rescue(
             $ cy::Syntax::Catch(cye, $$->*
@@ -223,6 +270,7 @@ void CYContext::NonLocal(CYStatement *&statements) {
                     $ CYReturn($M($V(cye), $S("$cyv"))))->*
                 $ cy::Syntax::Throw($V(cye))));
 
+        // XXX: I don't understand any of this
         context.Replace(declare);
         rescue->Replace(context);
 
@@ -272,10 +320,6 @@ void CYDeclarations::Replace(CYContext &context) { $T()
     next_->Replace(context);
 }
 
-CYProperty *CYDeclarations::Property(CYContext &context) { $T(NULL)
-    return $ CYProperty(declaration_->identifier_, declaration_->initialiser_, next_->Property(context));
-}
-
 CYFunctionParameter *CYDeclarations::Parameter(CYContext &context) { $T(NULL)
     return $ CYFunctionParameter($ CYDeclaration(declaration_->identifier_), next_->Parameter(context));
 }
@@ -284,10 +328,13 @@ CYArgument *CYDeclarations::Argument(CYContext &context) { $T(NULL)
     return $ CYArgument(declaration_->initialiser_, next_->Argument(context));
 }
 
-CYCompound *CYDeclarations::Compound(CYContext &context) { $T(NULL)
-    CYCompound *compound(next_->Compound(context));
+CYExpression *CYDeclarations::Expression(CYContext &context) { $T(NULL)
+    CYExpression *compound(next_->Expression(context));
     if (CYAssignment *assignment = declaration_->Assignment(context))
-        compound = $ CYCompound(assignment, compound);
+        if (compound == NULL)
+            compound = assignment;
+        else
+            compound = $ CYCompound(assignment, compound);
     return compound;
 }
 
@@ -299,13 +346,18 @@ CYExpression *CYDirectMember::Replace(CYContext &context) {
 
 CYStatement *CYDoWhile::Replace(CYContext &context) {
     context.Replace(test_);
-    context.Replace(code_);
+    context.ReplaceAll(code_);
     return this;
 }
 
-void CYElement::Replace(CYContext &context) { $T()
+void CYElementSpread::Replace(CYContext &context) {
     context.Replace(value_);
-    next_->Replace(context);
+}
+
+void CYElementValue::Replace(CYContext &context) {
+    context.Replace(value_);
+    if (next_ != NULL)
+        next_->Replace(context);
 }
 
 CYStatement *CYEmpty::Replace(CYContext &context) {
@@ -316,16 +368,12 @@ CYExpression *CYEncodedType::Replace(CYContext &context) {
     return typed_->Replace(context);
 }
 
-CYStatement *CYExpress::Replace(CYContext &context) {
-    while (CYExpress *express = dynamic_cast<CYExpress *>(next_)) {
-        expression_ = $ CYCompound(expression_, express->expression_);
-        SetNext(express->next_);
-    }
+CYStatement *CYExpress::Return() {
+    return $ CYReturn(expression_);
+}
 
+CYStatement *CYExpress::Replace(CYContext &context) {
     context.Replace(expression_);
-    if (expression_ == NULL)
-        return $ CYEmpty();
-
     return this;
 }
 
@@ -333,10 +381,6 @@ CYExpression *CYExpression::AddArgument(CYContext &context, CYExpression *value)
     return $C1(this, value);
 }
 
-CYExpression *CYExpression::ClassName(CYContext &context, bool object) {
-    return this;
-}
-
 CYStatement *CYExpression::ForEachIn(CYContext &context, CYExpression *value) {
     return $E($ CYAssign(this, value));
 }
@@ -349,10 +393,6 @@ CYFunctionParameter *CYExpression::Parameter() const {
     return NULL;
 }
 
-CYFunctionParameter *CYExpression::Parameters() const {
-    return NULL;
-}
-
 CYStatement *CYExternal::Replace(CYContext &context) {
     return $E($ CYAssign($V(typed_->identifier_), $C1(typed_->Replace(context), $C2($V("dlsym"), $V("RTLD_DEFAULT"), $S(typed_->identifier_->Word())))));
 }
@@ -372,20 +412,20 @@ CYExpression *CYFatArrow::Replace(CYContext &context) {
 }
 
 void CYFinally::Replace(CYContext &context) { $T()
-    code_.Replace(context);
+    context.ReplaceAll(code_);
 }
 
 CYStatement *CYFor::Replace(CYContext &context) {
     context.Replace(initialiser_);
     context.Replace(test_);
     context.Replace(increment_);
-    context.Replace(code_);
+    context.ReplaceAll(code_);
     return this;
 }
 
-CYCompound *CYForDeclarations::Replace(CYContext &context) {
+CYExpression *CYForDeclarations::Replace(CYContext &context) {
     declarations_->Replace(context);
-    return declarations_->Compound(context);
+    return declarations_->Expression(context);
 }
 
 // XXX: this still feels highly suboptimal
@@ -398,16 +438,16 @@ CYStatement *CYForIn::Replace(CYContext &context) {
 
     context.Replace(initialiser_);
     context.Replace(set_);
-    context.Replace(code_);
+    context.ReplaceAll(code_);
     return this;
 }
 
 CYFunctionParameter *CYForInComprehension::Parameter(CYContext &context) const {
-    return $ CYFunctionParameter($ CYDeclaration(name_));
+    return $ CYFunctionParameter(declaration_);
 }
 
 CYStatement *CYForInComprehension::Replace(CYContext &context, CYStatement *statement) const {
-    return $ CYForIn($V(name_), set_, CYComprehension::Replace(context, statement));
+    return $ CYForIn(declaration_->Variable(context), set_, CYComprehension::Replace(context, statement));
 }
 
 CYStatement *CYForOf::Replace(CYContext &context) {
@@ -417,43 +457,39 @@ CYStatement *CYForOf::Replace(CYContext &context) {
             this
         );
 
-    CYIdentifier *cys($I("$cys")), *cyt($I("$cyt"));
+    CYIdentifier *cys(context.Unique()), *cyt(context.Unique());
 
-    return $ CYLetStatement($L2($ CYDeclaration(cys, set_), $ CYDeclaration(cyt)), $$->*
-        $ CYForIn($V(cyt), $V(cys), $ CYBlock($$->*
-            initialiser_->ForEachIn(context, $M($V(cys), $V(cyt)))->*
-            code_
-        ))
-    );
+    return $ CYBlock($$
+        ->* $ CYLet($L2($L(cys, set_), $L(cyt)))
+        ->* $ CYForIn($V(cyt), $V(cys), $ CYBlock($$
+            ->* initialiser_->ForEachIn(context, $M($V(cys), $V(cyt)))
+            ->* code_
+    )));
 }
 
 CYFunctionParameter *CYForOfComprehension::Parameter(CYContext &context) const {
-    return $ CYFunctionParameter($ CYDeclaration(name_));
+    return $ CYFunctionParameter(declaration_);
 }
 
 CYStatement *CYForOfComprehension::Replace(CYContext &context, CYStatement *statement) const {
     CYIdentifier *cys($I("$cys"));
 
-    return $E($C0($F(NULL, $P1($L("$cys")), $$->*
+    return $E($C0($F(NULL, $P1($L($I("$cys"))), $$->*
         $E($ CYAssign($V(cys), set_))->*
-        $ CYForIn($V(name_), $V(cys), $ CYBlock($$->*
-            $E($ CYAssign($V(name_), $M($V(cys), $V(name_))))->*
+        $ CYForIn(declaration_->Variable(context), $V(cys), $ CYBlock($$->*
+            $E($ CYAssign(declaration_->Variable(context), $M($V(cys), declaration_->Variable(context))))->*
             CYComprehension::Replace(context, statement)
         ))
     )));
 }
 
-void CYFunction::Inject(CYContext &context) {
-    context.Replace(name_);
-    context.scope_->Declare(context, name_, CYIdentifierOther);
-}
-
-void CYFunction::Replace_(CYContext &context, bool outer) {
-    if (outer)
-        Inject(context);
-
+void CYFunction::Replace(CYContext &context) {
     CYThisScope *_this(context.this_);
-    context.this_ = CYGetLast(&this_);
+    context.this_ = &this_;
+    context.this_ = CYGetLast(context.this_);
+
+    CYIdentifier *super(context.super_);
+    context.super_ = super_;
 
     CYNonLocal *nonlocal(context.nonlocal_);
     CYNonLocal *nextlocal(context.nextlocal_);
@@ -468,50 +504,62 @@ void CYFunction::Replace_(CYContext &context, bool outer) {
         context.nextlocal_ = nonlocal_;
     }
 
-    CYScope scope(!localize, context, code_.statements_);
-
-    if (!outer && name_ != NULL)
-        Inject(context);
+    CYScope scope(!localize, context);
 
     parameters_->Replace(context, code_);
-    code_.Replace(context);
 
-    if (CYIdentifier *identifier = this_.identifier_)
-        code_.statements_ = $$->*
-            $ CYVar($L1($ CYDeclaration(identifier, $ CYThis())))->*
-            code_.statements_;
+    context.ReplaceAll(code_);
+
+    if (implicit_)
+        CYImplicitReturn(code_);
+
+    if (CYIdentifier *identifier = this_.identifier_) {
+        context.scope_->Declare(context, identifier, CYIdentifierVariable);
+        code_ = $$
+            ->*$E($ CYAssign($V(identifier), $ CYThis()))
+            ->*code_
+        ;
+    }
 
     if (localize)
-        context.NonLocal(code_.statements_);
+        context.NonLocal(code_);
 
     context.nextlocal_ = nextlocal;
     context.nonlocal_ = nonlocal;
 
+    context.super_ = super;
     context.this_ = _this;
 
-    scope.Close();
+    scope.Close(context, code_);
 }
 
 CYExpression *CYFunctionExpression::Replace(CYContext &context) {
-    Replace_(context, false);
+    CYScope scope(false, context);
+    if (name_ != NULL)
+        context.scope_->Declare(context, name_, CYIdentifierOther);
+    CYFunction::Replace(context);
+    scope.Close(context, code_);
     return this;
 }
 
-void CYFunctionParameter::Replace(CYContext &context, CYBlock &code) { $T()
+void CYFunctionParameter::Replace(CYContext &context, CYStatement *&statements) { $T()
     CYAssignment *assignment(initialiser_->Assignment(context));
     context.Replace(initialiser_);
 
-    next_->Replace(context, code);
+    next_->Replace(context, statements);
 
     if (assignment != NULL)
-        // XXX: this cast is quite incorrect
-        code.AddPrev($ CYIf($ CYIdentical($ CYTypeOf(dynamic_cast<CYExpression *>(initialiser_)), $S("undefined")), $$->*
-            $E(assignment)
-        ));
+        statements = $$->*
+            // XXX: this cast is quite incorrect
+            $ CYIf($ CYIdentical($ CYTypeOf(dynamic_cast<CYExpression *>(initialiser_)), $S("undefined")), $$->*
+                $E(assignment)
+            )->*
+            statements;
 }
 
 CYStatement *CYFunctionStatement::Replace(CYContext &context) {
-    Replace_(context, true);
+    context.scope_->Declare(context, name_, CYIdentifierOther);
+    CYFunction::Replace(context);
     return this;
 }
 
@@ -522,10 +570,16 @@ CYIdentifier *CYIdentifier::Replace(CYContext &context) {
     return replace_;
 }
 
+CYStatement *CYIf::Return() {
+    CYImplicitReturn(true_);
+    CYImplicitReturn(false_);
+    return this;
+}
+
 CYStatement *CYIf::Replace(CYContext &context) {
     context.Replace(test_);
-    context.Replace(true_);
-    context.Replace(false_);
+    context.ReplaceAll(true_);
+    context.ReplaceAll(false_);
     return this;
 }
 
@@ -538,7 +592,7 @@ CYStatement *CYIfComprehension::Replace(CYContext &context, CYStatement *stateme
 }
 
 CYStatement *CYImport::Replace(CYContext &context) {
-    return $ CYVar($L1($L(module_->part_->Word(), $C1($V("require"), module_->Replace(context, "/")))));
+    return $ CYVar($L1($L($I(module_->part_->Word()), $C1($V("require"), module_->Replace(context, "/")))));
 }
 
 CYExpression *CYIndirect::Replace(CYContext &context) {
@@ -561,11 +615,22 @@ CYStatement *CYLabel::Replace(CYContext &context) {
 }
 
 CYExpression *CYLambda::Replace(CYContext &context) {
-    return $N2($V("Functor"), $ CYFunctionExpression(NULL, parameters_->Parameters(context), statements_), parameters_->TypeSignature(context, typed_->Replace(context)));
+    return $N2($V("Functor"), $ CYFunctionExpression(NULL, parameters_->Parameters(context), code_), parameters_->TypeSignature(context, typed_->Replace(context)));
 }
 
-CYStatement *CYLetStatement::Replace(CYContext &context) {
-    return $E($ CYCall(CYNonLocalize(context, $ CYFunctionExpression(NULL, declarations_->Parameter(context), code_)), declarations_->Argument(context)));
+CYStatement *CYLet::Replace(CYContext &context) {
+    declarations_->Replace(context);
+    if (CYExpression *expression = declarations_->Expression(context))
+        return $E(expression);
+    return $ CYEmpty();
+}
+
+CYFunctionExpression *CYMethod::Constructor() {
+    return NULL;
+}
+
+void CYMethod::Replace(CYContext &context) {
+    CYFunction::Replace(context);
 }
 
 CYString *CYModule::Replace(CYContext &context, const char *separator) const {
@@ -617,11 +682,31 @@ CYString *CYNumber::String(CYContext &context) {
     return $S($pool.sprintf(24, "%.17g", Value()));
 }
 
+CYExpression *CYNumber::PropertyName(CYContext &context) {
+    return String(context);
+}
+
 CYExpression *CYObject::Replace(CYContext &context) {
-    properties_->Replace(context);
+    CYBuilder builder;
+    if (properties_ != NULL)
+        properties_ = properties_->ReplaceAll(context, builder, $ CYThis(), false);
+
+    if (builder) {
+        return $C1($M($ CYFunctionExpression(NULL, builder.declarations_->Parameter(context),
+            builder.statements_->*
+                $ CYReturn($ CYThis())
+        ), $S("call")), this, builder.declarations_->Argument(context));
+    }
+
+    CYForEach (property, properties_)
+        property->Replace(context);
     return this;
 }
 
+CYExpression *CYParenthetical::Replace(CYContext &context) {
+    return expression_;
+}
+
 CYExpression *CYPostfix::Replace(CYContext &context) {
     context.Replace(lhs_);
     return this;
@@ -632,6 +717,68 @@ CYExpression *CYPrefix::Replace(CYContext &context) {
     return this;
 }
 
+CYProperty *CYProperty::ReplaceAll(CYContext &context, CYBuilder &builder, CYExpression *self, bool update) {
+    update |= name_->Computed();
+    if (update)
+        Replace(context, builder, self, false);
+    if (next_ != NULL)
+        next_ = next_->ReplaceAll(context, builder, self, update);
+    return update ? next_ : this;
+}
+
+void CYProperty::Replace(CYContext &context, CYBuilder &builder, CYExpression *self, bool protect) {
+    CYExpression *name(name_->PropertyName(context));
+    if (name_->Computed()) {
+        CYIdentifier *unique(context.Unique());
+        builder.declarations_->*$L1($L(unique, name));
+        name = $V(unique);
+    }
+
+    Replace(context, builder, self, name, protect);
+}
+
+void CYPropertyGetter::Replace(CYContext &context, CYBuilder &builder, CYExpression *self, CYExpression *name, bool protect) {
+    CYIdentifier *unique(context.Unique());
+    builder.declarations_
+        ->* $L1($L(unique, CYSuperize(context, $ CYFunctionExpression(NULL, parameters_, code_))));
+    builder.statements_
+        ->* CYDefineProperty(self, name, true, !protect, $ CYPropertyValue($S("get"), $V(unique)));
+}
+
+CYFunctionExpression *CYPropertyMethod::Constructor() {
+    return name_->Constructor() ? $ CYFunctionExpression(NULL, parameters_, code_) : NULL;
+}
+
+void CYPropertyMethod::Replace(CYContext &context, CYBuilder &builder, CYExpression *self, CYExpression *name, bool protect) {
+    CYIdentifier *unique(context.Unique());
+    builder.declarations_
+        ->* $L1($L(unique, CYSuperize(context, $ CYFunctionExpression(NULL, parameters_, code_))));
+    builder.statements_
+        ->* (!protect ? $E($ CYAssign($M(self, name), $V(unique))) :
+            CYDefineProperty(self, name, true, !protect, $ CYPropertyValue($S("value"), $V(unique), $ CYPropertyValue($S("writable"), $ CYTrue()))));
+}
+
+void CYPropertySetter::Replace(CYContext &context, CYBuilder &builder, CYExpression *self, CYExpression *name, bool protect) {
+    CYIdentifier *unique(context.Unique());
+    builder.declarations_
+        ->* $L1($L(unique, CYSuperize(context, $ CYFunctionExpression(NULL, parameters_, code_))));
+    builder.statements_
+        ->* CYDefineProperty(self, name, true, !protect, $ CYPropertyValue($S("set"), $V(unique)));
+}
+
+void CYPropertyValue::Replace(CYContext &context, CYBuilder &builder, CYExpression *self, CYExpression *name, bool protect) {
+    _assert(!protect);
+    CYIdentifier *unique(context.Unique());
+    builder.declarations_
+        ->* $L1($L(unique, value_));
+    builder.statements_
+        ->* $E($ CYAssign($M(self, name), $V(unique)));
+}
+
+void CYPropertyValue::Replace(CYContext &context) {
+    context.Replace(value_);
+}
+
 // XXX: this is evil evil black magic. don't ask, don't tell... don't believe!
 #define MappingSet "0etnirsoalfucdphmgyvbxTwSNECAFjDLkMOIBPqzRH$_WXUVGYKQJZ"
 //#define MappingSet "0abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_"
@@ -650,14 +797,14 @@ namespace {
     typedef std::set<CYIdentifier *, IdentifierUsageLess> IdentifierUsages;
 }
 
-void CYProgram::Replace(CYContext &context) {
-    CYScope scope(true, context, statements_);
+void CYScript::Replace(CYContext &context) {
+    CYScope scope(true, context);
 
     context.nextlocal_ = $ CYNonLocal();
-    context.ReplaceAll(statements_);
-    context.NonLocal(statements_);
+    context.ReplaceAll(code_);
+    context.NonLocal(code_);
 
-    scope.Close();
+    scope.Close(context, code_);
 
     size_t offset(0);
 
@@ -706,18 +853,11 @@ void CYProgram::Replace(CYContext &context) {
     }
 }
 
-void CYProperty::Replace(CYContext &context) { $T()
-    context.Replace(value_);
-    next_->Replace(context);
-    if (value_ == NULL)
-        value_ = $U;
-}
-
 CYStatement *CYReturn::Replace(CYContext &context) {
     if (context.nonlocal_ != NULL) {
-        CYProperty *value(value_ == NULL ? NULL : $ CYProperty($S("$cyv"), value_));
+        CYProperty *value(value_ == NULL ? NULL : $ CYPropertyValue($S("$cyv"), value_));
         return $ cy::Syntax::Throw($ CYObject(
-            $ CYProperty($S("$cyk"), $V(context.nonlocal_->Target(context)), value)
+            $ CYPropertyValue($S("$cyk"), $V(context.nonlocal_->Target(context)), value)
         ));
     }
 
@@ -726,29 +866,25 @@ CYStatement *CYReturn::Replace(CYContext &context) {
 }
 
 CYExpression *CYRubyBlock::Replace(CYContext &context) {
-    // XXX: this needs to do something much more epic to handle return
     return call_->AddArgument(context, proc_->Replace(context));
 }
 
+CYExpression *CYRubyBlock::AddArgument(CYContext &context, CYExpression *value) {
+    return Replace(context)->AddArgument(context, value);
+}
+
 CYExpression *CYRubyProc::Replace(CYContext &context) {
-    return CYNonLocalize(context, $ CYFunctionExpression(NULL, parameters_, code_));
+    CYFunctionExpression *function($ CYFunctionExpression(NULL, parameters_, code_));
+    function = CYNonLocalize(context, function);
+    function->implicit_ = true;
+    return function;
 }
 
-CYScope::CYScope(bool transparent, CYContext &context, CYStatement *&statements) :
+CYScope::CYScope(bool transparent, CYContext &context) :
     transparent_(transparent),
-    context_(context),
-    statements_(statements),
     parent_(context.scope_)
 {
-    context_.scope_ = this;
-}
-
-CYScope::~CYScope() {
-}
-
-void CYScope::Close() {
-    context_.scope_ = parent_;
-    Scope(context_, statements_);
+    context.scope_ = this;
 }
 
 void CYScope::Declare(CYContext &context, CYIdentifier *identifier, CYIdentifierFlags flags) {
@@ -806,7 +942,9 @@ namespace {
     typedef std::set<IdentifierOffset, IdentifierOffsetLess> IdentifierOffsets;
 }
 
-void CYScope::Scope(CYContext &context, CYStatement *&statements) {
+void CYScope::Close(CYContext &context, CYStatement *&statements) {
+    context.scope_ = parent_;
+
     if (parent_ == NULL)
         return;
 
@@ -856,6 +994,14 @@ void CYScope::Scope(CYContext &context, CYStatement *&statements) {
         }
 }
 
+CYElementValue *CYSpan::Replace(CYContext &context) { $T(NULL)
+    return $ CYElementValue(expression_, $ CYElementValue(string_, next_->Replace(context)));
+}
+
+CYStatement *CYStatement::Return() {
+    return this;
+}
+
 CYString *CYString::Concat(CYContext &context, CYString *rhs) const {
     size_t size(size_ + rhs->size_);
     char *value($ char[size + 1]);
@@ -870,16 +1016,32 @@ CYNumber *CYString::Number(CYContext &context) {
     return NULL;
 }
 
+CYExpression *CYString::PropertyName(CYContext &context) {
+    return this;
+}
+
 CYString *CYString::String(CYContext &context) {
     return this;
 }
 
+CYExpression *CYSuperAccess::Replace(CYContext &context) {
+    return $C1($M($M($M($V(context.super_), $S("prototype")), property_), $S("bind")), $ CYThis());
+}
+
+CYExpression *CYSuperCall::Replace(CYContext &context) {
+    return $C($C1($M($V(context.super_), $S("bind")), $ CYThis()), arguments_);
+}
+
 CYStatement *CYSwitch::Replace(CYContext &context) {
     context.Replace(value_);
     clauses_->Replace(context);
     return this;
 }
 
+CYExpression *CYTemplate::Replace(CYContext &context) {
+    return $C2($M($M($M($V("String"), $S("prototype")), $S("concat")), $S("apply")), $S(""), $ CYArray($ CYElementValue(string_, spans_->Replace(context))));
+}
+
 CYExpression *CYThis::Replace(CYContext &context) {
     if (context.this_ != NULL)
         return $V(context.this_->Identifier(context));
@@ -912,7 +1074,7 @@ namespace cy {
 namespace Syntax {
 
 CYStatement *Try::Replace(CYContext &context) {
-    code_.Replace(context);
+    context.ReplaceAll(code_);
     catch_->Replace(context);
     finally_->Replace(context);
     return this;
@@ -1012,8 +1174,8 @@ CYExpression *CYTypedParameter::TypeSignature(CYContext &context, CYExpression *
 
 CYStatement *CYVar::Replace(CYContext &context) {
     declarations_->Replace(context);
-    if (CYCompound *compound = declarations_->Compound(context))
-        return $E(compound);
+    if (CYExpression *expression = declarations_->Expression(context))
+        return $E(expression);
     return $ CYEmpty();
 }
 
@@ -1028,20 +1190,16 @@ CYFunctionParameter *CYVariable::Parameter() const {
 
 CYStatement *CYWhile::Replace(CYContext &context) {
     context.Replace(test_);
-    context.Replace(code_);
+    context.ReplaceAll(code_);
     return this;
 }
 
 CYStatement *CYWith::Replace(CYContext &context) {
     context.Replace(scope_);
-    context.Replace(code_);
+    context.ReplaceAll(code_);
     return this;
 }
 
-CYExpression *CYWord::ClassName(CYContext &context, bool object) {
-    CYString *name($S(this));
-    if (object)
-        return $C1($V("objc_getClass"), name);
-    else
-        return name;
+CYExpression *CYWord::PropertyName(CYContext &context) {
+    return $S(this);
 }