WIP: parseExpressionAux draft
authorDavid Teller <dteller@mozilla.com>
Fri, 04 Aug 2017 23:08:38 +0200
changeset 641380 c3a8b7d4a349bc402bbea1080d3cdaed95f6c25c
parent 641379 1dc1228db3f0bb3ea9fcfed60e4f459abb53c48a
child 641381 4ccb7cb527a3bce949786b19751d94ebf0f2c1bf
push id72504
push userdteller@mozilla.com
push dateSun, 06 Aug 2017 22:28:40 +0000
milestone57.0a1
WIP: parseExpressionAux MozReview-Commit-ID: 5I4NCZP3plF
js/src/frontend/BinSource.cpp
--- a/js/src/frontend/BinSource.cpp
+++ b/js/src/frontend/BinSource.cpp
@@ -1310,724 +1310,17 @@ ASTReader::parseExpression(SimpleTokenRe
     SimpleTokenReader::BinFields fields(this->cx);
     SimpleTokenReader sub(this->cx);
     BinKind kind;
 
     if (!reader->taggedTuple(kind, fields, &sub)) {
         return false;
     }
 
-    switch (kind) {
-        case BinKind::binjs_null:
-            return true;
-        case BinKind::identifier: {
-            Rooted<PropertyName*> id(this->cx);
-            for (auto field: fields) {
-                switch (field) {
-                    case BinField::name:
-                        if (!this->readString(&sub, &id)) {
-                            return false;
-                        }
-                        break;
-                    default:
-                        return this->raiseError();
-                }
-            }
-
-            if (!id) {
-                return this->raiseError();
-            }
-
-            UniquePtr<ParseNode> result(new_<NameNode>(PNK_NAME, JSOP_GETNAME, id, TokenPos()));
-            if (!result) {
-                return false;
-            }
-
-            out = Move(result);
-            break;
-        }
-        case BinKind::boolean_literal: {
-            Maybe<bool> value;
-            for (auto field: fields) {
-                switch (field) {
-                    case BinField::value:
-                        if (!this->readBool(&sub, value)) {
-                            return false;
-                        }
-                        break;
-                    default:
-                        return this->raiseError();
-                }
-            }
-
-            if (!value) {
-                return this->raiseError();
-            }
-
-            UniquePtr<ParseNode> result(new_<BooleanLiteral>(*value, TokenPos()));
-            if (!result) {
-                return false;
-            }
-
-            out = Move(result);
-            break;
-        }
-        case BinKind::directive_literal:
-            // A directive is not truly a literal, so this doesn't make sense
-            // here.
-            return this->raiseError();
-        case BinKind::null_literal: {
-            UniquePtr<ParseNode> result(new_<NullLiteral>(TokenPos()));
-            if (!result) {
-                return false;
-            }
-            out = Move(result);
-            break;
-        }
-        case BinKind::numeric_literal: {
-            Maybe<double> value;
-            for (auto field: fields) {
-                switch (field) {
-                    case BinField::value:
-                        if (!this->readNumber(&sub, value)) {
-                            return false;
-                        }
-                        break;
-                    default:
-                        return this->raiseError();
-                }
-            }
-
-            if (!value) {
-                return false;
-            }
-
-            UniquePtr<ParseNode> result(new_<NullaryNode>(PNK_NUMBER, TokenPos()));
-            if (!result) {
-                return false;
-            }
-            result->initNumber(*value, DecimalPoint::HasDecimal); // FIXME: Is the DecimalPoint important?
-            out = Move(result);
-            break;
-        }
-        case BinKind::regexp_literal: {
-            Maybe<std::u16string> pattern;
-            Maybe<std::string> flags;
-            for (auto field: fields) {
-                switch (field) {
-                    case BinField::pattern:
-                        if (!this->readString(&sub, pattern)) {
-                            return false;
-                        }
-                        break;
-                    case BinField::flags:
-                        if (!this->readString(&sub, flags)) {
-                            return false;
-                        }
-                        break;
-                    default:
-                        return this->raiseError();
-                }
-            }
-
-            if (!pattern || !flags) {
-                return this->raiseError();
-            }
-
-            RegExpFlag reflags = NoFlags;
-            for (char c: *flags) {
-                if (c == 'g' && !(reflags & GlobalFlag))
-                    reflags = RegExpFlag(reflags | GlobalFlag);
-                else if (c == 'i' && !(reflags & IgnoreCaseFlag))
-                    reflags = RegExpFlag(reflags | IgnoreCaseFlag);
-                else if (c == 'm' && !(reflags & MultilineFlag))
-                    reflags = RegExpFlag(reflags | MultilineFlag);
-                else if (c == 'y' && !(reflags & StickyFlag))
-                    reflags = RegExpFlag(reflags | StickyFlag);
-                else if (c == 'u' && !(reflags & UnicodeFlag))
-                    reflags = RegExpFlag(reflags | UnicodeFlag);
-                else
-                    return this->raiseError();
-            }
-
-
-            Rooted<RegExpObject*> reobj(this->cx);
-            reobj = RegExpObject::create(this->cx,
-                pattern->data(),
-                pattern->length(),
-                reflags,
-                /* options*/ nullptr,
-                /* tokenStream */ nullptr,
-                this->alloc,
-                TenuredObject);
-
-            if (!reobj) {
-                return false;
-            }
-
-
-            ObjectBox* objbox = this->newObjectBox(reobj);
-            if (!objbox) {
-                return false;
-            }
-            UniquePtr<ParseNode> result(new_<RegExpLiteral>(objbox, TokenPos()));
-            if (!result) {
-                // FIXME: I *think* that `objbox` is traced.
-                return false;
-            }
-
-            out = Move(result);
-            break;
-        }
-        case BinKind::string_literal: {
-            RootedAtom value(this->cx);
-            for (auto field: fields) {
-                switch (field) {
-                    case BinField::value:
-                        if (!this->readString(&sub, &value)) {
-                            return false;
-                        }
-                        break;
-                    default:
-                        return this->raiseError();
-                }
-            }
-
-            if (!value) {
-                return false;
-            }
-
-            UniquePtr<ParseNode> result(new_<NullaryNode>(PNK_STRING, JSOP_NOP, TokenPos(), value));
-            if (!result) {
-                return false;
-            }
-
-            out = Move(result);
-            break;
-        }
-        case BinKind::this_expression: {
-            UniquePtr<ParseNode> thisName;
-            if (this->thisBinding() == ThisBinding::Function) {
-                thisName = UniquePtr<ParseNode>(new_<NameNode>(PNK_NAME, JSOP_GETNAME, this->cx->names().dotThis, TokenPos()));
-                if (!thisName) {
-                    return false;
-                }
-            }
-
-            UniquePtr<ParseNode> result(new_<ThisLiteral>(TokenPos(), thisName.get()));
-            if (!result) {
-                return false;
-            }
-            Unused << thisName.release();
-
-            out = Move(result);
-            break;
-        }
-        case BinKind::array_expression: {
-            UniquePtr<ParseNode> result;
-            if (!this->parseExpressionOrElisionList(&sub, result)) {
-                return false;
-            }
-
-            result->setKind(PNK_ARRAY);
-            result->setOp(JSOP_NEWINIT);
-            out = Move(result);
-            break;
-        }
-        case BinKind::object_expression: {
-            UniquePtr<ParseNode> result;
-            if (!this->parseKeyValueList(&sub, result)) {
-                return false;
-            }
-
-            for (ParseNode* iter = result.get(); iter != nullptr; iter = iter->pn_next) {
-                MOZ_ASSERT(iter->isKind(PNK_COLON));
-                MOZ_ASSERT(iter->pn_left != nullptr);
-                MOZ_ASSERT(iter->pn_right != nullptr);
-            }
-
-            result->setKind(PNK_OBJECT);
-            result->setOp(JSOP_NEWINIT);
-            out = Move(result);
-            break;
-        }
-        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) {
-                switch (field) {
-                    case BinField::operator_:
-                        if (!this->readString(&sub, operation)) {
-                            return false;
-                        }
-                        break;
-                    case BinField::prefix:
-                        if (!this->readBool(&sub, prefix)) {
-                            return false;
-                        }
-                        break;
-                    case BinField::argument:
-                        if (!this->parseExpression(&sub, expr)) {
-                            return false;
-                        }
-                        break;
-                    default:
-                        return this->raiseError();
-                }
-            }
-
-            if (!expr || operation.length() == 0 || !prefix.isSome()) {
-                return this->raiseError();
-            }
-
-            ParseNodeKind pnk = PNK_LIMIT;
-            JSOp op = JSOP_NOP;
-            if (kind == BinKind::unary_expression) {
-                if (operation == "-") {
-                    pnk = PNK_NEG;
-                    op = JSOP_NEG;
-                } else if (operation == "+") {
-                    pnk = PNK_POS;
-                    op = JSOP_POS;
-                } else if (operation == "!") {
-                    pnk = PNK_NOT;
-                    op = JSOP_NOT;
-                } else if (operation == "~") {
-                    pnk = PNK_BITNOT;
-                    op = JSOP_BITNOT;
-                } else if (operation == "typeof") {
-                    if (expr->isKind(PNK_NAME)) {
-                        pnk = PNK_TYPEOFNAME;
-                    } else {
-                        pnk = PNK_TYPEOFEXPR;
-                    }
-                } else if (operation == "void") {
-                    pnk = PNK_VOID;
-                    op = JSOP_VOID;
-                } else if (operation == "delete") {
-                    switch (expr->getKind()) {
-                        case PNK_NAME:
-                            expr->setOp(JSOP_DELNAME);
-                            pnk = PNK_DELETENAME;
-                            break;
-                        case PNK_DOT:
-                            pnk = PNK_DELETEPROP;
-                            break;
-                        case PNK_ELEM:
-                            pnk = PNK_DELETEELEM;
-                            break;
-                        default:
-                            pnk = PNK_DELETEEXPR;
-                    }
-                } else {
-                    return this->raiseError();
-                }
-            } else if (kind == BinKind::update_expression) {
-                if (operation == "++") {
-                    if (*prefix) {
-                        pnk = PNK_PREINCREMENT;
-                    } else {
-                        pnk = PNK_PREDECREMENT;
-                    }
-                } else if (operation == "--") {
-                    if (*prefix) {
-                        pnk = PNK_PREDECREMENT;
-                    } else {
-                        pnk = PNK_POSTDECREMENT;
-                    }
-                } else {
-                    return this->raiseError();
-                }
-            }
-
-            UniquePtr<ParseNode> result(new_<UnaryNode>(pnk, op, TokenPos(), expr.get()));
-            if (!result) {
-                return false;
-            }
-
-            Unused << expr.release();
-            out = Move(result);
-            break;
-        }
-        case BinKind::binary_expression: MOZ_FALLTHROUGH;
-        case BinKind::logical_expression: {
-
-            UniquePtr<ParseNode> left;
-            UniquePtr<ParseNode> right;
-            std::string operation;
-            for (auto field: fields) {
-                switch (field) {
-                    case BinField::left:
-                        if (!this->parseExpression(&sub, left)) {
-                            return false;
-                        }
-                        break;
-                    case BinField::right:
-                        if (!this->parseExpression(&sub, right)) {
-                            return false;
-                        }
-                        break;
-                    case BinField::operator_:
-                        if (!this->readString(&sub, operation)) {
-                            return false;
-                        }
-                        break;
-                    default:
-                        return this->raiseError();
-                }
-            }
-
-            if (!left || !right || operation.length() == 0) {
-                return this->raiseError();
-            }
-
-            // FIXME: Instead of std::string, we should use atoms and comparison
-            // between atom ptr.
-            // FIXME: We should probably turn associative operations into lists.
-            ParseNodeKind pnk = PNK_LIMIT;
-            JSOp op;
-            if (operation == "==") {
-                pnk = PNK_EQ;
-                op = JSOP_EQ;
-            } else if (operation == "!=") {
-                pnk = PNK_NE;
-                op = JSOP_NE;
-            } else if (operation == "===") {
-                pnk = PNK_STRICTEQ;
-                op = JSOP_STRICTEQ;
-            } else if (operation == "!==") {
-                pnk = PNK_STRICTNE;
-                op = JSOP_STRICTNE;
-            } else if (operation == "<") {
-                pnk = PNK_LT;
-                op = JSOP_LT;
-            } else if (operation == "<=") {
-                pnk = PNK_LE;
-                op = JSOP_LE;
-            } else if (operation == ">") {
-                pnk = PNK_GT;
-                op = JSOP_GT;
-            } else if (operation == ">=") {
-                pnk = PNK_GE;
-                op = JSOP_GE;
-            } else if (operation == "<<") {
-                pnk = PNK_LSH;
-                op = JSOP_LSH;
-            } else if (operation == ">>") {
-                pnk = PNK_RSH;
-                op = JSOP_RSH;
-            } else if (operation == ">>>") {
-                pnk = PNK_URSH;
-                op = JSOP_URSH;
-            } else if (operation == "+") {
-                pnk = PNK_ADD;
-                op = JSOP_ADD;
-            } else if (operation == "-") {
-                pnk = PNK_SUB;
-                op = JSOP_SUB;
-            } else if (operation == "*") {
-                pnk = PNK_STAR;
-                op = JSOP_MUL;
-            } else if (operation == "/") {
-                pnk = PNK_DIV;
-                op = JSOP_DIV;
-            } else if (operation == "%") {
-                pnk = PNK_MOD;
-                op = JSOP_MOD;
-            } else if (operation == "|") {
-                pnk = PNK_BITOR;
-                op = JSOP_BITOR;
-            } else if (operation == "^") {
-                pnk = PNK_BITXOR;
-                op = JSOP_BITXOR;
-            } else if (operation == "&") {
-                pnk = PNK_BITAND;
-                op = JSOP_BITAND;
-            } else if (operation == "in") {
-                pnk = PNK_IN;
-                op = JSOP_IN;
-            } else if (operation == "instanceof") {
-                pnk = PNK_INSTANCEOF;
-                op = JSOP_INSTANCEOF;
-            } else if (operation == "||") {
-                pnk = PNK_OR;
-                op = JSOP_OR;
-            } else if (operation == "&&" ) {
-                pnk = PNK_AND;
-                op = JSOP_AND;
-            } else {
-                return this->raiseError();
-            }
-
-            UniquePtr<ParseNode> list(new_<ListNode>(pnk, JSOP_NOP, TokenPos()));
-            if (!list) {
-                return false;
-            }
-            list->makeEmpty();
-            list->append(left.release());
-            list->append(right.release());
-            out = Move(list);
-            break;
-        }
-        case BinKind::assignment_expression: {
-            UniquePtr<ParseNode> left;
-            UniquePtr<ParseNode> right;
-            std::string operation;
-            for (auto field: fields) {
-                switch (field) {
-                    case BinField::left:
-                        if (!this->parseExpression(&sub, left)) {
-                            return false;
-                        }
-                        break;
-                    case BinField::right:
-                        if (!this->parseExpression(&sub, right)) {
-                            return false;
-                        }
-                        break;
-                    case BinField::operator_:
-                        if (!this->readString(&sub, operation)) {
-                            return false;
-                        }
-                        break;
-                    default:
-                        return this->raiseError();
-                }
-            }
-
-            if (!left || !right || operation.length() == 0) {
-                return this->raiseError();
-            }
-
-            // FIXME: Instead of std::string, we should use atoms and comparison
-            // between atom ptr.
-            // FIXME: We should probably turn associative operations into lists.
-            ParseNodeKind pnk = PNK_LIMIT;
-            JSOp op = JSOP_NOP;
-            if (operation == "=") {
-                pnk = PNK_ASSIGN;
-            } else if (operation == "+=") {
-                pnk = PNK_ADDASSIGN;
-                op = JSOP_ADD;
-            } else if (operation == "-=") {
-                pnk = PNK_SUBASSIGN;
-                op = JSOP_SUB;
-            } else if (operation == "*=") {
-                pnk = PNK_MULASSIGN;
-                op = JSOP_MUL;
-            } else if (operation == "/=") {
-                pnk = PNK_DIVASSIGN;
-                op = JSOP_DIV;
-            } else if (operation == "%=") {
-                pnk = PNK_MODASSIGN;
-                op = JSOP_MOD;
-            } else if (operation == "<<=") {
-                pnk = PNK_LSHASSIGN;
-                op = JSOP_LSH;
-            } else if (operation == ">>=") {
-                pnk = PNK_RSHASSIGN;
-                op = JSOP_RSH;
-            } else if (operation == ">>>=") {
-                pnk = PNK_URSHASSIGN;
-                op = JSOP_URSH;
-            } else if (operation == "|=") {
-                pnk = PNK_BITORASSIGN;
-                op = JSOP_BITOR;
-            } else if (operation == "^=") {
-                pnk = PNK_BITXORASSIGN;
-                op = JSOP_BITXOR;
-            } else if (operation == "&=") {
-                pnk = PNK_BITANDASSIGN;
-                op = JSOP_BITAND;
-            } else {
-                return this->raiseError();
-            }
-
-            UniquePtr<ParseNode> list(new_<BinaryNode>(pnk, JSOP_NOP, TokenPos(), left.get(), right.get()));
-            if (!list) {
-                return false;
-            }
-            Unused << left.release();
-            Unused << right.release();
-
-            out = Move(list);
-            break;
-        }
-        case BinKind::member_expression: {
-            UniquePtr<ParseNode> object;
-            UniquePtr<ParseNode> property;
-            Maybe<bool> isComputed;
-
-            for (auto field: fields) {
-                switch (field) {
-                    case BinField::object:
-                        if (!this->parseExpression(&sub, object)) {
-                            return false;
-                        }
-                        break;
-                    case BinField::property:
-                        if (!this->parseExpression(&sub, property)) {
-                            return false;
-                        }
-                        break;
-                    case BinField::computed:
-                        if (!this->readBool(&sub, isComputed)) {
-                            return false;
-                        }
-                        break;
-                    default:
-                        return this->raiseError();
-                }
-            }
-
-            if (!object || !property || !isComputed) {
-                return this->raiseError();
-            }
-
-            UniquePtr<ParseNode> result;
-            if (*isComputed) {
-                if (!property->isKind(PNK_NAME)) {
-                    return this->raiseError();
-                }
-                PropertyName* name = property->pn_atom->asPropertyName();
-                result = UniquePtr<ParseNode>(new_<PropertyAccess>(object.get(), name, 0, 0));
-            } else {
-                result = UniquePtr<ParseNode>(new_<PropertyByValue>(object.get(), property.get(), 0, 0));
-            }
-            if (!result) {
-                return false;
-            }
-            out = Move(result);
-
-
-            Unused << object.release();
-            Unused << property.release();
-            break;
-        }
-        case BinKind::conditional_expression: {
-            UniquePtr<ParseNode> test;
-            UniquePtr<ParseNode> alternate;
-            UniquePtr<ParseNode> consequent;
-
-            for (auto field: fields) {
-                switch (field) {
-                    case BinField::test:
-                        if (!this->parseExpression(&sub, test)) {
-                            return false;
-                        }
-                        break;
-                    case BinField::alternate:
-                        if (!this->parseExpression(&sub, alternate)) {
-                            return false;
-                        }
-                        break;
-                    case BinField::consequent:
-                        if (!this->parseExpression(&sub, consequent)) {
-                            return false;
-                        }
-                        break;
-                    default:
-                        return this->raiseError();
-                }
-            }
-
-            if (!test || !alternate || !consequent) {
-                return this->raiseError();
-            }
-
-            UniquePtr<ParseNode> result(new_<ConditionalExpression>(test.get(), consequent.get(), alternate.get()));
-            if (!result) {
-                return false;
-            }
-
-            Unused << test.release();
-            Unused << alternate.release();
-            Unused << consequent.release();
-
-            out = Move(result);
-            break;
-        }
-        case BinKind::call_expression: MOZ_FALLTHROUGH;
-        case BinKind::new_expression: {
-            UniquePtr<ParseNode> callee;
-            UniquePtr<ParseNode> arguments;
-
-            for (auto field: fields) {
-                switch (field) {
-                    case BinField::callee:
-                        if (!this->parseExpression(&sub, callee)) {
-                            return false;
-                        }
-                        break;
-                    case BinField::arguments:
-                        if (!this->parseExpressionOrElisionList(&sub, arguments)) {
-                            return false;
-                        }
-                        break;
-                    default:
-                        return this->raiseError();
-                }
-            }
-
-            if (!callee || !arguments) {
-                return this->raiseError();
-            }
-
-            ParseNodeKind pnk =
-                kind == BinKind::call_expression
-                ? PNK_CALL
-                : PNK_NEW;
-            UniquePtr<ParseNode> result(new_<ListNode>(pnk, TokenPos()));
-            result->initList(arguments.release());
-            result->prepend(callee.release());
-
-            out = Move(result);
-            break;
-        }
-        case BinKind::sequence_expression: {
-            UniquePtr<ParseNode> sequence;
-
-            for (auto field: fields) {
-                switch (field) {
-                    case BinField::expressions:
-                        if (!this->parseExpressionOrElisionList(&sub, sequence)) {
-                            return false;
-                        }
-                        break;
-                    default:
-                        return this->raiseError();
-                }
-            }
-
-            if (!sequence) {
-                this->raiseError();
-            }
-
-            sequence->setKind(PNK_COMMA);
-            out = Move(sequence);
-            break;
-        }
-        default:
-            return this->raiseError();
-    }
-
-    return false;
+    return this->parseExpressionAux(&sub, kind, fields, out);
 }
 
 bool
 ASTReader::parseExpressionStatementAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out) {
     MOZ_ASSERT(kind == BinKind::expression_statement);
     if (out) {
         return this->raiseError();
     }
@@ -2196,16 +1489,727 @@ ASTReader::parseSwitchCaseList(SimpleTok
 
         result->append(case_.release());
     }
 
     out = Move(result);
     return true;
 }
 
