diff --git a/src/Esprima/Ast/Nodes.cs b/src/Esprima/Ast/Nodes.cs index 370330c7..2f2046a8 100644 --- a/src/Esprima/Ast/Nodes.cs +++ b/src/Esprima/Ast/Nodes.cs @@ -29,8 +29,10 @@ public enum Nodes MemberExpression, NewExpression, ObjectExpression, + PrivateIdentifier, Program, Property, + PropertyDefinition, RestElement, ReturnStatement, SequenceExpression, diff --git a/src/Esprima/Ast/PrivateIdentifier.cs b/src/Esprima/Ast/PrivateIdentifier.cs new file mode 100644 index 00000000..75f2e08a --- /dev/null +++ b/src/Esprima/Ast/PrivateIdentifier.cs @@ -0,0 +1,21 @@ +using Esprima.Utils; + +namespace Esprima.Ast +{ + public sealed class PrivateIdentifier : Expression + { + public readonly string? Name; + + public PrivateIdentifier(string? name) : base(Nodes.PrivateIdentifier) + { + Name = name; + } + + public override NodeCollection ChildNodes => NodeCollection.Empty; + + protected internal override void Accept(AstVisitor visitor) + { + visitor.VisitPrivateIdentifier(this); + } + } +} diff --git a/src/Esprima/Ast/PropertyDefinition.cs b/src/Esprima/Ast/PropertyDefinition.cs new file mode 100644 index 00000000..7615499f --- /dev/null +++ b/src/Esprima/Ast/PropertyDefinition.cs @@ -0,0 +1,27 @@ +using Esprima.Utils; + +namespace Esprima.Ast +{ + public sealed class PropertyDefinition : ClassProperty + { + public readonly bool Static; + + public PropertyDefinition( + Expression key, + bool computed, + Expression value, + bool isStatic) + : base(Nodes.PropertyDefinition) + { + Static = isStatic; + Key = key; + Computed = computed; + Value = value; + } + + protected internal override void Accept(AstVisitor visitor) + { + visitor.VisitPropertyDefinition(this); + } + } +} diff --git a/src/Esprima/Ast/PropertyKind.cs b/src/Esprima/Ast/PropertyKind.cs index 735ec214..ad2d5337 100644 --- a/src/Esprima/Ast/PropertyKind.cs +++ b/src/Esprima/Ast/PropertyKind.cs @@ -11,6 +11,7 @@ public enum PropertyKind Set = 4, Init = 8, Constructor = 16, - Method = 32 + Method = 32, + Property = 64 }; } diff --git a/src/Esprima/JavascriptParser.cs b/src/Esprima/JavascriptParser.cs index ae7b7087..515626a8 100644 --- a/src/Esprima/JavascriptParser.cs +++ b/src/Esprima/JavascriptParser.cs @@ -666,6 +666,10 @@ private Expression ParsePrimaryExpression() { expr = ParseClassExpression(); } + else if (MatchKeyword("new")) + { + expr = ParseNewExpression(); + } else if (MatchImportCall()) { expr = ParseImportCall(); @@ -834,7 +838,7 @@ private FunctionExpression ParsePropertyMethodAsyncFunction(bool isGenerator) return Finalize(node, new FunctionExpression(null, NodeList.From(ref parameters.Parameters), method, isGenerator, hasStrictDirective, true)); } - private Expression ParseObjectPropertyKey() + private Expression ParseObjectPropertyKey(Boolean isPrivate = false) { var node = CreateNode(); var token = NextToken(); @@ -866,7 +870,7 @@ private Expression ParseObjectPropertyKey() case TokenType.BooleanLiteral: case TokenType.NullLiteral: case TokenType.Keyword: - key = Finalize(node, new Identifier((string?) token.Value)); + key = isPrivate ? Finalize(node, new PrivateIdentifier((string?) token.Value)) : Finalize(node, new Identifier((string?) token.Value)); break; case TokenType.Punctuator: @@ -964,7 +968,7 @@ private Property ParseObjectProperty(Token hasProto) kind = PropertyKind.Init; computed = Match("["); key = ParseObjectPropertyKey(); - value = ParseGeneratorMethod(); + value = ParseGeneratorMethod(isAsync); method = true; } else @@ -1420,6 +1424,29 @@ private Identifier ParseIdentifierName() return Finalize(node, new Identifier((string?) token.Value)); } + private Expression ParseIdentifierOrPrivateIdentifierName() + { + var isPrivateField = false; + + var node = CreateNode(); + + var token = NextToken(); + + if (Equals(token.Value, "#")) + { + token = NextToken(); + token.Value = '#' + (string?)token.Value; + isPrivateField = true; + } + + if (!IsIdentifierName(token)) + { + return ThrowUnexpectedToken(token); + } + + return isPrivateField ? Finalize(node, new PrivateIdentifier((string?) token.Value)) : Finalize(node, new Identifier((string?) token.Value)); + } + private Expression ParseNewExpression() { var node = CreateNode(); @@ -1672,7 +1699,7 @@ private Expression ParseLeftHandSideExpressionAllowCall() Expect("."); } - var property = ParseIdentifierName(); + var property = ParseIdentifierOrPrivateIdentifierName(); expr = Finalize(StartNode(startToken), new StaticMemberExpression(expr, property, optional)); } else @@ -4164,7 +4191,7 @@ private static bool QualifiedPropertyName(Token token) TokenType.NullLiteral => true, TokenType.NumericLiteral => true, TokenType.Keyword => true, - TokenType.Punctuator => Equals(token.Value, "["), + TokenType.Punctuator => Equals(token.Value, "[") || Equals(token.Value, "#"), _ => false }; } @@ -4212,7 +4239,7 @@ private FunctionExpression ParseSetterMethod() return Finalize(node, new FunctionExpression(null, NodeList.From(ref formalParameters.Parameters), method, isGenerator, hasStrictDirective, false)); } - private FunctionExpression ParseGeneratorMethod() + private FunctionExpression ParseGeneratorMethod(bool isAsync = false) { var node = CreateNode(); @@ -4224,7 +4251,7 @@ private FunctionExpression ParseGeneratorMethod() var method = ParsePropertyMethod(parameters, out var hasStrictDirective); _context.AllowYield = previousAllowYield; - return Finalize(node, new FunctionExpression(null, NodeList.From(ref parameters.Parameters), method, true, hasStrictDirective, false)); + return Finalize(node, new FunctionExpression(null, NodeList.From(ref parameters.Parameters), method, true, hasStrictDirective, isAsync)); } // https://tc39.github.io/ecma262/#sec-generator-function-definitions @@ -4321,12 +4348,13 @@ private ClassProperty ParseClassElement(ref bool hasConstructor) var kind = PropertyKind.None; Expression? key = null; - FunctionExpression? value = null; + Expression? value = null; var computed = false; var method = false; var isStatic = false; var isAsync = false; - var isGenerator = false; + var isGenerator = false; + var isPrivate = false; if (Match("*")) { @@ -4336,10 +4364,17 @@ private ClassProperty ParseClassElement(ref bool hasConstructor) else { computed = Match("["); - key = ParseObjectPropertyKey(); + if (Match("#")) + { + isPrivate = true; + NextToken(); + token = _lookahead; + } + key = ParseObjectPropertyKey(isPrivate); var id = key switch { Identifier identifier => identifier.Name, + PrivateIdentifier privateIdentifier => privateIdentifier.Name, Literal literal => literal.StringValue, // "constructor" _ => null }; @@ -4352,9 +4387,21 @@ private ClassProperty ParseClassElement(ref bool hasConstructor) if (Match("*")) { NextToken(); + if (Match("#")) + { + isPrivate = true; + NextToken(); + token = _lookahead; + } } else { + if (Match("#")) + { + isPrivate = true; + NextToken(); + token = _lookahead; + } key = ParseObjectPropertyKey(); } } @@ -4368,11 +4415,17 @@ private ClassProperty ParseClassElement(ref bool hasConstructor) if (isGenerator) { NextToken(); + } + + if (Match("#")) + { + isPrivate = true; + NextToken(); } token = _lookahead; computed = Match("["); - key = ParseObjectPropertyKey(); + key = ParseObjectPropertyKey(isPrivate); if (token.Type == TokenType.Identifier && (string?) token.Value == "constructor") { TolerateUnexpectedToken(token, Messages.ConstructorIsAsync); @@ -4386,26 +4439,49 @@ private ClassProperty ParseClassElement(ref bool hasConstructor) { if (lookaheadPropertyKey && (string?) token.Value == "get") { - kind = PropertyKind.Get; + kind = PropertyKind.Get; + if (Match("#")) + { + isPrivate = true; + NextToken(); + token = _lookahead; + } computed = Match("["); - key = ParseObjectPropertyKey(); + key = ParseObjectPropertyKey(isPrivate); _context.AllowYield = false; value = ParseGetterMethod(); } else if (lookaheadPropertyKey && (string?) token.Value == "set") { kind = PropertyKind.Set; + if (Match("#")) + { + isPrivate = true; + NextToken(); + token = _lookahead; + } computed = Match("["); - key = ParseObjectPropertyKey(); - value = ParseSetterMethod(); + key = ParseObjectPropertyKey(isPrivate); + value = ParseSetterMethod(); + } + else if (!Match("(")) + { + kind = PropertyKind.Property; + computed = false; + + if (Match("=")) + { + NextToken(); + value = IsolateCoverGrammar(this.parseAssignmentExpression); + } } } else if (token.Type == TokenType.Punctuator && (string?) token.Value == "*" && lookaheadPropertyKey) { kind = PropertyKind.Init; computed = Match("["); - key = ParseObjectPropertyKey(); - value = ParseGeneratorMethod(); + key = ParseObjectPropertyKey(isPrivate); + value = ParseGeneratorMethod(isAsync); method = true; } @@ -4441,7 +4517,7 @@ private ClassProperty ParseClassElement(ref bool hasConstructor) if (!isStatic && IsPropertyKey(key!, "constructor")) { - if (kind != PropertyKind.Method || !method || value!.Generator) + if (kind != PropertyKind.Method || !method || ((FunctionExpression)value!).Generator) { ThrowUnexpectedToken(token, Messages.ConstructorSpecialMethod); } @@ -4457,10 +4533,15 @@ private ClassProperty ParseClassElement(ref bool hasConstructor) kind = PropertyKind.Constructor; } - } - - - return Finalize(node, new MethodDefinition(key!, computed, value!, kind, isStatic)); + } + + if (kind == PropertyKind.Property) + { + ConsumeSemicolon(); + return Finalize(node, new PropertyDefinition(key!, computed, value!, isStatic)); + } + + return Finalize(node, new MethodDefinition(key!, computed, (FunctionExpression)value!, kind, isStatic)); } private ArrayList ParseClassElementList() diff --git a/src/Esprima/Utils/AstVisitor.cs b/src/Esprima/Utils/AstVisitor.cs index ec0d998c..05877623 100644 --- a/src/Esprima/Utils/AstVisitor.cs +++ b/src/Esprima/Utils/AstVisitor.cs @@ -1,578 +1,592 @@ -using System; -using Esprima.Ast; - -namespace Esprima.Utils -{ - public class AstVisitor - { - public virtual void Visit(Node node) - { - node.Accept(this); - } - - protected internal virtual void VisitProgram(Program program) - { - ref readonly var statements = ref program.Body; - for (var i = 0; i < statements.Count; i++) - { - Visit(statements[i]); - } - } - - [Obsolete("This method may be removed in a future version as it will not be called anymore due to employing double dispatch (instead of switch dispatch).")] - protected virtual void VisitUnknownNode(Node node) - { - throw new NotImplementedException($"AST visitor doesn't support nodes of type {node.Type}, you can override VisitUnknownNode to handle this case."); - } - - protected internal virtual void VisitCatchClause(CatchClause catchClause) - { - if (catchClause.Param is not null) - { - Visit(catchClause.Param); - } - - Visit(catchClause.Body); - } - - protected internal virtual void VisitFunctionDeclaration(FunctionDeclaration functionDeclaration) - { - if (functionDeclaration.Id is not null) - { - Visit(functionDeclaration.Id); - } - - ref readonly var parameters = ref functionDeclaration.Params; - for (var i = 0; i < parameters.Count; i++) - { - Visit(parameters[i]); - } - - Visit(functionDeclaration.Body); - } - - protected internal virtual void VisitWithStatement(WithStatement withStatement) - { - Visit(withStatement.Object); - Visit(withStatement.Body); - } - - protected internal virtual void VisitWhileStatement(WhileStatement whileStatement) - { - Visit(whileStatement.Test); - Visit(whileStatement.Body); - } - - protected internal virtual void VisitVariableDeclaration(VariableDeclaration variableDeclaration) - { - ref readonly var declarations = ref variableDeclaration.Declarations; - for (var i = 0; i < declarations.Count; i++) - { - Visit(declarations[i]); - } - } - - protected internal virtual void VisitTryStatement(TryStatement tryStatement) - { - Visit(tryStatement.Block); - if (tryStatement.Handler is not null) - { - Visit(tryStatement.Handler); - } - - if (tryStatement.Finalizer is not null) - { - Visit(tryStatement.Finalizer); - } - } - - protected internal virtual void VisitThrowStatement(ThrowStatement throwStatement) - { - Visit(throwStatement.Argument); - } - - protected internal virtual void VisitSwitchStatement(SwitchStatement switchStatement) - { - Visit(switchStatement.Discriminant); - ref readonly var cases = ref switchStatement.Cases; - for (var i = 0; i < cases.Count; i++) - { - Visit(cases[i]); - } - } - - protected internal virtual void VisitSwitchCase(SwitchCase switchCase) - { - if (switchCase.Test is not null) - { - Visit(switchCase.Test); - } - - ref readonly var consequent = ref switchCase.Consequent; - for (var i = 0; i < consequent.Count; i++) - { - Visit(consequent[i]); - } - } - - protected internal virtual void VisitReturnStatement(ReturnStatement returnStatement) - { - if (returnStatement.Argument is not null) - { - Visit(returnStatement.Argument); - } - } - - protected internal virtual void VisitLabeledStatement(LabeledStatement labeledStatement) - { - Visit(labeledStatement.Label); - Visit(labeledStatement.Body); - } - - protected internal virtual void VisitIfStatement(IfStatement ifStatement) - { - Visit(ifStatement.Test); - Visit(ifStatement.Consequent); - if (ifStatement.Alternate is not null) - { - Visit(ifStatement.Alternate); - } - } - - protected internal virtual void VisitEmptyStatement(EmptyStatement emptyStatement) - { - } - - protected internal virtual void VisitDebuggerStatement(DebuggerStatement debuggerStatement) - { - } - - protected internal virtual void VisitExpressionStatement(ExpressionStatement expressionStatement) - { - Visit(expressionStatement.Expression); - } - - protected internal virtual void VisitForStatement(ForStatement forStatement) - { - if (forStatement.Init is not null) - { - Visit(forStatement.Init); - } - - if (forStatement.Test is not null) - { - Visit(forStatement.Test); - } - - if (forStatement.Update is not null) - { - Visit(forStatement.Update); - } - - Visit(forStatement.Body); - } - - protected internal virtual void VisitForInStatement(ForInStatement forInStatement) - { - Visit(forInStatement.Left); - Visit(forInStatement.Right); - Visit(forInStatement.Body); - } - - protected internal virtual void VisitDoWhileStatement(DoWhileStatement doWhileStatement) - { - Visit(doWhileStatement.Body); - Visit(doWhileStatement.Test); - } - - protected internal virtual void VisitArrowFunctionExpression(ArrowFunctionExpression arrowFunctionExpression) - { - ref readonly var parameters = ref arrowFunctionExpression.Params; - for (var i = 0; i < parameters.Count; i++) - { - Visit(parameters[i]); - } - - Visit(arrowFunctionExpression.Body); - } - - protected internal virtual void VisitUnaryExpression(UnaryExpression unaryExpression) - { - Visit(unaryExpression.Argument); - } - - protected internal virtual void VisitUpdateExpression(UpdateExpression updateExpression) - { - Visit(updateExpression.Argument); - } - - protected internal virtual void VisitThisExpression(ThisExpression thisExpression) - { - } - - protected internal virtual void VisitSequenceExpression(SequenceExpression sequenceExpression) - { - ref readonly var expressions = ref sequenceExpression.Expressions; - for (var i = 0; i < expressions.Count; i++) - { - Visit(expressions[i]); - } - } - - protected internal virtual void VisitObjectExpression(ObjectExpression objectExpression) - { - ref readonly var properties = ref objectExpression.Properties; - for (var i = 0; i < properties.Count; i++) - { - Visit(properties[i]); - } - } - - protected internal virtual void VisitNewExpression(NewExpression newExpression) - { - Visit(newExpression.Callee); - ref readonly var arguments = ref newExpression.Arguments; - for (var i = 0; i < arguments.Count; i++) - { - Visit(arguments[i]); - } - } - - protected internal virtual void VisitMemberExpression(MemberExpression memberExpression) - { - Visit(memberExpression.Object); - Visit(memberExpression.Property); - } - - protected internal virtual void VisitLogicalExpression(BinaryExpression binaryExpression) - { - Visit(binaryExpression.Left); - Visit(binaryExpression.Right); - } - - protected internal virtual void VisitLiteral(Literal literal) - { - } - - protected internal virtual void VisitIdentifier(Identifier identifier) - { - } - - protected internal virtual void VisitFunctionExpression(IFunction function) - { - if (function.Id is not null) - { - Visit(function.Id); - } - - ref readonly var parameters = ref function.Params; - for (var i = 0; i < parameters.Count; i++) - { - Visit(parameters[i]); - } - - Visit(function.Body); - } - - protected internal virtual void VisitChainExpression(ChainExpression chainExpression) - { - Visit(chainExpression.Expression); - } - - protected internal virtual void VisitClassExpression(ClassExpression classExpression) - { - if (classExpression.Id is not null) - { - Visit(classExpression.Id); - } - - if (classExpression.SuperClass is not null) - { - Visit(classExpression.SuperClass); - } - - Visit(classExpression.Body); - } - - protected internal virtual void VisitExportDefaultDeclaration(ExportDefaultDeclaration exportDefaultDeclaration) - { - Visit(exportDefaultDeclaration.Declaration); - } - - protected internal virtual void VisitExportAllDeclaration(ExportAllDeclaration exportAllDeclaration) - { - Visit(exportAllDeclaration.Source); - } - - protected internal virtual void VisitExportNamedDeclaration(ExportNamedDeclaration exportNamedDeclaration) - { - if (exportNamedDeclaration.Declaration is not null) - { - Visit(exportNamedDeclaration.Declaration); - } - - ref readonly var specifiers = ref exportNamedDeclaration.Specifiers; - for (var i = 0; i < specifiers.Count; i++) - { - Visit(specifiers[i]); - } - - if (exportNamedDeclaration.Source is not null) - { - Visit(exportNamedDeclaration.Source); - } - } - - protected internal virtual void VisitExportSpecifier(ExportSpecifier exportSpecifier) - { - Visit(exportSpecifier.Local); - Visit(exportSpecifier.Exported); - } - - protected internal virtual void VisitImport(Import import) - { - if (import.Source != null) - { - Visit(import.Source); - } - } - - protected internal virtual void VisitImportDeclaration(ImportDeclaration importDeclaration) - { - ref readonly var specifiers = ref importDeclaration.Specifiers; - for (var i = 0; i < specifiers.Count; i++) - { - Visit(specifiers[i]); - } - - Visit(importDeclaration.Source); - } - - protected internal virtual void VisitImportNamespaceSpecifier(ImportNamespaceSpecifier importNamespaceSpecifier) - { - Visit(importNamespaceSpecifier.Local); - } - - protected internal virtual void VisitImportDefaultSpecifier(ImportDefaultSpecifier importDefaultSpecifier) - { - Visit(importDefaultSpecifier.Local); - } - - protected internal virtual void VisitImportSpecifier(ImportSpecifier importSpecifier) - { - Visit(importSpecifier.Imported); - Visit(importSpecifier.Local); - } - - protected internal virtual void VisitMethodDefinition(MethodDefinition methodDefinition) - { - Visit(methodDefinition.Key); - Visit(methodDefinition.Value); - } - - protected internal virtual void VisitForOfStatement(ForOfStatement forOfStatement) - { - Visit(forOfStatement.Left); - Visit(forOfStatement.Right); - Visit(forOfStatement.Body); - } - - protected internal virtual void VisitClassDeclaration(ClassDeclaration classDeclaration) - { - if (classDeclaration.Id is not null) - { - Visit(classDeclaration.Id); - } - - if (classDeclaration.SuperClass is not null) - { - Visit(classDeclaration.SuperClass); - } - - Visit(classDeclaration.Body); - } - - protected internal virtual void VisitClassBody(ClassBody classBody) - { - ref readonly var body = ref classBody.Body; - for (var i = 0; i < body.Count; i++) - { - Visit(body[i]); - } - } - - protected internal virtual void VisitYieldExpression(YieldExpression yieldExpression) - { - if (yieldExpression.Argument is not null) - { - Visit(yieldExpression.Argument); - } - } - - protected internal virtual void VisitTaggedTemplateExpression(TaggedTemplateExpression taggedTemplateExpression) - { - Visit(taggedTemplateExpression.Tag); - Visit(taggedTemplateExpression.Quasi); - } - - protected internal virtual void VisitSuper(Super super) - { - } - - protected internal virtual void VisitMetaProperty(MetaProperty metaProperty) - { - Visit(metaProperty.Meta); - Visit(metaProperty.Property); - } - - protected internal virtual void VisitArrowParameterPlaceHolder(ArrowParameterPlaceHolder arrowParameterPlaceHolder) - { - // ArrowParameterPlaceHolder nodes never appear in the final tree and only used during the construction of a tree. - } - - protected internal virtual void VisitObjectPattern(ObjectPattern objectPattern) - { - ref readonly var properties = ref objectPattern.Properties; - for (var i = 0; i < properties.Count; i++) - { - Visit(properties[i]); - } - } - - protected internal virtual void VisitSpreadElement(SpreadElement spreadElement) - { - Visit(spreadElement.Argument); - } - - protected internal virtual void VisitAssignmentPattern(AssignmentPattern assignmentPattern) - { - Visit(assignmentPattern.Left); - Visit(assignmentPattern.Right); - } - - protected internal virtual void VisitArrayPattern(ArrayPattern arrayPattern) - { - ref readonly var elements = ref arrayPattern.Elements; - for (var i = 0; i < elements.Count; i++) - { - var expr = elements[i]; - if (expr is not null) - { - Visit(expr); - } - } - } - - protected internal virtual void VisitVariableDeclarator(VariableDeclarator variableDeclarator) - { - Visit(variableDeclarator.Id); - if (variableDeclarator.Init is not null) - { - Visit(variableDeclarator.Init); - } - } - - protected internal virtual void VisitTemplateLiteral(TemplateLiteral templateLiteral) - { - ref readonly var quasis = ref templateLiteral.Quasis; - ref readonly var expressions = ref templateLiteral.Expressions; - - var n = expressions.Count; - - for (var i = 0; i < n; i++) - { - Visit(quasis[i]); - Visit(expressions[i]); - } - - Visit(quasis[n]); - } - - protected internal virtual void VisitTemplateElement(TemplateElement templateElement) - { - } - - protected internal virtual void VisitRestElement(RestElement restElement) - { - Visit(restElement.Argument); - } - - protected internal virtual void VisitProperty(Property property) - { - Visit(property.Key); - Visit(property.Value); - } - - protected internal virtual void VisitAwaitExpression(AwaitExpression awaitExpression) - { - Visit(awaitExpression.Argument); - } - - protected internal virtual void VisitConditionalExpression(ConditionalExpression conditionalExpression) - { - Visit(conditionalExpression.Test); - Visit(conditionalExpression.Consequent); - Visit(conditionalExpression.Alternate); - } - - protected internal virtual void VisitCallExpression(CallExpression callExpression) - { - Visit(callExpression.Callee); - ref readonly var arguments = ref callExpression.Arguments; - for (var i = 0; i < arguments.Count; i++) - { - Visit(arguments[i]); - } - } - - protected internal virtual void VisitBinaryExpression(BinaryExpression binaryExpression) - { - Visit(binaryExpression.Left); - Visit(binaryExpression.Right); - } - - protected internal virtual void VisitArrayExpression(ArrayExpression arrayExpression) - { - ref readonly var elements = ref arrayExpression.Elements; - for (var i = 0; i < elements.Count; i++) - { - var expr = elements[i]; - if (expr is not null) - { - Visit(expr); - } - } - } - - protected internal virtual void VisitAssignmentExpression(AssignmentExpression assignmentExpression) - { - Visit(assignmentExpression.Left); - Visit(assignmentExpression.Right); - } - - protected internal virtual void VisitContinueStatement(ContinueStatement continueStatement) - { - if (continueStatement.Label is not null) - { - Visit(continueStatement.Label); - } - } - - protected internal virtual void VisitBreakStatement(BreakStatement breakStatement) - { - if (breakStatement.Label is not null) - { - Visit(breakStatement.Label); - } - } - - protected internal virtual void VisitBlockStatement(BlockStatement blockStatement) - { - ref readonly var body = ref blockStatement.Body; - for (var i = 0; i < body.Count; i++) - { - Visit(body[i]); - } - } - } -} +using System; +using Esprima.Ast; + +namespace Esprima.Utils +{ + public class AstVisitor + { + public virtual void Visit(Node node) + { + node.Accept(this); + } + + protected internal virtual void VisitProgram(Program program) + { + ref readonly var statements = ref program.Body; + for (var i = 0; i < statements.Count; i++) + { + Visit(statements[i]); + } + } + + [Obsolete("This method may be removed in a future version as it will not be called anymore due to employing double dispatch (instead of switch dispatch).")] + protected virtual void VisitUnknownNode(Node node) + { + throw new NotImplementedException($"AST visitor doesn't support nodes of type {node.Type}, you can override VisitUnknownNode to handle this case."); + } + + protected internal virtual void VisitCatchClause(CatchClause catchClause) + { + if (catchClause.Param is not null) + { + Visit(catchClause.Param); + } + + Visit(catchClause.Body); + } + + protected internal virtual void VisitFunctionDeclaration(FunctionDeclaration functionDeclaration) + { + if (functionDeclaration.Id is not null) + { + Visit(functionDeclaration.Id); + } + + ref readonly var parameters = ref functionDeclaration.Params; + for (var i = 0; i < parameters.Count; i++) + { + Visit(parameters[i]); + } + + Visit(functionDeclaration.Body); + } + + protected internal virtual void VisitWithStatement(WithStatement withStatement) + { + Visit(withStatement.Object); + Visit(withStatement.Body); + } + + protected internal virtual void VisitWhileStatement(WhileStatement whileStatement) + { + Visit(whileStatement.Test); + Visit(whileStatement.Body); + } + + protected internal virtual void VisitVariableDeclaration(VariableDeclaration variableDeclaration) + { + ref readonly var declarations = ref variableDeclaration.Declarations; + for (var i = 0; i < declarations.Count; i++) + { + Visit(declarations[i]); + } + } + + protected internal virtual void VisitTryStatement(TryStatement tryStatement) + { + Visit(tryStatement.Block); + if (tryStatement.Handler is not null) + { + Visit(tryStatement.Handler); + } + + if (tryStatement.Finalizer is not null) + { + Visit(tryStatement.Finalizer); + } + } + + protected internal virtual void VisitThrowStatement(ThrowStatement throwStatement) + { + Visit(throwStatement.Argument); + } + + protected internal virtual void VisitSwitchStatement(SwitchStatement switchStatement) + { + Visit(switchStatement.Discriminant); + ref readonly var cases = ref switchStatement.Cases; + for (var i = 0; i < cases.Count; i++) + { + Visit(cases[i]); + } + } + + protected internal virtual void VisitSwitchCase(SwitchCase switchCase) + { + if (switchCase.Test is not null) + { + Visit(switchCase.Test); + } + + ref readonly var consequent = ref switchCase.Consequent; + for (var i = 0; i < consequent.Count; i++) + { + Visit(consequent[i]); + } + } + + protected internal virtual void VisitReturnStatement(ReturnStatement returnStatement) + { + if (returnStatement.Argument is not null) + { + Visit(returnStatement.Argument); + } + } + + protected internal virtual void VisitLabeledStatement(LabeledStatement labeledStatement) + { + Visit(labeledStatement.Label); + Visit(labeledStatement.Body); + } + + protected internal virtual void VisitIfStatement(IfStatement ifStatement) + { + Visit(ifStatement.Test); + Visit(ifStatement.Consequent); + if (ifStatement.Alternate is not null) + { + Visit(ifStatement.Alternate); + } + } + + protected internal virtual void VisitEmptyStatement(EmptyStatement emptyStatement) + { + } + + protected internal virtual void VisitDebuggerStatement(DebuggerStatement debuggerStatement) + { + } + + protected internal virtual void VisitExpressionStatement(ExpressionStatement expressionStatement) + { + Visit(expressionStatement.Expression); + } + + protected internal virtual void VisitForStatement(ForStatement forStatement) + { + if (forStatement.Init is not null) + { + Visit(forStatement.Init); + } + + if (forStatement.Test is not null) + { + Visit(forStatement.Test); + } + + if (forStatement.Update is not null) + { + Visit(forStatement.Update); + } + + Visit(forStatement.Body); + } + + protected internal virtual void VisitForInStatement(ForInStatement forInStatement) + { + Visit(forInStatement.Left); + Visit(forInStatement.Right); + Visit(forInStatement.Body); + } + + protected internal virtual void VisitDoWhileStatement(DoWhileStatement doWhileStatement) + { + Visit(doWhileStatement.Body); + Visit(doWhileStatement.Test); + } + + protected internal virtual void VisitArrowFunctionExpression(ArrowFunctionExpression arrowFunctionExpression) + { + ref readonly var parameters = ref arrowFunctionExpression.Params; + for (var i = 0; i < parameters.Count; i++) + { + Visit(parameters[i]); + } + + Visit(arrowFunctionExpression.Body); + } + + protected internal virtual void VisitUnaryExpression(UnaryExpression unaryExpression) + { + Visit(unaryExpression.Argument); + } + + protected internal virtual void VisitUpdateExpression(UpdateExpression updateExpression) + { + Visit(updateExpression.Argument); + } + + protected internal virtual void VisitThisExpression(ThisExpression thisExpression) + { + } + + protected internal virtual void VisitSequenceExpression(SequenceExpression sequenceExpression) + { + ref readonly var expressions = ref sequenceExpression.Expressions; + for (var i = 0; i < expressions.Count; i++) + { + Visit(expressions[i]); + } + } + + protected internal virtual void VisitObjectExpression(ObjectExpression objectExpression) + { + ref readonly var properties = ref objectExpression.Properties; + for (var i = 0; i < properties.Count; i++) + { + Visit(properties[i]); + } + } + + protected internal virtual void VisitNewExpression(NewExpression newExpression) + { + Visit(newExpression.Callee); + ref readonly var arguments = ref newExpression.Arguments; + for (var i = 0; i < arguments.Count; i++) + { + Visit(arguments[i]); + } + } + + protected internal virtual void VisitMemberExpression(MemberExpression memberExpression) + { + Visit(memberExpression.Object); + Visit(memberExpression.Property); + } + + protected internal virtual void VisitLogicalExpression(BinaryExpression binaryExpression) + { + Visit(binaryExpression.Left); + Visit(binaryExpression.Right); + } + + protected internal virtual void VisitLiteral(Literal literal) + { + } + + protected internal virtual void VisitIdentifier(Identifier identifier) + { + } + + protected internal virtual void VisitPrivateIdentifier(PrivateIdentifier privateIdentifier) + { + } + + protected internal virtual void VisitFunctionExpression(IFunction function) + { + if (function.Id is not null) + { + Visit(function.Id); + } + + ref readonly var parameters = ref function.Params; + for (var i = 0; i < parameters.Count; i++) + { + Visit(parameters[i]); + } + + Visit(function.Body); + } + + protected internal virtual void VisitPropertyDefinition(PropertyDefinition propertyDefinition) + { + Visit(propertyDefinition.Key); + + if (propertyDefinition.Value is not null) + { + Visit(propertyDefinition.Value); + } + } + + protected internal virtual void VisitChainExpression(ChainExpression chainExpression) + { + Visit(chainExpression.Expression); + } + + protected internal virtual void VisitClassExpression(ClassExpression classExpression) + { + if (classExpression.Id is not null) + { + Visit(classExpression.Id); + } + + if (classExpression.SuperClass is not null) + { + Visit(classExpression.SuperClass); + } + + Visit(classExpression.Body); + } + + protected internal virtual void VisitExportDefaultDeclaration(ExportDefaultDeclaration exportDefaultDeclaration) + { + Visit(exportDefaultDeclaration.Declaration); + } + + protected internal virtual void VisitExportAllDeclaration(ExportAllDeclaration exportAllDeclaration) + { + Visit(exportAllDeclaration.Source); + } + + protected internal virtual void VisitExportNamedDeclaration(ExportNamedDeclaration exportNamedDeclaration) + { + if (exportNamedDeclaration.Declaration is not null) + { + Visit(exportNamedDeclaration.Declaration); + } + + ref readonly var specifiers = ref exportNamedDeclaration.Specifiers; + for (var i = 0; i < specifiers.Count; i++) + { + Visit(specifiers[i]); + } + + if (exportNamedDeclaration.Source is not null) + { + Visit(exportNamedDeclaration.Source); + } + } + + protected internal virtual void VisitExportSpecifier(ExportSpecifier exportSpecifier) + { + Visit(exportSpecifier.Local); + Visit(exportSpecifier.Exported); + } + + protected internal virtual void VisitImport(Import import) + { + if (import.Source != null) + { + Visit(import.Source); + } + } + + protected internal virtual void VisitImportDeclaration(ImportDeclaration importDeclaration) + { + ref readonly var specifiers = ref importDeclaration.Specifiers; + for (var i = 0; i < specifiers.Count; i++) + { + Visit(specifiers[i]); + } + + Visit(importDeclaration.Source); + } + + protected internal virtual void VisitImportNamespaceSpecifier(ImportNamespaceSpecifier importNamespaceSpecifier) + { + Visit(importNamespaceSpecifier.Local); + } + + protected internal virtual void VisitImportDefaultSpecifier(ImportDefaultSpecifier importDefaultSpecifier) + { + Visit(importDefaultSpecifier.Local); + } + + protected internal virtual void VisitImportSpecifier(ImportSpecifier importSpecifier) + { + Visit(importSpecifier.Imported); + Visit(importSpecifier.Local); + } + + protected internal virtual void VisitMethodDefinition(MethodDefinition methodDefinition) + { + Visit(methodDefinition.Key); + Visit(methodDefinition.Value); + } + + protected internal virtual void VisitForOfStatement(ForOfStatement forOfStatement) + { + Visit(forOfStatement.Left); + Visit(forOfStatement.Right); + Visit(forOfStatement.Body); + } + + protected internal virtual void VisitClassDeclaration(ClassDeclaration classDeclaration) + { + if (classDeclaration.Id is not null) + { + Visit(classDeclaration.Id); + } + + if (classDeclaration.SuperClass is not null) + { + Visit(classDeclaration.SuperClass); + } + + Visit(classDeclaration.Body); + } + + protected internal virtual void VisitClassBody(ClassBody classBody) + { + ref readonly var body = ref classBody.Body; + for (var i = 0; i < body.Count; i++) + { + Visit(body[i]); + } + } + + protected internal virtual void VisitYieldExpression(YieldExpression yieldExpression) + { + if (yieldExpression.Argument is not null) + { + Visit(yieldExpression.Argument); + } + } + + protected internal virtual void VisitTaggedTemplateExpression(TaggedTemplateExpression taggedTemplateExpression) + { + Visit(taggedTemplateExpression.Tag); + Visit(taggedTemplateExpression.Quasi); + } + + protected internal virtual void VisitSuper(Super super) + { + } + + protected internal virtual void VisitMetaProperty(MetaProperty metaProperty) + { + Visit(metaProperty.Meta); + Visit(metaProperty.Property); + } + + protected internal virtual void VisitArrowParameterPlaceHolder(ArrowParameterPlaceHolder arrowParameterPlaceHolder) + { + // ArrowParameterPlaceHolder nodes never appear in the final tree and only used during the construction of a tree. + } + + protected internal virtual void VisitObjectPattern(ObjectPattern objectPattern) + { + ref readonly var properties = ref objectPattern.Properties; + for (var i = 0; i < properties.Count; i++) + { + Visit(properties[i]); + } + } + + protected internal virtual void VisitSpreadElement(SpreadElement spreadElement) + { + Visit(spreadElement.Argument); + } + + protected internal virtual void VisitAssignmentPattern(AssignmentPattern assignmentPattern) + { + Visit(assignmentPattern.Left); + Visit(assignmentPattern.Right); + } + + protected internal virtual void VisitArrayPattern(ArrayPattern arrayPattern) + { + ref readonly var elements = ref arrayPattern.Elements; + for (var i = 0; i < elements.Count; i++) + { + var expr = elements[i]; + if (expr is not null) + { + Visit(expr); + } + } + } + + protected internal virtual void VisitVariableDeclarator(VariableDeclarator variableDeclarator) + { + Visit(variableDeclarator.Id); + if (variableDeclarator.Init is not null) + { + Visit(variableDeclarator.Init); + } + } + + protected internal virtual void VisitTemplateLiteral(TemplateLiteral templateLiteral) + { + ref readonly var quasis = ref templateLiteral.Quasis; + ref readonly var expressions = ref templateLiteral.Expressions; + + var n = expressions.Count; + + for (var i = 0; i < n; i++) + { + Visit(quasis[i]); + Visit(expressions[i]); + } + + Visit(quasis[n]); + } + + protected internal virtual void VisitTemplateElement(TemplateElement templateElement) + { + } + + protected internal virtual void VisitRestElement(RestElement restElement) + { + Visit(restElement.Argument); + } + + protected internal virtual void VisitProperty(Property property) + { + Visit(property.Key); + Visit(property.Value); + } + + protected internal virtual void VisitAwaitExpression(AwaitExpression awaitExpression) + { + Visit(awaitExpression.Argument); + } + + protected internal virtual void VisitConditionalExpression(ConditionalExpression conditionalExpression) + { + Visit(conditionalExpression.Test); + Visit(conditionalExpression.Consequent); + Visit(conditionalExpression.Alternate); + } + + protected internal virtual void VisitCallExpression(CallExpression callExpression) + { + Visit(callExpression.Callee); + ref readonly var arguments = ref callExpression.Arguments; + for (var i = 0; i < arguments.Count; i++) + { + Visit(arguments[i]); + } + } + + protected internal virtual void VisitBinaryExpression(BinaryExpression binaryExpression) + { + Visit(binaryExpression.Left); + Visit(binaryExpression.Right); + } + + protected internal virtual void VisitArrayExpression(ArrayExpression arrayExpression) + { + ref readonly var elements = ref arrayExpression.Elements; + for (var i = 0; i < elements.Count; i++) + { + var expr = elements[i]; + if (expr is not null) + { + Visit(expr); + } + } + } + + protected internal virtual void VisitAssignmentExpression(AssignmentExpression assignmentExpression) + { + Visit(assignmentExpression.Left); + Visit(assignmentExpression.Right); + } + + protected internal virtual void VisitContinueStatement(ContinueStatement continueStatement) + { + if (continueStatement.Label is not null) + { + Visit(continueStatement.Label); + } + } + + protected internal virtual void VisitBreakStatement(BreakStatement breakStatement) + { + if (breakStatement.Label is not null) + { + Visit(breakStatement.Label); + } + } + + protected internal virtual void VisitBlockStatement(BlockStatement blockStatement) + { + ref readonly var body = ref blockStatement.Body; + for (var i = 0; i < body.Count; i++) + { + Visit(body[i]); + } + } + } +} diff --git a/test/Esprima.Tests/Fixtures/ES2017/async/methods/invalid-async-line-terminator-method.js b/test/Esprima.Tests/Fixtures/ES2017/async/methods/async-line-terminator-method.js similarity index 100% rename from test/Esprima.Tests/Fixtures/ES2017/async/methods/invalid-async-line-terminator-method.js rename to test/Esprima.Tests/Fixtures/ES2017/async/methods/async-line-terminator-method.js diff --git a/test/Esprima.Tests/Fixtures/ES2017/async/methods/async-line-terminator-method.tree.json b/test/Esprima.Tests/Fixtures/ES2017/async/methods/async-line-terminator-method.tree.json new file mode 100644 index 00000000..4641f5ad --- /dev/null +++ b/test/Esprima.Tests/Fixtures/ES2017/async/methods/async-line-terminator-method.tree.json @@ -0,0 +1,171 @@ +{ + "type": "Program", + "body": [ + { + "type": "ClassDeclaration", + "id": { + "type": "Identifier", + "name": "X", + "range": [ + 6, + 7 + ], + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 7 + } + } + }, + "superClass": null, + "body": { + "type": "ClassBody", + "body": [ + { + "type": "Identifier", + "name": "async", + "range": [ + 10, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 15 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "f", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 1 + } + } + }, + "computed": false, + "value": { + "type": "FunctionExpression", + "id": null, + "params": [], + "body": { + "type": "BlockStatement", + "body": [], + "range": [ + 19, + 21 + ], + "loc": { + "start": { + "line": 2, + "column": 3 + }, + "end": { + "line": 2, + "column": 5 + } + } + }, + "generator": false, + "expression": false, + "async": false, + "range": [ + 17, + 21 + ], + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 5 + } + } + }, + "kind": "method", + "static": false, + "range": [ + 16, + 21 + ], + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 5 + } + } + } + ], + "range": [ + 8, + 23 + ], + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 2, + "column": 7 + } + } + }, + "range": [ + 0, + 23 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 7 + } + } + } + ], + "sourceType": "script", + "range": [ + 0, + 23 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 7 + } + } +} \ No newline at end of file diff --git a/test/Esprima.Tests/Fixtures/ES2017/async/methods/invalid-async-line-terminator-static-method.js b/test/Esprima.Tests/Fixtures/ES2017/async/methods/async-line-terminator-static-method.js similarity index 100% rename from test/Esprima.Tests/Fixtures/ES2017/async/methods/invalid-async-line-terminator-static-method.js rename to test/Esprima.Tests/Fixtures/ES2017/async/methods/async-line-terminator-static-method.js diff --git a/test/Esprima.Tests/Fixtures/ES2017/async/methods/async-line-terminator-static-method.tree.json b/test/Esprima.Tests/Fixtures/ES2017/async/methods/async-line-terminator-static-method.tree.json new file mode 100644 index 00000000..d035925c --- /dev/null +++ b/test/Esprima.Tests/Fixtures/ES2017/async/methods/async-line-terminator-static-method.tree.json @@ -0,0 +1,171 @@ +{ + "type": "Program", + "body": [ + { + "type": "ClassDeclaration", + "id": { + "type": "Identifier", + "name": "X", + "range": [ + 6, + 7 + ], + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 7 + } + } + }, + "superClass": null, + "body": { + "type": "ClassBody", + "body": [ + { + "type": "Identifier", + "name": "async", + "range": [ + 17, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 17 + }, + "end": { + "line": 1, + "column": 22 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "f", + "range": [ + 23, + 24 + ], + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 1 + } + } + }, + "computed": false, + "value": { + "type": "FunctionExpression", + "id": null, + "params": [], + "body": { + "type": "BlockStatement", + "body": [], + "range": [ + 26, + 28 + ], + "loc": { + "start": { + "line": 2, + "column": 3 + }, + "end": { + "line": 2, + "column": 5 + } + } + }, + "generator": false, + "expression": false, + "async": false, + "range": [ + 24, + 28 + ], + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 5 + } + } + }, + "kind": "method", + "static": false, + "range": [ + 23, + 28 + ], + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 5 + } + } + } + ], + "range": [ + 8, + 30 + ], + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 2, + "column": 7 + } + } + }, + "range": [ + 0, + 30 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 7 + } + } + } + ], + "sourceType": "script", + "range": [ + 0, + 30 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 7 + } + } +} \ No newline at end of file diff --git a/test/Esprima.Tests/Fixtures/ES2017/async/methods/invalid-async-line-terminator-method.failure.json b/test/Esprima.Tests/Fixtures/ES2017/async/methods/invalid-async-line-terminator-method.failure.json deleted file mode 100644 index 10acdf05..00000000 --- a/test/Esprima.Tests/Fixtures/ES2017/async/methods/invalid-async-line-terminator-method.failure.json +++ /dev/null @@ -1 +0,0 @@ -{"index":16,"lineNumber":2,"column":17,"message":"Error: Line 2: Unexpected identifier","description":"Unexpected identifier"} \ No newline at end of file diff --git a/test/Esprima.Tests/Fixtures/ES2017/async/methods/invalid-async-line-terminator-static-method.failure.json b/test/Esprima.Tests/Fixtures/ES2017/async/methods/invalid-async-line-terminator-static-method.failure.json deleted file mode 100644 index c98a6e8e..00000000 --- a/test/Esprima.Tests/Fixtures/ES2017/async/methods/invalid-async-line-terminator-static-method.failure.json +++ /dev/null @@ -1 +0,0 @@ -{"index":23,"lineNumber":2,"column":24,"message":"Error: Line 2: Unexpected identifier","description":"Unexpected identifier"} \ No newline at end of file