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