Skip to content

Commit

Permalink
Support for ES2020 import.meta (#171)
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma authored Jul 18, 2021
1 parent 611b7da commit 794b45d
Show file tree
Hide file tree
Showing 15 changed files with 1,296 additions and 8 deletions.
63 changes: 58 additions & 5 deletions src/Esprima/JavascriptParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,14 @@ private Expression ParsePrimaryExpression()
{
expr = ParseImportCall();
}
else if (MatchImportMeta())
{
if (!_context.IsModule)
{
TolerateUnexpectedToken(_lookahead, Messages.CannotUseImportMetaOutsideAModule);
}
expr = ParseImportMeta();
}
else
{
return ThrowUnexpectedToken<Expression>(NextToken());
Expand Down Expand Up @@ -1486,7 +1494,48 @@ private Import ParseImportCall()
{
var node = CreateNode();
ExpectKeyword("import");
return this.Finalize(node, new Import());
return Finalize(node, new Import());
}

private bool MatchImportMeta()
{
var match = MatchKeyword("import");
if (match)
{
var state = _scanner.SaveState();
_scanner.ScanComments();
var dot = _scanner.Lex();
if (dot.Type == TokenType.Punctuator && Equals(dot.Value, "."))
{
_scanner.ScanComments();
var meta = _scanner.Lex();
match = meta.Type == TokenType.Identifier && Equals(meta.Value, "meta");
if (match)
{
if (meta.End - meta.Start != "meta".Length)
{
TolerateUnexpectedToken(meta, Messages.InvalidEscapedReservedWord);
}
}
}
else
{
match = false;
}
_scanner.RestoreState(state);
}

return match;
}

private MetaProperty ParseImportMeta()
{
var node = CreateNode();
var id = ParseIdentifierName(); // 'import', already ensured by matchImportMeta
Expect(".");
var property = ParseIdentifierName(); // 'meta', already ensured by matchImportMeta
_context.IsAssignmentTarget = false;
return Finalize(node, new MetaProperty(id, property));
}

private Expression ParseLeftHandSideExpressionAllowCall()
Expand Down Expand Up @@ -1573,8 +1622,8 @@ private Expression ParseLeftHandSideExpressionAllowCall()
}
else if (Match(".") || optional)
{
this._context.IsBindingElement = false;
this._context.IsAssignmentTarget = !optional;
_context.IsBindingElement = false;
_context.IsAssignmentTarget = !optional;
if (!optional)
{
Expect(".");
Expand Down Expand Up @@ -1688,7 +1737,7 @@ private Expression ParseUpdateExpression()
Expression expr;
var startToken = _lookahead;

if (Match("++") || this.Match("--"))
if (Match("++") || Match("--"))
{
var node = StartNode(startToken);
var token = NextToken();
Expand Down Expand Up @@ -2321,6 +2370,10 @@ private Statement ParseStatementListItem()
{
statement = ParseExpressionStatement();
}
else if (MatchImportMeta())
{
statement = ParseStatement();
}
else
{
if (!_context.IsModule)
Expand Down Expand Up @@ -3979,7 +4032,7 @@ private FunctionExpression ParseGetterMethod()
{
TolerateError(Messages.BadGetterArity);
}
var method = this.ParsePropertyMethod(formalParameters);
var method = ParsePropertyMethod(formalParameters);
_context.AllowYield = previousAllowYield;

return Finalize(node, new FunctionExpression(null, NodeList.From(ref formalParameters.Parameters), method, generator: isGenerator, _context.Strict, async: false));
Expand Down
1 change: 1 addition & 0 deletions src/Esprima/Messages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public static class Messages
public const string BadGetterArity = "Getter must not have any formal parameters";
public const string BadSetterArity = "Setter must have exactly one formal parameter";
public const string BadSetterRestParameter = "Setter function argument must not be a rest parameter";
public const string CannotUseImportMetaOutsideAModule = "Cannot use 'import.meta' outside a module";
public const string ConstructorIsAsync = "Class constructor may not be an async method";
public const string ConstructorSpecialMethod = "Class constructor may not be an accessor";
public const string DeclarationMissingInitializer = "Missing initializer in {0} declaration";
Expand Down
7 changes: 4 additions & 3 deletions test/Esprima.Tests/Fixtures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Json;
using Esprima.Ast;
using Esprima.Utils;
using Newtonsoft.Json.Linq;
Expand Down Expand Up @@ -34,7 +35,7 @@ private static string ParseAndFormat(SourceType sourceType, string source, Parse
);
}

public bool CompareTrees(string actual, string expected)
private static void CompareTrees(string actual, string expected, string path)
{
var actualJObject = JObject.Parse(actual);
var expectedJObject = JObject.Parse(expected);
Expand All @@ -49,8 +50,8 @@ public bool CompareTrees(string actual, string expected)
{
var actualString = actualJObject.ToString();
var expectedString = expectedJObject.ToString();
Assert.Equal(expectedString, actualString);
}
return areEqual;
}

[Theory]
Expand Down Expand Up @@ -134,7 +135,7 @@ public void ExecuteTestCase(string fixture)
options.Tolerant = true;

var actual = ParseAndFormat(sourceType, script, options);
Assert.True(CompareTrees(actual, expected), jsFilePath);
CompareTrees(actual, expected, jsFilePath);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import.meta.foo = 'bar';
Loading

0 comments on commit 794b45d

Please sign in to comment.