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