• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ETSparser.h"
17 #include "ETSNolintParser.h"
18 #include <utility>
19 
20 #include "macros.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/base/decorator.h"
32 #include "ir/base/catchClause.h"
33 #include "ir/base/scriptFunction.h"
34 #include "ir/base/methodDefinition.h"
35 #include "ir/base/spreadElement.h"
36 #include "ir/expressions/identifier.h"
37 #include "ir/expressions/functionExpression.h"
38 #include "ir/expressions/dummyNode.h"
39 #include "ir/module/importDeclaration.h"
40 #include "ir/module/importDefaultSpecifier.h"
41 #include "ir/module/importSpecifier.h"
42 #include "ir/module/exportSpecifier.h"
43 #include "ir/module/exportNamedDeclaration.h"
44 #include "ir/ets/etsPrimitiveType.h"
45 #include "ir/ets/etsPackageDeclaration.h"
46 #include "ir/ets/etsReExportDeclaration.h"
47 #include "ir/ets/etsWildcardType.h"
48 #include "ir/ets/etsTuple.h"
49 #include "ir/ets/etsFunctionType.h"
50 #include "ir/ets/etsScript.h"
51 #include "ir/ets/etsTypeReference.h"
52 #include "ir/ets/etsTypeReferencePart.h"
53 #include "ir/ets/etsNullishTypes.h"
54 #include "ir/ets/etsUnionType.h"
55 #include "ir/ets/etsImportSource.h"
56 #include "ir/ets/etsImportDeclaration.h"
57 #include "ir/ets/etsStructDeclaration.h"
58 #include "ir/module/importNamespaceSpecifier.h"
59 #include "ir/ts/tsInterfaceDeclaration.h"
60 #include "ir/ts/tsTypeParameterInstantiation.h"
61 #include "ir/ts/tsInterfaceBody.h"
62 #include "ir/ts/tsImportEqualsDeclaration.h"
63 #include "ir/ts/tsArrayType.h"
64 #include "ir/ts/tsQualifiedName.h"
65 #include "ir/ts/tsTypeReference.h"
66 #include "ir/ts/tsTypeParameter.h"
67 #include "ir/ts/tsInterfaceHeritage.h"
68 #include "ir/ts/tsFunctionType.h"
69 #include "ir/ts/tsTypeAliasDeclaration.h"
70 #include "ir/ts/tsTypeParameterDeclaration.h"
71 #include "ir/ts/tsThisType.h"
72 #include "generated/signatures.h"
73 
74 namespace ark::es2panda::parser {
75 class FunctionContext;
76 
77 using namespace std::literals::string_literals;
78 
ParseFunctionReturnType(ParserStatus status)79 ir::TypeNode *ETSParser::ParseFunctionReturnType([[maybe_unused]] ParserStatus status)
80 {
81     if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
82         if ((status & ParserStatus::CONSTRUCTOR_FUNCTION) != 0U) {
83             ThrowSyntaxError("Type annotation isn't allowed for constructor.");
84         }
85         Lexer()->NextToken();  // eat ':'
86         TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR |
87                                                TypeAnnotationParsingOptions::CAN_BE_TS_TYPE_PREDICATE |
88                                                TypeAnnotationParsingOptions::RETURN_TYPE;
89         return ParseTypeAnnotation(&options);
90     }
91 
92     return nullptr;
93 }
94 
ParsePrimitiveType(TypeAnnotationParsingOptions * options,ir::PrimitiveType type)95 ir::TypeNode *ETSParser::ParsePrimitiveType(TypeAnnotationParsingOptions *options, ir::PrimitiveType type)
96 {
97     if (((*options) & TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE) != 0) {
98         ThrowSyntaxError("Primitive type is not allowed here.");
99     }
100 
101     auto *typeAnnotation = AllocNode<ir::ETSPrimitiveType>(type);
102     typeAnnotation->SetRange(Lexer()->GetToken().Loc());
103     Lexer()->NextToken();
104     return typeAnnotation;
105 }
106 
ParseUnionType(ir::TypeNode * const firstType)107 ir::TypeNode *ETSParser::ParseUnionType(ir::TypeNode *const firstType)
108 {
109     ArenaVector<ir::TypeNode *> types(Allocator()->Adapter());
110     types.push_back(firstType->AsTypeNode());
111 
112     while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR) {
113         Lexer()->NextToken();  // eat '|'
114 
115         auto options = TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::DISALLOW_UNION;
116         types.push_back(ParseTypeAnnotation(&options));
117     }
118 
119     auto const endLoc = types.back()->End();
120     auto *const unionType = AllocNode<ir::ETSUnionType>(std::move(types));
121     unionType->SetRange({firstType->Start(), endLoc});
122     return unionType;
123 }
124 
GetTypeAnnotationOfPrimitiveType(lexer::TokenType tokenType,TypeAnnotationParsingOptions * options)125 ir::TypeNode *ETSParser::GetTypeAnnotationOfPrimitiveType([[maybe_unused]] lexer::TokenType tokenType,
126                                                           TypeAnnotationParsingOptions *options)
127 {
128     ir::TypeNode *typeAnnotation = nullptr;
129     switch (tokenType) {
130         case lexer::TokenType::KEYW_BOOLEAN:
131             typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::BOOLEAN);
132             break;
133         case lexer::TokenType::KEYW_DOUBLE:
134             typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::DOUBLE);
135             break;
136         case lexer::TokenType::KEYW_BYTE:
137             typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::BYTE);
138             break;
139         case lexer::TokenType::KEYW_FLOAT:
140             typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::FLOAT);
141             break;
142         case lexer::TokenType::KEYW_SHORT:
143             typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::SHORT);
144             break;
145         case lexer::TokenType::KEYW_INT:
146             typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::INT);
147             break;
148         case lexer::TokenType::KEYW_CHAR:
149             typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::CHAR);
150             break;
151         case lexer::TokenType::KEYW_LONG:
152             typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::LONG);
153             break;
154         case lexer::TokenType::KEYW_VOID:
155             typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::VOID);
156             break;
157         default:
158             typeAnnotation = ParseTypeReference(options);
159             break;
160     }
161     return typeAnnotation;
162 }
163 
ParseWildcardType(TypeAnnotationParsingOptions * options)164 ir::TypeNode *ETSParser::ParseWildcardType(TypeAnnotationParsingOptions *options)
165 {
166     const auto varianceStartLoc = Lexer()->GetToken().Start();
167     const auto varianceEndLoc = Lexer()->GetToken().End();
168     const auto varianceModifier = ParseTypeVarianceModifier(options);
169 
170     auto *typeReference = [this, &varianceModifier, options]() -> ir::ETSTypeReference * {
171         if (varianceModifier == ir::ModifierFlags::OUT &&
172             (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_GREATER_THAN ||
173              Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA)) {
174             // unbounded 'out'
175             return nullptr;
176         }
177         return ParseTypeReference(options)->AsETSTypeReference();
178     }();
179 
180     auto *wildcardType = AllocNode<ir::ETSWildcardType>(typeReference, varianceModifier);
181     wildcardType->SetRange({varianceStartLoc, typeReference == nullptr ? varianceEndLoc : typeReference->End()});
182 
183     return wildcardType;
184 }
185 
ParseFunctionType()186 ir::TypeNode *ETSParser::ParseFunctionType()
187 {
188     auto startLoc = Lexer()->GetToken().Start();
189     auto fullParams = ParseFunctionParams();
190 
191     auto *const returnTypeAnnotation = [this]() -> ir::TypeNode * {
192         ExpectToken(lexer::TokenType::PUNCTUATOR_ARROW);
193         TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR;
194         return ParseTypeAnnotation(&options);
195     }();
196 
197     ir::ScriptFunctionFlags throwMarker = ParseFunctionThrowMarker(false);
198 
199     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
200     ArenaVector<ir::TypeNode *> constituentTypes(Allocator()->Adapter());
201     for (auto it : fullParams) {
202         if (!it->AsETSParameterExpression()->IsDefault()) {
203             params.push_back(it);
204         } else {
205             ArenaVector<ir::Expression *> tmpParams(Allocator()->Adapter());
206 
207             for (auto param : params) {
208                 tmpParams.push_back(param->Clone(Allocator(), nullptr)->AsExpression());
209             }
210 
211             auto *funcType = AllocNode<ir::ETSFunctionType>(
212                 ir::FunctionSignature(nullptr, std::move(tmpParams), returnTypeAnnotation->Clone(Allocator(), nullptr)),
213                 throwMarker);
214 
215             funcType->ReturnType()->SetParent(funcType);
216 
217             constituentTypes.push_back(funcType);
218             params.push_back(it);
219         }
220     }
221 
222     if (constituentTypes.empty()) {
223         auto *funcType = AllocNode<ir::ETSFunctionType>(
224             ir::FunctionSignature(nullptr, std::move(params), returnTypeAnnotation), throwMarker);
225         const auto endLoc = returnTypeAnnotation->End();
226         funcType->SetRange({startLoc, endLoc});
227         return funcType;
228     }
229 
230     auto *funcType = AllocNode<ir::ETSFunctionType>(
231         ir::FunctionSignature(nullptr, std::move(params), returnTypeAnnotation), throwMarker);
232     constituentTypes.push_back(funcType);
233 
234     auto *const unionType = AllocNode<ir::ETSUnionType>(std::move(constituentTypes));
235     const auto endLoc = returnTypeAnnotation->End();
236     unionType->SetRange({startLoc, endLoc});
237 
238     return unionType;
239 }
240 
ParseETSTupleType(TypeAnnotationParsingOptions * const options)241 ir::TypeNode *ETSParser::ParseETSTupleType(TypeAnnotationParsingOptions *const options)
242 {
243     ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET);
244 
245     const auto startLoc = Lexer()->GetToken().Start();
246     Lexer()->NextToken();  // eat '['
247 
248     ArenaVector<ir::TypeNode *> tupleTypeList(Allocator()->Adapter());
249     auto *const tupleType = AllocNode<ir::ETSTuple>(Allocator());
250 
251     bool spreadTypePresent = false;
252 
253     while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
254         // Parse named parameter if name presents
255         if ((Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) &&
256             (Lexer()->Lookahead() == lexer::LEX_CHAR_COLON)) {
257             ExpectIdentifier();
258             Lexer()->NextToken();  // eat ':'
259         }
260 
261         if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) {
262             if (spreadTypePresent) {
263                 ThrowSyntaxError("Only one spread type declaration allowed, at the last index");
264             }
265 
266             spreadTypePresent = true;
267             Lexer()->NextToken();  // eat '...'
268         } else if (spreadTypePresent) {
269             // This can't be implemented to any index, with type consistency. If a spread type is in the middle of
270             // the tuple, then bounds check can't be made for element access, so the type of elements after the
271             // spread can't be determined in compile time.
272             ThrowSyntaxError("Spread type must be at the last index in the tuple type");
273         }
274 
275         auto *const currentTypeAnnotation = ParseTypeAnnotation(options);
276         currentTypeAnnotation->SetParent(tupleType);
277 
278         if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) {
279             // NOTE(mmartin): implement optional types for tuples
280             ThrowSyntaxError("Optional types in tuples are not yet implemented.");
281         }
282 
283         if (spreadTypePresent) {
284             if (!currentTypeAnnotation->IsTSArrayType()) {
285                 ThrowSyntaxError("Spread type must be an array type");
286             }
287 
288             tupleType->SetSpreadType(currentTypeAnnotation);
289         } else {
290             tupleTypeList.push_back(currentTypeAnnotation);
291         }
292 
293         if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) {
294             Lexer()->NextToken();  // eat comma
295             continue;
296         }
297 
298         if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
299             ThrowSyntaxError("Comma is mandatory between elements in a tuple type declaration");
300         }
301     }
302 
303     Lexer()->NextToken();  // eat ']'
304 
305     tupleType->SetTypeAnnotationsList(tupleTypeList);
306     const auto endLoc = Lexer()->GetToken().End();
307     tupleType->SetRange({startLoc, endLoc});
308 
309     return tupleType;
310 }
311 
312 // Helper function for  ETSParser::GetTypeAnnotationFromToken(...) method
ParsePotentialFunctionalType(TypeAnnotationParsingOptions * options,lexer::SourcePosition startLoc)313 ir::TypeNode *ETSParser::ParsePotentialFunctionalType(TypeAnnotationParsingOptions *options,
314                                                       lexer::SourcePosition startLoc)
315 {
316     if (((*options) & TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE) == 0 &&
317         (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS ||
318          Lexer()->Lookahead() == lexer::LEX_CHAR_COLON || Lexer()->Lookahead() == lexer::LEX_CHAR_QUESTION)) {
319         GetContext().Status() |= ParserStatus::ALLOW_DEFAULT_VALUE;
320         auto typeAnnotation = ParseFunctionType();
321         typeAnnotation->SetStart(startLoc);
322         GetContext().Status() ^= ParserStatus::ALLOW_DEFAULT_VALUE;
323         return typeAnnotation;
324     }
325 
326     auto savePos = Lexer()->Save();
327     ParseTypeAnnotation(options);
328 
329     Lexer()->Rewind(savePos);
330     return nullptr;
331 }
332 
333 // Just to reduce the size of ParseTypeAnnotation(...) method
GetTypeAnnotationFromToken(TypeAnnotationParsingOptions * options)334 std::pair<ir::TypeNode *, bool> ETSParser::GetTypeAnnotationFromToken(TypeAnnotationParsingOptions *options)
335 {
336     ir::TypeNode *typeAnnotation = nullptr;
337 
338     switch (Lexer()->GetToken().Type()) {
339         case lexer::TokenType::LITERAL_IDENT: {
340             typeAnnotation = ParseLiteralIdent(options);
341             if (((*options) & TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL) != 0 &&
342                 (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS || IsStructKeyword())) {
343                 return std::make_pair(typeAnnotation, false);
344             }
345             return std::make_pair(typeAnnotation, true);
346         }
347         case lexer::TokenType::LITERAL_NULL: {
348             typeAnnotation = AllocNode<ir::ETSNullType>();
349             typeAnnotation->SetRange(Lexer()->GetToken().Loc());
350             Lexer()->NextToken();
351             return std::make_pair(typeAnnotation, true);
352         }
353         case lexer::TokenType::KEYW_UNDEFINED: {
354             typeAnnotation = AllocNode<ir::ETSUndefinedType>();
355             typeAnnotation->SetRange(Lexer()->GetToken().Loc());
356             Lexer()->NextToken();
357             return std::make_pair(typeAnnotation, true);
358         }
359         case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: {
360             return GetTypeAnnotationFromParentheses(options);
361         }
362         case lexer::TokenType::PUNCTUATOR_FORMAT:
363             return std::make_pair(ParseTypeFormatPlaceholder(), true);
364         case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET:
365             return std::make_pair(ParseETSTupleType(options), true);
366         case lexer::TokenType::KEYW_THIS:
367             return std::make_pair(ParseThisType(options), true);
368         default:
369             return std::make_pair(typeAnnotation, true);
370     }
371 }
372 
GetTypeAnnotationFromParentheses(TypeAnnotationParsingOptions * options)373 std::pair<ir::TypeNode *, bool> ETSParser::GetTypeAnnotationFromParentheses(TypeAnnotationParsingOptions *options)
374 {
375     ir::TypeNode *typeAnnotation = nullptr;
376     auto startLoc = Lexer()->GetToken().Start();
377     lexer::LexerPosition savedPos = Lexer()->Save();
378     Lexer()->NextToken();  // eat '('
379 
380     typeAnnotation = ParsePotentialFunctionalType(options, startLoc);
381     if (typeAnnotation != nullptr) {
382         return std::make_pair(typeAnnotation, true);
383     }
384 
385     typeAnnotation = ParseTypeAnnotation(options);
386     if (typeAnnotation == nullptr) {
387         return std::make_pair(typeAnnotation, true);
388     }
389     typeAnnotation->SetStart(startLoc);
390 
391     if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR) {
392         typeAnnotation = ParseUnionType(typeAnnotation);
393     }
394 
395     ParseRightParenthesis(options, typeAnnotation, savedPos);
396 
397     return std::make_pair(typeAnnotation, true);
398 }
399 
ParseThisType(TypeAnnotationParsingOptions * options)400 ir::TypeNode *ETSParser::ParseThisType(TypeAnnotationParsingOptions *options)
401 {
402     ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_THIS);
403 
404     // A syntax error should be thrown if
405     // - the usage of 'this' as a type is not allowed in the current context, or
406     // - 'this' is not used as a return type, or
407     // - the current context is an arrow function (might be inside a method of a class where 'this' is allowed).
408     if (((*options & TypeAnnotationParsingOptions::THROW_ERROR) != 0) &&
409         (((GetContext().Status() & ParserStatus::ALLOW_THIS_TYPE) == 0) ||
410          ((*options & TypeAnnotationParsingOptions::RETURN_TYPE) == 0) ||
411          ((GetContext().Status() & ParserStatus::ARROW_FUNCTION) != 0))) {
412         ThrowSyntaxError("A 'this' type is available only as return type in a non-static method of a class or struct.");
413     }
414 
415     auto *thisType = AllocNode<ir::TSThisType>();
416     thisType->SetRange(Lexer()->GetToken().Loc());
417 
418     Lexer()->NextToken();  // eat 'this'
419 
420     return thisType;
421 }
422 
ParseTypeAnnotation(TypeAnnotationParsingOptions * options)423 ir::TypeNode *ETSParser::ParseTypeAnnotation(TypeAnnotationParsingOptions *options)
424 {
425     bool const throwError = ((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0;
426 
427     auto [typeAnnotation, needFurtherProcessing] = GetTypeAnnotationFromToken(options);
428 
429     if (typeAnnotation == nullptr) {
430         if (throwError) {
431             ThrowSyntaxError("Invalid Type");
432         }
433         return nullptr;
434     }
435 
436     if (!needFurtherProcessing) {
437         return typeAnnotation;
438     }
439 
440     const lexer::SourcePosition &startPos = Lexer()->GetToken().Start();
441 
442     while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) {
443         Lexer()->NextToken();  // eat '['
444 
445         if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
446             if (throwError) {
447                 ThrowExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET);
448             }
449             return nullptr;
450         }
451 
452         Lexer()->NextToken();  // eat ']'
453         typeAnnotation = AllocNode<ir::TSArrayType>(typeAnnotation);
454         typeAnnotation->SetRange({startPos, Lexer()->GetToken().End()});
455     }
456 
457     if (((*options) & TypeAnnotationParsingOptions::DISALLOW_UNION) == 0 &&
458         Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR) {
459         return ParseUnionType(typeAnnotation);
460     }
461 
462     return typeAnnotation;
463 }
464 
465 }  // namespace ark::es2panda::parser
466