forked from mirrors/gecko-dev
5330 lines
186 KiB
C++
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, ¶ms, &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, ¶ms, &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, ¶ms, &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, ¶ms, &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, ¶ms, &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
|