+bool
+ASTReader::parseExpressionAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out) {
+        switch (kind) {
+            case BinKind::binjs_null:
+                return true;
+            case BinKind::identifier: {
+                Rooted<PropertyName*> id(this->cx);
+                for (auto field: fields) {
+                    switch (field) {
+                        case BinField::name:
+                            if (!this->readString(reader, &id)) {
+                                return false;
+                            }
+                            break;
+                        default:
+                            return this->raiseError();
+                    }
+                }
+
+                if (!id) {
+                    return this->raiseError();
+                }
+
+                UniquePtr<ParseNode> result(new_<NameNode>(PNK_NAME, JSOP_GETNAME, id, TokenPos()));
+                if (!result) {
+                    return false;
+                }
+
+                out = Move(result);
+                break;
+            }
+            case BinKind::boolean_literal: {
+                Maybe<bool> value;
+                for (auto field: fields) {
+                    switch (field) {
+                        case BinField::value:
+                            if (!this->readBool(reader, value)) {
+                                return false;
+                            }
+                            break;
+                        default:
+                            return this->raiseError();
+                    }
+                }
+
+                if (!value) {
+                    return this->raiseError();
+                }
+
+                UniquePtr<ParseNode> result(new_<BooleanLiteral>(*value, TokenPos()));
+                if (!result) {
+                    return false;
+                }
+
+                out = Move(result);
+                break;
+            }
+            case BinKind::directive_literal:
+                // A directive is not truly a literal, so this doesn't make sense
+                // here.
+                return this->raiseError();
+            case BinKind::null_literal: {
+                UniquePtr<ParseNode> result(new_<NullLiteral>(TokenPos()));
+                if (!result) {
+                    return false;
+                }
+                out = Move(result);
+                break;
+            }
+            case BinKind::numeric_literal: {
+                Maybe<double> value;
+                for (auto field: fields) {
+                    switch (field) {
+                        case BinField::value:
+                            if (!this->readNumber(reader, value)) {
+                                return false;
+                            }
+                            break;
+                        default:
+                            return this->raiseError();
+                    }
+                }
+
+                if (!value) {
+                    return false;
+                }
+
+                UniquePtr<ParseNode> result(new_<NullaryNode>(PNK_NUMBER, TokenPos()));
+                if (!result) {
+                    return false;
+                }
+                result->initNumber(*value, DecimalPoint::HasDecimal); // FIXME: Is the DecimalPoint important?
+                out = Move(result);
+                break;
+            }
+            case BinKind::regexp_literal: {
+                Maybe<std::u16string> pattern;
+                Maybe<std::string> flags;
+                for (auto field: fields) {
+                    switch (field) {
+                        case BinField::pattern:
+                            if (!this->readString(reader, pattern)) {
+                                return false;
+                            }
+                            break;
+                        case BinField::flags:
+                            if (!this->readString(reader, flags)) {
+                                return false;
+                            }
+                            break;
+                        default:
+                            return this->raiseError();
+                    }
+                }
+
+                if (!pattern || !flags) {
+                    return this->raiseError();
+                }
+
+                RegExpFlag reflags = NoFlags;
+                for (char c: *flags) {
+                    if (c == 'g' && !(reflags & GlobalFlag))
+                        reflags = RegExpFlag(reflags | GlobalFlag);
+                    else if (c == 'i' && !(reflags & IgnoreCaseFlag))
+                        reflags = RegExpFlag(reflags | IgnoreCaseFlag);
+                    else if (c == 'm' && !(reflags & MultilineFlag))
+                        reflags = RegExpFlag(reflags | MultilineFlag);
+                    else if (c == 'y' && !(reflags & StickyFlag))
+                        reflags = RegExpFlag(reflags | StickyFlag);
+                    else if (c == 'u' && !(reflags & UnicodeFlag))
+                        reflags = RegExpFlag(reflags | UnicodeFlag);
+                    else
+                        return this->raiseError();
+                }
+
+
+                Rooted<RegExpObject*> reobj(this->cx);
+                reobj = RegExpObject::create(this->cx,
+                    pattern->data(),
+                    pattern->length(),
+                    reflags,
+                    /* options*/ nullptr,
+                    /* tokenStream */ nullptr,
+                    this->alloc,
+                    TenuredObject);
+
+                if (!reobj) {
+                    return false;
+                }
+
+
+                ObjectBox* objbox = this->newObjectBox(reobj);
+                if (!objbox) {
+                    return false;
+                }
+                UniquePtr<ParseNode> result(new_<RegExpLiteral>(objbox, TokenPos()));
+                if (!result) {
+                    // FIXME: I *think* that `objbox` is traced.
+                    return false;
+                }
+
+                out = Move(result);
+                break;
+            }
+            case BinKind::string_literal: {
+                RootedAtom value(this->cx);
+                for (auto field: fields) {
+                    switch (field) {
+                        case BinField::value:
+                            if (!this->readString(reader, &value)) {
+                                return false;
+                            }
+                            break;
+                        default:
+                            return this->raiseError();
+                    }
+                }
+
+                if (!value) {
+                    return false;
+                }
+
+                UniquePtr<ParseNode> result(new_<NullaryNode>(PNK_STRING, JSOP_NOP, TokenPos(), value));
+                if (!result) {
+                    return false;
+                }
+
+                out = Move(result);
+                break;
+            }
+            case BinKind::this_expression: {
+                UniquePtr<ParseNode> thisName;
+                if (this->thisBinding() == ThisBinding::Function) {
+                    thisName = UniquePtr<ParseNode>(new_<NameNode>(PNK_NAME, JSOP_GETNAME, this->cx->names().dotThis, TokenPos()));
+                    if (!thisName) {
+                        return false;
+                    }
+                }
+
+                UniquePtr<ParseNode> result(new_<ThisLiteral>(TokenPos(), thisName.get()));
+                if (!result) {
+                    return false;
+                }
+                Unused << thisName.release();
+
+                out = Move(result);
+                break;
+            }
+            case BinKind::array_expression: {
+                UniquePtr<ParseNode> result;
+                if (!this->parseExpressionOrElisionList(reader, result)) {
+                    return false;
+                }
+
+                result->setKind(PNK_ARRAY);
+                result->setOp(JSOP_NEWINIT);
+                out = Move(result);
+                break;
+            }
+            case BinKind::object_expression: {
+                UniquePtr<ParseNode> result;
+                if (!this->parseKeyValueList(reader, result)) {
+                    return false;
+                }
+
+                for (ParseNode* iter = result.get(); iter != nullptr; iter = iter->pn_next) {
+                    MOZ_ASSERT(iter->isKind(PNK_COLON));
+                    MOZ_ASSERT(iter->pn_left != nullptr);
+                    MOZ_ASSERT(iter->pn_right != nullptr);
+                }
+
+                result->setKind(PNK_OBJECT);
+                result->setOp(JSOP_NEWINIT);
+                out = Move(result);
+                break;
+            }
+            case BinKind::function_expression: {
+                UniquePtr<ParseNode> result;
+                if (!this->parseFunctionAux(reader, 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) {
+                    switch (field) {
+                        case BinField::operator_:
+                            if (!this->readString(reader, operation)) {
+                                return false;
+                            }
+                            break;
+                        case BinField::prefix:
+                            if (!this->readBool(reader, prefix)) {
+                                return false;
+                            }
+                            break;
+                        case BinField::argument:
+                            if (!this->parseExpression(reader, expr)) {
+                                return false;
+                            }
+                            break;
+                        default:
+                            return this->raiseError();
+                    }
+                }
+
+                if (!expr || operation.length() == 0 || !prefix.isSome()) {
+                    return this->raiseError();
+                }
+
+                ParseNodeKind pnk = PNK_LIMIT;
+                JSOp op = JSOP_NOP;
+                if (kind == BinKind::unary_expression) {
+                    if (operation == "-") {
+                        pnk = PNK_NEG;
+                        op = JSOP_NEG;
+                    } else if (operation == "+") {
+                        pnk = PNK_POS;
+                        op = JSOP_POS;
+                    } else if (operation == "!") {
+                        pnk = PNK_NOT;
+                        op = JSOP_NOT;
+                    } else if (operation == "~") {
+                        pnk = PNK_BITNOT;
+                        op = JSOP_BITNOT;
+                    } else if (operation == "typeof") {
+                        if (expr->isKind(PNK_NAME)) {
+                            pnk = PNK_TYPEOFNAME;
+                        } else {
+                            pnk = PNK_TYPEOFEXPR;
+                        }
+                    } else if (operation == "void") {
+                        pnk = PNK_VOID;
+                        op = JSOP_VOID;
+                    } else if (operation == "delete") {
+                        switch (expr->getKind()) {
+                            case PNK_NAME:
+                                expr->setOp(JSOP_DELNAME);
+                                pnk = PNK_DELETENAME;
+                                break;
+                            case PNK_DOT:
+                                pnk = PNK_DELETEPROP;
+                                break;
+                            case PNK_ELEM:
+                                pnk = PNK_DELETEELEM;
+                                break;
+                            default:
+                                pnk = PNK_DELETEEXPR;
+                        }
+                    } else {
+                        return this->raiseError();
+                    }
+                } else if (kind == BinKind::update_expression) {
+                    if (operation == "++") {
+                        if (*prefix) {
+                            pnk = PNK_PREINCREMENT;
+                        } else {
+                            pnk = PNK_PREDECREMENT;
+                        }
+                    } else if (operation == "--") {
+                        if (*prefix) {
+                            pnk = PNK_PREDECREMENT;
+                        } else {
+                            pnk = PNK_POSTDECREMENT;
+                        }
+                    } else {
+                        return this->raiseError();
+                    }
+                }
+
+                UniquePtr<ParseNode> result(new_<UnaryNode>(pnk, op, TokenPos(), expr.get()));
+                if (!result) {
+                    return false;
+                }
+
+                Unused << expr.release();
+                out = Move(result);
+                break;
+            }
+            case BinKind::binary_expression: MOZ_FALLTHROUGH;
+            case BinKind::logical_expression: {
+
+                UniquePtr<ParseNode> left;
+                UniquePtr<ParseNode> right;
+                std::string operation;
+                for (auto field: fields) {
+                    switch (field) {
+                        case BinField::left:
+                            if (!this->parseExpression(reader, left)) {
+                                return false;
+                            }
+                            break;
+                        case BinField::right:
+                            if (!this->parseExpression(reader, right)) {
+                                return false;
+                            }
+                            break;
+                        case BinField::operator_:
+                            if (!this->readString(reader, operation)) {
+                                return false;
+                            }
+                            break;
+                        default:
+                            return this->raiseError();
+                    }
+                }
+
+                if (!left || !right || operation.length() == 0) {
+                    return this->raiseError();
+                }
+
+                // FIXME: Instead of std::string, we should use atoms and comparison
+                // between atom ptr.
+                // FIXME: We should probably turn associative operations into lists.
+                ParseNodeKind pnk = PNK_LIMIT;
+                JSOp op;
+                if (operation == "==") {
+                    pnk = PNK_EQ;
+                    op = JSOP_EQ;
+                } else if (operation == "!=") {
+                    pnk = PNK_NE;
+                    op = JSOP_NE;
+                } else if (operation == "===") {
+                    pnk = PNK_STRICTEQ;
+                    op = JSOP_STRICTEQ;
+                } else if (operation == "!==") {
+                    pnk = PNK_STRICTNE;
+                    op = JSOP_STRICTNE;
+                } else if (operation == "<") {
+                    pnk = PNK_LT;
+                    op = JSOP_LT;
+                } else if (operation == "<=") {
+                    pnk = PNK_LE;
+                    op = JSOP_LE;
+                } else if (operation == ">") {
+                    pnk = PNK_GT;
+                    op = JSOP_GT;
+                } else if (operation == ">=") {
+                    pnk = PNK_GE;
+                    op = JSOP_GE;
+                } else if (operation == "<<") {
+                    pnk = PNK_LSH;
+                    op = JSOP_LSH;
+                } else if (operation == ">>") {
+                    pnk = PNK_RSH;
+                    op = JSOP_RSH;
+                } else if (operation == ">>>") {
+                    pnk = PNK_URSH;
+                    op = JSOP_URSH;
+                } else if (operation == "+") {
+                    pnk = PNK_ADD;
+                    op = JSOP_ADD;
+                } else if (operation == "-") {
+                    pnk = PNK_SUB;
+                    op = JSOP_SUB;
+                } else if (operation == "*") {
+                    pnk = PNK_STAR;
+                    op = JSOP_MUL;
+                } else if (operation == "/") {
+                    pnk = PNK_DIV;
+                    op = JSOP_DIV;
+                } else if (operation == "%") {
+                    pnk = PNK_MOD;
+                    op = JSOP_MOD;
+                } else if (operation == "|") {
+                    pnk = PNK_BITOR;
+                    op = JSOP_BITOR;
+                } else if (operation == "^") {
+                    pnk = PNK_BITXOR;
+                    op = JSOP_BITXOR;
+                } else if (operation == "&") {
+                    pnk = PNK_BITAND;
+                    op = JSOP_BITAND;
+                } else if (operation == "in") {
+                    pnk = PNK_IN;
+                    op = JSOP_IN;
+                } else if (operation == "instanceof") {
+                    pnk = PNK_INSTANCEOF;
+                    op = JSOP_INSTANCEOF;
+                } else if (operation == "||") {
+                    pnk = PNK_OR;
+                    op = JSOP_OR;
+                } else if (operation == "&&" ) {
+                    pnk = PNK_AND;
+                    op = JSOP_AND;
+                } else {
+                    return this->raiseError();
+                }
+
+                UniquePtr<ParseNode> list(new_<ListNode>(pnk, JSOP_NOP, TokenPos()));
+                if (!list) {
+                    return false;
+                }
+                list->makeEmpty();
+                list->append(left.release());
+                list->append(right.release());
+                out = Move(list);
+                break;
+            }
+            case BinKind::assignment_expression: {
+                UniquePtr<ParseNode> left;
+                UniquePtr<ParseNode> right;
+                std::string operation;
+                for (auto field: fields) {
+                    switch (field) {
+                        case BinField::left:
+                            if (!this->parseExpression(reader, left)) {
+                                return false;
+                            }
+                            break;
+                        case BinField::right:
+                            if (!this->parseExpression(reader, right)) {
+                                return false;
+                            }
+                            break;
+                        case BinField::operator_:
+                            if (!this->readString(reader, operation)) {
+                                return false;
+                            }
+                            break;
+                        default:
+                            return this->raiseError();
+                    }
+                }
+
+                if (!left || !right || operation.length() == 0) {
+                    return this->raiseError();
+                }
+
+                // FIXME: Instead of std::string, we should use atoms and comparison
+                // between atom ptr.
+                // FIXME: We should probably turn associative operations into lists.
+                ParseNodeKind pnk = PNK_LIMIT;
+                JSOp op = JSOP_NOP;
+                if (operation == "=") {
+                    pnk = PNK_ASSIGN;
+                } else if (operation == "+=") {
+                    pnk = PNK_ADDASSIGN;
+                    op = JSOP_ADD;
+                } else if (operation == "-=") {
+                    pnk = PNK_SUBASSIGN;
+                    op = JSOP_SUB;
+                } else if (operation == "*=") {
+                    pnk = PNK_MULASSIGN;
+                    op = JSOP_MUL;
+                } else if (operation == "/=") {
+                    pnk = PNK_DIVASSIGN;
+                    op = JSOP_DIV;
+                } else if (operation == "%=") {
+                    pnk = PNK_MODASSIGN;
+                    op = JSOP_MOD;
+                } else if (operation == "<<=") {
+                    pnk = PNK_LSHASSIGN;
+                    op = JSOP_LSH;
+                } else if (operation == ">>=") {
+                    pnk = PNK_RSHASSIGN;
+                    op = JSOP_RSH;
+                } else if (operation == ">>>=") {
+                    pnk = PNK_URSHASSIGN;
+                    op = JSOP_URSH;
+                } else if (operation == "|=") {
+                    pnk = PNK_BITORASSIGN;
+                    op = JSOP_BITOR;
+                } else if (operation == "^=") {
+                    pnk = PNK_BITXORASSIGN;
+                    op = JSOP_BITXOR;
+                } else if (operation == "&=") {
+                    pnk = PNK_BITANDASSIGN;
+                    op = JSOP_BITAND;
+                } else {
+                    return this->raiseError();
+                }
+
+                UniquePtr<ParseNode> list(new_<BinaryNode>(pnk, JSOP_NOP, TokenPos(), left.get(), right.get()));
+                if (!list) {
+                    return false;
+                }
+                Unused << left.release();
+                Unused << right.release();
+
+                out = Move(list);
+                break;
+            }
+            case BinKind::member_expression: {
+                UniquePtr<ParseNode> object;
+                UniquePtr<ParseNode> property;
+                Maybe<bool> isComputed;
+
+                for (auto field: fields) {
+                    switch (field) {
+                        case BinField::object:
+                            if (!this->parseExpression(reader, object)) {
+                                return false;
+                            }
+                            break;
+                        case BinField::property:
+                            if (!this->parseExpression(reader, property)) {
+                                return false;
+                            }
+                            break;
+                        case BinField::computed:
+                            if (!this->readBool(reader, isComputed)) {
+                                return false;
+                            }
+                            break;
+                        default:
+                            return this->raiseError();
+                    }
+                }
+
+                if (!object || !property || !isComputed) {
+                    return this->raiseError();
+                }
+
+                UniquePtr<ParseNode> result;
+                if (*isComputed) {
+                    if (!property->isKind(PNK_NAME)) {
+                        return this->raiseError();
+                    }
+                    PropertyName* name = property->pn_atom->asPropertyName();
+                    result = UniquePtr<ParseNode>(new_<PropertyAccess>(object.get(), name, 0, 0));
+                } else {
+                    result = UniquePtr<ParseNode>(new_<PropertyByValue>(object.get(), property.get(), 0, 0));
+                }
+                if (!result) {
+                    return false;
+                }
+                out = Move(result);
+
+
+                Unused << object.release();
+                Unused << property.release();
+                break;
+            }
+            case BinKind::conditional_expression: {
+                UniquePtr<ParseNode> test;
+                UniquePtr<ParseNode> alternate;
+                UniquePtr<ParseNode> consequent;
+
+                for (auto field: fields) {
+                    switch (field) {
+                        case BinField::test:
+                            if (!this->parseExpression(reader, test)) {
+                                return false;
+                            }
+                            break;
+                        case BinField::alternate:
+                            if (!this->parseExpression(reader, alternate)) {
+                                return false;
+                            }
+                            break;
+                        case BinField::consequent:
+                            if (!this->parseExpression(reader, consequent)) {
+                                return false;
+                            }
+                            break;
+                        default:
+                            return this->raiseError();
+                    }
+                }
+
+                if (!test || !alternate || !consequent) {
+                    return this->raiseError();
+                }
+
+                UniquePtr<ParseNode> result(new_<ConditionalExpression>(test.get(), consequent.get(), alternate.get()));
+                if (!result) {
+                    return false;
+                }
+
+                Unused << test.release();
+                Unused << alternate.release();
+                Unused << consequent.release();
+
+                out = Move(result);
+                break;
+            }
+            case BinKind::call_expression: MOZ_FALLTHROUGH;
+            case BinKind::new_expression: {
+                UniquePtr<ParseNode> callee;
+                UniquePtr<ParseNode> arguments;
+
+                for (auto field: fields) {
+                    switch (field) {
+                        case BinField::callee:
+                            if (!this->parseExpression(reader, callee)) {
+                                return false;
+                            }
+                            break;
+                        case BinField::arguments:
+                            if (!this->parseExpressionOrElisionList(reader, arguments)) {
+                                return false;
+                            }
+                            break;
+                        default:
+                            return this->raiseError();
+                    }
+                }
+
+                if (!callee || !arguments) {
+                    return this->raiseError();
+                }
+
+                ParseNodeKind pnk =
+                    kind == BinKind::call_expression
+                    ? PNK_CALL
+                    : PNK_NEW;
+                UniquePtr<ParseNode> result(new_<ListNode>(pnk, TokenPos()));
+                result->initList(arguments.release());
+                result->prepend(callee.release());
+
+                out = Move(result);
+                break;
+            }
+            case BinKind::sequence_expression: {
+                UniquePtr<ParseNode> sequence;
+
+                for (auto field: fields) {
+                    switch (field) {
+                        case BinField::expressions:
+                            if (!this->parseExpressionOrElisionList(reader, sequence)) {
+                                return false;
+                            }
+                            break;
+                        default:
+                            return this->raiseError();
+                    }
+                }
+
+                if (!sequence) {
+                    this->raiseError();
+                }
+
+                sequence->setKind(PNK_COMMA);
+                out = Move(sequence);
+                break;
+            }
+            default:
+                return this->raiseError();
+        }
+
+        return true;
+}
 
 bool
 ASTReader::readNumber(SimpleTokenReader* reader, Maybe<double>& out) {
     if (out) {
         return this->raiseError();
     }
 
     return reader->readMaybeF64(&out);