Eliminate transform_yield_break()

The only places where ReturnStatement is constructed are:

- onReturn(check_yield=true) -> not allowed in generator
- onReturn(check_yield=false) -> coming from transform_yield_break, right after creating hphp_continuation_done()
- MethodStatement, end of function call -> hphp_continuation_done() is created at end of generator in prepare_generator()

Emitter is emitting ContExit in ReturnStatements used in generators. As
can be seen from the analysis above, it's always preceded by emitting
ContDone from hphp_continuation_done(). Let's emit ContDone inside the
ReturnStatement directly and kill usage of hphp_continuation_done().

transform_yield_break() becomes a simple onReturn(check_yield=false), so
let's inline it into onYield and create ReturnStatement directly. After
this change, check_yield flag is always true and can be killed.

ContExit was also used after emitting a generator method in case the end
of method is still reachable. ContDone is added so that the generator is
properly closed. I believe this is never actually used, as MethodStatement
creates ReturnStatement at the end of method anyway.
Esse commit está contido em:
jan
2013-03-21 15:53:07 -07:00
commit de Sara Golemon
commit 06713e6226
16 arquivos alterados com 1514 adições e 1648 exclusões
+7 -2
Ver Arquivo
@@ -2181,7 +2181,8 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
ReturnStatementPtr r(static_pointer_cast<ReturnStatement>(node));
bool retV = false;
if (m_curFunc->isGenerator()) {
// used by yield break
assert(m_evalStack.size() == 0);
e.ContDone();
e.ContExit();
return false;
}
@@ -3169,7 +3170,9 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
} else if (call->isCompilerCallToFunction("hphp_continuation_done")) {
inputIsAnObject(0);
e.ContDone();
return false;
e.ContExit();
e.Null();
return true;
} else if ((call->isCallToFunction("class_exists") ||
call->isCallToFunction("interface_exists") ||
call->isCallToFunction("trait_exists")) && params &&
@@ -5419,6 +5422,8 @@ void EmitterVisitor::emitPostponedMeths() {
// return null
if (currentPositionIsReachable()) {
if (p.m_meth->getFunctionScope()->isGenerator()) {
assert(m_evalStack.size() == 0);
e.ContDone();
e.ContExit();
} else {
e.Null();
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+7 -8
Ver Arquivo
@@ -116,7 +116,6 @@ extern void create_generator(Parser *_p, Token &out, Token &params,
const char *clsname, Token *modifiers,
bool getArgs, Token &origGenFunc, bool isHhvm,
Token *attr);
extern void transform_yield_break(Parser *_p, Token &out);
namespace HPHP {
@@ -790,9 +789,9 @@ void Parser::fixStaticVars() {
m_staticVars.pop_back();
}
void Parser::onFunction(Token &out, Token *modifiers, Token &ret, Token &ref,
void Parser::onFunction(Token &out, Token *modifiers, Token &ret, Token &ref,
Token &name, Token &params, Token &stmt, Token *attr) {
ModifierExpressionPtr exp = modifiers?
dynamic_pointer_cast<ModifierExpression>(modifiers->exp)
: NEW_EXP0(ModifierExpression);
@@ -1341,9 +1340,9 @@ void Parser::onContinue(Token &out, Token *expr) {
out->stmt = NEW_STMT(ContinueStatement, expr ? expr->exp : ExpressionPtr());
}
void Parser::onReturn(Token &out, Token *expr, bool checkYield /* = true */) {
void Parser::onReturn(Token &out, Token *expr) {
out->stmt = NEW_STMT(ReturnStatement, expr ? expr->exp : ExpressionPtr());
if (checkYield && !m_funcContexts.empty()) {
if (!m_funcContexts.empty()) {
if (!m_funcContexts.back().setIsNotGenerator()) {
Compiler::Error(InvalidYield, out->stmt);
PARSE_ERROR("Cannot mix 'return' and 'yield' in the same function");
@@ -1420,7 +1419,7 @@ void Parser::onYieldBreak(Token &out) {
return;
}
transform_yield_break(this, out);
out->stmt = NEW_STMT(ReturnStatement, ExpressionPtr());
}
void Parser::onGlobal(Token &out, Token &expr) {
@@ -1546,10 +1545,10 @@ void Parser::onClosureStart(Token &name) {
onFunctionStart(name, true);
}
void Parser::onClosure(Token &out, Token &ret, Token &ref, Token &params,
void Parser::onClosure(Token &out, Token &ret, Token &ref, Token &params,
Token &cparams, Token &stmts, bool is_static) {
Token func, name, modifiers;
ModifierExpressionPtr modifier_exp = NEW_EXP0(ModifierExpression);
modifiers->exp = modifier_exp;
if (is_static) {
+2 -2
Ver Arquivo
@@ -169,7 +169,7 @@ public:
void onClassConst(Token &out, Token &cls, Token &name, bool text);
void fixStaticVars();
void onFunctionStart(Token &name, bool doPushComment = true);
void onFunction(Token &out, Token *modifier, Token &ret, Token &ref,
void onFunction(Token &out, Token *modifier, Token &ret, Token &ref,
Token &name, Token &params, Token &stmt, Token *attr);
void onParam(Token &out, Token *params, Token &type, Token &var,
bool ref, Token *defValue, Token *attr);
@@ -210,7 +210,7 @@ public:
void onCase(Token &out, Token &cases, Token *cond, Token &stmt);
void onBreak(Token &out, Token *expr);
void onContinue(Token &out, Token *expr);
void onReturn(Token &out, Token *expr, bool checkYield = true);
void onReturn(Token &out, Token *expr);
void onYield(Token &out, Token &expr);
void onYieldBreak(Token &out);
void onGlobal(Token &out, Token &expr);
-8
Ver Arquivo
@@ -242,14 +242,6 @@ DefineFunction(
),
));
DefineFunction(
array(
'name' => 'done',
'return' => array(
'type' => null,
),
));
DefineFunction(
array(
'name' => "getWaitHandle",
-5
Ver Arquivo
@@ -93,11 +93,6 @@ void c_Continuation::t_update(int64_t label, CVarRef value) {
m_value.assignVal(value);
}
void c_Continuation::t_done() {
m_done = true;
m_value.setNull();
}
Object c_Continuation::t_getwaithandle() {
return m_waitHandle.isNull() ? c_ContinuationWaitHandle::t_start(this) : m_waitHandle;
}
@@ -283,42 +283,6 @@ TypedValue* tg_12Continuation_update(HPHP::VM::ActRec *ar) {
return &ar->m_r;
}
/*
void HPHP::c_Continuation::t_done()
_ZN4HPHP14c_Continuation6t_doneEv
this_ => rdi
*/
void th_12Continuation_done(ObjectData* this_) asm("_ZN4HPHP14c_Continuation6t_doneEv");
TypedValue* tg_12Continuation_done(HPHP::VM::ActRec *ar) {
TypedValue rv;
int64_t count = ar->numArgs();
TypedValue* args UNUSED = ((TypedValue*)ar) - 1;
ObjectData* this_ = (ar->hasThis() ? ar->getThis() : NULL);
if (this_) {
if (count == 0LL) {
rv.m_data.num = 0LL;
rv.m_type = KindOfNull;
th_12Continuation_done((this_));
frame_free_locals_inl(ar, 0);
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
return &ar->m_r;
} else {
throw_toomany_arguments_nr("Continuation::done", 0, 1);
}
} else {
throw_instance_method_fatal("Continuation::done");
}
rv.m_data.num = 0LL;
rv.m_type = KindOfNull;
frame_free_locals_inl(ar, 0);
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
return &ar->m_r;
return &ar->m_r;
}
/*
HPHP::Object HPHP::c_Continuation::t_getwaithandle()
_ZN4HPHP14c_Continuation15t_getwaithandleEv
-1
Ver Arquivo
@@ -48,7 +48,6 @@ class c_Continuation : public ExtObjectData {
public: ~c_Continuation();
public: void t___construct(int64_t func, CStrRef origFuncName, CVarRef obj = uninit_null(), CArrRef args = null_array);
public: void t_update(int64_t label, CVarRef value);
public: void t_done();
public: Object t_getwaithandle();
public: int64_t t_getlabel();
public: int64_t t_num_args();
+1 -3
Ver Arquivo
@@ -2401,7 +2401,6 @@ TypedValue* tg_13TupleIterator_rewind(VM::ActRec *ar);
VM::Instance* new_Continuation_Instance(VM::Class*);
TypedValue* tg_12Continuation___construct(VM::ActRec *ar);
TypedValue* tg_12Continuation_update(VM::ActRec *ar);
TypedValue* tg_12Continuation_done(VM::ActRec *ar);
TypedValue* tg_12Continuation_getWaitHandle(VM::ActRec *ar);
TypedValue* tg_12Continuation_getLabel(VM::ActRec *ar);
TypedValue* tg_12Continuation_num_args(VM::ActRec *ar);
@@ -5464,11 +5463,10 @@ static const HhbcExtMethodInfo hhbc_ext_methods_TupleIterator[] = {
{ "rewind", tg_13TupleIterator_rewind }
};
static const long long hhbc_ext_method_count_Continuation = 17;
static const long long hhbc_ext_method_count_Continuation = 16;
static const HhbcExtMethodInfo hhbc_ext_methods_Continuation[] = {
{ "__construct", tg_12Continuation___construct },
{ "update", tg_12Continuation_update },
{ "done", tg_12Continuation_done },
{ "getWaitHandle", tg_12Continuation_getWaitHandle },
{ "getLabel", tg_12Continuation_getLabel },
{ "num_args", tg_12Continuation_num_args },
+3 -2
Ver Arquivo
@@ -2071,7 +2071,7 @@ void VMExecutionContext::invokeFunc(TypedValue* retval,
// If this is a method, either this_ or cls must be non-NULL
assert(!f->preClass() || (this_ || cls));
// If this is a static method, this_ must be NULL
assert(!(f->attrs() & HPHP::VM::AttrStatic && !f->isClosureBody()) ||
assert(!(f->attrs() & HPHP::VM::AttrStatic && !f->isClosureBody()) ||
(!this_));
// invName should only be non-NULL if we are calling __call or
// __callStatic
@@ -7076,7 +7076,8 @@ inline void OPTBLD_INLINE VMExecutionContext::iopContReceive(PC& pc) {
inline void OPTBLD_INLINE VMExecutionContext::iopContDone(PC& pc) {
NEXT();
c_Continuation* cont = frame_continuation(m_fp);
cont->t_done();
cont->m_done = true;
cont->m_value.setNull();
}
inline void OPTBLD_INLINE VMExecutionContext::iopContNext(PC& pc) {
-5
Ver Arquivo
@@ -21953,11 +21953,6 @@ const char *g_class_map[] = {
NULL,
NULL,
NULL,
(const char *)0x10006040, "done", "", (const char*)0, (const char*)0,
"/**\n * ( excerpt from http://php.net/manual/en/continuation.done.php )\n *\n *\n */",
(const char *)-1, NULL,
NULL,
NULL,
(const char *)0x10006040, "getWaitHandle", "", (const char*)0, (const char*)0,
"/**\n * ( excerpt from http://php.net/manual/en/continuation.getwaithandle.php )\n *\n * Start asynchronous execution of this Continuation and return the wait\n * handle\n *\n * @return object\n */",
(const char *)0x40, NULL,
+1 -1
Ver Arquivo
@@ -7,7 +7,7 @@
#elif EXT_TYPE == 1
#elif EXT_TYPE == 2
"Continuation", "", "iterator","awaitable",NULL, "__construct", T(Void), S(0), "func", T(Int64), NULL, S(0), NULL, S(0), "extra", T(Int64), NULL, S(0), NULL, S(0), "isMethod", T(Boolean), NULL, S(0), NULL, S(0), "origFuncName", T(String), NULL, S(0), NULL, S(0), "obj", T(Variant), "N;", S(2), "null", S(0), "args", T(Array), "N;", S(2), "null", S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.construct.php )\n *\n *\n * @func int\n * @extra int\n * @isMethod bool\n * @origFuncName\n * string\n * @obj mixed\n * @args map\n */", S(16384),"update", T(Void), S(0), "label", T(Int64), NULL, S(0), NULL, S(0), "value", T(Variant), NULL, S(0), NULL, S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.update.php )\n *\n *\n * @label int\n * @value mixed\n */", S(16384),"done", T(Void), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.done.php )\n *\n *\n */", S(16384),"getWaitHandle", T(Object), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.getwaithandle.php )\n *\n * Start asynchronous execution of this Continuation and return the wait\n * handle\n *\n * @return object\n */", S(16384),"getLabel", T(Int64), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.getlabel.php )\n *\n *\n * @return int\n */", S(16384),"num_args", T(Int64), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.num-args.php )\n *\n *\n * @return int\n */", S(16384),"get_args", T(Array), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.get-args.php )\n *\n *\n * @return vector\n */", S(16384),"get_arg", T(Variant), S(0), "id", T(Int64), NULL, S(0), NULL, S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.get-arg.php )\n *\n *\n * @id int\n *\n * @return mixed\n */", S(16384),"current", T(Variant), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.current.php )\n *\n *\n * @return mixed\n */", S(16384),"key", T(Int64), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.key.php )\n *\n *\n * @return int\n */", S(16384),"next", T(Void), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.next.php )\n *\n *\n */", S(16384),"rewind", T(Void), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.rewind.php )\n *\n *\n */", S(16384),"valid", T(Boolean), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.valid.php )\n *\n *\n * @return bool\n */", S(16384),"send", T(Void), S(0), "v", T(Variant), NULL, S(0), NULL, S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.send.php )\n *\n *\n * @v mixed\n */", S(16384),"raise", T(Void), S(0), "v", T(Variant), NULL, S(0), NULL, S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.raise.php )\n *\n *\n * @v mixed\n */", S(16384),"getOrigFuncName", T(String), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.getorigfuncname.php\n * )\n *\n *\n * @return string\n */", S(16384),"__clone", T(Variant), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.clone.php )\n *\n *\n * @return mixed\n */", S(16384),NULL,NULL,NULL,
"Continuation", "", "iterator","awaitable",NULL, "__construct", T(Void), S(0), "func", T(Int64), NULL, S(0), NULL, S(0), "origFuncName", T(String), NULL, S(0), NULL, S(0), "obj", T(Variant), "N;", S(2), "null", S(0), "args", T(Array), "N;", S(2), "null", S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.construct.php )\n *\n *\n * @func int\n * @origFuncName\n * string\n * @obj mixed\n * @args map\n */", S(16384),"update", T(Void), S(0), "label", T(Int64), NULL, S(0), NULL, S(0), "value", T(Variant), NULL, S(0), NULL, S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.update.php )\n *\n *\n * @label int\n * @value mixed\n */", S(16384),"getWaitHandle", T(Object), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.getwaithandle.php )\n *\n * Start asynchronous execution of this Continuation and return the wait\n * handle\n *\n * @return object\n */", S(16384),"getLabel", T(Int64), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.getlabel.php )\n *\n *\n * @return int\n */", S(16384),"num_args", T(Int64), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.num-args.php )\n *\n *\n * @return int\n */", S(16384),"get_args", T(Array), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.get-args.php )\n *\n *\n * @return vector\n */", S(16384),"get_arg", T(Variant), S(0), "id", T(Int64), NULL, S(0), NULL, S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.get-arg.php )\n *\n *\n * @id int\n *\n * @return mixed\n */", S(16384),"current", T(Variant), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.current.php )\n *\n *\n * @return mixed\n */", S(16384),"key", T(Int64), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.key.php )\n *\n *\n * @return int\n */", S(16384),"next", T(Void), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.next.php )\n *\n *\n */", S(16384),"rewind", T(Void), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.rewind.php )\n *\n *\n */", S(16384),"valid", T(Boolean), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.valid.php )\n *\n *\n * @return bool\n */", S(16384),"send", T(Void), S(0), "v", T(Variant), NULL, S(0), NULL, S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.send.php )\n *\n *\n * @v mixed\n */", S(16384),"raise", T(Void), S(0), "v", T(Variant), NULL, S(0), NULL, S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.raise.php )\n *\n *\n * @v mixed\n */", S(16384),"getOrigFuncName", T(String), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.getorigfuncname.php\n * )\n *\n *\n * @return string\n */", S(16384),"__clone", T(Variant), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/continuation.clone.php )\n *\n *\n * @return mixed\n */", S(16384),NULL,NULL,NULL,
S(16416), "/**\n * ( excerpt from http://php.net/manual/en/class.continuation.php )\n *\n *\n */", "DummyContinuation", "", "iterator",NULL, "__construct", T(Void), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/dummycontinuation.construct.php\n * )\n *\n *\n */", S(16384),"current", T(Variant), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/dummycontinuation.current.php )\n *\n *\n * @return mixed\n */", S(16384),"key", T(Int64), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/dummycontinuation.key.php )\n *\n *\n * @return int\n */", S(16384),"next", T(Void), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/dummycontinuation.next.php )\n *\n *\n */", S(16384),"rewind", T(Void), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/dummycontinuation.rewind.php )\n *\n *\n */", S(16384),"valid", T(Boolean), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/dummycontinuation.valid.php )\n *\n *\n * @return bool\n */", S(16384),NULL,NULL,NULL,
S(16384), "/**\n * ( excerpt from http://php.net/manual/en/class.dummycontinuation.php )\n *\n * Represents an invalid continuation which will fatal when used.\n *\n */",
#endif
-4
Ver Arquivo
@@ -660,9 +660,7 @@ bool TestParserStmt::TestYieldStatement() {
"function ($" CONTINUATION_OBJECT_NAME ") {\n"
"switch (hphp_unpack_continuation($" CONTINUATION_OBJECT_NAME ")) {\n"
"}\n"
"hphp_continuation_done();\n"
"return;\n"
"hphp_continuation_done();\n"
"}\n"
"function foo() {\n"
"return hphp_create_continuation"
@@ -676,7 +674,6 @@ bool TestParserStmt::TestYieldStatement() {
"goto " YIELD_LABEL_PREFIX "1;\n"
"}\n"
"yield 123;\n"
"hphp_continuation_done();\n"
"}\n"
"function foo() {\n"
"return hphp_create_continuation"
@@ -699,7 +696,6 @@ bool TestParserStmt::TestYieldStatement() {
"}\n"
"yield 123;\n"
"yield 456;\n"
"hphp_continuation_done();\n"
"}\n"
"}\n");
+1 -27
Ver Arquivo
@@ -143,12 +143,6 @@ static void on_constant(Parser *_p, Token &out, Token *stmts,
///////////////////////////////////////////////////////////////////////////////
// continuation transformations
static void prepare_continuation_call(Parser* _p, Token& rhs, const char* cname) {
Token fname; fname.setText(std::string("hphp_continuation_") + cname);
Token empty;
_p->onCall(rhs, false, fname, empty, NULL, true);
}
void prepare_generator(Parser *_p, Token &stmt, Token &params, int count) {
// 1. add prologue and epilogue to original body and store it back to "stmt"
{
@@ -190,20 +184,14 @@ void prepare_generator(Parser *_p, Token &stmt, Token &params, int count) {
}
_p->popLabelScope();
}
Token sdone;
{
Token mcall; prepare_continuation_call(_p, mcall, "done");
_p->onExpStatement(sdone, mcall);
}
{
Token stmts0; _p->onStatementListStart(stmts0);
Token stmts1; _p->addStatement(stmts1, stmts0, scall);
Token stmts2; _p->addStatement(stmts2, stmts1, sswitch);
Token stmts3; _p->addStatement(stmts3, stmts2, stmt);
Token stmts4; _p->addStatement(stmts4, stmts3, sdone);
stmt.reset();
_p->finishStatement(stmt, stmts4); stmt = 1;
_p->finishStatement(stmt, stmts3); stmt = 1;
}
}
@@ -288,20 +276,6 @@ void create_generator(Parser *_p, Token &out, Token &params,
}
}
void transform_yield_break(Parser *_p, Token &out) {
// hphp_continuation_done()
Token mcall; prepare_continuation_call(_p, mcall, "done");
Token done; _p->onExpStatement(done, mcall);
// return
Token ret; _p->onReturn(ret, NULL, false);
Token stmts0; _p->onStatementListStart(stmts0);
Token stmts1; _p->addStatement(stmts1, stmts0, done);
Token stmts2; _p->addStatement(stmts2, stmts1, ret);
_p->finishStatement(out, stmts2); out = 1;
}
///////////////////////////////////////////////////////////////////////////////
static void user_attribute_check(Parser *_p) {
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+4 -4
Ver Arquivo
@@ -318,7 +318,7 @@ struct Parser : ParserBase {
X(name);
}
void onFunction(Token& out, Token* modifiers, Token& ret, Token& ref,
void onFunction(Token& out, Token* modifiers, Token& ret, Token& ref,
Token& name, Token& params, Token& stmt, Token* attr) {
X(modifiers, ret, ref, name, params, stmt, attr);
}
@@ -437,8 +437,8 @@ struct Parser : ParserBase {
X(expr);
}
void onReturn(Token &out, Token *expr, bool checkYield = true) {
X(expr, checkYield);
void onReturn(Token &out, Token *expr) {
X(expr);
}
void onYield(Token &out, Token &expr) {
@@ -484,7 +484,7 @@ struct Parser : ParserBase {
void onThrow(Token &out, Token &expr) { X(expr); }
void onClosure(Token &out, Token &ret, Token &ref, Token &params,
void onClosure(Token &out, Token &ret, Token &ref, Token &params,
Token &cparams, Token &stmts, bool is_static) {
X(ret, ref, params, cparams, stmts, is_static);
}