From: Jay Freeman (saurik) Date: Tue, 24 Nov 2015 00:33:49 +0000 (-0800) Subject: Support implicit return from block_lambda_revival. X-Git-Tag: v0.9.590~293 X-Git-Url: https://git.saurik.com/cycript.git/commitdiff_plain/12e37ba3b9b322dd5b0483b45008e78e12aaa670 Support implicit return from block_lambda_revival. --- diff --git a/List.hpp b/List.hpp index f218f54..30390eb 100644 --- a/List.hpp +++ b/List.hpp @@ -53,14 +53,14 @@ Type_ *&CYSetLast(Type_ *&list) { } template -Type_ *CYGetLast(Type_ *list) { +Type_ *&CYGetLast(Type_ *&list) { if (list == NULL) - return NULL; + return list; - Type_ *next(list); - while (next->next_ != NULL) - next = next->next_; - return next; + Type_ **next(&list); + while ((*next)->next_ != NULL) + next = &(*next)->next_; + return *next; } #define CYForEach(value, list) \ diff --git a/Parser.hpp b/Parser.hpp index 8bd7cdc..2c534cc 100644 --- a/Parser.hpp +++ b/Parser.hpp @@ -158,6 +158,8 @@ struct CYStatement : virtual CYStatement *Replace(CYContext &context) = 0; + virtual CYStatement *Return(); + private: virtual void Output(CYOutput &out, CYFlags flags) const = 0; }; @@ -447,6 +449,8 @@ struct CYBlock : virtual CYStatement *Replace(CYContext &context); virtual void Output(CYOutput &out, CYFlags flags) const; + + virtual CYStatement *Return(); }; struct CYForInitialiser { @@ -1399,6 +1403,8 @@ struct CYIf : virtual CYStatement *Replace(CYContext &context); virtual void Output(CYOutput &out, CYFlags flags) const; + + virtual CYStatement *Return(); }; struct CYDoWhile : @@ -1440,13 +1446,15 @@ struct CYFunction { CYStatement *code_; CYNonLocal *nonlocal_; + bool implicit_; CYThisScope this_; CYFunction(CYIdentifier *name, CYFunctionParameter *parameters, CYStatement *code) : name_(name), parameters_(parameters), code_(code), - nonlocal_(NULL) + nonlocal_(NULL), + implicit_(false) { } @@ -1533,6 +1541,8 @@ struct CYExpress : virtual CYStatement *Replace(CYContext &context); virtual void Output(CYOutput &out, CYFlags flags) const; + + virtual CYStatement *Return(); }; struct CYContinue : diff --git a/Replace.cpp b/Replace.cpp index 74f04d9..7b99022 100644 --- a/Replace.cpp +++ b/Replace.cpp @@ -29,6 +29,11 @@ CYFunctionExpression *CYNonLocalize(CYContext &context, CYFunctionExpression *fu return function; } +static void CYImplicitReturn(CYStatement *&code) { + if (CYStatement *&last = CYGetLast(code)) + last = last->Return(); +} + CYExpression *CYAdd::Replace(CYContext &context) { CYInfix::Replace(context); @@ -95,6 +100,11 @@ CYExpression *CYAssignment::Replace(CYContext &context) { return this; } +CYStatement *CYBlock::Return() { + CYImplicitReturn(code_); + return this; +} + CYStatement *CYBlock::Replace(CYContext &context) { context.ReplaceAll(code_); if (code_ == NULL) @@ -305,6 +315,10 @@ CYExpression *CYEncodedType::Replace(CYContext &context) { return typed_->Replace(context); } +CYStatement *CYExpress::Return() { + return $ CYReturn(expression_); +} + CYStatement *CYExpress::Replace(CYContext &context) { context.Replace(expression_); return this; @@ -430,7 +444,8 @@ void CYFunction::Replace_(CYContext &context, bool outer) { Inject(context); CYThisScope *_this(context.this_); - context.this_ = CYGetLast(&this_); + context.this_ = &this_; + context.this_ = CYGetLast(context.this_); CYNonLocal *nonlocal(context.nonlocal_); CYNonLocal *nextlocal(context.nextlocal_); @@ -453,6 +468,9 @@ void CYFunction::Replace_(CYContext &context, bool outer) { parameters_->Replace(context, code_); context.ReplaceAll(code_); + if (implicit_) + CYImplicitReturn(code_); + if (CYIdentifier *identifier = this_.identifier_) code_ = $$->* $ CYVar($L1($ CYDeclaration(identifier, $ CYThis())))->* @@ -501,6 +519,12 @@ 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.ReplaceAll(true_); @@ -709,12 +733,14 @@ 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 *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) : @@ -831,6 +857,10 @@ void CYScope::Close(CYContext &context, CYStatement *&statements) { } } +CYStatement *CYStatement::Return() { + return this; +} + CYString *CYString::Concat(CYContext &context, CYString *rhs) const { size_t size(size_ + rhs->size_); char *value($ char[size + 1]);