--- 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);