fune/js/src/frontend/BinASTParser.cpp

5330 lines
186 KiB
C++

// This file was autogenerated by binjs_generate_spidermonkey,
// please DO NOT EDIT BY HAND.
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// To generate this file, see the documentation in
// js/src/frontend/binast/README.md.
#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/BinASTTokenReaderContext.h"
#include "frontend/BinASTTokenReaderMultipart.h"
#include "frontend/FullParseHandler.h"
#include "frontend/ParseNode.h"
#include "frontend/Parser.h"
#include "frontend/SharedContext.h"
#include "js/RegExpFlags.h" // JS::RegExpFlag, JS::RegExpFlags
#include "vm/RegExpObject.h"
#include "frontend/ParseContext-inl.h"
using JS::RegExpFlag;
using JS::RegExpFlags;
namespace js {
namespace frontend {
// Compare a bunch of `uint8_t` values (as returned by the tokenizer_) with
// a string literal (and ONLY a string literal).
template <typename Tok, size_t N>
bool operator==(const typename Tok::Chars& left, const char (&right)[N]) {
return Tok::equals(left, right);
}
// ----- Sums of interfaces (autogenerated, by lexicographical order)
// Sums of sums are flattened.
/*
AssertedMaybePositionalParameterName ::= AssertedParameterName
AssertedPositionalParameterName
AssertedRestParameterName
*/
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseAssertedMaybePositionalParameterName(
AssertedScopeKind scopeKind,
MutableHandle<GCVector<JSAtom*>> positionalParams, const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
BINJS_MOZ_TRY_DECL(
result, parseSumAssertedMaybePositionalParameterName(
start, kind, fields, scopeKind, positionalParams, context));
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, const Context& context) {
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,
context));
break;
case BinASTKind::AssertedRestParameterName:
return raiseError(
"FIXME: Not implemented yet in this preview release "
"(AssertedRestParameterName)");
default:
return raiseInvalidKind("AssertedMaybePositionalParameterName", kind);
}
return result;
}
/*
AssignmentTarget ::= ArrayAssignmentTarget
AssignmentTargetIdentifier
ComputedMemberAssignmentTarget
ObjectAssignmentTarget
StaticMemberAssignmentTarget
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseAssignmentTarget(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
BINJS_MOZ_TRY_DECL(result,
parseSumAssignmentTarget(start, kind, fields, context));
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,
const Context& context) {
ParseNode* result;
switch (kind) {
case BinASTKind::ArrayAssignmentTarget:
MOZ_TRY_VAR(result, parseInterfaceArrayAssignmentTarget(start, kind,
fields, context));
break;
case BinASTKind::AssignmentTargetIdentifier:
MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(
start, kind, fields, context));
break;
case BinASTKind::ComputedMemberAssignmentTarget:
MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(
start, kind, fields, context));
break;
case BinASTKind::ObjectAssignmentTarget:
MOZ_TRY_VAR(result, parseInterfaceObjectAssignmentTarget(
start, kind, fields, context));
break;
case BinASTKind::StaticMemberAssignmentTarget:
MOZ_TRY_VAR(result, parseInterfaceStaticMemberAssignmentTarget(
start, kind, fields, context));
break;
default:
return raiseInvalidKind("AssignmentTarget", kind);
}
return result;
}
/*
Binding ::= ArrayBinding
BindingIdentifier
ObjectBinding
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseBinding(const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
BINJS_MOZ_TRY_DECL(result, parseSumBinding(start, kind, fields, context));
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,
const Context& context) {
ParseNode* result;
switch (kind) {
case BinASTKind::ArrayBinding:
MOZ_TRY_VAR(result,
parseInterfaceArrayBinding(start, kind, fields, context));
break;
case BinASTKind::BindingIdentifier:
MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields,
context));
break;
case BinASTKind::ObjectBinding:
MOZ_TRY_VAR(result,
parseInterfaceObjectBinding(start, kind, fields, context));
break;
default:
return raiseInvalidKind("Binding", kind);
}
return result;
}
/*
Expression ::= ArrayExpression
AssignmentExpression
AwaitExpression
BinaryExpression
CallExpression
ClassExpression
CompoundAssignmentExpression
ComputedMemberExpression
ConditionalExpression
EagerArrowExpressionWithExpression
EagerArrowExpressionWithFunctionBody
EagerFunctionExpression
IdentifierExpression
LazyArrowExpressionWithExpression
LazyArrowExpressionWithFunctionBody
LazyFunctionExpression
LiteralBooleanExpression
LiteralInfinityExpression
LiteralNullExpression
LiteralNumericExpression
LiteralRegExpExpression
LiteralStringExpression
NewExpression
NewTargetExpression
ObjectExpression
StaticMemberExpression
TemplateExpression
ThisExpression
UnaryExpression
UpdateExpression
YieldExpression
YieldStarExpression
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseExpression(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
BINJS_MOZ_TRY_DECL(result, parseSumExpression(start, kind, fields, context));
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,
const Context& context) {
ParseNode* result;
switch (kind) {
case BinASTKind::ArrayExpression:
MOZ_TRY_VAR(result,
parseInterfaceArrayExpression(start, kind, fields, context));
break;
case BinASTKind::AssignmentExpression:
MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind,
fields, context));
break;
case BinASTKind::AwaitExpression:
MOZ_TRY_VAR(result,
parseInterfaceAwaitExpression(start, kind, fields, context));
break;
case BinASTKind::BinaryExpression:
MOZ_TRY_VAR(result,
parseInterfaceBinaryExpression(start, kind, fields, context));
break;
case BinASTKind::CallExpression:
MOZ_TRY_VAR(result,
parseInterfaceCallExpression(start, kind, fields, context));
break;
case BinASTKind::ClassExpression:
MOZ_TRY_VAR(result,
parseInterfaceClassExpression(start, kind, fields, context));
break;
case BinASTKind::CompoundAssignmentExpression:
MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(
start, kind, fields, context));
break;
case BinASTKind::ComputedMemberExpression:
MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(
start, kind, fields, context));
break;
case BinASTKind::ConditionalExpression:
MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind,
fields, context));
break;
case BinASTKind::EagerArrowExpressionWithExpression:
MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(
start, kind, fields, context));
break;
case BinASTKind::EagerArrowExpressionWithFunctionBody:
MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(
start, kind, fields, context));
break;
case BinASTKind::EagerFunctionExpression:
MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(
start, kind, fields, context));
break;
case BinASTKind::IdentifierExpression:
MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind,
fields, context));
break;
case BinASTKind::LazyArrowExpressionWithExpression:
MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(
start, kind, fields, context));
break;
case BinASTKind::LazyArrowExpressionWithFunctionBody:
MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(
start, kind, fields, context));
break;
case BinASTKind::LazyFunctionExpression:
MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralBooleanExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralInfinityExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralNullExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind,
fields, context));
break;
case BinASTKind::LiteralNumericExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralRegExpExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralStringExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(
start, kind, fields, context));
break;
case BinASTKind::NewExpression:
MOZ_TRY_VAR(result,
parseInterfaceNewExpression(start, kind, fields, context));
break;
case BinASTKind::NewTargetExpression:
MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields,
context));
break;
case BinASTKind::ObjectExpression:
MOZ_TRY_VAR(result,
parseInterfaceObjectExpression(start, kind, fields, context));
break;
case BinASTKind::StaticMemberExpression:
MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(
start, kind, fields, context));
break;
case BinASTKind::TemplateExpression:
MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields,
context));
break;
case BinASTKind::ThisExpression:
MOZ_TRY_VAR(result,
parseInterfaceThisExpression(start, kind, fields, context));
break;
case BinASTKind::UnaryExpression:
MOZ_TRY_VAR(result,
parseInterfaceUnaryExpression(start, kind, fields, context));
break;
case BinASTKind::UpdateExpression:
MOZ_TRY_VAR(result,
parseInterfaceUpdateExpression(start, kind, fields, context));
break;
case BinASTKind::YieldExpression:
MOZ_TRY_VAR(result,
parseInterfaceYieldExpression(start, kind, fields, context));
break;
case BinASTKind::YieldStarExpression:
MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields,
context));
break;
default:
return raiseInvalidKind("Expression", kind);
}
return result;
}
/*
ExpressionOrSuper ::= ArrayExpression
AssignmentExpression
AwaitExpression
BinaryExpression
CallExpression
ClassExpression
CompoundAssignmentExpression
ComputedMemberExpression
ConditionalExpression
EagerArrowExpressionWithExpression
EagerArrowExpressionWithFunctionBody
EagerFunctionExpression
IdentifierExpression
LazyArrowExpressionWithExpression
LazyArrowExpressionWithFunctionBody
LazyFunctionExpression
LiteralBooleanExpression
LiteralInfinityExpression
LiteralNullExpression
LiteralNumericExpression
LiteralRegExpExpression
LiteralStringExpression
NewExpression
NewTargetExpression
ObjectExpression
StaticMemberExpression
Super
TemplateExpression
ThisExpression
UnaryExpression
UpdateExpression
YieldExpression
YieldStarExpression
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseExpressionOrSuper(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
BINJS_MOZ_TRY_DECL(result,
parseSumExpressionOrSuper(start, kind, fields, context));
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,
const Context& context) {
ParseNode* result;
switch (kind) {
case BinASTKind::ArrayExpression:
MOZ_TRY_VAR(result,
parseInterfaceArrayExpression(start, kind, fields, context));
break;
case BinASTKind::AssignmentExpression:
MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind,
fields, context));
break;
case BinASTKind::AwaitExpression:
MOZ_TRY_VAR(result,
parseInterfaceAwaitExpression(start, kind, fields, context));
break;
case BinASTKind::BinaryExpression:
MOZ_TRY_VAR(result,
parseInterfaceBinaryExpression(start, kind, fields, context));
break;
case BinASTKind::CallExpression:
MOZ_TRY_VAR(result,
parseInterfaceCallExpression(start, kind, fields, context));
break;
case BinASTKind::ClassExpression:
MOZ_TRY_VAR(result,
parseInterfaceClassExpression(start, kind, fields, context));
break;
case BinASTKind::CompoundAssignmentExpression:
MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(
start, kind, fields, context));
break;
case BinASTKind::ComputedMemberExpression:
MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(
start, kind, fields, context));
break;
case BinASTKind::ConditionalExpression:
MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind,
fields, context));
break;
case BinASTKind::EagerArrowExpressionWithExpression:
MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(
start, kind, fields, context));
break;
case BinASTKind::EagerArrowExpressionWithFunctionBody:
MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(
start, kind, fields, context));
break;
case BinASTKind::EagerFunctionExpression:
MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(
start, kind, fields, context));
break;
case BinASTKind::IdentifierExpression:
MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind,
fields, context));
break;
case BinASTKind::LazyArrowExpressionWithExpression:
MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(
start, kind, fields, context));
break;
case BinASTKind::LazyArrowExpressionWithFunctionBody:
MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(
start, kind, fields, context));
break;
case BinASTKind::LazyFunctionExpression:
MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralBooleanExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralInfinityExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralNullExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind,
fields, context));
break;
case BinASTKind::LiteralNumericExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralRegExpExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralStringExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(
start, kind, fields, context));
break;
case BinASTKind::NewExpression:
MOZ_TRY_VAR(result,
parseInterfaceNewExpression(start, kind, fields, context));
break;
case BinASTKind::NewTargetExpression:
MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields,
context));
break;
case BinASTKind::ObjectExpression:
MOZ_TRY_VAR(result,
parseInterfaceObjectExpression(start, kind, fields, context));
break;
case BinASTKind::StaticMemberExpression:
MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(
start, kind, fields, context));
break;
case BinASTKind::Super:
MOZ_TRY_VAR(result, parseInterfaceSuper(start, kind, fields, context));
break;
case BinASTKind::TemplateExpression:
MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields,
context));
break;
case BinASTKind::ThisExpression:
MOZ_TRY_VAR(result,
parseInterfaceThisExpression(start, kind, fields, context));
break;
case BinASTKind::UnaryExpression:
MOZ_TRY_VAR(result,
parseInterfaceUnaryExpression(start, kind, fields, context));
break;
case BinASTKind::UpdateExpression:
MOZ_TRY_VAR(result,
parseInterfaceUpdateExpression(start, kind, fields, context));
break;
case BinASTKind::YieldExpression:
MOZ_TRY_VAR(result,
parseInterfaceYieldExpression(start, kind, fields, context));
break;
case BinASTKind::YieldStarExpression:
MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields,
context));
break;
default:
return raiseInvalidKind("ExpressionOrSuper", kind);
}
return result;
}
/*
ForInOfBindingOrAssignmentTarget ::= ArrayAssignmentTarget
AssignmentTargetIdentifier
ComputedMemberAssignmentTarget
ForInOfBinding
ObjectAssignmentTarget
StaticMemberAssignmentTarget
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseForInOfBindingOrAssignmentTarget(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
BINJS_MOZ_TRY_DECL(result, parseSumForInOfBindingOrAssignmentTarget(
start, kind, fields, context));
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,
const Context& context) {
ParseNode* result;
switch (kind) {
case BinASTKind::ArrayAssignmentTarget:
MOZ_TRY_VAR(result, parseInterfaceArrayAssignmentTarget(start, kind,
fields, context));
break;
case BinASTKind::AssignmentTargetIdentifier:
MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(
start, kind, fields, context));
break;
case BinASTKind::ComputedMemberAssignmentTarget:
MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(
start, kind, fields, context));
break;
case BinASTKind::ForInOfBinding:
MOZ_TRY_VAR(result,
parseInterfaceForInOfBinding(start, kind, fields, context));
break;
case BinASTKind::ObjectAssignmentTarget:
MOZ_TRY_VAR(result, parseInterfaceObjectAssignmentTarget(
start, kind, fields, context));
break;
case BinASTKind::StaticMemberAssignmentTarget:
MOZ_TRY_VAR(result, parseInterfaceStaticMemberAssignmentTarget(
start, kind, fields, context));
break;
default:
return raiseInvalidKind("ForInOfBindingOrAssignmentTarget", kind);
}
return result;
}
/*
ObjectProperty ::= DataProperty
EagerGetter
EagerMethod
EagerSetter
LazyGetter
LazyMethod
LazySetter
ShorthandProperty
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseObjectProperty(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
BINJS_MOZ_TRY_DECL(result,
parseSumObjectProperty(start, kind, fields, context));
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,
const Context& context) {
ParseNode* result;
switch (kind) {
case BinASTKind::DataProperty:
MOZ_TRY_VAR(result,
parseInterfaceDataProperty(start, kind, fields, context));
break;
case BinASTKind::EagerGetter:
MOZ_TRY_VAR(result,
parseInterfaceEagerGetter(start, kind, fields, context));
break;
case BinASTKind::EagerMethod:
MOZ_TRY_VAR(result,
parseInterfaceEagerMethod(start, kind, fields, context));
break;
case BinASTKind::EagerSetter:
MOZ_TRY_VAR(result,
parseInterfaceEagerSetter(start, kind, fields, context));
break;
case BinASTKind::LazyGetter:
MOZ_TRY_VAR(result,
parseInterfaceLazyGetter(start, kind, fields, context));
break;
case BinASTKind::LazyMethod:
MOZ_TRY_VAR(result,
parseInterfaceLazyMethod(start, kind, fields, context));
break;
case BinASTKind::LazySetter:
MOZ_TRY_VAR(result,
parseInterfaceLazySetter(start, kind, fields, context));
break;
case BinASTKind::ShorthandProperty:
MOZ_TRY_VAR(result, parseInterfaceShorthandProperty(start, kind, fields,
context));
break;
default:
return raiseInvalidKind("ObjectProperty", kind);
}
return result;
}
/*
Parameter ::= ArrayBinding
BindingIdentifier
BindingWithInitializer
ObjectBinding
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseParameter(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
BINJS_MOZ_TRY_DECL(result, parseSumParameter(start, kind, fields, context));
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,
const Context& context) {
ParseNode* result;
switch (kind) {
case BinASTKind::ArrayBinding:
MOZ_TRY_VAR(result,
parseInterfaceArrayBinding(start, kind, fields, context));
break;
case BinASTKind::BindingIdentifier:
MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields,
context));
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, context));
break;
case BinASTKind::ObjectBinding:
MOZ_TRY_VAR(result,
parseInterfaceObjectBinding(start, kind, fields, context));
break;
default:
return raiseInvalidKind("Parameter", kind);
}
return result;
}
/*
Program ::= Module
Script
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseProgram(const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
BINJS_MOZ_TRY_DECL(result, parseSumProgram(start, kind, fields, context));
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,
const Context& context) {
ParseNode* result;
switch (kind) {
case BinASTKind::Module:
MOZ_TRY_VAR(result, parseInterfaceModule(start, kind, fields, context));
break;
case BinASTKind::Script:
MOZ_TRY_VAR(result, parseInterfaceScript(start, kind, fields, context));
break;
default:
return raiseInvalidKind("Program", kind);
}
return result;
}
/*
PropertyName ::= ComputedPropertyName
LiteralPropertyName
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parsePropertyName(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
BINJS_MOZ_TRY_DECL(result,
parseSumPropertyName(start, kind, fields, context));
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,
const Context& context) {
ParseNode* result;
switch (kind) {
case BinASTKind::ComputedPropertyName:
MOZ_TRY_VAR(result, parseInterfaceComputedPropertyName(start, kind,
fields, context));
break;
case BinASTKind::LiteralPropertyName:
MOZ_TRY_VAR(result, parseInterfaceLiteralPropertyName(start, kind, fields,
context));
break;
default:
return raiseInvalidKind("PropertyName", kind);
}
return result;
}
/*
SimpleAssignmentTarget ::= AssignmentTargetIdentifier
ComputedMemberAssignmentTarget
StaticMemberAssignmentTarget
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseSimpleAssignmentTarget(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
BINJS_MOZ_TRY_DECL(
result, parseSumSimpleAssignmentTarget(start, kind, fields, context));
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,
const Context& context) {
ParseNode* result;
switch (kind) {
case BinASTKind::AssignmentTargetIdentifier:
MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(
start, kind, fields, context));
break;
case BinASTKind::ComputedMemberAssignmentTarget:
MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(
start, kind, fields, context));
break;
case BinASTKind::StaticMemberAssignmentTarget:
MOZ_TRY_VAR(result, parseInterfaceStaticMemberAssignmentTarget(
start, kind, fields, context));
break;
default:
return raiseInvalidKind("SimpleAssignmentTarget", kind);
}
return result;
}
/*
SpreadElementOrExpression ::= ArrayExpression
AssignmentExpression
AwaitExpression
BinaryExpression
CallExpression
ClassExpression
CompoundAssignmentExpression
ComputedMemberExpression
ConditionalExpression
EagerArrowExpressionWithExpression
EagerArrowExpressionWithFunctionBody
EagerFunctionExpression
IdentifierExpression
LazyArrowExpressionWithExpression
LazyArrowExpressionWithFunctionBody
LazyFunctionExpression
LiteralBooleanExpression
LiteralInfinityExpression
LiteralNullExpression
LiteralNumericExpression
LiteralRegExpExpression
LiteralStringExpression
NewExpression
NewTargetExpression
ObjectExpression
SpreadElement
StaticMemberExpression
TemplateExpression
ThisExpression
UnaryExpression
UpdateExpression
YieldExpression
YieldStarExpression
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseSpreadElementOrExpression(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
BINJS_MOZ_TRY_DECL(
result, parseSumSpreadElementOrExpression(start, kind, fields, context));
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,
const Context& context) {
ParseNode* result;
switch (kind) {
case BinASTKind::ArrayExpression:
MOZ_TRY_VAR(result,
parseInterfaceArrayExpression(start, kind, fields, context));
break;
case BinASTKind::AssignmentExpression:
MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind,
fields, context));
break;
case BinASTKind::AwaitExpression:
MOZ_TRY_VAR(result,
parseInterfaceAwaitExpression(start, kind, fields, context));
break;
case BinASTKind::BinaryExpression:
MOZ_TRY_VAR(result,
parseInterfaceBinaryExpression(start, kind, fields, context));
break;
case BinASTKind::CallExpression:
MOZ_TRY_VAR(result,
parseInterfaceCallExpression(start, kind, fields, context));
break;
case BinASTKind::ClassExpression:
MOZ_TRY_VAR(result,
parseInterfaceClassExpression(start, kind, fields, context));
break;
case BinASTKind::CompoundAssignmentExpression:
MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(
start, kind, fields, context));
break;
case BinASTKind::ComputedMemberExpression:
MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(
start, kind, fields, context));
break;
case BinASTKind::ConditionalExpression:
MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind,
fields, context));
break;
case BinASTKind::EagerArrowExpressionWithExpression:
MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(
start, kind, fields, context));
break;
case BinASTKind::EagerArrowExpressionWithFunctionBody:
MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(
start, kind, fields, context));
break;
case BinASTKind::EagerFunctionExpression:
MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(
start, kind, fields, context));
break;
case BinASTKind::IdentifierExpression:
MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind,
fields, context));
break;
case BinASTKind::LazyArrowExpressionWithExpression:
MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(
start, kind, fields, context));
break;
case BinASTKind::LazyArrowExpressionWithFunctionBody:
MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(
start, kind, fields, context));
break;
case BinASTKind::LazyFunctionExpression:
MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralBooleanExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralInfinityExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralNullExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind,
fields, context));
break;
case BinASTKind::LiteralNumericExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralRegExpExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralStringExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(
start, kind, fields, context));
break;
case BinASTKind::NewExpression:
MOZ_TRY_VAR(result,
parseInterfaceNewExpression(start, kind, fields, context));
break;
case BinASTKind::NewTargetExpression:
MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields,
context));
break;
case BinASTKind::ObjectExpression:
MOZ_TRY_VAR(result,
parseInterfaceObjectExpression(start, kind, fields, context));
break;
case BinASTKind::SpreadElement:
MOZ_TRY_VAR(result,
parseInterfaceSpreadElement(start, kind, fields, context));
break;
case BinASTKind::StaticMemberExpression:
MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(
start, kind, fields, context));
break;
case BinASTKind::TemplateExpression:
MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields,
context));
break;
case BinASTKind::ThisExpression:
MOZ_TRY_VAR(result,
parseInterfaceThisExpression(start, kind, fields, context));
break;
case BinASTKind::UnaryExpression:
MOZ_TRY_VAR(result,
parseInterfaceUnaryExpression(start, kind, fields, context));
break;
case BinASTKind::UpdateExpression:
MOZ_TRY_VAR(result,
parseInterfaceUpdateExpression(start, kind, fields, context));
break;
case BinASTKind::YieldExpression:
MOZ_TRY_VAR(result,
parseInterfaceYieldExpression(start, kind, fields, context));
break;
case BinASTKind::YieldStarExpression:
MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields,
context));
break;
default:
return raiseInvalidKind("SpreadElementOrExpression", kind);
}
return result;
}
/*
Statement ::= Block
BreakStatement
ClassDeclaration
ContinueStatement
DebuggerStatement
DoWhileStatement
EagerFunctionDeclaration
EmptyStatement
ExpressionStatement
ForInStatement
ForOfStatement
ForStatement
IfStatement
LabelledStatement
LazyFunctionDeclaration
ReturnStatement
SwitchStatement
SwitchStatementWithDefault
ThrowStatement
TryCatchStatement
TryFinallyStatement
VariableDeclaration
WhileStatement
WithStatement
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseStatement(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
BINJS_MOZ_TRY_DECL(result, parseSumStatement(start, kind, fields, context));
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,
const Context& context) {
ParseNode* result;
switch (kind) {
case BinASTKind::Block:
MOZ_TRY_VAR(result, parseInterfaceBlock(start, kind, fields, context));
break;
case BinASTKind::BreakStatement:
MOZ_TRY_VAR(result,
parseInterfaceBreakStatement(start, kind, fields, context));
break;
case BinASTKind::ClassDeclaration:
MOZ_TRY_VAR(result,
parseInterfaceClassDeclaration(start, kind, fields, context));
break;
case BinASTKind::ContinueStatement:
MOZ_TRY_VAR(result, parseInterfaceContinueStatement(start, kind, fields,
context));
break;
case BinASTKind::DebuggerStatement:
MOZ_TRY_VAR(result, parseInterfaceDebuggerStatement(start, kind, fields,
context));
break;
case BinASTKind::DoWhileStatement:
MOZ_TRY_VAR(result,
parseInterfaceDoWhileStatement(start, kind, fields, context));
break;
case BinASTKind::EagerFunctionDeclaration:
MOZ_TRY_VAR(result, parseInterfaceEagerFunctionDeclaration(
start, kind, fields, context));
break;
case BinASTKind::EmptyStatement:
MOZ_TRY_VAR(result,
parseInterfaceEmptyStatement(start, kind, fields, context));
break;
case BinASTKind::ExpressionStatement:
MOZ_TRY_VAR(result, parseInterfaceExpressionStatement(start, kind, fields,
context));
break;
case BinASTKind::ForInStatement:
MOZ_TRY_VAR(result,
parseInterfaceForInStatement(start, kind, fields, context));
break;
case BinASTKind::ForOfStatement:
MOZ_TRY_VAR(result,
parseInterfaceForOfStatement(start, kind, fields, context));
break;
case BinASTKind::ForStatement:
MOZ_TRY_VAR(result,
parseInterfaceForStatement(start, kind, fields, context));
break;
case BinASTKind::IfStatement:
MOZ_TRY_VAR(result,
parseInterfaceIfStatement(start, kind, fields, context));
break;
case BinASTKind::LabelledStatement:
MOZ_TRY_VAR(result, parseInterfaceLabelledStatement(start, kind, fields,
context));
break;
case BinASTKind::LazyFunctionDeclaration:
MOZ_TRY_VAR(result, parseInterfaceLazyFunctionDeclaration(
start, kind, fields, context));
break;
case BinASTKind::ReturnStatement:
MOZ_TRY_VAR(result,
parseInterfaceReturnStatement(start, kind, fields, context));
break;
case BinASTKind::SwitchStatement:
MOZ_TRY_VAR(result,
parseInterfaceSwitchStatement(start, kind, fields, context));
break;
case BinASTKind::SwitchStatementWithDefault:
MOZ_TRY_VAR(result, parseInterfaceSwitchStatementWithDefault(
start, kind, fields, context));
break;
case BinASTKind::ThrowStatement:
MOZ_TRY_VAR(result,
parseInterfaceThrowStatement(start, kind, fields, context));
break;
case BinASTKind::TryCatchStatement:
MOZ_TRY_VAR(result, parseInterfaceTryCatchStatement(start, kind, fields,
context));
break;
case BinASTKind::TryFinallyStatement:
MOZ_TRY_VAR(result, parseInterfaceTryFinallyStatement(start, kind, fields,
context));
break;
case BinASTKind::VariableDeclaration:
MOZ_TRY_VAR(result, parseInterfaceVariableDeclaration(start, kind, fields,
context));
break;
case BinASTKind::WhileStatement:
MOZ_TRY_VAR(result,
parseInterfaceWhileStatement(start, kind, fields, context));
break;
case BinASTKind::WithStatement:
MOZ_TRY_VAR(result,
parseInterfaceWithStatement(start, kind, fields, context));
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,
const Context& context) {
ParseNode* result;
switch (kind) {
case BinASTKind::ArrayExpression:
MOZ_TRY_VAR(result,
parseInterfaceArrayExpression(start, kind, fields, context));
break;
case BinASTKind::AssignmentExpression:
MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind,
fields, context));
break;
case BinASTKind::AwaitExpression:
MOZ_TRY_VAR(result,
parseInterfaceAwaitExpression(start, kind, fields, context));
break;
case BinASTKind::BinaryExpression:
MOZ_TRY_VAR(result,
parseInterfaceBinaryExpression(start, kind, fields, context));
break;
case BinASTKind::CallExpression:
MOZ_TRY_VAR(result,
parseInterfaceCallExpression(start, kind, fields, context));
break;
case BinASTKind::ClassExpression:
MOZ_TRY_VAR(result,
parseInterfaceClassExpression(start, kind, fields, context));
break;
case BinASTKind::CompoundAssignmentExpression:
MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(
start, kind, fields, context));
break;
case BinASTKind::ComputedMemberExpression:
MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(
start, kind, fields, context));
break;
case BinASTKind::ConditionalExpression:
MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind,
fields, context));
break;
case BinASTKind::EagerArrowExpressionWithExpression:
MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(
start, kind, fields, context));
break;
case BinASTKind::EagerArrowExpressionWithFunctionBody:
MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(
start, kind, fields, context));
break;
case BinASTKind::EagerFunctionExpression:
MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(
start, kind, fields, context));
break;
case BinASTKind::IdentifierExpression:
MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind,
fields, context));
break;
case BinASTKind::LazyArrowExpressionWithExpression:
MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(
start, kind, fields, context));
break;
case BinASTKind::LazyArrowExpressionWithFunctionBody:
MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(
start, kind, fields, context));
break;
case BinASTKind::LazyFunctionExpression:
MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralBooleanExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralInfinityExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralNullExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind,
fields, context));
break;
case BinASTKind::LiteralNumericExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralRegExpExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(
start, kind, fields, context));
break;
case BinASTKind::LiteralStringExpression:
MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(
start, kind, fields, context));
break;
case BinASTKind::NewExpression:
MOZ_TRY_VAR(result,
parseInterfaceNewExpression(start, kind, fields, context));
break;
case BinASTKind::NewTargetExpression:
MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields,
context));
break;
case BinASTKind::ObjectExpression:
MOZ_TRY_VAR(result,
parseInterfaceObjectExpression(start, kind, fields, context));
break;
case BinASTKind::StaticMemberExpression:
MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(
start, kind, fields, context));
break;
case BinASTKind::TemplateExpression:
MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields,
context));
break;
case BinASTKind::ThisExpression:
MOZ_TRY_VAR(result,
parseInterfaceThisExpression(start, kind, fields, context));
break;
case BinASTKind::UnaryExpression:
MOZ_TRY_VAR(result,
parseInterfaceUnaryExpression(start, kind, fields, context));
break;
case BinASTKind::UpdateExpression:
MOZ_TRY_VAR(result,
parseInterfaceUpdateExpression(start, kind, fields, context));
break;
case BinASTKind::VariableDeclaration:
MOZ_TRY_VAR(result, parseInterfaceVariableDeclaration(start, kind, fields,
context));
break;
case BinASTKind::YieldExpression:
MOZ_TRY_VAR(result,
parseInterfaceYieldExpression(start, kind, fields, context));
break;
case BinASTKind::YieldStarExpression:
MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields,
context));
break;
default:
return raiseInvalidKind("VariableDeclarationOrExpression", kind);
}
return result;
}
// ----- Interfaces (autogenerated, by lexicographical order)
// When fields have a non-trivial type, implementation is deanonymized and
// delegated to another parser.
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceArrayAssignmentTarget(
const size_t start, const BinASTKind kind, const BinASTFields& fields,
const Context& context) {
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,
const Context& context) {
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::ArrayExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Elements};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(
elements, parseListOfOptionalSpreadElementOrExpression(fieldContext++));
if (elements->empty()) {
elements->setHasNonConstInitializer();
}
auto result = elements;
return result;
}
/*
interface AssertedBlockScope : Node {
FrozenArray<AssertedDeclaredName> declaredNames;
bool hasDirectEval;
}
*/
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseAssertedBlockScope(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
if (kind != BinASTKind::AssertedBlockScope) {
return raiseInvalidKind("AssertedBlockScope", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(
result, parseInterfaceAssertedBlockScope(start, kind, fields, context));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::AssertedBlockScope);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::DeclaredNames,
BinASTField::HasDirectEval};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
const auto scopeKind = AssertedScopeKind::Block;
MOZ_TRY(parseListOfAssertedDeclaredName(scopeKind, fieldContext++));
BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool(fieldContext++));
if (hasDirectEval) {
pc_->sc()->setHasDirectEval();
pc_->sc()->setBindingsAccessedDynamically();
}
if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
// In non-strict mode code, direct calls to eval can
// add variables to the call object.
pc_->functionBox()->setHasExtensibleScope();
}
auto result = Ok();
return result;
}
/*
interface AssertedBoundName : Node {
[IdentifierName] string name;
bool isCaptured;
}
*/
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseAssertedBoundName(
AssertedScopeKind scopeKind, const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
if (kind != BinASTKind::AssertedBoundName) {
return raiseInvalidKind("AssertedBoundName", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedBoundName(
start, kind, fields, scopeKind, context));
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, const Context& context) {
MOZ_ASSERT(kind == BinASTKind::AssertedBoundName);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Name,
BinASTField::IsCaptured};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
const bool allowDuplicateName = false;
RootedAtom name(cx_);
MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(fieldContext++));
BINJS_MOZ_TRY_DECL(isCaptured, tokenizer_->readBool(fieldContext++));
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;
}
/*
interface AssertedBoundNamesScope : Node {
FrozenArray<AssertedBoundName> boundNames;
bool hasDirectEval;
}
*/
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseAssertedBoundNamesScope(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
if (kind != BinASTKind::AssertedBoundNamesScope) {
return raiseInvalidKind("AssertedBoundNamesScope", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedBoundNamesScope(
start, kind, fields, context));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::AssertedBoundNamesScope);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::BoundNames,
BinASTField::HasDirectEval};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
const auto scopeKind = AssertedScopeKind::Catch;
MOZ_TRY(parseListOfAssertedBoundName(scopeKind, fieldContext++));
BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool(fieldContext++));
if (hasDirectEval) {
pc_->sc()->setHasDirectEval();
pc_->sc()->setBindingsAccessedDynamically();
}
if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
// In non-strict mode code, direct calls to eval can
// add variables to the call object.
pc_->functionBox()->setHasExtensibleScope();
}
auto result = Ok();
return result;
}
/*
interface AssertedDeclaredName : Node {
[IdentifierName] string name;
AssertedDeclaredKind kind;
bool isCaptured;
}
*/
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseAssertedDeclaredName(
AssertedScopeKind scopeKind, const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
if (kind != BinASTKind::AssertedDeclaredName) {
return raiseInvalidKind("AssertedDeclaredName", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedDeclaredName(
start, kind, fields, scopeKind, context));
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, const Context& context) {
MOZ_ASSERT(kind == BinASTKind::AssertedDeclaredName);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[3] = {BinASTField::Name, BinASTField::Kind,
BinASTField::IsCaptured};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
const bool allowDuplicateName = false;
RootedAtom name(cx_);
MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(fieldContext++));
BINJS_MOZ_TRY_DECL(kind_, parseAssertedDeclaredKind(fieldContext++));
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(fieldContext++));
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;
}
/*
interface AssertedParameterScope : Node {
FrozenArray<AssertedMaybePositionalParameterName> paramNames;
bool hasDirectEval;
bool isSimpleParameterList;
}
*/
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseAssertedParameterScope(
MutableHandle<GCVector<JSAtom*>> positionalParams, const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
if (kind != BinASTKind::AssertedParameterScope) {
return raiseInvalidKind("AssertedParameterScope", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(
result, parseInterfaceAssertedParameterScope(start, kind, fields,
positionalParams, context));
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, const Context& context) {
MOZ_ASSERT(kind == BinASTKind::AssertedParameterScope);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[3] = {BinASTField::ParamNames,
BinASTField::HasDirectEval,
BinASTField::IsSimpleParameterList};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
const auto scopeKind = AssertedScopeKind::Parameter;
MOZ_TRY(parseListOfAssertedMaybePositionalParameterName(
scopeKind, positionalParams, fieldContext++));
BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool(fieldContext++));
if (hasDirectEval) {
pc_->sc()->setHasDirectEval();
pc_->sc()->setBindingsAccessedDynamically();
}
BINJS_MOZ_TRY_DECL(isSimpleParameterList,
tokenizer_->readBool(fieldContext++));
(void)isSimpleParameterList;
if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
// In non-strict mode code, direct calls to eval can
// add variables to the call object.
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, const Context& context) {
MOZ_ASSERT(kind == BinASTKind::AssertedPositionalParameterName);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[3] = {BinASTField::Index, BinASTField::Name,
BinASTField::IsCaptured};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
bool allowDuplicateName = !pc_->sc()->strict();
BINJS_MOZ_TRY_DECL(index, tokenizer_->readUnsignedLong(fieldContext++));
RootedAtom name(cx_);
MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(fieldContext++));
// `positionalParams` vector can be shorter than the actual
// parameter length. Resize on demand.
// (see also ListOfAssertedMaybePositionalParameterName)
size_t prevLength = positionalParams.get().length();
if (index >= prevLength) {
// This is implementation limit, which is not in the spec.
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(fieldContext++));
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;
}
/*
interface AssertedScriptGlobalScope : Node {
FrozenArray<AssertedDeclaredName> declaredNames;
bool hasDirectEval;
}
*/
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseAssertedScriptGlobalScope(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
if (kind != BinASTKind::AssertedScriptGlobalScope) {
return raiseInvalidKind("AssertedScriptGlobalScope", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result, parseInterfaceAssertedScriptGlobalScope(
start, kind, fields, context));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::AssertedScriptGlobalScope);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::DeclaredNames,
BinASTField::HasDirectEval};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
const auto scopeKind = AssertedScopeKind::Global;
MOZ_TRY(parseListOfAssertedDeclaredName(scopeKind, fieldContext++));
BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool(fieldContext++));
if (hasDirectEval) {
pc_->sc()->setHasDirectEval();
pc_->sc()->setBindingsAccessedDynamically();
}
if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
// In non-strict mode code, direct calls to eval can
// add variables to the call object.
pc_->functionBox()->setHasExtensibleScope();
}
auto result = Ok();
return result;
}
/*
interface AssertedVarScope : Node {
FrozenArray<AssertedDeclaredName> declaredNames;
bool hasDirectEval;
}
*/
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseAssertedVarScope(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
if (kind != BinASTKind::AssertedVarScope) {
return raiseInvalidKind("AssertedVarScope", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(
result, parseInterfaceAssertedVarScope(start, kind, fields, context));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::AssertedVarScope);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::DeclaredNames,
BinASTField::HasDirectEval};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
const auto scopeKind = AssertedScopeKind::Var;
MOZ_TRY(parseListOfAssertedDeclaredName(scopeKind, fieldContext++));
BINJS_MOZ_TRY_DECL(hasDirectEval, tokenizer_->readBool(fieldContext++));
if (hasDirectEval) {
pc_->sc()->setHasDirectEval();
pc_->sc()->setBindingsAccessedDynamically();
}
if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
// In non-strict mode code, direct calls to eval can
// add variables to the call object.
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::AssignmentExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Binding,
BinASTField::Expression};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(binding, parseAssignmentTarget(fieldContext++));
BINJS_MOZ_TRY_DECL(expression, parseExpression(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::AssignmentTargetIdentifier);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Name};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
RootedAtom name(cx_);
MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(fieldContext++));
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,
const Context& context) {
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::BinaryExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::Operator, BinASTField::Left, BinASTField::Right};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(operator_, parseBinaryOperator(fieldContext++));
BINJS_MOZ_TRY_DECL(left, parseExpression(fieldContext++));
BINJS_MOZ_TRY_DECL(right, parseExpression(fieldContext++));
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;
// ParseNodeKind::PowExpr is not left-associative
if (left->isKind(pnk) && pnk != ParseNodeKind::PowExpr) {
// Regroup left-associative operations into lists.
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;
}
/*
interface BindingIdentifier : Node {
[IdentifierName] string name;
}
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseBindingIdentifier(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
if (kind != BinASTKind::BindingIdentifier) {
return raiseInvalidKind("BindingIdentifier", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(
result, parseInterfaceBindingIdentifier(start, kind, fields, context));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::BindingIdentifier);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Name};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
RootedAtom name(cx_);
MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(fieldContext++));
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,
const Context& context) {
return raiseError(
"FIXME: Not implemented yet in this preview release "
"(BindingWithInitializer)");
}
/*
interface Block : Node {
AssertedBlockScope scope;
FrozenArray<Statement> statements;
}
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseBlock(const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
if (kind != BinASTKind::Block) {
return raiseInvalidKind("Block", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result, parseInterfaceBlock(start, kind, fields, context));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::Block);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Scope,
BinASTField::Statements};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
ParseContext::Statement stmt(pc_, StatementKind::Block);
ParseContext::Scope currentScope(cx_, pc_, usedNames_);
BINJS_TRY(currentScope.init(pc_));
MOZ_TRY(parseAssertedBlockScope(fieldContext++));
BINJS_MOZ_TRY_DECL(statements, parseListOfStatement(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::BreakStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Label};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
RootedAtom label(cx_);
MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::CallExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Callee,
BinASTField::Arguments};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(callee, parseExpressionOrSuper(fieldContext++));
BINJS_MOZ_TRY_DECL(arguments, parseArguments(fieldContext++));
auto op = JSOP_CALL;
// Try to optimize funcall and funapply at the bytecode level
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;
}
}
// Check for direct calls to `eval`.
if (handler_.isEvalName(callee, cx_)) {
if (!pc_->varScope().lookupDeclaredNameForAdd(cx_->names().eval) &&
!pc_->innermostScope()->lookupDeclaredNameForAdd(cx_->names().eval)) {
// This is a direct call to `eval`.
if (!pc_->sc()->hasDirectEval()) {
return raiseMissingDirectEvalInAssertedScope();
}
op = pc_->sc()->strict() ? JSOP_STRICTEVAL : JSOP_EVAL;
}
}
BINJS_TRY_DECL(result, handler_.newCall(callee, arguments, op));
return result;
}
/*
interface CatchClause : Node {
AssertedBoundNamesScope bindingScope;
Binding binding;
Block body;
}
*/
template <typename Tok>
JS::Result<LexicalScopeNode*> BinASTParser<Tok>::parseCatchClause(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
if (kind != BinASTKind::CatchClause) {
return raiseInvalidKind("CatchClause", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result,
parseInterfaceCatchClause(start, kind, fields, context));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::CatchClause);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::BindingScope, BinASTField::Binding, BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
ParseContext::Statement stmt(pc_, StatementKind::Catch);
ParseContext::Scope currentScope(cx_, pc_, usedNames_);
BINJS_TRY(currentScope.init(pc_));
MOZ_TRY(parseAssertedBoundNamesScope(fieldContext++));
BINJS_MOZ_TRY_DECL(binding, parseBinding(fieldContext++));
if (!currentScope.lookupDeclaredName(
binding->template as<NameNode>().atom())) {
return raiseError("Missing catch variable in scope");
}
BINJS_MOZ_TRY_DECL(body, parseBlock(fieldContext++));
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,
const Context& context) {
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,
const Context& context) {
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::CompoundAssignmentExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::Operator, BinASTField::Binding, BinASTField::Expression};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(operator_,
parseCompoundAssignmentOperator(fieldContext++));
BINJS_MOZ_TRY_DECL(binding, parseSimpleAssignmentTarget(fieldContext++));
BINJS_MOZ_TRY_DECL(expression, parseExpression(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::ComputedMemberAssignmentTarget);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Object,
BinASTField::Expression};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper(fieldContext++));
BINJS_MOZ_TRY_DECL(expression, parseExpression(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::ComputedMemberExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Object,
BinASTField::Expression};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper(fieldContext++));
BINJS_MOZ_TRY_DECL(expression, parseExpression(fieldContext++));
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,
const Context& context) {
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::ConditionalExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::Test, BinASTField::Consequent, BinASTField::Alternate};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(test, parseExpression(fieldContext++));
BINJS_MOZ_TRY_DECL(consequent, parseExpression(fieldContext++));
BINJS_MOZ_TRY_DECL(alternate, parseExpression(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::ContinueStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Label};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
RootedAtom label(cx_);
MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::DataProperty);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Name,
BinASTField::Expression};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(name, parsePropertyName(fieldContext++));
BINJS_MOZ_TRY_DECL(expression, parseExpression(fieldContext++));
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,
const Context& context) {
return raiseError(
"FIXME: Not implemented yet in this preview release (DebuggerStatement)");
}
/*
interface Directive : Node {
string rawValue;
}
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseDirective(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
if (kind != BinASTKind::Directive) {
return raiseInvalidKind("Directive", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result,
parseInterfaceDirective(start, kind, fields, context));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::Directive);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::RawValue};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
RootedAtom rawValue(cx_);
MOZ_TRY_VAR(rawValue, tokenizer_->readAtom(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::DoWhileStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Test, BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
ParseContext::Statement stmt(pc_, StatementKind::DoLoop);
BINJS_MOZ_TRY_DECL(test, parseExpression(fieldContext++));
BINJS_MOZ_TRY_DECL(body, parseStatement(fieldContext++));
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,
const Context& context) {
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,
const Context& context) {
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::EagerFunctionDeclaration);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#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 // defined(DEBUG)
const auto syntax = FunctionSyntaxKind::Statement;
BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool(fieldContext++));
if (isAsync) {
return raiseError(
"Async function is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool(fieldContext++));
if (isGenerator) {
return raiseError("Generator is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(name, parseBindingIdentifier(fieldContext++));
BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong(fieldContext++));
BINJS_MOZ_TRY_DECL(directives, parseListOfDirective(fieldContext++));
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);
// Push a new ParseContext. It will be used to parse `scope`, the arguments,
// the function.
BinASTParseContext funpc(cx_, this, funbox, /* newDirectives = */ 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, &params, &body, fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::EagerFunctionExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#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 // defined(DEBUG)
const auto syntax = FunctionSyntaxKind::Expression;
BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool(fieldContext++));
if (isAsync) {
return raiseError(
"Async function is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool(fieldContext++));
if (isGenerator) {
return raiseError("Generator is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(name, parseOptionalBindingIdentifier(fieldContext++));
BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong(fieldContext++));
BINJS_MOZ_TRY_DECL(directives, parseListOfDirective(fieldContext++));
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);
// Push a new ParseContext. It will be used to parse `scope`, the arguments,
// the function.
BinASTParseContext funpc(cx_, this, funbox, /* newDirectives = */ 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, &params, &body, fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::EagerGetter);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::Name, BinASTField::Directives, BinASTField::Contents};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
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(fieldContext++));
BINJS_MOZ_TRY_DECL(directives, parseListOfDirective(fieldContext++));
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);
// Push a new ParseContext. It will be used to parse `scope`, the arguments,
// the function.
BinASTParseContext funpc(cx_, this, funbox, /* newDirectives = */ 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, &params, &body, fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::EagerMethod);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#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 // defined(DEBUG)
const auto syntax = FunctionSyntaxKind::Method;
const auto accessorType = AccessorType::None;
BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool(fieldContext++));
if (isAsync) {
return raiseError(
"Async function is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool(fieldContext++));
if (isGenerator) {
return raiseError("Generator is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(name, parsePropertyName(fieldContext++));
BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong(fieldContext++));
BINJS_MOZ_TRY_DECL(directives, parseListOfDirective(fieldContext++));
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);
// Push a new ParseContext. It will be used to parse `scope`, the arguments,
// the function.
BinASTParseContext funpc(cx_, this, funbox, /* newDirectives = */ 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, &params, &body, fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::EagerSetter);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#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 // defined(DEBUG)
const auto syntax = FunctionSyntaxKind::Setter;
const bool isGenerator = false;
const bool isAsync = false;
const auto accessorType = AccessorType::Setter;
BINJS_MOZ_TRY_DECL(name, parsePropertyName(fieldContext++));
BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong(fieldContext++));
BINJS_MOZ_TRY_DECL(directives, parseListOfDirective(fieldContext++));
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);
// Push a new ParseContext. It will be used to parse `scope`, the arguments,
// the function.
BinASTParseContext funpc(cx_, this, funbox, /* newDirectives = */ 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, &params, &body, fieldContext++));
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,
const Context& context) {
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::ExpressionStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Expression};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(expression, parseExpression(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::ForInOfBinding);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Kind,
BinASTField::Binding};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
AutoVariableDeclarationKind kindGuard(this);
BINJS_MOZ_TRY_DECL(kind_, parseVariableDeclarationKind(fieldContext++));
BINJS_MOZ_TRY_DECL(binding, parseBinding(fieldContext++));
// Restored by `kindGuard`.
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::ForInStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[3] = {BinASTField::Left, BinASTField::Right,
BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
ParseContext::Statement stmt(pc_, StatementKind::ForInLoop);
// Implicit scope around the `for`, used to store `for (let x in ...)`
// or `for (const x in ...)`-style declarations. Detail on the
// declaration is stored as part of `scope`.
ParseContext::Scope scope(cx_, pc_, usedNames_);
BINJS_TRY(scope.init(pc_));
BINJS_MOZ_TRY_DECL(left,
parseForInOfBindingOrAssignmentTarget(fieldContext++));
BINJS_MOZ_TRY_DECL(right, parseExpression(fieldContext++));
BINJS_MOZ_TRY_DECL(body, parseStatement(fieldContext++));
BINJS_TRY_DECL(forHead,
handler_.newForInOrOfHead(ParseNodeKind::ForIn, left, right,
tokenizer_->pos(start)));
ParseNode* result;
BINJS_TRY_VAR(result, handler_.newForStatement(start, forHead, body,
/* iflags = */ 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,
const Context& context) {
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::ForStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#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 // defined(DEBUG)
ParseContext::Statement stmt(pc_, StatementKind::ForLoop);
// Implicit scope around the `for`, used to store `for (let x; ...; ...)`
// or `for (const x; ...; ...)`-style declarations. Detail on the
// declaration is stored as part of `BINJS_Scope`.
ParseContext::Scope scope(cx_, pc_, usedNames_);
BINJS_TRY(scope.init(pc_));
BINJS_MOZ_TRY_DECL(
init, parseOptionalVariableDeclarationOrExpression(fieldContext++));
BINJS_MOZ_TRY_DECL(test, parseOptionalExpression(fieldContext++));
BINJS_MOZ_TRY_DECL(update, parseOptionalExpression(fieldContext++));
BINJS_MOZ_TRY_DECL(body, parseStatement(fieldContext++));
BINJS_TRY_DECL(
forHead, handler_.newForHead(init, test, update, tokenizer_->pos(start)));
ParseNode* result;
BINJS_TRY_VAR(result, handler_.newForStatement(start, forHead, body,
/* iflags = */ 0));
if (!scope.isEmpty()) {
BINJS_TRY_DECL(bindings, NewLexicalScopeData(cx_, scope, alloc_, pc_));
BINJS_TRY_VAR(result, handler_.newLexicalScope(*bindings, result));
}
return result;
}
/*
interface FormalParameters : Node {
FrozenArray<Parameter> items;
Binding? rest;
}
*/
template <typename Tok>
JS::Result<ListNode*> BinASTParser<Tok>::parseFormalParameters(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
if (kind != BinASTKind::FormalParameters) {
return raiseInvalidKind("FormalParameters", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(
result, parseInterfaceFormalParameters(start, kind, fields, context));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::FormalParameters);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Items,
BinASTField::Rest};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(items, parseListOfParameter(fieldContext++));
BINJS_MOZ_TRY_DECL(rest, parseOptionalBinding(fieldContext++));
auto result = items;
if (rest) {
return raiseError(
"Rest parameter is not supported in this preview release");
}
return result;
}
/*
interface FunctionExpressionContents : Node {
bool isFunctionNameCaptured;
bool isThisCaptured;
AssertedParameterScope parameterScope;
FormalParameters params;
AssertedVarScope bodyScope;
FunctionBody body;
}
*/
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseFunctionExpressionContents(
uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, 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, context));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::FunctionExpressionContents);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#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 // defined(DEBUG)
BINJS_MOZ_TRY_DECL(isFunctionNameCaptured,
tokenizer_->readBool(fieldContext++));
// Per spec, isFunctionNameCaptured can be true for anonymous
// function. Check isFunctionNameCaptured only for named
// function.
if (pc_->functionBox()->isNamedLambda() &&
isFunctionNameCaptured) {
captureFunctionName();
}
BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool(fieldContext++));
// TODO: Use this in BinASTParser::buildFunction.
(void)isThisCaptured;
Rooted<GCVector<JSAtom*>> positionalParams(cx_, GCVector<JSAtom*>(cx_));
MOZ_TRY(parseAssertedParameterScope(&positionalParams, fieldContext++));
BINJS_MOZ_TRY_DECL(params, parseFormalParameters(fieldContext++));
MOZ_TRY(checkFunctionLength(funLength));
MOZ_TRY(checkPositionalParameterIndices(positionalParams, params));
MOZ_TRY(parseAssertedVarScope(fieldContext++));
BINJS_MOZ_TRY_DECL(body, parseFunctionBody(fieldContext++));
*paramsOut = params;
*bodyOut = body;
auto result = Ok();
return result;
}
/*
interface FunctionOrMethodContents : Node {
bool isThisCaptured;
AssertedParameterScope parameterScope;
FormalParameters params;
AssertedVarScope bodyScope;
FunctionBody body;
}
*/
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseFunctionOrMethodContents(
uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, 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, context));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::FunctionOrMethodContents);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#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 // defined(DEBUG)
BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool(fieldContext++));
// TODO: Use this in BinASTParser::buildFunction.
(void)isThisCaptured;
Rooted<GCVector<JSAtom*>> positionalParams(cx_, GCVector<JSAtom*>(cx_));
MOZ_TRY(parseAssertedParameterScope(&positionalParams, fieldContext++));
BINJS_MOZ_TRY_DECL(params, parseFormalParameters(fieldContext++));
MOZ_TRY(checkFunctionLength(funLength));
MOZ_TRY(checkPositionalParameterIndices(positionalParams, params));
MOZ_TRY(parseAssertedVarScope(fieldContext++));
BINJS_MOZ_TRY_DECL(body, parseFunctionBody(fieldContext++));
*paramsOut = params;
*bodyOut = body;
auto result = Ok();
return result;
}
/*
interface GetterContents : Node {
bool isThisCaptured;
AssertedVarScope bodyScope;
FunctionBody body;
}
*/
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseGetterContents(uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut,
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, 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, context));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::GetterContents);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::IsThisCaptured, BinASTField::BodyScope, BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool(fieldContext++));
// TODO: Use this in BinASTParser::buildFunction.
(void)isThisCaptured;
MOZ_TRY(parseAssertedVarScope(fieldContext++));
BINJS_TRY_DECL(params, handler_.newParamsBody(tokenizer_->pos(start)));
BINJS_MOZ_TRY_DECL(body, parseFunctionBody(fieldContext++));
*paramsOut = params;
*bodyOut = body;
auto result = Ok();
return result;
}
/*
interface IdentifierExpression : Node {
[IdentifierName] string name;
}
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseIdentifierExpression(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
if (kind != BinASTKind::IdentifierExpression) {
return raiseInvalidKind("IdentifierExpression", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(
result, parseInterfaceIdentifierExpression(start, kind, fields, context));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::IdentifierExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Name};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
RootedAtom name(cx_);
MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::IfStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::Test, BinASTField::Consequent, BinASTField::Alternate};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(test, parseExpression(fieldContext++));
BINJS_MOZ_TRY_DECL(consequent, parseStatement(fieldContext++));
BINJS_MOZ_TRY_DECL(alternate, parseOptionalStatement(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::LabelledStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Label,
BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
RootedAtom label(cx_);
MOZ_TRY_VAR(label, tokenizer_->readAtom(fieldContext++));
if (!IsIdentifier(label)) {
return raiseError("Invalid identifier");
}
ParseContext::LabelStatement stmt(pc_, label);
BINJS_MOZ_TRY_DECL(body, parseStatement(fieldContext++));
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,
const Context& context) {
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,
const Context& context) {
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::LazyFunctionDeclaration);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#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 // defined(DEBUG)
const auto syntax = FunctionSyntaxKind::Statement;
BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool(fieldContext++));
if (isAsync) {
return raiseError(
"Async function is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool(fieldContext++));
if (isGenerator) {
return raiseError("Generator is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(name, parseBindingIdentifier(fieldContext++));
BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong(fieldContext++));
BINJS_MOZ_TRY_DECL(directives, parseListOfDirective(fieldContext++));
BINJS_MOZ_TRY_DECL(contentsSkip,
tokenizer_->readSkippableSubTree(fieldContext++));
// Don't parse the contents until we delazify.
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());
// TODO: This will become incorrect in the face of ES6 features.
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::LazyFunctionExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#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 // defined(DEBUG)
const auto syntax = FunctionSyntaxKind::Expression;
BINJS_MOZ_TRY_DECL(isAsync, tokenizer_->readBool(fieldContext++));
if (isAsync) {
return raiseError(
"Async function is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(isGenerator, tokenizer_->readBool(fieldContext++));
if (isGenerator) {
return raiseError("Generator is not supported in this preview release");
}
BINJS_MOZ_TRY_DECL(name, parseOptionalBindingIdentifier(fieldContext++));
BINJS_MOZ_TRY_DECL(length, tokenizer_->readUnsignedLong(fieldContext++));
BINJS_MOZ_TRY_DECL(directives, parseListOfDirective(fieldContext++));
BINJS_MOZ_TRY_DECL(contentsSkip,
tokenizer_->readSkippableSubTree(fieldContext++));
// Don't parse the contents until we delazify.
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());
// TODO: This will become incorrect in the face of ES6 features.
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,
const Context& context) {
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,
const Context& context) {
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,
const Context& context) {
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::LiteralBooleanExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Value};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(value, tokenizer_->readBool(fieldContext++));
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,
const Context& context) {
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,
const Context& context) {
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::LiteralNumericExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Value};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(value, tokenizer_->readDouble(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::LiteralPropertyName);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Value};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
RootedAtom value(cx_);
MOZ_TRY_VAR(value, tokenizer_->readAtom(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::LiteralRegExpExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Pattern,
BinASTField::Flags};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
RootedAtom pattern(cx_);
MOZ_TRY_VAR(pattern, tokenizer_->readAtom(fieldContext++));
Chars flags(cx_);
MOZ_TRY(tokenizer_->readChars(flags, fieldContext++));
RegExpFlags reflags = RegExpFlag::NoFlags;
for (auto c : flags) {
if (c == 'g' && !reflags.global()) {
reflags |= RegExpFlag::Global;
} else if (c == 'i' && !reflags.ignoreCase()) {
reflags |= RegExpFlag::IgnoreCase;
} else if (c == 'm' && !reflags.multiline()) {
reflags |= RegExpFlag::Multiline;
} else if (c == 'u' && !reflags.unicode()) {
reflags |= RegExpFlag::Unicode;
} else if (c == 'y' && !reflags.sticky()) {
reflags |= RegExpFlag::Sticky;
} 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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::LiteralStringExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Value};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
RootedAtom value(cx_);
MOZ_TRY_VAR(value, tokenizer_->readAtom(fieldContext++));
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,
const Context& context) {
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::NewExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Callee,
BinASTField::Arguments};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(callee, parseExpression(fieldContext++));
BINJS_MOZ_TRY_DECL(arguments, parseArguments(fieldContext++));
BINJS_TRY_DECL(result,
handler_.newNewExpression(tokenizer_->pos(start).begin, callee,
arguments, /* isSpread = */ false));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceNewTargetExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields,
const Context& context) {
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,
const Context& context) {
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,
const Context& context) {
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::ObjectExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Properties};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(properties, parseListOfObjectProperty(fieldContext++));
auto result = properties;
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceReturnStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::ReturnStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Expression};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
if (!pc_->isFunctionBox()) {
// Return statements are permitted only inside functions.
return raiseInvalidKind("Toplevel Statement", kind);
}
pc_->functionBox()->usesReturn = true;
BINJS_MOZ_TRY_DECL(expression, parseOptionalExpression(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::Script);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::Scope, BinASTField::Directives, BinASTField::Statements};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
MOZ_TRY(parseAssertedScriptGlobalScope(fieldContext++));
BINJS_MOZ_TRY_DECL(directives, parseListOfDirective(fieldContext++));
forceStrictIfNecessary(pc_->sc(), directives);
BINJS_MOZ_TRY_DECL(statements, parseListOfStatement(fieldContext++));
MOZ_TRY(checkClosedVars(pc_->varScope()));
MOZ_TRY(prependDirectivesToBody(/* body = */ statements, directives));
auto result = statements;
return result;
}
/*
interface SetterContents : Node {
bool isThisCaptured;
AssertedParameterScope parameterScope;
Parameter param;
AssertedVarScope bodyScope;
FunctionBody body;
}
*/
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseSetterContents(uint32_t funLength,
ListNode** paramsOut,
ListNode** bodyOut,
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, 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, context));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::SetterContents);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#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 // defined(DEBUG)
BINJS_MOZ_TRY_DECL(isThisCaptured, tokenizer_->readBool(fieldContext++));
// TODO: Use this in BinASTParser::buildFunction.
(void)isThisCaptured;
Rooted<GCVector<JSAtom*>> positionalParams(cx_, GCVector<JSAtom*>(cx_));
MOZ_TRY(parseAssertedParameterScope(&positionalParams, fieldContext++));
BINJS_MOZ_TRY_DECL(param, parseParameter(fieldContext++));
BINJS_TRY_DECL(params, handler_.newParamsBody(param->pn_pos));
handler_.addList(params, param);
MOZ_TRY(checkPositionalParameterIndices(positionalParams, params));
MOZ_TRY(parseAssertedVarScope(fieldContext++));
BINJS_MOZ_TRY_DECL(body, parseFunctionBody(fieldContext++));
*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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::ShorthandProperty);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Name};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(name, parseIdentifierExpression(fieldContext++));
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,
const Context& context) {
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::StaticMemberAssignmentTarget);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Object,
BinASTField::Property};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
size_t nameStart;
BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper(fieldContext++));
RootedAtom property(cx_);
{
nameStart = tokenizer_->offset();
MOZ_TRY_VAR(property, tokenizer_->readPropertyKey(fieldContext++));
}
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::StaticMemberExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Object,
BinASTField::Property};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
size_t nameStart;
BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper(fieldContext++));
RootedAtom property(cx_);
{
nameStart = tokenizer_->offset();
MOZ_TRY_VAR(property, tokenizer_->readPropertyKey(fieldContext++));
}
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,
const Context& context) {
return raiseError(
"FIXME: Not implemented yet in this preview release (Super)");
}
/*
interface SwitchCase : Node {
Expression test;
FrozenArray<Statement> consequent;
}
*/
template <typename Tok>
JS::Result<CaseClause*> BinASTParser<Tok>::parseSwitchCase(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
if (kind != BinASTKind::SwitchCase) {
return raiseInvalidKind("SwitchCase", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result,
parseInterfaceSwitchCase(start, kind, fields, context));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::SwitchCase);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Test,
BinASTField::Consequent};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(test, parseExpression(fieldContext++));
BINJS_MOZ_TRY_DECL(consequent, parseListOfStatement(fieldContext++));
BINJS_TRY_DECL(result, handler_.newCaseOrDefault(start, test, consequent));
return result;
}
/*
interface SwitchDefault : Node {
FrozenArray<Statement> consequent;
}
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseSwitchDefault(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
if (kind != BinASTKind::SwitchDefault) {
return raiseInvalidKind("SwitchDefault", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(result,
parseInterfaceSwitchDefault(start, kind, fields, context));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::SwitchDefault);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Consequent};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(consequent, parseListOfStatement(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::SwitchStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Discriminant,
BinASTField::Cases};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(discriminant, parseExpression(fieldContext++));
ParseContext::Statement stmt(pc_, StatementKind::Switch);
BINJS_MOZ_TRY_DECL(cases, parseListOfSwitchCase(fieldContext++));
BINJS_TRY_DECL(scope, handler_.newLexicalScope(nullptr, cases));
BINJS_TRY_DECL(result, handler_.newSwitchStatement(start, discriminant, scope,
/* hasDefault = */ false));
return result;
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseInterfaceSwitchStatementWithDefault(
const size_t start, const BinASTKind kind, const BinASTFields& fields,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::SwitchStatementWithDefault);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#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 // defined(DEBUG)
BINJS_MOZ_TRY_DECL(discriminant, parseExpression(fieldContext++));
ParseContext::Statement stmt(pc_, StatementKind::Switch);
BINJS_MOZ_TRY_DECL(preDefaultCases, parseListOfSwitchCase(fieldContext++));
BINJS_MOZ_TRY_DECL(defaultCase, parseSwitchDefault(fieldContext++));
BINJS_MOZ_TRY_DECL(postDefaultCases, parseListOfSwitchCase(fieldContext++));
// Concatenate `preDefaultCase`, `defaultCase`, `postDefaultCase`
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,
/* hasDefault = */ true));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceTemplateExpression(
const size_t start, const BinASTKind kind, const BinASTFields& fields,
const Context& context) {
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,
const Context& context) {
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::ThrowStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[1] = {BinASTField::Expression};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(expression, parseExpression(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::TryCatchStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Body,
BinASTField::CatchClause};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
ParseNode* body;
{
ParseContext::Statement stmt(pc_, StatementKind::Try);
ParseContext::Scope scope(cx_, pc_, usedNames_);
BINJS_TRY(scope.init(pc_));
MOZ_TRY_VAR(body, parseBlock(fieldContext++));
}
BINJS_MOZ_TRY_DECL(catchClause, parseCatchClause(fieldContext++));
BINJS_TRY_DECL(result,
handler_.newTryStatement(start, body, catchClause,
/* finallyBlock = */ nullptr));
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceTryFinallyStatement(
const size_t start, const BinASTKind kind, const BinASTFields& fields,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::TryFinallyStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::Body, BinASTField::CatchClause, BinASTField::Finalizer};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
ParseNode* body;
{
ParseContext::Statement stmt(pc_, StatementKind::Try);
ParseContext::Scope scope(cx_, pc_, usedNames_);
BINJS_TRY(scope.init(pc_));
MOZ_TRY_VAR(body, parseBlock(fieldContext++));
}
BINJS_MOZ_TRY_DECL(catchClause, parseOptionalCatchClause(fieldContext++));
ParseNode* finalizer;
{
ParseContext::Statement stmt(pc_, StatementKind::Finally);
ParseContext::Scope scope(cx_, pc_, usedNames_);
BINJS_TRY(scope.init(pc_));
MOZ_TRY_VAR(finalizer, parseBlock(fieldContext++));
}
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::UnaryExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Operator,
BinASTField::Operand};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(operator_, parseUnaryOperator(fieldContext++));
BINJS_MOZ_TRY_DECL(operand, parseExpression(fieldContext++));
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:
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::UpdateExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[3] = {
BinASTField::IsPrefix, BinASTField::Operator, BinASTField::Operand};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(isPrefix, tokenizer_->readBool(fieldContext++));
BINJS_MOZ_TRY_DECL(operator_, parseUpdateOperator(fieldContext++));
BINJS_MOZ_TRY_DECL(operand, parseSimpleAssignmentTarget(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::VariableDeclaration);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Kind,
BinASTField::Declarators};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
AutoVariableDeclarationKind kindGuard(this);
BINJS_MOZ_TRY_DECL(kind_, parseVariableDeclarationKind(fieldContext++));
// Restored by `kindGuard`.
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, fieldContext++));
// By specification, the list may not be empty.
if (declarators->empty()) {
return raiseEmpty("VariableDeclaration");
}
auto result = declarators;
return result;
}
/*
interface VariableDeclarator : Node {
Binding binding;
Expression? init;
}
*/
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseVariableDeclarator(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
if (kind != BinASTKind::VariableDeclarator) {
return raiseInvalidKind("VariableDeclarator", kind);
}
const auto start = tokenizer_->offset();
BINJS_MOZ_TRY_DECL(
result, parseInterfaceVariableDeclarator(start, kind, fields, context));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::VariableDeclarator);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Binding,
BinASTField::Init};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(binding, parseBinding(fieldContext++));
BINJS_MOZ_TRY_DECL(init, parseOptionalExpression(fieldContext++));
ParseNode* result;
if (binding->isKind(ParseNodeKind::Name)) {
// `var foo [= bar]``
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 {
// `var pattern = bar`
if (!init) {
// Here, `init` is required.
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::WhileStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Test, BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
ParseContext::Statement stmt(pc_, StatementKind::WhileLoop);
BINJS_MOZ_TRY_DECL(test, parseExpression(fieldContext++));
BINJS_MOZ_TRY_DECL(body, parseStatement(fieldContext++));
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,
const Context& context) {
MOZ_ASSERT(kind == BinASTKind::WithStatement);
BINJS_TRY(CheckRecursionLimit(cx_));
Context fieldContext = Context::firstField(kind);
#if defined(DEBUG)
const BinASTField expected_fields[2] = {BinASTField::Object,
BinASTField::Body};
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
BINJS_MOZ_TRY_DECL(object, parseExpression(fieldContext++));
ParseContext::Statement stmt(pc_, StatementKind::With);
BINJS_MOZ_TRY_DECL(body, parseStatement(fieldContext++));
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,
const Context& context) {
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,
const Context& context) {
return raiseError(
"FIXME: Not implemented yet in this preview release "
"(YieldStarExpression)");
}
// ----- String enums (autogenerated, by lexicographical order)
/*
enum AssertedDeclaredKind {
"var",
"non-const lexical",
"const lexical"
};
*/
template <typename Tok>
JS::Result<typename BinASTParser<Tok>::AssertedDeclaredKind>
BinASTParser<Tok>::parseAssertedDeclaredKind(const Context& context) {
BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
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);
}
}
/*
enum BinaryOperator {
",",
"||",
"&&",
"|",
"^",
"&",
"==",
"!=",
"===",
"!==",
"<",
"<=",
">",
">=",
"in",
"instanceof",
"<<",
">>",
">>>",
"+",
"-",
"*",
"/",
"%",
"**"
};
*/
template <typename Tok>
JS::Result<typename BinASTParser<Tok>::BinaryOperator>
BinASTParser<Tok>::parseBinaryOperator(const Context& context) {
BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
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);
}
}
/*
enum CompoundAssignmentOperator {
"+=",
"-=",
"*=",
"/=",
"%=",
"**=",
"<<=",
">>=",
">>>=",
"|=",
"^=",
"&="
};
*/
template <typename Tok>
JS::Result<typename BinASTParser<Tok>::CompoundAssignmentOperator>
BinASTParser<Tok>::parseCompoundAssignmentOperator(const Context& context) {
BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
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);
}
}
/*
enum UnaryOperator {
"+",
"-",
"!",
"~",
"typeof",
"void",
"delete"
};
*/
template <typename Tok>
JS::Result<typename BinASTParser<Tok>::UnaryOperator>
BinASTParser<Tok>::parseUnaryOperator(const Context& context) {
BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
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);
}
}
/*
enum UpdateOperator {
"++",
"--"
};
*/
template <typename Tok>
JS::Result<typename BinASTParser<Tok>::UpdateOperator>
BinASTParser<Tok>::parseUpdateOperator(const Context& context) {
BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
switch (variant) {
case BinASTVariant::UpdateOperatorIncr:
return UpdateOperator::Incr;
case BinASTVariant::UpdateOperatorDecr:
return UpdateOperator::Decr;
default:
return raiseInvalidVariant("UpdateOperator", variant);
}
}
/*
enum VariableDeclarationKind {
"var",
"let",
"const"
};
*/
template <typename Tok>
JS::Result<typename BinASTParser<Tok>::VariableDeclarationKind>
BinASTParser<Tok>::parseVariableDeclarationKind(const Context& context) {
BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
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);
}
}
// ----- Lists (autogenerated, by lexicographical order)
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseArguments(
const Context& context) {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, context, guard));
BINJS_TRY_DECL(result, handler_.newList(ParseNodeKind::Arguments,
tokenizer_->pos(start)));
const Context childContext(context.arrayElement());
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseSpreadElementOrExpression(childContext));
handler_.addList(/* list = */ result, /* kid = */ item);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ListNode*> BinASTParser<Tok>::parseFunctionBody(
const Context& context) {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, context, guard));
BINJS_TRY_DECL(result, handler_.newStatementList(tokenizer_->pos(start)));
const Context childContext(context.arrayElement());
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseStatement(childContext));
handler_.addStatementToList(result, item);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseListOfAssertedBoundName(
AssertedScopeKind scopeKind, const Context& context) {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, context, guard));
(void)start;
auto result = Ok();
const Context childContext(context.arrayElement());
for (uint32_t i = 0; i < length; ++i) {
MOZ_TRY(parseAssertedBoundName(scopeKind, childContext));
// Nothing to do here.
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok> BinASTParser<Tok>::parseListOfAssertedDeclaredName(
AssertedScopeKind scopeKind, const Context& context) {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, context, guard));
(void)start;
auto result = Ok();
const Context childContext(context.arrayElement());
for (uint32_t i = 0; i < length; ++i) {
MOZ_TRY(parseAssertedDeclaredName(scopeKind, childContext));
// Nothing to do here.
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<Ok>
BinASTParser<Tok>::parseListOfAssertedMaybePositionalParameterName(
AssertedScopeKind scopeKind,
MutableHandle<GCVector<JSAtom*>> positionalParams, const Context& context) {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, context, guard));
(void)start;
auto result = Ok();
// This list contains also destructuring parameters, and the number of
// list items can be greater than the actual parameters, or more than
// ARGNO_LIMIT even if the number of parameters fits into ARGNO_LIMIT.
// Also, the number of parameters can be greater than this list's length
// if one of destructuring parameter is empty.
//
// We resize `positionalParams` vector on demand, to keep the vector
// length match to the known maximum positional parameter index + 1.
const Context childContext(context.arrayElement());
for (uint32_t i = 0; i < length; ++i) {
MOZ_TRY(parseAssertedMaybePositionalParameterName(
scopeKind, positionalParams, childContext));
// Nothing to do here.
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ListNode*> BinASTParser<Tok>::parseListOfDirective(
const Context& context) {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, context, guard));
BINJS_TRY_DECL(result, handler_.newStatementList(tokenizer_->pos(start)));
const Context childContext(context.arrayElement());
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseDirective(childContext));
handler_.addStatementToList(result, item);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ListNode*> BinASTParser<Tok>::parseListOfObjectProperty(
const Context& context) {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, context, guard));
BINJS_TRY_DECL(result, handler_.newObjectLiteral(start));
const Context childContext(context.arrayElement());
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseObjectProperty(childContext));
if (!item->isConstant()) result->setHasNonConstInitializer();
result->appendWithoutOrderAssumption(item);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ListNode*>
BinASTParser<Tok>::parseListOfOptionalSpreadElementOrExpression(
const Context& context) {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, context, guard));
BINJS_TRY_DECL(result, handler_.newArrayLiteral(start));
const Context childContext(context.arrayElement());
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item,
parseOptionalSpreadElementOrExpression(childContext));
if (item) {
handler_.addArrayElement(result, item); // Infallible.
} else {
BINJS_TRY(handler_.addElision(result, tokenizer_->pos(start)));
}
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ListNode*> BinASTParser<Tok>::parseListOfParameter(
const Context& context) {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, context, guard));
BINJS_TRY_DECL(result, handler_.newParamsBody(tokenizer_->pos(start)));
const Context childContext(context.arrayElement());
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseParameter(childContext));
handler_.addList(/* list = */ result, /* kid = */ item);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ListNode*> BinASTParser<Tok>::parseListOfStatement(
const Context& context) {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, context, guard));
BINJS_TRY_DECL(result, handler_.newStatementList(tokenizer_->pos(start)));
const Context childContext(context.arrayElement());
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseStatement(childContext));
handler_.addStatementToList(result, item);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ListNode*> BinASTParser<Tok>::parseListOfSwitchCase(
const Context& context) {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, context, guard));
BINJS_TRY_DECL(result, handler_.newStatementList(tokenizer_->pos(start)));
const Context childContext(context.arrayElement());
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseSwitchCase(childContext));
handler_.addCaseStatementToList(result, item);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ListNode*> BinASTParser<Tok>::parseListOfVariableDeclarator(
ParseNodeKind declarationListKind, const Context& context) {
uint32_t length;
AutoList guard(*tokenizer_);
const auto start = tokenizer_->offset();
MOZ_TRY(tokenizer_->enterList(length, context, guard));
BINJS_TRY_DECL(result, handler_.newDeclarationList(declarationListKind,
tokenizer_->pos(start)));
const Context childContext(context.arrayElement());
for (uint32_t i = 0; i < length; ++i) {
BINJS_MOZ_TRY_DECL(item, parseVariableDeclarator(childContext));
result->appendWithoutOrderAssumption(item);
}
MOZ_TRY(guard.done());
return result;
}
// ----- Default values (by lexicographical order)
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalBinding(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
ParseNode* result;
if (kind == BinASTKind::_Null) {
result = nullptr;
} else {
const auto start = tokenizer_->offset();
MOZ_TRY_VAR(result, parseSumBinding(start, kind, fields, context));
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalBindingIdentifier(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, 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, context));
} else {
return raiseInvalidKind("BindingIdentifier", kind);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<LexicalScopeNode*> BinASTParser<Tok>::parseOptionalCatchClause(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, 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, context));
} else {
return raiseInvalidKind("CatchClause", kind);
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalExpression(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
ParseNode* result;
if (kind == BinASTKind::_Null) {
result = nullptr;
} else {
const auto start = tokenizer_->offset();
MOZ_TRY_VAR(result, parseSumExpression(start, kind, fields, context));
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseOptionalSpreadElementOrExpression(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
ParseNode* result;
if (kind == BinASTKind::_Null) {
result = nullptr;
} else {
const auto start = tokenizer_->offset();
MOZ_TRY_VAR(result, parseSumSpreadElementOrExpression(start, kind, fields,
context));
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalStatement(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
ParseNode* result;
if (kind == BinASTKind::_Null) {
result = nullptr;
} else {
const auto start = tokenizer_->offset();
MOZ_TRY_VAR(result, parseSumStatement(start, kind, fields, context));
}
MOZ_TRY(guard.done());
return result;
}
template <typename Tok>
JS::Result<ParseNode*>
BinASTParser<Tok>::parseOptionalVariableDeclarationOrExpression(
const Context& context) {
BinASTKind kind;
BinASTFields fields(cx_);
AutoTaggedTuple guard(*tokenizer_);
MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
ParseNode* result;
if (kind == BinASTKind::_Null) {
result = nullptr;
} else {
const auto start = tokenizer_->offset();
MOZ_TRY_VAR(result, parseSumVariableDeclarationOrExpression(
start, kind, fields, context));
}
MOZ_TRY(guard.done());
return result;
}
// Force class instantiation.
// This ensures that the symbols are built, without having to export all our
// code (and its baggage of #include and macros) in the header.
template class BinASTParser<BinASTTokenReaderContext>;
template class BinASTParser<BinASTTokenReaderMultipart>;
} // namespace frontend
} // namespace js