1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ETSparser.h"
17
18#include "lexer/lexer.h"
19#include "ir/typeNode.h"
20#include "ir/expressions/identifier.h"
21#include "ir/expressions/blockExpression.h"
22#include "ir/expressions/sequenceExpression.h"
23#include "ir/statements/blockStatement.h"
24#include "ir/statements/expressionStatement.h"
25#include "ir/base/methodDefinition.h"
26#include "ir/ts/tsInterfaceBody.h"
27#include "parser/parserStatusContext.h"
28
29namespace ark::es2panda::parser {
30//================================================================================================//
31//  Methods to create AST node(s) from the specified string (part of valid ETS-code!)
32//================================================================================================//
33
34// NOLINTBEGIN(modernize-avoid-c-arrays)
35inline constexpr char const FORMAT_SIGNATURE = '@';
36inline constexpr char const TYPE_FORMAT_NODE = 'T';
37inline constexpr char const GENERAL_FORMAT_NODE = 'N';
38inline constexpr char const IDENTIFIER_FORMAT_NODE = 'I';
39
40static constexpr char const INVALID_NUMBER_NODE[] = "Invalid node number in format expression.";
41static constexpr char const INVALID_FORMAT_NODE[] = "Invalid node type in format expression.";
42static constexpr char const INSERT_NODE_ABSENT[] = "There is no any node to insert at the placeholder position.";
43static constexpr char const INVALID_INSERT_NODE[] =
44    "Inserting node type differs from that required by format specification.";
45static constexpr char const INVALID_CLASS_FIELD[] = "Cannot parse class field definition property.";
46static constexpr char const INVALID_CLASS_METHOD[] = "Cannot parse class method definition property.";
47// NOLINTEND(modernize-avoid-c-arrays)
48
49ParserImpl::NodeFormatType ETSParser::GetFormatPlaceholderType() const
50{
51    ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_FORMAT);
52    Lexer()->NextToken();
53
54    bool isArray = false;
55    if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) {
56        isArray = true;
57        Lexer()->NextToken();
58    }
59
60    ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT);
61    char const *const identData = Lexer()->GetToken().Ident().Bytes();
62
63    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic, cert-err34-c)
64    auto identNumber = std::atoi(identData + 1U);
65    if (identNumber <= 0) {
66        ThrowSyntaxError(INVALID_NUMBER_NODE, Lexer()->GetToken().Start());
67    }
68
69    return {isArray, *identData,
70            static_cast<decltype(std::get<2>(std::declval<ParserImpl::NodeFormatType>()))>(identNumber - 1)};
71}
72
73ir::Expression *ETSParser::ParseExpressionFormatPlaceholder()
74{
75    if (insertingNodes_.empty()) {
76        ThrowSyntaxError(INSERT_NODE_ABSENT, Lexer()->GetToken().Start());
77    }
78
79    ParserImpl::NodeFormatType nodeFormat = GetFormatPlaceholderType();
80    if (std::get<0>(nodeFormat)) {
81        ThrowSyntaxError(INVALID_FORMAT_NODE, Lexer()->GetToken().Start());
82    }
83
84    if (auto const placeholderType = std::get<1>(nodeFormat); placeholderType == TYPE_FORMAT_NODE) {
85        return ParseTypeFormatPlaceholder(std::make_optional(std::move(nodeFormat)));
86    } else if (placeholderType == IDENTIFIER_FORMAT_NODE) {  // NOLINT(readability-else-after-return)
87        return ParseIdentifierFormatPlaceholder(std::make_optional(std::move(nodeFormat)));
88    } else if (placeholderType != EXPRESSION_FORMAT_NODE) {  // NOLINT(readability-else-after-return)
89        ThrowSyntaxError(INVALID_FORMAT_NODE, Lexer()->GetToken().Start());
90    }
91
92    auto const placeholderNumber = std::get<2>(nodeFormat);
93    auto *const insertingNode =
94        placeholderNumber < insertingNodes_.size() ? insertingNodes_[placeholderNumber] : nullptr;
95    if (insertingNode == nullptr || !insertingNode->IsExpression()) {
96        ThrowSyntaxError(INVALID_INSERT_NODE, Lexer()->GetToken().Start());
97    }
98
99    auto *const insertExpression = insertingNode->AsExpression();
100    Lexer()->NextToken();
101    return insertExpression;
102}
103
104ir::TypeNode *ETSParser::ParseTypeFormatPlaceholder(std::optional<ParserImpl::NodeFormatType> nodeFormat)
105{
106    if (!nodeFormat.has_value()) {
107        if (insertingNodes_.empty()) {
108            ThrowSyntaxError(INSERT_NODE_ABSENT, Lexer()->GetToken().Start());
109        }
110
111        nodeFormat = GetFormatPlaceholderType();
112        if (std::get<0>(*nodeFormat) || std::get<1>(*nodeFormat) != TYPE_FORMAT_NODE) {
113            ThrowSyntaxError(INVALID_FORMAT_NODE, Lexer()->GetToken().Start());
114        }
115    }
116
117    auto const placeholderNumber = std::get<2>(*nodeFormat);
118    auto *const insertingNode =
119        placeholderNumber < insertingNodes_.size() ? insertingNodes_[placeholderNumber] : nullptr;
120    if (insertingNode == nullptr || !insertingNode->IsExpression() || !insertingNode->AsExpression()->IsTypeNode()) {
121        ThrowSyntaxError(INVALID_INSERT_NODE, Lexer()->GetToken().Start());
122    }
123
124    auto *const insertType = insertingNode->AsExpression()->AsTypeNode();
125    Lexer()->NextToken();
126    return insertType;
127}
128
129ir::Identifier *ETSParser::ParseIdentifierFormatPlaceholder(std::optional<ParserImpl::NodeFormatType> nodeFormat) const
130{
131    if (!nodeFormat.has_value()) {
132        if (insertingNodes_.empty()) {
133            ThrowSyntaxError(INSERT_NODE_ABSENT, Lexer()->GetToken().Start());
134        }
135
136        nodeFormat = GetFormatPlaceholderType();
137        if (std::get<0>(*nodeFormat) || std::get<1>(*nodeFormat) != IDENTIFIER_FORMAT_NODE) {
138            ThrowSyntaxError(INVALID_FORMAT_NODE, Lexer()->GetToken().Start());
139        }
140    }
141
142    auto const placeholderNumber = std::get<2>(*nodeFormat);
143    auto *const insertingNode =
144        placeholderNumber < insertingNodes_.size() ? insertingNodes_[placeholderNumber] : nullptr;
145    if (insertingNode == nullptr || !insertingNode->IsExpression() || !insertingNode->AsExpression()->IsIdentifier()) {
146        ThrowSyntaxError(INVALID_INSERT_NODE, Lexer()->GetToken().Start());
147    }
148
149    auto *const insertIdentifier = insertingNode->AsExpression()->AsIdentifier();
150    Lexer()->NextToken();
151    return insertIdentifier;
152}
153
154ir::Statement *ETSParser::ParseStatementFormatPlaceholder() const
155{
156    if (insertingNodes_.empty()) {
157        ThrowSyntaxError(INSERT_NODE_ABSENT, Lexer()->GetToken().Start());
158    }
159
160    ParserImpl::NodeFormatType nodeFormat = GetFormatPlaceholderType();
161    if (std::get<0>(nodeFormat) || std::get<1>(nodeFormat) != STATEMENT_FORMAT_NODE) {
162        ThrowSyntaxError(INVALID_FORMAT_NODE, Lexer()->GetToken().Start());
163    }
164
165    auto const placeholderNumber = std::get<2>(nodeFormat);
166    auto *const insertingNode =
167        placeholderNumber < insertingNodes_.size() ? insertingNodes_[placeholderNumber] : nullptr;
168    if (insertingNode == nullptr || !insertingNode->IsStatement()) {
169        ThrowSyntaxError(INVALID_INSERT_NODE, Lexer()->GetToken().Start());
170    }
171
172    Lexer()->NextToken();
173    return insertingNode->AsStatement();
174}
175
176ir::AstNode *ETSParser::ParseTypeParametersFormatPlaceholder() const
177{
178    ParserImpl::NodeFormatType nodeFormat = GetFormatPlaceholderType();
179    if (std::get<0>(nodeFormat) || std::get<1>(nodeFormat) != EXPRESSION_FORMAT_NODE) {
180        ThrowSyntaxError(INVALID_FORMAT_NODE, Lexer()->GetToken().Start());
181    }
182
183    auto const placeholderNumber = std::get<2>(nodeFormat);
184    if (placeholderNumber >= insertingNodes_.size()) {
185        ThrowSyntaxError(INSERT_NODE_ABSENT, Lexer()->GetToken().Start());
186    }
187
188    auto *const insertingNode = insertingNodes_[placeholderNumber];
189    if (insertingNode != nullptr && !insertingNode->IsTSTypeParameterDeclaration() &&
190        !insertingNode->IsTSTypeParameterInstantiation()) {
191        ThrowSyntaxError(INVALID_INSERT_NODE, Lexer()->GetToken().Start());
192    }
193
194    Lexer()->NextToken();
195    return insertingNode;
196}
197
198ArenaVector<ir::AstNode *> &ETSParser::ParseAstNodesArrayFormatPlaceholder() const
199{
200    if (insertingNodes_.empty()) {
201        ThrowSyntaxError(INSERT_NODE_ABSENT, Lexer()->GetToken().Start());
202    }
203
204    ParserImpl::NodeFormatType nodeFormat = GetFormatPlaceholderType();
205    if (!std::get<0>(nodeFormat) || std::get<1>(nodeFormat) != GENERAL_FORMAT_NODE) {
206        ThrowSyntaxError(INVALID_FORMAT_NODE, Lexer()->GetToken().Start());
207    }
208
209    auto const placeholderNumber = std::get<2>(nodeFormat);
210    auto *const insertingNode =
211        placeholderNumber < insertingNodes_.size() ? insertingNodes_[placeholderNumber] : nullptr;
212    if (insertingNode == nullptr || !insertingNode->IsTSInterfaceBody()) {
213        ThrowSyntaxError(INVALID_INSERT_NODE, Lexer()->GetToken().Start());
214    }
215
216    Lexer()->NextToken();
217    return insertingNode->AsTSInterfaceBody()->Body();
218}
219
220ArenaVector<ir::Statement *> &ETSParser::ParseStatementsArrayFormatPlaceholder() const
221{
222    if (insertingNodes_.empty()) {
223        ThrowSyntaxError(INSERT_NODE_ABSENT, Lexer()->GetToken().Start());
224    }
225
226    ParserImpl::NodeFormatType nodeFormat = GetFormatPlaceholderType();
227    if (!std::get<0>(nodeFormat) || std::get<1>(nodeFormat) != STATEMENT_FORMAT_NODE) {
228        ThrowSyntaxError(INVALID_FORMAT_NODE, Lexer()->GetToken().Start());
229    }
230
231    auto const placeholderNumber = std::get<2>(nodeFormat);
232    auto *const insertingNode =
233        placeholderNumber < insertingNodes_.size() ? insertingNodes_[placeholderNumber] : nullptr;
234    if (insertingNode == nullptr || !insertingNode->IsBlockExpression()) {
235        ThrowSyntaxError(INVALID_INSERT_NODE, Lexer()->GetToken().Start());
236    }
237
238    Lexer()->NextToken();
239    return insertingNode->AsBlockExpression()->Statements();
240}
241
242ArenaVector<ir::Expression *> &ETSParser::ParseExpressionsArrayFormatPlaceholder() const
243{
244    if (insertingNodes_.empty()) {
245        ThrowSyntaxError(INSERT_NODE_ABSENT, Lexer()->GetToken().Start());
246    }
247
248    ParserImpl::NodeFormatType nodeFormat = GetFormatPlaceholderType();
249    if (!std::get<0>(nodeFormat) || std::get<1>(nodeFormat) != EXPRESSION_FORMAT_NODE) {
250        ThrowSyntaxError(INVALID_FORMAT_NODE, Lexer()->GetToken().Start());
251    }
252
253    auto const placeholderNumber = std::get<2>(nodeFormat);
254    auto *const insertingNode =
255        placeholderNumber < insertingNodes_.size() ? insertingNodes_[placeholderNumber] : nullptr;
256    if (insertingNode == nullptr || !insertingNode->IsSequenceExpression()) {
257        ThrowSyntaxError(INVALID_INSERT_NODE, Lexer()->GetToken().Start());
258    }
259
260    Lexer()->NextToken();
261    return insertingNode->AsSequenceExpression()->Sequence();
262}
263
264ir::Statement *ETSParser::CreateStatement(std::string_view const sourceCode)
265{
266    util::UString source {sourceCode, Allocator()};
267    auto const isp = InnerSourceParser(this);
268    auto const lexer = InitLexer({GetContext().FormattingFileName(), source.View().Utf8()});
269
270    lexer::SourcePosition const startLoc = lexer->GetToken().Start();
271    lexer->NextToken();
272
273    auto statements = ParseStatementList(StatementParsingFlags::STMT_GLOBAL_LEXICAL);
274    auto const statementNumber = statements.size();
275    if (statementNumber == 0U) {
276        return nullptr;
277    }
278
279    if (statementNumber == 1U) {
280        return statements[0U];
281    }
282
283    auto *const blockStmt = AllocNode<ir::BlockStatement>(Allocator(), std::move(statements));
284    blockStmt->SetRange({startLoc, lexer->GetToken().End()});
285
286    for (auto *statement : blockStmt->Statements()) {
287        statement->SetParent(blockStmt);
288    }
289
290    return blockStmt;
291}
292
293ir::Statement *ETSParser::CreateFormattedStatement(std::string_view const sourceCode,
294                                                   std::vector<ir::AstNode *> &insertingNodes)
295{
296    insertingNodes_.swap(insertingNodes);
297    auto const statement = CreateStatement(sourceCode);
298    insertingNodes_.swap(insertingNodes);
299    return statement;
300}
301
302ArenaVector<ir::Statement *> ETSParser::CreateStatements(std::string_view const sourceCode)
303{
304    util::UString source {sourceCode, Allocator()};
305    auto const isp = InnerSourceParser(this);
306    auto const lexer = InitLexer({GetContext().FormattingFileName(), source.View().Utf8()});
307
308    lexer->NextToken();
309    return ParseStatementList(StatementParsingFlags::STMT_GLOBAL_LEXICAL);
310}
311
312ArenaVector<ir::Statement *> ETSParser::CreateFormattedStatements(std::string_view const sourceCode,
313                                                                  std::vector<ir::AstNode *> &insertingNodes)
314{
315    insertingNodes_.swap(insertingNodes);
316    auto statements = CreateStatements(sourceCode);
317    insertingNodes_.swap(insertingNodes);
318    return statements;
319}
320
321//  NOTE: this method returns only a single (the first) class filed definition.
322//  It seems that it is possible to have several of them be parsed at a time but nobody knows how...
323ir::AstNode *ETSParser::CreateFormattedClassFieldDefinition(std::string_view sourceCode,
324                                                            std::vector<ir::AstNode *> &insertingNodes)
325{
326    static ArenaVector<ir::AstNode *> const DUMMY_ARRAY {Allocator()->Adapter()};
327    insertingNodes_.swap(insertingNodes);
328
329    auto *const property = CreateClassElement(sourceCode, DUMMY_ARRAY, ir::ClassDefinitionModifiers::NONE);
330    if (!property->IsTSInterfaceBody() || property->AsTSInterfaceBody()->Body().empty()) {
331        ThrowSyntaxError(INVALID_CLASS_FIELD);
332    }
333
334    insertingNodes_.swap(insertingNodes);
335    return property->AsTSInterfaceBody()->Body().front();
336}
337
338ir::AstNode *ETSParser::CreateFormattedClassMethodDefinition(std::string_view sourceCode,
339                                                             std::vector<ir::AstNode *> &insertingNodes)
340{
341    static ArenaVector<ir::AstNode *> const DUMMY_ARRAY {Allocator()->Adapter()};
342    insertingNodes_.swap(insertingNodes);
343
344    auto *const property = CreateClassElement(sourceCode, DUMMY_ARRAY, ir::ClassDefinitionModifiers::NONE);
345    if (!property->IsMethodDefinition()) {
346        ThrowSyntaxError(INVALID_CLASS_METHOD);
347    }
348
349    insertingNodes_.swap(insertingNodes);
350    return property;
351}
352
353ir::AstNode *ETSParser::CreateFormattedClassElement(std::string_view sourceCode,
354                                                    std::vector<ir::AstNode *> &insertingNodes,
355                                                    const ArenaVector<ir::AstNode *> &properties,
356                                                    ir::ClassDefinitionModifiers modifiers)
357{
358    insertingNodes_.swap(insertingNodes);
359    auto *const classElement = CreateClassElement(sourceCode, properties, modifiers);
360    insertingNodes_.swap(insertingNodes);
361    return classElement;
362}
363
364//  NOTE: the method has limited functionality - it returns 'ir::TSInterfaceBody' placeholder for the field
365//  declaration(s) (properties themselves are in ->Body() member) and does not perform any check of the node returned.
366//  Also the node isn't placed in the providing properties container.
367ir::AstNode *ETSParser::CreateClassElement(std::string_view sourceCode, const ArenaVector<ir::AstNode *> &properties,
368                                           ir::ClassDefinitionModifiers modifiers)
369{
370    util::UString source {sourceCode, Allocator()};
371    auto const isp = InnerSourceParser(this);
372    auto const lexer = InitLexer({GetContext().FormattingFileName(), source.View().Utf8()});
373
374    auto savedCtx = SavedStatusContext<ParserStatus::IN_CLASS_BODY>(&GetContext());
375    SavedClassPrivateContext classContext(this);
376
377    lexer->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
378
379    return ParseClassElement(properties, modifiers, ir::ModifierFlags::NONE);
380}
381
382ir::ClassDeclaration *ETSParser::CreateFormattedClassDeclaration(std::string_view sourceCode,
383                                                                 std::vector<ir::AstNode *> &insertingNodes,
384                                                                 bool const allowStatic)
385{
386    insertingNodes_.swap(insertingNodes);
387    auto *const classDeclaration = CreateClassDeclaration(sourceCode, allowStatic);
388    insertingNodes_.swap(insertingNodes);
389    return classDeclaration;
390}
391
392ir::ClassDeclaration *ETSParser::CreateClassDeclaration(std::string_view sourceCode, bool allowStatic)
393{
394    util::UString source {sourceCode, Allocator()};
395    auto const isp = InnerSourceParser(this);
396    auto const lexer = InitLexer({GetContext().FormattingFileName(), source.View().Utf8()});
397
398    auto savedCtx = SavedStatusContext<ParserStatus::IN_CLASS_BODY>(&GetContext());
399
400    auto modifiers = ir::ClassDefinitionModifiers::ID_REQUIRED | ir::ClassDefinitionModifiers::CLASS_DECL;
401    ir::ModifierFlags flags = ir::ModifierFlags::NONE;
402
403    lexer->NextToken();
404
405    switch (auto tokenType = Lexer()->GetToken().Type(); tokenType) {
406        case lexer::TokenType::KEYW_STATIC: {
407            if (!allowStatic) {
408                ThrowUnexpectedToken(Lexer()->GetToken().Type());
409            }
410            [[fallthrough]];
411        }
412        case lexer::TokenType::KEYW_ABSTRACT:
413        case lexer::TokenType::KEYW_FINAL: {
414            flags = ParseClassModifiers();
415            if (allowStatic && (flags & ir::ModifierFlags::STATIC) == 0U) {
416                modifiers |= ir::ClassDefinitionModifiers::INNER;
417            }
418
419            if (auto const tokType = Lexer()->GetToken().Type(); tokType != lexer::TokenType::KEYW_CLASS) {
420                ThrowUnexpectedToken(tokType);
421            }
422            [[fallthrough]];
423        }
424        case lexer::TokenType::KEYW_CLASS: {
425            return ParseClassDeclaration(modifiers);
426        }
427        default: {
428            ThrowUnexpectedToken(tokenType);
429        }
430    }
431}
432
433ir::MethodDefinition *ETSParser::CreateConstructorDefinition(ir::ModifierFlags modifiers,
434                                                             std::string_view const sourceCode)
435{
436    util::UString source {sourceCode, Allocator()};
437    auto const isp = InnerSourceParser(this);
438    auto const lexer = InitLexer({GetContext().FormattingFileName(), source.View().Utf8()});
439
440    auto const startLoc = Lexer()->GetToken().Start();
441    Lexer()->NextToken();
442
443    if (IsClassMethodModifier(Lexer()->GetToken().Type())) {
444        modifiers |= ParseClassMethodModifiers(false);
445    }
446
447    if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_CONSTRUCTOR) {
448        ThrowSyntaxError({"Unexpected token. 'Constructor' keyword is expected."});
449    }
450
451    if ((modifiers & ir::ModifierFlags::ASYNC) != 0) {
452        ThrowSyntaxError({"Constructor should not be async."});
453    }
454
455    auto *memberName = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
456    modifiers |= ir::ModifierFlags::CONSTRUCTOR;
457    Lexer()->NextToken();
458
459    auto *const methodDefinition = ParseClassMethodDefinition(memberName, modifiers);
460    methodDefinition->SetStart(startLoc);
461
462    return methodDefinition;
463}
464
465ir::Expression *ETSParser::CreateExpression(std::string_view const sourceCode, ExpressionParseFlags const flags)
466{
467    util::UString source {sourceCode, Allocator()};
468    auto const isp = InnerSourceParser(this);
469    auto const lexer = InitLexer({GetContext().FormattingFileName(), source.View().Utf8()});
470
471    lexer::SourcePosition const startLoc = lexer->GetToken().Start();
472    lexer->NextToken();
473
474    ir::Expression *returnExpression = ParseExpression(flags);
475    returnExpression->SetRange({startLoc, lexer->GetToken().End()});
476
477    return returnExpression;
478}
479
480ir::Expression *ETSParser::CreateFormattedExpression(std::string_view const sourceCode,
481                                                     std::vector<ir::AstNode *> &insertingNodes)
482{
483    ir::Expression *returnExpression;
484    insertingNodes_.swap(insertingNodes);
485
486    if (auto statements = CreateStatements(sourceCode);
487        statements.size() == 1U && statements.back()->IsExpressionStatement()) {
488        returnExpression = statements.back()->AsExpressionStatement()->GetExpression();
489    } else {
490        returnExpression = AllocNode<ir::BlockExpression>(std::move(statements));
491    }
492
493    insertingNodes_.swap(insertingNodes);
494    return returnExpression;
495}
496
497ir::Statement *ETSParser::CreateTopLevelStatement(std::string_view const sourceCode)
498{
499    util::UString source {sourceCode, Allocator()};
500    auto const isp = InnerSourceParser(this);
501    auto const lexer = InitLexer({GetContext().FormattingFileName(), source.View().Utf8()});
502
503    lexer->NextToken();
504
505    return ParseTopLevelStatement();
506}
507
508ir::Statement *ETSParser::CreateFormattedTopLevelStatement(std::string_view const sourceCode,
509                                                           std::vector<ir::AstNode *> &insertingNodes)
510{
511    insertingNodes_.swap(insertingNodes);
512    auto const statement = CreateTopLevelStatement(sourceCode);
513    insertingNodes_.swap(insertingNodes);
514    return statement;
515}
516
517ir::TypeNode *ETSParser::CreateTypeAnnotation(TypeAnnotationParsingOptions *options, std::string_view const sourceCode)
518{
519    util::UString source {sourceCode, Allocator()};
520    auto const isp = InnerSourceParser(this);
521    auto const lexer = InitLexer({GetContext().FormattingFileName(), source.View().Utf8()});
522
523    lexer->NextToken();
524    return ParseTypeAnnotation(options);
525}
526}  // namespace ark::es2panda::parser
527