]> git.saurik.com Git - cycript.git/commitdiff
Added RubyProc/Blocks.
authorJay Freeman (saurik) <saurik@saurik.com>
Fri, 2 Jul 2010 07:33:05 +0000 (07:33 +0000)
committerJay Freeman (saurik) <saurik@saurik.com>
Fri, 2 Jul 2010 07:33:05 +0000 (07:33 +0000)
Parser.hpp
Replace.cpp

index 49e072263f13824e6a576f6d8601b45bc204061c..2d3a59f4b1417fc53e6e5035832b51fec01ab932 100644 (file)
@@ -357,16 +357,24 @@ struct CYProgram :
     virtual void Output(CYOutput &out) const;
 };
 
+struct CYNonLocal;
+
 struct CYContext {
     apr_pool_t *pool_;
     CYOptions &options_;
+
     CYScope *scope_;
     CYIdentifierUsageVector rename_;
 
+    CYNonLocal *nonlocal_;
+    unsigned unique_;
+
     CYContext(apr_pool_t *pool, CYOptions &options) :
         pool_(pool),
         options_(options),
-        scope_(NULL)
+        scope_(NULL),
+        nonlocal_(NULL),
+        unique_(0)
     {
     }
 
@@ -384,6 +392,24 @@ struct CYContext {
             else break;
         }
     }
+
+    void NonLocal(CYStatement *&statements);
+    CYIdentifier *Unique();
+};
+
+struct CYNonLocal {
+    CYIdentifier *identifier_;
+
+    CYNonLocal() :
+        identifier_(NULL)
+    {
+    }
+
+    CYIdentifier *Target(CYContext &context) {
+        if (identifier_ == NULL)
+            identifier_ = context.Unique();
+        return identifier_;
+    }
 };
 
 struct CYBlock :
@@ -1261,7 +1287,7 @@ struct CYObject :
 {
     CYProperty *properties_;
 
-    CYObject(CYProperty *properties) :
+    CYObject(CYProperty *properties = NULL) :
         properties_(properties)
     {
     }
@@ -1440,11 +1466,13 @@ struct CYFunction {
     CYIdentifier *name_;
     CYFunctionParameter *parameters_;
     CYBlock code_;
+    CYNonLocal *nonlocal_;
 
     CYFunction(CYIdentifier *name, CYFunctionParameter *parameters, CYStatement *statements) :
         name_(name),
         parameters_(parameters),
-        code_(statements)
+        code_(statements),
+        nonlocal_(NULL)
     {
     }
 
@@ -1623,7 +1651,7 @@ struct Throw :
 {
     CYExpression *value_;
 
-    Throw(CYExpression *value) :
+    Throw(CYExpression *value = NULL) :
         value_(value)
     {
     }
index 1285e8fb567a16b048954c72d0e028e0deb44bb8..21157726990d239c37546386a3c664b01f5c3054 100644 (file)
@@ -172,6 +172,28 @@ CYExpression *CYCondition::Replace(CYContext &context) {
     return this;
 }
 
+void CYContext::NonLocal(CYStatement *&statements) {
+    CYContext &context(*this);
+
+    if (nonlocal_->identifier_ != NULL) {
+        CYVariable *cye($V("$cye"));
+        CYVariable *unique($ CYVariable(nonlocal_->identifier_));
+
+        statements = $$->*
+            $E($ CYAssign(unique, $ CYObject()))->*
+            $ cy::Syntax::Try(statements, $ cy::Syntax::Catch(cye->name_, $$->*
+                $ CYIf($ CYIdentical($M(cye, $S("$cyk")), unique), $$->*
+                    $ CYReturn($M(cye, $S("$cyv"))))->*
+                $ cy::Syntax::Throw(cye)
+            ), NULL);
+    }
+}
+
+CYIdentifier *CYContext::Unique() {
+    CYContext &context(*this);
+    return $ CYIdentifier(apr_psprintf(pool_, "$cy%u", unique_++));
+}
+
 CYStatement *CYContinue::Replace(CYContext &context) {
     return this;
 }
@@ -354,6 +376,17 @@ void CYFunction::Replace_(CYContext &context, bool outer) {
     scope.parent_ = context.scope_;
     context.scope_ = &scope;
 
+    bool localize;
+    if (nonlocal_ != NULL)
+        localize = false;
+    else {
+        localize = true;
+        nonlocal_ = $ CYNonLocal();
+    }
+
+    CYNonLocal *nonlocal(context.nonlocal_);
+    context.nonlocal_ = nonlocal_;
+
     if (!outer && name_ != NULL)
         Inject(context);
 
@@ -361,6 +394,10 @@ void CYFunction::Replace_(CYContext &context, bool outer) {
         parameters_ = parameters_->Replace(context, code_);
     code_.Replace(context);
 
+    if (localize)
+        context.NonLocal(code_.statements_);
+    context.nonlocal_ = nonlocal;
+
     context.scope_ = scope.parent_;
     scope.Scope(context, code_.statements_);
 }
@@ -515,7 +552,11 @@ void CYProgram::Replace(CYContext &context) {
     CYScope scope;
     scope.parent_ = context.scope_;
     context.scope_ = &scope;
+
+    context.nonlocal_ = $ CYNonLocal();
     statements_ = statements_->ReplaceAll(context);
+    context.NonLocal(statements_);
+
     context.scope_ = scope.parent_;
     scope.Scope(context, statements_);
 
@@ -572,6 +613,13 @@ void CYProperty::Replace(CYContext &context) { $T()
 }
 
 CYStatement *CYReturn::Replace(CYContext &context) {
+    if (context.nonlocal_ != NULL) {
+        CYProperty *value(value_ == NULL ? NULL : $ CYProperty($S("$cyv"), value_));
+        return $ cy::Syntax::Throw($ CYObject(
+            $ CYProperty($S("$cyk"), $ CYVariable(context.nonlocal_->Target(context)), value)
+        ));
+    }
+
     context.Replace(value_);
     return this;
 }
@@ -582,7 +630,9 @@ CYExpression *CYRubyBlock::Replace(CYContext &context) {
 }
 
 CYExpression *CYRubyProc::Replace(CYContext &context) {
-    return $ CYFunctionExpression(NULL, parameters_, code_);
+    CYFunctionExpression *function($ CYFunctionExpression(NULL, parameters_, code_));
+    function->nonlocal_ = context.nonlocal_;
+    return function;
 }
 
 void CYScope::Declare(CYContext &context, CYIdentifier *identifier, CYIdentifierFlags flags) {