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)
{
}
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 :
{
CYProperty *properties_;
- CYObject(CYProperty *properties) :
+ CYObject(CYProperty *properties = NULL) :
properties_(properties)
{
}
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)
{
}
{
CYExpression *value_;
- Throw(CYExpression *value) :
+ Throw(CYExpression *value = NULL) :
value_(value)
{
}
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;
}
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);
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_);
}
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_);
}
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;
}
}
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) {