Skip to content

Commit f9f8904

Browse files
committed
support es2022 class properties
1 parent 27ad334 commit f9f8904

File tree

6 files changed

+170
-24
lines changed

6 files changed

+170
-24
lines changed

src/Esprima/Ast/Nodes.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ public enum Nodes
2929
MemberExpression,
3030
NewExpression,
3131
ObjectExpression,
32+
PrivateIdentifier,
3233
Program,
3334
Property,
35+
PropertyDefinition,
3436
RestElement,
3537
ReturnStatement,
3638
SequenceExpression,

src/Esprima/Ast/PrivateIdentifier.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using Esprima.Utils;
2+
3+
namespace Esprima.Ast
4+
{
5+
public sealed class PrivateIdentifier : Expression
6+
{
7+
public readonly string? Name;
8+
9+
public PrivateIdentifier(string? name) : base(Nodes.PrivateIdentifier)
10+
{
11+
Name = name;
12+
}
13+
14+
public override NodeCollection ChildNodes => NodeCollection.Empty;
15+
16+
protected internal override void Accept(AstVisitor visitor)
17+
{
18+
visitor.VisitPrivateIdentifier(this);
19+
}
20+
}
21+
}

src/Esprima/Ast/PropertyDefinition.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using Esprima.Utils;
2+
3+
namespace Esprima.Ast
4+
{
5+
public sealed class PropertyDefinition : ClassProperty
6+
{
7+
public readonly bool Static;
8+
9+
public PropertyDefinition(
10+
Expression key,
11+
bool computed,
12+
Expression value,
13+
bool isStatic)
14+
: base(Nodes.PropertyDefinition)
15+
{
16+
Static = isStatic;
17+
Key = key;
18+
Computed = computed;
19+
Value = value;
20+
}
21+
22+
protected internal override void Accept(AstVisitor visitor)
23+
{
24+
visitor.VisitPropertyDefinition(this);
25+
}
26+
}
27+
}

src/Esprima/Ast/PropertyKind.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22

33
namespace Esprima.Ast
44
{
@@ -11,6 +11,7 @@ public enum PropertyKind
1111
Set = 4,
1212
Init = 8,
1313
Constructor = 16,
14-
Method = 32
14+
Method = 32,
15+
Property = 64
1516
};
1617
}

src/Esprima/JavascriptParser.cs

Lines changed: 103 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,10 @@ private Expression ParsePrimaryExpression()
665665
{
666666
expr = ParseClassExpression();
667667
}
668+
else if (MatchKeyword("new"))
669+
{
670+
expr = ParseNewExpression();
671+
}
668672
else if (MatchImportCall())
669673
{
670674
expr = ParseImportCall();
@@ -833,7 +837,7 @@ private FunctionExpression ParsePropertyMethodAsyncFunction(bool isGenerator)
833837
return Finalize(node, new FunctionExpression(null, NodeList.From(ref parameters.Parameters), method, isGenerator, hasStrictDirective, true));
834838
}
835839

836-
private Expression ParseObjectPropertyKey()
840+
private Expression ParseObjectPropertyKey(Boolean isPrivate = false)
837841
{
838842
var node = CreateNode();
839843
var token = NextToken();
@@ -865,7 +869,7 @@ private Expression ParseObjectPropertyKey()
865869
case TokenType.BooleanLiteral:
866870
case TokenType.NullLiteral:
867871
case TokenType.Keyword:
868-
key = Finalize(node, new Identifier((string?) token.Value));
872+
key = isPrivate ? Finalize(node, new PrivateIdentifier((string?) token.Value)) : Finalize(node, new Identifier((string?) token.Value));
869873
break;
870874

871875
case TokenType.Punctuator:
@@ -963,7 +967,7 @@ private Property ParseObjectProperty(Token hasProto)
963967
kind = PropertyKind.Init;
964968
computed = Match("[");
965969
key = ParseObjectPropertyKey();
966-
value = ParseGeneratorMethod();
970+
value = ParseGeneratorMethod(isAsync);
967971
method = true;
968972
}
969973
else
@@ -1419,6 +1423,29 @@ private Identifier ParseIdentifierName()
14191423
return Finalize(node, new Identifier((string?) token.Value));
14201424
}
14211425

