WIP: Implemented function_expression draft
authorDavid Teller <dteller@mozilla.com>
Mon, 31 Jul 2017 17:04:02 +0200
changeset 641364 95db7b2c5d670dd9ea6b7f65eae9713939e05a5d
parent 641363 314520b84053ade060ab3616aee187038b332bc4
child 641365 3a8a1e44a3a0533406ad7314b7fd447ede0d15a3
push id72504
push userdteller@mozilla.com
push dateSun, 06 Aug 2017 22:28:40 +0000
milestone57.0a1
WIP: Implemented function_expression MozReview-Commit-ID: 59C9QeFoBO5
js/src/frontend/BinSource.cpp
--- 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) {