Bug 1891041 - Implement parsing for explicit resource management. r=arai

Implements simple parsing for the explicit resource management
proposal.

Differential Revision: https://phabricator.services.mozilla.com/D207371
This commit is contained in:
Debadree Chatterjee 2024-05-19 08:01:59 +00:00
parent c3ecdeeb2d
commit 49af7ffb9e
18 changed files with 653 additions and 270 deletions

View File

@ -173,6 +173,24 @@ def enable_decorators(value):
set_config("ENABLE_DECORATORS", enable_decorators)
set_define("ENABLE_DECORATORS", enable_decorators)
# Enable explicit resource management
# ===================================================
option(
"--enable-explicit-resource-management",
default=False,
help="Enable explicit resource management",
)
@depends("--enable-explicit-resource-management")
def enable_explicit_resource_management(value):
if value:
return True
set_config("ENABLE_EXPLICIT_RESOURCE_MANAGEMENT", enable_explicit_resource_management)
set_define("ENABLE_EXPLICIT_RESOURCE_MANAGEMENT", enable_explicit_resource_management)
# Enable JSON.parse with source
# ===================================================

View File

@ -148,4 +148,10 @@ using jsid = JS::PropertyKey;
# define IF_DECORATORS(x, ...) __VA_ARGS__
#endif
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
# define IF_EXPLICIT_RESOURCE_MANAGEMENT(x, ...) x
#else
# define IF_EXPLICIT_RESOURCE_MANAGEMENT(x, ...) __VA_ARGS__
#endif
#endif /* js_TypeDecls_h */

View File