1426+
private Expression ParseIdentifierOrPrivateIdentifierName()
1427+
{
1428+
var isPrivateField = false;
1429+
1430+
var node = CreateNode();
1431+
1432+
var token = NextToken();
1433+
1434+
if (Equals(token.Value, "#"))
1435+
{
1436+
token = NextToken();
1437+
token.Value = '#' + (string?)token.Value;
1438+
isPrivateField = true;
1439+
}
1440+
1441+
if (!IsIdentifierName(token))
1442+
{
1443+
return ThrowUnexpectedToken<Identifier>(token);
1444+
}
1445+
1446+
return isPrivateField ? Finalize(node, new PrivateIdentifier((string?) token.Value)) : Finalize(node, new Identifier((string?) token.Value));
1447+
}
1448+
14221449
private Expression ParseNewExpression()
14231450
{
14241451
var node = CreateNode();
@@ -1655,7 +1682,7 @@ private Expression ParseLeftHandSideExpressionAllowCall()
16551682
Expect(".");
16561683
}
16571684

1658-
var property = ParseIdentifierName();
1685+
var property = ParseIdentifierOrPrivateIdentifierName();
16591686
expr = Finalize(StartNode(startToken), new StaticMemberExpression(expr, property, optional));
16601687
}
16611688
else
@@ -4143,7 +4170,7 @@ private static bool QualifiedPropertyName(Token token)
41434170
TokenType.NullLiteral => true,
41444171
TokenType.NumericLiteral => true,
41454172
TokenType.Keyword => true,
4146-
TokenType.Punctuator => Equals(token.Value, "["),
4173+
TokenType.Punctuator => Equals(token.Value, "[") || Equals(token.Value, "#"),
41474174
_ => false
41484175
};
41494176
}
@@ -4191,7 +4218,7 @@ private FunctionExpression ParseSetterMethod()
41914218
return Finalize(node, new FunctionExpression(null, NodeList.From(ref formalParameters.Parameters), method, isGenerator, hasStrictDirective, false));
41924219
}
41934220

4194-
private FunctionExpression ParseGeneratorMethod()
4221+
private FunctionExpression ParseGeneratorMethod(bool isAsync = false)
41954222
{
41964223
var node = CreateNode();
41974224

@@ -4203,7 +4230,7 @@ private FunctionExpression ParseGeneratorMethod()
42034230
var method = ParsePropertyMethod(parameters, out var hasStrictDirective);
42044231
_context.AllowYield = previousAllowYield;
42054232

4206-
return Finalize(node, new FunctionExpression(null, NodeList.From(ref parameters.Parameters), method, true, hasStrictDirective, false));
4233+
return Finalize(node, new FunctionExpression(null, NodeList.From(ref parameters.Parameters), method, true, hasStrictDirective, isAsync));
42074234
}
42084235

42094236
// https://tc39.github.io/ecma262/#sec-generator-function-definitions
@@ -4300,12 +4327,13 @@ private ClassProperty ParseClassElement(ref bool hasConstructor)
43004327

43014328
var kind = PropertyKind.None;
43024329
Expression? key = null;
4303-
FunctionExpression? value = null;
4330+
Expression? value = null;
43044331
var computed = false;
43054332
var method = false;
43064333
var isStatic = false;
43074334
var isAsync = false;
4308-
var isGenerator = false;
4335+
var isGenerator = false;
4336+
var isPrivate = false;
43094337

