mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
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:
parent
c3ecdeeb2d
commit
49af7ffb9e
@ -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
|
||||
# ===================================================
|
||||
|
@ -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 */
|
||||
|
@ -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")
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -121,6 +121,7 @@ class FunctionBox;
|
||||
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) \
|
||||
@ -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;
|
||||
|
@ -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,12 +6554,26 @@ 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),
|
||||
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);
|
||||
|
@ -38,6 +38,7 @@
|
||||
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) \
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) \
|
||||
\
|
||||
|
@ -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(
|
||||
|
159
js/src/jit-test/tests/explicit-resource-management/syntax.js
Normal file
159
js/src/jit-test/tests/explicit-resource-management/syntax.js
Normal 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);
|
@ -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") \
|
||||
|
Loading…
Reference in New Issue
Block a user