@ -401,6 +401,7 @@ MSG_DEF(JSMSG_ASSERT_STRING_LITERAL, 0, JSEXN_SYNTAXERR, "expected string lite
MSG_DEF(JSMSG_ASSERT_KEY_EXPECTED, 0, JSEXN_SYNTAXERR, "expected assertion key")
MSG_DEF(JSMSG_DECORATOR_NAME_EXPECTED, 0, JSEXN_SYNTAXERR, "expected property name in decorator expression")
MSG_DEF(JSMSG_CLASS_EXPECTED, 0, JSEXN_SYNTAXERR, "expected class")
MSG_DEF(JSMSG_NO_IN_WITH_USING, 0, JSEXN_SYNTAXERR, "'using' is not allowed in a for-in loop")
// UTF-8 source text encoding errors
MSG_DEF(JSMSG_BAD_LEADING_UTF8_UNIT, 1, JSEXN_SYNTAXERR, "{0} byte doesn't begin a valid UTF-8 code point")

View File

@ -136,6 +136,9 @@ enum VarDeclKind {
VARDECL_VAR = 0,
VARDECL_CONST,
VARDECL_LET,
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
VARDECL_USING,
#endif
VARDECL_LIMIT
};
@ -1235,10 +1238,23 @@ bool NodeBuilder::variableDeclaration(NodeVector& elts, VarDeclKind kind,
MOZ_ASSERT(kind > VARDECL_ERR && kind < VARDECL_LIMIT);
RootedValue array(cx), kindName(cx);
if (!newArray(elts, &array) || !atomValue(kind == VARDECL_CONST ? "const"
: kind == VARDECL_LET ? "let"
: "var",
&kindName)) {
const char* s;
switch (kind) {
case VARDECL_CONST:
s = "const";
break;
case VARDECL_LET:
s = "let";
break;
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
case VARDECL_USING:
s = "using";
break;
#endif
default:
s = "var";
}
if (!newArray(elts, &array) || !atomValue(s, &kindName)) {
return false;
}
@ -1729,6 +1745,9 @@ bool ASTSerializer::declaration(ParseNode* pn, MutableHandleValue dst) {
MOZ_ASSERT(pn->isKind(ParseNodeKind::Function) ||
pn->isKind(ParseNodeKind::VarStmt) ||
pn->isKind(ParseNodeKind::LetDecl) ||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
pn->isKind(ParseNodeKind::UsingDecl) ||
#endif
pn->isKind(ParseNodeKind::ConstDecl));
switch (pn->getKind()) {
@ -1740,6 +1759,9 @@ bool ASTSerializer::declaration(ParseNode* pn, MutableHandleValue dst) {
default:
MOZ_ASSERT(pn->isKind(ParseNodeKind::LetDecl) ||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
pn->isKind(ParseNodeKind::UsingDecl) ||
#endif
pn->isKind(ParseNodeKind::ConstDecl));
return variableDeclaration(&pn->as<ListNode>(), true, dst);
}
@ -1748,6 +1770,9 @@ bool ASTSerializer::declaration(ParseNode* pn, MutableHandleValue dst) {
bool ASTSerializer::variableDeclaration(ListNode* declList, bool lexical,
MutableHandleValue dst) {
MOZ_ASSERT_IF(lexical, declList->isKind(ParseNodeKind::LetDecl) ||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
declList->isKind(ParseNodeKind::UsingDecl) ||
#endif
declList->isKind(ParseNodeKind::ConstDecl));
MOZ_ASSERT_IF(!lexical, declList->isKind(ParseNodeKind::VarStmt));
@ -1755,8 +1780,17 @@ bool ASTSerializer::variableDeclaration(ListNode* declList, bool lexical,
// Treat both the toplevel const binding (secretly var-like) and the lexical
// const the same way
if (lexical) {
kind =
declList->isKind(ParseNodeKind::LetDecl) ? VARDECL_LET : VARDECL_CONST;
if (declList->isKind(ParseNodeKind::LetDecl)) {
kind = VARDECL_LET;
}
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
else if (declList->isKind(ParseNodeKind::UsingDecl)) {
kind = VARDECL_USING;
}
#endif
else {
kind = VARDECL_CONST;
}
} else {
kind =
declList->isKind(ParseNodeKind::VarStmt) ? VARDECL_VAR : VARDECL_CONST;
@ -2143,7 +2177,11 @@ bool ASTSerializer::forInit(ParseNode* pn, MutableHandleValue dst) {
}
bool lexical = pn->isKind(ParseNodeKind::LetDecl) ||
pn->isKind(ParseNodeKind::ConstDecl);
pn->isKind(ParseNodeKind::ConstDecl)
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|| pn->isKind(ParseNodeKind::UsingDecl)
#endif
;
return (lexical || pn->isKind(ParseNodeKind::VarStmt))
? variableDeclaration(&pn->as<ListNode>(), lexical, dst)
: expression(pn, dst);
@ -2218,6 +2256,9 @@ bool ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst) {
case ParseNodeKind::LetDecl:
case ParseNodeKind::ConstDecl:
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
case ParseNodeKind::UsingDecl:
#endif
return declaration(pn, dst);
case ParseNodeKind::ImportDecl:
@ -2339,6 +2380,9 @@ bool ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst) {
}
} else if (!initNode->isKind(ParseNodeKind::VarStmt) &&
!initNode->isKind(ParseNodeKind::LetDecl) &&
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
!initNode->isKind(ParseNodeKind::UsingDecl) &&
#endif
!initNode->isKind(ParseNodeKind::ConstDecl)) {
if (!pattern(initNode, &var)) {
return false;
@ -2347,6 +2391,9 @@ bool ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst) {
if (!variableDeclaration(
&initNode->as<ListNode>(),
initNode->isKind(ParseNodeKind::LetDecl) ||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
initNode->isKind(ParseNodeKind::UsingDecl) ||
#endif
initNode->isKind(ParseNodeKind::ConstDecl),
&var)) {
return false;

View File

@ -604,6 +604,15 @@ static bool GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
value = BooleanValue(true);
#else
value = BooleanValue(false);
#endif
if (!JS_SetProperty(cx, info, "explicit-resource-management", value)) {
return false;
}
#ifdef FUZZING
value = BooleanValue(true);
#else

View File

@ -1086,6 +1086,11 @@ restart:
MOZ_CRASH("Decorators are not supported yet");
#endif
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
case ParseNodeKind::UsingDecl:
MOZ_CRASH("Using declarations are not supported yet");
#endif
// Most other binary operations (parsed as lists in SpiderMonkey) may
// perform conversions triggering side effects. Math operations perform
// ToNumber and may fail invoking invalid user-defined toString/valueOf:

View File

@ -105,6 +105,9 @@ restart:
// Non-global lexical declarations are block-scoped (ergo not hoistable).
case ParseNodeKind::LetDecl:
case ParseNodeKind::ConstDecl:
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
case ParseNodeKind::UsingDecl:
#endif
MOZ_ASSERT(node->is<ListNode>());
*result = false;
return true;

View File

@ -6,7 +6,9 @@ import re
import sys
def read_reserved_word_list(filename, enable_decorators):
def read_reserved_word_list(
filename, enable_decorators, enable_explicit_resource_management
):
macro_pat = re.compile(r"MACRO\(([^,]+), *[^,]+, *[^\)]+\)\s*\\?")
reserved_word_list = []
@ -18,6 +20,8 @@ def read_reserved_word_list(filename, enable_decorators):
reserved_word = m.group(1)
if reserved_word == "accessor" and not enable_decorators:
continue
if reserved_word == "using" and not enable_explicit_resource_management:
continue
reserved_word_list.append((index, reserved_word))
index += 1
@ -216,8 +220,20 @@ def generate_switch(opt, reserved_word_list):
line(opt, "JSRW_NO_MATCH()")
def main(output, reserved_words_h, enable_decorators=False):
reserved_word_list = read_reserved_word_list(reserved_words_h, enable_decorators)
def main(output, reserved_words_h, *args):
enable_decorators = False
enable_explicit_resource_management = False
for arg in args:
if arg == "--enable-decorators":
enable_decorators = True
elif arg == "--enable-explicit-resource-management":
enable_explicit_resource_management = True
else:
raise ValueError("Unknown argument: " + arg)
reserved_word_list = read_reserved_word_list(
reserved_words_h, enable_decorators, enable_explicit_resource_management
)
opt = {
"indent_level": 1,

View File

@ -81,6 +81,9 @@ enum class DeclarationKind : uint8_t {
Var,
Let,
Const,
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
Using,
#endif
Class, // Handled as same as `let` after parsing.
Import,
BodyLevelFunction,
@ -120,6 +123,10 @@ static inline BindingKind DeclarationKindToBindingKind(DeclarationKind kind) {
return BindingKind::Let;
case DeclarationKind::Const:
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
case DeclarationKind::Using: // we treat using as a const for now. (Bug
// 1897609)
#endif
return BindingKind::Const;
case DeclarationKind::Import:

View File

@ -33,6 +33,10 @@ const char* DeclarationKindString(DeclarationKind kind) {
return "let";
case DeclarationKind::Const:
return "const";
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
case DeclarationKind::Using:
return "using";
#endif
case DeclarationKind::Class:
return "class";
case DeclarationKind::Import:

View File

@ -60,185 +60,186 @@ class FullParseHandler;
class FunctionBox;
#define FOR_EACH_PARSE_NODE_KIND(F) \
F(EmptyStmt, NullaryNode) \
F(ExpressionStmt, UnaryNode) \
F(CommaExpr, ListNode) \
F(ConditionalExpr, ConditionalExpression) \
F(PropertyDefinition, PropertyDefinition) \
F(Shorthand, BinaryNode) \
F(PosExpr, UnaryNode) \
F(NegExpr, UnaryNode) \
F(PreIncrementExpr, UnaryNode) \
F(PostIncrementExpr, UnaryNode) \
F(PreDecrementExpr, UnaryNode) \
F(PostDecrementExpr, UnaryNode) \
F(PropertyNameExpr, NameNode) \
F(DotExpr, PropertyAccess) \
F(ArgumentsLength, ArgumentsLength) \
F(ElemExpr, PropertyByValue) \
F(PrivateMemberExpr, PrivateMemberAccess) \
F(OptionalDotExpr, OptionalPropertyAccess) \
F(OptionalChain, UnaryNode) \
F(OptionalElemExpr, OptionalPropertyByValue) \
F(OptionalPrivateMemberExpr, OptionalPrivateMemberAccess) \
F(OptionalCallExpr, CallNode) \
F(ArrayExpr, ListNode) \
F(Elision, NullaryNode) \
F(StatementList, ListNode) \
F(LabelStmt, LabeledStatement) \
F(ObjectExpr, ListNode) \
F(CallExpr, CallNode) \
F(Arguments, ListNode) \
F(Name, NameNode) \
F(ObjectPropertyName, NameNode) \
F(PrivateName, NameNode) \
F(ComputedName, UnaryNode) \
F(NumberExpr, NumericLiteral) \
F(BigIntExpr, BigIntLiteral) \
F(StringExpr, NameNode) \
F(TemplateStringListExpr, ListNode) \
F(TemplateStringExpr, NameNode) \
F(TaggedTemplateExpr, CallNode) \
F(CallSiteObj, CallSiteNode) \
F(RegExpExpr, RegExpLiteral) \
F(TrueExpr, BooleanLiteral) \
F(FalseExpr, BooleanLiteral) \
F(NullExpr, NullLiteral) \
F(RawUndefinedExpr, RawUndefinedLiteral) \
F(ThisExpr, UnaryNode) \
IF_RECORD_TUPLE(F(RecordExpr, ListNode)) \
IF_RECORD_TUPLE(F(TupleExpr, ListNode)) \
F(Function, FunctionNode) \
F(Module, ModuleNode) \
F(IfStmt, TernaryNode) \
F(SwitchStmt, SwitchStatement) \
F(Case, CaseClause) \
F(WhileStmt, BinaryNode) \
F(DoWhileStmt, BinaryNode) \
F(ForStmt, ForNode) \
F(BreakStmt, BreakStatement) \
F(ContinueStmt, ContinueStatement) \
F(VarStmt, DeclarationListNode) \
F(ConstDecl, DeclarationListNode) \
F(WithStmt, BinaryNode) \
F(ReturnStmt, UnaryNode) \
F(NewExpr, CallNode) \
IF_DECORATORS(F(DecoratorList, ListNode)) \
/* Delete operations. These must be sequential. */ \
F(DeleteNameExpr, UnaryNode) \
F(DeletePropExpr, UnaryNode) \
F(DeleteElemExpr, UnaryNode) \
F(DeleteOptionalChainExpr, UnaryNode) \
F(DeleteExpr, UnaryNode) \
F(TryStmt, TernaryNode) \
F(Catch, BinaryNode) \
F(ThrowStmt, UnaryNode) \
F(DebuggerStmt, DebuggerStatement) \
F(Generator, NullaryNode) \
F(InitialYield, UnaryNode) \
F(YieldExpr, UnaryNode) \
F(YieldStarExpr, UnaryNode) \
F(LexicalScope, LexicalScopeNode) \
F(LetDecl, DeclarationListNode) \
F(ImportDecl, BinaryNode) \
F(ImportSpecList, ListNode) \
F(ImportSpec, BinaryNode) \
F(ImportNamespaceSpec, UnaryNode) \
F(ImportAttributeList, ListNode) \
F(ImportAttribute, BinaryNode) \
F(ImportModuleRequest, BinaryNode) \
F(ExportStmt, UnaryNode) \
F(ExportFromStmt, BinaryNode) \
F(ExportDefaultStmt, BinaryNode) \
F(ExportSpecList, ListNode) \
F(ExportSpec, BinaryNode) \
F(ExportNamespaceSpec, UnaryNode) \
F(ExportBatchSpecStmt, NullaryNode) \
F(ForIn, TernaryNode) \
F(ForOf, TernaryNode) \
F(ForHead, TernaryNode) \
F(ParamsBody, ParamsBodyNode) \
F(Spread, UnaryNode) \
F(MutateProto, UnaryNode) \
F(ClassDecl, ClassNode) \
F(DefaultConstructor, ClassMethod) \
F(ClassBodyScope, ClassBodyScopeNode) \
F(ClassMethod, ClassMethod) \
F(StaticClassBlock, StaticClassBlock) \
F(ClassField, ClassField) \
F(ClassMemberList, ListNode) \
F(ClassNames, ClassNames) \
F(NewTargetExpr, NewTargetNode) \
F(PosHolder, NullaryNode) \
F(SuperBase, UnaryNode) \
F(SuperCallExpr, CallNode) \
F(SetThis, BinaryNode) \
F(ImportMetaExpr, BinaryNode) \
F(CallImportExpr, BinaryNode) \
F(CallImportSpec, BinaryNode) \
F(InitExpr, BinaryNode) \
\
/* Unary operators. */ \
F(TypeOfNameExpr, UnaryNode) \
F(TypeOfExpr, UnaryNode) \
F(VoidExpr, UnaryNode) \
F(NotExpr, UnaryNode) \
F(BitNotExpr, UnaryNode) \
F(AwaitExpr, UnaryNode) \
\
/* \
* Binary operators. \
* This list must be kept in the same order in several places: \
* - The binary operators in ParseNode.h \
* - the binary operators in TokenKind.h \
* - the precedence list in Parser.cpp \
* - the JSOp code list in BytecodeEmitter.cpp \
*/ \
F(CoalesceExpr, ListNode) \
F(OrExpr, ListNode) \
F(AndExpr, ListNode) \
F(BitOrExpr, ListNode) \
F(BitXorExpr, ListNode) \
F(BitAndExpr, ListNode) \
F(StrictEqExpr, ListNode) \
F(EqExpr, ListNode) \
F(StrictNeExpr, ListNode) \
F(NeExpr, ListNode) \
F(LtExpr, ListNode) \
F(LeExpr, ListNode) \
F(GtExpr, ListNode) \
F(GeExpr, ListNode) \
F(InstanceOfExpr, ListNode) \
F(InExpr, ListNode) \
F(PrivateInExpr, ListNode) \
F(LshExpr, ListNode) \
F(RshExpr, ListNode) \
F(UrshExpr, ListNode) \
F(AddExpr, ListNode) \
F(SubExpr, ListNode) \
F(MulExpr, ListNode) \
F(DivExpr, ListNode) \
F(ModExpr, ListNode) \
F(PowExpr, ListNode) \
\
/* Assignment operators (= += -= etc.). */ \
/* AssignmentNode::test assumes all these are consecutive. */ \
F(AssignExpr, AssignmentNode) \
F(AddAssignExpr, AssignmentNode) \
F(SubAssignExpr, AssignmentNode) \
F(CoalesceAssignExpr, AssignmentNode) \
F(OrAssignExpr, AssignmentNode) \
F(AndAssignExpr, AssignmentNode) \
F(BitOrAssignExpr, AssignmentNode) \
F(BitXorAssignExpr, AssignmentNode) \
F(BitAndAssignExpr, AssignmentNode) \
F(LshAssignExpr, AssignmentNode) \
F(RshAssignExpr, AssignmentNode) \
F(UrshAssignExpr, AssignmentNode) \
F(MulAssignExpr, AssignmentNode) \
F(DivAssignExpr, AssignmentNode) \
F(ModAssignExpr, AssignmentNode) \
#define FOR_EACH_PARSE_NODE_KIND(F) \
F(EmptyStmt, NullaryNode) \
F(ExpressionStmt, UnaryNode) \
F(CommaExpr, ListNode) \
F(ConditionalExpr, ConditionalExpression) \
F(PropertyDefinition, PropertyDefinition) \
F(Shorthand, BinaryNode) \
F(PosExpr, UnaryNode) \
F(NegExpr, UnaryNode) \
F(PreIncrementExpr, UnaryNode) \
F(PostIncrementExpr, UnaryNode) \
F(PreDecrementExpr, UnaryNode) \
F(PostDecrementExpr, UnaryNode) \
F(PropertyNameExpr, NameNode) \
F(DotExpr, PropertyAccess) \
F(ArgumentsLength, ArgumentsLength) \
F(ElemExpr, PropertyByValue) \
F(PrivateMemberExpr, PrivateMemberAccess) \
F(OptionalDotExpr, OptionalPropertyAccess) \
F(OptionalChain, UnaryNode) \
F(OptionalElemExpr, OptionalPropertyByValue) \
F(OptionalPrivateMemberExpr, OptionalPrivateMemberAccess) \
F(OptionalCallExpr, CallNode) \
F(ArrayExpr, ListNode) \
F(Elision, NullaryNode) \
F(StatementList, ListNode) \
F(LabelStmt, LabeledStatement) \
F(ObjectExpr, ListNode) \
F(CallExpr, CallNode) \
F(Arguments, ListNode) \
F(Name, NameNode) \
F(ObjectPropertyName, NameNode) \
F(PrivateName, NameNode) \
F(ComputedName, UnaryNode) \
F(NumberExpr, NumericLiteral) \
F(BigIntExpr, BigIntLiteral) \
F(StringExpr, NameNode) \
F(TemplateStringListExpr, ListNode) \
F(TemplateStringExpr, NameNode) \
F(TaggedTemplateExpr, CallNode) \
F(CallSiteObj, CallSiteNode) \
F(RegExpExpr, RegExpLiteral) \
F(TrueExpr, BooleanLiteral) \
F(FalseExpr, BooleanLiteral) \
F(NullExpr, NullLiteral) \
F(RawUndefinedExpr, RawUndefinedLiteral) \
F(ThisExpr, UnaryNode) \
IF_RECORD_TUPLE(F(RecordExpr, ListNode)) \
IF_RECORD_TUPLE(F(TupleExpr, ListNode)) \
F(Function, FunctionNode) \
F(Module, ModuleNode) \
F(IfStmt, TernaryNode) \
F(SwitchStmt, SwitchStatement) \
F(Case, CaseClause) \
F(WhileStmt, BinaryNode) \
F(DoWhileStmt, BinaryNode) \
F(ForStmt, ForNode) \
F(BreakStmt, BreakStatement) \
F(ContinueStmt, ContinueStatement) \
F(VarStmt, DeclarationListNode) \
F(ConstDecl, DeclarationListNode) \
IF_EXPLICIT_RESOURCE_MANAGEMENT(F(UsingDecl, DeclarationListNode)) \
F(WithStmt, BinaryNode) \
F(ReturnStmt, UnaryNode) \
F(NewExpr, CallNode) \
IF_DECORATORS(F(DecoratorList, ListNode)) \
/* Delete operations. These must be sequential. */ \
F(DeleteNameExpr, UnaryNode) \
F(DeletePropExpr, UnaryNode) \
F(DeleteElemExpr, UnaryNode) \
F(DeleteOptionalChainExpr, UnaryNode) \
F(DeleteExpr, UnaryNode) \
F(TryStmt, TernaryNode) \
F(Catch, BinaryNode) \
F(ThrowStmt, UnaryNode) \
F(DebuggerStmt, DebuggerStatement) \
F(Generator, NullaryNode) \
F(InitialYield, UnaryNode) \
F(YieldExpr, UnaryNode) \
F(YieldStarExpr, UnaryNode) \
F(LexicalScope, LexicalScopeNode) \
F(LetDecl, DeclarationListNode) \
F(ImportDecl, BinaryNode) \
F(ImportSpecList, ListNode) \
F(ImportSpec, BinaryNode) \
F(ImportNamespaceSpec, UnaryNode) \
F(ImportAttributeList, ListNode) \
F(ImportAttribute, BinaryNode) \
F(ImportModuleRequest, BinaryNode) \
F(ExportStmt, UnaryNode) \
F(ExportFromStmt, BinaryNode) \
F(ExportDefaultStmt, BinaryNode) \
F(ExportSpecList, ListNode) \
F(ExportSpec, BinaryNode) \
F(ExportNamespaceSpec, UnaryNode) \
F(ExportBatchSpecStmt, NullaryNode) \
F(ForIn, TernaryNode) \
F(ForOf, TernaryNode) \
F(ForHead, TernaryNode) \
F(ParamsBody, ParamsBodyNode) \
F(Spread, UnaryNode) \
F(MutateProto, UnaryNode) \
F(ClassDecl, ClassNode) \
F(DefaultConstructor, ClassMethod) \
F(ClassBodyScope, ClassBodyScopeNode) \
F(ClassMethod, ClassMethod) \
F(StaticClassBlock, StaticClassBlock) \
F(ClassField, ClassField) \
F(ClassMemberList, ListNode) \
F(ClassNames, ClassNames) \
F(NewTargetExpr, NewTargetNode) \
F(PosHolder, NullaryNode) \
F(SuperBase, UnaryNode) \
F(SuperCallExpr, CallNode) \
F(SetThis, BinaryNode) \
F(ImportMetaExpr, BinaryNode) \
F(CallImportExpr, BinaryNode) \
F(CallImportSpec, BinaryNode) \
F(InitExpr, BinaryNode) \
\
/* Unary operators. */ \
F(TypeOfNameExpr, UnaryNode) \
F(TypeOfExpr, UnaryNode) \
F(VoidExpr, UnaryNode) \
F(NotExpr, UnaryNode) \
F(BitNotExpr, UnaryNode) \
F(AwaitExpr, UnaryNode) \
\
/* \
* Binary operators. \
* This list must be kept in the same order in several places: \
* - The binary operators in ParseNode.h \
* - the binary operators in TokenKind.h \
* - the precedence list in Parser.cpp \
* - the JSOp code list in BytecodeEmitter.cpp \
*/ \
F(CoalesceExpr, ListNode) \
F(OrExpr, ListNode) \
F(AndExpr, ListNode) \
F(BitOrExpr, ListNode) \
F(BitXorExpr, ListNode) \
F(BitAndExpr, ListNode) \
F(StrictEqExpr, ListNode) \
F(EqExpr, ListNode) \
F(StrictNeExpr, ListNode) \
F(NeExpr, ListNode) \
F(LtExpr, ListNode) \
F(LeExpr, ListNode) \
F(GtExpr, ListNode) \
F(GeExpr, ListNode) \
F(InstanceOfExpr, ListNode) \
F(InExpr, ListNode) \
F(PrivateInExpr, ListNode) \
F(LshExpr, ListNode) \
F(RshExpr, ListNode) \
F(UrshExpr, ListNode) \
F(AddExpr, ListNode) \
F(SubExpr, ListNode) \
F(MulExpr, ListNode) \
F(DivExpr, ListNode) \
F(ModExpr, ListNode) \
F(PowExpr, ListNode) \
\
/* Assignment operators (= += -= etc.). */ \
/* AssignmentNode::test assumes all these are consecutive. */ \
F(AssignExpr, AssignmentNode) \
F(AddAssignExpr, AssignmentNode) \
F(SubAssignExpr, AssignmentNode) \
F(CoalesceAssignExpr, AssignmentNode) \
F(OrAssignExpr, AssignmentNode) \
F(AndAssignExpr, AssignmentNode) \
F(BitOrAssignExpr, AssignmentNode) \
F(BitXorAssignExpr, AssignmentNode) \
F(BitAndAssignExpr, AssignmentNode) \
F(LshAssignExpr, AssignmentNode) \
F(RshAssignExpr, AssignmentNode) \
F(UrshAssignExpr, AssignmentNode) \
F(MulAssignExpr, AssignmentNode) \
F(DivAssignExpr, AssignmentNode) \
F(ModAssignExpr, AssignmentNode) \
F(PowAssignExpr, AssignmentNode)
/*
@ -1256,7 +1257,7 @@ class ListNode : public ParseNode {
void checkConsistency() const
#ifndef DEBUG
{}
{}
#endif
;
@ -1483,6 +1484,9 @@ class DeclarationListNode : public ListNode {
static bool test(const ParseNode& node) {
bool match = node.isKind(ParseNodeKind::VarStmt) ||
node.isKind(ParseNodeKind::LetDecl) ||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
node.isKind(ParseNodeKind::UsingDecl) ||
#endif
node.isKind(ParseNodeKind::ConstDecl);
MOZ_ASSERT_IF(match, node.is<ListNode>());
return match;

View File

@ -733,6 +733,9 @@ bool GeneralParser<ParseHandler, Unit>::noteDeclaredName(
case DeclarationKind::Let:
case DeclarationKind::Const:
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
case DeclarationKind::Using:
#endif
case DeclarationKind::Class:
// The BoundNames of LexicalDeclaration and ForDeclaration must not
// contain 'let'. (CatchParameter is the only lexical binding form
@ -4761,6 +4764,12 @@ GeneralParser<ParseHandler, Unit>::declarationName(DeclarationKind declKind,
if (isForIn) {
*forHeadKind = ParseNodeKind::ForIn;
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
if (declKind == DeclarationKind::Using) {
errorAt(namePos.begin, JSMSG_NO_IN_WITH_USING);
return errorResult();
}
#endif
} else if (isForOf) {
*forHeadKind = ParseNodeKind::ForOf;
} else {
@ -4797,7 +4806,11 @@ GeneralParser<ParseHandler, Unit>::declarationList(
ParseNodeKind* forHeadKind /* = nullptr */,
Node* forInOrOfExpression /* = nullptr */) {
MOZ_ASSERT(kind == ParseNodeKind::VarStmt || kind == ParseNodeKind::LetDecl ||
kind == ParseNodeKind::ConstDecl);
kind == ParseNodeKind::ConstDecl
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|| kind == ParseNodeKind::UsingDecl
#endif
);
DeclarationKind declKind;
switch (kind) {
@ -4810,6 +4823,11 @@ GeneralParser<ParseHandler, Unit>::declarationList(
case ParseNodeKind::LetDecl:
declKind = DeclarationKind::Let;
break;
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
case ParseNodeKind::UsingDecl:
declKind = DeclarationKind::Using;
break;
#endif
default:
MOZ_CRASH("Unknown declaration kind");
}
@ -4862,7 +4880,11 @@ template <class ParseHandler, typename Unit>
typename ParseHandler::DeclarationListNodeResult
GeneralParser<ParseHandler, Unit>::lexicalDeclaration(
YieldHandling yieldHandling, DeclarationKind kind) {
MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let);
MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|| kind == DeclarationKind::Using
#endif
);
if (options().selfHostingMode) {
error(JSMSG_SELFHOSTED_LEXICAL);
@ -4881,10 +4903,23 @@ GeneralParser<ParseHandler, Unit>::lexicalDeclaration(
* See 8.1.1.1.6 and the note in 13.2.1.
*/
DeclarationListNodeType decl;
MOZ_TRY_VAR(decl,
declarationList(yieldHandling, kind == DeclarationKind::Const
? ParseNodeKind::ConstDecl
: ParseNodeKind::LetDecl));
ParseNodeKind pnk;
switch (kind) {
case DeclarationKind::Const:
pnk = ParseNodeKind::ConstDecl;
break;
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
case DeclarationKind::Using:
pnk = ParseNodeKind::UsingDecl;
break;
#endif
case DeclarationKind::Let:
pnk = ParseNodeKind::LetDecl;
break;
default:
MOZ_CRASH("unexpected node kind");
}
MOZ_TRY_VAR(decl, declarationList(yieldHandling, pnk));
if (!matchOrInsertSemicolon()) {
return errorResult();
}
@ -6440,10 +6475,30 @@ bool GeneralParser<ParseHandler, Unit>::forHeadStart(
bool parsingLexicalDeclaration = false;
bool letIsIdentifier = false;
bool startsWithForOf = false;
if (tt == TokenKind::Const) {
parsingLexicalDeclaration = true;
tokenStream.consumeKnownToken(tt, TokenStream::SlashIsRegExp);
} else if (tt == TokenKind::Let) {
}
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
else if (tt == TokenKind::Using) {
tokenStream.consumeKnownToken(tt, TokenStream::SlashIsRegExp);
// Look ahead to find either a 'of' token or if not identifier
TokenKind nextTok = TokenKind::Eof;
if (!tokenStream.peekTokenSameLine(&nextTok)) {
return false;
}
if (nextTok == TokenKind::Of || !TokenKindIsPossibleIdentifier(nextTok)) {
anyChars.ungetToken(); // we didnt find a valid case of using decl put
// back the token
} else {
parsingLexicalDeclaration = true;
}
}
#endif
else if (tt == TokenKind::Let) {
// We could have a {For,Lexical}Declaration, or we could have a
// LeftHandSideExpression with lookahead restrictions so it's not
// ambiguous with the former. Check for a continuation of the former
@ -6499,13 +6554,27 @@ bool GeneralParser<ParseHandler, Unit>::forHeadStart(
// statements.
ParseContext::Statement forHeadStmt(pc_, StatementKind::ForLoopLexicalHead);
MOZ_TRY_VAR_OR_RETURN(
*forInitialPart,
declarationList(yieldHandling,
tt == TokenKind::Const ? ParseNodeKind::ConstDecl
: ParseNodeKind::LetDecl,
forHeadKind, forInOrOfExpression),
false);
ParseNodeKind declKind;
switch (tt) {
case TokenKind::Const:
declKind = ParseNodeKind::ConstDecl;
break;
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
case TokenKind::Using:
declKind = ParseNodeKind::UsingDecl;
break;
#endif
case TokenKind::Let:
declKind = ParseNodeKind::LetDecl;
break;
default:
MOZ_CRASH("unexpected node kind");
}
MOZ_TRY_VAR_OR_RETURN(*forInitialPart,
declarationList(yieldHandling, declKind, forHeadKind,
forInOrOfExpression),
false);
return true;
}
@ -9612,6 +9681,26 @@ GeneralParser<ParseHandler, Unit>::statementListItem(
// their heads to handle |in| in this situation.
return lexicalDeclaration(yieldHandling, DeclarationKind::Const);
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
case TokenKind::Using: {
TokenKind nextTok = TokenKind::Eol;
if (!tokenStream.peekTokenSameLine(&nextTok)) {
return errorResult();
}
if (!TokenKindIsPossibleIdentifier(nextTok)) {
if (!tokenStream.peekToken(&nextTok)) {
return errorResult();
}
// labelled statement could be like using\n:\nexpr
if (nextTok == TokenKind::Colon) {
return labeledStatement(yieldHandling);
}
return expressionStatement(yieldHandling);
}
return lexicalDeclaration(yieldHandling, DeclarationKind::Using);
}
#endif
// ImportDeclaration (only inside modules)
case TokenKind::Import:
return importDeclarationOrImportExpr(yieldHandling);

View File

@ -9,70 +9,71 @@
#ifndef vm_ReservedWords_h
#define vm_ReservedWords_h
#define FOR_EACH_JAVASCRIPT_RESERVED_WORD(MACRO) \
MACRO(false, false_, TokenKind::False) \
MACRO(true, true_, TokenKind::True) \
MACRO(null, null, TokenKind::Null) \
\
/* Keywords. */ \
MACRO(break, break_, TokenKind::Break) \
MACRO(case, case_, TokenKind::Case) \
MACRO(catch, catch_, TokenKind::Catch) \
MACRO(const, const_, TokenKind::Const) \
MACRO(continue, continue_, TokenKind::Continue) \
MACRO(debugger, debugger, TokenKind::Debugger) \
MACRO(default, default_, TokenKind::Default) \
MACRO(delete, delete_, TokenKind::Delete) \
MACRO(do, do_, TokenKind::Do) \
MACRO(else, else_, TokenKind::Else) \
MACRO(finally, finally_, TokenKind::Finally) \
MACRO(for, for_, TokenKind::For) \
MACRO(function, function, TokenKind::Function) \
MACRO(if, if_, TokenKind::If) \
MACRO(in, in, TokenKind::In) \
MACRO(instanceof, instanceof, TokenKind::InstanceOf) \
MACRO(new, new_, TokenKind::New) \
MACRO(return, return_, TokenKind::Return) \
MACRO(switch, switch_, TokenKind::Switch) \
MACRO(this, this_, TokenKind::This) \
MACRO(throw, throw_, TokenKind::Throw) \
MACRO(try, try_, TokenKind::Try) \
MACRO(typeof, typeof_, TokenKind::TypeOf) \
MACRO(var, var, TokenKind::Var) \
MACRO(void, void_, TokenKind::Void) \
MACRO(while, while_, TokenKind::While) \
MACRO(with, with, TokenKind::With) \
MACRO(import, import, TokenKind::Import) \
MACRO(export, export_, TokenKind::Export) \
MACRO(class, class_, TokenKind::Class) \
MACRO(extends, extends, TokenKind::Extends) \
IF_DECORATORS(MACRO(accessor, accessor, TokenKind::Accessor)) \
MACRO(super, super, TokenKind::Super) \
\
/* Future reserved words. */ \
MACRO(enum, enum_, TokenKind::Enum) \
\
/* Future reserved words, but only in strict mode. */ \
MACRO(implements, implements, TokenKind::Implements) \
MACRO(interface, interface, TokenKind::Interface) \
MACRO(package, package, TokenKind::Package) \
MACRO(private, private_, TokenKind::Private) \
MACRO(protected, protected_, TokenKind::Protected) \
MACRO(public, public_, TokenKind::Public) \
\
/* Contextual keywords. */ \
MACRO(as, as, TokenKind::As) \
MACRO(assert, assert_, TokenKind::Assert) \
MACRO(async, async, TokenKind::Async) \
MACRO(await, await, TokenKind::Await) \
MACRO(from, from, TokenKind::From) \
MACRO(get, get, TokenKind::Get) \
MACRO(let, let, TokenKind::Let) \
MACRO(meta, meta, TokenKind::Meta) \
MACRO(of, of, TokenKind::Of) \
MACRO(set, set, TokenKind::Set) \
MACRO(static, static_, TokenKind::Static) \
MACRO(target, target, TokenKind::Target) \
#define FOR_EACH_JAVASCRIPT_RESERVED_WORD(MACRO) \
MACRO(false, false_, TokenKind::False) \
MACRO(true, true_, TokenKind::True) \
MACRO(null, null, TokenKind::Null) \
\
/* Keywords. */ \
MACRO(break, break_, TokenKind::Break) \
MACRO(case, case_, TokenKind::Case) \
MACRO(catch, catch_, TokenKind::Catch) \
MACRO(const, const_, TokenKind::Const) \
MACRO(continue, continue_, TokenKind::Continue) \
MACRO(debugger, debugger, TokenKind::Debugger) \
MACRO(default, default_, TokenKind::Default) \
MACRO(delete, delete_, TokenKind::Delete) \
MACRO(do, do_, TokenKind::Do) \
MACRO(else, else_, TokenKind::Else) \
MACRO(finally, finally_, TokenKind::Finally) \
MACRO(for, for_, TokenKind::For) \
MACRO(function, function, TokenKind::Function) \
MACRO(if, if_, TokenKind::If) \
MACRO(in, in, TokenKind::In) \
MACRO(instanceof, instanceof, TokenKind::InstanceOf) \
MACRO(new, new_, TokenKind::New) \
MACRO(return, return_, TokenKind::Return) \
MACRO(switch, switch_, TokenKind::Switch) \
MACRO(this, this_, TokenKind::This) \
MACRO(throw, throw_, TokenKind::Throw) \
MACRO(try, try_, TokenKind::Try) \
MACRO(typeof, typeof_, TokenKind::TypeOf) \
IF_EXPLICIT_RESOURCE_MANAGEMENT(MACRO(using, using_, TokenKind::Using)) \
MACRO(var, var, TokenKind::Var) \
MACRO(void, void_, TokenKind::Void) \
MACRO(while, while_, TokenKind::While) \
MACRO(with, with, TokenKind::With) \
MACRO(import, import, TokenKind::Import) \
MACRO(export, export_, TokenKind::Export) \
MACRO(class, class_, TokenKind::Class) \
MACRO(extends, extends, TokenKind::Extends) \
IF_DECORATORS(MACRO(accessor, accessor, TokenKind::Accessor)) \
MACRO(super, super, TokenKind::Super) \
\
/* Future reserved words. */ \
MACRO(enum, enum_, TokenKind::Enum) \
\
/* Future reserved words, but only in strict mode. */ \
MACRO(implements, implements, TokenKind::Implements) \
MACRO(interface, interface, TokenKind::Interface) \
MACRO(package, package, TokenKind::Package) \
MACRO(private, private_, TokenKind::Private) \
MACRO(protected, protected_, TokenKind::Protected) \
MACRO(public, public_, TokenKind::Public) \
\
/* Contextual keywords. */ \
MACRO(as, as, TokenKind::As) \
MACRO(assert, assert_, TokenKind::Assert) \
MACRO(async, async, TokenKind::Async) \
MACRO(await, await, TokenKind::Await) \
MACRO(from, from, TokenKind::From) \
MACRO(get, get, TokenKind::Get) \
MACRO(let, let, TokenKind::Let) \
MACRO(meta, meta, TokenKind::Meta) \
MACRO(of, of, TokenKind::Of) \
MACRO(set, set, TokenKind::Set) \
MACRO(static, static_, TokenKind::Static) \
MACRO(target, target, TokenKind::Target) \
MACRO(yield, yield, TokenKind::Yield)
#endif /* vm_ReservedWords_h */

View File

@ -693,6 +693,9 @@ class SyntaxParseHandler {
MOZ_ASSERT(kind != ParseNodeKind::LetDecl);
MOZ_ASSERT(kind != ParseNodeKind::ConstDecl);
MOZ_ASSERT(kind != ParseNodeKind::ParamsBody);
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
MOZ_ASSERT(kind != ParseNodeKind::UsingDecl);
#endif
return NodeGeneric;
}
@ -706,7 +709,11 @@ class SyntaxParseHandler {
return NodeVarDeclaration;
}
MOZ_ASSERT(kind == ParseNodeKind::LetDecl ||
kind == ParseNodeKind::ConstDecl);
kind == ParseNodeKind::ConstDecl
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|| kind == ParseNodeKind::UsingDecl
#endif
);
return NodeLexicalDeclaration;
}

View File

@ -143,6 +143,7 @@
MACRO(Set, "'set'") \
MACRO(Static, "'static'") \
MACRO(Target, "'target'") \
IF_EXPLICIT_RESOURCE_MANAGEMENT(MACRO(Using, "'using'")) \
MACRO(Yield, "'yield'") \
RANGE(ContextualKeywordLast, Yield) \
\

View File

@ -14,12 +14,17 @@ include("../js-cxxflags.mozbuild")
# Generate frontend/ReservedWordsGenerated.h from frontend/ReservedWords.h
flags = []
if CONFIG["ENABLE_DECORATORS"]:
flags.append("--enable-decorators")
if CONFIG["ENABLE_EXPLICIT_RESOURCE_MANAGEMENT"]:
flags.append("--enable-explicit-resource-management")
if flags:
GeneratedFile(
"ReservedWordsGenerated.h",
script="GenerateReservedWords.py",
inputs=["ReservedWords.h"],
flags=["--enable-decorators"],
flags=flags,
)
else:
GeneratedFile(

View File

@ -0,0 +1,159 @@
// |jit-test| skip-if: !getBuildConfiguration("explicit-resource-management")
load(libdir + "asserts.js");
Reflect.parse("using x = {}");
Reflect.parse("using x = fn()");
Reflect.parse("{ using x = fn(); }");
Reflect.parse("function f() { using x = fn(); }");
Reflect.parse("using a = fn1(), b = fn2();");
Reflect.parse("for (using x of y) {}");
Reflect.parse("async function fn() { for await (using x of y) {} }");
Reflect.parse("using x = null");
Reflect.parse("using x = undefined");
// Existing syntaxes that should not break
Reflect.parse("for (using of y) {}");
Reflect.parse("for (using of of) {}");
Reflect.parse("for (using\nof y) {}");
Reflect.parse("const using = 10");
Reflect.parse("let using = 10");
Reflect.parse("var using = 10");
Reflect.parse("using = 10");
Reflect.parse("using + 1");
Reflect.parse("using++");
Reflect.parse("using\nx = 10");
Reflect.parse("using = {x: 10}");
Reflect.parse("x = { using: 10 }");
Reflect.parse("x.using = 10");
Reflect.parse("x\n.using = 10");
Reflect.parse("using.x = 10");
Reflect.parse("using\n.x = 10");
Reflect.parse("for (using[1] of {}) {}");
Reflect.parse("for (using\n[1] of {}) {}")
Reflect.parse("for (using.x of {}) {}");
Reflect.parse("for (using\n.x of {}) {}");
Reflect.parse("for (x.using in {}) {}");
Reflect.parse("for (x\n.using in {}) {}")
Reflect.parse("using: x = 10;");
Reflect.parse("using\n: x = 10;");
Reflect.parse("using /a/g;");
Reflect.parse("/using/g");
Reflect.parse("export const using = 10", { target: "module" });
Reflect.parse("import using from 'xyz'", { target: "module" });
// ast checks
const ast = Reflect.parse("using x = {}");
assertEq(ast.body[0].type, "VariableDeclaration");
assertEq(ast.body[0].kind, "using");
assertEq(ast.body[0].declarations[0].type, "VariableDeclarator");
assertEq(ast.body[0].declarations[0].id.name, "x");
const ast2 = Reflect.parse("for (using x of y) {}");
assertEq(ast2.body[0].type, "ForOfStatement");
assertEq(ast2.body[0].left.type, "VariableDeclaration");
assertEq(ast2.body[0].left.kind, "using");
assertEq(ast2.body[0].left.declarations[0].type, "VariableDeclarator");
assertEq(ast2.body[0].left.declarations[0].id.type, "Identifier");
assertEq(ast2.body[0].left.declarations[0].id.name, "x");
const ast3 = Reflect.parse("async function fn() { for await (using x of y) {} }");
const forStatement = ast3.body[0].body.body[0];
assertEq(forStatement.type, "ForOfStatement");
assertEq(forStatement.left.type, "VariableDeclaration");
assertEq(forStatement.left.kind, "using");
assertEq(forStatement.left.declarations[0].type, "VariableDeclarator");
assertEq(forStatement.left.declarations[0].id.type, "Identifier");
assertEq(forStatement.left.declarations[0].id.name, "x");
const ast4 = Reflect.parse("using = 10");
assertEq(ast4.body[0].type, "ExpressionStatement");
assertEq(ast4.body[0].expression.type, "AssignmentExpression");
assertEq(ast4.body[0].expression.left.type, "Identifier");
assertEq(ast4.body[0].expression.left.name, "using");
const ast5 = Reflect.parse("for (using of y) {}");
assertEq(ast5.body[0].type, "ForOfStatement");
assertEq(ast5.body[0].left.type, "Identifier");
assertEq(ast5.body[0].left.name, "using");
const ast6 = Reflect.parse("using + 1");
assertEq(ast6.body[0].type, "ExpressionStatement");
assertEq(ast6.body[0].expression.type, "BinaryExpression");
assertEq(ast6.body[0].expression.left.type, "Identifier");
assertEq(ast6.body[0].expression.left.name, "using");
const ast7 = Reflect.parse("for (using of of) {}");
assertEq(ast7.body[0].type, "ForOfStatement");
assertEq(ast7.body[0].left.type, "Identifier");
assertEq(ast7.body[0].left.name, "using");
assertEq(ast7.body[0].right.type, "Identifier");
assertEq(ast7.body[0].right.name, "of");
const ast8 = Reflect.parse("for (using\nof y) {}");
assertEq(ast8.body[0].type, "ForOfStatement");
assertEq(ast8.body[0].left.type, "Identifier");
assertEq(ast8.body[0].left.name, "using");
assertEq(ast8.body[0].right.type, "Identifier");
assertEq(ast8.body[0].right.name, "y");
const ast9 = Reflect.parse("for (using[1] of {}) {}");
assertEq(ast9.body[0].type, "ForOfStatement");
assertEq(ast9.body[0].left.type, "MemberExpression");
assertEq(ast9.body[0].left.object.type, "Identifier");
assertEq(ast9.body[0].left.object.name, "using");
assertEq(ast9.body[0].left.property.type, "Literal");
assertEq(ast9.body[0].left.property.value, 1);
const ast10 = Reflect.parse("for (using\n[1] of {}) {}");
assertEq(ast10.body[0].type, "ForOfStatement");
assertEq(ast10.body[0].left.type, "MemberExpression");
assertEq(ast10.body[0].left.object.type, "Identifier");
assertEq(ast10.body[0].left.object.name, "using");
assertEq(ast10.body[0].left.property.type, "Literal");
assertEq(ast10.body[0].left.property.value, 1);
const ast11 = Reflect.parse("/using/g");
assertEq(ast11.body[0].type, "ExpressionStatement");
assertEq(ast11.body[0].expression.type, "Literal");
assertEq(ast11.body[0].expression.value.source, "using");
assertEq(ast11.body[0].expression.value.flags, "g");
const ast12 = Reflect.parse("using: x = 10;");
assertEq(ast12.body[0].type, "LabeledStatement");
assertEq(ast12.body[0].label.type, "Identifier");
assertEq(ast12.body[0].label.name, "using");
const ast13 = Reflect.parse("using\n: x = 10;");
assertEq(ast13.body[0].type, "LabeledStatement");
assertEq(ast13.body[0].label.type, "Identifier");
assertEq(ast13.body[0].label.name, "using");
const ast14 = Reflect.parse("using /a/g;");
// should be parsed as division, not regex
assertEq(ast14.body[0].type, "ExpressionStatement");
assertEq(ast14.body[0].expression.type, "BinaryExpression");
assertEq(ast14.body[0].expression.operator, "/");
assertEq(ast14.body[0].expression.left.type, "BinaryExpression");
assertEq(ast14.body[0].expression.left.operator, "/");
const ast15 = Reflect.parse("import using from 'xyz'", { target: "module" });
assertEq(ast15.body[0].type, "ImportDeclaration");
assertEq(ast15.body[0].specifiers[0].type, "ImportSpecifier");
assertEq(ast15.body[0].specifiers[0].name.name, "using");
assertThrowsInstanceOf(() => Reflect.parse("const using x = fn()"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("let using x = fn()"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("var using x = fn()"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("using const x = fn()"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("using let x = fn()"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("using var x = fn()"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("using x = fn(), x = fn()"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("for (using x in y) {}"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("for (using\nx of y) {}"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("for (using of of y) {}"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("using /a/;"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("for (using /a/g of y) {}"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("if(1) using x = {}"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("for (;;) using x = 10;"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("foo: using x = 10;"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("export using x = 10", { target: "module" }), SyntaxError);

View File

@ -605,6 +605,7 @@
MACRO_(use_asm_, "use asm") \
MACRO_(use_strict_, "use strict") \
MACRO_(useGrouping, "useGrouping") \
IF_EXPLICIT_RESOURCE_MANAGEMENT(MACRO_(using_, "using")) \
MACRO_(UTC, "UTC") \
MACRO_(value, "value") \
MACRO_(valueOf, "valueOf") \