#include "frontend/BinASTParser.h"
#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/BinAST-macros.h"
#include "frontend/BinASTTokenReaderMultipart.h"
#include "frontend/FullParseHandler.h"
#include "frontend/ParseNode.h"
#include "frontend/Parser.h"
#include "frontend/SharedContext.h"
#include "vm/RegExpObject.h"
#include "frontend/ParseContext-inl.h"
namespace js {
namespace frontend {
template <typename Tok, size_t N>
bool operator==(const typename Tok::Chars& left, const char (&right)[N]) {
return Tok::equals(left, right);
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseAssertedMaybePositionalParameterName(
AssertedScopeKind scopeKind,
MutableHandle<GCVector<JSAtom*>> positionalParams) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
BINJS_MOZ_TRY_DECL(result,
parseSumAssertedMaybePositionalParameterName(
start, kind, fields, scopeKind, positionalParams));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseSumAssertedMaybePositionalParameterName(
const size_t start, const BinASTKind kind, const BinASTFields& fields,
AssertedScopeKind scopeKind,
MutableHandle<GCVector<JSAtom*>> positionalParams) {
Ok result;
switch (kind) {
case BinASTKind::AssertedParameterName:
return raiseError(
"FIXME: Not implemented yet in this preview release "
"(AssertedParameterName)");
case BinASTKind::AssertedPositionalParameterName:
MOZ_TRY_VAR(result,
parseInterfaceAssertedPositionalParameterName(
start, kind, fields, scopeKind, positionalParams));
break;
case BinASTKind::AssertedRestParameterName:
return raiseError(
"FIXME: Not implemented yet in this preview release "
"(AssertedRestParameterName)");
default:
return raiseInvalidKind("AssertedMaybePositionalParameterName", kind);
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseAssignmentTarget() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
BINJS_MOZ_TRY_DECL(result, parseSumAssignmentTarget(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseSumAssignmentTarget(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
ParseNode* result;
switch (kind) {
case BinASTKind::ArrayAssignmentTarget:
MOZ_TRY_VAR(result,
parseInterfaceArrayAssignmentTarget(start, kind, fields));
break;
case BinASTKind::AssignmentTargetIdentifier:
MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind,
fields));
break;
case BinASTKind::ComputedMemberAssignmentTarget:
MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(
start, kind, fields));
break;
case BinASTKind::ObjectAssignmentTarget:
MOZ_TRY_VAR(result,
parseInterfaceObjectAssignmentTarget(start, kind, fields));
break;
case BinASTKind::StaticMemberAssignmentTarget:
MOZ_TRY_VAR(result, parseInterfaceStaticMemberAssignmentTarget(
start, kind, fields));
break;
default:
return raiseInvalidKind("AssignmentTarget", kind);
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseBinding() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
BINJS_MOZ_TRY_DECL(result, parseSumBinding(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseSumBinding(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
ParseNode* result;
switch (kind) {
case BinASTKind::ArrayBinding:
MOZ_TRY_VAR(result, parseInterfaceArrayBinding(start, kind, fields));
break;
case BinASTKind::BindingIdentifier:
MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields));
break;
case BinASTKind::ObjectBinding:
MOZ_TRY_VAR(result, parseInterfaceObjectBinding(start, kind, fields));
break;
default:
return raiseInvalidKind("Binding", kind);
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseExpression() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
BINJS_MOZ_TRY_DECL(result, parseSumExpression(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseSumExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
ParseNode* result;
switch (kind) {
case BinASTKind::ArrayExpression:
MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
break;
case BinASTKind::AssignmentExpression:
MOZ_TRY_VAR(result,
parseInterfaceAssignmentExpression(start, kind, fields));
break;
case BinASTKind::AwaitExpression:
MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields));
break;
case BinASTKind::BinaryExpression:
MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields));
break;
case BinASTKind::CallExpression:
MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields));
break;
case BinASTKind::ClassExpression:
MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields));
break;
case BinASTKind::CompoundAssignmentExpression:
MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(
start, kind, fields));
break;
case BinASTKind::ComputedMemberExpression:
MOZ_TRY_VAR(result,
parseInterfaceComputedMemberExpression(start, kind, fields));
break;
case BinASTKind::ConditionalExpression:
MOZ_TRY_VAR(result,
parseInterfaceConditionalExpression(start, kind, fields));
break;
case BinASTKind::EagerArrowExpressionWithExpression:
MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(
start, kind, fields));
break;
case BinASTKind::EagerArrowExpressionWithFunctionBody:
MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(
start, kind, fields));
break;
case BinASTKind::EagerFunctionExpression:
MOZ_TRY_VAR(result,
parseInterfaceEagerFunctionExpression(start, kind, fields));
break;
case BinASTKind::IdentifierExpression:
MOZ_TRY_VAR(result,
parseInterfaceIdentifierExpression(start, kind, fields));
break;
case BinASTKind::LazyArrowExpressionWithExpression:
MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(
start, kind, fields));
break;
case BinASTKind::LazyArrowExpressionWithFunctionBody:
MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(
start, kind, fields));
break;
case BinASTKind::LazyFunctionExpression:
MOZ_TRY_VAR(result,
parseInterfaceLazyFunctionExpression(start, kind, fields));
break;
case BinASTKind::LiteralBooleanExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralBooleanExpression(start, kind, fields));
break;
case BinASTKind::LiteralInfinityExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralInfinityExpression(start, kind, fields));
break;
case BinASTKind::LiteralNullExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralNullExpression(start, kind, fields));
break;
case BinASTKind::LiteralNumericExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralNumericExpression(start, kind, fields));
break;
case BinASTKind::LiteralRegExpExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralRegExpExpression(start, kind, fields));
break;
case BinASTKind::LiteralStringExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralStringExpression(start, kind, fields));
break;
case BinASTKind::NewExpression:
MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
break;
case BinASTKind::NewTargetExpression:
MOZ_TRY_VAR(result,
parseInterfaceNewTargetExpression(start, kind, fields));
break;
case BinASTKind::ObjectExpression:
MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
break;
case BinASTKind::StaticMemberExpression:
MOZ_TRY_VAR(result,
parseInterfaceStaticMemberExpression(start, kind, fields));
break;
case BinASTKind::TemplateExpression:
MOZ_TRY_VAR(result,
parseInterfaceTemplateExpression(start, kind, fields));
break;
case BinASTKind::ThisExpression:
MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
break;
case BinASTKind::UnaryExpression:
MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields));
break;
case BinASTKind::UpdateExpression:
MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields));
break;
case BinASTKind::YieldExpression:
MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields));
break;
case BinASTKind::YieldStarExpression:
MOZ_TRY_VAR(result,
parseInterfaceYieldStarExpression(start, kind, fields));
break;
default:
return raiseInvalidKind("Expression", kind);
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseExpressionOrSuper() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
BINJS_MOZ_TRY_DECL(result, parseSumExpressionOrSuper(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseSumExpressionOrSuper(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
ParseNode* result;
switch (kind) {
case BinASTKind::ArrayExpression:
MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
break;
case BinASTKind::AssignmentExpression:
MOZ_TRY_VAR(result,
parseInterfaceAssignmentExpression(start, kind, fields));
break;
case BinASTKind::AwaitExpression:
MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields));
break;
case BinASTKind::BinaryExpression:
MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields));
break;
case BinASTKind::CallExpression:
MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields));
break;
case BinASTKind::ClassExpression:
MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields));
break;
case BinASTKind::CompoundAssignmentExpression:
MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(
start, kind, fields));
break;
case BinASTKind::ComputedMemberExpression:
MOZ_TRY_VAR(result,
parseInterfaceComputedMemberExpression(start, kind, fields));
break;
case BinASTKind::ConditionalExpression:
MOZ_TRY_VAR(result,
parseInterfaceConditionalExpression(start, kind, fields));
break;
case BinASTKind::EagerArrowExpressionWithExpression:
MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(
start, kind, fields));
break;
case BinASTKind::EagerArrowExpressionWithFunctionBody:
MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(
start, kind, fields));
break;
case BinASTKind::EagerFunctionExpression:
MOZ_TRY_VAR(result,
parseInterfaceEagerFunctionExpression(start, kind, fields));
break;
case BinASTKind::IdentifierExpression:
MOZ_TRY_VAR(result,
parseInterfaceIdentifierExpression(start, kind, fields));
break;
case BinASTKind::LazyArrowExpressionWithExpression:
MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(
start, kind, fields));
break;
case BinASTKind::LazyArrowExpressionWithFunctionBody:
MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(
start, kind, fields));
break;
case BinASTKind::LazyFunctionExpression:
MOZ_TRY_VAR(result,
parseInterfaceLazyFunctionExpression(start, kind, fields));
break;
case BinASTKind::LiteralBooleanExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralBooleanExpression(start, kind, fields));
break;
case BinASTKind::LiteralInfinityExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralInfinityExpression(start, kind, fields));
break;
case BinASTKind::LiteralNullExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralNullExpression(start, kind, fields));
break;
case BinASTKind::LiteralNumericExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralNumericExpression(start, kind, fields));
break;
case BinASTKind::LiteralRegExpExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralRegExpExpression(start, kind, fields));
break;
case BinASTKind::LiteralStringExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralStringExpression(start, kind, fields));
break;
case BinASTKind::NewExpression:
MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
break;
case BinASTKind::NewTargetExpression:
MOZ_TRY_VAR(result,
parseInterfaceNewTargetExpression(start, kind, fields));
break;
case BinASTKind::ObjectExpression:
MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
break;
case BinASTKind::StaticMemberExpression:
MOZ_TRY_VAR(result,
parseInterfaceStaticMemberExpression(start, kind, fields));
break;
case BinASTKind::Super:
MOZ_TRY_VAR(result, parseInterfaceSuper(start, kind, fields));
break;
case BinASTKind::TemplateExpression:
MOZ_TRY_VAR(result,
parseInterfaceTemplateExpression(start, kind, fields));
break;
case BinASTKind::ThisExpression:
MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
break;
case BinASTKind::UnaryExpression:
MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields));
break;
case BinASTKind::UpdateExpression:
MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields));
break;
case BinASTKind::YieldExpression:
MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields));
break;
case BinASTKind::YieldStarExpression:
MOZ_TRY_VAR(result,
parseInterfaceYieldStarExpression(start, kind, fields));
break;
default:
return raiseInvalidKind("ExpressionOrSuper", kind);
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseForInOfBindingOrAssignmentTarget() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
BINJS_MOZ_TRY_DECL(
result, parseSumForInOfBindingOrAssignmentTarget(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumForInOfBindingOrAssignmentTarget(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
ParseNode* result;
switch (kind) {
case BinASTKind::ArrayAssignmentTarget:
MOZ_TRY_VAR(result,
parseInterfaceArrayAssignmentTarget(start, kind, fields));
break;
case BinASTKind::AssignmentTargetIdentifier:
MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind,
fields));
break;
case BinASTKind::ComputedMemberAssignmentTarget:
MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(
start, kind, fields));
break;
case BinASTKind::ForInOfBinding:
MOZ_TRY_VAR(result, parseInterfaceForInOfBinding(start, kind, fields));
break;
case BinASTKind::ObjectAssignmentTarget:
MOZ_TRY_VAR(result,
parseInterfaceObjectAssignmentTarget(start, kind, fields));
break;
case BinASTKind::StaticMemberAssignmentTarget:
MOZ_TRY_VAR(result, parseInterfaceStaticMemberAssignmentTarget(
start, kind, fields));
break;
default:
return raiseInvalidKind("ForInOfBindingOrAssignmentTarget", kind);
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseObjectProperty() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
BINJS_MOZ_TRY_DECL(result, parseSumObjectProperty(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseSumObjectProperty(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
ParseNode* result;
switch (kind) {
case BinASTKind::DataProperty:
MOZ_TRY_VAR(result, parseInterfaceDataProperty(start, kind, fields));
break;
case BinASTKind::EagerGetter:
MOZ_TRY_VAR(result, parseInterfaceEagerGetter(start, kind, fields));
break;
case BinASTKind::EagerMethod:
MOZ_TRY_VAR(result, parseInterfaceEagerMethod(start, kind, fields));
break;
case BinASTKind::EagerSetter:
MOZ_TRY_VAR(result, parseInterfaceEagerSetter(start, kind, fields));
break;
case BinASTKind::LazyGetter:
MOZ_TRY_VAR(result, parseInterfaceLazyGetter(start, kind, fields));
break;
case BinASTKind::LazyMethod:
MOZ_TRY_VAR(result, parseInterfaceLazyMethod(start, kind, fields));
break;
case BinASTKind::LazySetter:
MOZ_TRY_VAR(result, parseInterfaceLazySetter(start, kind, fields));
break;
case BinASTKind::ShorthandProperty:
MOZ_TRY_VAR(result, parseInterfaceShorthandProperty(start, kind, fields));
break;
default:
return raiseInvalidKind("ObjectProperty", kind);
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseParameter() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
BINJS_MOZ_TRY_DECL(result, parseSumParameter(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseSumParameter(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
ParseNode* result;
switch (kind) {
case BinASTKind::ArrayBinding:
MOZ_TRY_VAR(result, parseInterfaceArrayBinding(start, kind, fields));
break;
case BinASTKind::BindingIdentifier:
MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields));
if (!pc_->positionalFormalParameterNames().append(
result->template as<NameNode>().atom())) {
return raiseOOM();
}
if (pc_->isFunctionBox()) {
pc_->functionBox()->length++;
}
break;
case BinASTKind::BindingWithInitializer:
MOZ_TRY_VAR(result,
parseInterfaceBindingWithInitializer(start, kind, fields));
break;
case BinASTKind::ObjectBinding:
MOZ_TRY_VAR(result, parseInterfaceObjectBinding(start, kind, fields));
break;
default:
return raiseInvalidKind("Parameter", kind);
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseProgram() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
BINJS_MOZ_TRY_DECL(result, parseSumProgram(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseSumProgram(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
ParseNode* result;
switch (kind) {
case BinASTKind::Module:
MOZ_TRY_VAR(result, parseInterfaceModule(start, kind, fields));
break;
case BinASTKind::Script:
MOZ_TRY_VAR(result, parseInterfaceScript(start, kind, fields));
break;
default:
return raiseInvalidKind("Program", kind);
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parsePropertyName() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
BINJS_MOZ_TRY_DECL(result, parseSumPropertyName(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseSumPropertyName(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
ParseNode* result;
switch (kind) {
case BinASTKind::ComputedPropertyName:
MOZ_TRY_VAR(result,
parseInterfaceComputedPropertyName(start, kind, fields));
break;
case BinASTKind::LiteralPropertyName:
MOZ_TRY_VAR(result,
parseInterfaceLiteralPropertyName(start, kind, fields));
break;
default:
return raiseInvalidKind("PropertyName", kind);
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseSimpleAssignmentTarget() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
BINJS_MOZ_TRY_DECL(result,
parseSumSimpleAssignmentTarget(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseSumSimpleAssignmentTarget(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
ParseNode* result;
switch (kind) {
case BinASTKind::AssignmentTargetIdentifier:
MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(start, kind,
fields));
break;
case BinASTKind::ComputedMemberAssignmentTarget:
MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(
start, kind, fields));
break;
case BinASTKind::StaticMemberAssignmentTarget:
MOZ_TRY_VAR(result, parseInterfaceStaticMemberAssignmentTarget(
start, kind, fields));
break;
default:
return raiseInvalidKind("SimpleAssignmentTarget", kind);
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseSpreadElementOrExpression() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
BINJS_MOZ_TRY_DECL(result,
parseSumSpreadElementOrExpression(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseSumSpreadElementOrExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
ParseNode* result;
switch (kind) {
case BinASTKind::ArrayExpression:
MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
break;
case BinASTKind::AssignmentExpression:
MOZ_TRY_VAR(result,
parseInterfaceAssignmentExpression(start, kind, fields));
break;
case BinASTKind::AwaitExpression:
MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields));
break;
case BinASTKind::BinaryExpression:
MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields));
break;
case BinASTKind::CallExpression:
MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields));
break;
case BinASTKind::ClassExpression:
MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields));
break;
case BinASTKind::CompoundAssignmentExpression:
MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(
start, kind, fields));
break;
case BinASTKind::ComputedMemberExpression:
MOZ_TRY_VAR(result,
parseInterfaceComputedMemberExpression(start, kind, fields));
break;
case BinASTKind::ConditionalExpression:
MOZ_TRY_VAR(result,
parseInterfaceConditionalExpression(start, kind, fields));
break;
case BinASTKind::EagerArrowExpressionWithExpression:
MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(
start, kind, fields));
break;
case BinASTKind::EagerArrowExpressionWithFunctionBody:
MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(
start, kind, fields));
break;
case BinASTKind::EagerFunctionExpression:
MOZ_TRY_VAR(result,
parseInterfaceEagerFunctionExpression(start, kind, fields));
break;
case BinASTKind::IdentifierExpression:
MOZ_TRY_VAR(result,
parseInterfaceIdentifierExpression(start, kind, fields));
break;
case BinASTKind::LazyArrowExpressionWithExpression:
MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(
start, kind, fields));
break;
case BinASTKind::LazyArrowExpressionWithFunctionBody:
MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(
start, kind, fields));
break;
case BinASTKind::LazyFunctionExpression:
MOZ_TRY_VAR(result,
parseInterfaceLazyFunctionExpression(start, kind, fields));
break;
case BinASTKind::LiteralBooleanExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralBooleanExpression(start, kind, fields));
break;
case BinASTKind::LiteralInfinityExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralInfinityExpression(start, kind, fields));
break;
case BinASTKind::LiteralNullExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralNullExpression(start, kind, fields));
break;
case BinASTKind::LiteralNumericExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralNumericExpression(start, kind, fields));
break;
case BinASTKind::LiteralRegExpExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralRegExpExpression(start, kind, fields));
break;
case BinASTKind::LiteralStringExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralStringExpression(start, kind, fields));
break;
case BinASTKind::NewExpression:
MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
break;
case BinASTKind::NewTargetExpression:
MOZ_TRY_VAR(result,
parseInterfaceNewTargetExpression(start, kind, fields));
break;
case BinASTKind::ObjectExpression:
MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
break;
case BinASTKind::SpreadElement:
MOZ_TRY_VAR(result, parseInterfaceSpreadElement(start, kind, fields));
break;
case BinASTKind::StaticMemberExpression:
MOZ_TRY_VAR(result,
parseInterfaceStaticMemberExpression(start, kind, fields));
break;
case BinASTKind::TemplateExpression:
MOZ_TRY_VAR(result,
parseInterfaceTemplateExpression(start, kind, fields));
break;
case BinASTKind::ThisExpression:
MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
break;
case BinASTKind::UnaryExpression:
MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields));
break;
case BinASTKind::UpdateExpression:
MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields));
break;
case BinASTKind::YieldExpression:
MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields));
break;
case BinASTKind::YieldStarExpression:
MOZ_TRY_VAR(result,
parseInterfaceYieldStarExpression(start, kind, fields));
break;
default:
return raiseInvalidKind("SpreadElementOrExpression", kind);
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseStatement() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
BINJS_MOZ_TRY_DECL(result, parseSumStatement(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseSumStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
ParseNode* result;
switch (kind) {
case BinASTKind::Block:
MOZ_TRY_VAR(result, parseInterfaceBlock(start, kind, fields));
break;
case BinASTKind::BreakStatement:
MOZ_TRY_VAR(result, parseInterfaceBreakStatement(start, kind, fields));
break;
case BinASTKind::ClassDeclaration:
MOZ_TRY_VAR(result, parseInterfaceClassDeclaration(start, kind, fields));
break;
case BinASTKind::ContinueStatement:
MOZ_TRY_VAR(result, parseInterfaceContinueStatement(start, kind, fields));
break;
case BinASTKind::DebuggerStatement:
MOZ_TRY_VAR(result, parseInterfaceDebuggerStatement(start, kind, fields));
break;
case BinASTKind::DoWhileStatement:
MOZ_TRY_VAR(result, parseInterfaceDoWhileStatement(start, kind, fields));
break;
case BinASTKind::EagerFunctionDeclaration:
MOZ_TRY_VAR(result,
parseInterfaceEagerFunctionDeclaration(start, kind, fields));
break;
case BinASTKind::EmptyStatement:
MOZ_TRY_VAR(result, parseInterfaceEmptyStatement(start, kind, fields));
break;
case BinASTKind::ExpressionStatement:
MOZ_TRY_VAR(result,
parseInterfaceExpressionStatement(start, kind, fields));
break;
case BinASTKind::ForInStatement:
MOZ_TRY_VAR(result, parseInterfaceForInStatement(start, kind, fields));
break;
case BinASTKind::ForOfStatement:
MOZ_TRY_VAR(result, parseInterfaceForOfStatement(start, kind, fields));
break;
case BinASTKind::ForStatement:
MOZ_TRY_VAR(result, parseInterfaceForStatement(start, kind, fields));
break;
case BinASTKind::IfStatement:
MOZ_TRY_VAR(result, parseInterfaceIfStatement(start, kind, fields));
break;
case BinASTKind::LabelledStatement:
MOZ_TRY_VAR(result, parseInterfaceLabelledStatement(start, kind, fields));
break;
case BinASTKind::LazyFunctionDeclaration:
MOZ_TRY_VAR(result,
parseInterfaceLazyFunctionDeclaration(start, kind, fields));
break;
case BinASTKind::ReturnStatement:
MOZ_TRY_VAR(result, parseInterfaceReturnStatement(start, kind, fields));
break;
case BinASTKind::SwitchStatement:
MOZ_TRY_VAR(result, parseInterfaceSwitchStatement(start, kind, fields));
break;
case BinASTKind::SwitchStatementWithDefault:
MOZ_TRY_VAR(result, parseInterfaceSwitchStatementWithDefault(start, kind,
fields));
break;
case BinASTKind::ThrowStatement:
MOZ_TRY_VAR(result, parseInterfaceThrowStatement(start, kind, fields));
break;
case BinASTKind::TryCatchStatement:
MOZ_TRY_VAR(result, parseInterfaceTryCatchStatement(start, kind, fields));
break;
case BinASTKind::TryFinallyStatement:
MOZ_TRY_VAR(result,
parseInterfaceTryFinallyStatement(start, kind, fields));
break;
case BinASTKind::VariableDeclaration:
MOZ_TRY_VAR(result,
parseInterfaceVariableDeclaration(start, kind, fields));
break;
case BinASTKind::WhileStatement:
MOZ_TRY_VAR(result, parseInterfaceWhileStatement(start, kind, fields));
break;
case BinASTKind::WithStatement:
MOZ_TRY_VAR(result, parseInterfaceWithStatement(start, kind, fields));
break;
default:
return raiseInvalidKind("Statement", kind);
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseSumVariableDeclarationOrExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
ParseNode* result;
switch (kind) {
case BinASTKind::ArrayExpression:
MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields));
break;
case BinASTKind::AssignmentExpression:
MOZ_TRY_VAR(result,
parseInterfaceAssignmentExpression(start, kind, fields));
break;
case BinASTKind::AwaitExpression:
MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields));
break;
case BinASTKind::BinaryExpression:
MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields));
break;
case BinASTKind::CallExpression:
MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields));
break;
case BinASTKind::ClassExpression:
MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields));
break;
case BinASTKind::CompoundAssignmentExpression:
MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(
start, kind, fields));
break;
case BinASTKind::ComputedMemberExpression:
MOZ_TRY_VAR(result,
parseInterfaceComputedMemberExpression(start, kind, fields));
break;
case BinASTKind::ConditionalExpression:
MOZ_TRY_VAR(result,
parseInterfaceConditionalExpression(start, kind, fields));
break;
case BinASTKind::EagerArrowExpressionWithExpression:
MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(
start, kind, fields));
break;
case BinASTKind::EagerArrowExpressionWithFunctionBody:
MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(
start, kind, fields));
break;
case BinASTKind::EagerFunctionExpression:
MOZ_TRY_VAR(result,
parseInterfaceEagerFunctionExpression(start, kind, fields));
break;
case BinASTKind::IdentifierExpression:
MOZ_TRY_VAR(result,
parseInterfaceIdentifierExpression(start, kind, fields));
break;
case BinASTKind::LazyArrowExpressionWithExpression:
MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(
start, kind, fields));
break;
case BinASTKind::LazyArrowExpressionWithFunctionBody:
MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(
start, kind, fields));
break;
case BinASTKind::LazyFunctionExpression:
MOZ_TRY_VAR(result,
parseInterfaceLazyFunctionExpression(start, kind, fields));
break;
case BinASTKind::LiteralBooleanExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralBooleanExpression(start, kind, fields));
break;
case BinASTKind::LiteralInfinityExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralInfinityExpression(start, kind, fields));
break;
case BinASTKind::LiteralNullExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralNullExpression(start, kind, fields));
break;
case BinASTKind::LiteralNumericExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralNumericExpression(start, kind, fields));
break;
case BinASTKind::LiteralRegExpExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralRegExpExpression(start, kind, fields));
break;
case BinASTKind::LiteralStringExpression:
MOZ_TRY_VAR(result,
parseInterfaceLiteralStringExpression(start, kind, fields));
break;
case BinASTKind::NewExpression:
MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields));
break;
case BinASTKind::NewTargetExpression:
MOZ_TRY_VAR(result,
parseInterfaceNewTargetExpression(start, kind, fields));
break;
case BinASTKind::ObjectExpression:
MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields));
break;
case BinASTKind::StaticMemberExpression:
MOZ_TRY_VAR(result,
parseInterfaceStaticMemberExpression(start, kind, fields));
break;
case BinASTKind::TemplateExpression:
MOZ_TRY_VAR(result,
parseInterfaceTemplateExpression(start, kind, fields));
break;
case BinASTKind::ThisExpression:
MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields));
break;
case BinASTKind::UnaryExpression:
MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields));
break;
case BinASTKind::UpdateExpression:
MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields));
break;
case BinASTKind::VariableDeclaration:
MOZ_TRY_VAR(result,
parseInterfaceVariableDeclaration(start, kind, fields));
break;
case BinASTKind::YieldExpression:
MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields));
break;
case BinASTKind::YieldStarExpression:
MOZ_TRY_VAR(result,
parseInterfaceYieldStarExpression(start, kind, fields));
break;
default:
return raiseInvalidKind("VariableDeclarationOrExpression", kind);
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceArrayAssignmentTarget(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release "
"(ArrayAssignmentTarget)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceArrayBinding(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release (ArrayBinding)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceArrayExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::ArrayExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Elements};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(elements, parseListOfOptionalSpreadElementOrExpression());
if (elements->empty()) {
elements->setHasNonConstInitializer();
}
auto result = elements;
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseAssertedBlockScope() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::AssertedBlockScope) {
return raiseInvalidKind("AssertedBlockScope", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result,
parseInterfaceAssertedBlockScope(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedBlockScope(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::AssertedBlockScope);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::DeclaredNames,
BinASTField::HasDirectEval};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif const auto scopeKind = AssertedScopeKind::Block;
MOZ_TRY(parseListOfAssertedDeclaredName(scopeKind));
BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
if (hasDirectEval) {
pc_->sc()->setHasDirectEval();
pc_->sc()->setBindingsAccessedDynamically();
}
if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
pc_->functionBox()->setHasExtensibleScope();
}
auto result = Ok();
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseAssertedBoundName(
AssertedScopeKind scopeKind) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::AssertedBoundName) {
return raiseInvalidKind("AssertedBoundName", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(
result, parseInterfaceAssertedBoundName(start, kind, fields, scopeKind));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedBoundName(
const size_t start, const BinASTKind kind, const BinASTFields& fields,
AssertedScopeKind scopeKind) {
MOZ_ASSERT(kind == BinASTKind::AssertedBoundName);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Name,
BinASTField::IsCaptured};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif const bool allowDuplicateName = false;
RootedAtom name(cx_);
MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());
BINJS_MOZ_TRY_DECL(isCaptured, tokenizer_->readBool());
ParseContext::Scope* scope;
DeclarationKind declKind;
MOZ_TRY(getBoundScope(scopeKind, scope, declKind));
MOZ_TRY(addScopeName(scopeKind, name, scope, declKind, isCaptured,
allowDuplicateName));
auto result = Ok();
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseAssertedBoundNamesScope() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::AssertedBoundNamesScope) {
return raiseInvalidKind("AssertedBoundNamesScope", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(
result, parseInterfaceAssertedBoundNamesScope(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedBoundNamesScope(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::AssertedBoundNamesScope);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::BoundNames,
BinASTField::HasDirectEval};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif const auto scopeKind = AssertedScopeKind::Catch;
MOZ_TRY(parseListOfAssertedBoundName(scopeKind));
BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
if (hasDirectEval) {
pc_->sc()->setHasDirectEval();
pc_->sc()->setBindingsAccessedDynamically();
}
if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
pc_->functionBox()->setHasExtensibleScope();
}
auto result = Ok();
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseAssertedDeclaredName(
AssertedScopeKind scopeKind) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::AssertedDeclaredName) {
return raiseInvalidKind("AssertedDeclaredName", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedDeclaredName(
start, kind, fields, scopeKind));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedDeclaredName(
const size_t start, const BinASTKind kind, const BinASTFields& fields,
AssertedScopeKind scopeKind) {
MOZ_ASSERT(kind == BinASTKind::AssertedDeclaredName);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[3] = {BinASTField::Name, BinASTField::Kind,
BinASTField::IsCaptured};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif const bool allowDuplicateName = false;
RootedAtom name(cx_);
MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());
BINJS_MOZ_TRY_DECL(kind_, parseAssertedDeclaredKind());
if (kind_ == AssertedDeclaredKind::NonConstLexical) {
return raiseError("Let is not supported in this preview release");
}
if (kind_ == AssertedDeclaredKind::ConstLexical) {
return raiseError("Const is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(isCaptured, tokenizer_->readBool());
ParseContext::Scope* scope;
DeclarationKind declKind;
MOZ_TRY(getDeclaredScope(scopeKind, kind_, scope, declKind));
MOZ_TRY(addScopeName(scopeKind, name, scope, declKind, isCaptured,
allowDuplicateName));
auto result = Ok();
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseAssertedParameterScope(
MutableHandle<GCVector<JSAtom*>> positionalParams) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::AssertedParameterScope) {
return raiseInvalidKind("AssertedParameterScope", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedParameterScope(
start, kind, fields, positionalParams));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedParameterScope(
const size_t start, const BinASTKind kind, const BinASTFields& fields,
MutableHandle<GCVector<JSAtom*>> positionalParams) {
MOZ_ASSERT(kind == BinASTKind::AssertedParameterScope);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[3] = {BinASTField::ParamNames,
BinASTField::HasDirectEval,
BinASTField::IsSimpleParameterList};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif const auto scopeKind = AssertedScopeKind::Parameter;
MOZ_TRY(parseListOfAssertedMaybePositionalParameterName(scopeKind,
positionalParams));
BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
if (hasDirectEval) {
pc_->sc()->setHasDirectEval();
pc_->sc()->setBindingsAccessedDynamically();
}
BINJS_MOZ_TRY_DECL(isSimpleParameterList, tokenizer_->readBool());
(void)isSimpleParameterList;
if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
pc_->functionBox()->setHasExtensibleScope();
}
auto result = Ok();
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedPositionalParameterName(
const size_t start, const BinASTKind kind, const BinASTFields& fields,
AssertedScopeKind scopeKind,
MutableHandle<GCVector<JSAtom*>> positionalParams) {
MOZ_ASSERT(kind == BinASTKind::AssertedPositionalParameterName);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[3] = {BinASTField::Index, BinASTField::Name,
BinASTField::IsCaptured};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif bool allowDuplicateName = !pc_->sc()->strict();
BINJS_MOZ_TRY_DECL(index, tokenizer_->readUnsignedLong());
RootedAtom name(cx_);
MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());
size_t prevLength = positionalParams.get().length();
if (index >= prevLength) {
if (index >= ARGNO_LIMIT - 1) {
return raiseError("AssertedPositionalParameterName.index is too big");
}
size_t newLength = index + 1;
BINJS_TRY(positionalParams.get().resize(newLength));
for (uint32_t i = prevLength; i < newLength; i++) {
positionalParams.get()[i] = nullptr;
}
}
if (positionalParams.get()[index]) {
return raiseError(
"AssertedPositionalParameterName has duplicate entry for the same "
"index");
}
positionalParams.get()[index] = name;
BINJS_MOZ_TRY_DECL(isCaptured, tokenizer_->readBool());
ParseContext::Scope* scope;
DeclarationKind declKind;
MOZ_TRY(getBoundScope(scopeKind, scope, declKind));
MOZ_TRY(addScopeName(scopeKind, name, scope, declKind, isCaptured,
allowDuplicateName));
auto result = Ok();
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseAssertedScriptGlobalScope() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::AssertedScriptGlobalScope) {
return raiseInvalidKind("AssertedScriptGlobalScope", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(
result, parseInterfaceAssertedScriptGlobalScope(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedScriptGlobalScope(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::AssertedScriptGlobalScope);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::DeclaredNames,
BinASTField::HasDirectEval};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif const auto scopeKind = AssertedScopeKind::Global;
MOZ_TRY(parseListOfAssertedDeclaredName(scopeKind));
BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
if (hasDirectEval) {
pc_->sc()->setHasDirectEval();
pc_->sc()->setBindingsAccessedDynamically();
}
if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
pc_->functionBox()->setHasExtensibleScope();
}
auto result = Ok();
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseAssertedVarScope() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::AssertedVarScope) {
return raiseInvalidKind("AssertedVarScope", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result,
parseInterfaceAssertedVarScope(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedVarScope(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::AssertedVarScope);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::DeclaredNames,
BinASTField::HasDirectEval};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif const auto scopeKind = AssertedScopeKind::Var;
MOZ_TRY(parseListOfAssertedDeclaredName(scopeKind));
BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool());
if (hasDirectEval) {
pc_->sc()->setHasDirectEval();
pc_->sc()->setBindingsAccessedDynamically();
}
if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
pc_->functionBox()->setHasExtensibleScope();
}
auto result = Ok();
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceAssignmentExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::AssignmentExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Binding,
BinASTField::Expression};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(binding, parseAssignmentTarget());
BINJS_MOZ_TRY_DECL(expression, parseExpression());
BINJS_TRY_DECL(result, handler_.newAssignment(ParseNodeKind::AssignExpr,
binding, expression));
return result;
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceAssignmentTargetIdentifier(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::AssignmentTargetIdentifier);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Name};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
RootedAtom name(cx_);
MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());
BINJS_TRY(usedNames_.noteUse(cx_, name, pc_->scriptId(),
pc_->innermostScope()->id()));
BINJS_TRY_DECL(result, handler_.newName(name->asPropertyName(),
tokenizer_->pos(start), cx_));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceAwaitExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release (AwaitExpression)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceBinaryExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::BinaryExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::Operator, BinASTField::Left, BinASTField::Right};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(operator_, parseBinaryOperator());
BINJS_MOZ_TRY_DECL(left, parseExpression());
BINJS_MOZ_TRY_DECL(right, parseExpression());
ParseNodeKind pnk;
switch (operator_) {
case BinaryOperator::Comma:
pnk = ParseNodeKind::CommaExpr;
break;
case BinaryOperator::LogicalOr:
pnk = ParseNodeKind::OrExpr;
break;
case BinaryOperator::LogicalAnd:
pnk = ParseNodeKind::AndExpr;
break;
case BinaryOperator::BitOr:
pnk = ParseNodeKind::BitOrExpr;
break;
case BinaryOperator::BitXor:
pnk = ParseNodeKind::BitXorExpr;
break;
case BinaryOperator::BitAnd:
pnk = ParseNodeKind::BitAndExpr;
break;
case BinaryOperator::Eq:
pnk = ParseNodeKind::EqExpr;
break;
case BinaryOperator::Neq:
pnk = ParseNodeKind::NeExpr;
break;
case BinaryOperator::StrictEq:
pnk = ParseNodeKind::StrictEqExpr;
break;
case BinaryOperator::StrictNeq:
pnk = ParseNodeKind::StrictNeExpr;
break;
case BinaryOperator::LessThan:
pnk = ParseNodeKind::LtExpr;
break;
case BinaryOperator::LeqThan:
pnk = ParseNodeKind::LeExpr;
break;
case BinaryOperator::GreaterThan:
pnk = ParseNodeKind::GtExpr;
break;
case BinaryOperator::GeqThan:
pnk = ParseNodeKind::GeExpr;
break;
case BinaryOperator::In:
pnk = ParseNodeKind::InExpr;
break;
case BinaryOperator::Instanceof:
pnk = ParseNodeKind::InstanceOfExpr;
break;
case BinaryOperator::Lsh:
pnk = ParseNodeKind::LshExpr;
break;
case BinaryOperator::Rsh:
pnk = ParseNodeKind::RshExpr;
break;
case BinaryOperator::Ursh:
pnk = ParseNodeKind::UrshExpr;
break;
case BinaryOperator::Plus:
pnk = ParseNodeKind::AddExpr;
break;
case BinaryOperator::Minus:
pnk = ParseNodeKind::SubExpr;
break;
case BinaryOperator::Mul:
pnk = ParseNodeKind::MulExpr;
break;
case BinaryOperator::Div:
pnk = ParseNodeKind::DivExpr;
break;
case BinaryOperator::Mod:
pnk = ParseNodeKind::ModExpr;
break;
case BinaryOperator::Pow:
pnk = ParseNodeKind::PowExpr;
break;
}
ParseNode* result;
if (left->isKind(pnk) && pnk != ParseNodeKind::PowExpr) {
left->template as<ListNode>().appendWithoutOrderAssumption(right);
result = left;
} else {
BINJS_TRY_DECL(list, handler_.newList(pnk, tokenizer_->pos(start)));
list->appendWithoutOrderAssumption(left);
list->appendWithoutOrderAssumption(right);
result = list;
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseBindingIdentifier() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::BindingIdentifier) {
return raiseInvalidKind("BindingIdentifier", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result,
parseInterfaceBindingIdentifier(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceBindingIdentifier(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::BindingIdentifier);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Name};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
RootedAtom name(cx_);
MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());
BINJS_TRY_DECL(result, handler_.newName(name->asPropertyName(),
tokenizer_->pos(start), cx_));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceBindingWithInitializer(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release "
"(BindingWithInitializer)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseBlock() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::Block) {
return raiseInvalidKind("Block", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result, parseInterfaceBlock(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceBlock(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::Block);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Scope,
BinASTField::Statements};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif ParseContext::Statement stmt(pc_, StatementKind::Block);
ParseContext::Scope currentScope(cx_, pc_, usedNames_);
BINJS_TRY(currentScope.init(pc_));
MOZ_TRY(parseAssertedBlockScope());
BINJS_MOZ_TRY_DECL(statements, parseListOfStatement());
MOZ_TRY(checkClosedVars(currentScope));
BINJS_TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, pc_));
BINJS_TRY_DECL(result, handler_.newLexicalScope(*bindings, statements));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceBreakStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::BreakStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Label};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif RootedAtom label(cx_);
MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom());
if (label) {
if (!IsIdentifier(label)) {
return raiseError("Invalid identifier");
}
}
auto validity =
pc_->checkBreakStatement(label ? label->asPropertyName() : nullptr);
if (validity.isErr()) {
switch (validity.unwrapErr()) {
case ParseContext::BreakStatementError::ToughBreak:
this->error(JSMSG_TOUGH_BREAK);
return cx_->alreadyReportedError();
case ParseContext::BreakStatementError::LabelNotFound:
this->error(JSMSG_LABEL_NOT_FOUND);
return cx_->alreadyReportedError();
}
}
BINJS_TRY_DECL(result, handler_.newBreakStatement(
label ? label->asPropertyName() : nullptr,
tokenizer_->pos(start)));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceCallExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::CallExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Callee,
BinASTField::Arguments};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(callee, parseExpressionOrSuper());
BINJS_MOZ_TRY_DECL(arguments, parseArguments());
auto op = JSOP_CALL;
if (PropertyName* prop = handler_.maybeDottedProperty(callee)) {
if (prop == cx_->names().apply) {
op = JSOP_FUNAPPLY;
if (pc_->isFunctionBox()) {
pc_->functionBox()->usesApply = true;
}
} else if (prop == cx_->names().call) {
op = JSOP_FUNCALL;
}
}
if (handler_.isEvalName(callee, cx_)) {
if (!pc_->varScope().lookupDeclaredNameForAdd(cx_->names().eval) &&
!pc_->innermostScope()->lookupDeclaredNameForAdd(cx_->names().eval)) {
if (!pc_->sc()->hasDirectEval()) {
return raiseMissingDirectEvalInAssertedScope();
}
op = pc_->sc()->strict() ? JSOP_STRICTEVAL : JSOP_EVAL;
}
}
BINJS_TRY_DECL(result, handler_.newCall(callee, arguments));
result->setOp(op);
return result;
}
template <typename Tok>
JS::Result<LexicalScopeNode*> BinASTParser<Tok>::parseCatchClause() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::CatchClause) {
return raiseInvalidKind("CatchClause", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result, parseInterfaceCatchClause(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<LexicalScopeNode*> BinASTParser<Tok>::parseInterfaceCatchClause(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::CatchClause);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::BindingScope, BinASTField::Binding, BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif ParseContext::Statement stmt(pc_, StatementKind::Catch);
ParseContext::Scope currentScope(cx_, pc_, usedNames_);
BINJS_TRY(currentScope.init(pc_));
MOZ_TRY(parseAssertedBoundNamesScope());
BINJS_MOZ_TRY_DECL(binding, parseBinding());
if (!currentScope.lookupDeclaredName(
binding->template as<NameNode>().atom())) {
return raiseError("Missing catch variable in scope");
}
BINJS_MOZ_TRY_DECL(body, parseBlock());
MOZ_TRY(checkClosedVars(currentScope));
BINJS_TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, pc_));
BINJS_TRY_DECL(result, handler_.newLexicalScope(*bindings, body));
BINJS_TRY(handler_.setupCatchScope(result, binding, body));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceClassDeclaration(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release (ClassDeclaration)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceClassExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release (ClassExpression)");
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceCompoundAssignmentExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::CompoundAssignmentExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::Operator, BinASTField::Binding, BinASTField::Expression};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(operator_, parseCompoundAssignmentOperator());
BINJS_MOZ_TRY_DECL(binding, parseSimpleAssignmentTarget());
BINJS_MOZ_TRY_DECL(expression, parseExpression());
ParseNodeKind pnk;
switch (operator_) {
case CompoundAssignmentOperator::PlusAssign:
pnk = ParseNodeKind::AddAssignExpr;
break;
case CompoundAssignmentOperator::MinusAssign:
pnk = ParseNodeKind::SubAssignExpr;
break;
case CompoundAssignmentOperator::MulAssign:
pnk = ParseNodeKind::MulAssignExpr;
break;
case CompoundAssignmentOperator::DivAssign:
pnk = ParseNodeKind::DivAssignExpr;
break;
case CompoundAssignmentOperator::ModAssign:
pnk = ParseNodeKind::ModAssignExpr;
break;
case CompoundAssignmentOperator::PowAssign:
pnk = ParseNodeKind::PowAssignExpr;
break;
case CompoundAssignmentOperator::LshAssign:
pnk = ParseNodeKind::LshAssignExpr;
break;
case CompoundAssignmentOperator::RshAssign:
pnk = ParseNodeKind::RshAssignExpr;
break;
case CompoundAssignmentOperator::UrshAssign:
pnk = ParseNodeKind::UrshAssignExpr;
break;
case CompoundAssignmentOperator::BitOrAssign:
pnk = ParseNodeKind::BitOrAssignExpr;
break;
case CompoundAssignmentOperator::BitXorAssign:
pnk = ParseNodeKind::BitXorAssignExpr;
break;
case CompoundAssignmentOperator::BitAndAssign:
pnk = ParseNodeKind::BitAndAssignExpr;
break;
}
BINJS_TRY_DECL(result, handler_.newAssignment(pnk, binding, expression));
return result;
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceComputedMemberAssignmentTarget(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::ComputedMemberAssignmentTarget);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Object,
BinASTField::Expression};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
BINJS_MOZ_TRY_DECL(expression, parseExpression());
BINJS_TRY_DECL(result, handler_.newPropertyByValue(object, expression,
tokenizer_->offset()));
return result;
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceComputedMemberExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::ComputedMemberExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Object,
BinASTField::Expression};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
BINJS_MOZ_TRY_DECL(expression, parseExpression());
BINJS_TRY_DECL(result, handler_.newPropertyByValue(object, expression,
tokenizer_->offset()));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceComputedPropertyName(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release "
"(ComputedPropertyName)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceConditionalExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::ConditionalExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::Test, BinASTField::Consequent, BinASTField::Alternate};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(test, parseExpression());
BINJS_MOZ_TRY_DECL(consequent, parseExpression());
BINJS_MOZ_TRY_DECL(alternate, parseExpression());
BINJS_TRY_DECL(result, handler_.newConditional(test, consequent, alternate));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceContinueStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::ContinueStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Label};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif RootedAtom label(cx_);
MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom());
if (label) {
if (!IsIdentifier(label)) {
return raiseError("ContinueStatement - Label MUST be an identifier");
}
}
auto validity =
pc_->checkContinueStatement(label ? label->asPropertyName() : nullptr);
if (validity.isErr()) {
switch (validity.unwrapErr()) {
case ParseContext::ContinueStatementError::NotInALoop:
this->error(JSMSG_BAD_CONTINUE);
return cx_->alreadyReportedError();
case ParseContext::ContinueStatementError::LabelNotFound:
this->error(JSMSG_LABEL_NOT_FOUND);
return cx_->alreadyReportedError();
}
}
BINJS_TRY_DECL(result, handler_.newContinueStatement(
label ? label->asPropertyName() : nullptr,
tokenizer_->pos(start)));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceDataProperty(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::DataProperty);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Name,
BinASTField::Expression};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(name, parsePropertyName());
BINJS_MOZ_TRY_DECL(expression, parseExpression());
if (!handler_.isUsableAsObjectPropertyName(name)) {
return raiseError("DataProperty key kind");
}
ParseNode* result;
if (name->template is<NameNode>() &&
name->template as<NameNode>().atom() == cx_->names().proto) {
BINJS_TRY_VAR(result, handler_.newUnary(ParseNodeKind::MutateProto, start,
expression));
} else {
BINJS_TRY_VAR(result, handler_.newObjectMethodOrPropertyDefinition(
name, expression, AccessorType::None));
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceDebuggerStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release (DebuggerStatement)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseDirective() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::Directive) {
return raiseInvalidKind("Directive", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result, parseInterfaceDirective(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceDirective(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::Directive);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::RawValue};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
RootedAtom rawValue(cx_);
MOZ_TRY_VAR(rawValue, tokenizer_->readAtom());
TokenPos pos = tokenizer_->pos(start);
BINJS_TRY_DECL(result, handler_.newStringLiteral(rawValue, pos));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceDoWhileStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::DoWhileStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Test, BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif ParseContext::Statement stmt(pc_, StatementKind::DoLoop);
BINJS_MOZ_TRY_DECL(test, parseExpression());
BINJS_MOZ_TRY_DECL(body, parseStatement());
BINJS_TRY_DECL(
result, handler_.newDoWhileStatement(body, test, tokenizer_->pos(start)));
return result;
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceEagerArrowExpressionWithExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release "
"(EagerArrowExpressionWithExpression)");
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceEagerArrowExpressionWithFunctionBody(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release "
"(EagerArrowExpressionWithFunctionBody)");
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceEagerFunctionDeclaration(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::EagerFunctionDeclaration);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[6] = {
BinASTField::IsAsync, BinASTField::IsGenerator, BinASTField::Name,
BinASTField::Length, BinASTField::Directives, BinASTField::Contents};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif const auto syntax = FunctionSyntaxKind::Statement;
BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
if (isAsync) {
return raiseError(
"Async function is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
if (isGenerator) {
return raiseError("Generator is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(name, parseBindingIdentifier());
BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());
BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
BINJS_MOZ_TRY_DECL(funbox,
buildFunctionBox(isGenerator ? GeneratorKind::Generator
: GeneratorKind::NotGenerator,
isAsync ? FunctionAsyncKind::AsyncFunction
: FunctionAsyncKind::SyncFunction,
syntax,
(syntax != FunctionSyntaxKind::Setter &&
syntax != FunctionSyntaxKind::Getter)
? name
: nullptr));
forceStrictIfNecessary(funbox, directives);
BinASTParseContext funpc(cx_, this, funbox, nullptr);
BINJS_TRY(funpc.init());
pc_->functionScope().useAsVarScope(pc_);
MOZ_ASSERT(pc_->isFunctionBox());
ParseContext::Scope lexicalScope(cx_, pc_, usedNames_);
BINJS_TRY(lexicalScope.init(pc_));
ListNode* params;
ListNode* body;
MOZ_TRY(parseFunctionOrMethodContents(length, ¶ms, &body));
MOZ_TRY(prependDirectivesToBody(body, directives));
BINJS_TRY_DECL(lexicalScopeData,
NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
BINJS_MOZ_TRY_DECL(result,
buildFunction(start, kind, name, params, bodyScope));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerFunctionExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::EagerFunctionExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[6] = {
BinASTField::IsAsync, BinASTField::IsGenerator, BinASTField::Name,
BinASTField::Length, BinASTField::Directives, BinASTField::Contents};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif const auto syntax = FunctionSyntaxKind::Expression;
BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
if (isAsync) {
return raiseError(
"Async function is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
if (isGenerator) {
return raiseError("Generator is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(name, parseOptionalBindingIdentifier());
BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());
BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
BINJS_MOZ_TRY_DECL(funbox,
buildFunctionBox(isGenerator ? GeneratorKind::Generator
: GeneratorKind::NotGenerator,
isAsync ? FunctionAsyncKind::AsyncFunction
: FunctionAsyncKind::SyncFunction,
syntax,
(syntax != FunctionSyntaxKind::Setter &&
syntax != FunctionSyntaxKind::Getter)
? name
: nullptr));
forceStrictIfNecessary(funbox, directives);
BinASTParseContext funpc(cx_, this, funbox, nullptr);
BINJS_TRY(funpc.init());
pc_->functionScope().useAsVarScope(pc_);
MOZ_ASSERT(pc_->isFunctionBox());
ParseContext::Scope lexicalScope(cx_, pc_, usedNames_);
BINJS_TRY(lexicalScope.init(pc_));
ListNode* params;
ListNode* body;
MOZ_TRY(parseFunctionExpressionContents(length, ¶ms, &body));
MOZ_TRY(prependDirectivesToBody(body, directives));
BINJS_TRY_DECL(lexicalScopeData,
NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
BINJS_MOZ_TRY_DECL(result,
buildFunction(start, kind, name, params, bodyScope));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerGetter(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::EagerGetter);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::Name, BinASTField::Directives, BinASTField::Contents};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif const auto syntax = FunctionSyntaxKind::Setter;
const bool isGenerator = false;
const bool isAsync = false;
const auto accessorType = AccessorType::Getter;
const uint32_t length = 0;
BINJS_MOZ_TRY_DECL(name, parsePropertyName());
BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
BINJS_MOZ_TRY_DECL(funbox,
buildFunctionBox(isGenerator ? GeneratorKind::Generator
: GeneratorKind::NotGenerator,
isAsync ? FunctionAsyncKind::AsyncFunction
: FunctionAsyncKind::SyncFunction,
syntax,
(syntax != FunctionSyntaxKind::Setter &&
syntax != FunctionSyntaxKind::Getter)
? name
: nullptr));
forceStrictIfNecessary(funbox, directives);
BinASTParseContext funpc(cx_, this, funbox, nullptr);
BINJS_TRY(funpc.init());
pc_->functionScope().useAsVarScope(pc_);
MOZ_ASSERT(pc_->isFunctionBox());
ParseContext::Scope lexicalScope(cx_, pc_, usedNames_);
BINJS_TRY(lexicalScope.init(pc_));
ListNode* params;
ListNode* body;
MOZ_TRY(parseGetterContents(length, ¶ms, &body));
MOZ_TRY(prependDirectivesToBody(body, directives));
BINJS_TRY_DECL(lexicalScopeData,
NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
BINJS_MOZ_TRY_DECL(method,
buildFunction(start, kind, name, params, bodyScope));
BINJS_TRY_DECL(result, handler_.newObjectMethodOrPropertyDefinition(
name, method, accessorType));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerMethod(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::EagerMethod);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[6] = {
BinASTField::IsAsync, BinASTField::IsGenerator, BinASTField::Name,
BinASTField::Length, BinASTField::Directives, BinASTField::Contents};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif const auto syntax = FunctionSyntaxKind::Method;
const auto accessorType = AccessorType::None;
BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
if (isAsync) {
return raiseError(
"Async function is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
if (isGenerator) {
return raiseError("Generator is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(name, parsePropertyName());
BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());
BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
BINJS_MOZ_TRY_DECL(funbox,
buildFunctionBox(isGenerator ? GeneratorKind::Generator
: GeneratorKind::NotGenerator,
isAsync ? FunctionAsyncKind::AsyncFunction
: FunctionAsyncKind::SyncFunction,
syntax,
(syntax != FunctionSyntaxKind::Setter &&
syntax != FunctionSyntaxKind::Getter)
? name
: nullptr));
forceStrictIfNecessary(funbox, directives);
BinASTParseContext funpc(cx_, this, funbox, nullptr);
BINJS_TRY(funpc.init());
pc_->functionScope().useAsVarScope(pc_);
MOZ_ASSERT(pc_->isFunctionBox());
ParseContext::Scope lexicalScope(cx_, pc_, usedNames_);
BINJS_TRY(lexicalScope.init(pc_));
ListNode* params;
ListNode* body;
MOZ_TRY(parseFunctionOrMethodContents(length, ¶ms, &body));
MOZ_TRY(prependDirectivesToBody(body, directives));
BINJS_TRY_DECL(lexicalScopeData,
NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
BINJS_MOZ_TRY_DECL(method,
buildFunction(start, kind, name, params, bodyScope));
BINJS_TRY_DECL(result, handler_.newObjectMethodOrPropertyDefinition(
name, method, accessorType));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerSetter(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::EagerSetter);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[4] = {
BinASTField::Name, BinASTField::Length, BinASTField::Directives,
BinASTField::Contents};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif const auto syntax = FunctionSyntaxKind::Setter;
const bool isGenerator = false;
const bool isAsync = false;
const auto accessorType = AccessorType::Setter;
BINJS_MOZ_TRY_DECL(name, parsePropertyName());
BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());
BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
BINJS_MOZ_TRY_DECL(funbox,
buildFunctionBox(isGenerator ? GeneratorKind::Generator
: GeneratorKind::NotGenerator,
isAsync ? FunctionAsyncKind::AsyncFunction
: FunctionAsyncKind::SyncFunction,
syntax,
(syntax != FunctionSyntaxKind::Setter &&
syntax != FunctionSyntaxKind::Getter)
? name
: nullptr));
forceStrictIfNecessary(funbox, directives);
BinASTParseContext funpc(cx_, this, funbox, nullptr);
BINJS_TRY(funpc.init());
pc_->functionScope().useAsVarScope(pc_);
MOZ_ASSERT(pc_->isFunctionBox());
ParseContext::Scope lexicalScope(cx_, pc_, usedNames_);
BINJS_TRY(lexicalScope.init(pc_));
ListNode* params;
ListNode* body;
MOZ_TRY(parseSetterContents(length, ¶ms, &body));
MOZ_TRY(prependDirectivesToBody(body, directives));
BINJS_TRY_DECL(lexicalScopeData,
NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
BINJS_MOZ_TRY_DECL(method,
buildFunction(start, kind, name, params, bodyScope));
BINJS_TRY_DECL(result, handler_.newObjectMethodOrPropertyDefinition(
name, method, accessorType));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEmptyStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::EmptyStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
MOZ_TRY(tokenizer_->checkFields0(kind, fields));
BINJS_TRY_DECL(result, handler_.newEmptyStatement(tokenizer_->pos(start)));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceExpressionStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::ExpressionStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Expression};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(expression, parseExpression());
BINJS_TRY_DECL(result,
handler_.newExprStatement(expression, tokenizer_->offset()));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceForInOfBinding(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::ForInOfBinding);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Kind,
BinASTField::Binding};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif AutoVariableDeclarationKind kindGuard(this);
BINJS_MOZ_TRY_DECL(kind_, parseVariableDeclarationKind());
BINJS_MOZ_TRY_DECL(binding, parseBinding());
variableDeclarationKind_ = kind_;
MOZ_TRY(
checkBinding(binding->template as<NameNode>().atom()->asPropertyName()));
ParseNodeKind pnk;
switch (kind_) {
case VariableDeclarationKind::Var:
pnk = ParseNodeKind::VarStmt;
break;
case VariableDeclarationKind::Let:
return raiseError("Let is not supported in this preview release");
case VariableDeclarationKind::Const:
return raiseError("Const is not supported in this preview release");
}
BINJS_TRY_DECL(result,
handler_.newDeclarationList(pnk, tokenizer_->pos(start)));
handler_.addList(result, binding);
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceForInStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::ForInStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[3] = {BinASTField::Left, BinASTField::Right,
BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif ParseContext::Statement stmt(pc_, StatementKind::ForInLoop);
ParseContext::Scope scope(cx_, pc_, usedNames_);
BINJS_TRY(scope.init(pc_));
BINJS_MOZ_TRY_DECL(left, parseForInOfBindingOrAssignmentTarget());
BINJS_MOZ_TRY_DECL(right, parseExpression());
BINJS_MOZ_TRY_DECL(body, parseStatement());
BINJS_TRY_DECL(forHead,
handler_.newForInOrOfHead(ParseNodeKind::ForIn, left, right,
tokenizer_->pos(start)));
ParseNode* result;
BINJS_TRY_VAR(result, handler_.newForStatement(start, forHead, body,
0));
if (!scope.isEmpty()) {
BINJS_TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, pc_));
BINJS_TRY_VAR(result, handler_.newLexicalScope(*bindings, result));
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceForOfStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release (ForOfStatement)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceForStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::ForStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[4] = {BinASTField::Init, BinASTField::Test,
BinASTField::Update,
BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif ParseContext::Statement stmt(pc_, StatementKind::ForLoop);
ParseContext::Scope scope(cx_, pc_, usedNames_);
BINJS_TRY(scope.init(pc_));
BINJS_MOZ_TRY_DECL(init, parseOptionalVariableDeclarationOrExpression());
BINJS_MOZ_TRY_DECL(test, parseOptionalExpression());
BINJS_MOZ_TRY_DECL(update, parseOptionalExpression());
BINJS_MOZ_TRY_DECL(body, parseStatement());
BINJS_TRY_DECL(
forHead, handler_.newForHead(init, test, update, tokenizer_->pos(start)));
ParseNode* result;
BINJS_TRY_VAR(result, handler_.newForStatement(start, forHead, body,
0));
if (!scope.isEmpty()) {
BINJS_TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, pc_));
BINJS_TRY_VAR(result, handler_.newLexicalScope(*bindings, result));
}
return result;
}
template <typename Tok>
JS::Result<ListNode*> BinASTParser<Tok>::parseFormalParameters() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::FormalParameters) {
return raiseInvalidKind("FormalParameters", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result,
parseInterfaceFormalParameters(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ListNode*> BinASTParser<Tok>::parseInterfaceFormalParameters(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::FormalParameters);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Items,
BinASTField::Rest};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(items, parseListOfParameter());
BINJS_MOZ_TRY_DECL(rest, parseOptionalBinding());
auto result = items;
if (rest) {
return raiseError(
"Rest parameter is not supported in this preview release");
}
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseFunctionExpressionContents(
uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::FunctionExpressionContents) {
return raiseInvalidKind("FunctionExpressionContents", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result,
parseInterfaceFunctionExpressionContents(
start, kind, fields, funLength, paramsOut, bodyOut));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseInterfaceFunctionExpressionContents(
const size_t start, const BinASTKind kind, const BinASTFields& fields,
uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut) {
MOZ_ASSERT(kind == BinASTKind::FunctionExpressionContents);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[6] = {BinASTField::IsFunctionNameCaptured,
BinASTField::IsThisCaptured,
BinASTField::ParameterScope,
BinASTField::Params,
BinASTField::BodyScope,
BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(isFunctionNameCaptured, tokenizer_->readBool());
if (pc_->functionBox()->function()->isNamedLambda() &&
isFunctionNameCaptured) {
captureFunctionName();
}
BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool());
(void)isThisCaptured;
Rooted<GCVector<JSAtom*>> positionalParams(cx_, GCVector<JSAtom*>(cx_));
MOZ_TRY(parseAssertedParameterScope(&positionalParams));
BINJS_MOZ_TRY_DECL(params, parseFormalParameters());
MOZ_TRY(checkFunctionLength(funLength));
MOZ_TRY(checkPositionalParameterIndices(positionalParams, params));
MOZ_TRY(parseAssertedVarScope());
BINJS_MOZ_TRY_DECL(body, parseFunctionBody());
*paramsOut = params;
*bodyOut = body;
auto result = Ok();
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseFunctionOrMethodContents(
uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::FunctionOrMethodContents) {
return raiseInvalidKind("FunctionOrMethodContents", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result,
parseInterfaceFunctionOrMethodContents(
start, kind, fields, funLength, paramsOut, bodyOut));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseInterfaceFunctionOrMethodContents(
const size_t start, const BinASTKind kind, const BinASTFields& fields,
uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut) {
MOZ_ASSERT(kind == BinASTKind::FunctionOrMethodContents);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[5] = {
BinASTField::IsThisCaptured, BinASTField::ParameterScope,
BinASTField::Params, BinASTField::BodyScope, BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool());
(void)isThisCaptured;
Rooted<GCVector<JSAtom*>> positionalParams(cx_, GCVector<JSAtom*>(cx_));
MOZ_TRY(parseAssertedParameterScope(&positionalParams));
BINJS_MOZ_TRY_DECL(params, parseFormalParameters());
MOZ_TRY(checkFunctionLength(funLength));
MOZ_TRY(checkPositionalParameterIndices(positionalParams, params));
MOZ_TRY(parseAssertedVarScope());
BINJS_MOZ_TRY_DECL(body, parseFunctionBody());
*paramsOut = params;
*bodyOut = body;
auto result = Ok();
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseGetterContents(uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::GetterContents) {
return raiseInvalidKind("GetterContents", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(
result, parseInterfaceGetterContents(start, kind, fields, funLength,
paramsOut, bodyOut));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseInterfaceGetterContents(
const size_t start, const BinASTKind kind, const BinASTFields& fields,
uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut) {
MOZ_ASSERT(kind == BinASTKind::GetterContents);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::IsThisCaptured, BinASTField::BodyScope, BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool());
(void)isThisCaptured;
MOZ_TRY(parseAssertedVarScope());
BINJS_TRY_DECL(params, handler_.newParamsBody(tokenizer_->pos(start)));
BINJS_MOZ_TRY_DECL(body, parseFunctionBody());
*paramsOut = params;
*bodyOut = body;
auto result = Ok();
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseIdentifierExpression() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::IdentifierExpression) {
return raiseInvalidKind("IdentifierExpression", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result,
parseInterfaceIdentifierExpression(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceIdentifierExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::IdentifierExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Name};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
RootedAtom name(cx_);
MOZ_TRY_VAR(name, tokenizer_->readIdentifierName());
BINJS_TRY(usedNames_.noteUse(cx_, name, pc_->scriptId(),
pc_->innermostScope()->id()));
BINJS_TRY_DECL(result, handler_.newName(name->asPropertyName(),
tokenizer_->pos(start), cx_));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceIfStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::IfStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::Test, BinASTField::Consequent, BinASTField::Alternate};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(test, parseExpression());
BINJS_MOZ_TRY_DECL(consequent, parseStatement());
BINJS_MOZ_TRY_DECL(alternate, parseOptionalStatement());
BINJS_TRY_DECL(result,
handler_.newIfStatement(start, test, consequent, alternate));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLabelledStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::LabelledStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Label,
BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
RootedAtom label(cx_);
MOZ_TRY_VAR(label, tokenizer_->readAtom());
if (!IsIdentifier(label)) {
return raiseError("Invalid identifier");
}
ParseContext::LabelStatement stmt(pc_, label);
BINJS_MOZ_TRY_DECL(body, parseStatement());
BINJS_TRY_DECL(result, handler_.newLabeledStatement(label->asPropertyName(),
body, start));
return result;
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLazyArrowExpressionWithExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release "
"(LazyArrowExpressionWithExpression)");
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLazyArrowExpressionWithFunctionBody(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release "
"(LazyArrowExpressionWithFunctionBody)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLazyFunctionDeclaration(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::LazyFunctionDeclaration);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[7] = {
BinASTField::IsAsync, BinASTField::IsGenerator, BinASTField::Name,
BinASTField::Length, BinASTField::Directives, BinASTField::ContentsSkip,
BinASTField::Contents};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif const auto syntax = FunctionSyntaxKind::Statement;
BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
if (isAsync) {
return raiseError(
"Async function is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
if (isGenerator) {
return raiseError("Generator is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(name, parseBindingIdentifier());
BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());
BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
BINJS_MOZ_TRY_DECL(contentsSkip, tokenizer_->readSkippableSubTree());
BINJS_MOZ_TRY_DECL(funbox,
buildFunctionBox(isGenerator ? GeneratorKind::Generator
: GeneratorKind::NotGenerator,
isAsync ? FunctionAsyncKind::AsyncFunction
: FunctionAsyncKind::SyncFunction,
syntax, name));
forceStrictIfNecessary(funbox, directives);
RootedFunction fun(cx_, funbox->function());
fun->setArgCount(length);
auto skipStart = contentsSkip.startOffset();
BINJS_TRY_DECL(
lazy, LazyScript::Create(cx_, fun, sourceObject_,
pc_->closedOverBindingsForLazy(),
pc_->innerFunctionsForLazy, skipStart,
skipStart + contentsSkip.length(), skipStart, 0,
skipStart, ParseGoal::Script));
if (funbox->strict()) {
lazy->setStrict();
}
lazy->setIsBinAST();
funbox->function()->initLazyScript(lazy);
BINJS_MOZ_TRY_DECL(result, makeEmptyFunctionNode(skipStart, kind, funbox));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLazyFunctionExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::LazyFunctionExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[7] = {
BinASTField::IsAsync, BinASTField::IsGenerator, BinASTField::Name,
BinASTField::Length, BinASTField::Directives, BinASTField::ContentsSkip,
BinASTField::Contents};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif const auto syntax = FunctionSyntaxKind::Expression;
BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool());
if (isAsync) {
return raiseError(
"Async function is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool());
if (isGenerator) {
return raiseError("Generator is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(name, parseOptionalBindingIdentifier());
BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong());
BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
BINJS_MOZ_TRY_DECL(contentsSkip, tokenizer_->readSkippableSubTree());
BINJS_MOZ_TRY_DECL(funbox,
buildFunctionBox(isGenerator ? GeneratorKind::Generator
: GeneratorKind::NotGenerator,
isAsync ? FunctionAsyncKind::AsyncFunction
: FunctionAsyncKind::SyncFunction,
syntax, name));
forceStrictIfNecessary(funbox, directives);
RootedFunction fun(cx_, funbox->function());
fun->setArgCount(length);
auto skipStart = contentsSkip.startOffset();
BINJS_TRY_DECL(
lazy, LazyScript::Create(cx_, fun, sourceObject_,
pc_->closedOverBindingsForLazy(),
pc_->innerFunctionsForLazy, skipStart,
skipStart + contentsSkip.length(), skipStart, 0,
skipStart, ParseGoal::Script));
if (funbox->strict()) {
lazy->setStrict();
}
lazy->setIsBinAST();
funbox->function()->initLazyScript(lazy);
BINJS_MOZ_TRY_DECL(result, makeEmptyFunctionNode(skipStart, kind, funbox));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLazyGetter(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release (LazyGetter)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLazyMethod(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release (LazyMethod)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLazySetter(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release (LazySetter)");
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLiteralBooleanExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::LiteralBooleanExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Value};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(value, tokenizer_->readBool());
BINJS_TRY_DECL(result,
handler_.newBooleanLiteral(value, tokenizer_->pos(start)));
return result;
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLiteralInfinityExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release "
"(LiteralInfinityExpression)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLiteralNullExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::LiteralNullExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
MOZ_TRY(tokenizer_->checkFields0(kind, fields));
BINJS_TRY_DECL(result, handler_.newNullLiteral(tokenizer_->pos(start)));
return result;
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceLiteralNumericExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::LiteralNumericExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Value};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(value, tokenizer_->readDouble());
BINJS_TRY_DECL(result, handler_.newNumber(value, DecimalPoint::HasDecimal,
tokenizer_->pos(start)));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLiteralPropertyName(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::LiteralPropertyName);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Value};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
RootedAtom value(cx_);
MOZ_TRY_VAR(value, tokenizer_->readAtom());
ParseNode* result;
uint32_t index;
if (value->isIndex(&index)) {
BINJS_TRY_VAR(result,
handler_.newNumber(index, NoDecimal,
TokenPos(start, tokenizer_->offset())));
} else {
BINJS_TRY_VAR(result, handler_.newObjectLiteralPropertyName(
value, tokenizer_->pos(start)));
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLiteralRegExpExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::LiteralRegExpExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Pattern,
BinASTField::Flags};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
RootedAtom pattern(cx_);
MOZ_TRY_VAR(pattern, tokenizer_->readAtom());
Chars flags(cx_);
MOZ_TRY(tokenizer_->readChars(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 raiseError("Invalid regexp flags");
}
}
Rooted<RegExpObject*> reobj(cx_);
BINJS_TRY_VAR(reobj,
RegExpObject::create(cx_, pattern, reflags, TenuredObject));
BINJS_TRY_DECL(result,
handler_.newRegExp(reobj, tokenizer_->pos(start), *this));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLiteralStringExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::LiteralStringExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Value};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
RootedAtom value(cx_);
MOZ_TRY_VAR(value, tokenizer_->readAtom());
BINJS_TRY_DECL(result,
handler_.newStringLiteral(value, tokenizer_->pos(start)));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceModule(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release (Module)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceNewExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::NewExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Callee,
BinASTField::Arguments};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(callee, parseExpression());
BINJS_MOZ_TRY_DECL(arguments, parseArguments());
BINJS_TRY_DECL(result, handler_.newNewExpression(tokenizer_->pos(start).begin,
callee, arguments));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceNewTargetExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release "
"(NewTargetExpression)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceObjectAssignmentTarget(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release "
"(ObjectAssignmentTarget)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceObjectBinding(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release (ObjectBinding)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceObjectExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::ObjectExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Properties};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(properties, parseListOfObjectProperty());
auto result = properties;
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceReturnStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::ReturnStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Expression};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif if (!pc_->isFunctionBox()) {
return raiseInvalidKind("Toplevel Statement", kind);
}
pc_->functionBox()->usesReturn = true;
BINJS_MOZ_TRY_DECL(expression, parseOptionalExpression());
BINJS_TRY_DECL(
result, handler_.newReturnStatement(expression, tokenizer_->pos(start)));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceScript(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::Script);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::Scope, BinASTField::Directives, BinASTField::Statements};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
MOZ_TRY(parseAssertedScriptGlobalScope());
BINJS_MOZ_TRY_DECL(directives, parseListOfDirective());
forceStrictIfNecessary(pc_->sc(), directives);
BINJS_MOZ_TRY_DECL(statements, parseListOfStatement());
MOZ_TRY(checkClosedVars(pc_->varScope()));
MOZ_TRY(prependDirectivesToBody( statements, directives));
auto result = statements;
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseSetterContents(uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::SetterContents) {
return raiseInvalidKind("SetterContents", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(
result, parseInterfaceSetterContents(start, kind, fields, funLength,
paramsOut, bodyOut));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseInterfaceSetterContents(
const size_t start, const BinASTKind kind, const BinASTFields& fields,
uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut) {
MOZ_ASSERT(kind == BinASTKind::SetterContents);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[5] = {
BinASTField::IsThisCaptured, BinASTField::ParameterScope,
BinASTField::Param, BinASTField::BodyScope, BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool());
(void)isThisCaptured;
Rooted<GCVector<JSAtom*>> positionalParams(cx_, GCVector<JSAtom*>(cx_));
MOZ_TRY(parseAssertedParameterScope(&positionalParams));
BINJS_MOZ_TRY_DECL(param, parseParameter());
BINJS_TRY_DECL(params, handler_.newParamsBody(param->pn_pos));
handler_.addList(params, param);
MOZ_TRY(checkPositionalParameterIndices(positionalParams, params));
MOZ_TRY(parseAssertedVarScope());
BINJS_MOZ_TRY_DECL(body, parseFunctionBody());
*paramsOut = params;
*bodyOut = body;
auto result = Ok();
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceShorthandProperty(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::ShorthandProperty);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Name};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(name, parseIdentifierExpression());
MOZ_ASSERT(name->isKind(ParseNodeKind::Name));
MOZ_ASSERT(!handler_.isUsableAsObjectPropertyName(name));
BINJS_TRY_DECL(propName, handler_.newObjectLiteralPropertyName(
name->template as<NameNode>().name(),
tokenizer_->pos(start)));
BINJS_TRY_DECL(result,
handler_.newShorthandPropertyDefinition(propName, name));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceSpreadElement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release (SpreadElement)");
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceStaticMemberAssignmentTarget(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::StaticMemberAssignmentTarget);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Object,
BinASTField::Property};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif size_t nameStart;
BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
RootedAtom property(cx_);
{
nameStart = tokenizer_->offset();
MOZ_TRY_VAR(property, tokenizer_->readPropertyKey());
}
BINJS_TRY_DECL(name, handler_.newPropertyName(property->asPropertyName(),
tokenizer_->pos(nameStart)));
BINJS_TRY_DECL(result, handler_.newPropertyAccess(object, name));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceStaticMemberExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::StaticMemberExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Object,
BinASTField::Property};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif size_t nameStart;
BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
RootedAtom property(cx_);
{
nameStart = tokenizer_->offset();
MOZ_TRY_VAR(property, tokenizer_->readPropertyKey());
}
BINJS_TRY_DECL(name, handler_.newPropertyName(property->asPropertyName(),
tokenizer_->pos(nameStart)));
BINJS_TRY_DECL(result, handler_.newPropertyAccess(object, name));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceSuper(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release (Super)");
}
template <typename Tok>
JS::Result<CaseClause*> BinASTParser<Tok>::parseSwitchCase() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::SwitchCase) {
return raiseInvalidKind("SwitchCase", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result, parseInterfaceSwitchCase(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<CaseClause*> BinASTParser<Tok>::parseInterfaceSwitchCase(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::SwitchCase);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Test,
BinASTField::Consequent};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(test, parseExpression());
BINJS_MOZ_TRY_DECL(consequent, parseListOfStatement());
BINJS_TRY_DECL(result, handler_.newCaseOrDefault(start, test, consequent));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseSwitchDefault() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::SwitchDefault) {
return raiseInvalidKind("SwitchDefault", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result, parseInterfaceSwitchDefault(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceSwitchDefault(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::SwitchDefault);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Consequent};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(consequent, parseListOfStatement());
BINJS_TRY_DECL(result, handler_.newCaseOrDefault(start, nullptr, consequent));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceSwitchStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::SwitchStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Discriminant,
BinASTField::Cases};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(discriminant, parseExpression());
ParseContext::Statement stmt(pc_, StatementKind::Switch);
BINJS_MOZ_TRY_DECL(cases, parseListOfSwitchCase());
BINJS_TRY_DECL(scope, handler_.newLexicalScope(nullptr, cases));
BINJS_TRY_DECL(result, handler_.newSwitchStatement(start, discriminant, scope,
false));
return result;
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceSwitchStatementWithDefault(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::SwitchStatementWithDefault);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[4] = {
BinASTField::Discriminant, BinASTField::PreDefaultCases,
BinASTField::DefaultCase, BinASTField::PostDefaultCases};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(discriminant, parseExpression());
ParseContext::Statement stmt(pc_, StatementKind::Switch);
BINJS_MOZ_TRY_DECL(preDefaultCases, parseListOfSwitchCase());
BINJS_MOZ_TRY_DECL(defaultCase, parseSwitchDefault());
BINJS_MOZ_TRY_DECL(postDefaultCases, parseListOfSwitchCase());
auto cases = preDefaultCases;
handler_.addList(cases, defaultCase);
ParseNode* iter = postDefaultCases->head();
while (iter) {
ParseNode* next = iter->pn_next;
handler_.addList(cases, iter);
iter = next;
}
BINJS_TRY_DECL(scope, handler_.newLexicalScope(nullptr, cases));
BINJS_TRY_DECL(result, handler_.newSwitchStatement(start, discriminant, scope,
true));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceTemplateExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release "
"(TemplateExpression)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceThisExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::ThisExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
MOZ_TRY(tokenizer_->checkFields0(kind, fields));
if (pc_->isFunctionBox()) {
pc_->functionBox()->usesThis = true;
}
TokenPos pos = tokenizer_->pos(start);
ParseNode* thisName(nullptr);
if (pc_->sc()->thisBinding() == ThisBinding::Function) {
HandlePropertyName dotThis = cx_->names().dotThis;
BINJS_TRY(usedNames_.noteUse(cx_, dotThis, pc_->scriptId(),
pc_->innermostScope()->id()));
BINJS_TRY_VAR(thisName, handler_.newName(dotThis, pos, cx_));
}
BINJS_TRY_DECL(result, handler_.newThisLiteral(pos, thisName));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceThrowStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::ThrowStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Expression};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(expression, parseExpression());
BINJS_TRY_DECL(
result, handler_.newThrowStatement(expression, tokenizer_->pos(start)));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceTryCatchStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::TryCatchStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Body,
BinASTField::CatchClause};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif ParseNode* body;
{
ParseContext::Statement stmt(pc_, StatementKind::Try);
ParseContext::Scope scope(cx_, pc_, usedNames_);
BINJS_TRY(scope.init(pc_));
MOZ_TRY_VAR(body, parseBlock());
}
BINJS_MOZ_TRY_DECL(catchClause, parseCatchClause());
BINJS_TRY_DECL(result,
handler_.newTryStatement(start, body, catchClause,
nullptr));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceTryFinallyStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::TryFinallyStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::Body, BinASTField::CatchClause, BinASTField::Finalizer};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif ParseNode* body;
{
ParseContext::Statement stmt(pc_, StatementKind::Try);
ParseContext::Scope scope(cx_, pc_, usedNames_);
BINJS_TRY(scope.init(pc_));
MOZ_TRY_VAR(body, parseBlock());
}
BINJS_MOZ_TRY_DECL(catchClause, parseOptionalCatchClause());
ParseNode* finalizer;
{
ParseContext::Statement stmt(pc_, StatementKind::Finally);
ParseContext::Scope scope(cx_, pc_, usedNames_);
BINJS_TRY(scope.init(pc_));
MOZ_TRY_VAR(finalizer, parseBlock());
}
BINJS_TRY_DECL(result,
handler_.newTryStatement(start, body, catchClause, finalizer));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceUnaryExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::UnaryExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Operator,
BinASTField::Operand};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(operator_, parseUnaryOperator());
BINJS_MOZ_TRY_DECL(operand, parseExpression());
ParseNodeKind pnk;
switch (operator_) {
case UnaryOperator::Minus:
pnk = ParseNodeKind::NegExpr;
break;
case UnaryOperator::Plus:
pnk = ParseNodeKind::PosExpr;
break;
case UnaryOperator::Not:
pnk = ParseNodeKind::NotExpr;
break;
case UnaryOperator::BitNot:
pnk = ParseNodeKind::BitNotExpr;
break;
case UnaryOperator::Typeof: {
if (operand->isKind(ParseNodeKind::Name)) {
pnk = ParseNodeKind::TypeOfNameExpr;
} else {
pnk = ParseNodeKind::TypeOfExpr;
}
break;
}
case UnaryOperator::Void:
pnk = ParseNodeKind::VoidExpr;
break;
case UnaryOperator::Delete: {
switch (operand->getKind()) {
case ParseNodeKind::Name:
operand->setOp(JSOP_DELNAME);
pnk = ParseNodeKind::DeleteNameExpr;
BINJS_TRY(this->strictModeError(JSMSG_DEPRECATED_DELETE_OPERAND));
pc_->sc()->setBindingsAccessedDynamically();
break;
case ParseNodeKind::DotExpr:
pnk = ParseNodeKind::DeletePropExpr;
break;
case ParseNodeKind::ElemExpr:
pnk = ParseNodeKind::DeleteElemExpr;
break;
default:
pnk = ParseNodeKind::DeleteExpr;
}
break;
}
}
BINJS_TRY_DECL(result, handler_.newUnary(pnk, start, operand));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceUpdateExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::UpdateExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::IsPrefix, BinASTField::Operator, BinASTField::Operand};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(isPrefix, tokenizer_->readBool());
BINJS_MOZ_TRY_DECL(operator_, parseUpdateOperator());
BINJS_MOZ_TRY_DECL(operand, parseSimpleAssignmentTarget());
ParseNodeKind pnk;
switch (operator_) {
case UpdateOperator::Incr:
pnk = isPrefix ? ParseNodeKind::PreIncrementExpr
: ParseNodeKind::PostIncrementExpr;
break;
case UpdateOperator::Decr:
pnk = isPrefix ? ParseNodeKind::PreDecrementExpr
: ParseNodeKind::PostDecrementExpr;
break;
}
BINJS_TRY_DECL(result, handler_.newUnary(pnk, start, operand));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceVariableDeclaration(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::VariableDeclaration);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Kind,
BinASTField::Declarators};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif AutoVariableDeclarationKind kindGuard(this);
BINJS_MOZ_TRY_DECL(kind_, parseVariableDeclarationKind());
variableDeclarationKind_ = kind_;
ParseNodeKind declarationListKind;
switch (kind_) {
case VariableDeclarationKind::Var:
declarationListKind = ParseNodeKind::VarStmt;
break;
case VariableDeclarationKind::Let:
return raiseError("Let is not supported in this preview release");
case VariableDeclarationKind::Const:
return raiseError("Const is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(declarators,
parseListOfVariableDeclarator(declarationListKind));
if (declarators->empty()) {
return raiseEmpty("VariableDeclaration");
}
auto result = declarators;
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseVariableDeclarator() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
if (kind != BinASTKind::VariableDeclarator) {
return raiseInvalidKind("VariableDeclarator", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result,
parseInterfaceVariableDeclarator(start, kind, fields));
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceVariableDeclarator(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::VariableDeclarator);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Binding,
BinASTField::Init};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(binding, parseBinding());
BINJS_MOZ_TRY_DECL(init, parseOptionalExpression());
ParseNode* result;
if (binding->isKind(ParseNodeKind::Name)) {
NameNode* bindingNameNode = &binding->template as<NameNode>();
MOZ_TRY(checkBinding(bindingNameNode->atom()->asPropertyName()));
if (init) {
BINJS_TRY_VAR(
result, handler_.finishInitializerAssignment(bindingNameNode, init));
} else {
result = bindingNameNode;
}
} else {
if (!init) {
return raiseMissingField("VariableDeclarator (with non-trivial pattern)",
BinASTField::Init);
}
MOZ_CRASH(
"Unimplemented: AssertedScope check for BindingPattern variable "
"declaration");
BINJS_TRY_VAR(result, handler_.newAssignment(ParseNodeKind::AssignExpr,
binding, init));
}
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceWhileStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::WhileStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Test, BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif ParseContext::Statement stmt(pc_, StatementKind::WhileLoop);
BINJS_MOZ_TRY_DECL(test, parseExpression());
BINJS_MOZ_TRY_DECL(body, parseStatement());
BINJS_TRY_DECL(result, handler_.newWhileStatement(start, test, body));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceWithStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
MOZ_ASSERT(kind == BinASTKind::WithStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Object,
BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif
BINJS_MOZ_TRY_DECL(object, parseExpression());
ParseContext::Statement stmt(pc_, StatementKind::With);
BINJS_MOZ_TRY_DECL(body, parseStatement());
pc_->sc()->setBindingsAccessedDynamically();
BINJS_TRY_DECL(result, handler_.newWithStatement(start, object, body));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceYieldExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release (YieldExpression)");
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceYieldStarExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields) {
return raiseError(
"FIXME: Not implemented yet in this preview release "
"(YieldStarExpression)");
}
template <typename Tok>
JS::Result<typename BinASTParser<Tok>::AssertedDeclaredKind>
BinASTParser<Tok>::parseAssertedDeclaredKind() {
BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());
switch (variant) {
case BinASTVariant::AssertedDeclaredKindOrVariableDeclarationKindVar:
return AssertedDeclaredKind::Var;
case BinASTVariant::AssertedDeclaredKindNonConstLexical:
return AssertedDeclaredKind::NonConstLexical;
case BinASTVariant::AssertedDeclaredKindConstLexical:
return AssertedDeclaredKind::ConstLexical;
default:
return raiseInvalidVariant("AssertedDeclaredKind", variant);
}
}
template <typename Tok>
JS::Result<typename BinASTParser<Tok>::BinaryOperator>
BinASTParser<Tok>::parseBinaryOperator() {
BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());
switch (variant) {
case BinASTVariant::BinaryOperatorComma:
return BinaryOperator::Comma;
case BinASTVariant::BinaryOperatorLogicalOr:
return BinaryOperator::LogicalOr;
case BinASTVariant::BinaryOperatorLogicalAnd:
return BinaryOperator::LogicalAnd;
case BinASTVariant::BinaryOperatorBitOr:
return BinaryOperator::BitOr;
case BinASTVariant::BinaryOperatorBitXor:
return BinaryOperator::BitXor;
case BinASTVariant::BinaryOperatorBitAnd:
return BinaryOperator::BitAnd;
case BinASTVariant::BinaryOperatorEq:
return BinaryOperator::Eq;
case BinASTVariant::BinaryOperatorNeq:
return BinaryOperator::Neq;
case BinASTVariant::BinaryOperatorStrictEq:
return BinaryOperator::StrictEq;
case BinASTVariant::BinaryOperatorStrictNeq:
return BinaryOperator::StrictNeq;
case BinASTVariant::BinaryOperatorLessThan:
return BinaryOperator::LessThan;
case BinASTVariant::BinaryOperatorLeqThan:
return BinaryOperator::LeqThan;
case BinASTVariant::BinaryOperatorGreaterThan:
return BinaryOperator::GreaterThan;
case BinASTVariant::BinaryOperatorGeqThan:
return BinaryOperator::GeqThan;
case BinASTVariant::BinaryOperatorIn:
return BinaryOperator::In;
case BinASTVariant::BinaryOperatorInstanceof:
return BinaryOperator::Instanceof;
case BinASTVariant::BinaryOperatorLsh:
return BinaryOperator::Lsh;
case BinASTVariant::BinaryOperatorRsh:
return BinaryOperator::Rsh;
case BinASTVariant::BinaryOperatorUrsh:
return BinaryOperator::Ursh;
case BinASTVariant::BinaryOperatorOrUnaryOperatorPlus:
return BinaryOperator::Plus;
case BinASTVariant::BinaryOperatorOrUnaryOperatorMinus:
return BinaryOperator::Minus;
case BinASTVariant::BinaryOperatorMul:
return BinaryOperator::Mul;
case BinASTVariant::BinaryOperatorDiv:
return BinaryOperator::Div;
case BinASTVariant::BinaryOperatorMod:
return BinaryOperator::Mod;
case BinASTVariant::BinaryOperatorPow:
return BinaryOperator::Pow;
default:
return raiseInvalidVariant("BinaryOperator", variant);
}
}
template <typename Tok>
JS::Result<typename BinASTParser<Tok>::CompoundAssignmentOperator>
BinASTParser<Tok>::parseCompoundAssignmentOperator() {
BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());
switch (variant) {
case BinASTVariant::CompoundAssignmentOperatorPlusAssign:
return CompoundAssignmentOperator::PlusAssign;
case BinASTVariant::CompoundAssignmentOperatorMinusAssign:
return CompoundAssignmentOperator::MinusAssign;
case BinASTVariant::CompoundAssignmentOperatorMulAssign:
return CompoundAssignmentOperator::MulAssign;
case BinASTVariant::CompoundAssignmentOperatorDivAssign:
return CompoundAssignmentOperator::DivAssign;
case BinASTVariant::CompoundAssignmentOperatorModAssign:
return CompoundAssignmentOperator::ModAssign;
case BinASTVariant::CompoundAssignmentOperatorPowAssign:
return CompoundAssignmentOperator::PowAssign;
case BinASTVariant::CompoundAssignmentOperatorLshAssign:
return CompoundAssignmentOperator::LshAssign;
case BinASTVariant::CompoundAssignmentOperatorRshAssign:
return CompoundAssignmentOperator::RshAssign;
case BinASTVariant::CompoundAssignmentOperatorUrshAssign:
return CompoundAssignmentOperator::UrshAssign;
case BinASTVariant::CompoundAssignmentOperatorBitOrAssign:
return CompoundAssignmentOperator::BitOrAssign;
case BinASTVariant::CompoundAssignmentOperatorBitXorAssign:
return CompoundAssignmentOperator::BitXorAssign;
case BinASTVariant::CompoundAssignmentOperatorBitAndAssign:
return CompoundAssignmentOperator::BitAndAssign;
default:
return raiseInvalidVariant("CompoundAssignmentOperator", variant);
}
}
template <typename Tok>
JS::Result<typename BinASTParser<Tok>::UnaryOperator>
BinASTParser<Tok>::parseUnaryOperator() {
BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());
switch (variant) {
case BinASTVariant::BinaryOperatorOrUnaryOperatorPlus:
return UnaryOperator::Plus;
case BinASTVariant::BinaryOperatorOrUnaryOperatorMinus:
return UnaryOperator::Minus;
case BinASTVariant::UnaryOperatorNot:
return UnaryOperator::Not;
case BinASTVariant::UnaryOperatorBitNot:
return UnaryOperator::BitNot;
case BinASTVariant::UnaryOperatorTypeof:
return UnaryOperator::Typeof;
case BinASTVariant::UnaryOperatorVoid:
return UnaryOperator::Void;
case BinASTVariant::UnaryOperatorDelete:
return UnaryOperator::Delete;
default:
return raiseInvalidVariant("UnaryOperator", variant);
}
}
template <typename Tok>
JS::Result<typename BinASTParser<Tok>::UpdateOperator>
BinASTParser<Tok>::parseUpdateOperator() {
BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());
switch (variant) {
case BinASTVariant::UpdateOperatorIncr:
return UpdateOperator::Incr;
case BinASTVariant::UpdateOperatorDecr:
return UpdateOperator::Decr;
default:
return raiseInvalidVariant("UpdateOperator", variant);
}
}
template <typename Tok>
JS::Result<typename BinASTParser<Tok>::VariableDeclarationKind>
BinASTParser<Tok>::parseVariableDeclarationKind() {
BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant());
switch (variant) {
case BinASTVariant::AssertedDeclaredKindOrVariableDeclarationKindVar:
return VariableDeclarationKind::Var;
case BinASTVariant::VariableDeclarationKindLet:
return VariableDeclarationKind::Let;
case BinASTVariant::VariableDeclarationKindConst:
return VariableDeclarationKind::Const;
default:
return raiseInvalidVariant("VariableDeclarationKind", variant);
}
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseArguments() {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, guard));
BINJS_TRY_DECL(result, handler_.newList(ParseNodeKind::Arguments,
tokenizer_->pos(start)));
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseSpreadElementOrExpression());
handler_.addList( result, item);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ListNode*> BinASTParser<Tok>::parseFunctionBody() {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, guard));
BINJS_TRY_DECL(result, handler_.newStatementList(tokenizer_->pos(start)));
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseStatement());
handler_.addStatementToList(result, item);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseListOfAssertedBoundName(
AssertedScopeKind scopeKind) {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, guard));
(void)start;
auto result = Ok();
for (uint32_t i = 0; i < length; ++i) {
MOZ_TRY(parseAssertedBoundName(scopeKind));
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseListOfAssertedDeclaredName(
AssertedScopeKind scopeKind) {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, guard));
(void)start;
auto result = Ok();
for (uint32_t i = 0; i < length; ++i) {
MOZ_TRY(parseAssertedDeclaredName(scopeKind));
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok>
BinASTParser<Tok>::parseListOfAssertedMaybePositionalParameterName(
AssertedScopeKind scopeKind,
MutableHandle<GCVector<JSAtom*>> positionalParams) {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, guard));
(void)start;
auto result = Ok();
for (uint32_t i = 0; i < length; ++i) {
MOZ_TRY(
parseAssertedMaybePositionalParameterName(scopeKind, positionalParams));
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ListNode*> BinASTParser<Tok>::parseListOfDirective() {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, guard));
BINJS_TRY_DECL(result, handler_.newStatementList(tokenizer_->pos(start)));
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseDirective());
handler_.addStatementToList(result, item);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ListNode*> BinASTParser<Tok>::parseListOfObjectProperty() {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, guard));
BINJS_TRY_DECL(result, handler_.newObjectLiteral(start));
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseObjectProperty());
if (!item->isConstant()) result->setHasNonConstInitializer();
result->appendWithoutOrderAssumption(item);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ListNode*>
BinASTParser<Tok>::parseListOfOptionalSpreadElementOrExpression() {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, guard));
BINJS_TRY_DECL(result, handler_.newArrayLiteral(start));
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseOptionalSpreadElementOrExpression());
if (item) {
handler_.addArrayElement(result, item); } else {
BINJS_TRY(handler_.addElision(result, tokenizer_->pos(start)));
}
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ListNode*> BinASTParser<Tok>::parseListOfParameter() {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, guard));
BINJS_TRY_DECL(result, handler_.newParamsBody(tokenizer_->pos(start)));
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseParameter());
handler_.addList( result, item);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ListNode*> BinASTParser<Tok>::parseListOfStatement() {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, guard));
BINJS_TRY_DECL(result, handler_.newStatementList(tokenizer_->pos(start)));
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseStatement());
handler_.addStatementToList(result, item);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ListNode*> BinASTParser<Tok>::parseListOfSwitchCase() {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, guard));
BINJS_TRY_DECL(result, handler_.newStatementList(tokenizer_->pos(start)));
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseSwitchCase());
handler_.addCaseStatementToList(result, item);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ListNode*> BinASTParser<Tok>::parseListOfVariableDeclarator(
ParseNodeKind declarationListKind) {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, guard));
BINJS_TRY_DECL(result, handler_.newDeclarationList(declarationListKind,
tokenizer_->pos(start)));
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseVariableDeclarator());
result->appendWithoutOrderAssumption(item);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalBinding() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
ParseNode* result;
if (kind == BinASTKind::_Null) {
result = nullptr;
} else {
const auto start = tokenizer_->offset();
MOZ_TRY_VAR(result, parseSumBinding(start, kind, fields));
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalBindingIdentifier() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
ParseNode* result;
if (kind == BinASTKind::_Null) {
result = nullptr;
} else if (kind == BinASTKind::BindingIdentifier) {
const auto start = tokenizer_->offset();
MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields));
} else {
return raiseInvalidKind("BindingIdentifier", kind);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<LexicalScopeNode*> BinASTParser<Tok>::parseOptionalCatchClause() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
LexicalScopeNode* result;
if (kind == BinASTKind::_Null) {
result = nullptr;
} else if (kind == BinASTKind::CatchClause) {
const auto start = tokenizer_->offset();
MOZ_TRY_VAR(result, parseInterfaceCatchClause(start, kind, fields));
} else {
return raiseInvalidKind("CatchClause", kind);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalExpression() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
ParseNode* result;
if (kind == BinASTKind::_Null) {
result = nullptr;
} else {
const auto start = tokenizer_->offset();
MOZ_TRY_VAR(result, parseSumExpression(start, kind, fields));
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseOptionalSpreadElementOrExpression() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
ParseNode* result;
if (kind == BinASTKind::_Null) {
result = nullptr;
} else {
const auto start = tokenizer_->offset();
MOZ_TRY_VAR(result, parseSumSpreadElementOrExpression(start, kind, fields));
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalStatement() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
ParseNode* result;
if (kind == BinASTKind::_Null) {
result = nullptr;
} else {
const auto start = tokenizer_->offset();
MOZ_TRY_VAR(result, parseSumStatement(start, kind, fields));
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseOptionalVariableDeclarationOrExpression() {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, guard));
ParseNode* result;
if (kind == BinASTKind::_Null) {
result = nullptr;
} else {
const auto start = tokenizer_->offset();
MOZ_TRY_VAR(result,
parseSumVariableDeclarationOrExpression(start, kind, fields));
}
MOZ_TRY(guard.done());
return result;
}
template class BinASTParser<BinASTTokenReaderMultipart>;
} }