diff --git a/config/check_spidermonkey_style.py b/config/check_spidermonkey_style.py index df651ffdf168..e9bab3ab9f59 100644 --- a/config/check_spidermonkey_style.py +++ b/config/check_spidermonkey_style.py @@ -113,6 +113,7 @@ included_inclnames_to_ignore = set([ # ignore #includes of them when checking #include ordering. oddly_ordered_inclnames = set([ 'ctypes/typedefs.h', # Included multiple times in the body of ctypes/CTypes.h + 'frontend/BinSource-auto.h', # Included in the body of frontend/BinSource.h 'frontend/ReservedWordsGenerated.h', # Included in the body of frontend/TokenStream.h 'gc/StatsPhasesGenerated.h', # Included in the body of gc/Statistics.h 'gc/StatsPhasesGenerated.cpp', # Included in the body of gc/Statistics.cpp diff --git a/js/src/frontend/BinSource-auto.cpp b/js/src/frontend/BinSource-auto.cpp new file mode 100644 index 000000000000..88165291b5fb --- /dev/null +++ b/js/src/frontend/BinSource-auto.cpp @@ -0,0 +1,7326 @@ +// This file was autogenerated by binjs_generate_spidermonkey, +// please DO NOT EDIT BY HAND. +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- +* vim: set ts=8 sts=4 et sw=4 tw=99: +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// To generate this file, see the documentation in +// js/src/frontend/binsource/README.md. + +#include "mozilla/ArrayUtils.h" +#include "mozilla/Casting.h" +#include "mozilla/Maybe.h" +#include "mozilla/Move.h" +#include "mozilla/PodOperations.h" +#include "mozilla/Vector.h" + +#include "frontend/BinSource.h" +#include "frontend/BinTokenReaderTester.h" +#include "frontend/FullParseHandler.h" +#include "frontend/Parser.h" +#include "frontend/SharedContext.h" + +#include "vm/RegExpObject.h" + +#include "frontend/ParseContext-inl.h" +#include "frontend/ParseNode-inl.h" + +namespace js { +namespace frontend { + +using AutoList = BinTokenReaderTester::AutoList; +using AutoTaggedTuple = BinTokenReaderTester::AutoTaggedTuple; +using AutoTuple = BinTokenReaderTester::AutoTuple; +using BinFields = BinTokenReaderTester::BinFields; +using Chars = BinTokenReaderTester::Chars; +using NameBag = GCHashSet; +using Names = GCVector; +using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr; + +// Evaluate an expression EXPR, checking that the result is not falsy. +// +// Throw `cx->alreadyReportedError()` if it returns 0/nullptr. +#define TRY(EXPR) \ + do { \ + if (!EXPR) \ + return cx_->alreadyReportedError(); \ + } while(false) + + +// Evaluate an expression EXPR, checking that the result is not falsy. +// In case of success, assign the result to VAR. +// +// Throw `cx->alreadyReportedError()` if it returns 0/nullptr. +#define TRY_VAR(VAR, EXPR) \ + do { \ + VAR = EXPR; \ + if (!VAR) \ + return cx_->alreadyReportedError(); \ + } while (false) + +// Evaluate an expression EXPR, checking that the result is not falsy. +// In case of success, assign the result to a new variable VAR. +// +// Throw `cx->alreadyReportedError()` if it returns 0/nullptr. +#define TRY_DECL(VAR, EXPR) \ + auto VAR = EXPR; \ + if (!VAR) \ + return cx_->alreadyReportedError(); + +// Evaluate an expression EXPR, checking that the result is a success. +// In case of success, unwrap and assign the result to a new variable VAR. +// +// In case of error, propagate the error. +#define MOZ_TRY_DECL(VAR, EXPR) \ + auto _##VAR = EXPR; \ + if (_##VAR.isErr()) \ + return ::mozilla::Err(_##VAR.unwrapErr()); \ + auto VAR = _##VAR.unwrap(); + +// Ensure that we are visiting the right fields. +template +JS::Result +BinASTParser::checkFields(const BinKind kind, const BinFields& actual, const BinField (&expected)[N]) +{ + if (actual.length() != N) + return raiseInvalidNumberOfFields(kind, N, actual.length()); + + for (size_t i = 0; i < N; ++i) { + if (actual[i] != expected[i]) + return raiseInvalidField(describeBinKind(kind), actual[i]); + } + + return Ok(); +} + +// Special case for N=0, as empty arrays are not permitted in C++ +JS::Result +BinASTParser::checkFields0(const BinKind kind, const BinFields& actual) +{ + if (actual.length() != 0) + return raiseInvalidNumberOfFields(kind, 0, actual.length()); + + return Ok(); +} + +// Compare a bunch of `uint8_t` values (as returned by the tokenizer_) with +// a string literal (and ONLY a string literal). +template +bool operator==(const Chars& left, const char (&right)[N]) { + return BinTokenReaderTester::equals(left, right); +} + +// Helper class: Restore field `variableDeclarationKind_` upon leaving a scope. +class MOZ_RAII AutoVariableDeclarationKind { + public: + explicit AutoVariableDeclarationKind(BinASTParser* parser + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : + parser_(parser), + kind(parser->variableDeclarationKind_) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + ~AutoVariableDeclarationKind() { + parser_->variableDeclarationKind_ = kind; + } + private: + BinASTParser* parser_; + BinASTParser::VariableDeclarationKind kind; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + + +// ----- Sums of interfaces (autogenerated, by lexicographical order) +// Sums of sums are flattened. +/* +AssignmentTarget ::= ArrayAssignmentTarget + AssignmentTargetIdentifier + ComputedMemberAssignmentTarget + ObjectAssignmentTarget + StaticMemberAssignmentTarget +*/ +JS::Result +BinASTParser::parseAssignmentTarget() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumAssignmentTarget(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::ArrayAssignmentTarget: + MOZ_TRY_VAR(result, parseInterfaceArrayAssignmentTarget(start, kind, fields)); + break; + case BinKind::AssignmentTargetIdentifier: + MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind, fields)); + break; + case BinKind::ComputedMemberAssignmentTarget: + MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(start, kind, fields)); + break; + case BinKind::ObjectAssignmentTarget: + MOZ_TRY_VAR(result, parseInterfaceObjectAssignmentTarget(start, kind, fields)); + break; + case BinKind::StaticMemberAssignmentTarget: + MOZ_TRY_VAR(result, parseInterfaceStaticMemberAssignmentTarget(start, kind, fields)); + break; + default: + return raiseInvalidKind("AssignmentTarget", kind); + } + return result; +} + +/* +AssignmentTargetOrAssignmentTargetWithInitializer ::= ArrayAssignmentTarget + AssignmentTargetIdentifier + AssignmentTargetWithInitializer + ComputedMemberAssignmentTarget + ObjectAssignmentTarget + StaticMemberAssignmentTarget +*/ +JS::Result +BinASTParser::parseAssignmentTargetOrAssignmentTargetWithInitializer() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumAssignmentTargetOrAssignmentTargetWithInitializer(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumAssignmentTargetOrAssignmentTargetWithInitializer(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::ArrayAssignmentTarget: + MOZ_TRY_VAR(result, parseInterfaceArrayAssignmentTarget(start, kind, fields)); + break; + case BinKind::AssignmentTargetIdentifier: + MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind, fields)); + break; + case BinKind::AssignmentTargetWithInitializer: + MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetWithInitializer(start, kind, fields)); + break; + case BinKind::ComputedMemberAssignmentTarget: + MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(start, kind, fields)); + break; + case BinKind::ObjectAssignmentTarget: + MOZ_TRY_VAR(result, parseInterfaceObjectAssignmentTarget(start, kind, fields)); + break; + case BinKind::StaticMemberAssignmentTarget: + MOZ_TRY_VAR(result, parseInterfaceStaticMemberAssignmentTarget(start, kind, fields)); + break; + default: + return raiseInvalidKind("AssignmentTargetOrAssignmentTargetWithInitializer", kind); + } + return result; +} + +/* +AssignmentTargetPattern ::= ArrayAssignmentTarget + ObjectAssignmentTarget +*/ +JS::Result +BinASTParser::parseAssignmentTargetPattern() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumAssignmentTargetPattern(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumAssignmentTargetPattern(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::ArrayAssignmentTarget: + MOZ_TRY_VAR(result, parseInterfaceArrayAssignmentTarget(start, kind, fields)); + break; + case BinKind::ObjectAssignmentTarget: + MOZ_TRY_VAR(result, parseInterfaceObjectAssignmentTarget(start, kind, fields)); + break; + default: + return raiseInvalidKind("AssignmentTargetPattern", kind); + } + return result; +} + +/* +AssignmentTargetProperty ::= AssignmentTargetPropertyIdentifier + AssignmentTargetPropertyProperty +*/ +JS::Result +BinASTParser::parseAssignmentTargetProperty() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumAssignmentTargetProperty(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumAssignmentTargetProperty(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::AssignmentTargetPropertyIdentifier: + MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetPropertyIdentifier(start, kind, fields)); + break; + case BinKind::AssignmentTargetPropertyProperty: + MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetPropertyProperty(start, kind, fields)); + break; + default: + return raiseInvalidKind("AssignmentTargetProperty", kind); + } + return result; +} + +/* +Binding ::= ArrayBinding + BindingIdentifier + ObjectBinding +*/ +JS::Result +BinASTParser::parseBinding() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumBinding(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumBinding(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::ArrayBinding: + MOZ_TRY_VAR(result, parseInterfaceArrayBinding(start, kind, fields)); + break; + case BinKind::BindingIdentifier: + MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields)); + break; + case BinKind::ObjectBinding: + MOZ_TRY_VAR(result, parseInterfaceObjectBinding(start, kind, fields)); + break; + default: + return raiseInvalidKind("Binding", kind); + } + return result; +} + +/* +BindingOrBindingWithInitializer ::= ArrayBinding + BindingIdentifier + BindingWithInitializer + ObjectBinding +*/ +JS::Result +BinASTParser::parseBindingOrBindingWithInitializer() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumBindingOrBindingWithInitializer(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumBindingOrBindingWithInitializer(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::ArrayBinding: + MOZ_TRY_VAR(result, parseInterfaceArrayBinding(start, kind, fields)); + break; + case BinKind::BindingIdentifier: + MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields)); + break; + case BinKind::BindingWithInitializer: + MOZ_TRY_VAR(result, parseInterfaceBindingWithInitializer(start, kind, fields)); + break; + case BinKind::ObjectBinding: + MOZ_TRY_VAR(result, parseInterfaceObjectBinding(start, kind, fields)); + break; + default: + return raiseInvalidKind("BindingOrBindingWithInitializer", kind); + } + return result; +} + +/* +BindingPattern ::= ArrayBinding + ObjectBinding +*/ +JS::Result +BinASTParser::parseBindingPattern() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumBindingPattern(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumBindingPattern(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::ArrayBinding: + MOZ_TRY_VAR(result, parseInterfaceArrayBinding(start, kind, fields)); + break; + case BinKind::ObjectBinding: + MOZ_TRY_VAR(result, parseInterfaceObjectBinding(start, kind, fields)); + break; + default: + return raiseInvalidKind("BindingPattern", kind); + } + return result; +} + +/* +BindingProperty ::= BindingPropertyIdentifier + BindingPropertyProperty +*/ +JS::Result +BinASTParser::parseBindingProperty() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumBindingProperty(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumBindingProperty(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::BindingPropertyIdentifier: + MOZ_TRY_VAR(result, parseInterfaceBindingPropertyIdentifier(start, kind, fields)); + break; + case BinKind::BindingPropertyProperty: + MOZ_TRY_VAR(result, parseInterfaceBindingPropertyProperty(start, kind, fields)); + break; + default: + return raiseInvalidKind("BindingProperty", kind); + } + return result; +} + +/* +ExportDeclaration ::= Export + ExportAllFrom + ExportDefault + ExportFrom + ExportLocals +*/ +JS::Result +BinASTParser::parseExportDeclaration() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumExportDeclaration(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumExportDeclaration(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::Export: + MOZ_TRY_VAR(result, parseInterfaceExport(start, kind, fields)); + break; + case BinKind::ExportAllFrom: + MOZ_TRY_VAR(result, parseInterfaceExportAllFrom(start, kind, fields)); + break; + case BinKind::ExportDefault: + MOZ_TRY_VAR(result, parseInterfaceExportDefault(start, kind, fields)); + break; + case BinKind::ExportFrom: + MOZ_TRY_VAR(result, parseInterfaceExportFrom(start, kind, fields)); + break; + case BinKind::ExportLocals: + MOZ_TRY_VAR(result, parseInterfaceExportLocals(start, kind, fields)); + break; + default: + return raiseInvalidKind("ExportDeclaration", kind); + } + return result; +} + +/* +Expression ::= ArrayExpression + ArrowExpression + AssignmentExpression + AwaitExpression + BinaryExpression + CallExpression + ClassExpression + CompoundAssignmentExpression + ComputedMemberExpression + ConditionalExpression + FunctionExpression + IdentifierExpression + LiteralBooleanExpression + LiteralInfinityExpression + LiteralNullExpression + LiteralNumericExpression + LiteralRegExpExpression + LiteralStringExpression + NewExpression + NewTargetExpression + ObjectExpression + StaticMemberExpression + TemplateExpression + ThisExpression + UnaryExpression + UpdateExpression + YieldExpression + YieldStarExpression +*/ +JS::Result +BinASTParser::parseExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumExpression(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::ArrayExpression: + MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields)); + break; + case BinKind::ArrowExpression: + MOZ_TRY_VAR(result, parseInterfaceArrowExpression(start, kind, fields)); + break; + case BinKind::AssignmentExpression: + MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind, fields)); + break; + case BinKind::AwaitExpression: + MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields)); + break; + case BinKind::BinaryExpression: + MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields)); + break; + case BinKind::CallExpression: + MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields)); + break; + case BinKind::ClassExpression: + MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields)); + break; + case BinKind::CompoundAssignmentExpression: + MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(start, kind, fields)); + break; + case BinKind::ComputedMemberExpression: + MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(start, kind, fields)); + break; + case BinKind::ConditionalExpression: + MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind, fields)); + break; + case BinKind::FunctionExpression: + MOZ_TRY_VAR(result, parseInterfaceFunctionExpression(start, kind, fields)); + break; + case BinKind::IdentifierExpression: + MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields)); + break; + case BinKind::LiteralBooleanExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields)); + break; + case BinKind::LiteralInfinityExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(start, kind, fields)); + break; + case BinKind::LiteralNullExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind, fields)); + break; + case BinKind::LiteralNumericExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(start, kind, fields)); + break; + case BinKind::LiteralRegExpExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(start, kind, fields)); + break; + case BinKind::LiteralStringExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(start, kind, fields)); + break; + case BinKind::NewExpression: + MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields)); + break; + case BinKind::NewTargetExpression: + MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields)); + break; + case BinKind::ObjectExpression: + MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields)); + break; + case BinKind::StaticMemberExpression: + MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields)); + break; + case BinKind::TemplateExpression: + MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields)); + break; + case BinKind::ThisExpression: + MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields)); + break; + case BinKind::UnaryExpression: + MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields)); + break; + case BinKind::UpdateExpression: + MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields)); + break; + case BinKind::YieldExpression: + MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields)); + break; + case BinKind::YieldStarExpression: + MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields)); + break; + default: + return raiseInvalidKind("Expression", kind); + } + return result; +} + +/* +ExpressionOrSuper ::= ArrayExpression + ArrowExpression + AssignmentExpression + AwaitExpression + BinaryExpression + CallExpression + ClassExpression + CompoundAssignmentExpression + ComputedMemberExpression + ConditionalExpression + FunctionExpression + IdentifierExpression + LiteralBooleanExpression + LiteralInfinityExpression + LiteralNullExpression + LiteralNumericExpression + LiteralRegExpExpression + LiteralStringExpression + NewExpression + NewTargetExpression + ObjectExpression + StaticMemberExpression + Super + TemplateExpression + ThisExpression + UnaryExpression + UpdateExpression + YieldExpression + YieldStarExpression +*/ +JS::Result +BinASTParser::parseExpressionOrSuper() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumExpressionOrSuper(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumExpressionOrSuper(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::ArrayExpression: + MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields)); + break; + case BinKind::ArrowExpression: + MOZ_TRY_VAR(result, parseInterfaceArrowExpression(start, kind, fields)); + break; + case BinKind::AssignmentExpression: + MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind, fields)); + break; + case BinKind::AwaitExpression: + MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields)); + break; + case BinKind::BinaryExpression: + MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields)); + break; + case BinKind::CallExpression: + MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields)); + break; + case BinKind::ClassExpression: + MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields)); + break; + case BinKind::CompoundAssignmentExpression: + MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(start, kind, fields)); + break; + case BinKind::ComputedMemberExpression: + MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(start, kind, fields)); + break; + case BinKind::ConditionalExpression: + MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind, fields)); + break; + case BinKind::FunctionExpression: + MOZ_TRY_VAR(result, parseInterfaceFunctionExpression(start, kind, fields)); + break; + case BinKind::IdentifierExpression: + MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields)); + break; + case BinKind::LiteralBooleanExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields)); + break; + case BinKind::LiteralInfinityExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(start, kind, fields)); + break; + case BinKind::LiteralNullExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind, fields)); + break; + case BinKind::LiteralNumericExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(start, kind, fields)); + break; + case BinKind::LiteralRegExpExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(start, kind, fields)); + break; + case BinKind::LiteralStringExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(start, kind, fields)); + break; + case BinKind::NewExpression: + MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields)); + break; + case BinKind::NewTargetExpression: + MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields)); + break; + case BinKind::ObjectExpression: + MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields)); + break; + case BinKind::StaticMemberExpression: + MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields)); + break; + case BinKind::Super: + MOZ_TRY_VAR(result, parseInterfaceSuper(start, kind, fields)); + break; + case BinKind::TemplateExpression: + MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields)); + break; + case BinKind::ThisExpression: + MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields)); + break; + case BinKind::UnaryExpression: + MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields)); + break; + case BinKind::UpdateExpression: + MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields)); + break; + case BinKind::YieldExpression: + MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields)); + break; + case BinKind::YieldStarExpression: + MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields)); + break; + default: + return raiseInvalidKind("ExpressionOrSuper", kind); + } + return result; +} + +/* +ExpressionOrTemplateElement ::= ArrayExpression + ArrowExpression + AssignmentExpression + AwaitExpression + BinaryExpression + CallExpression + ClassExpression + CompoundAssignmentExpression + ComputedMemberExpression + ConditionalExpression + FunctionExpression + IdentifierExpression + LiteralBooleanExpression + LiteralInfinityExpression + LiteralNullExpression + LiteralNumericExpression + LiteralRegExpExpression + LiteralStringExpression + NewExpression + NewTargetExpression + ObjectExpression + StaticMemberExpression + TemplateElement + TemplateExpression + ThisExpression + UnaryExpression + UpdateExpression + YieldExpression + YieldStarExpression +*/ +JS::Result +BinASTParser::parseExpressionOrTemplateElement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumExpressionOrTemplateElement(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumExpressionOrTemplateElement(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::ArrayExpression: + MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields)); + break; + case BinKind::ArrowExpression: + MOZ_TRY_VAR(result, parseInterfaceArrowExpression(start, kind, fields)); + break; + case BinKind::AssignmentExpression: + MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind, fields)); + break; + case BinKind::AwaitExpression: + MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields)); + break; + case BinKind::BinaryExpression: + MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields)); + break; + case BinKind::CallExpression: + MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields)); + break; + case BinKind::ClassExpression: + MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields)); + break; + case BinKind::CompoundAssignmentExpression: + MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(start, kind, fields)); + break; + case BinKind::ComputedMemberExpression: + MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(start, kind, fields)); + break; + case BinKind::ConditionalExpression: + MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind, fields)); + break; + case BinKind::FunctionExpression: + MOZ_TRY_VAR(result, parseInterfaceFunctionExpression(start, kind, fields)); + break; + case BinKind::IdentifierExpression: + MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields)); + break; + case BinKind::LiteralBooleanExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields)); + break; + case BinKind::LiteralInfinityExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(start, kind, fields)); + break; + case BinKind::LiteralNullExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind, fields)); + break; + case BinKind::LiteralNumericExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(start, kind, fields)); + break; + case BinKind::LiteralRegExpExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(start, kind, fields)); + break; + case BinKind::LiteralStringExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(start, kind, fields)); + break; + case BinKind::NewExpression: + MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields)); + break; + case BinKind::NewTargetExpression: + MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields)); + break; + case BinKind::ObjectExpression: + MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields)); + break; + case BinKind::StaticMemberExpression: + MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields)); + break; + case BinKind::TemplateElement: + MOZ_TRY_VAR(result, parseInterfaceTemplateElement(start, kind, fields)); + break; + case BinKind::TemplateExpression: + MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields)); + break; + case BinKind::ThisExpression: + MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields)); + break; + case BinKind::UnaryExpression: + MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields)); + break; + case BinKind::UpdateExpression: + MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields)); + break; + case BinKind::YieldExpression: + MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields)); + break; + case BinKind::YieldStarExpression: + MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields)); + break; + default: + return raiseInvalidKind("ExpressionOrTemplateElement", kind); + } + return result; +} + +/* +ForInOfBindingOrAssignmentTarget ::= ArrayAssignmentTarget + AssignmentTargetIdentifier + ComputedMemberAssignmentTarget + ForInOfBinding + ObjectAssignmentTarget + StaticMemberAssignmentTarget +*/ +JS::Result +BinASTParser::parseForInOfBindingOrAssignmentTarget() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumForInOfBindingOrAssignmentTarget(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumForInOfBindingOrAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::ArrayAssignmentTarget: + MOZ_TRY_VAR(result, parseInterfaceArrayAssignmentTarget(start, kind, fields)); + break; + case BinKind::AssignmentTargetIdentifier: + MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind, fields)); + break; + case BinKind::ComputedMemberAssignmentTarget: + MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(start, kind, fields)); + break; + case BinKind::ForInOfBinding: + MOZ_TRY_VAR(result, parseInterfaceForInOfBinding(start, kind, fields)); + break; + case BinKind::ObjectAssignmentTarget: + MOZ_TRY_VAR(result, parseInterfaceObjectAssignmentTarget(start, kind, fields)); + break; + case BinKind::StaticMemberAssignmentTarget: + MOZ_TRY_VAR(result, parseInterfaceStaticMemberAssignmentTarget(start, kind, fields)); + break; + default: + return raiseInvalidKind("ForInOfBindingOrAssignmentTarget", kind); + } + return result; +} + +/* +FunctionBodyOrExpression ::= ArrayExpression + ArrowExpression + AssignmentExpression + AwaitExpression + BinaryExpression + CallExpression + ClassExpression + CompoundAssignmentExpression + ComputedMemberExpression + ConditionalExpression + FunctionBody + FunctionExpression + IdentifierExpression + LiteralBooleanExpression + LiteralInfinityExpression + LiteralNullExpression + LiteralNumericExpression + LiteralRegExpExpression + LiteralStringExpression + NewExpression + NewTargetExpression + ObjectExpression + StaticMemberExpression + TemplateExpression + ThisExpression + UnaryExpression + UpdateExpression + YieldExpression + YieldStarExpression +*/ +JS::Result +BinASTParser::parseFunctionBodyOrExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumFunctionBodyOrExpression(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumFunctionBodyOrExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::ArrayExpression: + MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields)); + break; + case BinKind::ArrowExpression: + MOZ_TRY_VAR(result, parseInterfaceArrowExpression(start, kind, fields)); + break; + case BinKind::AssignmentExpression: + MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind, fields)); + break; + case BinKind::AwaitExpression: + MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields)); + break; + case BinKind::BinaryExpression: + MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields)); + break; + case BinKind::CallExpression: + MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields)); + break; + case BinKind::ClassExpression: + MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields)); + break; + case BinKind::CompoundAssignmentExpression: + MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(start, kind, fields)); + break; + case BinKind::ComputedMemberExpression: + MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(start, kind, fields)); + break; + case BinKind::ConditionalExpression: + MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind, fields)); + break; + case BinKind::FunctionBody: + MOZ_TRY_VAR(result, parseInterfaceFunctionBody(start, kind, fields)); + break; + case BinKind::FunctionExpression: + MOZ_TRY_VAR(result, parseInterfaceFunctionExpression(start, kind, fields)); + break; + case BinKind::IdentifierExpression: + MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields)); + break; + case BinKind::LiteralBooleanExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields)); + break; + case BinKind::LiteralInfinityExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(start, kind, fields)); + break; + case BinKind::LiteralNullExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind, fields)); + break; + case BinKind::LiteralNumericExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(start, kind, fields)); + break; + case BinKind::LiteralRegExpExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(start, kind, fields)); + break; + case BinKind::LiteralStringExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(start, kind, fields)); + break; + case BinKind::NewExpression: + MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields)); + break; + case BinKind::NewTargetExpression: + MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields)); + break; + case BinKind::ObjectExpression: + MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields)); + break; + case BinKind::StaticMemberExpression: + MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields)); + break; + case BinKind::TemplateExpression: + MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields)); + break; + case BinKind::ThisExpression: + MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields)); + break; + case BinKind::UnaryExpression: + MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields)); + break; + case BinKind::UpdateExpression: + MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields)); + break; + case BinKind::YieldExpression: + MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields)); + break; + case BinKind::YieldStarExpression: + MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields)); + break; + default: + return raiseInvalidKind("FunctionBodyOrExpression", kind); + } + return result; +} + +/* +FunctionDeclarationOrClassDeclarationOrExpression ::= ArrayExpression + ArrowExpression + AssignmentExpression + AwaitExpression + BinaryExpression + CallExpression + ClassDeclaration + ClassExpression + CompoundAssignmentExpression + ComputedMemberExpression + ConditionalExpression + FunctionDeclaration + FunctionExpression + IdentifierExpression + LiteralBooleanExpression + LiteralInfinityExpression + LiteralNullExpression + LiteralNumericExpression + LiteralRegExpExpression + LiteralStringExpression + NewExpression + NewTargetExpression + ObjectExpression + StaticMemberExpression + TemplateExpression + ThisExpression + UnaryExpression + UpdateExpression + YieldExpression + YieldStarExpression +*/ +JS::Result +BinASTParser::parseFunctionDeclarationOrClassDeclarationOrExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumFunctionDeclarationOrClassDeclarationOrExpression(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumFunctionDeclarationOrClassDeclarationOrExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::ArrayExpression: + MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields)); + break; + case BinKind::ArrowExpression: + MOZ_TRY_VAR(result, parseInterfaceArrowExpression(start, kind, fields)); + break; + case BinKind::AssignmentExpression: + MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind, fields)); + break; + case BinKind::AwaitExpression: + MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields)); + break; + case BinKind::BinaryExpression: + MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields)); + break; + case BinKind::CallExpression: + MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields)); + break; + case BinKind::ClassDeclaration: + MOZ_TRY_VAR(result, parseInterfaceClassDeclaration(start, kind, fields)); + break; + case BinKind::ClassExpression: + MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields)); + break; + case BinKind::CompoundAssignmentExpression: + MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(start, kind, fields)); + break; + case BinKind::ComputedMemberExpression: + MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(start, kind, fields)); + break; + case BinKind::ConditionalExpression: + MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind, fields)); + break; + case BinKind::FunctionDeclaration: + MOZ_TRY_VAR(result, parseInterfaceFunctionDeclaration(start, kind, fields)); + break; + case BinKind::FunctionExpression: + MOZ_TRY_VAR(result, parseInterfaceFunctionExpression(start, kind, fields)); + break; + case BinKind::IdentifierExpression: + MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields)); + break; + case BinKind::LiteralBooleanExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields)); + break; + case BinKind::LiteralInfinityExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(start, kind, fields)); + break; + case BinKind::LiteralNullExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind, fields)); + break; + case BinKind::LiteralNumericExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(start, kind, fields)); + break; + case BinKind::LiteralRegExpExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(start, kind, fields)); + break; + case BinKind::LiteralStringExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(start, kind, fields)); + break; + case BinKind::NewExpression: + MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields)); + break; + case BinKind::NewTargetExpression: + MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields)); + break; + case BinKind::ObjectExpression: + MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields)); + break; + case BinKind::StaticMemberExpression: + MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields)); + break; + case BinKind::TemplateExpression: + MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields)); + break; + case BinKind::ThisExpression: + MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields)); + break; + case BinKind::UnaryExpression: + MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields)); + break; + case BinKind::UpdateExpression: + MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields)); + break; + case BinKind::YieldExpression: + MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields)); + break; + case BinKind::YieldStarExpression: + MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields)); + break; + default: + return raiseInvalidKind("FunctionDeclarationOrClassDeclarationOrExpression", kind); + } + return result; +} + +/* +FunctionDeclarationOrClassDeclarationOrVariableDeclaration ::= ClassDeclaration + FunctionDeclaration + VariableDeclaration +*/ +JS::Result +BinASTParser::parseFunctionDeclarationOrClassDeclarationOrVariableDeclaration() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumFunctionDeclarationOrClassDeclarationOrVariableDeclaration(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumFunctionDeclarationOrClassDeclarationOrVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::ClassDeclaration: + MOZ_TRY_VAR(result, parseInterfaceClassDeclaration(start, kind, fields)); + break; + case BinKind::FunctionDeclaration: + MOZ_TRY_VAR(result, parseInterfaceFunctionDeclaration(start, kind, fields)); + break; + case BinKind::VariableDeclaration: + MOZ_TRY_VAR(result, parseInterfaceVariableDeclaration(start, kind, fields)); + break; + default: + return raiseInvalidKind("FunctionDeclarationOrClassDeclarationOrVariableDeclaration", kind); + } + return result; +} + +/* +ImportDeclaration ::= Import + ImportNamespace +*/ +JS::Result +BinASTParser::parseImportDeclaration() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumImportDeclaration(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumImportDeclaration(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::Import: + MOZ_TRY_VAR(result, parseInterfaceImport(start, kind, fields)); + break; + case BinKind::ImportNamespace: + MOZ_TRY_VAR(result, parseInterfaceImportNamespace(start, kind, fields)); + break; + default: + return raiseInvalidKind("ImportDeclaration", kind); + } + return result; +} + +/* +ImportDeclarationOrExportDeclarationOrStatement ::= Block + BreakStatement + ClassDeclaration + ContinueStatement + DebuggerStatement + DoWhileStatement + EmptyStatement + Export + ExportAllFrom + ExportDefault + ExportFrom + ExportLocals + ExpressionStatement + ForInStatement + ForOfStatement + ForStatement + FunctionDeclaration + IfStatement + Import + ImportNamespace + LabelledStatement + ReturnStatement + SwitchStatement + SwitchStatementWithDefault + ThrowStatement + TryCatchStatement + TryFinallyStatement + VariableDeclaration + WhileStatement + WithStatement +*/ +JS::Result +BinASTParser::parseImportDeclarationOrExportDeclarationOrStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumImportDeclarationOrExportDeclarationOrStatement(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumImportDeclarationOrExportDeclarationOrStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::Block: + MOZ_TRY_VAR(result, parseInterfaceBlock(start, kind, fields)); + break; + case BinKind::BreakStatement: + MOZ_TRY_VAR(result, parseInterfaceBreakStatement(start, kind, fields)); + break; + case BinKind::ClassDeclaration: + MOZ_TRY_VAR(result, parseInterfaceClassDeclaration(start, kind, fields)); + break; + case BinKind::ContinueStatement: + MOZ_TRY_VAR(result, parseInterfaceContinueStatement(start, kind, fields)); + break; + case BinKind::DebuggerStatement: + MOZ_TRY_VAR(result, parseInterfaceDebuggerStatement(start, kind, fields)); + break; + case BinKind::DoWhileStatement: + MOZ_TRY_VAR(result, parseInterfaceDoWhileStatement(start, kind, fields)); + break; + case BinKind::EmptyStatement: + MOZ_TRY_VAR(result, parseInterfaceEmptyStatement(start, kind, fields)); + break; + case BinKind::Export: + MOZ_TRY_VAR(result, parseInterfaceExport(start, kind, fields)); + break; + case BinKind::ExportAllFrom: + MOZ_TRY_VAR(result, parseInterfaceExportAllFrom(start, kind, fields)); + break; + case BinKind::ExportDefault: + MOZ_TRY_VAR(result, parseInterfaceExportDefault(start, kind, fields)); + break; + case BinKind::ExportFrom: + MOZ_TRY_VAR(result, parseInterfaceExportFrom(start, kind, fields)); + break; + case BinKind::ExportLocals: + MOZ_TRY_VAR(result, parseInterfaceExportLocals(start, kind, fields)); + break; + case BinKind::ExpressionStatement: + MOZ_TRY_VAR(result, parseInterfaceExpressionStatement(start, kind, fields)); + break; + case BinKind::ForInStatement: + MOZ_TRY_VAR(result, parseInterfaceForInStatement(start, kind, fields)); + break; + case BinKind::ForOfStatement: + MOZ_TRY_VAR(result, parseInterfaceForOfStatement(start, kind, fields)); + break; + case BinKind::ForStatement: + MOZ_TRY_VAR(result, parseInterfaceForStatement(start, kind, fields)); + break; + case BinKind::FunctionDeclaration: + MOZ_TRY_VAR(result, parseInterfaceFunctionDeclaration(start, kind, fields)); + break; + case BinKind::IfStatement: + MOZ_TRY_VAR(result, parseInterfaceIfStatement(start, kind, fields)); + break; + case BinKind::Import: + MOZ_TRY_VAR(result, parseInterfaceImport(start, kind, fields)); + break; + case BinKind::ImportNamespace: + MOZ_TRY_VAR(result, parseInterfaceImportNamespace(start, kind, fields)); + break; + case BinKind::LabelledStatement: + MOZ_TRY_VAR(result, parseInterfaceLabelledStatement(start, kind, fields)); + break; + case BinKind::ReturnStatement: + MOZ_TRY_VAR(result, parseInterfaceReturnStatement(start, kind, fields)); + break; + case BinKind::SwitchStatement: + MOZ_TRY_VAR(result, parseInterfaceSwitchStatement(start, kind, fields)); + break; + case BinKind::SwitchStatementWithDefault: + MOZ_TRY_VAR(result, parseInterfaceSwitchStatementWithDefault(start, kind, fields)); + break; + case BinKind::ThrowStatement: + MOZ_TRY_VAR(result, parseInterfaceThrowStatement(start, kind, fields)); + break; + case BinKind::TryCatchStatement: + MOZ_TRY_VAR(result, parseInterfaceTryCatchStatement(start, kind, fields)); + break; + case BinKind::TryFinallyStatement: + MOZ_TRY_VAR(result, parseInterfaceTryFinallyStatement(start, kind, fields)); + break; + case BinKind::VariableDeclaration: + MOZ_TRY_VAR(result, parseInterfaceVariableDeclaration(start, kind, fields)); + break; + case BinKind::WhileStatement: + MOZ_TRY_VAR(result, parseInterfaceWhileStatement(start, kind, fields)); + break; + case BinKind::WithStatement: + MOZ_TRY_VAR(result, parseInterfaceWithStatement(start, kind, fields)); + break; + default: + return raiseInvalidKind("ImportDeclarationOrExportDeclarationOrStatement", kind); + } + return result; +} + +/* +IterationStatement ::= DoWhileStatement + ForInStatement + ForOfStatement + ForStatement + WhileStatement +*/ +JS::Result +BinASTParser::parseIterationStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumIterationStatement(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumIterationStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::DoWhileStatement: + MOZ_TRY_VAR(result, parseInterfaceDoWhileStatement(start, kind, fields)); + break; + case BinKind::ForInStatement: + MOZ_TRY_VAR(result, parseInterfaceForInStatement(start, kind, fields)); + break; + case BinKind::ForOfStatement: + MOZ_TRY_VAR(result, parseInterfaceForOfStatement(start, kind, fields)); + break; + case BinKind::ForStatement: + MOZ_TRY_VAR(result, parseInterfaceForStatement(start, kind, fields)); + break; + case BinKind::WhileStatement: + MOZ_TRY_VAR(result, parseInterfaceWhileStatement(start, kind, fields)); + break; + default: + return raiseInvalidKind("IterationStatement", kind); + } + return result; +} + +/* +Literal ::= LiteralBooleanExpression + LiteralInfinityExpression + LiteralNullExpression + LiteralNumericExpression + LiteralStringExpression +*/ +JS::Result +BinASTParser::parseLiteral() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumLiteral(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumLiteral(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::LiteralBooleanExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields)); + break; + case BinKind::LiteralInfinityExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(start, kind, fields)); + break; + case BinKind::LiteralNullExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind, fields)); + break; + case BinKind::LiteralNumericExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(start, kind, fields)); + break; + case BinKind::LiteralStringExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(start, kind, fields)); + break; + default: + return raiseInvalidKind("Literal", kind); + } + return result; +} + +/* +MethodDefinition ::= Getter + Method + Setter +*/ +JS::Result +BinASTParser::parseMethodDefinition() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumMethodDefinition(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumMethodDefinition(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::Getter: + MOZ_TRY_VAR(result, parseInterfaceGetter(start, kind, fields)); + break; + case BinKind::Method: + MOZ_TRY_VAR(result, parseInterfaceMethod(start, kind, fields)); + break; + case BinKind::Setter: + MOZ_TRY_VAR(result, parseInterfaceSetter(start, kind, fields)); + break; + default: + return raiseInvalidKind("MethodDefinition", kind); + } + return result; +} + +/* +ObjectProperty ::= DataProperty + Getter + Method + Setter + ShorthandProperty +*/ +JS::Result +BinASTParser::parseObjectProperty() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumObjectProperty(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumObjectProperty(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::DataProperty: + MOZ_TRY_VAR(result, parseInterfaceDataProperty(start, kind, fields)); + break; + case BinKind::Getter: + MOZ_TRY_VAR(result, parseInterfaceGetter(start, kind, fields)); + break; + case BinKind::Method: + MOZ_TRY_VAR(result, parseInterfaceMethod(start, kind, fields)); + break; + case BinKind::Setter: + MOZ_TRY_VAR(result, parseInterfaceSetter(start, kind, fields)); + break; + case BinKind::ShorthandProperty: + MOZ_TRY_VAR(result, parseInterfaceShorthandProperty(start, kind, fields)); + break; + default: + return raiseInvalidKind("ObjectProperty", kind); + } + return result; +} + +/* +Parameter ::= ArrayBinding + BindingIdentifier + BindingWithInitializer + ObjectBinding +*/ +JS::Result +BinASTParser::parseParameter() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumParameter(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumParameter(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::ArrayBinding: + MOZ_TRY_VAR(result, parseInterfaceArrayBinding(start, kind, fields)); + break; + case BinKind::BindingIdentifier: + MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields)); + break; + case BinKind::BindingWithInitializer: + MOZ_TRY_VAR(result, parseInterfaceBindingWithInitializer(start, kind, fields)); + break; + case BinKind::ObjectBinding: + MOZ_TRY_VAR(result, parseInterfaceObjectBinding(start, kind, fields)); + break; + default: + return raiseInvalidKind("Parameter", kind); + } + return result; +} + +/* +Program ::= Module + Script +*/ +JS::Result +BinASTParser::parseProgram() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumProgram(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumProgram(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::Module: + MOZ_TRY_VAR(result, parseInterfaceModule(start, kind, fields)); + break; + case BinKind::Script: + MOZ_TRY_VAR(result, parseInterfaceScript(start, kind, fields)); + break; + default: + return raiseInvalidKind("Program", kind); + } + return result; +} + +/* +PropertyName ::= ComputedPropertyName + LiteralPropertyName +*/ +JS::Result +BinASTParser::parsePropertyName() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumPropertyName(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumPropertyName(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::ComputedPropertyName: + MOZ_TRY_VAR(result, parseInterfaceComputedPropertyName(start, kind, fields)); + break; + case BinKind::LiteralPropertyName: + MOZ_TRY_VAR(result, parseInterfaceLiteralPropertyName(start, kind, fields)); + break; + default: + return raiseInvalidKind("PropertyName", kind); + } + return result; +} + +/* +SimpleAssignmentTarget ::= AssignmentTargetIdentifier + ComputedMemberAssignmentTarget + StaticMemberAssignmentTarget +*/ +JS::Result +BinASTParser::parseSimpleAssignmentTarget() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumSimpleAssignmentTarget(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumSimpleAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::AssignmentTargetIdentifier: + MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind, fields)); + break; + case BinKind::ComputedMemberAssignmentTarget: + MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(start, kind, fields)); + break; + case BinKind::StaticMemberAssignmentTarget: + MOZ_TRY_VAR(result, parseInterfaceStaticMemberAssignmentTarget(start, kind, fields)); + break; + default: + return raiseInvalidKind("SimpleAssignmentTarget", kind); + } + return result; +} + +/* +SpreadElementOrExpression ::= ArrayExpression + ArrowExpression + AssignmentExpression + AwaitExpression + BinaryExpression + CallExpression + ClassExpression + CompoundAssignmentExpression + ComputedMemberExpression + ConditionalExpression + FunctionExpression + IdentifierExpression + LiteralBooleanExpression + LiteralInfinityExpression + LiteralNullExpression + LiteralNumericExpression + LiteralRegExpExpression + LiteralStringExpression + NewExpression + NewTargetExpression + ObjectExpression + SpreadElement + StaticMemberExpression + TemplateExpression + ThisExpression + UnaryExpression + UpdateExpression + YieldExpression + YieldStarExpression +*/ +JS::Result +BinASTParser::parseSpreadElementOrExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumSpreadElementOrExpression(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumSpreadElementOrExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::ArrayExpression: + MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields)); + break; + case BinKind::ArrowExpression: + MOZ_TRY_VAR(result, parseInterfaceArrowExpression(start, kind, fields)); + break; + case BinKind::AssignmentExpression: + MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind, fields)); + break; + case BinKind::AwaitExpression: + MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields)); + break; + case BinKind::BinaryExpression: + MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields)); + break; + case BinKind::CallExpression: + MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields)); + break; + case BinKind::ClassExpression: + MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields)); + break; + case BinKind::CompoundAssignmentExpression: + MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(start, kind, fields)); + break; + case BinKind::ComputedMemberExpression: + MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(start, kind, fields)); + break; + case BinKind::ConditionalExpression: + MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind, fields)); + break; + case BinKind::FunctionExpression: + MOZ_TRY_VAR(result, parseInterfaceFunctionExpression(start, kind, fields)); + break; + case BinKind::IdentifierExpression: + MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields)); + break; + case BinKind::LiteralBooleanExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields)); + break; + case BinKind::LiteralInfinityExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(start, kind, fields)); + break; + case BinKind::LiteralNullExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind, fields)); + break; + case BinKind::LiteralNumericExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(start, kind, fields)); + break; + case BinKind::LiteralRegExpExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(start, kind, fields)); + break; + case BinKind::LiteralStringExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(start, kind, fields)); + break; + case BinKind::NewExpression: + MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields)); + break; + case BinKind::NewTargetExpression: + MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields)); + break; + case BinKind::ObjectExpression: + MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields)); + break; + case BinKind::SpreadElement: + MOZ_TRY_VAR(result, parseInterfaceSpreadElement(start, kind, fields)); + break; + case BinKind::StaticMemberExpression: + MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields)); + break; + case BinKind::TemplateExpression: + MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields)); + break; + case BinKind::ThisExpression: + MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields)); + break; + case BinKind::UnaryExpression: + MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields)); + break; + case BinKind::UpdateExpression: + MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields)); + break; + case BinKind::YieldExpression: + MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields)); + break; + case BinKind::YieldStarExpression: + MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields)); + break; + default: + return raiseInvalidKind("SpreadElementOrExpression", kind); + } + return result; +} + +/* +Statement ::= Block + BreakStatement + ClassDeclaration + ContinueStatement + DebuggerStatement + DoWhileStatement + EmptyStatement + ExpressionStatement + ForInStatement + ForOfStatement + ForStatement + FunctionDeclaration + IfStatement + LabelledStatement + ReturnStatement + SwitchStatement + SwitchStatementWithDefault + ThrowStatement + TryCatchStatement + TryFinallyStatement + VariableDeclaration + WhileStatement + WithStatement +*/ +JS::Result +BinASTParser::parseStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumStatement(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::Block: + MOZ_TRY_VAR(result, parseInterfaceBlock(start, kind, fields)); + break; + case BinKind::BreakStatement: + MOZ_TRY_VAR(result, parseInterfaceBreakStatement(start, kind, fields)); + break; + case BinKind::ClassDeclaration: + MOZ_TRY_VAR(result, parseInterfaceClassDeclaration(start, kind, fields)); + break; + case BinKind::ContinueStatement: + MOZ_TRY_VAR(result, parseInterfaceContinueStatement(start, kind, fields)); + break; + case BinKind::DebuggerStatement: + MOZ_TRY_VAR(result, parseInterfaceDebuggerStatement(start, kind, fields)); + break; + case BinKind::DoWhileStatement: + MOZ_TRY_VAR(result, parseInterfaceDoWhileStatement(start, kind, fields)); + break; + case BinKind::EmptyStatement: + MOZ_TRY_VAR(result, parseInterfaceEmptyStatement(start, kind, fields)); + break; + case BinKind::ExpressionStatement: + MOZ_TRY_VAR(result, parseInterfaceExpressionStatement(start, kind, fields)); + break; + case BinKind::ForInStatement: + MOZ_TRY_VAR(result, parseInterfaceForInStatement(start, kind, fields)); + break; + case BinKind::ForOfStatement: + MOZ_TRY_VAR(result, parseInterfaceForOfStatement(start, kind, fields)); + break; + case BinKind::ForStatement: + MOZ_TRY_VAR(result, parseInterfaceForStatement(start, kind, fields)); + break; + case BinKind::FunctionDeclaration: + MOZ_TRY_VAR(result, parseInterfaceFunctionDeclaration(start, kind, fields)); + break; + case BinKind::IfStatement: + MOZ_TRY_VAR(result, parseInterfaceIfStatement(start, kind, fields)); + break; + case BinKind::LabelledStatement: + MOZ_TRY_VAR(result, parseInterfaceLabelledStatement(start, kind, fields)); + break; + case BinKind::ReturnStatement: + MOZ_TRY_VAR(result, parseInterfaceReturnStatement(start, kind, fields)); + break; + case BinKind::SwitchStatement: + MOZ_TRY_VAR(result, parseInterfaceSwitchStatement(start, kind, fields)); + break; + case BinKind::SwitchStatementWithDefault: + MOZ_TRY_VAR(result, parseInterfaceSwitchStatementWithDefault(start, kind, fields)); + break; + case BinKind::ThrowStatement: + MOZ_TRY_VAR(result, parseInterfaceThrowStatement(start, kind, fields)); + break; + case BinKind::TryCatchStatement: + MOZ_TRY_VAR(result, parseInterfaceTryCatchStatement(start, kind, fields)); + break; + case BinKind::TryFinallyStatement: + MOZ_TRY_VAR(result, parseInterfaceTryFinallyStatement(start, kind, fields)); + break; + case BinKind::VariableDeclaration: + MOZ_TRY_VAR(result, parseInterfaceVariableDeclaration(start, kind, fields)); + break; + case BinKind::WhileStatement: + MOZ_TRY_VAR(result, parseInterfaceWhileStatement(start, kind, fields)); + break; + case BinKind::WithStatement: + MOZ_TRY_VAR(result, parseInterfaceWithStatement(start, kind, fields)); + break; + default: + return raiseInvalidKind("Statement", kind); + } + return result; +} + +/* +VariableDeclarationOrExpression ::= ArrayExpression + ArrowExpression + AssignmentExpression + AwaitExpression + BinaryExpression + CallExpression + ClassExpression + CompoundAssignmentExpression + ComputedMemberExpression + ConditionalExpression + FunctionExpression + IdentifierExpression + LiteralBooleanExpression + LiteralInfinityExpression + LiteralNullExpression + LiteralNumericExpression + LiteralRegExpExpression + LiteralStringExpression + NewExpression + NewTargetExpression + ObjectExpression + StaticMemberExpression + TemplateExpression + ThisExpression + UnaryExpression + UpdateExpression + VariableDeclaration + YieldExpression + YieldStarExpression +*/ +JS::Result +BinASTParser::parseVariableDeclarationOrExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + const auto start = tokenizer_->offset(); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + + MOZ_TRY_DECL(result, parseSumVariableDeclarationOrExpression(start, kind, fields)); + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseSumVariableDeclarationOrExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + ParseNode* result; + switch(kind) { + case BinKind::ArrayExpression: + MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields)); + break; + case BinKind::ArrowExpression: + MOZ_TRY_VAR(result, parseInterfaceArrowExpression(start, kind, fields)); + break; + case BinKind::AssignmentExpression: + MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind, fields)); + break; + case BinKind::AwaitExpression: + MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields)); + break; + case BinKind::BinaryExpression: + MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields)); + break; + case BinKind::CallExpression: + MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields)); + break; + case BinKind::ClassExpression: + MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields)); + break; + case BinKind::CompoundAssignmentExpression: + MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(start, kind, fields)); + break; + case BinKind::ComputedMemberExpression: + MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(start, kind, fields)); + break; + case BinKind::ConditionalExpression: + MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind, fields)); + break; + case BinKind::FunctionExpression: + MOZ_TRY_VAR(result, parseInterfaceFunctionExpression(start, kind, fields)); + break; + case BinKind::IdentifierExpression: + MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind, fields)); + break; + case BinKind::LiteralBooleanExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(start, kind, fields)); + break; + case BinKind::LiteralInfinityExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(start, kind, fields)); + break; + case BinKind::LiteralNullExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind, fields)); + break; + case BinKind::LiteralNumericExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(start, kind, fields)); + break; + case BinKind::LiteralRegExpExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(start, kind, fields)); + break; + case BinKind::LiteralStringExpression: + MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(start, kind, fields)); + break; + case BinKind::NewExpression: + MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields)); + break; + case BinKind::NewTargetExpression: + MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields)); + break; + case BinKind::ObjectExpression: + MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields)); + break; + case BinKind::StaticMemberExpression: + MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(start, kind, fields)); + break; + case BinKind::TemplateExpression: + MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields)); + break; + case BinKind::ThisExpression: + MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields)); + break; + case BinKind::UnaryExpression: + MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields)); + break; + case BinKind::UpdateExpression: + MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields)); + break; + case BinKind::VariableDeclaration: + MOZ_TRY_VAR(result, parseInterfaceVariableDeclaration(start, kind, fields)); + break; + case BinKind::YieldExpression: + MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields)); + break; + case BinKind::YieldStarExpression: + MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields)); + break; + default: + return raiseInvalidKind("VariableDeclarationOrExpression", kind); + } + return result; +} + + + +// ----- Interfaces (autogenerated, by lexicographical order) +// When fields have a non-trivial type, implementation is deanonymized and delegated to another parser. + +/* + interface ArrayAssignmentTarget : Node { + FrozenArray<(AssignmentTarget or AssignmentTargetWithInitializer)> elements; + AssignmentTarget? rest; + } +*/ +JS::Result +BinASTParser::parseArrayAssignmentTarget() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceArrayAssignmentTarget(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceArrayAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ArrayAssignmentTarget)"); +} + + +/* + interface ArrayBinding : Node { + FrozenArray<(Binding or BindingWithInitializer)?> elements; + Binding? rest; + } +*/ +JS::Result +BinASTParser::parseArrayBinding() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceArrayBinding(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceArrayBinding(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ArrayBinding)"); +} + + +/* + interface ArrayExpression : Node { + FrozenArray<(SpreadElement or Expression)?> elements; + } +*/ +JS::Result +BinASTParser::parseArrayExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceArrayExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceArrayExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::ArrayExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Elements })); + + + + MOZ_TRY_DECL(elements, parseListOfOptionalSpreadElementOrExpression()); + + + auto result = elements;return result; +} + + +/* + interface ArrowExpression : Node { + bool isAsync; + AssertedParameterScope? parameterScope; + AssertedVarScope? bodyScope; + FormalParameters params; + (FunctionBody or Expression) body; + } +*/ +JS::Result +BinASTParser::parseArrowExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceArrowExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceArrowExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ArrowExpression)"); +} + + +/* + interface AssertedBlockScope : Node { + FrozenArray lexicallyDeclaredNames; + FrozenArray capturedNames; + bool hasDirectEval; + } +*/ +JS::Result +BinASTParser::parseAssertedBlockScope() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceAssertedBlockScope(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceAssertedBlockScope(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::AssertedBlockScope); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::LexicallyDeclaredNames, BinField::CapturedNames, BinField::HasDirectEval })); + MOZ_TRY(parseAndUpdateScopeNames(*parseContext_->innermostScope(), DeclarationKind::Let)); + MOZ_TRY(parseAndUpdateCapturedNames()); + + + + MOZ_TRY_DECL(hasDirectEval, readBool()); + if (hasDirectEval) { + parseContext_->sc()->setHasDirectEval(); + parseContext_->sc()->setBindingsAccessedDynamically(); + } + + if (hasDirectEval && parseContext_->isFunctionBox() && !parseContext_->sc()->strict()) { + // In non-strict mode code, direct calls to eval can + // add variables to the call object. + parseContext_->functionBox()->setHasExtensibleScope(); + } + auto result = Ok();return result; +} + + +/* + interface AssertedParameterScope : Node { + FrozenArray parameterNames; + FrozenArray capturedNames; + bool hasDirectEval; + } +*/ +JS::Result +BinASTParser::parseAssertedParameterScope() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceAssertedParameterScope(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceAssertedParameterScope(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::AssertedParameterScope); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::ParameterNames, BinField::CapturedNames, BinField::HasDirectEval })); + MOZ_TRY(parseAndUpdateScopeNames(parseContext_->functionScope(), DeclarationKind:: PositionalFormalParameter)); + MOZ_TRY(parseAndUpdateCapturedNames()); + + + + MOZ_TRY_DECL(hasDirectEval, readBool()); + if (hasDirectEval) { + parseContext_->sc()->setHasDirectEval(); + parseContext_->sc()->setBindingsAccessedDynamically(); + } + + if (hasDirectEval && parseContext_->isFunctionBox() && !parseContext_->sc()->strict()) { + // In non-strict mode code, direct calls to eval can + // add variables to the call object. + parseContext_->functionBox()->setHasExtensibleScope(); + } + auto result = Ok();return result; +} + + +/* + interface AssertedVarScope : Node { + FrozenArray lexicallyDeclaredNames; + FrozenArray varDeclaredNames; + FrozenArray capturedNames; + bool hasDirectEval; + } +*/ +JS::Result +BinASTParser::parseAssertedVarScope() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceAssertedVarScope(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceAssertedVarScope(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::AssertedVarScope); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::LexicallyDeclaredNames, BinField::VarDeclaredNames, BinField::CapturedNames, BinField::HasDirectEval })); + MOZ_TRY(parseAndUpdateScopeNames(*parseContext_->innermostScope(), DeclarationKind::Let)); + MOZ_TRY(parseAndUpdateScopeNames(parseContext_->varScope(), DeclarationKind::Var)); + MOZ_TRY(parseAndUpdateCapturedNames()); + + + + MOZ_TRY_DECL(hasDirectEval, readBool()); + if (hasDirectEval) { + parseContext_->sc()->setHasDirectEval(); + parseContext_->sc()->setBindingsAccessedDynamically(); + } + + if (hasDirectEval && parseContext_->isFunctionBox() && !parseContext_->sc()->strict()) { + // In non-strict mode code, direct calls to eval can + // add variables to the call object. + parseContext_->functionBox()->setHasExtensibleScope(); + } + auto result = Ok();return result; +} + + +/* + interface AssignmentExpression : Node { + AssignmentTarget binding; + Expression expression; + } +*/ +JS::Result +BinASTParser::parseAssignmentExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceAssignmentExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::AssignmentExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Binding, BinField::Expression })); + + + + MOZ_TRY_DECL(binding, parseAssignmentTarget()); + + + + + MOZ_TRY_DECL(expression, parseExpression()); + + + TRY_DECL(result, factory_.newAssignment(ParseNodeKind::Assign, binding, expression));return result; +} + + +/* + interface AssignmentTargetIdentifier : Node { + Identifier name; + } +*/ +JS::Result +BinASTParser::parseAssignmentTargetIdentifier() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceAssignmentTargetIdentifier(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceAssignmentTargetIdentifier(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::AssignmentTargetIdentifier); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Name })); + + + RootedAtom name(cx_); + MOZ_TRY(readString(&name)); + + + if (!IsIdentifier(name)) + return raiseError("Invalid identifier"); + TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_));return result; +} + + +/* + interface AssignmentTargetPropertyIdentifier : Node { + AssignmentTargetIdentifier binding; + Expression? init; + } +*/ +JS::Result +BinASTParser::parseAssignmentTargetPropertyIdentifier() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceAssignmentTargetPropertyIdentifier(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceAssignmentTargetPropertyIdentifier(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (AssignmentTargetPropertyIdentifier)"); +} + + +/* + interface AssignmentTargetPropertyProperty : Node { + PropertyName name; + (AssignmentTarget or AssignmentTargetWithInitializer) binding; + } +*/ +JS::Result +BinASTParser::parseAssignmentTargetPropertyProperty() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceAssignmentTargetPropertyProperty(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceAssignmentTargetPropertyProperty(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (AssignmentTargetPropertyProperty)"); +} + + +/* + interface AssignmentTargetWithInitializer : Node { + AssignmentTarget binding; + Expression init; + } +*/ +JS::Result +BinASTParser::parseAssignmentTargetWithInitializer() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceAssignmentTargetWithInitializer(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceAssignmentTargetWithInitializer(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (AssignmentTargetWithInitializer)"); +} + + +/* + interface AwaitExpression : Node { + Expression expression; + } +*/ +JS::Result +BinASTParser::parseAwaitExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceAwaitExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceAwaitExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (AwaitExpression)"); +} + + +/* + interface BinaryExpression : Node { + BinaryOperator operator; + Expression left; + Expression right; + } +*/ +JS::Result +BinASTParser::parseBinaryExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceBinaryExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceBinaryExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::BinaryExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Operator, BinField::Left, BinField::Right })); + + + + MOZ_TRY_DECL(operator_, parseBinaryOperator()); + + + + + MOZ_TRY_DECL(left, parseExpression()); + + + + + MOZ_TRY_DECL(right, parseExpression()); + + + ParseNodeKind pnk; + switch (operator_) { + case BinaryOperator::Comma: + pnk = ParseNodeKind::Comma; + break; + case BinaryOperator::LogicalOr: + pnk = ParseNodeKind::Or; + break; + case BinaryOperator::LogicalAnd: + pnk = ParseNodeKind::And; + break; + case BinaryOperator::BitOr: + pnk = ParseNodeKind::BitOr; + break; + case BinaryOperator::BitXor: + pnk = ParseNodeKind::BitXor; + break; + case BinaryOperator::BitAnd: + pnk = ParseNodeKind::BitAnd; + break; + case BinaryOperator::Eq: + pnk = ParseNodeKind::Eq; + break; + case BinaryOperator::Neq: + pnk = ParseNodeKind::Ne; + break; + case BinaryOperator::StrictEq: + pnk = ParseNodeKind::StrictEq; + break; + case BinaryOperator::StrictNeq: + pnk = ParseNodeKind::StrictNe; + break; + case BinaryOperator::LessThan: + pnk = ParseNodeKind::Lt; + break; + case BinaryOperator::LeqThan: + pnk = ParseNodeKind::Le; + break; + case BinaryOperator::GreaterThan: + pnk = ParseNodeKind::Gt; + break; + case BinaryOperator::GeqThan: + pnk = ParseNodeKind::Ge; + break; + case BinaryOperator::In: + pnk = ParseNodeKind::In; + break; + case BinaryOperator::Instanceof: + pnk = ParseNodeKind::InstanceOf; + break; + case BinaryOperator::Lsh: + pnk = ParseNodeKind::Lsh; + break; + case BinaryOperator::Rsh: + pnk = ParseNodeKind::Rsh; + break; + case BinaryOperator::Ursh: + pnk = ParseNodeKind::Ursh; + break; + case BinaryOperator::Plus: + pnk = ParseNodeKind::Add; + break; + case BinaryOperator::Minus: + pnk = ParseNodeKind::Sub; + break; + case BinaryOperator::Mul: + pnk = ParseNodeKind::Star; + break; + case BinaryOperator::Div: + pnk = ParseNodeKind::Div; + break; + case BinaryOperator::Mod: + pnk = ParseNodeKind::Mod; + break; + case BinaryOperator::Pow: + pnk = ParseNodeKind::Pow; + break; + } + + ParseNode* result; + if (left->isKind(pnk) && + pnk != ParseNodeKind::Pow /* ParseNodeKind::Pow is not left-associative */) + { + // Regroup left-associative operations into lists. + left->appendWithoutOrderAssumption(right); + result = left; + } else { + TRY_DECL(list, factory_.newList(pnk, tokenizer_->pos(start))); + + list->appendWithoutOrderAssumption(left); + list->appendWithoutOrderAssumption(right); + result = list; + }return result; +} + + +/* + interface BindingIdentifier : Node { + Identifier name; + } +*/ +JS::Result +BinASTParser::parseBindingIdentifier() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceBindingIdentifier(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceBindingIdentifier(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::BindingIdentifier); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Name })); + + + RootedAtom name(cx_); + MOZ_TRY(readString(&name)); + + + if (!IsIdentifier(name)) + return raiseError("Invalid identifier"); + TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_));return result; +} + + +/* + interface BindingPropertyIdentifier : Node { + BindingIdentifier binding; + Expression? init; + } +*/ +JS::Result +BinASTParser::parseBindingPropertyIdentifier() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceBindingPropertyIdentifier(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceBindingPropertyIdentifier(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (BindingPropertyIdentifier)"); +} + + +/* + interface BindingPropertyProperty : Node { + PropertyName name; + (Binding or BindingWithInitializer) binding; + } +*/ +JS::Result +BinASTParser::parseBindingPropertyProperty() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceBindingPropertyProperty(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceBindingPropertyProperty(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (BindingPropertyProperty)"); +} + + +/* + interface BindingWithInitializer : Node { + Binding binding; + Expression init; + } +*/ +JS::Result +BinASTParser::parseBindingWithInitializer() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceBindingWithInitializer(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceBindingWithInitializer(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (BindingWithInitializer)"); +} + + +/* + interface Block : Node { + AssertedBlockScope? scope; + FrozenArray statements; + } +*/ +JS::Result +BinASTParser::parseBlock() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceBlock(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceBlock(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::Block); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Scope, BinField::Statements })); + fprintf(stderr, "Block: PUSH parse context\n"); + ParseContext::Statement stmt(parseContext_, StatementKind::Block); + ParseContext::Scope currentScope(cx_, parseContext_, usedNames_); + TRY(currentScope.init(parseContext_)); + + + MOZ_TRY(parseOptionalAssertedBlockScope()); + + + + + MOZ_TRY_DECL(statements, parseListOfStatement()); + + + TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, parseContext_)); + TRY_DECL(result, factory_.newLexicalScope(*bindings, statements)); + fprintf(stderr, "Block: POP parse context\n");return result; +} + + +/* + interface BreakStatement : Node { + Label? label; + } +*/ +JS::Result +BinASTParser::parseBreakStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceBreakStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceBreakStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::BreakStatement); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Label })); + RootedAtom label(cx_); + MOZ_TRY(readMaybeString(&label)); + + if (label && !IsIdentifier(label)) + return raiseError("Invalid identifier"); + + if (label) { + auto validity = parseContext_->checkBreakStatement(label->asPropertyName()); + + if (validity.isErr()) { + switch (validity.unwrapErr()) { + case ParseContext::BreakStatementError::ToughBreak: + return raiseError(kind, "Not in a loop"); + case ParseContext::BreakStatementError::LabelNotFound: + return raiseError(kind, "Label not found"); + } + } + } + TRY_DECL(result, factory_.newBreakStatement(label ? label->asPropertyName() : nullptr, tokenizer_->pos(start)));return result; +} + + +/* + interface CallExpression : Node { + (Expression or Super) callee; + Arguments arguments; + } +*/ +JS::Result +BinASTParser::parseCallExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceCallExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceCallExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::CallExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Callee, BinField::Arguments })); + + + + MOZ_TRY_DECL(callee, parseExpressionOrSuper()); + + + + + MOZ_TRY_DECL(arguments, parseArguments()); + + + auto op = JSOP_CALL; + // Check for direct calls to `eval`. + if (factory_.isEvalName(callee, cx_)) { + if (!parseContext_->varScope().lookupDeclaredNameForAdd(callee->name()) + && !parseContext_->innermostScope()->lookupDeclaredNameForAdd(callee->name())) { + // This is a direct call to `eval`. + if (!parseContext_->sc()->hasDirectEval()) + return raiseMissingDirectEvalInAssertedScope(); + + op = parseContext_->sc()->strict() ? JSOP_STRICTEVAL : JSOP_EVAL; + } + } + auto result = arguments; + result->setKind(ParseNodeKind::Call); + result->prepend(callee); + result->setOp(op);return result; +} + + +/* + interface CatchClause : Node { + Binding binding; + Block body; + } +*/ +JS::Result +BinASTParser::parseCatchClause() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceCatchClause(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceCatchClause(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::CatchClause); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Binding, BinField::Body })); + ParseContext::Statement stmt(parseContext_, StatementKind::Catch); + ParseContext::Scope currentScope(cx_, parseContext_, usedNames_); + TRY(currentScope.init(parseContext_)); + + + MOZ_TRY_DECL(binding, parseBinding()); + + + + + MOZ_TRY_DECL(body, parseBlock()); + + + // Export implicit variables to the scope. + // FIXME: Handle cases other than Name. + MOZ_ASSERT(binding->isKind(ParseNodeKind::Name)); + auto ptr = currentScope.lookupDeclaredNameForAdd(binding->name()); + TRY(currentScope.addDeclaredName(parseContext_, ptr, binding->name(), DeclarationKind::Let, start)); + + TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, parseContext_)); + TRY_DECL(result, factory_.newLexicalScope(*bindings, body)); + TRY(factory_.setupCatchScope(result, binding, body));return result; +} + + +/* + interface ClassDeclaration : Node { + BindingIdentifier name; + Expression? super; + FrozenArray elements; + } +*/ +JS::Result +BinASTParser::parseClassDeclaration() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceClassDeclaration(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceClassDeclaration(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ClassDeclaration)"); +} + + +/* + interface ClassElement : Node { + bool isStatic; + MethodDefinition method; + } +*/ +JS::Result +BinASTParser::parseClassElement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceClassElement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceClassElement(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ClassElement)"); +} + + +/* + interface ClassExpression : Node { + BindingIdentifier? name; + Expression? super; + FrozenArray elements; + } +*/ +JS::Result +BinASTParser::parseClassExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceClassExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceClassExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ClassExpression)"); +} + + +/* + interface CompoundAssignmentExpression : Node { + CompoundAssignmentOperator operator; + SimpleAssignmentTarget binding; + Expression expression; + } +*/ +JS::Result +BinASTParser::parseCompoundAssignmentExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceCompoundAssignmentExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceCompoundAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::CompoundAssignmentExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Operator, BinField::Binding, BinField::Expression })); + + + + MOZ_TRY_DECL(operator_, parseCompoundAssignmentOperator()); + + + + + MOZ_TRY_DECL(binding, parseSimpleAssignmentTarget()); + + + + + MOZ_TRY_DECL(expression, parseExpression()); + + + ParseNodeKind pnk; + switch (operator_){ + case CompoundAssignmentOperator::PlusAssign: + pnk = ParseNodeKind::AddAssign; + break; + case CompoundAssignmentOperator::MinusAssign: + pnk = ParseNodeKind::SubAssign; + break; + case CompoundAssignmentOperator::MulAssign: + pnk = ParseNodeKind::MulAssign; + break; + case CompoundAssignmentOperator::DivAssign: + pnk = ParseNodeKind::DivAssign; + break; + case CompoundAssignmentOperator::ModAssign: + pnk = ParseNodeKind::ModAssign; + break; + case CompoundAssignmentOperator::PowAssign: + pnk = ParseNodeKind::PowAssign; + break; + case CompoundAssignmentOperator::LshAssign: + pnk = ParseNodeKind::LshAssign; + break; + case CompoundAssignmentOperator::RshAssign: + pnk = ParseNodeKind::RshAssign; + break; + case CompoundAssignmentOperator::UrshAssign: + pnk = ParseNodeKind::UrshAssign; + break; + case CompoundAssignmentOperator::BitOrAssign: + pnk = ParseNodeKind::BitOrAssign; + break; + case CompoundAssignmentOperator::BitXorAssign: + pnk = ParseNodeKind::BitXorAssign; + break; + case CompoundAssignmentOperator::BitAndAssign: + pnk = ParseNodeKind::BitAndAssign; + break; + } + TRY_DECL(result, factory_.newAssignment(pnk, binding, expression));return result; +} + + +/* + interface ComputedMemberAssignmentTarget : Node { + (Expression or Super) object; + Expression expression; + } +*/ +JS::Result +BinASTParser::parseComputedMemberAssignmentTarget() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceComputedMemberAssignmentTarget(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceComputedMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::ComputedMemberAssignmentTarget); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Object, BinField::Expression })); + + + + MOZ_TRY_DECL(object, parseExpressionOrSuper()); + + + + + MOZ_TRY_DECL(expression, parseExpression()); + + + TRY_DECL(result, factory_.newPropertyByValue(object, expression, start));return result; +} + + +/* + interface ComputedMemberExpression : Node { + (Expression or Super) object; + Expression expression; + } +*/ +JS::Result +BinASTParser::parseComputedMemberExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceComputedMemberExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceComputedMemberExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::ComputedMemberExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Object, BinField::Expression })); + + + + MOZ_TRY_DECL(object, parseExpressionOrSuper()); + + + + + MOZ_TRY_DECL(expression, parseExpression()); + + + TRY_DECL(result, factory_.newPropertyByValue(object, expression, start));return result; +} + + +/* + interface ComputedPropertyName : Node { + Expression expression; + } +*/ +JS::Result +BinASTParser::parseComputedPropertyName() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceComputedPropertyName(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceComputedPropertyName(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ComputedPropertyName)"); +} + + +/* + interface ConditionalExpression : Node { + Expression test; + Expression consequent; + Expression alternate; + } +*/ +JS::Result +BinASTParser::parseConditionalExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceConditionalExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceConditionalExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::ConditionalExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Test, BinField::Consequent, BinField::Alternate })); + + + + MOZ_TRY_DECL(test, parseExpression()); + + + + + MOZ_TRY_DECL(consequent, parseExpression()); + + + + + MOZ_TRY_DECL(alternate, parseExpression()); + + + TRY_DECL(result, factory_.newConditional(test, consequent, alternate));return result; +} + + +/* + interface ContinueStatement : Node { + Label? label; + } +*/ +JS::Result +BinASTParser::parseContinueStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceContinueStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceContinueStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::ContinueStatement); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Label })); + RootedAtom label(cx_); + MOZ_TRY(readMaybeString(&label)); + + if (label && !IsIdentifier(label)) + return raiseError("ContinueStatement - Label MUST be an identifier"); + + if (label) { + auto validity = parseContext_->checkContinueStatement(label ? label->asPropertyName() : nullptr); + if (validity.isErr()) { + switch (validity.unwrapErr()) { + case ParseContext::ContinueStatementError::NotInALoop: + return raiseError(kind, "Not in a loop"); + case ParseContext::ContinueStatementError::LabelNotFound: + return raiseError(kind, "Label not found"); + } + } + } + + TRY_DECL(result, factory_.newContinueStatement(label ? label->asPropertyName() : nullptr, tokenizer_->pos(start)));return result; +} + + +/* + interface DataProperty : Node { + PropertyName name; + Expression expression; + } +*/ +JS::Result +BinASTParser::parseDataProperty() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceDataProperty(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceDataProperty(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::DataProperty); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Name, BinField::Expression })); + + + + MOZ_TRY_DECL(name, parsePropertyName()); + + + + + MOZ_TRY_DECL(expression, parseExpression()); + + + if (!factory_.isUsableAsObjectPropertyName(name)) + return raiseError("DataProperty key kind"); + + TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, expression, AccessorType::None));return result; +} + + +/* + interface DebuggerStatement : Node { + } +*/ +JS::Result +BinASTParser::parseDebuggerStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceDebuggerStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceDebuggerStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (DebuggerStatement)"); +} + + +/* + interface Directive : Node { + string rawValue; + } +*/ +JS::Result +BinASTParser::parseDirective() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceDirective(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceDirective(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::Directive); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::RawValue })); + + + RootedAtom rawValue(cx_); + MOZ_TRY(readString(&rawValue)); + + + TokenPos pos = tokenizer_->pos(start); + TRY_DECL(result, factory_.newStringLiteral(rawValue, pos));return result; +} + + +/* + interface DoWhileStatement : Node { + Expression test; + Statement body; + } +*/ +JS::Result +BinASTParser::parseDoWhileStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceDoWhileStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceDoWhileStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::DoWhileStatement); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Test, BinField::Body })); + ParseContext::Statement stmt(parseContext_, StatementKind::DoLoop); + + + MOZ_TRY_DECL(test, parseExpression()); + + + + + MOZ_TRY_DECL(body, parseStatement()); + + + TRY_DECL(result, factory_.newDoWhileStatement(body, test, tokenizer_->pos(start)));return result; +} + + +/* + interface EmptyStatement : Node { + } +*/ +JS::Result +BinASTParser::parseEmptyStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceEmptyStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceEmptyStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::EmptyStatement); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields0(kind, fields)); + + TRY_DECL(result, factory_.newEmptyStatement(tokenizer_->pos(start)));return result; +} + + +/* + interface Export : Node { + (FunctionDeclaration or ClassDeclaration or VariableDeclaration) declaration; + } +*/ +JS::Result +BinASTParser::parseExport() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceExport(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceExport(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (Export)"); +} + + +/* + interface ExportAllFrom : Node { + string moduleSpecifier; + } +*/ +JS::Result +BinASTParser::parseExportAllFrom() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceExportAllFrom(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceExportAllFrom(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ExportAllFrom)"); +} + + +/* + interface ExportDefault : Node { + (FunctionDeclaration or ClassDeclaration or Expression) body; + } +*/ +JS::Result +BinASTParser::parseExportDefault() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceExportDefault(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceExportDefault(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ExportDefault)"); +} + + +/* + interface ExportFrom : Node { + FrozenArray namedExports; + string moduleSpecifier; + } +*/ +JS::Result +BinASTParser::parseExportFrom() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceExportFrom(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceExportFrom(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ExportFrom)"); +} + + +/* + interface ExportFromSpecifier : Node { + IdentifierName name; + IdentifierName? exportedName; + } +*/ +JS::Result +BinASTParser::parseExportFromSpecifier() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceExportFromSpecifier(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceExportFromSpecifier(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ExportFromSpecifier)"); +} + + +/* + interface ExportLocalSpecifier : Node { + IdentifierExpression name; + IdentifierName? exportedName; + } +*/ +JS::Result +BinASTParser::parseExportLocalSpecifier() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceExportLocalSpecifier(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceExportLocalSpecifier(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ExportLocalSpecifier)"); +} + + +/* + interface ExportLocals : Node { + FrozenArray namedExports; + } +*/ +JS::Result +BinASTParser::parseExportLocals() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceExportLocals(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceExportLocals(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ExportLocals)"); +} + + +/* + interface ExpressionStatement : Node { + Expression expression; + } +*/ +JS::Result +BinASTParser::parseExpressionStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceExpressionStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceExpressionStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::ExpressionStatement); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Expression })); + + + + MOZ_TRY_DECL(expression, parseExpression()); + + + TRY_DECL(result, factory_.newExprStatement(expression, tokenizer_->offset()));return result; +} + + +/* + interface ForInOfBinding : Node { + VariableDeclarationKind kind; + Binding binding; + } +*/ +JS::Result +BinASTParser::parseForInOfBinding() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceForInOfBinding(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceForInOfBinding(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::ForInOfBinding); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Kind, BinField::Binding })); + AutoVariableDeclarationKind kindGuard(this); + + + MOZ_TRY_DECL(kind_, parseVariableDeclarationKind()); + + + + + MOZ_TRY_DECL(binding, parseBinding()); + + + // Restored by `kindGuard`. + variableDeclarationKind_ = kind_; + MOZ_TRY(checkBinding(binding->pn_atom->asPropertyName())); + auto pnk = + kind_ == VariableDeclarationKind::Let + ? ParseNodeKind::Let + : ParseNodeKind::Var; + TRY_DECL(result, factory_.newDeclarationList(pnk, tokenizer_->pos(start))); + factory_.addList(result, binding);return result; +} + + +/* + interface ForInStatement : Node { + (ForInOfBinding or AssignmentTarget) left; + Expression right; + Statement body; + } +*/ +JS::Result +BinASTParser::parseForInStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceForInStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceForInStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::ForInStatement); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Left, BinField::Right, BinField::Body })); + ParseContext::Statement stmt(parseContext_, StatementKind::ForInLoop); + + // Implicit scope around the `for`, used to store `for (let x in ...)` + // or `for (const x in ...)`-style declarations. Detail on the + // declaration is stored as part of `scope`. + ParseContext::Scope scope(cx_, parseContext_, usedNames_); + TRY(scope.init(parseContext_)); + + + MOZ_TRY_DECL(left, parseForInOfBindingOrAssignmentTarget()); + + + + + MOZ_TRY_DECL(right, parseExpression()); + + + + + MOZ_TRY_DECL(body, parseStatement()); + + + TRY_DECL(forHead, factory_.newForInOrOfHead(ParseNodeKind::ForIn, left, right, tokenizer_->pos(start))); + TRY_DECL(result, factory_.newForStatement(start, forHead, body, /*flags*/ 0)); + + if (!scope.isEmpty()) { + TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, parseContext_)); + TRY_VAR(result, factory_.newLexicalScope(*bindings, result)); + }return result; +} + + +/* + interface ForOfStatement : Node { + (ForInOfBinding or AssignmentTarget) left; + Expression right; + Statement body; + } +*/ +JS::Result +BinASTParser::parseForOfStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceForOfStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceForOfStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ForOfStatement)"); +} + + +/* + interface ForStatement : Node { + (VariableDeclaration or Expression)? init; + Expression? test; + Expression? update; + Statement body; + } +*/ +JS::Result +BinASTParser::parseForStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceForStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceForStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::ForStatement); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Init, BinField::Test, BinField::Update, BinField::Body })); + ParseContext::Statement stmt(parseContext_, StatementKind::ForLoop); + + // Implicit scope around the `for`, used to store `for (let x; ...; ...)` + // or `for (const x; ...; ...)`-style declarations. Detail on the + // declaration is stored as part of `BINJS_Scope`. + ParseContext::Scope scope(cx_, parseContext_, usedNames_); + TRY(scope.init(parseContext_)); + + + MOZ_TRY_DECL(init, parseOptionalVariableDeclarationOrExpression()); + + + + + MOZ_TRY_DECL(test, parseOptionalExpression()); + + + + + MOZ_TRY_DECL(update, parseOptionalExpression()); + + + + + MOZ_TRY_DECL(body, parseStatement()); + + + TRY_DECL(forHead, factory_.newForHead(init, test, update, tokenizer_->pos(start))); + TRY_DECL(result, factory_.newForStatement(start, forHead, body, /* iflags = */ 0)); + + if (!scope.isEmpty()) { + TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, parseContext_)); + TRY_VAR(result, factory_.newLexicalScope(*bindings, result)); + }return result; +} + + +/* + interface FormalParameters : Node { + FrozenArray items; + Binding? rest; + } +*/ +JS::Result +BinASTParser::parseFormalParameters() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceFormalParameters(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceFormalParameters(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::FormalParameters); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Items, BinField::Rest })); + + + + MOZ_TRY_DECL(items, parseListOfParameter()); + + + + + MOZ_TRY_DECL(rest, parseOptionalBinding()); + + + auto result = items; + if (rest) { + TRY_DECL(spread, factory_.newSpread(start, rest)); + factory_.addList(result, spread); + }return result; +} + + +/* + interface FunctionBody : Node { + FrozenArray directives; + FrozenArray statements; + } +*/ +JS::Result +BinASTParser::parseFunctionBody() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceFunctionBody(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceFunctionBody(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::FunctionBody); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Directives, BinField::Statements })); + + + + MOZ_TRY_DECL(directives, parseListOfDirective()); + + + + + MOZ_TRY_DECL(statements, parseListOfStatement()); + + + MOZ_TRY_DECL(result, appendDirectivesToBody(/* body = */ statements, /* directives = */ directives));return result; +} + + +/* + interface FunctionDeclaration : Node { + bool isAsync; + bool isGenerator; + AssertedParameterScope? parameterScope; + AssertedVarScope? bodyScope; + BindingIdentifier name; + FormalParameters params; + FunctionBody body; + } +*/ +JS::Result +BinASTParser::parseFunctionDeclaration() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceFunctionDeclaration(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::FunctionDeclaration); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::IsAsync, BinField::IsGenerator, BinField::ParameterScope, BinField::BodyScope, BinField::Name, BinField::Params, BinField::Body })); + + + + MOZ_TRY_DECL(isAsync, readBool()); + + + + + MOZ_TRY_DECL(isGenerator, readBool()); + + + MOZ_TRY_DECL(funbox, buildFunctionBox( + isGenerator ? GeneratorKind::Generator + : GeneratorKind::NotGenerator, + isAsync ? FunctionAsyncKind::AsyncFunction + : FunctionAsyncKind::SyncFunction)); + + // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function. + BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr); + TRY(funpc.init()); + parseContext_->functionScope().useAsVarScope(parseContext_); + MOZ_ASSERT(parseContext_->isFunctionBox()); + + ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_); + TRY(lexicalScope.init(parseContext_)); + + MOZ_TRY(parseOptionalAssertedParameterScope()); + + + + + MOZ_TRY(parseOptionalAssertedVarScope()); + + + + + MOZ_TRY_DECL(name, parseBindingIdentifier()); + + + + + MOZ_TRY_DECL(params, parseFormalParameters()); + + + + + MOZ_TRY_DECL(body, parseFunctionBody()); + + + TRY_DECL(lexicalScopeData, NewLexicalScopeData(cx_, lexicalScope, alloc_, parseContext_)); + TRY_VAR(body, factory_.newLexicalScope(*lexicalScopeData, body)); + MOZ_TRY_DECL(result, buildFunction(start, kind, name, params, body, funbox));return result; +} + + +/* + interface FunctionExpression : Node { + bool isAsync; + bool isGenerator; + AssertedParameterScope? parameterScope; + AssertedVarScope? bodyScope; + BindingIdentifier? name; + FormalParameters params; + FunctionBody body; + } +*/ +JS::Result +BinASTParser::parseFunctionExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceFunctionExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::FunctionExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::IsAsync, BinField::IsGenerator, BinField::ParameterScope, BinField::BodyScope, BinField::Name, BinField::Params, BinField::Body })); + + + + MOZ_TRY_DECL(isAsync, readBool()); + + + + + MOZ_TRY_DECL(isGenerator, readBool()); + + + MOZ_TRY_DECL(funbox, buildFunctionBox( + isGenerator ? GeneratorKind::Generator + : GeneratorKind::NotGenerator, + isAsync ? FunctionAsyncKind::AsyncFunction + : FunctionAsyncKind::SyncFunction)); + + // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function. + BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr); + TRY(funpc.init()); + parseContext_->functionScope().useAsVarScope(parseContext_); + MOZ_ASSERT(parseContext_->isFunctionBox()); + + ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_); + TRY(lexicalScope.init(parseContext_)); + + MOZ_TRY(parseOptionalAssertedParameterScope()); + + + + + MOZ_TRY(parseOptionalAssertedVarScope()); + + + + + MOZ_TRY_DECL(name, parseOptionalBindingIdentifier()); + + + + + MOZ_TRY_DECL(params, parseFormalParameters()); + + + + + MOZ_TRY_DECL(body, parseFunctionBody()); + + + TRY_DECL(lexicalScopeData, NewLexicalScopeData(cx_, lexicalScope, alloc_, parseContext_)); + TRY_VAR(body, factory_.newLexicalScope(*lexicalScopeData, body)); + MOZ_TRY_DECL(result, buildFunction(start, kind, name, params, body, funbox));return result; +} + + +/* + interface Getter : Node { + AssertedVarScope? bodyScope; + PropertyName name; + FunctionBody body; + } +*/ +JS::Result +BinASTParser::parseGetter() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceGetter(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceGetter(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (Getter)"); +} + + +/* + interface IdentifierExpression : Node { + Identifier name; + } +*/ +JS::Result +BinASTParser::parseIdentifierExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceIdentifierExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceIdentifierExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::IdentifierExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Name })); + + + RootedAtom name(cx_); + MOZ_TRY(readString(&name)); + + + if (!IsIdentifier(name)) + return raiseError("Invalid identifier"); + TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_));return result; +} + + +/* + interface IfStatement : Node { + Expression test; + Statement consequent; + Statement? alternate; + } +*/ +JS::Result +BinASTParser::parseIfStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceIfStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceIfStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::IfStatement); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Test, BinField::Consequent, BinField::Alternate })); + + + + MOZ_TRY_DECL(test, parseExpression()); + + + + + MOZ_TRY_DECL(consequent, parseStatement()); + + + + + MOZ_TRY_DECL(alternate, parseOptionalStatement()); + + + TRY_DECL(result, factory_.newIfStatement(start, test, consequent, alternate));return result; +} + + +/* + interface Import : Node { + string moduleSpecifier; + BindingIdentifier? defaultBinding; + FrozenArray namedImports; + } +*/ +JS::Result +BinASTParser::parseImport() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceImport(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceImport(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (Import)"); +} + + +/* + interface ImportNamespace : Node { + string moduleSpecifier; + BindingIdentifier? defaultBinding; + BindingIdentifier namespaceBinding; + } +*/ +JS::Result +BinASTParser::parseImportNamespace() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceImportNamespace(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceImportNamespace(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ImportNamespace)"); +} + + +/* + interface ImportSpecifier : Node { + IdentifierName? name; + BindingIdentifier binding; + } +*/ +JS::Result +BinASTParser::parseImportSpecifier() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceImportSpecifier(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceImportSpecifier(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ImportSpecifier)"); +} + + +/* + interface LabelledStatement : Node { + Label label; + Statement body; + } +*/ +JS::Result +BinASTParser::parseLabelledStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceLabelledStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceLabelledStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::LabelledStatement); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Label, BinField::Body })); + + + RootedAtom label(cx_); + MOZ_TRY(readString(&label)); + if (!IsIdentifier(label)) + return raiseError("Invalid identifier"); + ParseContext::LabelStatement stmt(parseContext_, label); + + + + MOZ_TRY_DECL(body, parseStatement()); + + + TRY_DECL(result, factory_.newLabeledStatement(label->asPropertyName(), body, start));return result; +} + + +/* + interface LiteralBooleanExpression : Node { + bool value; + } +*/ +JS::Result +BinASTParser::parseLiteralBooleanExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceLiteralBooleanExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceLiteralBooleanExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::LiteralBooleanExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Value })); + + + + MOZ_TRY_DECL(value, readBool()); + + + TRY_DECL(result, factory_.newBooleanLiteral(value, tokenizer_->pos(start)));return result; +} + + +/* + interface LiteralInfinityExpression : Node { + } +*/ +JS::Result +BinASTParser::parseLiteralInfinityExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceLiteralInfinityExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceLiteralInfinityExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (LiteralInfinityExpression)"); +} + + +/* + interface LiteralNullExpression : Node { + } +*/ +JS::Result +BinASTParser::parseLiteralNullExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceLiteralNullExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceLiteralNullExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::LiteralNullExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields0(kind, fields)); + + TRY_DECL(result, factory_.newNullLiteral(tokenizer_->pos(start)));return result; +} + + +/* + interface LiteralNumericExpression : Node { + number value; + } +*/ +JS::Result +BinASTParser::parseLiteralNumericExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceLiteralNumericExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceLiteralNumericExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::LiteralNumericExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Value })); + + + + MOZ_TRY_DECL(value, readNumber()); + + + TRY_DECL(result, factory_.newNumber(value, DecimalPoint::HasDecimal, tokenizer_->pos(start)));return result; +} + + +/* + interface LiteralPropertyName : Node { + string value; + } +*/ +JS::Result +BinASTParser::parseLiteralPropertyName() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceLiteralPropertyName(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceLiteralPropertyName(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::LiteralPropertyName); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Value })); + + + RootedAtom value(cx_); + MOZ_TRY(readString(&value)); + + + ParseNode* result; + uint32_t index; + if (value->isIndex(&index)) + TRY_VAR(result, factory_.newNumber(index, NoDecimal, TokenPos(start, tokenizer_->offset()))); + else + TRY_VAR(result, factory_.newObjectLiteralPropertyName(value, tokenizer_->pos(start)));return result; +} + + +/* + interface LiteralRegExpExpression : Node { + string pattern; + string flags; + } +*/ +JS::Result +BinASTParser::parseLiteralRegExpExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceLiteralRegExpExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceLiteralRegExpExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::LiteralRegExpExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Pattern, BinField::Flags })); + + + RootedAtom pattern(cx_); + MOZ_TRY(readString(&pattern)); + + Chars flags(cx_); MOZ_TRY(readString(flags)); + + RegExpFlag reflags = NoFlags; + for (auto 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 raiseInvalidEnum("RegExpLiteral", flags); + } + + + Rooted reobj(cx_); + TRY_VAR(reobj, RegExpObject::create(cx_, + pattern, + reflags, + alloc_, + TenuredObject)); + + TRY_DECL(result, factory_.newRegExp(reobj, tokenizer_->pos(start), *this));return result; +} + + +/* + interface LiteralStringExpression : Node { + string value; + } +*/ +JS::Result +BinASTParser::parseLiteralStringExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceLiteralStringExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceLiteralStringExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::LiteralStringExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Value })); + + + RootedAtom value(cx_); + MOZ_TRY(readString(&value)); + + + TRY_DECL(result, factory_.newStringLiteral(value, tokenizer_->pos(start)));return result; +} + + +/* + interface Method : Node { + bool isAsync; + bool isGenerator; + AssertedParameterScope? parameterScope; + AssertedVarScope? bodyScope; + PropertyName name; + FormalParameters params; + FunctionBody body; + } +*/ +JS::Result +BinASTParser::parseMethod() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceMethod(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceMethod(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::Method); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::IsAsync, BinField::IsGenerator, BinField::ParameterScope, BinField::BodyScope, BinField::Name, BinField::Params, BinField::Body })); + + + + MOZ_TRY_DECL(isAsync, readBool()); + + + + + MOZ_TRY_DECL(isGenerator, readBool()); + + + MOZ_TRY_DECL(funbox, buildFunctionBox( + isGenerator ? GeneratorKind::Generator + : GeneratorKind::NotGenerator, + isAsync ? FunctionAsyncKind::AsyncFunction + : FunctionAsyncKind::SyncFunction)); + + // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function. + BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr); + TRY(funpc.init()); + parseContext_->functionScope().useAsVarScope(parseContext_); + MOZ_ASSERT(parseContext_->isFunctionBox()); + + ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_); + TRY(lexicalScope.init(parseContext_)); + + MOZ_TRY(parseOptionalAssertedParameterScope()); + + + + + MOZ_TRY(parseOptionalAssertedVarScope()); + + + + + MOZ_TRY_DECL(name, parsePropertyName()); + + + + + MOZ_TRY_DECL(params, parseFormalParameters()); + + + + + MOZ_TRY_DECL(body, parseFunctionBody()); + + + MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body, funbox)); + TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, method, AccessorType::None));return result; +} + + +/* + interface Module : Node { + AssertedVarScope? scope; + FrozenArray directives; + FrozenArray<(ImportDeclaration or ExportDeclaration or Statement)> items; + } +*/ +JS::Result +BinASTParser::parseModule() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceModule(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceModule(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (Module)"); +} + + +/* + interface NewExpression : Node { + Expression callee; + Arguments arguments; + } +*/ +JS::Result +BinASTParser::parseNewExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceNewExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceNewExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::NewExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Callee, BinField::Arguments })); + + + + MOZ_TRY_DECL(callee, parseExpression()); + + + + + MOZ_TRY_DECL(arguments, parseArguments()); + + + auto result = arguments; + result->setKind(ParseNodeKind::New); + result->prepend(callee);return result; +} + + +/* + interface NewTargetExpression : Node { + } +*/ +JS::Result +BinASTParser::parseNewTargetExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceNewTargetExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceNewTargetExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (NewTargetExpression)"); +} + + +/* + interface ObjectAssignmentTarget : Node { + FrozenArray properties; + } +*/ +JS::Result +BinASTParser::parseObjectAssignmentTarget() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceObjectAssignmentTarget(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceObjectAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ObjectAssignmentTarget)"); +} + + +/* + interface ObjectBinding : Node { + FrozenArray properties; + } +*/ +JS::Result +BinASTParser::parseObjectBinding() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceObjectBinding(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceObjectBinding(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (ObjectBinding)"); +} + + +/* + interface ObjectExpression : Node { + FrozenArray properties; + } +*/ +JS::Result +BinASTParser::parseObjectExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceObjectExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceObjectExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::ObjectExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Properties })); + + + + MOZ_TRY_DECL(properties, parseListOfObjectProperty()); + + + auto result = properties;return result; +} + + +/* + interface ReturnStatement : Node { + Expression? expression; + } +*/ +JS::Result +BinASTParser::parseReturnStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceReturnStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceReturnStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::ReturnStatement); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Expression })); + if (!parseContext_->isFunctionBox()) { + // Return statements are permitted only inside functions. + return raiseInvalidKind("Toplevel Statement", kind); + } + + parseContext_->functionBox()->usesReturn = true; + + + MOZ_TRY_DECL(expression, parseOptionalExpression()); + + + TRY_DECL(result, factory_.newReturnStatement(expression, tokenizer_->pos(start)));return result; +} + + +/* + interface Script : Node { + AssertedVarScope? scope; + FrozenArray directives; + FrozenArray statements; + } +*/ +JS::Result +BinASTParser::parseScript() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceScript(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceScript(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::Script); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Scope, BinField::Directives, BinField::Statements })); + + + + MOZ_TRY(parseOptionalAssertedVarScope()); + + + + + MOZ_TRY_DECL(directives, parseListOfDirective()); + + + + + MOZ_TRY_DECL(statements, parseListOfStatement()); + + + MOZ_TRY_DECL(result, appendDirectivesToBody(/* body = */ statements, /* directives = */ directives));return result; +} + + +/* + interface Setter : Node { + AssertedParameterScope? parameterScope; + AssertedVarScope? bodyScope; + PropertyName name; + Parameter param; + FunctionBody body; + } +*/ +JS::Result +BinASTParser::parseSetter() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceSetter(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceSetter(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::Setter); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::ParameterScope, BinField::BodyScope, BinField::Name, BinField::Param, BinField::Body })); + const auto isAsync = false; + const auto isGenerator = false; + MOZ_TRY_DECL(funbox, buildFunctionBox( + isGenerator ? GeneratorKind::Generator + : GeneratorKind::NotGenerator, + isAsync ? FunctionAsyncKind::AsyncFunction + : FunctionAsyncKind::SyncFunction)); + + // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function. + BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr); + TRY(funpc.init()); + parseContext_->functionScope().useAsVarScope(parseContext_); + MOZ_ASSERT(parseContext_->isFunctionBox()); + + ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_); + TRY(lexicalScope.init(parseContext_)); + + MOZ_TRY(parseOptionalAssertedParameterScope()); + + + + + MOZ_TRY(parseOptionalAssertedVarScope()); + + + + + MOZ_TRY_DECL(name, parsePropertyName()); + + + + + MOZ_TRY_DECL(param, parseParameter()); + + + + + MOZ_TRY_DECL(body, parseFunctionBody()); + + + TRY_DECL(params, factory_.newList(ParseNodeKind::ParamsBody, param)); + MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body, funbox)); + TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, method, AccessorType::Setter));return result; +} + + +/* + interface ShorthandProperty : Node { + IdentifierExpression name; + } +*/ +JS::Result +BinASTParser::parseShorthandProperty() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceShorthandProperty(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceShorthandProperty(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::ShorthandProperty); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Name })); + + + + MOZ_TRY_DECL(name, parseIdentifierExpression()); + + + if (!factory_.isUsableAsObjectPropertyName(name)) + TRY_VAR(name, factory_.newObjectLiteralPropertyName(name->name(), tokenizer_->pos(start))); + + TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, name, AccessorType::None));return result; +} + + +/* + interface SpreadElement : Node { + Expression expression; + } +*/ +JS::Result +BinASTParser::parseSpreadElement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceSpreadElement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceSpreadElement(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (SpreadElement)"); +} + + +/* + interface StaticMemberAssignmentTarget : Node { + (Expression or Super) object; + IdentifierName property; + } +*/ +JS::Result +BinASTParser::parseStaticMemberAssignmentTarget() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceStaticMemberAssignmentTarget(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceStaticMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::StaticMemberAssignmentTarget); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Object, BinField::Property })); + + + + MOZ_TRY_DECL(object, parseExpressionOrSuper()); + + + + RootedAtom property(cx_); + MOZ_TRY(readString(&property)); + + + TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), start));return result; +} + + +/* + interface StaticMemberExpression : Node { + (Expression or Super) object; + IdentifierName property; + } +*/ +JS::Result +BinASTParser::parseStaticMemberExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceStaticMemberExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceStaticMemberExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::StaticMemberExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Object, BinField::Property })); + + + + MOZ_TRY_DECL(object, parseExpressionOrSuper()); + + + + RootedAtom property(cx_); + MOZ_TRY(readString(&property)); + + + TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), start));return result; +} + + +/* + interface Super : Node { + } +*/ +JS::Result +BinASTParser::parseSuper() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceSuper(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceSuper(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (Super)"); +} + + +/* + interface SwitchCase : Node { + Expression test; + FrozenArray consequent; + } +*/ +JS::Result +BinASTParser::parseSwitchCase() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceSwitchCase(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceSwitchCase(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::SwitchCase); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Test, BinField::Consequent })); + + + + MOZ_TRY_DECL(test, parseExpression()); + + + + + MOZ_TRY_DECL(consequent, parseListOfStatement()); + + + TRY_DECL(result, factory_.newCaseOrDefault(start, test, consequent));return result; +} + + +/* + interface SwitchDefault : Node { + FrozenArray consequent; + } +*/ +JS::Result +BinASTParser::parseSwitchDefault() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceSwitchDefault(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceSwitchDefault(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::SwitchDefault); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Consequent })); + + + + MOZ_TRY_DECL(consequent, parseListOfStatement()); + + + TRY_DECL(result, factory_.newCaseOrDefault(start, nullptr, consequent));return result; +} + + +/* + interface SwitchStatement : Node { + Expression discriminant; + FrozenArray cases; + } +*/ +JS::Result +BinASTParser::parseSwitchStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceSwitchStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceSwitchStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::SwitchStatement); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Discriminant, BinField::Cases })); + + + + MOZ_TRY_DECL(discriminant, parseExpression()); + + + + + MOZ_TRY_DECL(cases, parseListOfSwitchCase()); + + + TRY_DECL(scope, factory_.newLexicalScope(nullptr, cases)); + TRY_DECL(result, factory_.newSwitchStatement(start, discriminant, scope));return result; +} + + +/* + interface SwitchStatementWithDefault : Node { + Expression discriminant; + FrozenArray preDefaultCases; + SwitchDefault defaultCase; + FrozenArray postDefaultCases; + } +*/ +JS::Result +BinASTParser::parseSwitchStatementWithDefault() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceSwitchStatementWithDefault(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceSwitchStatementWithDefault(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::SwitchStatementWithDefault); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Discriminant, BinField::PreDefaultCases, BinField::DefaultCase, BinField::PostDefaultCases })); + + + + MOZ_TRY_DECL(discriminant, parseExpression()); + + + + + MOZ_TRY_DECL(preDefaultCases, parseListOfSwitchCase()); + + + + + MOZ_TRY_DECL(defaultCase, parseSwitchDefault()); + + + + + MOZ_TRY_DECL(postDefaultCases, parseListOfSwitchCase()); + + + // Concatenate `preDefaultCase`, `defaultCase`, `postDefaultCase` + auto cases = preDefaultCases; + factory_.addList(cases, defaultCase); + ParseNode* iter = postDefaultCases->pn_head; + while (iter) { + ParseNode* next = iter->pn_next; + factory_.addList(cases, iter); + iter = next; + } + TRY_DECL(scope, factory_.newLexicalScope(nullptr, cases)); + TRY_DECL(result, factory_.newSwitchStatement(start, discriminant, scope));return result; +} + + +/* + interface TemplateElement : Node { + string rawValue; + } +*/ +JS::Result +BinASTParser::parseTemplateElement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceTemplateElement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceTemplateElement(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (TemplateElement)"); +} + + +/* + interface TemplateExpression : Node { + Expression? tag; + FrozenArray<(Expression or TemplateElement)> elements; + } +*/ +JS::Result +BinASTParser::parseTemplateExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceTemplateExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceTemplateExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (TemplateExpression)"); +} + + +/* + interface ThisExpression : Node { + } +*/ +JS::Result +BinASTParser::parseThisExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceThisExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceThisExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::ThisExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields0(kind, fields)); + + if (parseContext_->isFunctionBox()) + parseContext_->functionBox()->usesThis = true; + + TokenPos pos = tokenizer_->pos(start); + ParseNode* thisName(nullptr); + if (parseContext_->sc()->thisBinding() == ThisBinding::Function) + TRY_VAR(thisName, factory_.newName(cx_->names().dotThis, pos, cx_)); + + TRY_DECL(result, factory_.newThisLiteral(pos, thisName));return result; +} + + +/* + interface ThrowStatement : Node { + Expression expression; + } +*/ +JS::Result +BinASTParser::parseThrowStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceThrowStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceThrowStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::ThrowStatement); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Expression })); + + + + MOZ_TRY_DECL(expression, parseExpression()); + + + TRY_DECL(result, factory_.newThrowStatement(expression, tokenizer_->pos(start)));return result; +} + + +/* + interface TryCatchStatement : Node { + Block body; + CatchClause catchClause; + } +*/ +JS::Result +BinASTParser::parseTryCatchStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceTryCatchStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceTryCatchStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::TryCatchStatement); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Body, BinField::CatchClause })); + + ParseNode* body; + { + ParseContext::Statement stmt(parseContext_, StatementKind::Try); + ParseContext::Scope scope(cx_, parseContext_, usedNames_); + TRY(scope.init(parseContext_)); + MOZ_TRY_VAR(body, parseBlock()); + + } + + + + MOZ_TRY_DECL(catchClause, parseCatchClause()); + + + TRY_DECL(result, factory_.newTryStatement(start, body, catchClause, /* finally = */ nullptr));return result; +} + + +/* + interface TryFinallyStatement : Node { + Block body; + CatchClause? catchClause; + Block finalizer; + } +*/ +JS::Result +BinASTParser::parseTryFinallyStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceTryFinallyStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceTryFinallyStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::TryFinallyStatement); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Body, BinField::CatchClause, BinField::Finalizer })); + + ParseNode* body; + { + ParseContext::Statement stmt(parseContext_, StatementKind::Try); + ParseContext::Scope scope(cx_, parseContext_, usedNames_); + TRY(scope.init(parseContext_)); + MOZ_TRY_VAR(body, parseBlock()); + + } + + + + MOZ_TRY_DECL(catchClause, parseOptionalCatchClause()); + + + ParseNode* finalizer; + { + ParseContext::Statement stmt(parseContext_, StatementKind::Finally); + ParseContext::Scope scope(cx_, parseContext_, usedNames_); + TRY(scope.init(parseContext_)); + MOZ_TRY_VAR(finalizer, parseBlock()); + + } + + TRY_DECL(result, factory_.newTryStatement(start, body, catchClause, finalizer));return result; +} + + +/* + interface UnaryExpression : Node { + UnaryOperator operator; + Expression operand; + } +*/ +JS::Result +BinASTParser::parseUnaryExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceUnaryExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceUnaryExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::UnaryExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Operator, BinField::Operand })); + + + + MOZ_TRY_DECL(operator_, parseUnaryOperator()); + + + + + MOZ_TRY_DECL(operand, parseExpression()); + + + ParseNodeKind pnk; + switch (operator_) { + case UnaryOperator::Minus: + pnk = ParseNodeKind::Neg; + break; + case UnaryOperator::Plus: + pnk = ParseNodeKind::Pos; + break; + case UnaryOperator::Not: + pnk = ParseNodeKind::Not; + break; + case UnaryOperator::BitNot: + pnk = ParseNodeKind::BitNot; + break; + case UnaryOperator::Typeof: { + if (operand->isKind(ParseNodeKind::Name)) + pnk = ParseNodeKind::TypeOfName; + else + pnk = ParseNodeKind::TypeOfExpr; + break; + } + case UnaryOperator::Void: + pnk = ParseNodeKind::Void; + break; + case UnaryOperator::Delete: { + switch (operand->getKind()) { + case ParseNodeKind::Name: + operand->setOp(JSOP_DELNAME); + pnk = ParseNodeKind::DeleteName; + break; + case ParseNodeKind::Dot: + pnk = ParseNodeKind::DeleteProp; + break; + case ParseNodeKind::Elem: + pnk = ParseNodeKind::DeleteElem; + break; + default: + pnk = ParseNodeKind::DeleteExpr; + } + break; + } + } + TRY_DECL(result, factory_.newUnary(pnk, start, operand));return result; +} + + +/* + interface UpdateExpression : Node { + bool isPrefix; + UpdateOperator operator; + SimpleAssignmentTarget operand; + } +*/ +JS::Result +BinASTParser::parseUpdateExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceUpdateExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceUpdateExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::UpdateExpression); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::IsPrefix, BinField::Operator, BinField::Operand })); + + + + MOZ_TRY_DECL(isPrefix, readBool()); + + + + + MOZ_TRY_DECL(operator_, parseUpdateOperator()); + + + + + MOZ_TRY_DECL(operand, parseSimpleAssignmentTarget()); + + + ParseNodeKind pnk; + switch (operator_) { + case UpdateOperator::Incr: + pnk = isPrefix ? ParseNodeKind::PreIncrement + : ParseNodeKind::PostIncrement; + break; + case UpdateOperator::Decr: + pnk = isPrefix ? ParseNodeKind::PreDecrement + : ParseNodeKind::PostDecrement; + break; + } + TRY_DECL(result, factory_.newUnary(pnk, start, operand));return result; +} + + +/* + interface VariableDeclaration : Node { + VariableDeclarationKind kind; + FrozenArray declarators; + } +*/ +JS::Result +BinASTParser::parseVariableDeclaration() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceVariableDeclaration(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::VariableDeclaration); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Kind, BinField::Declarators })); + AutoVariableDeclarationKind kindGuard(this); + + + MOZ_TRY_DECL(kind_, parseVariableDeclarationKind()); + // Restored by `kindGuard`. + variableDeclarationKind_ = kind_; + + + + MOZ_TRY_DECL(declarators, parseListOfVariableDeclarator()); + + + // By specification, the list may not be empty. + if (declarators->pn_count == 0) + return raiseEmpty("VariableDeclaration"); + + ParseNodeKind pnk; + switch (kind_) { + case VariableDeclarationKind::Var: + pnk = ParseNodeKind::Var; + break; + case VariableDeclarationKind::Let: + pnk = ParseNodeKind::Let; + break; + case VariableDeclarationKind::Const: + pnk = ParseNodeKind::Const; + break; + } + declarators->setKind(pnk); + auto result = declarators;return result; +} + + +/* + interface VariableDeclarator : Node { + Binding binding; + Expression? init; + } +*/ +JS::Result +BinASTParser::parseVariableDeclarator() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceVariableDeclarator(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceVariableDeclarator(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::VariableDeclarator); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Binding, BinField::Init })); + + + + MOZ_TRY_DECL(binding, parseBinding()); + + + + + MOZ_TRY_DECL(init, parseOptionalExpression()); + + + ParseNode* result; + if (binding->isKind(ParseNodeKind::Name)) { + // `var foo [= bar]`` + MOZ_TRY(checkBinding(binding->pn_atom->asPropertyName())); + + TRY_VAR(result, factory_.newName(binding->pn_atom->asPropertyName(), tokenizer_->pos(start), cx_)); + if (init) + result->pn_expr = init; + } else { + // `var pattern = bar` + if (!init) { + // Here, `init` is required. + return raiseMissingField("VariableDeclarator (with non-trivial pattern)", BinField::Init); + } + + MOZ_CRASH("Unimplemented: AssertedScope check for BindingPattern variable declaration"); + TRY_VAR(result, factory_.newAssignment(ParseNodeKind::Assign, binding, init)); + }return result; +} + + +/* + interface WhileStatement : Node { + Expression test; + Statement body; + } +*/ +JS::Result +BinASTParser::parseWhileStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceWhileStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceWhileStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::WhileStatement); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Test, BinField::Body })); + ParseContext::Statement stmt(parseContext_, StatementKind::WhileLoop); + + + MOZ_TRY_DECL(test, parseExpression()); + + + + + MOZ_TRY_DECL(body, parseStatement()); + + + TRY_DECL(result, factory_.newWhileStatement(start, test, body));return result; +} + + +/* + interface WithStatement : Node { + Expression object; + Statement body; + } +*/ +JS::Result +BinASTParser::parseWithStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceWithStatement(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceWithStatement(const size_t start, const BinKind kind, const BinFields& fields) +{ + MOZ_ASSERT(kind == BinKind::WithStatement); + CheckRecursionLimit(cx_); + + MOZ_TRY(checkFields(kind, fields, { BinField::Object, BinField::Body })); + + + + MOZ_TRY_DECL(object, parseExpression()); + + + + + MOZ_TRY_DECL(body, parseStatement()); + + + TRY_DECL(result, factory_.newWithStatement(start, object, body));return result; +} + + +/* + interface YieldExpression : Node { + Expression? expression; + } +*/ +JS::Result +BinASTParser::parseYieldExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceYieldExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceYieldExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (YieldExpression)"); +} + + +/* + interface YieldStarExpression : Node { + Expression expression; + } +*/ +JS::Result +BinASTParser::parseYieldStarExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceYieldStarExpression(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceYieldStarExpression(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (YieldStarExpression)"); +} + + +/* + interface _Null : Node { + } +*/ +JS::Result +BinASTParser::parseNull() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + const auto start = tokenizer_->offset(); + + MOZ_TRY_DECL(result, parseInterfaceNull(start, kind, fields)); + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseInterfaceNull(const size_t start, const BinKind kind, const BinFields& fields) +{ + return raiseError("FIXME: Not implemented yet (Null)"); +} + + + +// ----- String enums (autogenerated, by lexicographical order) +/* +enum BinaryOperator { + ",", + "||", + "&&", + "|", + "^", + "&", + "==", + "!=", + "===", + "!==", + "<", + "<=", + ">", + ">=", + "in", + "instanceof", + "<<", + ">>", + ">>>", + "+", + "-", + "*", + "/", + "%", + "**" +}; +*/ +JS::Result +BinASTParser::parseBinaryOperator() +{ + // Unoptimized implementation. + Chars chars(cx_); + MOZ_TRY(readString(chars)); + + if (chars == ",") + return BinaryOperator::Comma; + if (chars == "||") + return BinaryOperator::LogicalOr; + if (chars == "&&") + return BinaryOperator::LogicalAnd; + if (chars == "|") + return BinaryOperator::BitOr; + if (chars == "^") + return BinaryOperator::BitXor; + if (chars == "&") + return BinaryOperator::BitAnd; + if (chars == "==") + return BinaryOperator::Eq; + if (chars == "!=") + return BinaryOperator::Neq; + if (chars == "===") + return BinaryOperator::StrictEq; + if (chars == "!==") + return BinaryOperator::StrictNeq; + if (chars == "<") + return BinaryOperator::LessThan; + if (chars == "<=") + return BinaryOperator::LeqThan; + if (chars == ">") + return BinaryOperator::GreaterThan; + if (chars == ">=") + return BinaryOperator::GeqThan; + if (chars == "in") + return BinaryOperator::In; + if (chars == "instanceof") + return BinaryOperator::Instanceof; + if (chars == "<<") + return BinaryOperator::Lsh; + if (chars == ">>") + return BinaryOperator::Rsh; + if (chars == ">>>") + return BinaryOperator::Ursh; + if (chars == "+") + return BinaryOperator::Plus; + if (chars == "-") + return BinaryOperator::Minus; + if (chars == "*") + return BinaryOperator::Mul; + if (chars == "/") + return BinaryOperator::Div; + if (chars == "%") + return BinaryOperator::Mod; + if (chars == "**") + return BinaryOperator::Pow; + + return raiseInvalidEnum("BinaryOperator", chars); +} + +/* +enum CompoundAssignmentOperator { + "+=", + "-=", + "*=", + "/=", + "%=", + "**=", + "<<=", + ">>=", + ">>>=", + "|=", + "^=", + "&=" +}; +*/ +JS::Result +BinASTParser::parseCompoundAssignmentOperator() +{ + // Unoptimized implementation. + Chars chars(cx_); + MOZ_TRY(readString(chars)); + + if (chars == "+=") + return CompoundAssignmentOperator::PlusAssign; + if (chars == "-=") + return CompoundAssignmentOperator::MinusAssign; + if (chars == "*=") + return CompoundAssignmentOperator::MulAssign; + if (chars == "/=") + return CompoundAssignmentOperator::DivAssign; + if (chars == "%=") + return CompoundAssignmentOperator::ModAssign; + if (chars == "**=") + return CompoundAssignmentOperator::PowAssign; + if (chars == "<<=") + return CompoundAssignmentOperator::LshAssign; + if (chars == ">>=") + return CompoundAssignmentOperator::RshAssign; + if (chars == ">>>=") + return CompoundAssignmentOperator::UrshAssign; + if (chars == "|=") + return CompoundAssignmentOperator::BitOrAssign; + if (chars == "^=") + return CompoundAssignmentOperator::BitXorAssign; + if (chars == "&=") + return CompoundAssignmentOperator::BitAndAssign; + + return raiseInvalidEnum("CompoundAssignmentOperator", chars); +} + +/* +enum UnaryOperator { + "+", + "-", + "!", + "~", + "typeof", + "void", + "delete" +}; +*/ +JS::Result +BinASTParser::parseUnaryOperator() +{ + // Unoptimized implementation. + Chars chars(cx_); + MOZ_TRY(readString(chars)); + + if (chars == "+") + return UnaryOperator::Plus; + if (chars == "-") + return UnaryOperator::Minus; + if (chars == "!") + return UnaryOperator::Not; + if (chars == "~") + return UnaryOperator::BitNot; + if (chars == "typeof") + return UnaryOperator::Typeof; + if (chars == "void") + return UnaryOperator::Void; + if (chars == "delete") + return UnaryOperator::Delete; + + return raiseInvalidEnum("UnaryOperator", chars); +} + +/* +enum UpdateOperator { + "++", + "--" +}; +*/ +JS::Result +BinASTParser::parseUpdateOperator() +{ + // Unoptimized implementation. + Chars chars(cx_); + MOZ_TRY(readString(chars)); + + if (chars == "++") + return UpdateOperator::Incr; + if (chars == "--") + return UpdateOperator::Decr; + + return raiseInvalidEnum("UpdateOperator", chars); +} + +/* +enum VariableDeclarationKind { + "var", + "let", + "const" +}; +*/ +JS::Result +BinASTParser::parseVariableDeclarationKind() +{ + // Unoptimized implementation. + Chars chars(cx_); + MOZ_TRY(readString(chars)); + + if (chars == "var") + return VariableDeclarationKind::Var; + if (chars == "let") + return VariableDeclarationKind::Let; + if (chars == "const") + return VariableDeclarationKind::Const; + + return raiseInvalidEnum("VariableDeclarationKind", chars); +} + + + +// ----- Lists (autogenerated, by lexicographical order) + +JS::Result +BinASTParser::parseArguments() +{ + uint32_t length; + AutoList guard(*tokenizer_); + + const auto start = tokenizer_->offset(); + TRY(tokenizer_->enterList(length, guard)); + TRY_DECL(result, factory_.newList(ParseNodeKind::ParamsBody, tokenizer_->pos(start))); + + for (uint32_t i = 0; i < length; ++i) { + MOZ_TRY_DECL(item, parseSpreadElementOrExpression()); + factory_.addList(/* list = */ result, /* child = */ item); + } + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseListOfAssignmentTargetOrAssignmentTargetWithInitializer() +{ + return raiseError("FIXME: Not implemented yet (ListOfAssignmentTargetOrAssignmentTargetWithInitializer)"); +} + +JS::Result +BinASTParser::parseListOfAssignmentTargetProperty() +{ + return raiseError("FIXME: Not implemented yet (ListOfAssignmentTargetProperty)"); +} + +JS::Result +BinASTParser::parseListOfBindingProperty() +{ + return raiseError("FIXME: Not implemented yet (ListOfBindingProperty)"); +} + +JS::Result +BinASTParser::parseListOfClassElement() +{ + return raiseError("FIXME: Not implemented yet (ListOfClassElement)"); +} + +JS::Result +BinASTParser::parseListOfDirective() +{ + uint32_t length; + AutoList guard(*tokenizer_); + + const auto start = tokenizer_->offset(); + TRY(tokenizer_->enterList(length, guard)); + TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start))); + + for (uint32_t i = 0; i < length; ++i) { + MOZ_TRY_DECL(item, parseDirective()); + factory_.addStatementToList(result, item); + } + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseListOfExportFromSpecifier() +{ + return raiseError("FIXME: Not implemented yet (ListOfExportFromSpecifier)"); +} + +JS::Result +BinASTParser::parseListOfExportLocalSpecifier() +{ + return raiseError("FIXME: Not implemented yet (ListOfExportLocalSpecifier)"); +} + +JS::Result +BinASTParser::parseListOfExpressionOrTemplateElement() +{ + return raiseError("FIXME: Not implemented yet (ListOfExpressionOrTemplateElement)"); +} + +JS::Result +BinASTParser::parseListOfIdentifierName() +{ + return raiseError("FIXME: Not implemented yet (ListOfIdentifierName)"); +} + +JS::Result +BinASTParser::parseListOfImportDeclarationOrExportDeclarationOrStatement() +{ + return raiseError("FIXME: Not implemented yet (ListOfImportDeclarationOrExportDeclarationOrStatement)"); +} + +JS::Result +BinASTParser::parseListOfImportSpecifier() +{ + return raiseError("FIXME: Not implemented yet (ListOfImportSpecifier)"); +} + +JS::Result +BinASTParser::parseListOfObjectProperty() +{ + uint32_t length; + AutoList guard(*tokenizer_); + + const auto start = tokenizer_->offset(); + TRY(tokenizer_->enterList(length, guard)); + TRY_DECL(result, factory_.newObjectLiteral(start)); + + for (uint32_t i = 0; i < length; ++i) { + MOZ_TRY_DECL(item, parseObjectProperty()); + result->appendWithoutOrderAssumption(item); + } + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseListOfOptionalBindingOrBindingWithInitializer() +{ + return raiseError("FIXME: Not implemented yet (ListOfOptionalBindingOrBindingWithInitializer)"); +} + +JS::Result +BinASTParser::parseListOfOptionalSpreadElementOrExpression() +{ + uint32_t length; + AutoList guard(*tokenizer_); + + const auto start = tokenizer_->offset(); + TRY(tokenizer_->enterList(length, guard)); + TRY_DECL(result, factory_.newArrayLiteral(start)); + + for (uint32_t i = 0; i < length; ++i) { + MOZ_TRY_DECL(item, parseOptionalSpreadElementOrExpression()); + if (item) + factory_.addArrayElement(result, item); // Infallible. + else + TRY(factory_.addElision(result, tokenizer_->pos(start))); + } + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseListOfParameter() +{ + uint32_t length; + AutoList guard(*tokenizer_); + + const auto start = tokenizer_->offset(); + TRY(tokenizer_->enterList(length, guard)); + ParseNode* result = new_(ParseNodeKind::ParamsBody, tokenizer_->pos(start)); + + for (uint32_t i = 0; i < length; ++i) { + MOZ_TRY_DECL(item, parseParameter()); + factory_.addList(/* list = */ result, /* item = */ item); + } + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseListOfStatement() +{ + uint32_t length; + AutoList guard(*tokenizer_); + + const auto start = tokenizer_->offset(); + TRY(tokenizer_->enterList(length, guard)); + TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start))); + + for (uint32_t i = 0; i < length; ++i) { + MOZ_TRY_DECL(item, parseStatement()); + factory_.addStatementToList(result, item); + } + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseListOfSwitchCase() +{ + uint32_t length; + AutoList guard(*tokenizer_); + + const auto start = tokenizer_->offset(); + TRY(tokenizer_->enterList(length, guard)); + TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start))); + + for (uint32_t i = 0; i < length; ++i) { + MOZ_TRY_DECL(item, parseSwitchCase()); + factory_.addCaseStatementToList(result, item); + } + + TRY(guard.done()); + return result; +} + +JS::Result +BinASTParser::parseListOfVariableDeclarator() +{ + uint32_t length; + AutoList guard(*tokenizer_); + + const auto start = tokenizer_->offset(); + TRY(tokenizer_->enterList(length, guard)); + TRY_DECL(result, factory_.newDeclarationList(ParseNodeKind::Const /*Placeholder*/, + tokenizer_->pos(start))); + + for (uint32_t i = 0; i < length; ++i) { + MOZ_TRY_DECL(item, parseVariableDeclarator()); + result->appendWithoutOrderAssumption(item); + } + + TRY(guard.done()); + return result; +} + + + // ----- Default values (by lexicographical order) +JS::Result +BinASTParser::parseOptionalAssertedBlockScope() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + Ok result; + if (kind == BinKind::_Null) { + result = Ok(); + } else { + const auto start = tokenizer_->offset(); + MOZ_TRY_VAR(result, parseInterfaceAssertedBlockScope(start, kind, fields)); + } + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseOptionalAssertedParameterScope() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + Ok result; + if (kind == BinKind::_Null) { + result = Ok(); + } else { + const auto start = tokenizer_->offset(); + MOZ_TRY_VAR(result, parseInterfaceAssertedParameterScope(start, kind, fields)); + } + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseOptionalAssertedVarScope() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + Ok result; + if (kind == BinKind::_Null) { + result = Ok(); + } else { + const auto start = tokenizer_->offset(); + MOZ_TRY_VAR(result, parseInterfaceAssertedVarScope(start, kind, fields)); + } + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseOptionalAssignmentTarget() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + ParseNode* result; + if (kind == BinKind::_Null) { + result = nullptr; + } else { + const auto start = tokenizer_->offset(); + MOZ_TRY_VAR(result, parseSumAssignmentTarget(start, kind, fields)); + } + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseOptionalBinding() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + ParseNode* result; + if (kind == BinKind::_Null) { + result = nullptr; + } else { + const auto start = tokenizer_->offset(); + MOZ_TRY_VAR(result, parseSumBinding(start, kind, fields)); + } + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseOptionalBindingIdentifier() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + ParseNode* result; + if (kind == BinKind::_Null) { + result = nullptr; + } else { + const auto start = tokenizer_->offset(); + MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields)); + } + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseOptionalBindingOrBindingWithInitializer() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + ParseNode* result; + if (kind == BinKind::_Null) { + result = nullptr; + } else { + const auto start = tokenizer_->offset(); + MOZ_TRY_VAR(result, parseSumBindingOrBindingWithInitializer(start, kind, fields)); + } + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseOptionalCatchClause() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + ParseNode* result; + if (kind == BinKind::_Null) { + result = nullptr; + } else { + const auto start = tokenizer_->offset(); + MOZ_TRY_VAR(result, parseInterfaceCatchClause(start, kind, fields)); + } + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseOptionalExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + ParseNode* result; + if (kind == BinKind::_Null) { + result = nullptr; + } else { + const auto start = tokenizer_->offset(); + MOZ_TRY_VAR(result, parseSumExpression(start, kind, fields)); + } + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseOptionalIdentifierName() +{ + RootedAtom string(cx_); + MOZ_TRY(readMaybeString(&string)); + + + + return raiseError("FIXME: Not implemented yet (OptionalIdentifierName)"); + +} + +JS::Result +BinASTParser::parseOptionalLabel() +{ + RootedAtom string(cx_); + MOZ_TRY(readMaybeString(&string)); + + + + return raiseError("FIXME: Not implemented yet (OptionalLabel)"); + +} + +JS::Result +BinASTParser::parseOptionalSpreadElementOrExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + ParseNode* result; + if (kind == BinKind::_Null) { + result = nullptr; + } else { + const auto start = tokenizer_->offset(); + MOZ_TRY_VAR(result, parseSumSpreadElementOrExpression(start, kind, fields)); + } + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseOptionalStatement() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + ParseNode* result; + if (kind == BinKind::_Null) { + result = nullptr; + } else { + const auto start = tokenizer_->offset(); + MOZ_TRY_VAR(result, parseSumStatement(start, kind, fields)); + } + TRY(guard.done()); + + return result; +} + +JS::Result +BinASTParser::parseOptionalVariableDeclarationOrExpression() +{ + BinKind kind; + BinFields fields(cx_); + AutoTaggedTuple guard(*tokenizer_); + + TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); + ParseNode* result; + if (kind == BinKind::_Null) { + result = nullptr; + } else { + const auto start = tokenizer_->offset(); + MOZ_TRY_VAR(result, parseSumVariableDeclarationOrExpression(start, kind, fields)); + } + TRY(guard.done()); + + return result; +} + + + +#undef TRY +#undef TRY_VAR +#undef TRY_DECL +#undef MOZ_TRY_DECL +} // namespace frontend +} // namespace js diff --git a/js/src/frontend/BinSource-auto.h b/js/src/frontend/BinSource-auto.h new file mode 100644 index 000000000000..63ab97070113 --- /dev/null +++ b/js/src/frontend/BinSource-auto.h @@ -0,0 +1,341 @@ +// This file was autogenerated by binjs_generate_spidermonkey, +// please DO NOT EDIT BY HAND. +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- +* vim: set ts=8 sts=4 et sw=4 tw=99: +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// To generate this file, see the documentation in +// js/src/frontend/binsource/README.md. + +// This file is meant to be included from the declaration +// of class `BinASTParser`. The include may be public or private. + + +// ----- Declaring string enums (by lexicographical order) +enum class BinaryOperator { + Comma /* "," */, + LogicalOr /* "||" */, + LogicalAnd /* "&&" */, + BitOr /* "|" */, + BitXor /* "^" */, + BitAnd /* "&" */, + Eq /* "==" */, + Neq /* "!=" */, + StrictEq /* "===" */, + StrictNeq /* "!==" */, + LessThan /* "<" */, + LeqThan /* "<=" */, + GreaterThan /* ">" */, + GeqThan /* ">=" */, + In /* "in" */, + Instanceof /* "instanceof" */, + Lsh /* "<<" */, + Rsh /* ">>" */, + Ursh /* ">>>" */, + Plus /* "+" */, + Minus /* "-" */, + Mul /* "*" */, + Div /* "/" */, + Mod /* "%" */, + Pow /* "**" */ +}; + +enum class CompoundAssignmentOperator { + PlusAssign /* "+=" */, + MinusAssign /* "-=" */, + MulAssign /* "*=" */, + DivAssign /* "/=" */, + ModAssign /* "%=" */, + PowAssign /* "**=" */, + LshAssign /* "<<=" */, + RshAssign /* ">>=" */, + UrshAssign /* ">>>=" */, + BitOrAssign /* "|=" */, + BitXorAssign /* "^=" */, + BitAndAssign /* "&=" */ +}; + +enum class UnaryOperator { + Plus /* "+" */, + Minus /* "-" */, + Not /* "!" */, + BitNot /* "~" */, + Typeof /* "typeof" */, + Void /* "void" */, + Delete /* "delete" */ +}; + +enum class UpdateOperator { + Incr /* "++" */, + Decr /* "--" */ +}; + +enum class VariableDeclarationKind { + Var /* "var" */, + Let /* "let" */, + Const /* "const" */ +}; + + + +// ----- Sums of interfaces (by lexicographical order) +// Implementations are autogenerated +// `ParseNode*` may never be nullptr +JS::Result parseAssignmentTarget();JS::Result parseAssignmentTargetOrAssignmentTargetWithInitializer();JS::Result parseAssignmentTargetPattern();JS::Result parseAssignmentTargetProperty();JS::Result parseBinding();JS::Result parseBindingOrBindingWithInitializer();JS::Result parseBindingPattern();JS::Result parseBindingProperty();JS::Result parseExportDeclaration();JS::Result parseExpression();JS::Result parseExpressionOrSuper();JS::Result parseExpressionOrTemplateElement();JS::Result parseForInOfBindingOrAssignmentTarget();JS::Result parseFunctionBodyOrExpression();JS::Result parseFunctionDeclarationOrClassDeclarationOrExpression();JS::Result parseFunctionDeclarationOrClassDeclarationOrVariableDeclaration();JS::Result parseImportDeclaration();JS::Result parseImportDeclarationOrExportDeclarationOrStatement();JS::Result parseIterationStatement();JS::Result parseLiteral();JS::Result parseMethodDefinition();JS::Result parseObjectProperty();JS::Result parseParameter();JS::Result parseProgram();JS::Result parsePropertyName();JS::Result parseSimpleAssignmentTarget();JS::Result parseSpreadElementOrExpression();JS::Result parseStatement();JS::Result parseVariableDeclarationOrExpression();JS::Result parseSumAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumAssignmentTargetOrAssignmentTargetWithInitializer(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumAssignmentTargetPattern(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumAssignmentTargetProperty(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumBinding(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumBindingOrBindingWithInitializer(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumBindingPattern(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumBindingProperty(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumExportDeclaration(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumExpression(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumExpressionOrSuper(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumExpressionOrTemplateElement(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumForInOfBindingOrAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumFunctionBodyOrExpression(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumFunctionDeclarationOrClassDeclarationOrExpression(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumFunctionDeclarationOrClassDeclarationOrVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumImportDeclaration(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumImportDeclarationOrExportDeclarationOrStatement(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumIterationStatement(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumLiteral(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumMethodDefinition(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumObjectProperty(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumParameter(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumProgram(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumPropertyName(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumSimpleAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumSpreadElementOrExpression(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumStatement(const size_t start, const BinKind kind, const BinFields& fields);JS::Result parseSumVariableDeclarationOrExpression(const size_t start, const BinKind kind, const BinFields& fields); + +// ----- Interfaces (by lexicographical order) +// Implementations are autogenerated +// `ParseNode*` may never be nullptr +JS::Result parseArrayAssignmentTarget(); +JS::Result parseArrayBinding(); +JS::Result parseArrayExpression(); +JS::Result parseArrowExpression(); +JS::Result parseAssertedBlockScope(); +JS::Result parseAssertedParameterScope(); +JS::Result parseAssertedVarScope(); +JS::Result parseAssignmentExpression(); +JS::Result parseAssignmentTargetIdentifier(); +JS::Result parseAssignmentTargetPropertyIdentifier(); +JS::Result parseAssignmentTargetPropertyProperty(); +JS::Result parseAssignmentTargetWithInitializer(); +JS::Result parseAwaitExpression(); +JS::Result parseBinaryExpression(); +JS::Result parseBindingIdentifier(); +JS::Result parseBindingPropertyIdentifier(); +JS::Result parseBindingPropertyProperty(); +JS::Result parseBindingWithInitializer(); +JS::Result parseBlock(); +JS::Result parseBreakStatement(); +JS::Result parseCallExpression(); +JS::Result parseCatchClause(); +JS::Result parseClassDeclaration(); +JS::Result parseClassElement(); +JS::Result parseClassExpression(); +JS::Result parseCompoundAssignmentExpression(); +JS::Result parseComputedMemberAssignmentTarget(); +JS::Result parseComputedMemberExpression(); +JS::Result parseComputedPropertyName(); +JS::Result parseConditionalExpression(); +JS::Result parseContinueStatement(); +JS::Result parseDataProperty(); +JS::Result parseDebuggerStatement(); +JS::Result parseDirective(); +JS::Result parseDoWhileStatement(); +JS::Result parseEmptyStatement(); +JS::Result parseExport(); +JS::Result parseExportAllFrom(); +JS::Result parseExportDefault(); +JS::Result parseExportFrom(); +JS::Result parseExportFromSpecifier(); +JS::Result parseExportLocalSpecifier(); +JS::Result parseExportLocals(); +JS::Result parseExpressionStatement(); +JS::Result parseForInOfBinding(); +JS::Result parseForInStatement(); +JS::Result parseForOfStatement(); +JS::Result parseForStatement(); +JS::Result parseFormalParameters(); +JS::Result parseFunctionBody(); +JS::Result parseFunctionDeclaration(); +JS::Result parseFunctionExpression(); +JS::Result parseGetter(); +JS::Result parseIdentifierExpression(); +JS::Result parseIfStatement(); +JS::Result parseImport(); +JS::Result parseImportNamespace(); +JS::Result parseImportSpecifier(); +JS::Result parseLabelledStatement(); +JS::Result parseLiteralBooleanExpression(); +JS::Result parseLiteralInfinityExpression(); +JS::Result parseLiteralNullExpression(); +JS::Result parseLiteralNumericExpression(); +JS::Result parseLiteralPropertyName(); +JS::Result parseLiteralRegExpExpression(); +JS::Result parseLiteralStringExpression(); +JS::Result parseMethod(); +JS::Result parseModule(); +JS::Result parseNewExpression(); +JS::Result parseNewTargetExpression(); +JS::Result parseObjectAssignmentTarget(); +JS::Result parseObjectBinding(); +JS::Result parseObjectExpression(); +JS::Result parseReturnStatement(); +JS::Result parseScript(); +JS::Result parseSetter(); +JS::Result parseShorthandProperty(); +JS::Result parseSpreadElement(); +JS::Result parseStaticMemberAssignmentTarget(); +JS::Result parseStaticMemberExpression(); +JS::Result parseSuper(); +JS::Result parseSwitchCase(); +JS::Result parseSwitchDefault(); +JS::Result parseSwitchStatement(); +JS::Result parseSwitchStatementWithDefault(); +JS::Result parseTemplateElement(); +JS::Result parseTemplateExpression(); +JS::Result parseThisExpression(); +JS::Result parseThrowStatement(); +JS::Result parseTryCatchStatement(); +JS::Result parseTryFinallyStatement(); +JS::Result parseUnaryExpression(); +JS::Result parseUpdateExpression(); +JS::Result parseVariableDeclaration(); +JS::Result parseVariableDeclarator(); +JS::Result parseWhileStatement(); +JS::Result parseWithStatement(); +JS::Result parseYieldExpression(); +JS::Result parseYieldStarExpression(); +JS::Result parseNull(); +JS::Result parseInterfaceArrayAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceArrayBinding(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceArrayExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceArrowExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceAssertedBlockScope(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceAssertedParameterScope(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceAssertedVarScope(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceAssignmentTargetIdentifier(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceAssignmentTargetPropertyIdentifier(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceAssignmentTargetPropertyProperty(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceAssignmentTargetWithInitializer(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceAwaitExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceBinaryExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceBindingIdentifier(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceBindingPropertyIdentifier(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceBindingPropertyProperty(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceBindingWithInitializer(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceBlock(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceBreakStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceCallExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceCatchClause(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceClassDeclaration(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceClassElement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceClassExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceCompoundAssignmentExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceComputedMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceComputedMemberExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceComputedPropertyName(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceConditionalExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceContinueStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceDataProperty(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceDebuggerStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceDirective(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceDoWhileStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceEmptyStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceExport(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceExportAllFrom(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceExportDefault(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceExportFrom(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceExportFromSpecifier(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceExportLocalSpecifier(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceExportLocals(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceExpressionStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceForInOfBinding(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceForInStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceForOfStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceForStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceFormalParameters(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceFunctionBody(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceFunctionDeclaration(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceFunctionExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceGetter(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceIdentifierExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceIfStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceImport(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceImportNamespace(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceImportSpecifier(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceLabelledStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceLiteralBooleanExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceLiteralInfinityExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceLiteralNullExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceLiteralNumericExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceLiteralPropertyName(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceLiteralRegExpExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceLiteralStringExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceMethod(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceModule(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceNewExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceNewTargetExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceObjectAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceObjectBinding(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceObjectExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceReturnStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceScript(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceSetter(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceShorthandProperty(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceSpreadElement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceStaticMemberAssignmentTarget(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceStaticMemberExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceSuper(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceSwitchCase(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceSwitchDefault(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceSwitchStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceSwitchStatementWithDefault(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceTemplateElement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceTemplateExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceThisExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceThrowStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceTryCatchStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceTryFinallyStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceUnaryExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceUpdateExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceVariableDeclaration(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceVariableDeclarator(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceWhileStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceWithStatement(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceYieldExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceYieldStarExpression(const size_t start, const BinKind kind, const BinFields& fields); +JS::Result parseInterfaceNull(const size_t start, const BinKind kind, const BinFields& fields); + + +// ----- String enums (by lexicographical order) +// Implementations are autogenerated +JS::Result parseBinaryOperator(); +JS::Result parseCompoundAssignmentOperator(); +JS::Result parseUnaryOperator(); +JS::Result parseUpdateOperator(); +JS::Result parseVariableDeclarationKind(); + + +// ----- Lists (by lexicographical order) +// Implementations are autogenerated +JS::Result parseArguments(); +JS::Result parseListOfAssignmentTargetOrAssignmentTargetWithInitializer(); +JS::Result parseListOfAssignmentTargetProperty(); +JS::Result parseListOfBindingProperty(); +JS::Result parseListOfClassElement(); +JS::Result parseListOfDirective(); +JS::Result parseListOfExportFromSpecifier(); +JS::Result parseListOfExportLocalSpecifier(); +JS::Result parseListOfExpressionOrTemplateElement(); +JS::Result parseListOfIdentifierName(); +JS::Result parseListOfImportDeclarationOrExportDeclarationOrStatement(); +JS::Result parseListOfImportSpecifier(); +JS::Result parseListOfObjectProperty(); +JS::Result parseListOfOptionalBindingOrBindingWithInitializer(); +JS::Result parseListOfOptionalSpreadElementOrExpression(); +JS::Result parseListOfParameter(); +JS::Result parseListOfStatement(); +JS::Result parseListOfSwitchCase(); +JS::Result parseListOfVariableDeclarator(); + + +// ----- Default values (by lexicographical order) +// Implementations are autogenerated +JS::Result parseOptionalAssertedBlockScope(); +JS::Result parseOptionalAssertedParameterScope(); +JS::Result parseOptionalAssertedVarScope(); +JS::Result parseOptionalAssignmentTarget(); +JS::Result parseOptionalBinding(); +JS::Result parseOptionalBindingIdentifier(); +JS::Result parseOptionalBindingOrBindingWithInitializer(); +JS::Result parseOptionalCatchClause(); +JS::Result parseOptionalExpression(); +JS::Result parseOptionalIdentifierName(); +JS::Result parseOptionalLabel(); +JS::Result parseOptionalSpreadElementOrExpression(); +JS::Result parseOptionalStatement(); +JS::Result parseOptionalVariableDeclarationOrExpression(); + diff --git a/js/src/frontend/BinSource.cpp b/js/src/frontend/BinSource.cpp index 1a46871a9aeb..8cc78d52b320 100644 --- a/js/src/frontend/BinSource.cpp +++ b/js/src/frontend/BinSource.cpp @@ -120,35 +120,7 @@ using NameBag = GCHashSet; using Names = GCVector; using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr; -namespace { - // Compare a bunch of `uint8_t` values (as returned by the tokenizer_) with - // a string literal (and ONLY a string literal). - template - bool operator==(const Chars& left, const char (&right)[N]) { - return BinTokenReaderTester::equals(left, right); - } - - bool isMethod(BinKind kind) { - switch (kind) { - case BinKind::ObjectMethod: - case BinKind::ObjectGetter: - case BinKind::ObjectSetter: - return true; - default: - return false; - } - } - -#if defined(DEBUG) - bool isMethodOrFunction(BinKind kind) { - if (isMethod(kind)) - return true; - if (kind == BinKind::FunctionExpression || kind == BinKind::FunctionDeclaration) - return true; - return false; - } -#endif // defined(DEBUG) -} +// ------------- Toplevel constructions JS::Result BinASTParser::parse(const Vector& data) @@ -192,45 +164,103 @@ BinASTParser::parseAux(const uint8_t* start, const size_t length) return result; // Magic conversion to Ok. } -Result -BinASTParser::parseProgram() +JS::Result +BinASTParser::buildFunctionBox(GeneratorKind generatorKind, FunctionAsyncKind functionAsyncKind) { - BinKind kind; - BinFields fields(cx_); - AutoTaggedTuple guard(*tokenizer_); + // Allocate the function before walking down the tree. + RootedFunction fun(cx_); + TRY_VAR(fun, NewFunctionWithProto(cx_, + /* native = */ nullptr, + /* nargs placeholder = */ 0, + JSFunction::INTERPRETED_NORMAL, + /* enclosingEnv = */ nullptr, + /* name (placeholder) = */ nullptr, + /* proto = */ nullptr, + gc::AllocKind::FUNCTION, + TenuredObject + )); + TRY_DECL(funbox, alloc_.new_(cx_, + traceListHead_, + fun, + /* toStringStart = */ 0, + Directives(parseContext_), + /* extraWarning = */ false, + generatorKind, + functionAsyncKind)); - TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); - if (kind != BinKind::Program) - return this->raiseInvalidKind("Program", kind); - - ParseNode* result; - MOZ_TRY_VAR(result, parseBlockStatementAux(kind, fields)); - - TRY(guard.done()); - return result; + traceListHead_ = funbox; + FunctionSyntaxKind syntax = PrimaryExpression; // FIXME - What if we're assigning? + // FIXME: The only thing we need to know is whether this is a + // ClassConstructor/DerivedClassConstructor + funbox->initWithEnclosingParseContext(parseContext_, syntax); + return funbox; } JS::Result -BinASTParser::parseBlockStatement() +BinASTParser::buildFunction(const size_t start, const BinKind kind, ParseNode* name, + ParseNode* params, ParseNode* body, FunctionBox* funbox) { - BinKind kind; - BinFields fields(cx_); - AutoTaggedTuple guard(*tokenizer_); + TokenPos pos = tokenizer_->pos(start); - TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); - ParseNode* result(nullptr); - switch (kind) { - default: - return raiseInvalidKind("BlockStatement", kind); - case BinKind::BlockStatement: - MOZ_TRY_VAR(result, parseBlockStatementAux(kind, fields)); - break; + RootedAtom atom((cx_)); + if (name) + atom = name->name(); + + + funbox->function()->setArgCount(uint16_t(params->pn_count)); + funbox->function()->initAtom(atom); + + // ParseNode represents the body as concatenated after the params. + params->appendWithoutOrderAssumption(body); + + TRY_DECL(result, kind == BinKind::FunctionDeclaration + ? factory_.newFunctionStatement(pos) + : factory_.newFunctionExpression(pos)); + + factory_.setFunctionBox(result, funbox); + factory_.setFunctionFormalParametersAndBody(result, params); + + HandlePropertyName dotThis = cx_->names().dotThis; + const bool declareThis = hasUsedName(dotThis) || + funbox->bindingsAccessedDynamically() || + funbox->isDerivedClassConstructor(); + + if (declareThis) { + ParseContext::Scope& funScope = parseContext_->functionScope(); + ParseContext::Scope::AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotThis); + MOZ_ASSERT(!p); + TRY(funScope.addDeclaredName(parseContext_, p, dotThis, DeclarationKind::Var, + DeclaredNameInfo::npos)); + funbox->setHasThisBinding(); } - TRY(guard.done()); + TRY_DECL(bindings, + NewFunctionScopeData(cx_, parseContext_->functionScope(), + /* hasParameterExprs = */ false, alloc_, parseContext_)); + + funbox->functionScopeBindings().set(*bindings); + return result; } +JS::Result +BinASTParser::parseAndUpdateCapturedNames() +{ + // For the moment, we do not attempt to validate the list of captured names. + AutoList guard(*tokenizer_); + uint32_t length = 0; + + TRY(tokenizer_->enterList(length, guard)); + RootedAtom name(cx_); + for (uint32_t i = 0; i < length; ++i) { + name = nullptr; + + MOZ_TRY(readString(&name)); + } + TRY(guard.done()); + return Ok(); +} + JS::Result BinASTParser::parseAndUpdateScopeNames(ParseContext::Scope& scope, DeclarationKind kind) { @@ -244,18 +274,8 @@ BinASTParser::parseAndUpdateScopeNames(ParseContext::Scope& scope, DeclarationKi MOZ_TRY(readString(&name)); auto ptr = scope.lookupDeclaredNameForAdd(name); - if (ptr) { - if (kind == DeclarationKind::Let || kind == DeclarationKind::Const) - return raiseError("Variable redeclaration"); - -#if defined(DEBUG) - // FIXME: Fix binjs-ref. - fprintf(stderr, "Weird: `var` redeclaration. Check encoder: "); - name->dump(); - fprintf(stderr, "\n"); -#endif // defined(DEBUG) - continue; - } + if (ptr) + return raiseError("Variable redeclaration"); TRY(scope.addDeclaredName(parseContext_, ptr, name.get(), kind, tokenizer_->offset())); } @@ -264,98 +284,21 @@ BinASTParser::parseAndUpdateScopeNames(ParseContext::Scope& scope, DeclarationKi } JS::Result -BinASTParser::parseAndUpdateCurrentScope() +BinASTParser::checkBinding(JSAtom* name) { - return parseAndUpdateScope(parseContext_->varScope(), *parseContext_->innermostScope()); -} + // Check that the variable appears in the corresponding scope. + ParseContext::Scope& scope = + variableDeclarationKind_ == VariableDeclarationKind::Var + ? parseContext_->varScope() + : *parseContext_->innermostScope(); -JS::Result -BinASTParser::parseAndUpdateScope(ParseContext::Scope& varScope, ParseContext::Scope& letScope) -{ - BinKind kind; - BinFields fields(cx_); - AutoTaggedTuple guard(*tokenizer_); + auto ptr = scope.lookupDeclaredName(name->asPropertyName()); + if (!ptr) + return raiseMissingVariableInAssertedScope(name); - TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); - switch (kind) { - default: - return raiseInvalidKind("Scope", kind); - case BinKind::BINJS_Scope: - for (auto field : fields) { - switch (field) { - case BinField::BINJS_HasDirectEval: - MOZ_TRY(readBool()); // Currently ignored. - break; - case BinField::BINJS_LetDeclaredNames: - MOZ_TRY(parseAndUpdateScopeNames(letScope, DeclarationKind::Let)); - break; - case BinField::BINJS_ConstDeclaredNames: - MOZ_TRY(parseAndUpdateScopeNames(letScope, DeclarationKind::Const)); - break; - case BinField::BINJS_VarDeclaredNames: - MOZ_TRY(parseAndUpdateScopeNames(varScope, DeclarationKind::Var)); - break; - case BinField::BINJS_CapturedNames: { - Rooted> names(cx_); //FIXME: Currently ignored. - MOZ_TRY(parseStringList(&names)); - break; - } - default: - return raiseInvalidField("Scope", field); - } - } - break; - } - - TRY(guard.done()); return Ok(); } -JS::Result -BinASTParser::parseBlockStatementAux(const BinKind kind, const BinFields& fields) -{ - ParseContext::Statement stmt(parseContext_, StatementKind::Block); - ParseContext::Scope scope(cx_, parseContext_, usedNames_); - TRY(scope.init(parseContext_)); - - ParseNode* body(nullptr); - ParseNode* directives(nullptr); // FIXME: Largely ignored - - for (auto field : fields) { - switch (field) { - case BinField::BINJS_Scope: - MOZ_TRY(parseAndUpdateCurrentScope()); - break; - case BinField::Body: - MOZ_TRY_VAR(body, parseStatementList()); - break; - case BinField::Directives: - if (kind != BinKind::Program) - return raiseInvalidField("BlockStatement", field); - MOZ_TRY_VAR(directives, parseDirectiveList()); - break; - default: - return raiseInvalidField("BlockStatement", field); - } - } - - // In case of absent optional fields, inject default values. - if (!body) - TRY_VAR(body, factory_.newStatementList(tokenizer_->pos())); - - MOZ_TRY_VAR(body, appendDirectivesToBody(body, directives)); - - ParseNode* result; - if (kind == BinKind::Program) { - result = body; - } else { - TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, parseContext_)); - TRY_VAR(result, factory_.newLexicalScope(*bindings, body)); - } - - return result; -} - JS::Result BinASTParser::appendDirectivesToBody(ParseNode* body, ParseNode* directives) { @@ -388,1995 +331,53 @@ BinASTParser::appendDirectivesToBody(ParseNode* body, ParseNode* directives) return result; } -JS::Result -BinASTParser::parseStringList(MutableHandle> out) -{ - MOZ_ASSERT(out.get().isNothing()); // Sanity check: the node must not have been parsed yet. - - uint32_t length; - AutoList guard(*tokenizer_); - - Names result(cx_); - - TRY(tokenizer_->enterList(length, guard)); - if (!result.reserve(length)) - return raiseOOM(); - - RootedAtom string(cx_); - for (uint32_t i = 0; i < length; ++i) { - string = nullptr; - - MOZ_TRY(readString(&string)); - result.infallibleAppend(Move(string)); // Checked in the call to `reserve`. - } - - TRY(guard.done()); - out.set(Move(Some(Move(result)))); - return Ok(); -} - -JS::Result -BinASTParser::parseStatementList() -{ - uint32_t length; - AutoList guard(*tokenizer_); - - TRY_DECL(result, factory_.newStatementList(tokenizer_->pos())); - - TRY(tokenizer_->enterList(length, guard)); - for (uint32_t i = 0; i < length; ++i) { - BinKind kind; - BinFields fields(cx_); - AutoTaggedTuple guard(*tokenizer_); - - ParseNode* statement(nullptr); - - TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); - switch (kind) { - case BinKind::FunctionDeclaration: - MOZ_TRY_VAR(statement, parseFunctionAux(kind, fields)); - break; - default: - MOZ_TRY_VAR(statement, parseStatementAux(kind, fields)); - break; - } - - TRY(guard.done()); - result->appendWithoutOrderAssumption(statement); - } - - TRY(guard.done()); - return result; -} - -JS::Result -BinASTParser::parseStatement() -{ - BinKind kind; - BinFields fields(cx_); - AutoTaggedTuple guard(*tokenizer_); - - TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); - ParseNode* result; - MOZ_TRY_VAR(result, parseStatementAux(kind, fields)); - - TRY(guard.done()); - return result; -} - -JS::Result -BinASTParser::parseStatementAux(const BinKind kind, const BinFields& fields) -{ - const size_t start = tokenizer_->offset(); - - ParseNode* result(nullptr); - switch (kind) { - case BinKind::EmptyStatement: { - TRY_VAR(result, factory_.newEmptyStatement(tokenizer_->pos(start))); - break; - } - case BinKind::BlockStatement: - MOZ_TRY_VAR(result, parseBlockStatementAux(kind, fields)); - break; - case BinKind::ExpressionStatement: - MOZ_TRY_VAR(result, parseExpressionStatementAux(kind, fields)); - break; - case BinKind::DebuggerStatement: { - TRY_VAR(result, factory_.newDebuggerStatement(tokenizer_->pos(start))); - break; - } - case BinKind::WithStatement: { - ParseNode* body(nullptr); - ParseNode* expr(nullptr); - for (auto field : fields) { - switch (field) { - case BinField::Body: - MOZ_TRY_VAR(body, parseStatement()); - break; - case BinField::Object: - MOZ_TRY_VAR(expr, parseExpression()); - break; - default: - return raiseInvalidField("WithStatement", field); - } - } - - if (!body) - return raiseMissingField("WithStatement", BinField::Body); - if (!expr) - return raiseMissingField("WithStatement", BinField::Object); - - TRY_VAR(result, factory_.newWithStatement(start, expr, body)); - - break; - } - case BinKind::ReturnStatement: { - if (!parseContext_->isFunctionBox()) { - // Return statements are permitted only inside functions. - return raiseInvalidKind("Toplevel Statement", kind); - } - parseContext_->functionBox()->usesReturn = true; - - ParseNode* arg(nullptr); - for (auto field : fields) { - switch (field) { - case BinField::Argument: - MOZ_TRY_VAR(arg, parseExpression()); - break; - default: - return raiseInvalidField("ReturnStatement", field); - } - } - - TRY_VAR(result, factory_.newReturnStatement(arg, tokenizer_->pos(start))); - - break; - } - case BinKind::LabeledStatement: { - // We check for the existence of the jump target when parsing `break label;` or `continue label;`. - ParseContext::Statement stmt(parseContext_, StatementKind::Label); - ParseNode* label(nullptr); - ParseNode* body(nullptr); - - for (auto field : fields) { - switch (field) { - case BinField::Label: - MOZ_TRY_VAR(label, parseIdentifier()); - break; - case BinField::Body: { - if (!label) // By order of fields, `label` MUST always be before `body` in the file. - return raiseMissingField("LabeledStatement", BinField::Label); - MOZ_ASSERT(label->name()); - ParseContext::LabelStatement stmt(parseContext_, label->name()); - MOZ_TRY_VAR(body, parseStatement()); - break; - } - default: - return raiseInvalidField("LabeledStatement", field); - } - } - - if (!label) - return raiseMissingField("LabeledStatement", BinField::Label); - if (!body) - return raiseMissingField("LabeledStatement", BinField::Body); - - TRY_VAR(result, factory_.newLabeledStatement(label->name(), body, start)); - - break; - } - - case BinKind::BreakStatement: - case BinKind::ContinueStatement: - MOZ_TRY_VAR(result, parseBreakOrContinueStatementAux(kind, fields)); - break; - - case BinKind::IfStatement: { - ParseContext::Statement stmt(parseContext_, StatementKind::If); - - ParseNode* test(nullptr); - ParseNode* consequent(nullptr); - ParseNode* alternate(nullptr); // Optional - - for (auto field : fields) { - switch (field) { - case BinField::Test: - MOZ_TRY_VAR(test, parseExpression()); - break; - case BinField::Consequent: - MOZ_TRY_VAR(consequent, parseStatement()); - break; - case BinField::Alternate: - MOZ_TRY_VAR(alternate, parseStatement()); - break; - default: - return raiseInvalidField("IfStatement", field); - } - } - - if (!test) - return raiseMissingField("IfStatement", BinField::Test); - if (!consequent) - return raiseMissingField("IfStatement", BinField::Consequent); - - TRY_VAR(result, factory_.newIfStatement(start, test, consequent, alternate)); - - break; - } - case BinKind::SwitchStatement: { - ParseContext::Statement stmt(parseContext_, StatementKind::Switch); - ParseNode* discriminant(nullptr); - ParseNode* cases(nullptr); - - for (auto field : fields) { - switch (field) { - case BinField::Discriminant: { - MOZ_TRY_VAR(discriminant, parseExpression()); - break; - } - case BinField::Cases: { - MOZ_TRY_VAR(cases, parseSwitchCaseList()); - break; - } - default: - return raiseInvalidField("SwitchStatement", field); - } - } - - if (!discriminant) - return raiseMissingField("SwitchStatement", BinField::Discriminant); - if (!cases) { - TRY_VAR(cases, factory_.newStatementList(tokenizer_->pos())); - - TRY_VAR(cases, factory_.newLexicalScope(nullptr, cases)); - } - - TRY_VAR(result, factory_.newSwitchStatement(start, discriminant, cases)); - - break; - } - - case BinKind::ThrowStatement: { - ParseNode* arg(nullptr); - for (auto field : fields) { - if (field != BinField::Argument) - return raiseInvalidField("ThrowStatement", field); - - MOZ_TRY_VAR(arg, parseExpression()); - } - - if (!arg) - return raiseMissingField("ThrowStatement", BinField::Argument); - - TRY_VAR(result, factory_.newThrowStatement(arg, tokenizer_->pos(start))); - - break; - } - - case BinKind::TryStatement: { - ParseNode* block(nullptr); - ParseNode* handler(nullptr); - ParseNode* finalizer(nullptr); - - for (auto field : fields) { - switch (field) { - case BinField::Block: { - ParseContext::Statement stmt(parseContext_, StatementKind::Try); - ParseContext::Scope scope(cx_, parseContext_, usedNames_); - TRY(scope.init(parseContext_)); - MOZ_TRY_VAR(block, parseBlockStatement()); - break; - } - case BinField::Handler: - MOZ_TRY_VAR(handler, parseCatchClause()); - break; - - case BinField::Finalizer: { - ParseContext::Statement stmt(parseContext_, StatementKind::Finally); - ParseContext::Scope scope(cx_, parseContext_, usedNames_); - TRY(scope.init(parseContext_)); - MOZ_TRY_VAR(finalizer, parseBlockStatement()); - break; - } - - default: - return raiseInvalidField("TryStatement", field); - } - } - - if (!block) - return raiseMissingField("TryStatement", BinField::Handler); - if (!handler && !finalizer) - return raiseMissingField("TryStatement (without catch)", BinField::Finalizer); - - TRY_VAR(result, factory_.newTryStatement(start, block, handler, finalizer)); - break; - } - - case BinKind::WhileStatement: - case BinKind::DoWhileStatement: { - ParseContext::Statement stmt(parseContext_, kind == BinKind::WhileStatement ? StatementKind::WhileLoop : StatementKind::DoLoop); - ParseNode* test(nullptr); - ParseNode* body(nullptr); - - for (auto field : fields) { - switch (field) { - case BinField::Test: - MOZ_TRY_VAR(test, parseExpression()); - break; - case BinField::Body: - MOZ_TRY_VAR(body, parseStatement()); - break; - default: - return raiseInvalidField("WhileStatement | DoWhileStatement", field); - } - } - - if (!test) - return raiseMissingField("WhileStatement | DoWhileStatement", BinField::Test); - if (!body) - return raiseMissingField("WhileStatement | DoWhileStatement", BinField::Body); - - if (kind == BinKind::WhileStatement) - TRY_VAR(result, factory_.newWhileStatement(start, test, body)); - else - TRY_VAR(result, factory_.newDoWhileStatement(body, test, tokenizer_->pos(start))); - - break; - } - case BinKind::ForStatement: { - ParseContext::Statement stmt(parseContext_, StatementKind::ForLoop); - - // Implicit scope around the `for`, used to store `for (let x; ...; ...)` - // or `for (const x; ...; ...)`-style declarations. Detail on the - // declaration is stored as part of `BINJS_Scope`. - ParseContext::Scope scope(cx_, parseContext_, usedNames_); - TRY(scope.init(parseContext_)); - ParseNode* init(nullptr); // Optional - ParseNode* test(nullptr); // Optional - ParseNode* update(nullptr); // Optional - ParseNode* body(nullptr); // Required - - for (auto field : fields) { - switch (field) { - case BinField::Init: - MOZ_TRY_VAR(init, parseForInit()); - break; - case BinField::Test: - MOZ_TRY_VAR(test, parseExpression()); - break; - case BinField::Update: - MOZ_TRY_VAR(update, parseExpression()); - break; - case BinField::BINJS_Scope: // The scope always appears before the body. - MOZ_TRY(parseAndUpdateCurrentScope()); - break; - case BinField::Body: - MOZ_TRY_VAR(body, parseStatement()); - break; - default: - return raiseInvalidField("ForStatement", field); - } - } - - if (!body) - return raiseMissingField("ForStatement", BinField::Body); - - TRY_DECL(forHead, factory_.newForHead(init, test, update, tokenizer_->pos(start))); - TRY_VAR(result, factory_.newForStatement(start, forHead, body, /* iflags = */ 0)); - - if (!scope.isEmpty()) { - TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, parseContext_)); - TRY_VAR(result, factory_.newLexicalScope(*bindings, result)); - } - - break; - } - case BinKind::ForInStatement: { - ParseContext::Statement stmt(parseContext_, StatementKind::ForInLoop); - - // Implicit scope around the `for`, used to store `for (let x in ...)` - // or `for (const x in ...)`-style declarations. Detail on the - // declaration is stored as part of `BINJS_Scope`. - ParseContext::Scope scope(cx_, parseContext_, usedNames_); - TRY(scope.init(parseContext_)); - ParseNode* left(nullptr); - ParseNode* right(nullptr); - ParseNode* body(nullptr); - - for (auto field : fields) { - switch (field) { - case BinField::Left: - MOZ_TRY_VAR(left, parseForInInit()); - break; - case BinField::Right: - MOZ_TRY_VAR(right, parseExpression()); - break; - case BinField::Body: - MOZ_TRY_VAR(body, parseStatement()); - break; - case BinField::BINJS_Scope: - MOZ_TRY(parseAndUpdateCurrentScope()); - break; - default: - return raiseInvalidField("ForInStatement", field); - } - } - - if (!left) - return raiseMissingField("ForInStatement", BinField::Left); - if (!right) - return raiseMissingField("ForInStatement", BinField::Right); - if (!body) - return raiseMissingField("ForInStatement", BinField::Body); - - TRY_DECL(forHead, factory_.newForInOrOfHead(ParseNodeKind::ForIn, left, right, - tokenizer_->pos(start))); - TRY_VAR(result, factory_.newForStatement(start, forHead, body, /*flags*/ 0)); - - if (!scope.isEmpty()) { - TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, parseContext_)); - TRY_VAR(result, factory_.newLexicalScope(*bindings, result)); - } - break; - } - - case BinKind::VariableDeclaration: - MOZ_TRY_VAR(result, parseVariableDeclarationAux(kind, fields)); - break; - - default: - return raiseInvalidKind("Statement", kind); - } - - return result; -} - -JS::Result -BinASTParser::parseBreakOrContinueStatementAux(const BinKind kind, const BinFields& fields) -{ - const auto start = tokenizer_->offset(); - ParseNode* label(nullptr); - - for (auto field : fields) { - switch (field) { - case BinField::Label: - MOZ_TRY_VAR(label, parsePattern()); - - if (label && !label->isKind(ParseNodeKind::Name)) - return raiseError("ContinueStatement | BreakStatement - Label MUST be an identifier"); // FIXME: This should be changed in the grammar. - - break; - default: - return raiseInvalidField("ContinueStatement", field); - } - } - - TokenPos pos = tokenizer_->pos(start); - ParseNode* result; - if (kind == BinKind::ContinueStatement) { -#if 0 // FIXME: We probably need to fix the AST before making this check. - auto validity = parseContext_->checkContinueStatement(label ? label->name() : nullptr); - if (validity.isErr()) { - switch (validity.unwrapErr()) { - case ParseContext::ContinueStatementError::NotInALoop: - return raiseError(kind, "Not in a loop"); - case ParseContext::ContinueStatementError::LabelNotFound: - return raiseError(kind, "Label not found"); - } - } -#endif // 0 - // Ok, this is a valid continue statement. - TRY_VAR(result, factory_.newContinueStatement(label ? label->name() : nullptr, pos)); - } else { -#if 0 // FIXME: We probably need to fix the AST before making this check. - auto validity = parseContext_->checkBreakStatement(label ? label->name() : nullptr); - if (validity.isErr()) { - switch (validity.unwrapErr()) { - case ParseContext::BreakStatementError::ToughBreak: - return raiseError(kind, "Not in a loop"); - case ParseContext::BreakStatementError::LabelNotFound: - return raiseError(kind, "Label not found"); - } - } -#endif // 0 - // Ok, this is a valid break statement. - TRY_VAR(result, factory_.newBreakStatement(label ? label->name() : nullptr, pos)); - } - - MOZ_ASSERT(result); - - return result; -} - -JS::Result -BinASTParser::parseForInit() -{ - // This can be either a VarDecl or an Expression. - BinFields fields(cx_); - AutoTaggedTuple guard(*tokenizer_); - BinKind kind; - - TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); - ParseNode* result(nullptr); - - switch (kind) { - case BinKind::VariableDeclaration: - MOZ_TRY_VAR(result, parseVariableDeclarationAux(kind, fields)); - break; - default: - // Parse as expression - MOZ_TRY_VAR(result, parseExpressionAux(kind, fields)); - break; - } - - TRY(guard.done()); - return result; -} - -JS::Result -BinASTParser::parseForInInit() -{ - // This can be either a VarDecl or a Pattern. - BinFields fields(cx_); - AutoTaggedTuple guard(*tokenizer_); - BinKind kind; - - TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); - ParseNode* result(nullptr); - - switch (kind) { - case BinKind::VariableDeclaration: - MOZ_TRY_VAR(result, parseVariableDeclarationAux(kind, fields)); - break; - default: - // Parse as expression. Not a joke: http://www.ecma-international.org/ecma-262/5.1/index.html#sec-12.6.4 . - MOZ_TRY_VAR(result, parseExpressionAux(kind, fields)); - break; - } - - TRY(guard.done()); - return result; -} - -JS::Result -BinASTParser::parseFunctionAux(const BinKind kind, const BinFields& fields) -{ - MOZ_ASSERT(isMethodOrFunction(kind)); - - const size_t start = tokenizer_->offset(); - - ParseNode* id(nullptr); - ParseNode* params(nullptr); - ParseNode* body(nullptr); - ParseNode* directives(nullptr); // Largely ignored for the moment. - ParseNode* key(nullptr); // Methods only - - // Allocate the function before walking down the tree. - RootedFunction fun(cx_); - TRY_VAR(fun, NewFunctionWithProto(cx_, - /*native*/nullptr, - /*nargs ?*/0, - /*flags */ JSFunction::INTERPRETED_NORMAL, - /*enclosing env*/nullptr, - /*name*/ nullptr, // Will be known later - /*proto*/ nullptr, - /*alloc*/gc::AllocKind::FUNCTION, - TenuredObject - )); - TRY_DECL(funbox, alloc_.new_(cx_, - traceListHead_, - fun, - /* toStringStart = */0, - /* directives = */Directives(parseContext_), - /* extraWarning = */false, - GeneratorKind::NotGenerator, - FunctionAsyncKind::SyncFunction - )); - - traceListHead_ = funbox; - - FunctionSyntaxKind syntax; - switch (kind) { - case BinKind::FunctionDeclaration: - syntax = Statement; - break; - case BinKind::FunctionExpression: - syntax = PrimaryExpression; // FIXME: Probably doesn't work. - break; - case BinKind::ObjectMethod: - syntax = Method; - break; - case BinKind::ObjectGetter: - syntax = Getter; - break; - case BinKind::ObjectSetter: - syntax = Setter; - break; - default: - MOZ_CRASH("Invalid FunctionSyntaxKind"); // Checked above. - } - funbox->initWithEnclosingParseContext(parseContext_, syntax); - - // Container scopes. - ParseContext::Scope& varScope = parseContext_->varScope(); - ParseContext::Scope* letScope = parseContext_->innermostScope(); - - // Push a new ParseContext. - BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr); - TRY(funpc.init()); - parseContext_->functionScope().useAsVarScope(parseContext_); - MOZ_ASSERT(parseContext_->isFunctionBox()); - - for (auto field : fields) { - switch (field) { - case BinField::Id: - MOZ_TRY_VAR(id, parseIdentifier()); - break; - case BinField::Params: - MOZ_TRY_VAR(params, parseArgumentList()); - break; - case BinField::BINJS_Scope: - // This scope information affects the scopes contained in the function body. MUST appear before the `body`. - MOZ_TRY(parseAndUpdateScope(varScope, *letScope)); - break; - case BinField::Directives: - MOZ_TRY_VAR(directives, parseDirectiveList()); - break; - case BinField::Body: - MOZ_TRY_VAR(body, parseBlockStatement()); - break; - case BinField::Key: - if (!isMethod(kind)) - return raiseInvalidField("Functions (unless defined as methods)", field); - - MOZ_TRY_VAR(key, parseObjectPropertyName()); - break; - default: - return raiseInvalidField("Function", field); - } - } - - // Inject default values for absent fields. - if (!params) - TRY_VAR(params, new_(ParseNodeKind::ParamsBody, tokenizer_->pos())); - - if (!body) - TRY_VAR(body, factory_.newStatementList(tokenizer_->pos())); - - if (kind == BinKind::FunctionDeclaration && !id) { - // The name is compulsory only for function declarations. - return raiseMissingField("FunctionDeclaration", BinField::Id); - } - - // Reject if required values are missing. - if (isMethod(kind) && !key) - return raiseMissingField("method", BinField::Key); - - if (id) - fun->initAtom(id->pn_atom); - - MOZ_ASSERT(params->isArity(PN_LIST)); - - if (!(body->isKind(ParseNodeKind::LexicalScope) && - body->pn_u.scope.body->isKind(ParseNodeKind::StatementList))) - { - // Promote to lexical scope + statement list. - if (!body->isKind(ParseNodeKind::StatementList)) { - TRY_DECL(list, factory_.newStatementList(tokenizer_->pos(start))); - - list->initList(body); - body = list; - } - - // Promote to lexical scope. - TRY_VAR(body, factory_.newLexicalScope(nullptr, body)); - } - MOZ_ASSERT(body->isKind(ParseNodeKind::LexicalScope)); - - MOZ_TRY_VAR(body, appendDirectivesToBody(body, directives)); - - params->appendWithoutOrderAssumption(body); - - TokenPos pos = tokenizer_->pos(start); - TRY_DECL(function, kind == BinKind::FunctionDeclaration - ? factory_.newFunctionStatement(pos) - : factory_.newFunctionExpression(pos)); - - factory_.setFunctionBox(function, funbox); - factory_.setFunctionFormalParametersAndBody(function, params); - - ParseNode* result; - if (kind == BinKind::ObjectMethod) - TRY_VAR(result, factory_.newObjectMethodOrPropertyDefinition(key, function, AccessorType::None)); - else if (kind == BinKind::ObjectGetter) - TRY_VAR(result, factory_.newObjectMethodOrPropertyDefinition(key, function, AccessorType::Getter)); - else if (kind == BinKind::ObjectSetter) - TRY_VAR(result, factory_.newObjectMethodOrPropertyDefinition(key, function, AccessorType::Setter)); - else - result = function; - - // Now handle bindings. - HandlePropertyName dotThis = cx_->names().dotThis; - const bool declareThis = hasUsedName(dotThis) || funbox->bindingsAccessedDynamically() || funbox->isDerivedClassConstructor(); - - if (declareThis) { - ParseContext::Scope& funScope = parseContext_->functionScope(); - ParseContext::Scope::AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotThis); - MOZ_ASSERT(!p); - TRY(funScope.addDeclaredName(parseContext_, p, dotThis, DeclarationKind::Var, - DeclaredNameInfo::npos)); - funbox->setHasThisBinding(); - } - - TRY_DECL(bindings, - NewFunctionScopeData(cx_, parseContext_->functionScope(), - /* hasParameterExprs = */false, alloc_, parseContext_)); - - funbox->functionScopeBindings().set(*bindings); - return result; -} - -JS::Result -BinASTParser::parseObjectPropertyName() -{ - auto start = tokenizer_->offset(); - - BinFields fields(cx_); - AutoTaggedTuple guard(*tokenizer_); - BinKind kind; - - TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); - ParseNode* result; - switch (kind) { - case BinKind::StringLiteral: { - ParseNode* string; - MOZ_TRY_VAR(string, parseStringLiteralAux(kind, fields)); - uint32_t index; - if (string->pn_atom->isIndex(&index)) - TRY_VAR(result, factory_.newNumber(index, NoDecimal, TokenPos(start, tokenizer_->offset()))); - else - result = string; - - break; - } - case BinKind::NumericLiteral: - MOZ_TRY_VAR(result, parseNumericLiteralAux(kind, fields)); - break; - case BinKind::Identifier: - MOZ_TRY_VAR(result, parseIdentifierAux(kind, fields, /* expectObjectPropertyName = */ true)); - break; - case BinKind::ComputedPropertyName: { - ParseNode* expr; - MOZ_TRY_VAR(expr, parseExpressionAux(kind, fields)); - TRY_VAR(result, factory_.newComputedName(expr, start, tokenizer_->offset())); - break; - } - default: - return raiseInvalidKind("ObjectLiteralPropertyName", kind); - } - - TRY(guard.done()); - return result; -} - -JS::Result -BinASTParser::parseVariableDeclarationAux(const BinKind kind, const BinFields& fields) -{ - const size_t start = tokenizer_->offset(); - - ParseNode* result(nullptr); - switch (kind) { - default: - return raiseInvalidKind("VariableDeclaration", kind); - case BinKind::VariableDeclaration: - ParseNodeKind pnk = ParseNodeKind::Limit; - - for (auto field : fields) { - switch (field) { - case BinField::Kind: { - Maybe kindName; - MOZ_TRY(readString(kindName)); - - if (*kindName == "let") - pnk = ParseNodeKind::Let; - else if (*kindName == "var") - pnk = ParseNodeKind::Var; - else if (*kindName == "const") - pnk = ParseNodeKind::Const; - else - return raiseInvalidEnum("VariableDeclaration", *kindName); - - break; - } - case BinField::Declarations: { - uint32_t length; - AutoList guard(*tokenizer_); - - TRY(tokenizer_->enterList(length, guard)); - TRY_VAR(result, factory_.newDeclarationList(ParseNodeKind::Const /*Placeholder*/, - tokenizer_->pos(start))); - - for (uint32_t i = 0; i < length; ++i) { - ParseNode* current; - MOZ_TRY_VAR(current, parseVariableDeclarator()); - MOZ_ASSERT(current); - - result->appendWithoutOrderAssumption(current); - } - - TRY(guard.done()); - break; - } - default: - return raiseInvalidField("VariableDeclaration", field); - } - } - - if (!result || pnk == ParseNodeKind::Limit) - return raiseMissingField("VariableDeclaration", BinField::Declarations); - - result->setKind(pnk); - } - - return result; -} - - -JS::Result -BinASTParser::parseExpressionStatementAux(const BinKind kind, const BinFields& fields) -{ - MOZ_ASSERT(kind == BinKind::ExpressionStatement); - - ParseNode* expr(nullptr); - for (auto field : fields) { - switch (field) { - case BinField::Expression: - MOZ_TRY_VAR(expr, parseExpression()); - - break; - default: - return raiseInvalidField("ExpressionStatement", field); - } - } - - if (!expr) - return raiseMissingField("ExpressionStatement", BinField::Expression); - - TRY_DECL(result, factory_.newExprStatement(expr, tokenizer_->offset())); - return result; -} - -JS::Result -BinASTParser::parseVariableDeclarator() -{ - const size_t start = tokenizer_->offset(); - - BinKind kind; - BinFields fields(cx_); - AutoTaggedTuple guard(*tokenizer_); - - TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); - if (kind != BinKind::VariableDeclarator) - return raiseInvalidKind("VariableDeclarator", kind); - - ParseNode* id(nullptr); - ParseNode* init(nullptr); // Optional. - for (auto field : fields) { - switch (field) { - case BinField::Id: - MOZ_TRY_VAR(id, parsePattern()); - - break; - case BinField::Init: - MOZ_TRY_VAR(init, parseExpression()); - - break; - default: - return raiseInvalidField("VariableDeclarator", field); - } - } - - TRY(guard.done()); - if (!id) - return raiseMissingField("VariableDeclarator", BinField::Id); - - ParseNode* result(nullptr); - - // FIXME: Documentation in ParseNode is clearly obsolete. - if (id->isKind(ParseNodeKind::Name)) { - // `var foo [= bar]`` - TRY_VAR(result, factory_.newName(id->pn_atom->asPropertyName(), tokenizer_->pos(start), cx_)); - - if (init) - result->pn_expr = init; - - } else { - // `var pattern = bar` - if (!init) { - // Here, `init` is required. - return raiseMissingField("VariableDeclarator (with non-trivial pattern)", BinField::Init); - } - - TRY_VAR(result, factory_.newAssignment(ParseNodeKind::Assign, id, init)); - } - - return result; -} - -JS::Result -BinASTParser::parseExpressionList(bool acceptElisions) -{ - const size_t start = tokenizer_->offset(); - - uint32_t length; - AutoList guard(*tokenizer_); - - TRY(tokenizer_->enterList(length, guard)); - TRY_DECL(result, factory_.newArrayLiteral(start)); - - for (uint32_t i = 0; i < length; ++i) { - BinFields fields(cx_); - AutoTaggedTuple guard(*tokenizer_); - BinKind kind; - - TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); - switch (kind) { - case BinKind::Elision: { - if (!acceptElisions) - return raiseInvalidKind("[Expression]", kind); - - MOZ_TRY(parseElisionAux(kind, fields)); - TRY(!factory_.addElision(result, tokenizer_->pos(start))); - break; - } - default: { - ParseNode* expr(nullptr); - MOZ_TRY_VAR(expr, parseExpressionAux(kind, fields)); - - MOZ_ASSERT(expr); - factory_.addArrayElement(result, expr); - } - } - - TRY(guard.done()); - } - - TRY(guard.done()); - return result; -} - -JS::Result -BinASTParser::parseElisionAux(const BinKind kind, const BinFields& fields) -{ - MOZ_ASSERT(kind == BinKind::Elision); - MOZ_TRY(checkEmptyTuple(kind, fields)); - - return Ok(); -} - -JS::Result -BinASTParser::parseSwitchCaseList() -{ - uint32_t length; - AutoList guard(*tokenizer_); - - TRY(tokenizer_->enterList(length, guard)); - TRY_DECL(list, factory_.newStatementList(tokenizer_->pos())); - - // Set to `true` once we have encountered a `default:` case. - // Two `default:` cases is an error. - bool haveDefault = false; - - for (uint32_t i = 0; i < length; ++i) { - ParseNode* caseNode(nullptr); - MOZ_TRY_VAR(caseNode, parseSwitchCase()); - MOZ_ASSERT(caseNode); - - if (caseNode->pn_left == nullptr) { - // Ah, seems that we have encountered a default case. - if (haveDefault) { - // Oh, wait, two defaults? That's an error. - return raiseError("This switch() has more than one `default:` case"); - } - haveDefault = true; - } - factory_.addCaseStatementToList(list, caseNode); - } - - TRY(guard.done()); - TRY_DECL(result, factory_.newLexicalScope(nullptr, list)); - - return result; -} - -JS::Result -BinASTParser::parseExpression() -{ - BinFields fields(cx_); - AutoTaggedTuple guard(*tokenizer_); - BinKind kind; - - TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); - ParseNode* result(nullptr); - MOZ_TRY_VAR(result, parseExpressionAux(kind, fields)); - - TRY(guard.done()); - return result; -} - -JS::Result -BinASTParser::parseExpressionAux(const BinKind kind, const BinFields& fields) -{ - const size_t start = tokenizer_->offset(); - - ParseNode* result(nullptr); - - switch (kind) { - case BinKind::Identifier: { - MOZ_TRY_VAR(result, parseIdentifierAux(kind, fields)); - break; - } - case BinKind::BooleanLiteral: { - Maybe value; - for (auto field : fields) { - switch (field) { - case BinField::Value: - MOZ_TRY_EMPLACE(value, readBool()); - break; - default: - return raiseInvalidField("BooleanLiteral", field); - } - } - - // In case of absent optional fields, inject default values. - if (!value) - value.emplace(false); - - TRY_VAR(result, factory_.newBooleanLiteral(*value, tokenizer_->pos(start))); - - break; - } - case BinKind::NullLiteral: { - MOZ_TRY(checkEmptyTuple(kind, fields)); - TRY_VAR(result, factory_.newNullLiteral(tokenizer_->pos(start))); - break; - } - case BinKind::NumericLiteral: - MOZ_TRY_VAR(result, parseNumericLiteralAux(kind, fields)); - break; - - case BinKind::RegExpLiteral: { - RootedAtom pattern(cx_); - Maybe flags; - for (auto field : fields) { - switch (field) { - case BinField::Pattern: - MOZ_TRY(readString(&pattern)); - break; - case BinField::Flags: - MOZ_TRY(readString(flags)); - break; - default: - return raiseInvalidField("RegExpLiteral", field); - } - } - - if (!pattern) - return raiseMissingField("RegExpLiteral", BinField::Pattern); - if (!flags) - return raiseMissingField("RegExpLiteral", BinField::Flags); - - RegExpFlag reflags = NoFlags; - for (auto 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 raiseInvalidEnum("RegExpLiteral", *flags); - } - - - Rooted reobj(cx_); - TRY_VAR(reobj, RegExpObject::create(cx_, - pattern, - reflags, - alloc_, - TenuredObject)); - - TRY_VAR(result, factory_.newRegExp(reobj, tokenizer_->pos(start), *this)); - - break; - } - case BinKind::StringLiteral: - MOZ_TRY_VAR(result, parseStringLiteralAux(kind, fields)); - break; - - case BinKind::ThisExpression: { - MOZ_TRY(checkEmptyTuple(kind, fields)); - - if (parseContext_->isFunctionBox()) - parseContext_->functionBox()->usesThis = true; - - TokenPos pos = tokenizer_->pos(start); - ParseNode* thisName(nullptr); - if (parseContext_->sc()->thisBinding() == ThisBinding::Function) - TRY_VAR(thisName, factory_.newName(cx_->names().dotThis, pos, cx_)); - - TRY_VAR(result, factory_.newThisLiteral(pos, thisName)); - break; - } - case BinKind::ArrayExpression: - MOZ_TRY_VAR(result, parseArrayExpressionAux(kind, fields)); - break; - - case BinKind::ObjectExpression: - MOZ_TRY_VAR(result, parseObjectExpressionAux(kind, fields)); - break; - - case BinKind::FunctionExpression: - MOZ_TRY_VAR(result, parseFunctionAux(kind, fields)); - result->setOp(JSOP_LAMBDA); - break; - - case BinKind::UnaryExpression: - case BinKind::UpdateExpression: { - ParseNode* expr(nullptr); - Maybe operation; - Maybe prefix; // FIXME: Ignored for unary_expression? - - for (auto field : fields) { - switch (field) { - case BinField::Operator: - MOZ_TRY(readString(operation)); - break; - case BinField::Prefix: - MOZ_TRY_EMPLACE(prefix, readBool()); - break; - case BinField::Argument: - // arguments are always parsed *after* operator. - if (operation.isNothing()) - return raiseMissingField("UpdateExpression", BinField::Operator); - MOZ_TRY_VAR(expr, parseExpression()); - break; - default: - return raiseInvalidField("UpdateExpression", field); - } - } - - if (!expr) - return raiseMissingField("UpdateExpression", BinField::Argument); - if (operation.isNothing()) - return raiseMissingField("UpdateExpression", BinField::Operator); - - // In case of absent optional fields, inject default values. - if (prefix.isNothing()) - prefix.emplace(false); - - ParseNodeKind pnk = ParseNodeKind::Limit; - if (kind == BinKind::UnaryExpression) { - if (*operation == "-") { - pnk = ParseNodeKind::Neg; - } else if (*operation == "+") { - pnk = ParseNodeKind::Pos; - } else if (*operation == "!") { - pnk = ParseNodeKind::Not; - } else if (*operation == "~") { - pnk = ParseNodeKind::BitNot; - } else if (*operation == "typeof") { - if (expr->isKind(ParseNodeKind::Name)) - pnk = ParseNodeKind::TypeOfName; - else - pnk = ParseNodeKind::TypeOfExpr; - } else if (*operation == "void") { - pnk = ParseNodeKind::Void; - } else if (*operation == "delete") { - switch (expr->getKind()) { - case ParseNodeKind::Name: - expr->setOp(JSOP_DELNAME); - pnk = ParseNodeKind::DeleteName; - break; - case ParseNodeKind::Dot: - pnk = ParseNodeKind::DeleteProp; - break; - case ParseNodeKind::Elem: - pnk = ParseNodeKind::DeleteElem; - break; - default: - pnk = ParseNodeKind::DeleteExpr; - } - } else { - return raiseInvalidEnum("UnaryOperator", *operation); - } - } else if (kind == BinKind::UpdateExpression) { - if (!expr->isKind(ParseNodeKind::Name) && !factory_.isPropertyAccess(expr)) - return raiseError("Invalid increment/decrement operand"); // FIXME: Shouldn't this be part of the syntax? - - if (*operation == "++") { - if (*prefix) - pnk = ParseNodeKind::PreIncrement; - else - pnk = ParseNodeKind::PostIncrement; - } else if (*operation == "--") { - if (*prefix) - pnk = ParseNodeKind::PreDecrement; - else - pnk = ParseNodeKind::PostDecrement; - } else { - return raiseInvalidEnum("UpdateOperator", *operation); - } - } - - TRY_VAR(result, factory_.newUnary(pnk, start, expr)); - - break; - } - case BinKind::BinaryExpression: - case BinKind::LogicalExpression: { - ParseNode* left(nullptr); - ParseNode* right(nullptr); - Maybe operation; - for (auto field : fields) { - switch (field) { - case BinField::Left: - MOZ_TRY_VAR(left, parseExpression()); - break; - case BinField::Right: - MOZ_TRY_VAR(right, parseExpression()); - break; - case BinField::Operator: - MOZ_TRY(readString(operation)); - break; - default: - return raiseInvalidField("LogicalExpression | BinaryExpression", field); - } - } - - if (!left) - return raiseMissingField("LogicalExpression | BinaryExpression", BinField::Left); - if (!right) - return raiseMissingField("LogicalExpression | BinaryExpression", BinField::Right); - if (operation.isNothing()) - return raiseMissingField("LogicalExpression | BinaryExpression", BinField::Operator); - - // FIXME: Instead of Chars, we should use atoms and comparison - // between atom ptr. - ParseNodeKind pnk = ParseNodeKind::Limit; - if (*operation == "==") - pnk = ParseNodeKind::Eq; - else if (*operation == "!=") - pnk = ParseNodeKind::Ne; - else if (*operation == "===") - pnk = ParseNodeKind::StrictEq; - else if (*operation == "!==") - pnk = ParseNodeKind::StrictNe; - else if (*operation == "<") - pnk = ParseNodeKind::Lt; - else if (*operation == "<=") - pnk = ParseNodeKind::Le; - else if (*operation == ">") - pnk = ParseNodeKind::Gt; - else if (*operation == ">=") - pnk = ParseNodeKind::Ge; - else if (*operation == "<<") - pnk = ParseNodeKind::Lsh; - else if (*operation == ">>") - pnk = ParseNodeKind::Rsh; - else if (*operation == ">>>") - pnk = ParseNodeKind::Ursh; - else if (*operation == "+") - pnk = ParseNodeKind::Add; - else if (*operation == "-") - pnk = ParseNodeKind::Sub; - else if (*operation == "*") - pnk = ParseNodeKind::Star; - else if (*operation == "/") - pnk = ParseNodeKind::Div; - else if (*operation == "%") - pnk = ParseNodeKind::Mod; - else if (*operation == "|") - pnk = ParseNodeKind::BitOr; - else if (*operation == "^") - pnk = ParseNodeKind::BitXor; - else if (*operation == "&") - pnk = ParseNodeKind::BitAnd; - else if (*operation == "in") - pnk = ParseNodeKind::In; - else if (*operation == "instanceof") - pnk = ParseNodeKind::InstanceOf; - else if (*operation == "||") - pnk = ParseNodeKind::Or; - else if (*operation == "&&") - pnk = ParseNodeKind::And; - else if (*operation == "**") - pnk = ParseNodeKind::Pow; - else - return raiseInvalidEnum("BinaryOperator | LogicalOperator", *operation); - - if (left->isKind(pnk) && - pnk != ParseNodeKind::Pow /* ParseNodeKind::Pow is not left-associative */) - { - // Regroup left-associative operations into lists. - left->appendWithoutOrderAssumption(right); - result = left; - } else { - TRY_DECL(list, factory_.newList(pnk, tokenizer_->pos(start))); - - list->appendWithoutOrderAssumption(left); - list->appendWithoutOrderAssumption(right); - result = list; - } - - break; - } - case BinKind::AssignmentExpression: { - ParseNode* left(nullptr); - ParseNode* right(nullptr); - Maybe operation; - for (auto field : fields) { - switch (field) { - case BinField::Left: - MOZ_TRY_VAR(left, parseExpression()); - break; - case BinField::Right: - MOZ_TRY_VAR(right, parseExpression()); - break; - case BinField::Operator: - MOZ_TRY(readString(operation)); - break; - default: - return raiseInvalidField("AssignmentExpression", field); - } - } - - if (!left) - return raiseMissingField("AssignmentExpression", BinField::Left); - if (!right) - return raiseMissingField("AssignmentExpression", BinField::Right); - if (operation.isNothing()) - return raiseMissingField("AssignmentExpression", BinField::Operator); - - // FIXME: Instead of Chars, we should use atoms and comparison - // between atom ptr. - // FIXME: We should probably turn associative operations into lists. - ParseNodeKind pnk = ParseNodeKind::Limit; - if (*operation == "=") - pnk = ParseNodeKind::Assign; - else if (*operation == "+=") - pnk = ParseNodeKind::AddAssign; - else if (*operation == "-=") - pnk = ParseNodeKind::SubAssign; - else if (*operation == "*=") - pnk = ParseNodeKind::MulAssign; - else if (*operation == "/=") - pnk = ParseNodeKind::DivAssign; - else if (*operation == "%=") - pnk = ParseNodeKind::ModAssign; - else if (*operation == "<<=") - pnk = ParseNodeKind::LshAssign; - else if (*operation == ">>=") - pnk = ParseNodeKind::RshAssign; - else if (*operation == ">>>=") - pnk = ParseNodeKind::UrshAssign; - else if (*operation == "|=") - pnk = ParseNodeKind::BitOrAssign; - else if (*operation == "^=") - pnk = ParseNodeKind::BitXorAssign; - else if (*operation == "&=") - pnk = ParseNodeKind::BitAndAssign; - else - return raiseInvalidEnum("AssignmentOperator", *operation); - - TRY_VAR(result, factory_.newAssignment(pnk, left, right)); - - break; - } - case BinKind::BracketExpression: - case BinKind::DotExpression: - MOZ_TRY_VAR(result, parseMemberExpressionAux(kind, fields)); - - break; - case BinKind::ConditionalExpression: { - ParseNode* test(nullptr); - ParseNode* alternate(nullptr); - ParseNode* consequent(nullptr); - - for (auto field : fields) { - switch (field) { - case BinField::Test: - MOZ_TRY_VAR(test, parseExpression()); - break; - case BinField::Consequent: - MOZ_TRY_VAR(consequent, parseExpression()); - break; - case BinField::Alternate: - MOZ_TRY_VAR(alternate, parseExpression()); - break; - default: - return raiseInvalidField("ConditionalExpression", field); - } - } - - if (!test) - return raiseMissingField("ConditionalExpression", BinField::Test); - if (!consequent) - return raiseMissingField("ConditionalExpression", BinField::Consequent); - if (!alternate) - return raiseMissingField("ConditionalExpression", BinField::Alternate); - - TRY_VAR(result, factory_.newConditional(test, consequent, alternate)); - - break; - } - case BinKind::CallExpression: - case BinKind::NewExpression: { - ParseNode* callee(nullptr); - - for (auto field : fields) { - switch (field) { - case BinField::Callee: - MOZ_TRY_VAR(callee, parseExpression()); - break; - case BinField::Arguments: - MOZ_TRY_VAR(result, parseExpressionList(/* acceptElisions = */ false)); - break; - default: - return raiseInvalidField("NewExpression", field); - } - } - - // In case of absent required fields, fail. - if (!callee) - return raiseMissingField("NewExpression", BinField::Callee); - - // In case of absent optional fields, inject default values. - if (!result) - TRY_VAR(result, factory_.newArrayLiteral(start)); - - ParseNodeKind pnk = - kind == BinKind::CallExpression - ? ParseNodeKind::Call - : ParseNodeKind::New; - result->setKind(pnk); - result->prepend(callee); - - break; - } - case BinKind::SequenceExpression: { - for (auto field : fields) { - switch (field) { - case BinField::Expressions: - MOZ_TRY_VAR(result, parseExpressionList(/* acceptElisions = */ false)); - break; - default: - return raiseInvalidField("SequenceExpression", field); - } - } - - if (!result) - return raiseMissingField("SequenceExpression", BinField::Expression); - - result->setKind(ParseNodeKind::Comma); - break; - } - default: - return raiseInvalidKind("Expression", kind); - } - - return result; -} - -JS::Result -BinASTParser::parseNumericLiteralAux(const BinKind kind, const BinFields& fields) -{ - auto start = tokenizer_->offset(); - - Maybe value; - for (auto field : fields) { - switch (field) { - case BinField::Value: - MOZ_TRY_EMPLACE(value, readNumber()); - break; - default: - return raiseInvalidField("NumericLiteral", field); - } - } - - // In case of absent optional fields, inject default values. - if (!value) - value.emplace(0); - - TRY_DECL(result, factory_.newNumber(*value, DecimalPoint::HasDecimal, tokenizer_->pos(start))); - return result; -} - -JS::Result -BinASTParser::parseStringLiteralAux(const BinKind kind, const BinFields& fields) -{ - auto start = tokenizer_->offset(); - - RootedAtom value(cx_); - for (auto field : fields) { - switch (field) { - case BinField::Value: - MOZ_TRY(readString(&value)); - break; - default: - return raiseInvalidField("StringLiteral", field); - } - } - - if (!value) - return raiseMissingField("StringLiteral", BinField::Value); - - TRY_DECL(result, factory_.newStringLiteral(value, tokenizer_->pos(start))); - return result; -} - -JS::Result -BinASTParser::parseArrayExpressionAux(const BinKind kind, const BinFields& fields) -{ - MOZ_ASSERT(kind == BinKind::ArrayExpression); - - ParseNode* result(nullptr); - for (auto field : fields) { - switch (field) { - case BinField::Elements: { - MOZ_TRY_VAR(result, parseExpressionList(/* acceptElisions = */ true)); - break; - } - default: - return raiseInvalidField("ArrayExpression", field); - } - } - - // Inject default values for absent fields. - if (!result) - TRY_VAR(result, factory_.newArrayLiteral(tokenizer_->offset())); - - MOZ_ASSERT(result->isKind(ParseNodeKind::Array)); - return result; -} - -JS::Result -BinASTParser::parseObjectExpressionAux(const BinKind kind, const BinFields& fields) -{ - MOZ_ASSERT(kind == BinKind::ObjectExpression); - - ParseNode* result(nullptr); - for (auto field : fields) { - switch (field) { - case BinField::Properties: { - MOZ_TRY_VAR(result, parseObjectMemberList()); - break; - } - default: - return raiseInvalidField("Property | Method", field); - } - } - - if (!result) - TRY_VAR(result, factory_.newObjectLiteral(tokenizer_->offset())); - - MOZ_ASSERT(result->isArity(PN_LIST)); - MOZ_ASSERT(result->isKind(ParseNodeKind::Object)); - -#if defined(DEBUG) - // Sanity check. - for (ParseNode* iter = result->pn_head; iter != nullptr; iter = iter->pn_next) { - MOZ_ASSERT(iter->isKind(ParseNodeKind::Colon)); - MOZ_ASSERT(iter->pn_left != nullptr); - MOZ_ASSERT(iter->pn_right != nullptr); - } -#endif // defined(DEBUG) - - return result; -} - -JS::Result -BinASTParser::parseMemberExpressionAux(const BinKind kind, const BinFields& fields) -{ - MOZ_ASSERT(kind == BinKind::DotExpression || kind == BinKind::BracketExpression); - - ParseNode* object(nullptr); - ParseNode* property(nullptr); - - for (auto field : fields) { - switch (field) { - case BinField::Object: - MOZ_TRY_VAR(object, parseExpression()); - break; - case BinField::Property: - if (kind == BinKind::BracketExpression) - MOZ_TRY_VAR(property, parseExpression()); - else - MOZ_TRY_VAR(property, parseIdentifier()); - break; - default: - return raiseInvalidField("MemberExpression", field); - } - } - - // In case of absent required fields, fail. - if (!object) - return raiseMissingField("MemberExpression", BinField::Object); - if (!property) - return raiseMissingField("MemberExpression", BinField::Property); - - ParseNode* result(nullptr); - if (kind == BinKind::DotExpression) { - MOZ_ASSERT(property->isKind(ParseNodeKind::Name)); - PropertyName* name = property->pn_atom->asPropertyName(); - TRY_VAR(result, factory_.newPropertyAccess(object, name, tokenizer_->offset())); - } else { - TRY_VAR(result, factory_.newPropertyByValue(object, property, tokenizer_->offset())); - } - - return result; -} - -JS::Result -BinASTParser::parseDirectiveList() -{ - uint32_t length; - AutoList guard(*tokenizer_); - TRY(tokenizer_->enterList(length, guard)); - - TokenPos pos = tokenizer_->pos(); - TRY_DECL(result, factory_.newStatementList(pos)); - - RootedAtom value(cx_); - for (uint32_t i = 0; i < length; ++i) { - value = nullptr; - MOZ_TRY(readString(&value)); - - TRY_DECL(directive, factory_.newStringLiteral(value, pos)); - factory_.addStatementToList(result, directive); - } - - TRY(guard.done()); - return result; -} - -JS::Result -BinASTParser::parseSwitchCase() -{ - const size_t start = tokenizer_->offset(); - - BinKind kind; - BinFields fields(cx_); - AutoTaggedTuple guard(*tokenizer_); - - TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); - if (kind != BinKind::SwitchCase) - return raiseInvalidKind("SwitchCase", kind); - - ParseNode* test(nullptr); // Optional. - ParseNode* statements(nullptr); // Required. - - for (auto field : fields) { - switch (field) { - case BinField::Test: - MOZ_TRY_VAR(test, parseExpression()); - break; - case BinField::Consequent: - MOZ_TRY_VAR(statements, parseStatementList()); - break; - default: - return raiseInvalidField("SwitchCase", field); - } - } - - TRY(guard.done()); - if (!statements) - return raiseMissingField("SwitchCase", BinField::Consequent); - - MOZ_ASSERT(statements->isKind(ParseNodeKind::StatementList)); - - TRY_DECL(result, factory_.newCaseOrDefault(start, test, statements)); - - return result; -} - -JS::Result -BinASTParser::parseCatchClause() -{ - ParseContext::Statement stmt(parseContext_, StatementKind::Catch); - ParseContext::Scope scope(cx_, parseContext_, usedNames_); - TRY(scope.init(parseContext_)); - - BinKind kind; - BinFields fields(cx_); - AutoTaggedTuple guard(*tokenizer_); - - TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); - ParseNode* result(nullptr); - - switch (kind) { - default: - return raiseInvalidKind("CatchClause", kind); - case BinKind::CatchClause: { - ParseNode* param(nullptr); - ParseNode* body(nullptr); - - for (auto field : fields) { - switch (field) { - case BinField::Param: - MOZ_TRY_VAR(param, parsePattern()); - break; - case BinField::Body: - MOZ_TRY_VAR(body, parseBlockStatement()); - break; - case BinField::BINJS_Scope: - MOZ_TRY(parseAndUpdateCurrentScope()); - break; - default: - return raiseInvalidField("CatchClause", field); - } - } - - if (!param) - return raiseMissingField("CatchClause", BinField::Param); - if (!body) - return raiseMissingField("CatchClause", BinField::Body); - - TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, parseContext_)); - TRY_VAR(result, factory_.newLexicalScope(*bindings, body)); - TRY(factory_.setupCatchScope(result, param, body)); - } - } - - TRY(guard.done()); - return result; -} - -JS::Result -BinASTParser::parseArgumentList() -{ - uint32_t length; - AutoList guard(*tokenizer_); - - TRY(tokenizer_->enterList(length, guard)); - ParseNode* result = new_(ParseNodeKind::ParamsBody, tokenizer_->pos()); - - for (uint32_t i = 0; i < length; ++i) { - ParseNode* pattern; - MOZ_TRY_VAR(pattern, parsePattern()); - - result->appendWithoutOrderAssumption(pattern); - } - - TRY(guard.done()); - return result; -} - -JS::Result -BinASTParser::parseIdentifier() -{ - BinKind kind; - BinFields fields(cx_); - AutoTaggedTuple guard(*tokenizer_); - - TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); - ParseNode* result; - MOZ_TRY_VAR(result, parseIdentifierAux(kind, fields)); - - TRY(guard.done()); - return result; -} - -JS::Result -BinASTParser::parseIdentifierAux(const BinKind, const BinFields& fields, const bool expectObjectPropertyName /* = false */) -{ - const size_t start = tokenizer_->offset(); - - RootedAtom id(cx_); - for (auto field : fields) { - switch (field) { - case BinField::Name: - MOZ_TRY(readString(&id)); - break; - default: - return raiseInvalidField("Identifier", field); - } - } - - if (!id) - return raiseMissingField("Identifier", BinField::Name); - - if (!IsIdentifier(id)) - return raiseError("Invalid identifier"); - if (!expectObjectPropertyName && IsKeyword(id)) - return raiseError("Invalid identifier (keyword)"); - - // Once `IsIdentifier` has returned true, we may call `asPropertyName()` without fear. - TokenPos pos = tokenizer_->pos(start); - - ParseNode* result; - if (expectObjectPropertyName) - TRY_VAR(result, factory_.newObjectLiteralPropertyName(id->asPropertyName(), pos)); - else - TRY_VAR(result, factory_.newName(id->asPropertyName(), pos, cx_)); - - return result; -} - - -JS::Result -BinASTParser::parsePattern() -{ - BinKind kind; - BinFields fields(cx_); - AutoTaggedTuple guard(*tokenizer_); - - TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); - ParseNode* result; - MOZ_TRY_VAR(result, parsePatternAux(kind, fields)); - - TRY(guard.done()); - return result; -} - -JS::Result -BinASTParser::parsePatternAux(const BinKind kind, const BinFields& fields) -{ - ParseNode* result; - switch (kind) { - case BinKind::Identifier: - MOZ_TRY_VAR(result, parseIdentifierAux(kind ,fields)); - break; - default: - return raiseInvalidKind("Pattern", kind); - } - - return result; -} - -JS::Result -BinASTParser::parseObjectMember() -{ - BinKind kind; - BinFields fields(cx_); - AutoTaggedTuple guard(*tokenizer_); - - TRY(tokenizer_->enterTaggedTuple(kind, fields, guard)); - ParseNode* result(nullptr); - - switch (kind) { - case BinKind::ObjectProperty: { - ParseNode* key(nullptr); - ParseNode* value(nullptr); - for (auto field : fields) { - switch (field) { - case BinField::Key: - MOZ_TRY_VAR(key, parseObjectPropertyName()); - break; - case BinField::Value: - MOZ_TRY_VAR(value, parseExpression()); - break; - default: - return raiseInvalidField("ObjectMember", field); - } - } - - if (!key) - return raiseMissingField("ObjectMember", BinField::Key); - if (!value) - return raiseMissingField("ObjectMember", BinField::Value); - - if (!factory_.isUsableAsObjectPropertyName(key)) - return raiseError("ObjectMember key kind"); - - TRY_VAR(result, factory_.newObjectMethodOrPropertyDefinition(key, value, AccessorType::None)); - - break; - } - case BinKind::ObjectMethod: - case BinKind::ObjectGetter: - case BinKind::ObjectSetter: - MOZ_TRY_VAR(result, parseFunctionAux(kind, fields)); - - if (!result) - return raiseEmpty("ObjectMethod"); - - MOZ_ASSERT(result->isKind(ParseNodeKind::Colon)); - break; - default: - return raiseInvalidKind("ObjectMember", kind); - } - - TRY(guard.done()); - MOZ_ASSERT(result); - return result; -} - -JS::Result -BinASTParser::parseObjectMemberList() -{ - uint32_t length; - AutoList guard(*tokenizer_); - - auto start = tokenizer_->offset(); - TRY(tokenizer_->enterList(length, guard)); - - TRY_DECL(result, factory_.newObjectLiteral(start)); - - for (uint32_t i = 0; i < length; ++i) { - ParseNode* keyValue; - MOZ_TRY_VAR(keyValue, parseObjectMember()); - MOZ_ASSERT(keyValue); - - result->appendWithoutOrderAssumption(keyValue); - } - - TRY(guard.done()); - return result; -} - - -JS::Result -BinASTParser::checkEmptyTuple(const BinKind kind, const BinFields& fields) -{ - if (fields.length() != 0) - return raiseInvalidField(describeBinKind(kind), fields[0]); - - return Ok(); -} - - JS::Result BinASTParser::readString(MutableHandleAtom out) { MOZ_ASSERT(!out); Maybe string; - MOZ_TRY(readString(string)); + MOZ_TRY(readMaybeString(string)); MOZ_ASSERT(string); RootedAtom atom(cx_); - TRY_VAR(atom, Atomize(cx_, (const char*)string->begin(), string->length())); + TRY_VAR(atom, AtomizeUTF8Chars(cx_, (const char*)string->begin(), string->length())); out.set(Move(atom)); return Ok(); } -JS::Result -BinASTParser::parsePropertyName() +JS::Result +BinASTParser::readMaybeString(MutableHandleAtom out) { + MOZ_ASSERT(!out); + + Maybe string; + MOZ_TRY(readMaybeString(string)); + if (!string) { + return Ok(); + } + RootedAtom atom(cx_); - MOZ_TRY(readString(&atom)); + TRY_VAR(atom, AtomizeUTF8Chars(cx_, (const char*)string->begin(), string->length())); - TokenPos pos = tokenizer_->pos(); + out.set(Move(atom)); + return Ok(); +} - ParseNode* result; - // If the atom matches an index (e.g. "3"), we need to normalize the - // propertyName to ensure that it has the same representation as - // the numeric index (e.g. 3). - uint32_t index; - if (atom->isIndex(&index)) - TRY_VAR(result, factory_.newNumber(index, NoDecimal, pos)); - else - TRY_VAR(result, factory_.newStringLiteral(atom, pos)); - - return result; +JS::Result +BinASTParser::readString(Chars& result) +{ + TRY(tokenizer_->readChars(result)); + return Ok(); } JS::Result -BinASTParser::readString(Maybe& out) +BinASTParser::readMaybeString(Maybe& out) { MOZ_ASSERT(out.isNothing()); - Chars result(cx_); - TRY(tokenizer_->readChars(result)); - - out.emplace(Move(result)); + TRY(tokenizer_->readMaybeChars(out)); return Ok(); } @@ -2398,6 +399,20 @@ BinASTParser::readBool() return result; } +mozilla::GenericErrorResult +BinASTParser::raiseMissingVariableInAssertedScope(JSAtom* name) +{ + // For the moment, we don't trust inputs sufficiently to put the name + // in an error message. + return raiseError("Missing variable in AssertedScope"); +} + +mozilla::GenericErrorResult +BinASTParser::raiseMissingDirectEvalInAssertedScope() +{ + return raiseError("Direct call to `eval` was not declared in AssertedScope"); +} + mozilla::GenericErrorResult BinASTParser::raiseInvalidKind(const char* superKind, const BinKind kind) { @@ -2416,6 +431,16 @@ BinASTParser::raiseInvalidField(const char* kind, const BinField field) return raiseError(out.string()); } +mozilla::GenericErrorResult +BinASTParser::raiseInvalidNumberOfFields(const BinKind kind, const uint32_t expected, const uint32_t got) +{ + Sprinter out(cx_); + TRY(out.init()); + TRY(out.printf("In %s, invalid number of fields: expected %u, got %u", + describeBinKind(kind), expected, got)); + return raiseError(out.string()); +} + mozilla::GenericErrorResult BinASTParser::raiseInvalidEnum(const char* kind, const Chars& value) { diff --git a/js/src/frontend/BinSource.h b/js/src/frontend/BinSource.h index 7c65b9f558ad..259a9ab38fb6 100644 --- a/js/src/frontend/BinSource.h +++ b/js/src/frontend/BinSource.h @@ -39,9 +39,10 @@ class BinASTParser; */ class BinASTParser : private JS::AutoGCRooter, public ErrorReporter { - using Names = JS::GCVector; using Tokenizer = BinTokenReaderTester; + using BinFields = Tokenizer::BinFields; using Chars = Tokenizer::Chars; + using Names = JS::GCVector; public: BinASTParser(JSContext* cx, LifoAlloc& alloc, UsedNameTracker& usedNames, const JS::ReadOnlyCompileOptions& options) @@ -92,87 +93,63 @@ class BinASTParser : private JS::AutoGCRooter, public ErrorReporter // // These methods return a (failed) JS::Result for convenience. - MOZ_MUST_USE mozilla::GenericErrorResult raiseInvalidKind(const char* superKind, const BinKind kind); - MOZ_MUST_USE mozilla::GenericErrorResult raiseInvalidField(const char* kind, const BinField field); - MOZ_MUST_USE mozilla::GenericErrorResult raiseInvalidEnum(const char* kind, const Chars& value); - MOZ_MUST_USE mozilla::GenericErrorResult raiseMissingField(const char* kind, const BinField field); + MOZ_MUST_USE mozilla::GenericErrorResult raiseMissingVariableInAssertedScope(JSAtom* name); + MOZ_MUST_USE mozilla::GenericErrorResult raiseMissingDirectEvalInAssertedScope(); + MOZ_MUST_USE mozilla::GenericErrorResult raiseInvalidKind(const char* superKind, + const BinKind kind); + MOZ_MUST_USE mozilla::GenericErrorResult raiseInvalidField(const char* kind, + const BinField field); + MOZ_MUST_USE mozilla::GenericErrorResult raiseInvalidNumberOfFields( + const BinKind kind, const uint32_t expected, const uint32_t got); + MOZ_MUST_USE mozilla::GenericErrorResult raiseInvalidEnum(const char* kind, + const Chars& value); + MOZ_MUST_USE mozilla::GenericErrorResult raiseMissingField(const char* kind, + const BinField field); MOZ_MUST_USE mozilla::GenericErrorResult raiseEmpty(const char* description); MOZ_MUST_USE mozilla::GenericErrorResult raiseOOM(); MOZ_MUST_USE mozilla::GenericErrorResult raiseError(const char* description); - MOZ_MUST_USE mozilla::GenericErrorResult raiseError(BinKind kind, const char* description); + MOZ_MUST_USE mozilla::GenericErrorResult raiseError(BinKind kind, + const char* description); + // Ensure that this parser will never be used again. void poison(); - // --- Parse full nodes (methods are sorted by alphabetical order) - // - // These method may NEVER return `nullptr`. // FIXME: We can probably optimize Result<> based on this. + // Auto-generated methods +#include "frontend/BinSource-auto.h" - MOZ_MUST_USE JS::Result parseBlockStatement(); - MOZ_MUST_USE JS::Result parseCatchClause(); - MOZ_MUST_USE JS::Result parseExpression(); - MOZ_MUST_USE JS::Result parseForInit(); - MOZ_MUST_USE JS::Result parseForInInit(); - MOZ_MUST_USE JS::Result parseIdentifier(); - MOZ_MUST_USE JS::Result parseObjectPropertyName(); - MOZ_MUST_USE JS::Result parseObjectMember(); - MOZ_MUST_USE JS::Result parsePattern(); // Parse a *binding* pattern. - MOZ_MUST_USE JS::Result parsePropertyName(); - MOZ_MUST_USE JS::Result parseProgram(); - MOZ_MUST_USE JS::Result parseStatement(); - MOZ_MUST_USE JS::Result parseSwitchCase(); - MOZ_MUST_USE JS::Result parseVariableDeclarator(); + // --- Auxiliary parsing functions + template + JS::Result + checkFields(const BinKind kind, const BinFields& actual, const BinField (&expected)[N]); + JS::Result + checkFields0(const BinKind kind, const BinFields& actual); + JS::Result + buildFunction(const size_t start, const BinKind kind, ParseNode* name, ParseNode* params, + ParseNode* body, FunctionBox* funbox); + JS::Result + buildFunctionBox(GeneratorKind generatorKind, FunctionAsyncKind functionAsyncKind); - // --- Parse lists of nodes (methods are sorted by alphabetical order) - - MOZ_MUST_USE JS::Result parseArgumentList(); - MOZ_MUST_USE JS::Result parseDirectiveList(); - MOZ_MUST_USE JS::Result parseExpressionList(bool acceptElisions); - - // Returns a list of PNK_COLON. - MOZ_MUST_USE JS::Result parseObjectMemberList(); - - MOZ_MUST_USE JS::Result parseStatementList(); - MOZ_MUST_USE JS::Result parseSwitchCaseList(); - - // --- Parse the contents of a node whose kind has already been determined. - - MOZ_MUST_USE JS::Result parseArrayExpressionAux(const BinKind kind, const Tokenizer::BinFields& fields); - MOZ_MUST_USE JS::Result parseBreakOrContinueStatementAux(const BinKind kind, const Tokenizer::BinFields& fields); - MOZ_MUST_USE JS::Result parseBlockStatementAux(const BinKind kind, const Tokenizer::BinFields& fields); - MOZ_MUST_USE JS::Result parseExpressionStatementAux(const BinKind kind, const Tokenizer::BinFields& fields); - MOZ_MUST_USE JS::Result parseExpressionAux(const BinKind kind, const Tokenizer::BinFields& fields); - MOZ_MUST_USE JS::Result parseFunctionAux(const BinKind kind, const Tokenizer::BinFields& fields); - MOZ_MUST_USE JS::Result parseIdentifierAux(const BinKind, const Tokenizer::BinFields& fields, const bool expectObjectPropertyName = false); - MOZ_MUST_USE JS::Result parseMemberExpressionAux(const BinKind kind, const Tokenizer::BinFields& fields); - MOZ_MUST_USE JS::Result parseNumericLiteralAux(const BinKind kind, const Tokenizer::BinFields& fields); - MOZ_MUST_USE JS::Result parseObjectExpressionAux(const BinKind kind, const Tokenizer::BinFields& fields); - MOZ_MUST_USE JS::Result parsePatternAux(const BinKind kind, const Tokenizer::BinFields& fields); - MOZ_MUST_USE JS::Result parseStringLiteralAux(const BinKind kind, const Tokenizer::BinFields& fields); - MOZ_MUST_USE JS::Result parseStatementAux(const BinKind kind, const Tokenizer::BinFields& fields); - MOZ_MUST_USE JS::Result parseVariableDeclarationAux(const BinKind kind, const Tokenizer::BinFields& fields); - - // --- Auxiliary parsing functions that may have a side-effect on the parser but do not return a node. - - MOZ_MUST_USE JS::Result checkEmptyTuple(const BinKind kind, const Tokenizer::BinFields& fields); - MOZ_MUST_USE JS::Result parseElisionAux(const BinKind kind, const Tokenizer::BinFields& fields); - - // Parse full scope information to the current innermost scope. - MOZ_MUST_USE JS::Result parseAndUpdateCurrentScope(); // Parse full scope information to a specific var scope / let scope combination. - MOZ_MUST_USE JS::Result parseAndUpdateScope(ParseContext::Scope& varScope, ParseContext::Scope& letScope); + MOZ_MUST_USE JS::Result parseAndUpdateScope(ParseContext::Scope& varScope, + ParseContext::Scope& letScope); // Parse a list of names and add it to a given scope. - MOZ_MUST_USE JS::Result parseAndUpdateScopeNames(ParseContext::Scope& scope, DeclarationKind kind); - MOZ_MUST_USE JS::Result parseStringList(MutableHandle> out); + MOZ_MUST_USE JS::Result parseAndUpdateScopeNames(ParseContext::Scope& scope, + DeclarationKind kind); + MOZ_MUST_USE JS::Result parseAndUpdateCapturedNames(); + MOZ_MUST_USE JS::Result checkBinding(JSAtom* name); // --- Utilities. - MOZ_MUST_USE JS::Result appendDirectivesToBody(ParseNode* body, ParseNode* directives); + MOZ_MUST_USE JS::Result appendDirectivesToBody(ParseNode* body, + ParseNode* directives); - // Read a string as a `Chars`. - MOZ_MUST_USE JS::Result readString(Maybe& out); + // Read a string + MOZ_MUST_USE JS::Result readString(Chars& out); + MOZ_MUST_USE JS::Result readMaybeString(Maybe& out); MOZ_MUST_USE JS::Result readString(MutableHandleAtom out); + MOZ_MUST_USE JS::Result readMaybeString(MutableHandleAtom out); MOZ_MUST_USE JS::Result readBool(); MOZ_MUST_USE JS::Result readNumber(); @@ -261,8 +238,10 @@ class BinASTParser : private JS::AutoGCRooter, public ErrorReporter UsedNameTracker& usedNames_; Maybe tokenizer_; FullParseHandler factory_; + VariableDeclarationKind variableDeclarationKind_; friend class BinParseContext; + friend class AutoVariableDeclarationKind; // Needs access to AutoGCRooter. friend void TraceBinParser(JSTracer* trc, AutoGCRooter* parser); @@ -271,7 +250,8 @@ class BinASTParser : private JS::AutoGCRooter, public ErrorReporter class BinParseContext : public ParseContext { public: - BinParseContext(JSContext* cx, BinASTParser* parser, SharedContext* sc, Directives* newDirectives) + BinParseContext(JSContext* cx, BinASTParser* parser, SharedContext* sc, + Directives* newDirectives) : ParseContext(cx, parser->parseContext_, sc, *parser, parser->usedNames_, newDirectives, /* isFull = */ true) { } diff --git a/js/src/frontend/BinSource.webidl_ b/js/src/frontend/BinSource.webidl_ new file mode 100644 index 000000000000..24de1aae03f7 --- /dev/null +++ b/js/src/frontend/BinSource.webidl_ @@ -0,0 +1,871 @@ +// Type aliases and enums. + +typedef FrozenArray<(SpreadElement or Expression)> Arguments; +typedef DOMString string; +typedef string Identifier; +typedef string IdentifierName; +typedef string Label; + +enum VariableDeclarationKind { + "var", + "let", + "const" +}; + +enum CompoundAssignmentOperator { + "+=", + "-=", + "*=", + "/=", + "%=", + "**=", + "<<=", + ">>=", + ">>>=", + "|=", + "^=", + "&=" +}; + +enum BinaryOperator { + ",", + "||", + "&&", + "|", + "^", + "&", + "==", + "!=", + "===", + "!==", + "<", + "<=", + ">", + ">=", + "in", + "instanceof", + "<<", + ">>", + ">>>", + "+", + "-", + "*", + "/", + "%", + "**", +}; + +enum UnaryOperator { + "+", + "-", + "!", + "~", + "typeof", + "void", + "delete" +}; + +enum UpdateOperator { + "++", + "--" +}; + + +// deferred assertions + +interface AssertedBlockScope { + // checked eagerly during transformation + attribute FrozenArray lexicallyDeclaredNames; + + // checked lazily as inner functions are invoked + attribute FrozenArray capturedNames; + attribute boolean hasDirectEval; +}; + +interface AssertedVarScope { + // checked eagerly during transformation + attribute FrozenArray lexicallyDeclaredNames; + attribute FrozenArray varDeclaredNames; + + // checked lazily as inner functions are invoked + attribute FrozenArray capturedNames; + attribute boolean hasDirectEval; +}; + +interface AssertedParameterScope { + // checked eagerly during transformation + attribute FrozenArray parameterNames; + + // checked lazily as inner functions are invoked + attribute FrozenArray capturedNames; + attribute boolean hasDirectEval; +}; + +// nodes + +interface Node { + [TypeIndicator] readonly attribute Type type; +}; + +typedef (Script or Module) Program; + +typedef (DoWhileStatement or + ForInStatement or + ForOfStatement or + ForStatement or + WhileStatement) + IterationStatement; + +typedef (Block or + BreakStatement or + ContinueStatement or + ClassDeclaration or + DebuggerStatement or + EmptyStatement or + ExpressionStatement or + FunctionDeclaration or + IfStatement or + IterationStatement or + LabelledStatement or + ReturnStatement or + SwitchStatement or + SwitchStatementWithDefault or + ThrowStatement or + TryCatchStatement or + TryFinallyStatement or + VariableDeclaration or + WithStatement) + Statement; + +typedef (LiteralBooleanExpression or + LiteralInfinityExpression or + LiteralNullExpression or + LiteralNumericExpression or + LiteralStringExpression) + Literal; + +typedef (Literal or + LiteralRegExpExpression or + ArrayExpression or + ArrowExpression or + AssignmentExpression or + BinaryExpression or + CallExpression or + CompoundAssignmentExpression or + ComputedMemberExpression or + ConditionalExpression or + ClassExpression or + FunctionExpression or + IdentifierExpression or + NewExpression or + NewTargetExpression or + ObjectExpression or + UnaryExpression or + StaticMemberExpression or + TemplateExpression or + ThisExpression or + UpdateExpression or + YieldExpression or + YieldStarExpression or + AwaitExpression) + Expression; + +typedef (ComputedPropertyName or + LiteralPropertyName) + PropertyName; + +typedef (Method or Getter or Setter) MethodDefinition; + +typedef (MethodDefinition or + DataProperty or + ShorthandProperty) + ObjectProperty; + +typedef (ExportAllFrom or + ExportFrom or + ExportLocals or + ExportDefault or + Export) + ExportDeclaration; + +typedef (ImportNamespace or Import) ImportDeclaration; + + +// bindings + +interface BindingIdentifier : Node { + attribute Identifier name; +}; + +typedef (ObjectBinding or + ArrayBinding) + BindingPattern; +typedef (BindingPattern or + BindingIdentifier) + Binding; + +typedef (AssignmentTargetIdentifier or + ComputedMemberAssignmentTarget or + StaticMemberAssignmentTarget) + SimpleAssignmentTarget; +typedef (ObjectAssignmentTarget or + ArrayAssignmentTarget) + AssignmentTargetPattern; +// `DestructuringAssignmentTarget` +typedef (AssignmentTargetPattern or + SimpleAssignmentTarget) + AssignmentTarget; + +// `FormalParameter` +typedef (Binding or + BindingWithInitializer) + Parameter; + +interface BindingWithInitializer : Node { + attribute Binding binding; + attribute Expression init; +}; + +interface AssignmentTargetIdentifier : Node { + attribute Identifier name; +}; + +interface ComputedMemberAssignmentTarget : Node { + // The object whose property is being assigned. + attribute (Expression or Super) _object; + // The expression resolving to the name of the property to be accessed. + attribute Expression expression; +}; + +interface StaticMemberAssignmentTarget : Node { + // The object whose property is being assigned. + attribute (Expression or Super) _object; + // The name of the property to be accessed. + attribute IdentifierName property; +}; + +// `ArrayBindingPattern` +interface ArrayBinding : Node { + // The elements of the array pattern; a null value represents an elision. + attribute FrozenArray<(Binding or BindingWithInitializer)?> elements; + attribute Binding? rest; +}; + +// `SingleNameBinding` +interface BindingPropertyIdentifier : Node { + attribute BindingIdentifier binding; + attribute Expression? init; +}; + +// `BindingProperty :: PropertyName : BindingElement` +interface BindingPropertyProperty : Node { + attribute PropertyName name; + attribute (Binding or BindingWithInitializer) binding; +}; + +typedef (BindingPropertyIdentifier or + BindingPropertyProperty) + BindingProperty; + +interface ObjectBinding : Node { + attribute FrozenArray properties; +}; + +// This interface represents the case where the initializer is present in +// `AssignmentElement :: DestructuringAssignmentTarget Initializer_opt`. +interface AssignmentTargetWithInitializer : Node { + attribute AssignmentTarget binding; + attribute Expression init; +}; + +// `ArrayAssignmentPattern` +interface ArrayAssignmentTarget : Node { + // The elements of the array pattern; a null value represents an elision. + attribute FrozenArray<(AssignmentTarget or AssignmentTargetWithInitializer?)> elements; + attribute AssignmentTarget? rest; +}; + +// `AssignmentProperty :: IdentifierReference Initializer_opt` +interface AssignmentTargetPropertyIdentifier : Node { + attribute AssignmentTargetIdentifier binding; + attribute Expression? init; +}; + +// `AssignmentProperty :: PropertyName : Node` +interface AssignmentTargetPropertyProperty : Node { + attribute PropertyName name; + attribute (AssignmentTarget or AssignmentTargetWithInitializer) binding; +}; + +typedef (AssignmentTargetPropertyIdentifier or + AssignmentTargetPropertyProperty) + AssignmentTargetProperty; + +// `ObjectAssignmentPattern` +interface ObjectAssignmentTarget : Node { + attribute FrozenArray properties; +}; + + +// classes + +interface ClassExpression : Node { + attribute BindingIdentifier? name; + attribute Expression? super; + attribute FrozenArray elements; +}; + +interface ClassDeclaration : Node { + attribute BindingIdentifier name; + attribute Expression? super; + attribute FrozenArray elements; +}; + +interface ClassElement : Node { + // True iff `IsStatic` of ClassElement is true. + attribute boolean isStatic; + attribute MethodDefinition method; +}; + + +// modules + +interface Module : Node { + attribute AssertedVarScope? scope; + attribute FrozenArray directives; + attribute FrozenArray<(ImportDeclaration or ExportDeclaration or Statement)> items; +}; + +// An `ImportDeclaration` not including a namespace import. +interface Import : Node { + attribute string moduleSpecifier; + // `ImportedDefaultBinding`, if present. + attribute BindingIdentifier? defaultBinding; + attribute FrozenArray namedImports; +}; + +// An `ImportDeclaration` including a namespace import. +interface ImportNamespace : Node { + attribute string moduleSpecifier; + // `ImportedDefaultBinding`, if present. + attribute BindingIdentifier? defaultBinding; + attribute BindingIdentifier namespaceBinding; +}; + +interface ImportSpecifier : Node { + // The `IdentifierName` in the production `ImportSpecifier :: IdentifierName as ImportedBinding`; + // absent if this specifier represents the production `ImportSpecifier :: ImportedBinding`. + attribute IdentifierName? name; + attribute BindingIdentifier binding; +}; + +// `export * FromClause;` +interface ExportAllFrom : Node { + attribute string moduleSpecifier; +}; + +// `export ExportClause FromClause;` +interface ExportFrom : Node { + attribute FrozenArray namedExports; + attribute string moduleSpecifier; +}; + +// `export ExportClause;` +interface ExportLocals : Node { + attribute FrozenArray namedExports; +}; + +// `export VariableStatement`, `export Declaration` +interface Export : Node { + attribute (FunctionDeclaration or ClassDeclaration or VariableDeclaration) declaration; +}; + +// `export default HoistableDeclaration`, +// `export default ClassDeclaration`, +// `export default AssignmentExpression` +interface ExportDefault : Node { + attribute (FunctionDeclaration or ClassDeclaration or Expression) body; +}; + +// `ExportSpecifier`, as part of an `ExportFrom`. +interface ExportFromSpecifier : Node { + // The only `IdentifierName in `ExportSpecifier :: IdentifierName`, + // or the first in `ExportSpecifier :: IdentifierName as IdentifierName`. + attribute IdentifierName name; + // The second `IdentifierName` in `ExportSpecifier :: IdentifierName as IdentifierName`, + // if that is the production represented. + attribute IdentifierName? exportedName; +}; + +// `ExportSpecifier`, as part of an `ExportLocals`. +interface ExportLocalSpecifier : Node { + // The only `IdentifierName in `ExportSpecifier :: IdentifierName`, + // or the first in `ExportSpecifier :: IdentifierName as IdentifierName`. + attribute IdentifierExpression name; + // The second `IdentifierName` in `ExportSpecifier :: IdentifierName as IdentifierName`, if present. + attribute IdentifierName? exportedName; +}; + + +// property definition + +// `MethodDefinition :: PropertyName ( UniqueFormalParameters ) { FunctionBody }`, +// `GeneratorMethod :: * PropertyName ( UniqueFormalParameters ) { GeneratorBody }`, +// `AsyncMethod :: async PropertyName ( UniqueFormalParameters ) { AsyncFunctionBody }` +interface Method : Node { + // True for `AsyncMethod`, false otherwise. + attribute boolean isAsync; + // True for `GeneratorMethod`, false otherwise. + attribute boolean isGenerator; + attribute AssertedParameterScope? parameterScope; + attribute AssertedVarScope? bodyScope; + attribute PropertyName name; + // The `UniqueFormalParameters`. + attribute FormalParameters params; + attribute FunctionBody body; +}; + +// `get PropertyName ( ) { FunctionBody }` +interface Getter : Node { + attribute AssertedVarScope? bodyScope; + attribute PropertyName name; + attribute FunctionBody body; +}; + +// `set PropertyName ( PropertySetParameterList ) { FunctionBody }` +interface Setter : Node { + attribute AssertedParameterScope? parameterScope; + attribute AssertedVarScope? bodyScope; + attribute PropertyName name; + // The `PropertySetParameterList`. + attribute Parameter param; + attribute FunctionBody body; +}; + +// `PropertyDefinition :: PropertyName : AssignmentExpression` +interface DataProperty : Node { + attribute PropertyName name; + // The `AssignmentExpression`. + attribute Expression expression; +}; + +// `PropertyDefinition :: IdentifierReference` +interface ShorthandProperty : Node { + // The `IdentifierReference`. + attribute IdentifierExpression name; +}; + +interface ComputedPropertyName : Node { + attribute Expression expression; +}; + +// `LiteralPropertyName` +interface LiteralPropertyName : Node { + attribute string value; +}; + + +// literals + +// `BooleanLiteral` +interface LiteralBooleanExpression : Node { + attribute boolean value; +}; + +// A `NumericLiteral` for which the Number value of its MV is positive infinity. +interface LiteralInfinityExpression : Node { }; + +// `NullLiteral` +interface LiteralNullExpression : Node { }; + +// `NumericLiteral` +interface LiteralNumericExpression : Node { + attribute double value; +}; + +// `RegularExpressionLiteral` +interface LiteralRegExpExpression : Node { + attribute string pattern; + attribute string flags; +}; + +// `StringLiteral` +interface LiteralStringExpression : Node { + attribute string value; +}; + + +// other expressions + +// `ArrayLiteral` +interface ArrayExpression : Node { + // The elements of the array literal; a null value represents an elision. + attribute FrozenArray<(SpreadElement or Expression)?> elements; +}; + +// `ArrowFunction`, +// `AsyncArrowFunction` +interface ArrowExpression : Node { + // True for `AsyncArrowFunction`, false otherwise. + attribute boolean isAsync; + attribute AssertedParameterScope? parameterScope; + attribute AssertedVarScope? bodyScope; + attribute FormalParameters params; + attribute (FunctionBody or Expression) body; +}; + +// `AssignmentExpression :: LeftHandSideExpression = AssignmentExpression` +interface AssignmentExpression : Node { + // The `LeftHandSideExpression`. + attribute AssignmentTarget binding; + // The `AssignmentExpression` following the `=`. + attribute Expression expression; +}; + +// `ExponentiationExpression`, +// `MultiplicativeExpression`, +// `AdditiveExpression`, +// `ShiftExpression`, +// `RelationalExpression`, +// `EqualityExpression`, +// `BitwiseANDExpression`, +// `BitwiseXORExpression`, +// `BitwiseORExpression`, +// `LogicalANDExpression`, +// `LogicalORExpression` +interface BinaryExpression : Node { + attribute BinaryOperator operator; + // The expression before the operator. + attribute Expression left; + // The expression after the operator. + attribute Expression right; +}; + +interface CallExpression : Node { + attribute (Expression or Super) callee; + attribute Arguments arguments; +}; + +// `AssignmentExpression :: LeftHandSideExpression AssignmentOperator AssignmentExpression` +interface CompoundAssignmentExpression : Node { + attribute CompoundAssignmentOperator operator; + // The `LeftHandSideExpression`. + attribute SimpleAssignmentTarget binding; + // The `AssignmentExpression`. + attribute Expression expression; +}; + +interface ComputedMemberExpression : Node { + // The object whose property is being accessed. + attribute (Expression or Super) _object; + // The expression resolving to the name of the property to be accessed. + attribute Expression expression; +}; + +// `ConditionalExpression :: LogicalORExpression ? AssignmentExpression : AssignmentExpression` +interface ConditionalExpression : Node { + // The `LogicalORExpression`. + attribute Expression test; + // The first `AssignmentExpression`. + attribute Expression consequent; + // The second `AssignmentExpression`. + attribute Expression alternate; +}; + +// `FunctionExpression`, +// `GeneratorExpression`, +// `AsyncFunctionExpression`, +interface FunctionExpression : Node { + attribute boolean isAsync; + attribute boolean isGenerator; + attribute AssertedParameterScope? parameterScope; + attribute AssertedVarScope? bodyScope; + attribute BindingIdentifier? name; + attribute FormalParameters params; + attribute FunctionBody body; +}; + +// `IdentifierReference` +interface IdentifierExpression : Node { + attribute Identifier name; +}; + +interface NewExpression : Node { + attribute Expression callee; + attribute Arguments arguments; +}; + +interface NewTargetExpression : Node { }; + +interface ObjectExpression : Node { + attribute FrozenArray properties; +}; + +interface UnaryExpression : Node { + attribute UnaryOperator operator; + attribute Expression operand; +}; + +interface StaticMemberExpression : Node { + // The object whose property is being accessed. + attribute (Expression or Super) _object; + // The name of the property to be accessed. + attribute IdentifierName property; +}; + +// `TemplateLiteral`, +// `MemberExpression :: MemberExpression TemplateLiteral`, +// `CallExpression : CallExpression TemplateLiteral` +interface TemplateExpression : Node { + // The second `MemberExpression` or `CallExpression`, if present. + attribute Expression? tag; + // The contents of the template. This list must be alternating + // TemplateElements and Expressions, beginning and ending with + // TemplateElement. + attribute FrozenArray<(Expression or TemplateElement)> elements; +}; + +// `PrimaryExpression :: this` +interface ThisExpression : Node { }; + +// `UpdateExpression :: LeftHandSideExpression ++`, +// `UpdateExpression :: LeftHandSideExpression --`, +// `UpdateExpression :: ++ LeftHandSideExpression`, +// `UpdateExpression :: -- LeftHandSideExpression` +interface UpdateExpression : Node { + // True for `UpdateExpression :: ++ LeftHandSideExpression` and + // `UpdateExpression :: -- LeftHandSideExpression`, false otherwise. + attribute boolean isPrefix; + attribute UpdateOperator operator; + attribute SimpleAssignmentTarget operand; +}; + +// `YieldExpression :: yield`, +// `YieldExpression :: yield AssignmentExpression` +interface YieldExpression : Node { + // The `AssignmentExpression`, if present. + attribute Expression? expression; +}; + +// `YieldExpression :: yield * AssignmentExpression` +interface YieldStarExpression : Node { + attribute Expression expression; +}; + +interface AwaitExpression : Node { + attribute Expression expression; +}; + + +// other statements + +interface BreakStatement : Node { + attribute Label? label; +}; + +interface ContinueStatement : Node { + attribute Label? label; +}; + +interface DebuggerStatement : Node { }; + +interface DoWhileStatement : Node { + attribute Expression test; + attribute Statement body; +}; + +interface EmptyStatement : Node { }; + +interface ExpressionStatement : Node { + attribute Expression expression; +}; + +interface ForInOfBinding : Node { + attribute VariableDeclarationKind kind; + attribute Binding binding; +}; + +// `for ( LeftHandSideExpression in Expression ) Statement`, +// `for ( var ForBinding in Expression ) Statement`, +// `for ( ForDeclaration in Expression ) Statement`, +// `for ( var BindingIdentifier Initializer in Expression ) Statement` +interface ForInStatement : Node { + // The expression or declaration before `in`. + attribute (ForInOfBinding or AssignmentTarget) left; + // The expression after `in`. + attribute Expression right; + attribute Statement body; +}; + +// `for ( LeftHandSideExpression of Expression ) Statement`, +// `for ( var ForBinding of Expression ) Statement`, +// `for ( ForDeclaration of Expression ) Statement` +interface ForOfStatement : Node { + // The expression or declaration before `of`. + attribute (ForInOfBinding or AssignmentTarget) left; + // The expression after `of`. + attribute Expression right; + attribute Statement body; +}; + +// `for ( Expression ; Expression ; Expression ) Statement`, +// `for ( var VariableDeclarationList ; Expression ; Expression ) Statement` +interface ForStatement : Node { + // The expression or declaration before the first `;`, if present. + attribute (VariableDeclaration or Expression)? init; + // The expression before the second `;`, if present + attribute Expression? test; + // The expression after the second `;`, if present + attribute Expression? update; + attribute Statement body; +}; + +// `if ( Expression ) Statement`, +// `if ( Expression ) Statement else Statement`, +interface IfStatement : Node { + attribute Expression test; + // The first `Statement`. + attribute Statement consequent; + // The second `Statement`, if present. + attribute Statement? alternate; +}; + +interface LabelledStatement : Node { + attribute Label label; + attribute Statement body; +}; + +interface ReturnStatement : Node { + attribute Expression? expression; +}; + +// A `SwitchStatement` whose `CaseBlock` is +// `CaseBlock :: { CaseClauses }`. +interface SwitchStatement : Node { + attribute Expression discriminant; + attribute FrozenArray cases; +}; + +// A `SwitchStatement` whose `CaseBlock` is +// `CaseBlock :: { CaseClauses DefaultClause CaseClauses }`. +interface SwitchStatementWithDefault : Node { + attribute Expression discriminant; + // The `CaseClauses` before the `DefaultClause`. + attribute FrozenArray preDefaultCases; + // The `DefaultClause`. + attribute SwitchDefault defaultCase; + // The `CaseClauses` after the `DefaultClause`. + attribute FrozenArray postDefaultCases; +}; + +interface ThrowStatement : Node { + attribute Expression expression; +}; + +// `TryStatement :: try Block Catch` +interface TryCatchStatement : Node { + attribute Block body; + attribute CatchClause catchClause; +}; + +// `TryStatement :: try Block Finally`, +// `TryStatement :: try Block Catch Finally` +interface TryFinallyStatement : Node { + // The `Block`. + attribute Block body; + // The `Catch`, if present. + attribute CatchClause? catchClause; + // The `Finally`. + attribute Block finalizer; +}; + +interface WhileStatement : Node { + attribute Expression test; + attribute Statement body; +}; + +interface WithStatement : Node { + attribute Expression _object; + attribute Statement body; +}; + + +// other nodes + +interface Block : Node { + attribute AssertedBlockScope? scope; + attribute FrozenArray statements; +}; + +// `Catch` +interface CatchClause : Node { + attribute Binding binding; + attribute Block body; +}; + +// An item in a `DirectivePrologue` +interface Directive : Node { + attribute string rawValue; +}; + +interface FormalParameters : Node { + attribute FrozenArray items; + attribute Binding? rest; +}; + +interface FunctionBody : Node { + attribute FrozenArray directives; + attribute FrozenArray statements; +}; + +// `FunctionDeclaration`, +// `GeneratorDeclaration`, +// `AsyncFunctionDeclaration` +interface FunctionDeclaration : Node { + attribute boolean isAsync; + attribute boolean isGenerator; + attribute AssertedParameterScope? parameterScope; + attribute AssertedVarScope? bodyScope; + attribute BindingIdentifier name; + attribute FormalParameters params; + attribute FunctionBody body; +}; + +interface Script : Node { + attribute AssertedVarScope? scope; + attribute FrozenArray directives; + attribute FrozenArray statements; +}; + +interface SpreadElement : Node { + attribute Expression expression; +}; + +// `super` +interface Super : Node { }; + +// `CaseClause` +interface SwitchCase : Node { + attribute Expression test; + attribute FrozenArray consequent; +}; + +// `DefaultClause` +interface SwitchDefault : Node { + attribute FrozenArray consequent; +}; + +// `TemplateCharacters` +interface TemplateElement : Node { + attribute string rawValue; +}; + +interface VariableDeclaration : Node { + attribute VariableDeclarationKind kind; + [NonEmpty] attribute FrozenArray declarators; +}; + +interface VariableDeclarator : Node { + attribute Binding binding; + attribute Expression? init; +}; diff --git a/js/src/frontend/BinSource.yaml b/js/src/frontend/BinSource.yaml new file mode 100644 index 000000000000..2933e417fc2d --- /dev/null +++ b/js/src/frontend/BinSource.yaml @@ -0,0 +1,1086 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Rules for generating BinSource-auto.cpp +cpp: + header: | + /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + // To generate this file, see the documentation in + // js/src/frontend/binsource/README.md. + + #include "mozilla/ArrayUtils.h" + #include "mozilla/Casting.h" + #include "mozilla/Maybe.h" + #include "mozilla/Move.h" + #include "mozilla/PodOperations.h" + #include "mozilla/Vector.h" + + #include "frontend/BinSource.h" + #include "frontend/BinTokenReaderTester.h" + #include "frontend/FullParseHandler.h" + #include "frontend/Parser.h" + #include "frontend/SharedContext.h" + + #include "vm/RegExpObject.h" + + #include "frontend/ParseContext-inl.h" + #include "frontend/ParseNode-inl.h" + + namespace js { + namespace frontend { + + using AutoList = BinTokenReaderTester::AutoList; + using AutoTaggedTuple = BinTokenReaderTester::AutoTaggedTuple; + using AutoTuple = BinTokenReaderTester::AutoTuple; + using BinFields = BinTokenReaderTester::BinFields; + using Chars = BinTokenReaderTester::Chars; + using NameBag = GCHashSet; + using Names = GCVector; + using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr; + + // Evaluate an expression EXPR, checking that the result is not falsy. + // + // Throw `cx->alreadyReportedError()` if it returns 0/nullptr. + #define TRY(EXPR) \ + do { \ + if (!EXPR) \ + return cx_->alreadyReportedError(); \ + } while(false) + + + // Evaluate an expression EXPR, checking that the result is not falsy. + // In case of success, assign the result to VAR. + // + // Throw `cx->alreadyReportedError()` if it returns 0/nullptr. + #define TRY_VAR(VAR, EXPR) \ + do { \ + VAR = EXPR; \ + if (!VAR) \ + return cx_->alreadyReportedError(); \ + } while (false) + + // Evaluate an expression EXPR, checking that the result is not falsy. + // In case of success, assign the result to a new variable VAR. + // + // Throw `cx->alreadyReportedError()` if it returns 0/nullptr. + #define TRY_DECL(VAR, EXPR) \ + auto VAR = EXPR; \ + if (!VAR) \ + return cx_->alreadyReportedError(); + + // Evaluate an expression EXPR, checking that the result is a success. + // In case of success, unwrap and assign the result to a new variable VAR. + // + // In case of error, propagate the error. + #define MOZ_TRY_DECL(VAR, EXPR) \ + auto _##VAR = EXPR; \ + if (_##VAR.isErr()) \ + return ::mozilla::Err(_##VAR.unwrapErr()); \ + auto VAR = _##VAR.unwrap(); + + // Ensure that we are visiting the right fields. + template + JS::Result + BinASTParser::checkFields(const BinKind kind, const BinFields& actual, const BinField (&expected)[N]) + { + if (actual.length() != N) + return raiseInvalidNumberOfFields(kind, N, actual.length()); + + for (size_t i = 0; i < N; ++i) { + if (actual[i] != expected[i]) + return raiseInvalidField(describeBinKind(kind), actual[i]); + } + + return Ok(); + } + + // Special case for N=0, as empty arrays are not permitted in C++ + JS::Result + BinASTParser::checkFields0(const BinKind kind, const BinFields& actual) + { + if (actual.length() != 0) + return raiseInvalidNumberOfFields(kind, 0, actual.length()); + + return Ok(); + } + + // Compare a bunch of `uint8_t` values (as returned by the tokenizer_) with + // a string literal (and ONLY a string literal). + template + bool operator==(const Chars& left, const char (&right)[N]) { + return BinTokenReaderTester::equals(left, right); + } + + // Helper class: Restore field `variableDeclarationKind_` upon leaving a scope. + class MOZ_RAII AutoVariableDeclarationKind { + public: + explicit AutoVariableDeclarationKind(BinASTParser* parser + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : + parser_(parser), + kind(parser->variableDeclarationKind_) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + ~AutoVariableDeclarationKind() { + parser_->variableDeclarationKind_ = kind; + } + private: + BinASTParser* parser_; + BinASTParser::VariableDeclarationKind kind; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + }; + + footer: | + + #undef TRY + #undef TRY_VAR + #undef TRY_DECL + #undef MOZ_TRY_DECL + } // namespace frontend + } // namespace js + +hpp: + # Rules for generating BinSource-class.h + class: + header: | + /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + // To generate this file, see the documentation in + // js/src/frontend/binsource/README.md. + + // This file is meant to be included from the declaration + // of class `BinASTParser`. The include may be public or private. + + # Rules for generating BinToken.h + tokens: + kind: + doc: | + /** + * The different kinds of Binary AST nodes, as per the specifications of + * Binary AST. + * + * These kinds match roughly with the `ParseNodeKind` used internally. + * + * Usage: + * + * ```c++ + * #define WITH_KIND(CPP_NAME, SPEC_NAME) ... + * FOR_EACH_BIN_KIND(WITH_KIND) + * ``` + * + * + * (sorted by alphabetical order) + */ + field: + doc: | + /** + * The different fields of Binary AST nodes, as per the specifications of + * Binary AST. + * + * Usage: + * + * ```c++ + * #define WITH_FIELD(CPP_NAME, SPEC_NAME) ... + * FOR_EACH_BIN_FIELD(WITH_FIELD) + * ``` + * + * (sorted by alphabetical order) + */ + + header: | + /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + + // To generate this file, see the documentation in + // js/src/frontend/binsource/README.md. + + #ifndef frontend_BinToken_h + #define frontend_BinToken_h + + #include + + /** + * Definition of Binary AST tokens. + * + * In the Binary AST world, an AST is composed of nodes, where a node is + * defined by: + * - a Kind (see `BinKind`); + * - a list of fields, where each field is: + * - a Name (see `BinField`); + * - a Value, which may be either a node or a primitive value. + * + * The mapping between Kind and list of fields is determined entirely by + * the grammar of Binary AST. The mapping between (Kind, Name) and the + * structure of Value is also determined entirely by the grammar of + * Binary AST. + * + * As per the specifications of Binary AST, kinds may be added as the + * language grows, but never removed. The mapping between Kind and list + * of fields may also change to add new fields or make some fields optional, + * but may never remove a field. Finally, the mapping between (Kind, Name) + * and the structure of Value may be modified to add new possible values, + * but never to remove a value. + * + * A Binary AST parser must be able to fail gracefully when confronted with + * unknown Kinds or Names. + */ + + namespace js { + namespace frontend { + footer: | + + /** + * Return a string describing a `BinKind`. + */ + const char* describeBinKind(const BinKind& kind); + + /** + * Return a string describing a `BinField`. + */ + const char* describeBinField(const BinField& kind); + + } // namespace frontend + } // namespace js + + #endif // frontend_BinToken_h + +Arguments: + init: + TRY_DECL(result, factory_.newList(ParseNodeKind::ParamsBody, tokenizer_->pos(start))); + append: + factory_.addList(/* list = */ result, /* child = */ item); + +ArrayExpression: + build: + auto result = elements; + +AssertedBlockScope: + type-ok: + Ok + build: | + if (hasDirectEval && parseContext_->isFunctionBox() && !parseContext_->sc()->strict()) { + // In non-strict mode code, direct calls to eval can + // add variables to the call object. + parseContext_->functionBox()->setHasExtensibleScope(); + } + auto result = Ok(); + fields: + capturedNames: + block: + replace: | + MOZ_TRY(parseAndUpdateCapturedNames()); + hasDirectEval: + after: | + if (hasDirectEval) { + parseContext_->sc()->setHasDirectEval(); + parseContext_->sc()->setBindingsAccessedDynamically(); + } + lexicallyDeclaredNames: + block: + replace: + MOZ_TRY(parseAndUpdateScopeNames(*parseContext_->innermostScope(), DeclarationKind::Let)); + +AssertedParameterScope: + inherits: AssertedBlockScope + fields: + parameterNames: + block: + replace: | + MOZ_TRY(parseAndUpdateScopeNames(parseContext_->functionScope(), DeclarationKind:: PositionalFormalParameter)); + +AssertedVarScope: + inherits: AssertedBlockScope + fields: + varDeclaredNames: + block: + replace: + MOZ_TRY(parseAndUpdateScopeNames(parseContext_->varScope(), DeclarationKind::Var)); + +AssignmentExpression: + build: | + TRY_DECL(result, factory_.newAssignment(ParseNodeKind::Assign, binding, expression)); + +AssignmentTargetIdentifier: + build: | + if (!IsIdentifier(name)) + return raiseError("Invalid identifier"); + TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_)); + +BindingIdentifier: + build: | + if (!IsIdentifier(name)) + return raiseError("Invalid identifier"); + TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_)); + +BinaryExpression: + build: | + ParseNodeKind pnk; + switch (operator_) { + case BinaryOperator::Comma: + pnk = ParseNodeKind::Comma; + break; + case BinaryOperator::LogicalOr: + pnk = ParseNodeKind::Or; + break; + case BinaryOperator::LogicalAnd: + pnk = ParseNodeKind::And; + break; + case BinaryOperator::BitOr: + pnk = ParseNodeKind::BitOr; + break; + case BinaryOperator::BitXor: + pnk = ParseNodeKind::BitXor; + break; + case BinaryOperator::BitAnd: + pnk = ParseNodeKind::BitAnd; + break; + case BinaryOperator::Eq: + pnk = ParseNodeKind::Eq; + break; + case BinaryOperator::Neq: + pnk = ParseNodeKind::Ne; + break; + case BinaryOperator::StrictEq: + pnk = ParseNodeKind::StrictEq; + break; + case BinaryOperator::StrictNeq: + pnk = ParseNodeKind::StrictNe; + break; + case BinaryOperator::LessThan: + pnk = ParseNodeKind::Lt; + break; + case BinaryOperator::LeqThan: + pnk = ParseNodeKind::Le; + break; + case BinaryOperator::GreaterThan: + pnk = ParseNodeKind::Gt; + break; + case BinaryOperator::GeqThan: + pnk = ParseNodeKind::Ge; + break; + case BinaryOperator::In: + pnk = ParseNodeKind::In; + break; + case BinaryOperator::Instanceof: + pnk = ParseNodeKind::InstanceOf; + break; + case BinaryOperator::Lsh: + pnk = ParseNodeKind::Lsh; + break; + case BinaryOperator::Rsh: + pnk = ParseNodeKind::Rsh; + break; + case BinaryOperator::Ursh: + pnk = ParseNodeKind::Ursh; + break; + case BinaryOperator::Plus: + pnk = ParseNodeKind::Add; + break; + case BinaryOperator::Minus: + pnk = ParseNodeKind::Sub; + break; + case BinaryOperator::Mul: + pnk = ParseNodeKind::Star; + break; + case BinaryOperator::Div: + pnk = ParseNodeKind::Div; + break; + case BinaryOperator::Mod: + pnk = ParseNodeKind::Mod; + break; + case BinaryOperator::Pow: + pnk = ParseNodeKind::Pow; + break; + } + + ParseNode* result; + if (left->isKind(pnk) && + pnk != ParseNodeKind::Pow /* ParseNodeKind::Pow is not left-associative */) + { + // Regroup left-associative operations into lists. + left->appendWithoutOrderAssumption(right); + result = left; + } else { + TRY_DECL(list, factory_.newList(pnk, tokenizer_->pos(start))); + + list->appendWithoutOrderAssumption(left); + list->appendWithoutOrderAssumption(right); + result = list; + } + +Block: + init: | + fprintf(stderr, "Block: PUSH parse context\n"); + ParseContext::Statement stmt(parseContext_, StatementKind::Block); + ParseContext::Scope currentScope(cx_, parseContext_, usedNames_); + TRY(currentScope.init(parseContext_)); + build: | + TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, parseContext_)); + TRY_DECL(result, factory_.newLexicalScope(*bindings, statements)); + fprintf(stderr, "Block: POP parse context\n"); + +BreakStatement: + fields: + label: + block: + replace: | + RootedAtom label(cx_); + MOZ_TRY(readMaybeString(&label)); + + if (label && !IsIdentifier(label)) + return raiseError("Invalid identifier"); + build: | + if (label) { + auto validity = parseContext_->checkBreakStatement(label->asPropertyName()); + + if (validity.isErr()) { + switch (validity.unwrapErr()) { + case ParseContext::BreakStatementError::ToughBreak: + return raiseError(kind, "Not in a loop"); + case ParseContext::BreakStatementError::LabelNotFound: + return raiseError(kind, "Label not found"); + } + } + } + TRY_DECL(result, factory_.newBreakStatement(label ? label->asPropertyName() : nullptr, tokenizer_->pos(start))); + +CallExpression: + build: | + auto op = JSOP_CALL; + // Check for direct calls to `eval`. + if (factory_.isEvalName(callee, cx_)) { + if (!parseContext_->varScope().lookupDeclaredNameForAdd(callee->name()) + && !parseContext_->innermostScope()->lookupDeclaredNameForAdd(callee->name())) { + // This is a direct call to `eval`. + if (!parseContext_->sc()->hasDirectEval()) + return raiseMissingDirectEvalInAssertedScope(); + + op = parseContext_->sc()->strict() ? JSOP_STRICTEVAL : JSOP_EVAL; + } + } + auto result = arguments; + result->setKind(ParseNodeKind::Call); + result->prepend(callee); + result->setOp(op); + + +CatchClause: + init: | + ParseContext::Statement stmt(parseContext_, StatementKind::Catch); + ParseContext::Scope currentScope(cx_, parseContext_, usedNames_); + TRY(currentScope.init(parseContext_)); + build: | + // Export implicit variables to the scope. + // FIXME: Handle cases other than Name. + MOZ_ASSERT(binding->isKind(ParseNodeKind::Name)); + auto ptr = currentScope.lookupDeclaredNameForAdd(binding->name()); + TRY(currentScope.addDeclaredName(parseContext_, ptr, binding->name(), DeclarationKind::Let, start)); + + TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, parseContext_)); + TRY_DECL(result, factory_.newLexicalScope(*bindings, body)); + TRY(factory_.setupCatchScope(result, binding, body)); + +CompoundAssignmentExpression: + build: | + ParseNodeKind pnk; + switch (operator_){ + case CompoundAssignmentOperator::PlusAssign: + pnk = ParseNodeKind::AddAssign; + break; + case CompoundAssignmentOperator::MinusAssign: + pnk = ParseNodeKind::SubAssign; + break; + case CompoundAssignmentOperator::MulAssign: + pnk = ParseNodeKind::MulAssign; + break; + case CompoundAssignmentOperator::DivAssign: + pnk = ParseNodeKind::DivAssign; + break; + case CompoundAssignmentOperator::ModAssign: + pnk = ParseNodeKind::ModAssign; + break; + case CompoundAssignmentOperator::PowAssign: + pnk = ParseNodeKind::PowAssign; + break; + case CompoundAssignmentOperator::LshAssign: + pnk = ParseNodeKind::LshAssign; + break; + case CompoundAssignmentOperator::RshAssign: + pnk = ParseNodeKind::RshAssign; + break; + case CompoundAssignmentOperator::UrshAssign: + pnk = ParseNodeKind::UrshAssign; + break; + case CompoundAssignmentOperator::BitOrAssign: + pnk = ParseNodeKind::BitOrAssign; + break; + case CompoundAssignmentOperator::BitXorAssign: + pnk = ParseNodeKind::BitXorAssign; + break; + case CompoundAssignmentOperator::BitAndAssign: + pnk = ParseNodeKind::BitAndAssign; + break; + } + TRY_DECL(result, factory_.newAssignment(pnk, binding, expression)); + +ComputedMemberAssignmentTarget: + build: | + TRY_DECL(result, factory_.newPropertyByValue(object, expression, start)); + +ComputedMemberExpression: + build: | + TRY_DECL(result, factory_.newPropertyByValue(object, expression, start)); + +ConditionalExpression: + build: | + TRY_DECL(result, factory_.newConditional(test, consequent, alternate)); + +ContinueStatement: + fields: + label: + block: + replace: | + RootedAtom label(cx_); + MOZ_TRY(readMaybeString(&label)); + + if (label && !IsIdentifier(label)) + return raiseError("ContinueStatement - Label MUST be an identifier"); + build: | + if (label) { + auto validity = parseContext_->checkContinueStatement(label ? label->asPropertyName() : nullptr); + if (validity.isErr()) { + switch (validity.unwrapErr()) { + case ParseContext::ContinueStatementError::NotInALoop: + return raiseError(kind, "Not in a loop"); + case ParseContext::ContinueStatementError::LabelNotFound: + return raiseError(kind, "Label not found"); + } + } + } + + TRY_DECL(result, factory_.newContinueStatement(label ? label->asPropertyName() : nullptr, tokenizer_->pos(start))); + +DataProperty: + build: | + if (!factory_.isUsableAsObjectPropertyName(name)) + return raiseError("DataProperty key kind"); + + TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, expression, AccessorType::None)); + +Directive: + build: | + TokenPos pos = tokenizer_->pos(start); + TRY_DECL(result, factory_.newStringLiteral(rawValue, pos)); + +DoWhileStatement: + init: + ParseContext::Statement stmt(parseContext_, StatementKind::DoLoop); + build: + TRY_DECL(result, factory_.newDoWhileStatement(body, test, tokenizer_->pos(start))); + +EmptyStatement: + build: + TRY_DECL(result, factory_.newEmptyStatement(tokenizer_->pos(start))); + +ExpressionStatement: + build: + TRY_DECL(result, factory_.newExprStatement(expression, tokenizer_->offset())); + +ForInOfBinding: + init: + AutoVariableDeclarationKind kindGuard(this); + build: | + // Restored by `kindGuard`. + variableDeclarationKind_ = kind_; + MOZ_TRY(checkBinding(binding->pn_atom->asPropertyName())); + auto pnk = + kind_ == VariableDeclarationKind::Let + ? ParseNodeKind::Let + : ParseNodeKind::Var; + TRY_DECL(result, factory_.newDeclarationList(pnk, tokenizer_->pos(start))); + factory_.addList(result, binding); + + + +ForInStatement: + init: | + ParseContext::Statement stmt(parseContext_, StatementKind::ForInLoop); + + // Implicit scope around the `for`, used to store `for (let x in ...)` + // or `for (const x in ...)`-style declarations. Detail on the + // declaration is stored as part of `scope`. + ParseContext::Scope scope(cx_, parseContext_, usedNames_); + TRY(scope.init(parseContext_)); + build: | + TRY_DECL(forHead, factory_.newForInOrOfHead(ParseNodeKind::ForIn, left, right, tokenizer_->pos(start))); + TRY_DECL(result, factory_.newForStatement(start, forHead, body, /*flags*/ 0)); + + if (!scope.isEmpty()) { + TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, parseContext_)); + TRY_VAR(result, factory_.newLexicalScope(*bindings, result)); + } + +FormalParameters: + build: | + auto result = items; + if (rest) { + TRY_DECL(spread, factory_.newSpread(start, rest)); + factory_.addList(result, spread); + } + +ForStatement: + init: | + ParseContext::Statement stmt(parseContext_, StatementKind::ForLoop); + + // Implicit scope around the `for`, used to store `for (let x; ...; ...)` + // or `for (const x; ...; ...)`-style declarations. Detail on the + // declaration is stored as part of `BINJS_Scope`. + ParseContext::Scope scope(cx_, parseContext_, usedNames_); + TRY(scope.init(parseContext_)); + build: | + TRY_DECL(forHead, factory_.newForHead(init, test, update, tokenizer_->pos(start))); + TRY_DECL(result, factory_.newForStatement(start, forHead, body, /* iflags = */ 0)); + + if (!scope.isEmpty()) { + TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, parseContext_)); + TRY_VAR(result, factory_.newLexicalScope(*bindings, result)); + } + +FunctionBody: + build: | + MOZ_TRY_DECL(result, appendDirectivesToBody(/* body = */ statements, /* directives = */ directives)); + +FunctionDeclaration: + inherits: FunctionExpression + +FunctionExpression: + fields: + parameterScope: + before: | + MOZ_TRY_DECL(funbox, buildFunctionBox( + isGenerator ? GeneratorKind::Generator + : GeneratorKind::NotGenerator, + isAsync ? FunctionAsyncKind::AsyncFunction + : FunctionAsyncKind::SyncFunction)); + + // Push a new ParseContext. It will be used to parse `scope`, the arguments, the function. + BinParseContext funpc(cx_, this, funbox, /* newDirectives = */ nullptr); + TRY(funpc.init()); + parseContext_->functionScope().useAsVarScope(parseContext_); + MOZ_ASSERT(parseContext_->isFunctionBox()); + + ParseContext::Scope lexicalScope(cx_, parseContext_, usedNames_); + TRY(lexicalScope.init(parseContext_)); + build: | + TRY_DECL(lexicalScopeData, NewLexicalScopeData(cx_, lexicalScope, alloc_, parseContext_)); + TRY_VAR(body, factory_.newLexicalScope(*lexicalScopeData, body)); + MOZ_TRY_DECL(result, buildFunction(start, kind, name, params, body, funbox)); + +IdentifierExpression: + build: | + if (!IsIdentifier(name)) + return raiseError("Invalid identifier"); + TRY_DECL(result, factory_.newName(name->asPropertyName(), tokenizer_->pos(start), cx_)); + +IfStatement: + build: | + TRY_DECL(result, factory_.newIfStatement(start, test, consequent, alternate)); + +LabelledStatement: + fields: + label: + after: | + if (!IsIdentifier(label)) + return raiseError("Invalid identifier"); + ParseContext::LabelStatement stmt(parseContext_, label); + build: + TRY_DECL(result, factory_.newLabeledStatement(label->asPropertyName(), body, start)); + +ListOfDirective: + init: + TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start))); + append: + factory_.addStatementToList(result, item); + +ListOfObjectProperty: + init: + TRY_DECL(result, factory_.newObjectLiteral(start)); + +ListOfOptionalSpreadElementOrExpression: + init: + TRY_DECL(result, factory_.newArrayLiteral(start)); + append: | + if (item) + factory_.addArrayElement(result, item); // Infallible. + else + TRY(factory_.addElision(result, tokenizer_->pos(start))); + +ListOfParameter: + init: | + ParseNode* result = new_(ParseNodeKind::ParamsBody, tokenizer_->pos(start)); + append: + factory_.addList(/* list = */ result, /* item = */ item); + +ListOfStatement: + init: + TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start))); + append: + factory_.addStatementToList(result, item); + + +#ListOfSpreadElementOrExpression: +# init: +# ParseNode* result = new_(ParseNodeKind::ParamsBody, tokenizer_->pos()); +# append: +# result->appendWithoutOrderAssumption(item); + +ListOfSwitchCase: + init: + TRY_DECL(result, factory_.newStatementList(tokenizer_->pos(start))); + append: + factory_.addCaseStatementToList(result, item); + +ListOfVariableDeclarator: + init: | + TRY_DECL(result, factory_.newDeclarationList(ParseNodeKind::Const /*Placeholder*/, + tokenizer_->pos(start))); + +LiteralBooleanExpression: + build: + TRY_DECL(result, factory_.newBooleanLiteral(value, tokenizer_->pos(start))); + +LiteralNumericExpression: + build: + TRY_DECL(result, factory_.newNumber(value, DecimalPoint::HasDecimal, tokenizer_->pos(start))); + +LiteralNullExpression: + build: + TRY_DECL(result, factory_.newNullLiteral(tokenizer_->pos(start))); + +LiteralPropertyName: + build: | + ParseNode* result; + uint32_t index; + if (value->isIndex(&index)) + TRY_VAR(result, factory_.newNumber(index, NoDecimal, TokenPos(start, tokenizer_->offset()))); + else + TRY_VAR(result, factory_.newObjectLiteralPropertyName(value, tokenizer_->pos(start))); + +LiteralRegExpExpression: + fields: + flags: + block: + replace: + Chars flags(cx_); + MOZ_TRY(readString(flags)); + build: | + RegExpFlag reflags = NoFlags; + for (auto 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 raiseInvalidEnum("RegExpLiteral", flags); + } + + + Rooted reobj(cx_); + TRY_VAR(reobj, RegExpObject::create(cx_, + pattern, + reflags, + alloc_, + TenuredObject)); + + TRY_DECL(result, factory_.newRegExp(reobj, tokenizer_->pos(start), *this)); + +LiteralStringExpression: + build: + TRY_DECL(result, factory_.newStringLiteral(value, tokenizer_->pos(start))); + +Method: + inherits: FunctionExpression + build: | + MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body, funbox)); + TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, method, AccessorType::None)); + +NewExpression: + build: | + auto result = arguments; + result->setKind(ParseNodeKind::New); + result->prepend(callee); + +ObjectExpression: + build: + auto result = properties; + +OptionalAssertedBlockScope: + type-ok: + Ok + +OptionalAssertedVarScope: + type-ok: + Ok + +OptionalAssertedParameterScope: + type-ok: + Ok + +ReturnStatement: + init: | + if (!parseContext_->isFunctionBox()) { + // Return statements are permitted only inside functions. + return raiseInvalidKind("Toplevel Statement", kind); + } + + parseContext_->functionBox()->usesReturn = true; + build: + TRY_DECL(result, factory_.newReturnStatement(expression, tokenizer_->pos(start))); + +Script: + build: + MOZ_TRY_DECL(result, appendDirectivesToBody(/* body = */ statements, /* directives = */ directives)); + +Setter: + inherits: Method + init: | + const auto isAsync = false; + const auto isGenerator = false; + build: | + TRY_DECL(params, factory_.newList(ParseNodeKind::ParamsBody, param)); + MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body, funbox)); + TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, method, AccessorType::Setter)); + +ShorthandProperty: + build: | + if (!factory_.isUsableAsObjectPropertyName(name)) + TRY_VAR(name, factory_.newObjectLiteralPropertyName(name->name(), tokenizer_->pos(start))); + + TRY_DECL(result, factory_.newObjectMethodOrPropertyDefinition(name, name, AccessorType::None)); + +SwitchCase: + build: | + TRY_DECL(result, factory_.newCaseOrDefault(start, test, consequent)); + +SwitchDefault: + build: | + TRY_DECL(result, factory_.newCaseOrDefault(start, nullptr, consequent)); + +SwitchStatement: + build: | + TRY_DECL(scope, factory_.newLexicalScope(nullptr, cases)); + TRY_DECL(result, factory_.newSwitchStatement(start, discriminant, scope)); + +SwitchStatementWithDefault: + build: | + // Concatenate `preDefaultCase`, `defaultCase`, `postDefaultCase` + auto cases = preDefaultCases; + factory_.addList(cases, defaultCase); + ParseNode* iter = postDefaultCases->pn_head; + while (iter) { + ParseNode* next = iter->pn_next; + factory_.addList(cases, iter); + iter = next; + } + TRY_DECL(scope, factory_.newLexicalScope(nullptr, cases)); + TRY_DECL(result, factory_.newSwitchStatement(start, discriminant, scope)); + +StaticMemberAssignmentTarget: + build: | + TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), start)); + +StaticMemberExpression: + build: | + TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), start)); + +ThisExpression: + build: | + if (parseContext_->isFunctionBox()) + parseContext_->functionBox()->usesThis = true; + + TokenPos pos = tokenizer_->pos(start); + ParseNode* thisName(nullptr); + if (parseContext_->sc()->thisBinding() == ThisBinding::Function) + TRY_VAR(thisName, factory_.newName(cx_->names().dotThis, pos, cx_)); + + TRY_DECL(result, factory_.newThisLiteral(pos, thisName)); + +ThrowStatement: + build: + TRY_DECL(result, factory_.newThrowStatement(expression, tokenizer_->pos(start))); + +TryCatchStatement: + fields: + body: + block: + declare: + ParseNode* body; + before: | + ParseContext::Statement stmt(parseContext_, StatementKind::Try); + ParseContext::Scope scope(cx_, parseContext_, usedNames_); + TRY(scope.init(parseContext_)); + build: + TRY_DECL(result, factory_.newTryStatement(start, body, catchClause, /* finally = */ nullptr)); + +TryFinallyStatement: + fields: + body: + block: + declare: + ParseNode* body; + before: | + ParseContext::Statement stmt(parseContext_, StatementKind::Try); + ParseContext::Scope scope(cx_, parseContext_, usedNames_); + TRY(scope.init(parseContext_)); + finalizer: + block: + declare: + ParseNode* finalizer; + before: | + ParseContext::Statement stmt(parseContext_, StatementKind::Finally); + ParseContext::Scope scope(cx_, parseContext_, usedNames_); + TRY(scope.init(parseContext_)); + build: + TRY_DECL(result, factory_.newTryStatement(start, body, catchClause, finalizer)); + +UnaryExpression: + build: | + ParseNodeKind pnk; + switch (operator_) { + case UnaryOperator::Minus: + pnk = ParseNodeKind::Neg; + break; + case UnaryOperator::Plus: + pnk = ParseNodeKind::Pos; + break; + case UnaryOperator::Not: + pnk = ParseNodeKind::Not; + break; + case UnaryOperator::BitNot: + pnk = ParseNodeKind::BitNot; + break; + case UnaryOperator::Typeof: { + if (operand->isKind(ParseNodeKind::Name)) + pnk = ParseNodeKind::TypeOfName; + else + pnk = ParseNodeKind::TypeOfExpr; + break; + } + case UnaryOperator::Void: + pnk = ParseNodeKind::Void; + break; + case UnaryOperator::Delete: { + switch (operand->getKind()) { + case ParseNodeKind::Name: + operand->setOp(JSOP_DELNAME); + pnk = ParseNodeKind::DeleteName; + break; + case ParseNodeKind::Dot: + pnk = ParseNodeKind::DeleteProp; + break; + case ParseNodeKind::Elem: + pnk = ParseNodeKind::DeleteElem; + break; + default: + pnk = ParseNodeKind::DeleteExpr; + } + break; + } + } + TRY_DECL(result, factory_.newUnary(pnk, start, operand)); + +UpdateExpression: + build: | + ParseNodeKind pnk; + switch (operator_) { + case UpdateOperator::Incr: + pnk = isPrefix ? ParseNodeKind::PreIncrement + : ParseNodeKind::PostIncrement; + break; + case UpdateOperator::Decr: + pnk = isPrefix ? ParseNodeKind::PreDecrement + : ParseNodeKind::PostDecrement; + break; + } + TRY_DECL(result, factory_.newUnary(pnk, start, operand)); + +VariableDeclaration: + init: + AutoVariableDeclarationKind kindGuard(this); + + fields: + kind: + after: | + // Restored by `kindGuard`. + variableDeclarationKind_ = kind_; + + build: | + // By specification, the list may not be empty. + if (declarators->pn_count == 0) + return raiseEmpty("VariableDeclaration"); + + ParseNodeKind pnk; + switch (kind_) { + case VariableDeclarationKind::Var: + pnk = ParseNodeKind::Var; + break; + case VariableDeclarationKind::Let: + pnk = ParseNodeKind::Let; + break; + case VariableDeclarationKind::Const: + pnk = ParseNodeKind::Const; + break; + } + declarators->setKind(pnk); + auto result = declarators; + +VariableDeclarator: + build: | + ParseNode* result; + if (binding->isKind(ParseNodeKind::Name)) { + // `var foo [= bar]`` + MOZ_TRY(checkBinding(binding->pn_atom->asPropertyName())); + + TRY_VAR(result, factory_.newName(binding->pn_atom->asPropertyName(), tokenizer_->pos(start), cx_)); + if (init) + result->pn_expr = init; + } else { + // `var pattern = bar` + if (!init) { + // Here, `init` is required. + return raiseMissingField("VariableDeclarator (with non-trivial pattern)", BinField::Init); + } + + MOZ_CRASH("Unimplemented: AssertedScope check for BindingPattern variable declaration"); + TRY_VAR(result, factory_.newAssignment(ParseNodeKind::Assign, binding, init)); + } + +WhileStatement: + init: + ParseContext::Statement stmt(parseContext_, StatementKind::WhileLoop); + build: + TRY_DECL(result, factory_.newWhileStatement(start, test, body)); + +WithStatement: + build: + TRY_DECL(result, factory_.newWithStatement(start, object, body)); diff --git a/js/src/frontend/BinToken.h b/js/src/frontend/BinToken.h index e5e487439145..29037976dc97 100644 --- a/js/src/frontend/BinToken.h +++ b/js/src/frontend/BinToken.h @@ -1,12 +1,20 @@ +// This file was autogenerated by binjs_generate_spidermonkey, +// please DO NOT EDIT BY HAND. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// To generate this file, see the documentation in +// js/src/frontend/binsource/README.md. + #ifndef frontend_BinToken_h #define frontend_BinToken_h +#include + /** * Definition of Binary AST tokens. * @@ -18,32 +26,25 @@ * - a Value, which may be either a node or a primitive value. * * The mapping between Kind and list of fields is determined entirely by - * the grammar of Binary AST. The mapping between (Kind, Name) and the structure - * of Value is also determined entirely by the grammar of Binary AST. + * the grammar of Binary AST. The mapping between (Kind, Name) and the + * structure of Value is also determined entirely by the grammar of + * Binary AST. * - * As per the specifications of Binary AST, kinds may be added as the language - * grows, but never removed. The mapping between Kind and list of fields may - * also change to add new fields or make some fields optional, but may never - * remove a field. Finally, the mapping between (Kind, Name) and the structure - * of Value may be modified to add new possible values, but never to remove a - * value. + * As per the specifications of Binary AST, kinds may be added as the + * language grows, but never removed. The mapping between Kind and list + * of fields may also change to add new fields or make some fields optional, + * but may never remove a field. Finally, the mapping between (Kind, Name) + * and the structure of Value may be modified to add new possible values, + * but never to remove a value. * * A Binary AST parser must be able to fail gracefully when confronted with * unknown Kinds or Names. - * - * At the time of this writing, the Binary AST defined from the Babylon AST - * (see https://github.com/babel/babylon/blob/master/ast/spec.md) restricted - * to ES5, with a few amendments to store additional scoping data and to - * represent the empty AST. - * - * Future versions of the Binary AST will progressively grow to encompass ES6 - * and beyond. */ namespace js { namespace frontend { - /** +/** * The different kinds of Binary AST nodes, as per the specifications of * Binary AST. * @@ -60,80 +61,188 @@ namespace frontend { * (sorted by alphabetical order) */ #define FOR_EACH_BIN_KIND(F) \ + F(Arguments, Arguments) \ + F(ArrayAssignmentTarget, ArrayAssignmentTarget) \ + F(ArrayBinding, ArrayBinding) \ F(ArrayExpression, ArrayExpression) \ + F(ArrowExpression, ArrowExpression) \ + F(AssertedBlockScope, AssertedBlockScope) \ + F(AssertedParameterScope, AssertedParameterScope) \ + F(AssertedVarScope, AssertedVarScope) \ F(AssignmentExpression, AssignmentExpression) \ - F(AssignmentOperator, AssignmentOperator) \ + F(AssignmentTarget, AssignmentTarget) \ + F(AssignmentTargetIdentifier, AssignmentTargetIdentifier) \ + F(AssignmentTargetOrAssignmentTargetWithInitializer, AssignmentTargetOrAssignmentTargetWithInitializer) \ + F(AssignmentTargetPattern, AssignmentTargetPattern) \ + F(AssignmentTargetProperty, AssignmentTargetProperty) \ + F(AssignmentTargetPropertyIdentifier, AssignmentTargetPropertyIdentifier) \ + F(AssignmentTargetPropertyProperty, AssignmentTargetPropertyProperty) \ + F(AssignmentTargetWithInitializer, AssignmentTargetWithInitializer) \ + F(AwaitExpression, AwaitExpression) \ F(BinaryExpression, BinaryExpression) \ F(BinaryOperator, BinaryOperator) \ - F(BINJS_Scope, BINJS:Scope) \ - F(BlockStatement, BlockStatement) \ - F(BooleanLiteral, BooleanLiteral) \ - F(BracketExpression, BracketExpression) \ + F(Binding, Binding) \ + F(BindingIdentifier, BindingIdentifier) \ + F(BindingOrBindingWithInitializer, BindingOrBindingWithInitializer) \ + F(BindingPattern, BindingPattern) \ + F(BindingProperty, BindingProperty) \ + F(BindingPropertyIdentifier, BindingPropertyIdentifier) \ + F(BindingPropertyProperty, BindingPropertyProperty) \ + F(BindingWithInitializer, BindingWithInitializer) \ + F(Block, Block) \ F(BreakStatement, BreakStatement) \ F(CallExpression, CallExpression) \ F(CatchClause, CatchClause) \ + F(ClassDeclaration, ClassDeclaration) \ + F(ClassElement, ClassElement) \ + F(ClassExpression, ClassExpression) \ + F(CompoundAssignmentExpression, CompoundAssignmentExpression) \ + F(CompoundAssignmentOperator, CompoundAssignmentOperator) \ + F(ComputedMemberAssignmentTarget, ComputedMemberAssignmentTarget) \ + F(ComputedMemberExpression, ComputedMemberExpression) \ F(ComputedPropertyName, ComputedPropertyName) \ F(ConditionalExpression, ConditionalExpression) \ F(ContinueStatement, ContinueStatement) \ + F(DataProperty, DataProperty) \ F(DebuggerStatement, DebuggerStatement) \ - F(Declaration, Declaration) \ F(Directive, Directive) \ - F(DirectiveLiteral, DirectiveLiteral) \ - F(DotExpression, DotExpression) \ F(DoWhileStatement, DoWhileStatement) \ - F(Elision, Elision) \ F(EmptyStatement, EmptyStatement) \ + F(Export, Export) \ + F(ExportAllFrom, ExportAllFrom) \ + F(ExportDeclaration, ExportDeclaration) \ + F(ExportDefault, ExportDefault) \ + F(ExportFrom, ExportFrom) \ + F(ExportFromSpecifier, ExportFromSpecifier) \ + F(ExportLocalSpecifier, ExportLocalSpecifier) \ + F(ExportLocals, ExportLocals) \ F(Expression, Expression) \ + F(ExpressionOrSuper, ExpressionOrSuper) \ + F(ExpressionOrTemplateElement, ExpressionOrTemplateElement) \ F(ExpressionStatement, ExpressionStatement) \ - F(ForStatement, ForStatement) \ + F(ForInOfBinding, ForInOfBinding) \ + F(ForInOfBindingOrAssignmentTarget, ForInOfBindingOrAssignmentTarget) \ F(ForInStatement, ForInStatement) \ - F(FunctionExpression, FunctionExpression) \ + F(ForOfStatement, ForOfStatement) \ + F(ForStatement, ForStatement) \ + F(FormalParameters, FormalParameters) \ + F(FunctionBody, FunctionBody) \ + F(FunctionBodyOrExpression, FunctionBodyOrExpression) \ F(FunctionDeclaration, FunctionDeclaration) \ + F(FunctionDeclarationOrClassDeclarationOrExpression, FunctionDeclarationOrClassDeclarationOrExpression) \ + F(FunctionDeclarationOrClassDeclarationOrVariableDeclaration, FunctionDeclarationOrClassDeclarationOrVariableDeclaration) \ + F(FunctionExpression, FunctionExpression) \ + F(Getter, Getter) \ F(Identifier, Identifier) \ + F(IdentifierExpression, IdentifierExpression) \ + F(IdentifierName, IdentifierName) \ F(IfStatement, IfStatement) \ - F(LabeledStatement, LabeledStatement) \ + F(Import, Import) \ + F(ImportDeclaration, ImportDeclaration) \ + F(ImportDeclarationOrExportDeclarationOrStatement, ImportDeclarationOrExportDeclarationOrStatement) \ + F(ImportNamespace, ImportNamespace) \ + F(ImportSpecifier, ImportSpecifier) \ + F(IterationStatement, IterationStatement) \ + F(Label, Label) \ + F(LabelledStatement, LabelledStatement) \ + F(ListOfAssignmentTargetOrAssignmentTargetWithInitializer, ListOfAssignmentTargetOrAssignmentTargetWithInitializer) \ + F(ListOfAssignmentTargetProperty, ListOfAssignmentTargetProperty) \ + F(ListOfBindingProperty, ListOfBindingProperty) \ + F(ListOfClassElement, ListOfClassElement) \ + F(ListOfDirective, ListOfDirective) \ + F(ListOfExportFromSpecifier, ListOfExportFromSpecifier) \ + F(ListOfExportLocalSpecifier, ListOfExportLocalSpecifier) \ + F(ListOfExpressionOrTemplateElement, ListOfExpressionOrTemplateElement) \ + F(ListOfIdentifierName, ListOfIdentifierName) \ + F(ListOfImportDeclarationOrExportDeclarationOrStatement, ListOfImportDeclarationOrExportDeclarationOrStatement) \ + F(ListOfImportSpecifier, ListOfImportSpecifier) \ + F(ListOfObjectProperty, ListOfObjectProperty) \ + F(ListOfOptionalBindingOrBindingWithInitializer, ListOfOptionalBindingOrBindingWithInitializer) \ + F(ListOfOptionalSpreadElementOrExpression, ListOfOptionalSpreadElementOrExpression) \ + F(ListOfParameter, ListOfParameter) \ + F(ListOfStatement, ListOfStatement) \ + F(ListOfSwitchCase, ListOfSwitchCase) \ + F(ListOfVariableDeclarator, ListOfVariableDeclarator) \ F(Literal, Literal) \ - F(LogicalExpression, LogicalExpression) \ - F(LogicalOperator, LogicalOperator) \ + F(LiteralBooleanExpression, LiteralBooleanExpression) \ + F(LiteralInfinityExpression, LiteralInfinityExpression) \ + F(LiteralNullExpression, LiteralNullExpression) \ + F(LiteralNumericExpression, LiteralNumericExpression) \ + F(LiteralPropertyName, LiteralPropertyName) \ + F(LiteralRegExpExpression, LiteralRegExpExpression) \ + F(LiteralStringExpression, LiteralStringExpression) \ + F(Method, Method) \ + F(MethodDefinition, MethodDefinition) \ + F(Module, Module) \ F(NewExpression, NewExpression) \ - F(NullLiteral, NullLiteral) \ - F(NumericLiteral, NumericLiteral) \ + F(NewTargetExpression, NewTargetExpression) \ + F(ObjectAssignmentTarget, ObjectAssignmentTarget) \ + F(ObjectBinding, ObjectBinding) \ F(ObjectExpression, ObjectExpression) \ - F(ObjectGetter, ObjectGetter) \ - F(ObjectMethod, ObjectMethod) \ - F(ObjectSetter, ObjectSetter) \ F(ObjectProperty, ObjectProperty) \ - F(Pattern, Pattern) \ + F(OptionalAssertedBlockScope, OptionalAssertedBlockScope) \ + F(OptionalAssertedParameterScope, OptionalAssertedParameterScope) \ + F(OptionalAssertedVarScope, OptionalAssertedVarScope) \ + F(OptionalAssignmentTarget, OptionalAssignmentTarget) \ + F(OptionalBinding, OptionalBinding) \ + F(OptionalBindingIdentifier, OptionalBindingIdentifier) \ + F(OptionalBindingOrBindingWithInitializer, OptionalBindingOrBindingWithInitializer) \ + F(OptionalCatchClause, OptionalCatchClause) \ + F(OptionalExpression, OptionalExpression) \ + F(OptionalIdentifierName, OptionalIdentifierName) \ + F(OptionalLabel, OptionalLabel) \ + F(OptionalSpreadElementOrExpression, OptionalSpreadElementOrExpression) \ + F(OptionalStatement, OptionalStatement) \ + F(OptionalVariableDeclarationOrExpression, OptionalVariableDeclarationOrExpression) \ + F(Parameter, Parameter) \ F(Program, Program) \ - F(PropertyKind, PropertyKind) \ - F(RegExpLiteral, RegExpLiteral) \ + F(PropertyName, PropertyName) \ F(ReturnStatement, ReturnStatement) \ - F(SequenceExpression, SequenceExpression) \ - F(StringLiteral, StringLiteral) \ + F(Script, Script) \ + F(Setter, Setter) \ + F(ShorthandProperty, ShorthandProperty) \ + F(SimpleAssignmentTarget, SimpleAssignmentTarget) \ + F(SpreadElement, SpreadElement) \ + F(SpreadElementOrExpression, SpreadElementOrExpression) \ F(Statement, Statement) \ + F(StaticMemberAssignmentTarget, StaticMemberAssignmentTarget) \ + F(StaticMemberExpression, StaticMemberExpression) \ + F(Super, Super) \ F(SwitchCase, SwitchCase) \ + F(SwitchDefault, SwitchDefault) \ F(SwitchStatement, SwitchStatement) \ + F(SwitchStatementWithDefault, SwitchStatementWithDefault) \ + F(TemplateElement, TemplateElement) \ + F(TemplateExpression, TemplateExpression) \ F(ThisExpression, ThisExpression) \ F(ThrowStatement, ThrowStatement) \ - F(TryStatement, TryStatement) \ + F(TryCatchStatement, TryCatchStatement) \ + F(TryFinallyStatement, TryFinallyStatement) \ F(UnaryExpression, UnaryExpression) \ F(UnaryOperator, UnaryOperator) \ F(UpdateExpression, UpdateExpression) \ F(UpdateOperator, UpdateOperator) \ F(VariableDeclaration, VariableDeclaration) \ + F(VariableDeclarationKind, VariableDeclarationKind) \ + F(VariableDeclarationOrExpression, VariableDeclarationOrExpression) \ F(VariableDeclarator, VariableDeclarator) \ - F(VariableKind, VariableKind) \ F(WhileStatement, WhileStatement) \ - F(WithStatement, WithStatement) + F(WithStatement, WithStatement) \ + F(YieldExpression, YieldExpression) \ + F(YieldStarExpression, YieldStarExpression) \ + F(_Null, _Null) \ + F(string, string) + enum class BinKind { #define EMIT_ENUM(name, _) name, FOR_EACH_BIN_KIND(EMIT_ENUM) #undef EMIT_ENUM - BINKIND_LIMIT /* domain size */ }; -const char* describeBinKind(const BinKind& kind); +// The number of distinct values of BinKind. +const size_t BINKIND_LIMIT = 171; + /** * The different fields of Binary AST nodes, as per the specifications of @@ -148,60 +257,91 @@ const char* describeBinKind(const BinKind& kind); * * (sorted by alphabetical order) */ - #define FOR_EACH_BIN_FIELD(F) \ +#define FOR_EACH_BIN_FIELD(F) \ F(Alternate, alternate) \ - F(Argument, argument) \ F(Arguments, arguments) \ - F(BINJS_CapturedNames, BINJS:CapturedNames) \ - F(BINJS_ConstDeclaredNames, BINJS:ConstDeclaredNames) \ - F(BINJS_HasDirectEval, BINJS:HasDirectEval) \ - F(BINJS_LetDeclaredNames, BINJS:LetDeclaredNames) \ - F(BINJS_VarDeclaredNames, BINJS:VarDeclaredNames) \ - F(BINJS_Scope, BINJS:Scope) \ - F(Block, block) \ - F(Callee, callee) \ - F(Cases, cases) \ - F(Consequent, consequent) \ + F(Binding, binding) \ F(Body, body) \ - F(Declarations, declarations) \ + F(BodyScope, bodyScope) \ + F(Callee, callee) \ + F(CapturedNames, capturedNames) \ + F(Cases, cases) \ + F(CatchClause, catchClause) \ + F(Consequent, consequent) \ + F(Declaration, declaration) \ + F(Declarators, declarators) \ + F(DefaultBinding, defaultBinding) \ + F(DefaultCase, defaultCase) \ F(Directives, directives) \ F(Discriminant, discriminant) \ F(Elements, elements) \ + F(ExportedName, exportedName) \ F(Expression, expression) \ - F(Expressions, expressions) \ F(Finalizer, finalizer) \ F(Flags, flags) \ - F(Handler, handler) \ - F(Id, id) \ + F(HasDirectEval, hasDirectEval) \ F(Init, init) \ - F(Key, key) \ + F(IsAsync, isAsync) \ + F(IsGenerator, isGenerator) \ + F(IsPrefix, isPrefix) \ + F(IsStatic, isStatic) \ + F(Items, items) \ F(Kind, kind) \ F(Label, label) \ F(Left, left) \ + F(LexicallyDeclaredNames, lexicallyDeclaredNames) \ + F(Method, method) \ + F(ModuleSpecifier, moduleSpecifier) \ F(Name, name) \ + F(NamedExports, namedExports) \ + F(NamedImports, namedImports) \ + F(NamespaceBinding, namespaceBinding) \ F(Object, object) \ + F(Operand, operand) \ F(Operator, operator) \ F(Param, param) \ + F(ParameterNames, parameterNames) \ + F(ParameterScope, parameterScope) \ F(Params, params) \ F(Pattern, pattern) \ - F(Prefix, prefix) \ + F(PostDefaultCases, postDefaultCases) \ + F(PreDefaultCases, preDefaultCases) \ F(Properties, properties) \ F(Property, property) \ + F(RawValue, rawValue) \ + F(Rest, rest) \ F(Right, right) \ + F(Scope, scope) \ + F(Statements, statements) \ + F(Super, super) \ + F(Tag, tag) \ F(Test, test) \ F(Update, update) \ - F(Value, value) + F(Value, value) \ + F(VarDeclaredNames, varDeclaredNames) + enum class BinField { #define EMIT_ENUM(name, _) name, FOR_EACH_BIN_FIELD(EMIT_ENUM) #undef EMIT_ENUM - BINFIELD_LIMIT /* domain size */ }; +// The number of distinct values of BinField. +const size_t BINFIELD_LIMIT = 61; + +/** + * Return a string describing a `BinKind`. + */ +const char* describeBinKind(const BinKind& kind); + +/** + * Return a string describing a `BinField`. + */ const char* describeBinField(const BinField& kind); } // namespace frontend } // namespace js #endif // frontend_BinToken_h + diff --git a/js/src/moz.build b/js/src/moz.build index 4e781db82165..05e2e3d4b965 100755 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -706,6 +706,7 @@ if CONFIG['JS_BUILD_BINAST']: SOURCES += ['frontend/BinTokenReaderTester.cpp'] # These parts of BinAST should eventually move to release. SOURCES += [ + 'frontend/BinSource-auto.cpp', 'frontend/BinSource.cpp', 'frontend/BinToken.cpp' ]