• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 #include "ETSNolintParser.h"
18 #include <utility>
19 #include <tuple>
20 #include "util/es2pandaMacros.h"
21 #include "parser/parserFlags.h"
22 #include "parser/parserStatusContext.h"
23 #include "util/helpers.h"
24 #include "util/language.h"
25 #include "utils/arena_containers.h"
26 #include "varbinder/varbinder.h"
27 #include "varbinder/ETSBinder.h"
28 #include "lexer/lexer.h"
29 #include "lexer/ETSLexer.h"
30 #include "ir/astNode.h"
31 #include "ir/brokenTypeNode.h"
32 #include "ir/base/classDefinition.h"
33 #include "ir/base/decorator.h"
34 #include "ir/base/catchClause.h"
35 #include "ir/base/classProperty.h"
36 #include "ir/base/scriptFunction.h"
37 #include "ir/base/methodDefinition.h"
38 #include "ir/base/classStaticBlock.h"
39 #include "ir/base/spreadElement.h"
40 #include "ir/expressions/identifier.h"
41 #include "ir/expressions/functionExpression.h"
42 #include "ir/expressions/dummyNode.h"
43 #include "ir/module/importDeclaration.h"
44 #include "ir/module/importDefaultSpecifier.h"
45 #include "ir/module/importSpecifier.h"
46 #include "ir/module/exportSpecifier.h"
47 #include "ir/module/exportNamedDeclaration.h"
48 #include "ir/statements/blockStatement.h"
49 #include "ir/statements/ifStatement.h"
50 #include "ir/statements/labelledStatement.h"
51 #include "ir/statements/switchStatement.h"
52 #include "ir/statements/throwStatement.h"
53 #include "ir/statements/tryStatement.h"
54 #include "ir/statements/whileStatement.h"
55 #include "ir/statements/forOfStatement.h"
56 #include "ir/statements/doWhileStatement.h"
57 #include "ir/statements/breakStatement.h"
58 #include "ir/statements/debuggerStatement.h"
59 #include "ir/ets/etsClassLiteral.h"
60 #include "ir/ets/etsPrimitiveType.h"
61 #include "ir/ets/etsPackageDeclaration.h"
62 #include "ir/ets/etsReExportDeclaration.h"
63 #include "ir/ets/etsWildcardType.h"
64 #include "ir/ets/etsNewArrayInstanceExpression.h"
65 #include "ir/ets/etsTuple.h"
66 #include "ir/ets/etsFunctionType.h"
67 #include "ir/ets/etsNewClassInstanceExpression.h"
68 #include "ir/ets/etsNewMultiDimArrayInstanceExpression.h"
69 #include "ir/ets/etsModule.h"
70 #include "ir/ets/etsTypeReference.h"
71 #include "ir/ets/etsTypeReferencePart.h"
72 #include "ir/ets/etsNullishTypes.h"
73 #include "ir/ets/etsUnionType.h"
74 #include "ir/ets/etsImportDeclaration.h"
75 #include "ir/ets/etsStructDeclaration.h"
76 #include "ir/ets/etsParameterExpression.h"
77 #include "ir/module/importNamespaceSpecifier.h"
78 #include "ir/ts/tsAsExpression.h"
79 #include "ir/ts/tsInterfaceDeclaration.h"
80 #include "ir/ts/tsEnumDeclaration.h"
81 #include "ir/ts/tsTypeParameterInstantiation.h"
82 #include "ir/ts/tsInterfaceBody.h"
83 #include "ir/ts/tsImportEqualsDeclaration.h"
84 #include "ir/ts/tsArrayType.h"
85 #include "ir/ts/tsQualifiedName.h"
86 #include "ir/ts/tsTypeReference.h"
87 #include "ir/ts/tsTypeParameter.h"
88 #include "ir/ts/tsInterfaceHeritage.h"
89 #include "ir/ts/tsFunctionType.h"
90 #include "ir/ts/tsClassImplements.h"
91 #include "ir/ts/tsEnumMember.h"
92 #include "ir/ts/tsTypeAliasDeclaration.h"
93 #include "ir/ts/tsTypeParameterDeclaration.h"
94 #include "ir/ts/tsNonNullExpression.h"
95 #include "ir/ts/tsThisType.h"
96 #include "generated/signatures.h"
97 #include "generated/diagnostic.h"
98 
99 namespace ark::es2panda::parser {
100 class FunctionContext;
101 
102 using namespace std::literals::string_literals;
103 
IsClassModifier(lexer::TokenType type)104 static bool IsClassModifier(lexer::TokenType type)
105 {
106     return type == lexer::TokenType::KEYW_STATIC || type == lexer::TokenType::KEYW_ABSTRACT ||
107            type == lexer::TokenType::KEYW_FINAL;
108 }
109 
ParseClassModifiers()110 ir::ModifierFlags ETSParser::ParseClassModifiers()
111 {
112     ir::ModifierFlags flags = ir::ModifierFlags::NONE;
113 
114     while (IsClassModifier(Lexer()->GetToken().KeywordType())) {
115         ir::ModifierFlags currentFlag = ir::ModifierFlags::NONE;
116 
117         lexer::TokenFlags tokenFlags = Lexer()->GetToken().Flags();
118         if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) {
119             LogError(diagnostic::KEYWORD_CONTAINS_ESCAPED_CHARS);  // Lexer will do it.
120         }
121 
122         switch (Lexer()->GetToken().KeywordType()) {
123             case lexer::TokenType::KEYW_STATIC: {
124                 currentFlag = ir::ModifierFlags::STATIC;
125                 break;
126             }
127             case lexer::TokenType::KEYW_FINAL: {
128                 currentFlag = ir::ModifierFlags::FINAL;
129                 break;
130             }
131             case lexer::TokenType::KEYW_ABSTRACT: {
132                 currentFlag = ir::ModifierFlags::ABSTRACT;
133                 break;
134             }
135             default: {
136                 ES2PANDA_UNREACHABLE();
137             }
138         }
139 
140         if ((flags & currentFlag) != 0) {
141             LogError(diagnostic::DUPLICATED_MODIFIER);
142         }
143 
144         Lexer()->NextToken();
145         flags |= currentFlag;
146     }
147 
148     return flags;
149 }
150 
ParseClassImplementsElement()151 std::tuple<ir::Expression *, ir::TSTypeParameterInstantiation *> ETSParser::ParseClassImplementsElement()
152 {
153     TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR |
154                                            TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE |
155                                            TypeAnnotationParsingOptions::ALLOW_WILDCARD;
156     return {ParseTypeReference(&options), nullptr};
157 }
158 
ParseSuperClassReference()159 ir::Expression *ETSParser::ParseSuperClassReference()
160 {
161     if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_EXTENDS) {
162         return nullptr;
163     }
164     Lexer()->NextToken();  // eat "extends"
165     TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR |
166                                            TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE |
167                                            TypeAnnotationParsingOptions::ALLOW_WILDCARD;
168     return ParseTypeReference(&options);
169 }
170 
ParseInterfaceExtendsElement()171 ir::TypeNode *ETSParser::ParseInterfaceExtendsElement()
172 {
173     TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR |
174                                            TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE |
175                                            TypeAnnotationParsingOptions::ALLOW_WILDCARD;
176     return ParseTypeReference(&options);
177 }
178 
IsClassMemberAccessModifier(lexer::TokenType type)179 static bool IsClassMemberAccessModifier(lexer::TokenType type)
180 {
181     return type == lexer::TokenType::KEYW_PUBLIC || type == lexer::TokenType::KEYW_PRIVATE ||
182            type == lexer::TokenType::KEYW_PROTECTED || type == lexer::TokenType::KEYW_INTERNAL;
183 }
184 
ReportAccessModifierError(const lexer::Token & token)185 void ETSParser::ReportAccessModifierError(const lexer::Token &token)
186 {
187     const auto keywordType = token.KeywordType();
188     if (InAmbientContext() && keywordType != lexer::TokenType::KEYW_PUBLIC &&
189         keywordType != lexer::TokenType::KEYW_PROTECTED) {
190         LogError(diagnostic::PROHIBITED_ACCESS_MODIFIER_IN_AMBIENT_CLASS, {token.ToString()}, token.Start());
191     }
192 }
193 
ParseAccessFlagFromToken(const lexer::Token & token)194 static std::tuple<ir::ModifierFlags, bool, bool> ParseAccessFlagFromToken(const lexer::Token &token)
195 {
196     ir::ModifierFlags accessFlag = ir::ModifierFlags::NONE;
197     switch (token.KeywordType()) {
198         case lexer::TokenType::KEYW_PUBLIC: {
199             accessFlag = ir::ModifierFlags::PUBLIC;
200             break;
201         }
202         case lexer::TokenType::KEYW_PRIVATE: {
203             accessFlag = ir::ModifierFlags::PRIVATE;
204             break;
205         }
206         case lexer::TokenType::KEYW_PROTECTED: {
207             accessFlag = ir::ModifierFlags::PROTECTED;
208             break;
209         }
210         case lexer::TokenType::KEYW_INTERNAL: {
211             accessFlag = ir::ModifierFlags::INTERNAL;
212             break;
213         }
214         case lexer::TokenType::EOS: {  // process invalid tokenType
215             return {ir::ModifierFlags::NONE, false, true};
216         }
217         default: {
218             ES2PANDA_UNREACHABLE();
219         }
220     }
221     return {accessFlag, false, false};
222 }
223 
ParseClassMemberAccessModifiers()224 std::tuple<ir::ModifierFlags, bool, bool> ETSParser::ParseClassMemberAccessModifiers()
225 {
226     if (!IsClassMemberAccessModifier(Lexer()->GetToken().Type())) {
227         return {ir::ModifierFlags::PUBLIC, false, true};
228     }
229 
230     char32_t nextCp = Lexer()->Lookahead();
231     if (nextCp == lexer::LEX_CHAR_EQUALS || nextCp == lexer::LEX_CHAR_COLON || nextCp == lexer::LEX_CHAR_LEFT_PAREN) {
232         return {ir::ModifierFlags::NONE, false, false};
233     }
234 
235     lexer::TokenFlags tokenFlags = Lexer()->GetToken().Flags();
236     if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) {
237         LogError(diagnostic::KEYWORD_CONTAINS_ESCAPED_CHARS);  // Lexer will do it.
238     }
239 
240     ir::ModifierFlags accessFlag = ir::ModifierFlags::NONE;
241     bool internalFlag = false;
242     bool earlyReturn = false;
243     const auto token = Lexer()->GetToken();
244 
245     std::tie(accessFlag, internalFlag, earlyReturn) = ParseAccessFlagFromToken(token);
246     if (earlyReturn) {
247         return {accessFlag, internalFlag, earlyReturn};
248     }
249 
250     if (token.KeywordType() == lexer::TokenType::KEYW_INTERNAL) {
251         Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
252         if (Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_PROTECTED) {
253             ReportAccessModifierError(token);
254             return {ir::ModifierFlags::INTERNAL, true, false};
255         }
256         accessFlag = ir::ModifierFlags::INTERNAL_PROTECTED;
257     }
258 
259     ReportAccessModifierError(token);
260 
261     if (((GetContext().Status() & ParserStatus::FUNCTION) != 0) &&
262         (accessFlag == ir::ModifierFlags::PUBLIC || accessFlag == ir::ModifierFlags::PRIVATE ||
263          accessFlag == ir::ModifierFlags::PROTECTED)) {
264         LogError(diagnostic::LOCAL_CLASS_ACCESS_MOD, {}, Lexer()->GetToken().Start());
265     }
266 
267     Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
268     return {accessFlag, true, false};
269 }
270 
IsClassFieldModifier(lexer::TokenType type)271 static bool IsClassFieldModifier(lexer::TokenType type)
272 {
273     return type == lexer::TokenType::KEYW_STATIC || type == lexer::TokenType::KEYW_READONLY;
274 }
275 
ParseClassFieldModifiers(bool seenStatic)276 ir::ModifierFlags ETSParser::ParseClassFieldModifiers(bool seenStatic)
277 {
278     ir::ModifierFlags flags = seenStatic ? ir::ModifierFlags::STATIC : ir::ModifierFlags::NONE;
279 
280     while (IsClassFieldModifier(Lexer()->GetToken().KeywordType())) {
281         char32_t nextCp = Lexer()->Lookahead();
282         if (!(nextCp != lexer::LEX_CHAR_EQUALS && nextCp != lexer::LEX_CHAR_COLON)) {
283             return flags;
284         }
285 
286         ir::ModifierFlags currentFlag;
287 
288         lexer::TokenFlags tokenFlags = Lexer()->GetToken().Flags();
289         if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) {
290             LogError(diagnostic::KEYWORD_CONTAINS_ESCAPED_CHARS);  // Lexer will do it.
291         }
292 
293         switch (Lexer()->GetToken().KeywordType()) {
294             case lexer::TokenType::KEYW_STATIC: {
295                 currentFlag = ir::ModifierFlags::STATIC;
296                 break;
297             }
298             case lexer::TokenType::KEYW_READONLY: {
299                 currentFlag = ir::ModifierFlags::READONLY;
300                 break;
301             }
302             default: {
303                 ES2PANDA_UNREACHABLE();
304             }
305         }
306 
307         if ((flags & currentFlag) != 0) {
308             LogError(diagnostic::DUPLICATED_MODIFIER);
309         }
310 
311         Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
312         flags |= currentFlag;
313     }
314 
315     return flags;
316 }
317 
IsClassMethodModifier(lexer::TokenType type)318 bool ETSParser::IsClassMethodModifier(lexer::TokenType type) noexcept
319 {
320     switch (type) {
321         case lexer::TokenType::KEYW_STATIC:
322         case lexer::TokenType::KEYW_FINAL:
323         case lexer::TokenType::KEYW_NATIVE:
324         case lexer::TokenType::KEYW_ASYNC:
325         case lexer::TokenType::KEYW_OVERRIDE:
326         case lexer::TokenType::KEYW_ABSTRACT: {
327             return true;
328         }
329         default: {
330             break;
331         }
332     }
333 
334     return false;
335 }
336 
HandleAmbientDeclaration(ir::ModifierFlags & memberModifiers,const std::function<ir::AstNode * (ir::Identifier *)> & parseClassMethod)337 ir::AstNode *ETSParser::HandleAmbientDeclaration(ir::ModifierFlags &memberModifiers,
338                                                  const std::function<ir::AstNode *(ir::Identifier *)> &parseClassMethod)
339 {
340     if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
341         // Special case for processing of special '(param: type): returnType` identifier using in ambient context
342         auto ident = CreateInvokeIdentifier();
343         memberModifiers |= ir::ModifierFlags::STATIC;
344         return parseClassMethod(ident);
345     }
346     if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) {
347         const auto startPosAmbient = Lexer()->GetToken().Start();
348         auto const savePos = Lexer()->Save();
349         Lexer()->NextToken();
350         if (Lexer()->GetToken().Ident().Is(compiler::Signatures::SYMBOL)) {
351             Lexer()->Rewind(savePos);
352             auto *memberName = ExpectIdentifier(false, false, TypeAnnotationParsingOptions::NO_OPTS);
353             if (memberName == nullptr) {
354                 LogUnexpectedToken(Lexer()->GetToken());
355                 const auto &rangeToken = Lexer()->GetToken().Loc();
356                 Lexer()->NextToken();
357                 return AllocBrokenStatement(rangeToken);
358             }
359 
360             if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS ||
361                 Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
362                 return parseClassMethod(memberName);
363             }
364         } else {
365             return ParseAmbientSignature(startPosAmbient);
366         }
367     }
368     return nullptr;
369 }
370 
371 // Helper method for ir::ModifierFlags ETSParser::ParseClassMethodModifiers(bool seenStatic)
ParseClassMethodModifierFlag()372 ir::ModifierFlags ETSParser::ParseClassMethodModifierFlag()
373 {
374     ir::ModifierFlags currentFlag = ir::ModifierFlags::NONE;
375 
376     switch (Lexer()->GetToken().KeywordType()) {
377         case lexer::TokenType::KEYW_STATIC: {
378             currentFlag = ir::ModifierFlags::STATIC;
379             break;
380         }
381         case lexer::TokenType::KEYW_FINAL: {
382             currentFlag = ir::ModifierFlags::FINAL;
383             break;
384         }
385         case lexer::TokenType::KEYW_NATIVE: {
386             currentFlag = ir::ModifierFlags::NATIVE;
387             break;
388         }
389         case lexer::TokenType::KEYW_ASYNC: {
390             currentFlag = ir::ModifierFlags::ASYNC;
391             break;
392         }
393         case lexer::TokenType::KEYW_OVERRIDE: {
394             currentFlag = ir::ModifierFlags::OVERRIDE;
395             break;
396         }
397         case lexer::TokenType::KEYW_ABSTRACT: {
398             currentFlag = ir::ModifierFlags::ABSTRACT;
399             break;
400         }
401         case lexer::TokenType::KEYW_DECLARE: {
402             currentFlag = ir::ModifierFlags::DECLARE;
403             break;
404         }
405         default: {
406             ES2PANDA_UNREACHABLE();
407         }
408     }
409 
410     return currentFlag;
411 }
412 
ParseClassMethodModifiers(bool seenStatic)413 ir::ModifierFlags ETSParser::ParseClassMethodModifiers(bool seenStatic)
414 {
415     ir::ModifierFlags flags = seenStatic ? ir::ModifierFlags::STATIC : ir::ModifierFlags::NONE;
416 
417     while (IsClassMethodModifier(Lexer()->GetToken().KeywordType())) {
418         char32_t nextCp = Lexer()->Lookahead();
419         if (!(nextCp != lexer::LEX_CHAR_LEFT_PAREN)) {
420             return flags;
421         }
422 
423         ir::ModifierFlags currentFlag = ir::ModifierFlags::NONE;
424 
425         lexer::TokenFlags tokenFlags = Lexer()->GetToken().Flags();
426         if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) {
427             LogError(diagnostic::KEYWORD_CONTAINS_ESCAPED_CHARS);  // Lexer will do it.
428         }
429 
430         currentFlag = ParseClassMethodModifierFlag();
431         if ((flags & currentFlag) != 0) {
432             LogError(diagnostic::DUPLICATED_MODIFIER);
433         }
434 
435         Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
436         flags |= currentFlag;
437         if ((flags & ir::ModifierFlags::ASYNC) != 0) {
438             if ((flags & ir::ModifierFlags::NATIVE) != 0) {
439                 LogError(diagnostic::NATIVE_METHOD_ASYNC);
440             } else if ((flags & ir::ModifierFlags::ABSTRACT) != 0) {
441                 LogError(diagnostic::ABSTRACT_METHOD_ASYNC);
442             }
443         }
444     }
445 
446     return flags;
447 }
448 
ConvertToOptionalUnionType(ir::TypeNode * typeAnno)449 ir::TypeNode *ETSParser::ConvertToOptionalUnionType(ir::TypeNode *typeAnno)
450 {
451     if (typeAnno == nullptr) {
452         return nullptr;
453     }
454 
455     // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage)
456     if (!typeAnno->IsETSUnionType()) {
457         ArenaVector<ir::TypeNode *> types(Allocator()->Adapter());
458         types.push_back(typeAnno);
459         types.push_back(AllocNode<ir::ETSUndefinedType>(Allocator()));
460         types.back()->SetRange(typeAnno->Range());
461         auto *newTypeAnno = AllocNode<ir::ETSUnionType>(std::move(types), Allocator());
462         ES2PANDA_ASSERT(newTypeAnno != nullptr);
463         newTypeAnno->SetRange(typeAnno->Range());
464         return newTypeAnno;
465     }
466 
467     auto unionTypes = typeAnno->AsETSUnionType()->Types();
468     for (const auto &type : unionTypes) {
469         if (type->IsETSUndefinedType()) {
470             return typeAnno;
471         }
472     }
473 
474     ArenaVector<ir::TypeNode *> types(typeAnno->AsETSUnionType()->Types(), Allocator()->Adapter());
475     types.push_back(AllocNode<ir::ETSUndefinedType>(Allocator()));
476     types.back()->SetRange(typeAnno->Range());
477     auto *newTypeAnno = AllocNode<ir::ETSUnionType>(std::move(types), Allocator());
478     ES2PANDA_ASSERT(newTypeAnno != nullptr);
479     newTypeAnno->SetRange(typeAnno->Range());
480     return newTypeAnno;
481 }
482 
ValidateFieldModifiers(ir::ModifierFlags modifiers,bool optionalField,ir::Expression * initializer,lexer::SourcePosition pos)483 void ETSParser::ValidateFieldModifiers(ir::ModifierFlags modifiers, bool optionalField, ir::Expression *initializer,
484                                        lexer::SourcePosition pos)
485 {
486     const bool isDeclare = (modifiers & ir::ModifierFlags::DECLARE) != 0;
487     const bool isDefinite = (modifiers & ir::ModifierFlags::DEFINITE) != 0;
488     const bool isStatic = (modifiers & ir::ModifierFlags::STATIC) != 0;
489 
490     if (isDeclare && initializer != nullptr) {
491         LogError(diagnostic::INITIALIZERS_IN_AMBIENT_CONTEXTS);
492         return;
493     }
494 
495     if (isDefinite) {
496         if (isStatic) {
497             LogError(diagnostic::STATIC_LATE_INITIALIZATION_FIELD_INVALID_MODIFIER, {}, pos);
498         }
499         if (initializer != nullptr) {
500             LogError(diagnostic::LATE_INITIALIZATION_FIELD_HAS_DEFAULT_VALUE, {}, pos);
501         }
502         if (optionalField) {
503             LogError(diagnostic::CONFLICTING_FIELD_MODIFIERS, {}, pos);
504         }
505     }
506 }
507 
508 // NOLINTNEXTLINE(google-default-arguments)
ParseClassFieldDefinition(ir::Identifier * fieldName,ir::ModifierFlags modifiers,ArenaVector<ir::AstNode * > * declarations,bool isDefault)509 void ETSParser::ParseClassFieldDefinition(ir::Identifier *fieldName, ir::ModifierFlags modifiers,
510                                           ArenaVector<ir::AstNode *> *declarations, bool isDefault)
511 {
512     lexer::SourcePosition endLoc = fieldName->End();
513     ir::TypeNode *typeAnnotation = nullptr;
514     TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
515     bool optionalField = false;
516 
517     auto start = Lexer()->GetToken().Start();
518     if (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK)) {
519         modifiers |= ir::ModifierFlags::DEFINITE;
520     }
521     if (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_QUESTION_MARK)) {
522         optionalField = true;
523     }
524     if (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK)) {
525         modifiers |= ir::ModifierFlags::DEFINITE;
526     }
527     if (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_COLON)) {
528         typeAnnotation = ParseTypeAnnotation(&options);
529         if (typeAnnotation == nullptr) {
530             LogError(diagnostic::ID_EXPECTED);
531             return;
532         }
533 
534         endLoc = typeAnnotation->End();
535     }
536 
537     typeAnnotation = optionalField ? ConvertToOptionalUnionType(typeAnnotation) : typeAnnotation;
538 
539     ir::Expression *initializer = nullptr;
540     if (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_SUBSTITUTION)) {
541         initializer = ParseExpression();
542     } else if (typeAnnotation == nullptr) {
543         typeAnnotation = AllocNode<ir::BrokenTypeNode>(Allocator());
544         typeAnnotation->SetRange({endLoc, endLoc});
545         LogError(diagnostic::FIELD_TPYE_ANNOTATION_MISSING);
546     }
547 
548     ValidateFieldModifiers(modifiers, optionalField, initializer, start);
549 
550     auto *field = AllocNode<ir::ClassProperty>(fieldName, initializer, typeAnnotation, modifiers, Allocator(), false);
551     ES2PANDA_ASSERT(field != nullptr);
552     field->SetDefaultAccessModifier(isDefault);
553     if (optionalField) {
554         field->AddModifier(ir::ModifierFlags::OPTIONAL);
555     }
556     field->SetRange({fieldName->Start(), initializer != nullptr ? initializer->End() : endLoc});
557 
558     declarations->push_back(field);
559 }
560 
ParseClassMethodDefinition(ir::Identifier * methodName,ir::ModifierFlags modifiers,bool isDefault)561 ir::MethodDefinition *ETSParser::ParseClassMethodDefinition(ir::Identifier *methodName, ir::ModifierFlags modifiers,
562                                                             bool isDefault)
563 {
564     auto newStatus = ParserStatus::NEED_RETURN_TYPE | ParserStatus::ALLOW_SUPER;
565     auto methodKind = ir::MethodDefinitionKind::METHOD;
566 
567     if ((modifiers & ir::ModifierFlags::CONSTRUCTOR) != 0) {
568         newStatus = ParserStatus::CONSTRUCTOR_FUNCTION | ParserStatus::ALLOW_SUPER | ParserStatus::ALLOW_SUPER_CALL;
569         methodKind = ir::MethodDefinitionKind::CONSTRUCTOR;
570     }
571 
572     if ((modifiers & ir::ModifierFlags::ASYNC) != 0) {
573         newStatus |= ParserStatus::ASYNC_FUNCTION;
574     }
575 
576     if ((modifiers & ir::ModifierFlags::STATIC) == 0) {
577         newStatus |= ParserStatus::ALLOW_THIS_TYPE;
578     }
579 
580     ir::ScriptFunction *func = ParseFunction(newStatus);
581     ES2PANDA_ASSERT(func != nullptr);
582     func->SetIdent(methodName);
583     auto *funcExpr = AllocNode<ir::FunctionExpression>(func);
584     ES2PANDA_ASSERT(funcExpr != nullptr);
585     funcExpr->SetRange(func->Range());
586     func->AddModifier(modifiers);
587 
588     ES2PANDA_ASSERT(methodName->Clone(Allocator(), nullptr) != nullptr);
589     auto *method = AllocNode<ir::MethodDefinition>(methodKind, methodName->Clone(Allocator(), nullptr)->AsExpression(),
590                                                    funcExpr, modifiers, Allocator(), false);
591     ES2PANDA_ASSERT(method != nullptr);
592     method->SetDefaultAccessModifier(isDefault);
593     method->SetRange(funcExpr->Range());
594     return method;
595 }
596 
ParseClassMethod(ClassElementDescriptor * desc,const ArenaVector<ir::AstNode * > & properties,ir::Expression * propName,lexer::SourcePosition * propEnd)597 ir::MethodDefinition *ETSParser::ParseClassMethod(ClassElementDescriptor *desc,
598                                                   const ArenaVector<ir::AstNode *> &properties,
599                                                   ir::Expression *propName, lexer::SourcePosition *propEnd)
600 {
601     if (desc->methodKind != ir::MethodDefinitionKind::SET &&
602         (desc->newStatus & ParserStatus::CONSTRUCTOR_FUNCTION) == 0) {
603         desc->newStatus |= ParserStatus::NEED_RETURN_TYPE;
604     }
605 
606     ir::ScriptFunction *func = ParseFunction(desc->newStatus);
607     ES2PANDA_ASSERT(func != nullptr);
608     if (propName->IsIdentifier()) {
609         func->SetIdent(propName->AsIdentifier()->Clone(Allocator(), nullptr));
610     }
611 
612     auto *funcExpr = AllocNode<ir::FunctionExpression>(func);
613     ES2PANDA_ASSERT(funcExpr != nullptr);
614     funcExpr->SetRange(func->Range());
615 
616     if (desc->methodKind == ir::MethodDefinitionKind::SET) {
617         ValidateClassSetter(desc, properties, propName, func);
618     } else if (desc->methodKind == ir::MethodDefinitionKind::GET) {
619         ValidateClassGetter(desc, properties, propName, func);
620     }
621 
622     *propEnd = func->End();
623     func->AddFlag(ir::ScriptFunctionFlags::METHOD);
624     auto *method =
625         AllocNode<ir::MethodDefinition>(desc->methodKind, propName->Clone(Allocator(), nullptr)->AsExpression(),
626                                         funcExpr, desc->modifiers, Allocator(), desc->isComputed);
627     ES2PANDA_ASSERT(method != nullptr);
628     method->SetRange(funcExpr->Range());
629 
630     return method;
631 }
632 
UpdateMemberModifiers(ir::ModifierFlags & memberModifiers,bool & seenStatic)633 void ETSParser::UpdateMemberModifiers(ir::ModifierFlags &memberModifiers, bool &seenStatic)
634 {
635     if (InAmbientContext()) {
636         memberModifiers |= ir::ModifierFlags::DECLARE;
637     }
638 
639     char32_t nextCp = Lexer()->Lookahead();
640     if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STATIC && nextCp != lexer::LEX_CHAR_EQUALS &&
641         nextCp != lexer::LEX_CHAR_COLON && nextCp != lexer::LEX_CHAR_LEFT_PAREN &&
642         nextCp != lexer::LEX_CHAR_LESS_THAN) {
643         Lexer()->NextToken();
644         memberModifiers |= ir::ModifierFlags::STATIC;
645         seenStatic = true;
646     } else {
647         seenStatic = false;
648     }
649 
650     if (IsClassFieldModifier(Lexer()->GetToken().KeywordType())) {
651         memberModifiers |= ParseClassFieldModifiers(seenStatic);
652     } else if (IsClassMethodModifier(Lexer()->GetToken().Type())) {
653         memberModifiers |= ParseClassMethodModifiers(seenStatic);
654     }
655 }
656 
HandleClassElementModifiers(ir::ModifierFlags & memberModifiers)657 std::tuple<bool, bool, bool> ETSParser::HandleClassElementModifiers(ir::ModifierFlags &memberModifiers)
658 {
659     auto [modifierFlags, isStepToken, isDefault] = ParseClassMemberAccessModifiers();
660     memberModifiers |= modifierFlags;
661 
662     bool seenStatic = false;
663     UpdateMemberModifiers(memberModifiers, seenStatic);
664 
665     return {seenStatic, isStepToken, isDefault};
666 }
667 
ParseClassElementHelper(const ArenaVector<ir::AstNode * > & properties,std::tuple<ir::ClassDefinitionModifiers,ir::ModifierFlags,ir::ModifierFlags> modifierInfo,std::tuple<bool,bool,bool> elementFlag,std::tuple<lexer::SourcePosition,lexer::LexerPosition> posInfo)668 ir::AstNode *ETSParser::ParseClassElementHelper(
669     const ArenaVector<ir::AstNode *> &properties,
670     std::tuple<ir::ClassDefinitionModifiers, ir::ModifierFlags, ir::ModifierFlags> modifierInfo,
671     std::tuple<bool, bool, bool> elementFlag, std::tuple<lexer::SourcePosition, lexer::LexerPosition> posInfo)
672 {
673     auto [seenStatic, isStepToken, isDefault] = elementFlag;
674     auto [startLoc, savedPos] = posInfo;
675     auto [modifiers, memberModifiers, flags] = modifierInfo;
676     auto delcStartLoc = Lexer()->GetToken().Start();
677     ir::AstNode *result = nullptr;
678     switch (Lexer()->GetToken().Type()) {
679         case lexer::TokenType::KEYW_INTERFACE:
680         case lexer::TokenType::KEYW_CLASS:
681         case lexer::TokenType::KEYW_ENUM:
682             result = ParseInnerTypeDeclaration(memberModifiers, savedPos, isStepToken, seenStatic);
683             break;
684         case lexer::TokenType::LITERAL_IDENT: {
685             if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STRUCT) {
686                 result = ParseInnerTypeDeclaration(memberModifiers, savedPos, isStepToken, seenStatic);
687             } else if (IsNamespaceDecl()) {
688                 result = ParseNamespace(flags);
689             } else {
690                 result = ParseInnerRest(properties, modifiers, memberModifiers, startLoc, isDefault);
691             }
692             break;
693         }
694         case lexer::TokenType::KEYW_CONSTRUCTOR:
695             result = ParseInnerConstructorDeclaration(memberModifiers, startLoc, isDefault);
696             break;
697         case lexer::TokenType::KEYW_PUBLIC:
698         case lexer::TokenType::KEYW_PRIVATE:
699         case lexer::TokenType::KEYW_PROTECTED: {
700             LogError(diagnostic::ACCESS_BEFORE_FIELD_METHOD);
701             Lexer()->NextToken();
702             return AllocBrokenStatement(delcStartLoc);
703         }
704         default: {
705             result = ParseInnerRest(properties, modifiers, memberModifiers, startLoc, isDefault);
706         }
707     }
708     return result;
709 }
710 
ParseClassElement(const ArenaVector<ir::AstNode * > & properties,ir::ClassDefinitionModifiers modifiers,ir::ModifierFlags flags)711 ir::AstNode *ETSParser::ParseClassElement(const ArenaVector<ir::AstNode *> &properties,
712                                           ir::ClassDefinitionModifiers modifiers,
713                                           [[maybe_unused]] ir::ModifierFlags flags)
714 {
715     ArenaVector<ir::JsDocInfo> jsDocInformation(Allocator()->Adapter());
716     if (Lexer()->TryEatTokenType(lexer::TokenType::JS_DOC_START)) {
717         jsDocInformation = ParseJsDocInfos();
718         if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE ||
719             Lexer()->GetToken().Type() == lexer::TokenType::EOS) {
720             return nullptr;
721         }
722     }
723 
724     auto startLoc = Lexer()->GetToken().Start();
725 
726     ArenaVector<ir::AnnotationUsage *> annotations(Allocator()->Adapter());
727     if (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_AT)) {
728         annotations = ParseAnnotations(false);
729     }
730 
731     ir::ModifierFlags memberModifiers = ir::ModifierFlags::NONE;
732     auto savedPos = Lexer()->Save();  // NOLINT(clang-analyzer-deadcode.DeadStores)
733 
734     if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STATIC &&
735         Lexer()->Lookahead() == lexer::LEX_CHAR_LEFT_BRACE) {
736         return ParseClassStaticBlock();
737     }
738 
739     auto [seenStatic, isStepToken, isDefault] = HandleClassElementModifiers(memberModifiers);
740     auto delcStartLoc = Lexer()->GetToken().Start();
741     ir::AstNode *result = ParseClassElementHelper(properties, std::make_tuple(modifiers, memberModifiers, flags),
742                                                   std::make_tuple(seenStatic, isStepToken, isDefault),
743                                                   std::make_tuple(startLoc, savedPos));
744     ApplyJsDocInfoToClassElement(result, std::move(jsDocInformation));
745     ApplyAnnotationsToClassElement(result, std::move(annotations), delcStartLoc);
746     return result;
747 }
748 
ApplyAnnotationsToClassElement(ir::AstNode * property,ArenaVector<ir::AnnotationUsage * > && annotations,lexer::SourcePosition pos)749 void *ETSParser::ApplyAnnotationsToClassElement(ir::AstNode *property, ArenaVector<ir::AnnotationUsage *> &&annotations,
750                                                 lexer::SourcePosition pos)
751 {
752     if (property == nullptr) {
753         return nullptr;
754     }
755 
756     if (annotations.empty()) {
757         return property;
758     }
759 
760     if (property->IsTSInterfaceBody()) {
761         for (auto *node : property->AsTSInterfaceBody()->Body()) {
762             ArenaVector<ir::AnnotationUsage *> cloneAnnotations(Allocator()->Adapter());
763             for (auto *annotationUsage : annotations) {
764                 auto cloneAnnotationUsage = annotationUsage->Clone(Allocator(), node);
765                 ES2PANDA_ASSERT(cloneAnnotationUsage != nullptr);
766                 cloneAnnotations.push_back(cloneAnnotationUsage->AsAnnotationUsage());
767             }
768             ApplyAnnotationsToNode(node, std::move(cloneAnnotations), pos);
769         }
770     } else {
771         ApplyAnnotationsToNode(property, std::move(annotations), pos);
772     }
773 
774     return property;
775 }
776 
CloneJsDocInfo(ArenaAllocator * const allocator,const ir::JsDocInfo & src)777 static ir::JsDocInfo CloneJsDocInfo(ArenaAllocator *const allocator, const ir::JsDocInfo &src)
778 {
779     ir::JsDocInfo res(allocator->Adapter());
780     for (const auto &entry : src) {
781         const util::StringView &key = entry.first;
782         const ir::JsDocRecord &record = entry.second;
783 
784         util::UString copiedKey {key, allocator};
785         util::UString copiedParam {record.param, allocator};
786         util::UString copiedComment {record.comment, allocator};
787         res.emplace(copiedKey.View(), ir::JsDocRecord(copiedKey.View(), copiedParam.View(), copiedComment.View()));
788     }
789     return res;
790 }
791 
ApplyJsDocInfoToClassElement(ir::AstNode * property,ArenaVector<ir::JsDocInfo> && jsDocInformation)792 void ETSParser::ApplyJsDocInfoToClassElement(ir::AstNode *property, ArenaVector<ir::JsDocInfo> &&jsDocInformation)
793 {
794     if (property == nullptr || jsDocInformation.empty()) {
795         return;
796     }
797 
798     if (!property->IsTSInterfaceBody()) {
799         ApplyJsDocInfoToSpecificNodeType(property, std::move(jsDocInformation));
800         return;
801     }
802 
803     for (auto *node : property->AsTSInterfaceBody()->Body()) {
804         ArenaVector<ir::JsDocInfo> clonedJsDocInformation(Allocator()->Adapter());
805         for (auto const &jsdocInfo : jsDocInformation) {
806             clonedJsDocInformation.emplace_back(CloneJsDocInfo(Allocator(), jsdocInfo));
807         }
808         ApplyJsDocInfoToSpecificNodeType(node, std::move(clonedJsDocInformation));
809     }
810 }
811 
ParseClassGetterSetterMethod(const ArenaVector<ir::AstNode * > & properties,const ir::ClassDefinitionModifiers modifiers,const ir::ModifierFlags memberModifiers,bool isDefault)812 ir::MethodDefinition *ETSParser::ParseClassGetterSetterMethod(const ArenaVector<ir::AstNode *> &properties,
813                                                               const ir::ClassDefinitionModifiers modifiers,
814                                                               const ir::ModifierFlags memberModifiers, bool isDefault)
815 {
816     ClassElementDescriptor desc(Allocator());
817     desc.methodKind = Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_GET ? ir::MethodDefinitionKind::GET
818                                                                                       : ir::MethodDefinitionKind::SET;
819     desc.propStart = Lexer()->GetToken().Start();
820     Lexer()->NextToken();  // eat get/set
821     auto *methodName = ExpectIdentifier();
822     ES2PANDA_ASSERT(methodName != nullptr);
823     if (desc.methodKind == ir::MethodDefinitionKind::GET) {
824         methodName->SetAccessor();
825     } else {
826         methodName->SetMutator();
827     }
828 
829     desc.newStatus = ParserStatus::ALLOW_SUPER;
830     desc.hasSuperClass = (modifiers & ir::ClassDefinitionModifiers::HAS_SUPER) != 0U;
831     desc.modifiers = memberModifiers;
832 
833     lexer::SourcePosition propEnd = methodName->End();
834     ir::MethodDefinition *method = ParseClassMethod(&desc, properties, methodName, &propEnd);
835     ES2PANDA_ASSERT(method != nullptr);
836     method->SetDefaultAccessModifier(isDefault);
837     auto *func = method->Function();
838     ES2PANDA_ASSERT(func != nullptr);
839     func->AddModifier(desc.modifiers);
840     method->SetRange({desc.propStart, propEnd});
841     if (desc.methodKind == ir::MethodDefinitionKind::GET) {
842         func->AddFlag(ir::ScriptFunctionFlags::GETTER);
843     } else {
844         func->AddFlag(ir::ScriptFunctionFlags::SETTER);
845     }
846 
847     return method;
848 }
849 
ParseInterfaceGetterSetterMethod(const ir::ModifierFlags modifiers)850 ir::MethodDefinition *ETSParser::ParseInterfaceGetterSetterMethod(const ir::ModifierFlags modifiers)
851 {
852     auto methodKind = Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_GET ? ir::MethodDefinitionKind::GET
853                                                                                       : ir::MethodDefinitionKind::SET;
854     Lexer()->NextToken();  // eat get/set
855     ExpectToken(lexer::TokenType::LITERAL_IDENT, false);
856     ir::MethodDefinition *method = ParseInterfaceMethod(modifiers, methodKind);
857     if (method == nullptr) {
858         return nullptr;
859     }
860     method->AddModifier(ir::ModifierFlags::PUBLIC);
861     auto *id = method->Id();
862     auto *func = method->Function();
863     ES2PANDA_ASSERT(id != nullptr);
864     ES2PANDA_ASSERT(func != nullptr);
865     method->SetRange({Lexer()->GetToken().Start(), method->Id()->End()});
866     if (methodKind == ir::MethodDefinitionKind::GET) {
867         id->SetAccessor();
868         func->AddFlag(ir::ScriptFunctionFlags::GETTER);
869     } else {
870         id->SetMutator();
871         func->AddFlag(ir::ScriptFunctionFlags::SETTER);
872     }
873     method->AddModifier(ir::ModifierFlags::PUBLIC);
874 
875     func->SetIdent(id->Clone(Allocator(), nullptr));
876     func->AddModifier(method->Modifiers());
877 
878     bool hasReturn = func->ReturnTypeAnnotation() != nullptr;
879     if (hasReturn && methodKind == ir::MethodDefinitionKind::SET) {
880         LogError(diagnostic::SETTER_NO_RETURN_TYPE, {}, func->Range().start);
881     }
882 
883     return method;
884 }
885 
ParseInterfaceBody(ir::Identifier * name,bool isStatic)886 ir::TSInterfaceDeclaration *ETSParser::ParseInterfaceBody(ir::Identifier *name, bool isStatic)
887 {
888     GetContext().Status() |= ParserStatus::ALLOW_THIS_TYPE;
889 
890     ir::TSTypeParameterDeclaration *typeParamDecl = nullptr;
891     if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
892         auto options =
893             TypeAnnotationParsingOptions::REPORT_ERROR | TypeAnnotationParsingOptions::ALLOW_DECLARATION_SITE_VARIANCE;
894         typeParamDecl = ParseTypeParameterDeclaration(&options);
895     }
896 
897     ArenaVector<ir::TSInterfaceHeritage *> extends(Allocator()->Adapter());
898     if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS) {
899         extends = ParseInterfaceExtendsClause();
900     }
901 
902     lexer::SourcePosition bodyStart = Lexer()->GetToken().Start();
903     auto members = ParseTypeLiteralOrInterface();
904 
905     for (auto &member : members) {
906         if (member->Type() == ir::AstNodeType::CLASS_DECLARATION ||
907             member->Type() == ir::AstNodeType::STRUCT_DECLARATION ||
908             member->Type() == ir::AstNodeType::TS_ENUM_DECLARATION ||
909             member->Type() == ir::AstNodeType::TS_INTERFACE_DECLARATION) {
910             LogError(diagnostic::IMPROPER_NESTING_INTERFACE);
911         }
912     }
913 
914     auto *body = AllocNode<ir::TSInterfaceBody>(std::move(members));
915     ES2PANDA_ASSERT(body != nullptr);
916     body->SetRange({bodyStart, Lexer()->GetToken().End()});
917 
918     const auto isExternal = IsExternal();
919     auto *interfaceDecl = AllocNode<ir::TSInterfaceDeclaration>(
920         Allocator(), std::move(extends),
921         ir::TSInterfaceDeclaration::ConstructorData {name, typeParamDecl, body, isStatic, isExternal,
922                                                      GetContext().GetLanguage()});
923 
924     Lexer()->NextToken();
925     GetContext().Status() &= ~ParserStatus::ALLOW_THIS_TYPE;
926 
927     return interfaceDecl;
928 }
929 
ParseInterfaceDeclaration(bool isStatic)930 ir::Statement *ETSParser::ParseInterfaceDeclaration(bool isStatic)
931 {
932     lexer::SourcePosition interfaceStart = Lexer()->GetToken().Start();
933     Lexer()->NextToken();  // eat interface keyword
934 
935     auto *id = ExpectIdentifier(false, true);
936 
937     auto *declNode = ParseInterfaceBody(id, isStatic);
938     ES2PANDA_ASSERT(declNode != nullptr);
939 
940     declNode->SetRange({interfaceStart, Lexer()->GetToken().End()});
941     return declNode;
942 }
943 
944 // NOLINTNEXTLINE(google-default-arguments)
ParseClassDefinition(ir::ClassDefinitionModifiers modifiers,ir::ModifierFlags flags)945 ir::ClassDefinition *ETSParser::ParseClassDefinition(ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags flags)
946 {
947     Lexer()->NextToken();
948 
949     ir::Identifier *identNode = ParseClassIdent(modifiers);
950     ir::TSTypeParameterDeclaration *typeParamDecl = nullptr;
951     if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
952         auto options =
953             TypeAnnotationParsingOptions::REPORT_ERROR | TypeAnnotationParsingOptions::ALLOW_DECLARATION_SITE_VARIANCE;
954         typeParamDecl = ParseTypeParameterDeclaration(&options);
955     }
956 
957     // Parse SuperClass
958     auto [superClass, superTypeParams] = ParseSuperClass();
959 
960     if (superClass != nullptr) {
961         modifiers |= ir::ClassDefinitionModifiers::HAS_SUPER;
962         GetContext().Status() |= ParserStatus::ALLOW_SUPER;
963     }
964 
965     if (InAmbientContext()) {
966         flags |= ir::ModifierFlags::DECLARE;
967     }
968 
969     // Parse implements clause
970     ArenaVector<ir::TSClassImplements *> implements(Allocator()->Adapter());
971     if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_IMPLEMENTS) {
972         Lexer()->NextToken();
973         implements = ParseClassImplementClause();
974     }
975 
976     ArenaVector<ir::AstNode *> properties(Allocator()->Adapter());
977     ir::MethodDefinition *ctor = nullptr;
978     lexer::SourceRange bodyRange;
979 
980     if ((flags & ir::ModifierFlags::DECLARE) != 0U &&
981         Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
982         // without ClassBody
983         bodyRange = lexer::SourceRange {Lexer()->GetToken().Start(), Lexer()->GetToken().Start()};
984         LogError(diagnostic::AMBIENT_CLASS_MISSING_BODY);
985     } else {
986         ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE, false);
987 
988         // Parse ClassBody
989         std::tie(ctor, properties, bodyRange) = ParseClassBody(modifiers, flags);
990     }
991 
992     auto *classDefinition =
993         AllocNode<ir::ClassDefinition>(identNode, typeParamDecl, superTypeParams, std::move(implements), ctor,
994                                        superClass, std::move(properties), modifiers, flags, GetContext().GetLanguage());
995     ES2PANDA_ASSERT(classDefinition != nullptr);
996 
997     classDefinition->SetRange(bodyRange);
998 
999     GetContext().Status() &= ~ParserStatus::ALLOW_SUPER;
1000 
1001     return classDefinition;
1002 }
1003 
ParseInterfaceMethodModifiers()1004 ir::ModifierFlags ETSParser::ParseInterfaceMethodModifiers()
1005 {
1006     if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT ||
1007         Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET ||
1008         Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
1009         return ir::ModifierFlags::PUBLIC;
1010     }
1011 
1012     if ((GetContext().Status() & ParserStatus::FUNCTION) != 0) {
1013         if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_PRIVATE) {
1014             LogError(diagnostic::LOCAL_CLASS_ACCESS_MOD, {}, Lexer()->GetToken().Start());
1015         }
1016     }
1017     if (Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_PRIVATE) {
1018         LogError(diagnostic::UNEXPECTED_TOKEN_PRIVATE_ID);
1019     }
1020 
1021     Lexer()->NextToken();
1022     return ir::ModifierFlags::PRIVATE;
1023 }
1024 
ParseInterfaceTypeAnnotation(ir::Identifier * name)1025 ir::TypeNode *ETSParser::ParseInterfaceTypeAnnotation(ir::Identifier *name)
1026 {
1027     if (!Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_COLON) &&
1028         Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT &&
1029         Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) {
1030         LogError(diagnostic::INTERFACE_FIELDS_TYPE_ANNOTATION);
1031         Lexer()->GetToken().SetTokenType(lexer::TokenType::PUNCTUATOR_COLON);
1032         Lexer()->NextToken();
1033     }
1034 
1035     TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
1036     auto *type = ParseTypeAnnotation(&options);
1037     name->SetTsTypeAnnotation(type);
1038     type->SetParent(name);
1039     return type;
1040 }
1041 
ParseInterfaceModifiers(ir::ModifierFlags & fieldModifiers,bool & optionalField)1042 void ETSParser::ParseInterfaceModifiers(ir::ModifierFlags &fieldModifiers, bool &optionalField)
1043 {
1044     auto processDefinite = [this, &fieldModifiers]() {
1045         if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK) {
1046             Lexer()->NextToken();
1047             fieldModifiers |= ir::ModifierFlags::DEFINITE;
1048             return true;
1049         }
1050         return false;
1051     };
1052     auto start = Lexer()->GetToken().Start();
1053     processDefinite();
1054 
1055     if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) {
1056         Lexer()->NextToken();
1057         optionalField = true;
1058     }
1059 
1060     processDefinite();
1061 
1062     if ((fieldModifiers & ir::ModifierFlags::DEFINITE) != 0 && optionalField) {
1063         LogError(diagnostic::CONFLICTING_FIELD_MODIFIERS, {}, start);
1064     }
1065 }
1066 
ParseInterfaceField()1067 ir::AstNode *ETSParser::ParseInterfaceField()
1068 {
1069     ES2PANDA_ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT ||
1070                     Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET ||
1071                     Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS);
1072     ir::ModifierFlags fieldModifiers = ir::ModifierFlags::PUBLIC;
1073     auto startLoc = Lexer()->GetToken().Start();
1074 
1075     auto *name = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
1076 
1077     if (name->IsErrorPlaceHolder()) {
1078         Lexer()->NextToken();
1079         return AllocBrokenExpression(Lexer()->GetToken().Loc());
1080     }
1081 
1082     auto parseClassMethod = [&fieldModifiers, &startLoc, this](ir::Identifier *methodName) {
1083         auto *classMethod = ParseClassMethodDefinition(methodName, fieldModifiers, false);
1084         ES2PANDA_ASSERT(classMethod != nullptr);
1085         classMethod->SetStart(startLoc);
1086         return classMethod;
1087     };
1088     if (InAmbientContext()) {
1089         fieldModifiers |= ir::ModifierFlags::DECLARE;
1090         auto property = HandleAmbientDeclaration(fieldModifiers, parseClassMethod);
1091         if (property != nullptr) {
1092             return property;
1093         }
1094     }
1095 
1096     ES2PANDA_ASSERT(name != nullptr);
1097     name->SetRange(Lexer()->GetToken().Loc());
1098     Lexer()->NextToken();
1099     bool optionalField = false;
1100 
1101     ParseInterfaceModifiers(fieldModifiers, optionalField);
1102     auto *typeAnnotation = ParseInterfaceTypeAnnotation(name);
1103     if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_EQUAL &&
1104         Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
1105         LogError(diagnostic::INITIALIZERS_INTERFACE_PROPS);
1106         Lexer()->NextToken();  // Error processing: eat '='.
1107     }
1108     auto *field = AllocNode<ir::ClassProperty>(name, nullptr, typeAnnotation->Clone(Allocator(), nullptr),
1109                                                fieldModifiers, Allocator(), false);
1110     ES2PANDA_ASSERT(field != nullptr);
1111     if (optionalField) {
1112         field->AddModifier(ir::ModifierFlags::OPTIONAL);
1113     }
1114     field->SetEnd(Lexer()->GetToken().End());
1115 
1116     return field;
1117 }
1118 
GetEndLoc(ir::BlockStatement * body,ir::ScriptFunction * func,lexer::Lexer * lexer)1119 static lexer::SourcePosition GetEndLoc(ir::BlockStatement *body, ir::ScriptFunction *func, lexer::Lexer *lexer)
1120 {
1121     if (body != nullptr) {
1122         return body->End();
1123     }
1124 
1125     if (func->ReturnTypeAnnotation() != nullptr) {
1126         return func->ReturnTypeAnnotation()->End();
1127     }
1128 
1129     if (!func->Params().empty()) {
1130         return func->Params().back()->End();
1131     }
1132 
1133     return lexer->GetToken().End();
1134 }
1135 
1136 // CC-OFFNXT(huge_method[C++], G.FUN.01-CPP) solid logic
ParseInterfaceMethod(ir::ModifierFlags flags,ir::MethodDefinitionKind methodKind)1137 ir::MethodDefinition *ETSParser::ParseInterfaceMethod(ir::ModifierFlags flags, ir::MethodDefinitionKind methodKind)
1138 {
1139     ir::Identifier *name = nullptr;
1140     if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
1141         LogError(diagnostic::EXPECTED_PARAM_GOT_PARAM,
1142                  {"method name", lexer::TokenToString(Lexer()->GetToken().Type())});
1143         name = AllocBrokenExpression(Lexer()->GetToken().Loc());
1144     } else {
1145         name = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
1146         ES2PANDA_ASSERT(name != nullptr);
1147         name->SetRange(Lexer()->GetToken().Loc());
1148         Lexer()->NextToken();
1149     }
1150     FunctionContext functionContext(this, ParserStatus::FUNCTION);
1151 
1152     lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
1153 
1154     auto [signature, throwMarker] = ParseFunctionSignature(ParserStatus::NEED_RETURN_TYPE);
1155 
1156     ir::BlockStatement *body = nullptr;
1157 
1158     bool isDeclare = InAmbientContext();
1159     if (isDeclare) {
1160         flags |= ir::ModifierFlags::DECLARE;
1161     }
1162 
1163     if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
1164         if (methodKind == ir::MethodDefinitionKind::SET || methodKind == ir::MethodDefinitionKind::GET) {
1165             LogError(diagnostic::GETTER_SETTER_NOT_ABSTRACT, {}, startLoc);
1166         }
1167         body = ParseBlockStatement();
1168     } else if ((flags & (ir::ModifierFlags::PRIVATE)) != 0 && !isDeclare) {
1169         LogError(diagnostic::PRIVATE_INTERFACE_MISSING_BODY, {}, startLoc);
1170     }
1171 
1172     functionContext.AddFlag(throwMarker);
1173 
1174     if ((GetContext().Status() & ParserStatus::FUNCTION_HAS_RETURN_STATEMENT) != 0) {
1175         functionContext.AddFlag(ir::ScriptFunctionFlags::HAS_RETURN);
1176         GetContext().Status() ^= ParserStatus::FUNCTION_HAS_RETURN_STATEMENT;
1177     }
1178 
1179     auto *func = AllocNode<ir::ScriptFunction>(
1180         Allocator(), ir::ScriptFunction::ScriptFunctionData {body, std::move(signature), functionContext.Flags(), flags,
1181                                                              GetContext().GetLanguage()});
1182     ES2PANDA_ASSERT(func != nullptr);
1183     if ((flags & ir::ModifierFlags::STATIC) == 0 && body == nullptr) {
1184         func->AddModifier(ir::ModifierFlags::ABSTRACT);
1185     }
1186     ValidateGetterSetter(methodKind, func->Params().size());
1187     func->SetRange({startLoc, GetEndLoc(body, func, Lexer())});
1188 
1189     auto *funcExpr = AllocNode<ir::FunctionExpression>(func);
1190     ES2PANDA_ASSERT(funcExpr != nullptr);
1191     funcExpr->SetRange(func->Range());
1192     func->AddFlag(ir::ScriptFunctionFlags::METHOD);
1193 
1194     func->SetIdent(name);
1195     ES2PANDA_ASSERT(name->Clone(Allocator(), nullptr) != nullptr);
1196     auto *method = AllocNode<ir::MethodDefinition>(methodKind, name->Clone(Allocator(), nullptr)->AsExpression(),
1197                                                    funcExpr, flags, Allocator(), false);
1198     ES2PANDA_ASSERT(method != nullptr);
1199     method->SetRange(funcExpr->Range());
1200 
1201     ConsumeSemicolon(method);
1202 
1203     return method;
1204 }
1205 
ParseJsDocInfoInInterfaceBody()1206 ir::AstNode *ETSParser::ParseJsDocInfoInInterfaceBody()
1207 {
1208     Lexer()->NextToken();  // eat '/**'
1209 
1210     auto jsDocInformation = ParseJsDocInfos();
1211     if (Lexer()->GetToken().Type() == lexer::TokenType::EOS ||
1212         Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) {
1213         return nullptr;
1214     }
1215 
1216     ir::AstNode *result = ParseTypeLiteralOrInterfaceMember();
1217     if (result != nullptr) {
1218         ApplyJsDocInfoToSpecificNodeType(result, std::move(jsDocInformation));
1219     }
1220     return result;
1221 }
1222 
ParseAnnotationsInInterfaceBody()1223 ir::AstNode *ETSParser::ParseAnnotationsInInterfaceBody()
1224 {
1225     Lexer()->NextToken();  // eat '@'
1226 
1227     auto annotations = ParseAnnotations(false);
1228     auto savePos = Lexer()->GetToken().Start();
1229     ir::AstNode *result = ParseTypeLiteralOrInterfaceMember();
1230     if (result != nullptr) {
1231         ApplyAnnotationsToNode(result, std::move(annotations), savePos);
1232     }
1233     return result;
1234 }
1235 
IsFieldStartToken(lexer::TokenType tokenType)1236 bool ETSParser::IsFieldStartToken(lexer::TokenType tokenType)
1237 {
1238     return tokenType == lexer::TokenType::LITERAL_IDENT ||
1239            tokenType == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET ||
1240            tokenType == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS;
1241 }
1242 
ParseTypeLiteralOrInterfaceMember()1243 ir::AstNode *ETSParser::ParseTypeLiteralOrInterfaceMember()
1244 {
1245     if (Lexer()->GetToken().Type() == lexer::TokenType::JS_DOC_START) {
1246         return ParseJsDocInfoInInterfaceBody();
1247     }
1248 
1249     if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_AT) {
1250         return ParseAnnotationsInInterfaceBody();
1251     }
1252 
1253     if (Lexer()->Lookahead() != lexer::LEX_CHAR_LEFT_PAREN && Lexer()->Lookahead() != lexer::LEX_CHAR_LESS_THAN &&
1254         (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_GET ||
1255          Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_SET)) {
1256         return ParseInterfaceGetterSetterMethod(ir::ModifierFlags::PUBLIC);
1257     }
1258 
1259     ir::ModifierFlags modifiers = ParseInterfaceMethodModifiers();
1260     char32_t nextCp = Lexer()->Lookahead();
1261     auto startLoc = Lexer()->GetToken().Start();
1262     auto readonlyTok = Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_READONLY);
1263     bool isReadonly = readonlyTok.has_value();
1264 
1265     if (nextCp == lexer::LEX_CHAR_LEFT_PAREN || nextCp == lexer::LEX_CHAR_LESS_THAN) {
1266         if (isReadonly) {
1267             LogError(diagnostic::READONLY_INTERFACE_METHOD, {}, startLoc);
1268         }
1269         auto *method = ParseInterfaceMethod(modifiers, ir::MethodDefinitionKind::METHOD);
1270         ES2PANDA_ASSERT(method != nullptr);
1271         method->SetStart(startLoc);
1272         return method;
1273     }
1274 
1275     auto tok = Lexer()->GetToken().Type();
1276     if (!IsFieldStartToken(tok)) {
1277         LogError(diagnostic::ID_EXPECTED, {}, startLoc);
1278         return AllocBrokenExpression(Lexer()->GetToken().Loc());
1279     }
1280 
1281     auto *field = ParseInterfaceField();
1282     if (field != nullptr) {
1283         field->SetStart(startLoc);
1284         if (isReadonly) {
1285             field->AddModifier(ir::ModifierFlags::READONLY);
1286         }
1287         return field;
1288     }
1289 
1290     return ParseTypeDeclaration(true);
1291 }
1292 
CheckClassElement(ir::AstNode * property,ir::MethodDefinition * & ctor,ArenaVector<ir::AstNode * > & properties)1293 bool ETSParser::CheckClassElement(ir::AstNode *property, [[maybe_unused]] ir::MethodDefinition *&ctor,
1294                                   [[maybe_unused]] ArenaVector<ir::AstNode *> &properties)
1295 {
1296     if (property->IsClassStaticBlock()) {
1297         if (std::any_of(properties.cbegin(), properties.cend(),
1298                         [](const auto *prop) { return prop->IsClassStaticBlock(); })) {
1299             LogError(diagnostic::MULTIPLE_STATIC_BLOCK, {}, property->Start());
1300         }
1301 
1302         auto *id = AllocNode<ir::Identifier>(compiler::Signatures::CCTOR, Allocator());
1303         property->AsClassStaticBlock()->Function()->SetIdent(id);
1304     }
1305 
1306     if (property->IsTSInterfaceBody()) {
1307         return CheckClassElementInterfaceBody(property, properties);
1308     }
1309 
1310     if (!property->IsMethodDefinition()) {
1311         return false;
1312     }
1313 
1314     auto const *const method = property->AsMethodDefinition();
1315     auto const *const function = method->Function();
1316 
1317     //  Check the special '$_get' and '$_set' methods using for object's index access
1318     if (method->Kind() == ir::MethodDefinitionKind::METHOD) {
1319         CheckPredefinedMethods(function, property->Start());
1320     }
1321 
1322     return false;  // resolve overloads later on scopes stage
1323 }
1324 
CheckPredefinedMethods(ir::ScriptFunction const * function,const lexer::SourcePosition & position)1325 void ETSParser::CheckPredefinedMethods(ir::ScriptFunction const *function, const lexer::SourcePosition &position)
1326 {
1327     ES2PANDA_ASSERT(function != nullptr);
1328     auto const name = function->Id()->Name();
1329 
1330     auto const checkAsynchronous = [this, function, &name, &position]() -> void {
1331         if (function->IsAsyncFunc()) {
1332             LogError(diagnostic::SPECIAL_PREDEFINED_METHOD_CANNOT_BE_ASYNC, {std::string(name)}, position);
1333         }
1334     };
1335 
1336     if (name.Is(compiler::Signatures::GET_INDEX_METHOD)) {
1337         checkAsynchronous();
1338 
1339         bool isValid = function->Params().size() == 1U;
1340         if (isValid) {
1341             auto const *const param = function->Params()[0]->AsETSParameterExpression();
1342             isValid = !param->IsOptional() && !param->IsRestParameter();
1343         }
1344 
1345         if (!isValid) {
1346             LogError(diagnostic::SPECIAL_PREDEFINED_METHOD_SHOULD_HAVE_ONE_PARAM, {std::string(name)}, position);
1347         }
1348     } else if (name.Is(compiler::Signatures::SET_INDEX_METHOD)) {
1349         checkAsynchronous();
1350 
1351         bool isValid = function->Params().size() == 2U;
1352         if (isValid) {
1353             auto const *const param1 = function->Params()[0]->AsETSParameterExpression();
1354             auto const *const param2 = function->Params()[1]->AsETSParameterExpression();
1355             isValid = !param1->IsOptional() && !param1->IsRestParameter() && !param2->IsOptional() &&
1356                       !param2->IsRestParameter();
1357         }
1358 
1359         if (!isValid) {
1360             LogError(diagnostic::SPECIAL_PREDEFINED_METHOD_SHOULD_HAVE_TWO_PARAMS, {std::string(name)}, position);
1361         }
1362     } else if (name.Is(compiler::Signatures::ITERATOR_METHOD)) {
1363         checkAsynchronous();
1364 
1365         if (!function->Params().empty()) {
1366             LogError(diagnostic::SPECIAL_PREDEFINED_METHOD_SHOULD_NOT_HAVE_PARAMS, {std::string(name)}, position);
1367         }
1368     }
1369 }
1370 
CreateImplicitConstructor(ir::MethodDefinition * & ctor,ArenaVector<ir::AstNode * > & properties,ir::ClassDefinitionModifiers modifiers,ir::ModifierFlags flags,const lexer::SourcePosition & startLoc)1371 void ETSParser::CreateImplicitConstructor([[maybe_unused]] ir::MethodDefinition *&ctor,
1372                                           ArenaVector<ir::AstNode *> &properties,
1373                                           [[maybe_unused]] ir::ClassDefinitionModifiers modifiers,
1374                                           ir::ModifierFlags flags, const lexer::SourcePosition &startLoc)
1375 {
1376     if (std::any_of(properties.cbegin(), properties.cend(), [](ir::AstNode *prop) {
1377             return prop->IsMethodDefinition() && prop->AsMethodDefinition()->IsConstructor();
1378         })) {
1379         return;
1380     }
1381 
1382     if ((modifiers & ir::ClassDefinitionModifiers::ANONYMOUS) != 0) {
1383         return;
1384     }
1385 
1386     auto *methodDef = BuildImplicitConstructor(ir::ClassDefinitionModifiers::SET_CTOR_ID, startLoc);
1387     ES2PANDA_ASSERT(methodDef != nullptr);
1388     if ((flags & ir::ModifierFlags::DECLARE) != 0) {
1389         auto func = methodDef->Function();
1390         ES2PANDA_ASSERT(func != nullptr);
1391         func->AddFlag(ir::ScriptFunctionFlags::EXTERNAL);
1392     }
1393     properties.push_back(methodDef);
1394 }
1395 
ParseMemberModifiers()1396 std::pair<ir::ModifierFlags, lexer::SourcePosition> ETSParser::ParseMemberModifiers()
1397 {
1398     auto memberModifiers = ir::ModifierFlags::STATIC | ir::ModifierFlags::PUBLIC;
1399 
1400     if (Lexer()->TryEatTokenType(lexer::TokenType::KEYW_EXPORT)) {
1401         const auto savedPos = Lexer()->Save();
1402         if (Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_DEFAULT)) {
1403             memberModifiers |= ir::ModifierFlags::DEFAULT_EXPORT;
1404         } else if (Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_TYPE)) {
1405             if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) {
1406                 Lexer()->Rewind(savedPos);
1407             }
1408             memberModifiers |= ir::ModifierFlags::EXPORT;
1409             memberModifiers |= ir::ModifierFlags::EXPORT_TYPE;
1410         } else {
1411             memberModifiers |= ir::ModifierFlags::EXPORT;
1412         }
1413     }
1414 
1415     lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
1416 
1417     if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_DECLARE) {
1418         CheckDeclare();
1419         memberModifiers |= ir::ModifierFlags::DECLARE;
1420     }
1421     const auto tokenType = Lexer()->GetToken().KeywordType();
1422     if (tokenType == lexer::TokenType::KEYW_ASYNC || tokenType == lexer::TokenType::KEYW_NATIVE) {
1423         bool isAsync = tokenType == lexer::TokenType::KEYW_ASYNC;
1424 
1425         if (isAsync) {
1426             memberModifiers |= ir::ModifierFlags::ASYNC;
1427         } else {
1428             memberModifiers |= ir::ModifierFlags::NATIVE;
1429         }
1430         Lexer()->NextToken();
1431 
1432         if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_FUNCTION) {
1433             // async_function_bas.ets
1434             if (isAsync) {
1435                 LogError(diagnostic::ASYNC_FLAG_ONLY_FOR_TOP_FUN);
1436             } else {
1437                 LogError(diagnostic::NATIVE_FLAG_ONLY_FOR_TOP_FUN);
1438             }
1439             Lexer()->GetToken().SetTokenType(lexer::TokenType::KEYW_FUNCTION);
1440         }
1441     }
1442     return std::make_pair(memberModifiers, startLoc);
1443 }
1444 
1445 }  // namespace ark::es2panda::parser
1446