43104338
if (Match("*"))
43114339
{
@@ -4315,10 +4343,17 @@ private ClassProperty ParseClassElement(ref bool hasConstructor)
43154343
else
43164344
{
43174345
computed = Match("[");
4318-
key = ParseObjectPropertyKey();
4346+
if (Match("#"))
4347+
{
4348+
isPrivate = true;
4349+
NextToken();
4350+
token = _lookahead;
4351+
}
4352+
key = ParseObjectPropertyKey(isPrivate);
43194353
var id = key switch
43204354
{
43214355
Identifier identifier => identifier.Name,
4356+
PrivateIdentifier privateIdentifier => privateIdentifier.Name,
43224357
Literal literal => literal.StringValue, // "constructor"
43234358
_ => null
43244359
};
@@ -4331,9 +4366,21 @@ private ClassProperty ParseClassElement(ref bool hasConstructor)
43314366
if (Match("*"))
43324367
{
43334368
NextToken();
4369+
if (Match("#"))
4370+
{
4371+
isPrivate = true;
4372+
NextToken();
4373+
token = _lookahead;
4374+
}
43344375
}
43354376
else
43364377
{
4378+
if (Match("#"))
4379+
{
4380+
isPrivate = true;
4381+
NextToken();
4382+
token = _lookahead;
4383+
}
43374384
key = ParseObjectPropertyKey();
43384385
}
43394386
}
@@ -4347,11 +4394,17 @@ private ClassProperty ParseClassElement(ref bool hasConstructor)
43474394
if (isGenerator)
43484395
{
43494396
NextToken();
4397+
}
4398+
4399+
if (Match("#"))
4400+
{
4401+
isPrivate = true;
4402+
NextToken();
43504403
}
43514404

43524405
token = _lookahead;
43534406
computed = Match("[");
4354-
key = ParseObjectPropertyKey();
4407+
key = ParseObjectPropertyKey(isPrivate);
43554408
if (token.Type == TokenType.Identifier && (string?) token.Value == "constructor")
43564409
{
43574410
TolerateUnexpectedToken(token, Messages.ConstructorIsAsync);
@@ -4365,26 +4418,49 @@ private ClassProperty ParseClassElement(ref bool hasConstructor)
43654418
{
43664419
if (lookaheadPropertyKey && (string?) token.Value == "get")
43674420
{
4368-
kind = PropertyKind.Get;
4421+
kind = PropertyKind.Get;
4422+
if (Match("#"))
4423+
{
4424+
isPrivate = true;
4425+
NextToken();
4426+
token = _lookahead;
4427+
}
43694428
computed = Match("[");
4370-
key = ParseObjectPropertyKey();
4429+
key = ParseObjectPropertyKey(isPrivate);
43714430
_context.AllowYield = false;
43724431
value = ParseGetterMethod();
43734432
}
43744433
else if (lookaheadPropertyKey && (string?) token.Value == "set")
43754434
{
43764435
kind = PropertyKind.Set;
4436+
if (Match("#"))
4437+
{
4438+
isPrivate = true;
4439+
NextToken();
4440+
token = _lookahead;
4441+
}
43774442
computed = Match("[");
4378-
key = ParseObjectPropertyKey();
4379-
value = ParseSetterMethod();
4443+
key = ParseObjectPropertyKey(isPrivate);
4444+
value = ParseSetterMethod();
4445+
}
4446+
else if (!Match("("))
4447+
{
4448+
kind = PropertyKind.Property;
4449+
computed = false;
4450+
4451+
if (Match("="))
4452+
{
4453+
NextToken();
4454+
value = IsolateCoverGrammar(this.parseAssignmentExpression);
4455+
}
43804456
}
43814457
}
43824458
else if (token.Type == TokenType.Punctuator && (string?) token.Value == "*" && lookaheadPropertyKey)
43834459
{
43844460
kind = PropertyKind.Init;
43854461
computed = Match("[");
4386-
key = ParseObjectPropertyKey();
4387-
value = ParseGeneratorMethod();
4462+
key = ParseObjectPropertyKey(isPrivate);
4463+
value = ParseGeneratorMethod(isAsync);
43884464
method = true;
43894465
}
43904466

@@ -4420,7 +4496,7 @@ private ClassProperty ParseClassElement(ref bool hasConstructor)
44204496

44214497
if (!isStatic && IsPropertyKey(key!, "constructor"))
44224498
{
4423-
if (kind != PropertyKind.Method || !method || value!.Generator)
4499+
if (kind != PropertyKind.Method || !method || ((FunctionExpression)value!).Generator)
44244500
{
44254501
ThrowUnexpectedToken(token, Messages.ConstructorSpecialMethod);
44264502
}
@@ -4436,10 +4512,15 @@ private ClassProperty ParseClassElement(ref bool hasConstructor)
44364512

44374513
kind = PropertyKind.Constructor;
44384514
}
4439-
}
4440-
4441-
4442-
return Finalize(node, new MethodDefinition(key!, computed, value!, kind, isStatic));
4515+
}
4516+
4517+
if (kind == PropertyKind.Property)
4518+
{
4519+
ConsumeSemicolon();
4520+
return Finalize(node, new PropertyDefinition(key!, computed, value!, isStatic));
4521+
}
4522+
4523+
return Finalize(node, new MethodDefinition(key!, computed, (FunctionExpression)value!, kind, isStatic));
44434524
}
44444525

44454526
private ArrayList<ClassProperty> ParseClassElementList()

src/Esprima/Utils/AstVisitor.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,10 @@ protected internal virtual void VisitIdentifier(Identifier identifier)
258258
{
259259
}
260260

261+
protected internal virtual void VisitPrivateIdentifier(PrivateIdentifier privateIdentifier)
262+
{
263+
}
264+
261265
protected internal virtual void VisitFunctionExpression(IFunction function)
262266
{
263267
if (function.Id is not null)
@@ -366,6 +370,16 @@ protected internal virtual void VisitMethodDefinition(MethodDefinition methodDef
366370
Visit(methodDefinition.Value);
367371
}
368372

373+
protected internal virtual void VisitPropertyDefinition(PropertyDefinition propertyDefinition)
374+
{
375+
Visit(propertyDefinition.Key);
376+
377+
if (propertyDefinition.Value is not null)
378+
{
379+
Visit(propertyDefinition.Value);
380+
}
381+
}
382+
369383
protected internal virtual void VisitForOfStatement(ForOfStatement forOfStatement)
370384
{
371385
Visit(forOfStatement.Left);

0 commit comments

Comments
 (0)