--- a/js/src/frontend/BinSource.cpp
+++ b/js/src/frontend/BinSource.cpp
@@ -1055,116 +1055,134 @@ ASTReader::parseStatement(SimpleTokenRea
Unused << body.release();
out = Move(result);
break;
}
case BinKind::function_declaration: {
-
- RootedAtom funName(this->cx);
- UniquePtr<ParseNode> params;
- UniquePtr<ParseNode> body;
- ScopeData scope(this->cx);
-
- for (auto field: fields) {
- switch (field) {
- case BinField::id:
- if (!this->readString(&sub, &funName)) {
- return false;
- }
- break;
- case BinField::params:
- if (!this->parsePatternList(&sub, params)) {
- return false;
- }
- break;
- case BinField::body:
- if (!this->parseStatement(&sub, body)) {
- return false;
- }
- break;
- case BinField::binjs_scope:
- if (!this->parseScope(&sub, scope)) {
- return false;
- }
- break;
- default:
- return this->raiseError();
- }
- }
-
- if (!funName || !params || !body || !scope.isSome()) {
- return this->raiseError();
- }
-
- RootedFunction fun(this->cx,
- NewFunctionWithProto(this->cx,
- /*native*/nullptr,
- /*nargs ?*/0,
- /*flags */ JSFunction::INTERPRETED_NORMAL,
- /*enclosing env*/nullptr,
- /*name*/ funName,
- /*proto*/ nullptr,
- /*alloc*/gc::AllocKind::FUNCTION,
- TenuredObject
- ));
- if (!fun) {
+ UniquePtr<ParseNode> result;
+ if (!this->parseFunctionAux(&sub, kind, fields, result)) {
return false;
}
- FunctionBox* funbox = new_<FunctionBox>(this->cx,
- this->alloc,
- this->traceListHead,
- fun,
- /*toStringStart*/0,
- /*Directives*/this->currentDirectives(),
- /*extraWarning*/false,
- GeneratorKind::NotGenerator,
- FunctionAsyncKind::SyncFunction
- );
- if (!funbox) {
- return false;
- }
- this->traceListHead = funbox;
-
- MOZ_ASSERT(params->isArity(PN_LIST));
- params->setKind(PNK_PARAMSBODY);
- params->setOp(JSOP_NOP);
-
- MOZ_ASSERT(body->getKind() == PNK_STATEMENTLIST); // FIXME: If that's not the case, promote to PNK_STATEMENTLIST
- params->append(body.release());
-
- UniquePtr<ParseNode> result(new_<CodeNode>(PNK_FUNCTION, JSOP_NOP, TokenPos()));
- if (!result) {
- return false;
- }
- result->pn_funbox = funbox;
- result->pn_body = params.release();
-
out = Move(result);
-
- // FIXME: Scope
break;
}
case BinKind::variable_declaration:
if (!this->parseVariableDeclarationAux(&sub, kind, fields, out)) {
return false;
}
break;
default:
return this->raiseError();
}
return true;
}
bool
+ASTReader::parseFunctionAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out) {
+ MOZ_ASSERT(kind == BinKind::function_declaration || kind == BinKind::function_expression);
+ if (out) {
+ return this->raiseError();
+ }
+
+ RootedAtom funName(this->cx);
+ UniquePtr<ParseNode> params;
+ UniquePtr<ParseNode> body;
+ ScopeData scope(this->cx);
+
+ for (auto field: fields) {
+ switch (field) {
+ case BinField::id:
+ if (!this->readString(reader, &funName)) {
+ return false;
+ }
+ break;
+ case BinField::params:
+ if (!this->parsePatternList(reader, params)) {
+ return false;
+ }
+ break;
+ case BinField::body:
+ if (!this->parseStatement(reader, body)) {
+ return false;
+ }
+ break;
+ case BinField::binjs_scope:
+ if (!this->parseScope(reader, scope)) {
+ return false;
+ }
+ break;
+ default:
+ return this->raiseError();
+ }
+ }
+
+ if (!params || !body || !scope.isSome()) {
+ return this->raiseError();
+ }
+
+ if (kind == BinKind::function_declaration && !funName) {
+ // The name is compulsory only for funciton declarations.
+ return this->raiseError();
+ }
+
+ RootedFunction fun(this->cx,
+ NewFunctionWithProto(this->cx,
+ /*native*/nullptr,
+ /*nargs ?*/0,
+ /*flags */ JSFunction::INTERPRETED_NORMAL,
+ /*enclosing env*/nullptr,
+ /*name*/ funName,
+ /*proto*/ nullptr,
+ /*alloc*/gc::AllocKind::FUNCTION,
+ TenuredObject
+ ));
+ if (!fun) {
+ return false;
+ }
+
+ FunctionBox* funbox = new_<FunctionBox>(this->cx,
+ this->alloc,
+ this->traceListHead,
+ fun,
+ /*toStringStart*/0,
+ /*Directives*/this->currentDirectives(),
+ /*extraWarning*/false,
+ GeneratorKind::NotGenerator,
+ FunctionAsyncKind::SyncFunction
+ );
+ if (!funbox) {
+ return false;
+ }
+ this->traceListHead = funbox;
+
+ MOZ_ASSERT(params->isArity(PN_LIST));
+ params->setKind(PNK_PARAMSBODY);
+ params->setOp(JSOP_NOP);
+
+ MOZ_ASSERT(body->getKind() == PNK_STATEMENTLIST); // FIXME: If that's not the case, promote to PNK_STATEMENTLIST
+ params->append(body.release());
+
+ UniquePtr<ParseNode> result(new_<CodeNode>(PNK_FUNCTION, JSOP_NOP, TokenPos()));
+ if (!result) {
+ return false;
+ }
+ result->pn_funbox = funbox;
+ result->pn_body = params.release();
+
+ out = Move(result);
+ return true;
+}
+
+bool
ASTReader::parseVariableDeclarationAux(SimpleTokenReader* reader, const BinKind name, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out) {
if (!out) {
return this->raiseError();
}
ParseNodeKind kind = PNK_LIMIT;
JSOp op = JSOP_NOP;
UniquePtr<ParseNode> result;
@@ -1504,19 +1522,25 @@ ASTReader::parseExpression(SimpleTokenRe
MOZ_ASSERT(iter->pn_right != nullptr);
}
result->setKind(PNK_OBJECT);
result->setOp(JSOP_NEWINIT);
out = Move(result);
break;
}
- case BinKind::function_expression:
- // FIXME: Implement
+ case BinKind::function_expression: {
+ UniquePtr<ParseNode> result;
+ if (!this->parseFunctionAux(&sub, kind, fields, result)) {
+ return false;
+ }
+ result->setOp(JSOP_LAMBDA);
+ out = Move(result);
break;
+ }
case BinKind::unary_expression:
case BinKind::update_expression: {
UniquePtr<ParseNode> expr;
std::string operation;
Maybe<bool> prefix; // FIXME: Ignored for unary_expression?
for (auto field: fields) {