• 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 "generated/diagnostic.h"
18 #include "lexer/lexer.h"
19 #include "ir/ets/etsTuple.h"
20 #include "ir/ets/etsUnionType.h"
21 #include "ir/statements/annotationDeclaration.h"
22 
23 namespace ark::es2panda::parser {
24 
ParseTopLevelAnnotation(ir::ModifierFlags memberModifiers)25 ir::Statement *ETSParser::ParseTopLevelAnnotation(ir::ModifierFlags memberModifiers)
26 {
27     ir::Statement *result = nullptr;
28 
29     Lexer()->NextToken();  // eat '@'
30     if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_INTERFACE) {
31         result = ParseAnnotationDeclaration(memberModifiers);
32     } else {
33         auto annotations = ParseAnnotations(true);
34         auto savePos = Lexer()->GetToken().Start();
35         result = ParseTopLevelStatement();
36         if (result != nullptr) {
37             ApplyAnnotationsToNode(result, std::move(annotations), savePos);
38         } else {
39             LogError(diagnostic::ANNOTATION_NOT_ALLOWED);
40         }
41     }
42 
43     return result;
44 }
45 
46 template <bool IS_USAGE>
ParseAnnotationName()47 ir::Expression *ETSParser::ParseAnnotationName()
48 {
49     ir::Expression *expr = nullptr;
50 
51     auto setAnnotation = [](ir::Identifier *ident) {
52         if constexpr (IS_USAGE) {
53             ident->SetAnnotationUsage();
54         } else {
55             ident->SetAnnotationDecl();
56         }
57     };
58     auto save = Lexer()->Save();
59     ir::Identifier *ident = nullptr;
60     Lexer()->NextToken();
61     if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) {
62         Lexer()->Rewind(save);
63         expr = ExpectIdentifier();
64         ident = expr->AsIdentifier();
65     } else {
66         Lexer()->Rewind(save);
67         if (Lexer()->Lookahead() == '.') {
68             auto opt = TypeAnnotationParsingOptions::NO_OPTS;
69             expr = ParseTypeReference(&opt);
70             ES2PANDA_ASSERT(expr != nullptr);
71             ident = expr->AsETSTypeReference()->Part()->GetIdent();
72         } else {
73             expr = ExpectIdentifier();
74             ES2PANDA_ASSERT(expr != nullptr);
75             ident = expr->AsIdentifier();
76         }
77     }
78 
79     if (ident->IsBrokenExpression()) {
80         LogError(diagnostic::INVALID_ANNOTATION_NAME, {}, expr->Start());
81     }
82 
83     setAnnotation(ident);
84     return expr;
85 }
86 
ParseAnnotationDeclaration(ir::ModifierFlags flags)87 ir::AnnotationDeclaration *ETSParser::ParseAnnotationDeclaration(ir::ModifierFlags flags)
88 {
89     const lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
90     // The default modifier of the annotation is public abstract
91     flags |= ir::ModifierFlags::ABSTRACT | ir::ModifierFlags::PUBLIC | ir::ModifierFlags::ANNOTATION_DECLARATION;
92     flags &= ~ir::ModifierFlags::STATIC;
93     if (InAmbientContext()) {
94         flags |= ir::ModifierFlags::DECLARE;
95     }
96     Lexer()->NextToken();
97     ir::Expression *expr = ParseAnnotationName<false>();
98 
99     ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE, false);
100     auto properties = ParseAnnotationProperties(flags);
101 
102     lexer::SourcePosition endLoc = Lexer()->GetToken().End();
103 
104     auto *annotationDecl = AllocNode<ir::AnnotationDeclaration>(expr, std::move(properties), Allocator());
105     ES2PANDA_ASSERT(annotationDecl != nullptr);
106     annotationDecl->SetRange({startLoc, endLoc});
107     annotationDecl->AddModifier(flags);
108     return annotationDecl;
109 }
110 
IsMemberAccessModifiers(lexer::TokenType type)111 static bool IsMemberAccessModifiers(lexer::TokenType type)
112 {
113     return type == lexer::TokenType::KEYW_STATIC || type == lexer::TokenType::KEYW_ASYNC ||
114            type == lexer::TokenType::KEYW_PUBLIC || type == lexer::TokenType::KEYW_PROTECTED ||
115            type == lexer::TokenType::KEYW_PRIVATE || type == lexer::TokenType::KEYW_DECLARE ||
116            type == lexer::TokenType::KEYW_READONLY || type == lexer::TokenType::KEYW_ABSTRACT ||
117            type == lexer::TokenType::KEYW_CONST || type == lexer::TokenType::KEYW_FINAL ||
118            type == lexer::TokenType::KEYW_NATIVE;
119 }
120 
ParseAnnotationProperties(ir::ModifierFlags memberModifiers)121 ArenaVector<ir::AstNode *> ETSParser::ParseAnnotationProperties(ir::ModifierFlags memberModifiers)
122 {
123     Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
124     ArenaVector<ir::AstNode *> properties(Allocator()->Adapter());
125 
126     while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE &&
127            Lexer()->GetToken().Type() != lexer::TokenType::EOS) {
128         if ((memberModifiers & ir::ModifierFlags::ANNOTATION_DECLARATION) != 0U &&
129             Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) {
130             Lexer()->NextToken();  // eat ';'
131             continue;
132         }
133         // check no modifiers
134         while (IsMemberAccessModifiers(Lexer()->GetToken().Type())) {
135             LogError(diagnostic::ANNOTATION_PROPERTY_ACCESS_MODIFIERS, {}, Lexer()->GetToken().Start());
136             Lexer()->NextToken();
137         }
138 
139         auto *fieldName = ExpectIdentifier();
140         ES2PANDA_ASSERT(fieldName != nullptr);
141         if (fieldName->IsErrorPlaceHolder()) {
142             //  Try to recover from error: simplest strategy: only one step ahead.
143             //  Probably we can seek for identifier till the enclosing right brace (staring after the next comma?)
144             //  if the simplest case failed.
145             auto const pos = Lexer()->Save();
146             auto *fieldName1 = ExpectIdentifier();
147             ES2PANDA_ASSERT(fieldName1 != nullptr);
148             if (fieldName1->IsErrorPlaceHolder()) {
149                 Lexer()->Rewind(pos);
150             } else {
151                 fieldName = fieldName1;
152             }
153         }
154 
155         bool needTypeAnnotation = (memberModifiers & ir::ModifierFlags::ANNOTATION_USAGE) == 0U;
156         properties.emplace_back(ParseAnnotationProperty(fieldName, memberModifiers, needTypeAnnotation));
157 
158         if ((memberModifiers & ir::ModifierFlags::ANNOTATION_USAGE) != 0U &&
159             Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) {
160             ExpectToken(lexer::TokenType::PUNCTUATOR_COMMA);  // eat ','
161         }
162     }
163 
164     Lexer()->NextToken();  // eat "}"
165     return properties;
166 }
167 
ValidAnnotationValue(ir::Expression * initializer)168 bool ETSParser::ValidAnnotationValue(ir::Expression *initializer)
169 {
170     if (initializer->IsArrayExpression()) {
171         for (auto *element : initializer->AsArrayExpression()->Elements()) {
172             if (!ValidAnnotationValue(element)) {
173                 return false;
174             }
175         }
176         return true;
177     }
178     return initializer->IsStringLiteral() || initializer->IsNumberLiteral() || initializer->IsMemberExpression() ||
179            initializer->IsBooleanLiteral() || initializer->IsBinaryExpression() || initializer->IsUnaryExpression() ||
180            initializer->IsConditionalExpression() || initializer->IsIdentifier() || initializer->IsTSAsExpression();
181 }
182 
ParseAnnotationProperty(ir::Identifier * fieldName,ir::ModifierFlags memberModifiers,bool needTypeAnnotation)183 ir::AstNode *ETSParser::ParseAnnotationProperty(ir::Identifier *fieldName, ir::ModifierFlags memberModifiers,
184                                                 bool needTypeAnnotation)
185 {
186     lexer::SourcePosition endLoc = fieldName->End();
187     // check no methods
188     if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS ||
189         Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
190         LogError(diagnostic::ANNOTATION_METHOD_AS_PROP, {}, Lexer()->GetToken().Start());
191     }
192 
193     ir::TypeNode *typeAnnotation = nullptr;
194     TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
195     if (needTypeAnnotation && Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
196         Lexer()->NextToken();  // eat ':'
197         typeAnnotation = ParseTypeAnnotation(&options);
198     }
199 
200     if (typeAnnotation == nullptr && (memberModifiers & ir::ModifierFlags::ANNOTATION_DECLARATION) != 0 &&
201         !fieldName->IsErrorPlaceHolder()) {
202         LogError(diagnostic::MISSING_TYPE_ANNOTATION, {fieldName->Name().Mutf8()}, Lexer()->GetToken().Start());
203     }
204 
205     if (typeAnnotation != nullptr) {
206         endLoc = typeAnnotation->End();
207     }
208 
209     ir::Expression *initializer = nullptr;
210     lexer::SourcePosition savePos;
211     if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION ||
212         (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON)) {
213         Lexer()->NextToken();  // eat '=' or ':'
214         savePos = Lexer()->GetToken().Start();
215         initializer = ParseExpression();
216     }
217 
218     if (initializer == nullptr && (memberModifiers & ir::ModifierFlags::ANNOTATION_USAGE) != 0 &&
219         !fieldName->IsErrorPlaceHolder()) {
220         LogError(diagnostic::INVALID_ARGUMENT_PASSED, {fieldName->Name().Mutf8()}, Lexer()->GetToken().Start());
221     }
222 
223     if (initializer != nullptr && !ValidAnnotationValue(initializer)) {
224         LogError(diagnostic::INVALID_VAL_ANNOTATION_FIELD, {}, savePos);
225         initializer = AllocBrokenExpression(savePos);
226     }
227 
228     memberModifiers |= ir::ModifierFlags::PUBLIC;
229     memberModifiers |= ir::ModifierFlags::ABSTRACT;
230     auto *field =
231         AllocNode<ir::ClassProperty>(fieldName, initializer, typeAnnotation, memberModifiers, Allocator(), false);
232     ES2PANDA_ASSERT(field != nullptr);
233     field->SetRange({fieldName->Start(), initializer != nullptr ? initializer->End() : endLoc});
234     return field;
235 }
236 
ParseAnnotations(bool isTopLevelSt)237 ArenaVector<ir::AnnotationUsage *> ETSParser::ParseAnnotations(bool isTopLevelSt)
238 {
239     ArenaVector<ir::AnnotationUsage *> annotations(Allocator()->Adapter());
240     bool hasMoreAnnotations = true;
241     auto save = Lexer()->Save();
242     while (hasMoreAnnotations) {
243         if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_INTERFACE) {
244             if (!isTopLevelSt) {
245                 LogError(diagnostic::ANNOTATION_ONLY_TOP_LEVEL);
246             }
247             Lexer()->Rewind(save);
248             return annotations;
249         }
250 
251         annotations.emplace_back(ParseAnnotationUsage());
252         if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_AT) {
253             hasMoreAnnotations = false;
254         } else {
255             save = Lexer()->Save();
256             Lexer()->NextToken();
257         }
258     }
259     return annotations;
260 }
261 
ApplyAnnotationsToNamespace(ir::ETSModule * ns,ArenaVector<ir::AnnotationUsage * > & annotations)262 static bool ApplyAnnotationsToNamespace(ir::ETSModule *ns, ArenaVector<ir::AnnotationUsage *> &annotations)
263 {
264     if (ns->IsNamespaceChainLastNode()) {
265         ns->SetAnnotations(std::move(annotations));
266         return true;
267     }
268 
269     for (auto *node : ns->Statements()) {
270         if (node->IsETSModule()) {
271             if (ApplyAnnotationsToNamespace(node->AsETSModule(), annotations)) {
272                 return true;
273             }
274         }
275     }
276     return false;
277 }
278 
ApplyAnnotationsToNode(ir::AstNode * node,ArenaVector<ir::AnnotationUsage * > && annotations,lexer::SourcePosition pos,TypeAnnotationParsingOptions options)279 void ETSParser::ApplyAnnotationsToNode(ir::AstNode *node, ArenaVector<ir::AnnotationUsage *> &&annotations,
280                                        lexer::SourcePosition pos, TypeAnnotationParsingOptions options)
281 {
282     if (node == nullptr || annotations.empty()) {
283         return;
284     }
285 
286     if ((options & TypeAnnotationParsingOptions::ANNOTATION_NOT_ALLOW) != 0) {
287         LogError(diagnostic::ANNOTATION_WRONG_DEC, {}, pos);
288         return;
289     }
290 
291     if (node->IsExpressionStatement()) {
292         ApplyAnnotationsToNode(node->AsExpressionStatement()->GetExpression(), std::move(annotations), pos);
293         return;
294     }
295 
296     ApplyAnnotationsToSpecificNodeType(node, std::move(annotations), pos);
297 }
298 
299 // CC-OFFNXT(huge_method,huge_cyclomatic_complexity,G.FUN.01-CPP) big switch-case, solid logic
ApplyAnnotationsToSpecificNodeType(ir::AstNode * node,ArenaVector<ir::AnnotationUsage * > && annotations,lexer::SourcePosition pos)300 void ETSParser::ApplyAnnotationsToSpecificNodeType(ir::AstNode *node, ArenaVector<ir::AnnotationUsage *> &&annotations,
301                                                    lexer::SourcePosition pos)
302 {
303     switch (node->Type()) {
304         case ir::AstNodeType::METHOD_DEFINITION: {
305             auto *func = node->AsMethodDefinition()->Function();
306             ES2PANDA_ASSERT(func != nullptr);
307             func->SetAnnotations(std::move(annotations));
308             break;
309         }
310         case ir::AstNodeType::CLASS_DECLARATION:
311             node->AsClassDeclaration()->Definition()->SetAnnotations(std::move(annotations));
312             break;
313         case ir::AstNodeType::STRUCT_DECLARATION:
314             node->AsETSStructDeclaration()->Definition()->SetAnnotations(std::move(annotations));
315             break;
316         case ir::AstNodeType::FUNCTION_DECLARATION:
317             node->AsFunctionDeclaration()->SetAnnotations(std::move(annotations));
318             break;
319         case ir::AstNodeType::TS_INTERFACE_DECLARATION:
320             node->AsTSInterfaceDeclaration()->SetAnnotations(std::move(annotations));
321             break;
322         case ir::AstNodeType::CLASS_PROPERTY:
323             node->AsClassProperty()->SetAnnotations(std::move(annotations));
324             break;
325         case ir::AstNodeType::VARIABLE_DECLARATION:
326             node->AsVariableDeclaration()->SetAnnotations(std::move(annotations));
327             break;
328         case ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION:
329             node->AsTSTypeAliasDeclaration()->SetAnnotations(std::move(annotations));
330             break;
331         case ir::AstNodeType::ETS_PARAMETER_EXPRESSION:
332             node->AsETSParameterExpression()->SetAnnotations(std::move(annotations));
333             break;
334         case ir::AstNodeType::ARROW_FUNCTION_EXPRESSION:
335             node->AsArrowFunctionExpression()->SetAnnotations(std::move(annotations));
336             break;
337         case ir::AstNodeType::ETS_MODULE:
338             ApplyAnnotationsToNamespace(node->AsETSModule(), annotations);
339             break;
340         case ir::AstNodeType::ETS_TYPE_REFERENCE:
341             node->AsETSTypeReference()->SetAnnotations(std::move(annotations));
342             break;
343         case ir::AstNodeType::TS_ARRAY_TYPE:
344             node->AsTSArrayType()->SetAnnotations(std::move(annotations));
345             break;
346         case ir::AstNodeType::ETS_TUPLE:
347             node->AsETSTuple()->SetAnnotations(std::move(annotations));
348             break;
349         case ir::AstNodeType::ETS_UNION_TYPE:
350             node->AsETSUnionType()->SetAnnotations(std::move(annotations));
351             break;
352         case ir::AstNodeType::ETS_FUNCTION_TYPE:
353             node->AsETSFunctionType()->SetAnnotations(std::move(annotations));
354             break;
355         case ir::AstNodeType::ETS_STRING_LITERAL_TYPE:
356             node->AsETSStringLiteralType()->SetAnnotations(std::move(annotations));
357             break;
358         case ir::AstNodeType::ETS_NULL_TYPE:
359             node->AsETSNullType()->SetAnnotations(std::move(annotations));
360             break;
361         case ir::AstNodeType::ETS_UNDEFINED_TYPE:
362             node->AsETSUndefinedType()->SetAnnotations(std::move(annotations));
363             break;
364         case ir::AstNodeType::TS_TYPE_PARAMETER:
365             node->AsTSTypeParameter()->SetAnnotations(std::move(annotations));
366             break;
367         case ir::AstNodeType::ANNOTATION_DECLARATION:
368             node->AsAnnotationDeclaration()->SetAnnotations(std::move(annotations));
369             break;
370         default:
371             LogError(diagnostic::ANNOTATION_WRONG_DEC, {}, pos);
372     }
373 }
374 
GetExpressionEndLoc(ir::Expression * expr)375 static lexer::SourcePosition GetExpressionEndLoc(ir::Expression *expr)
376 {
377     ES2PANDA_ASSERT(expr != nullptr);
378     if (expr->IsIdentifier()) {
379         return expr->AsIdentifier()->End();
380     }
381     auto *part = expr->AsETSTypeReference()->Part();
382     if (part->Name()->IsBrokenExpression()) {
383         return part->Name()->AsIdentifier()->End();
384     }
385     return part->Name()->AsTSQualifiedName()->Right()->End();
386 }
387 
ParseAnnotationUsage()388 ir::AnnotationUsage *ETSParser::ParseAnnotationUsage()
389 {
390     const lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
391     ir::Expression *expr = ParseAnnotationName<true>();
392 
393     auto flags = ir::ModifierFlags::ANNOTATION_USAGE;
394     ArenaVector<ir::AstNode *> properties(Allocator()->Adapter());
395 
396     if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS &&
397         !IsArrowFunctionExpressionStart() && IsAnnotationUsageStart(GetExpressionEndLoc(expr))) {
398         Lexer()->NextToken();  // eat '('
399         if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
400             properties = ParseAnnotationProperties(flags);
401         } else if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
402             // handle single field annotation
403             auto *singleParamName = AllocNode<ir::Identifier>(compiler::Signatures::ANNOTATION_KEY_VALUE, Allocator());
404             ES2PANDA_ASSERT(singleParamName != nullptr);
405             singleParamName->SetRange({Lexer()->GetToken().Start(), Lexer()->GetToken().End()});
406 
407             const auto savePos = Lexer()->GetToken().Start();
408             auto *initializer = ParseExpression();
409             if (initializer != nullptr && !ValidAnnotationValue(initializer)) {
410                 LogError(diagnostic::INVALID_VAL_ANNOTATION_FIELD, {}, savePos);
411             }
412 
413             auto *singleParam = AllocNode<ir::ClassProperty>(singleParamName, initializer, nullptr,
414                                                              ir::ModifierFlags::ANNOTATION_USAGE, Allocator(), false);
415             ES2PANDA_ASSERT(singleParam != nullptr);
416             singleParam->SetRange(
417                 {singleParamName->Start(), initializer != nullptr ? initializer->End() : singleParamName->End()});
418             properties.push_back(singleParam);
419         }
420 
421         auto *annotationUsage = AllocNode<ir::AnnotationUsage>(expr, std::move(properties));
422         annotationUsage->AddModifier(flags);
423         annotationUsage->SetRange({startLoc, Lexer()->GetToken().End()});
424 
425         ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS, true);  // eat ')'
426 
427         return annotationUsage;
428     }
429 
430     auto *annotationUsage = AllocNode<ir::AnnotationUsage>(expr, std::move(properties));
431     ES2PANDA_ASSERT(annotationUsage != nullptr);
432     annotationUsage->AddModifier(flags);
433     annotationUsage->SetRange({startLoc, GetExpressionEndLoc(expr)});
434 
435     return annotationUsage;
436 }
437 
TryParseAnnotations()438 bool ETSParser::TryParseAnnotations()
439 {
440     ArenaVector<ir::AnnotationUsage *> annotations(Allocator()->Adapter());
441 
442     while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_AT) {
443         Lexer()->NextToken();
444 
445         ir::Expression *ident = ParseAnnotationName<true>();
446         ArenaVector<ir::AstNode *> properties(Allocator()->Adapter());
447 
448         if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
449             TryParseAnnotationsParams();
450         }
451 
452         auto *annotation = AllocNode<ir::AnnotationUsage>(ident, std::move(properties));
453         annotations.push_back(annotation);
454     }
455 
456     return !annotations.empty();
457 }
458 
TryParseAnnotationsParams()459 void ETSParser::TryParseAnnotationsParams()
460 {
461     Lexer()->NextToken();
462     int parenthesesCount = 1;
463 
464     while (parenthesesCount > 0) {
465         if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
466             parenthesesCount++;
467         } else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
468             parenthesesCount--;
469         }
470         Lexer()->NextToken();
471     }
472 }
473 
IsAnnotationUsageStart(lexer::SourcePosition lastTokenEndIndex)474 bool ETSParser::IsAnnotationUsageStart(lexer::SourcePosition lastTokenEndIndex)
475 {
476     auto result = true;
477     if (Lexer()->GetToken().End().index - lastTokenEndIndex.index != 1) {
478         result = false;
479     }
480     return result;
481 }
482 
483 }  // namespace ark::es2panda::parser
484