Skip to content

Commit

Permalink
Fix import expression in yield expression (#404)
Browse files Browse the repository at this point in the history
* Fix import expression in yield expression

* Fix tests
  • Loading branch information
adams85 authored Sep 2, 2023
1 parent beed8bd commit bcd4c32
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 21 deletions.
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()
};
}
}

0 comments on commit bcd4c32

Please sign in to comment.