Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Esprima/JavascriptParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4625,7 +4625,7 @@ private FunctionExpression ParseMethod(bool isAsync, bool generator)
[StringMatcher("[", "(", "{", "+", "-", "!", "~", "++", "--", "/", "/=")]
private static partial bool IsPunctuatorExpressionStart(string input);

[StringMatcher("class", "delete", "function", "let", "new", "super", "this", "typeof", "void", "yield")]
[StringMatcher("class", "delete", "function", "import", "new", "super", "this", "typeof", "void", "yield")]
private static partial bool IsKeywordExpressionStart(string input);

private protected virtual bool IsStartOfExpression()
Expand All @@ -4643,7 +4643,7 @@ private protected virtual bool IsStartOfExpression()
}
else if (_lookahead.Type == TokenType.Keyword)
{
start = IsKeywordExpressionStart(value);
start = IsKeywordExpressionStart(value) || !_context.IsModule && value == "let";
}

return start;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,7 @@ private static partial bool IsKeywordExpressionStart(string input)
{
case 3:
{
return input[0] switch
{
'l' => input == "let",
'n' => input == "new",
_ => false
};
return input == "new";
}
case 4:
{
Expand All @@ -143,6 +138,7 @@ private static partial bool IsKeywordExpressionStart(string input)
return input[0] switch
{
'd' => input == "delete",
'i' => input == "import",
't' => input == "typeof",
_ => false
};
Expand Down
4 changes: 0 additions & 4 deletions test/Esprima.Tests.Test262/allow-list.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1172,8 +1172,6 @@ test/language/expressions/class/elements/syntax/early-errors/invalid-names/metho
test/language/expressions/class/static-init-await-binding.js(default)
test/language/expressions/class/static-init-await-binding.js(strict mode)
test/language/expressions/dynamic-import/escape-sequence-import.js(default)
test/language/expressions/dynamic-import/for-await-resolution-and-error-agen-yield.js(default)
test/language/expressions/dynamic-import/for-await-resolution-and-error-agen-yield.js(strict mode)
test/language/expressions/generators/param-dflt-yield.js(default)
test/language/expressions/in/private-field-in-nested.js(default)
test/language/expressions/in/private-field-in-nested.js(strict mode)
Expand Down Expand Up @@ -1248,8 +1246,6 @@ test/language/import/escaped-as-namespace-import.js(strict mode)
test/language/import/escaped-from.js(strict mode)
test/language/literals/bigint/mv-is-not-integer-dil-dot-dds.js(default)
test/language/literals/bigint/mv-is-not-integer-dil-dot-dds.js(strict mode)
test/language/literals/bigint/mv-is-not-integer-dot-dds.js(default)
test/language/literals/bigint/mv-is-not-integer-dot-dds.js(strict mode)
test/language/literals/regexp/named-groups/forward-reference.js(default)
test/language/literals/regexp/named-groups/forward-reference.js(strict mode)
test/language/literals/string/legacy-non-octal-escape-sequence-8-strict-explicit-pragma.js(default)
Expand Down
85 changes: 76 additions & 9 deletions test/Esprima.Tests/ParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -620,24 +620,91 @@ public void ShouldParseTopLevelAwait(string sourceType, bool shouldThrow)
const string code = "await import('x')";

var parser = new JavaScriptParser();
Func<JavaScriptParser, Node> parseAction = sourceType switch
{
"script" => parser => parser.ParseScript(code),
"module" => parser => parser.ParseModule(code),
"expression" => parser => parser.ParseExpression(code),
_ => throw new InvalidOperationException()
};
var parseAction = GetParseActionFor(sourceType);

if (!shouldThrow)
{
var node = parseAction(parser);
var node = parseAction(parser, code);
var awaitExpression = node.DescendantNodesAndSelf().OfType<AwaitExpression>().FirstOrDefault();
Assert.NotNull(awaitExpression);
Assert.IsType<ImportExpression>(awaitExpression.Argument);
}
else
{
Assert.Throws<ParserException>(() => parseAction(parser));
Assert.Throws<ParserException>(() => parseAction(parser, code));
}
}

[Theory]
[InlineData("script", false)]
[InlineData("module", true)]
[InlineData("expression", false)]
public void ShouldAllowLetKeywordInYieldExpression(string sourceType, bool shouldThrow)
{
// See also: https://github.com/sebastienros/esprima-dotnet/issues/403

const string code = "function* f(x) { yield let }";

var parser = new JavaScriptParser();
var parseAction = GetParseActionFor(sourceType);

if (!shouldThrow)
{
var node = parseAction(parser, code);
var yieldExpression = node.DescendantNodesAndSelf().OfType<YieldExpression>().FirstOrDefault();
Assert.NotNull(yieldExpression);
Assert.IsType<Identifier>(yieldExpression.Argument);
Assert.Equal("let", yieldExpression.Argument.As<Identifier>().Name);
}
else
{
Assert.Throws<ParserException>(() => parseAction(parser, code));
}
}

[Theory]
[InlineData("script")]
[InlineData("module")]
[InlineData("expression")]
public void ShouldAllowImportExpressionInYieldExpression(string sourceType)
{
// See also: https://github.com/sebastienros/esprima-dotnet/issues/403

const string code = "function* f(x) { yield import(x) }";

var parser = new JavaScriptParser();
var parseAction = GetParseActionFor(sourceType);

var node = parseAction(parser, code);
var yieldExpression = node.DescendantNodesAndSelf().OfType<YieldExpression>().FirstOrDefault();
Assert.NotNull(yieldExpression);
Assert.IsType<ImportExpression>(yieldExpression.Argument);
}

[Theory]
[InlineData("script")]
[InlineData("module")]
[InlineData("expression")]
public void ShouldDisallowImportKeywordInYieldExpression(string sourceType)
{
// See also: https://github.com/sebastienros/esprima-dotnet/issues/403

const string code = "function* f(x) { yield import }";

var parser = new JavaScriptParser();
var parseAction = GetParseActionFor(sourceType);

Assert.Throws<ParserException>(() => parseAction(parser, code));
}

private static Func<JavaScriptParser, string, Node> GetParseActionFor(string sourceType)
{
return sourceType switch
{
"script" => (parser, code) => parser.ParseScript(code),
"module" => (parser, code) => parser.ParseModule(code),
"expression" => (parser, code) => parser.ParseExpression(code),
_ => throw new InvalidOperationException()
};
}
}