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/statements/namespaceDeclaration.h"
37#include "ir/expressions/identifier.h"
38#include "ir/expressions/functionExpression.h"
39#include "ir/expressions/dummyNode.h"
40#include "ir/module/importDeclaration.h"
41#include "ir/module/importDefaultSpecifier.h"
42#include "ir/module/importSpecifier.h"
43#include "ir/module/exportSpecifier.h"
44#include "ir/module/exportNamedDeclaration.h"
45#include "ir/ets/etsPrimitiveType.h"
46#include "ir/ets/etsPackageDeclaration.h"
47#include "ir/ets/etsReExportDeclaration.h"
48#include "ir/ets/etsWildcardType.h"
49#include "ir/ets/etsTuple.h"
50#include "ir/ets/etsFunctionType.h"
51#include "ir/ets/etsScript.h"
52#include "ir/ets/etsTypeReference.h"
53#include "ir/ets/etsTypeReferencePart.h"
54#include "ir/ets/etsNullishTypes.h"
55#include "ir/ets/etsUnionType.h"
56#include "ir/ets/etsImportSource.h"
57#include "ir/ets/etsImportDeclaration.h"
58#include "ir/ets/etsStructDeclaration.h"
59#include "ir/module/importNamespaceSpecifier.h"
60#include "ir/ts/tsInterfaceDeclaration.h"
61#include "ir/ts/tsTypeParameterInstantiation.h"
62#include "ir/ts/tsInterfaceBody.h"
63#include "ir/ts/tsImportEqualsDeclaration.h"
64#include "ir/ts/tsArrayType.h"
65#include "ir/ts/tsQualifiedName.h"
66#include "ir/ts/tsTypeReference.h"
67#include "ir/ts/tsTypeParameter.h"
68#include "ir/ts/tsInterfaceHeritage.h"
69#include "ir/ts/tsFunctionType.h"
70#include "ir/ts/tsTypeAliasDeclaration.h"
71#include "ir/ts/tsTypeParameterDeclaration.h"
72#include "ir/ts/tsThisType.h"
73#include "generated/signatures.h"
74
75namespace ark::es2panda::parser {
76class FunctionContext;
77
78using namespace std::literals::string_literals;
79
80ETSParser::ETSParser(Program *program, const CompilerOptions &options, ParserStatus status)
81    : TypedParser(program, options, status), globalProgram_(GetProgram())
82{
83    importPathManager_ = std::make_unique<util::ImportPathManager>(Allocator(), ArkTSConfig(), GetOptions().stdLib);
84}
85
86bool ETSParser::IsETSParser() const noexcept
87{
88    return true;
89}
90
91std::unique_ptr<lexer::Lexer> ETSParser::InitLexer(const SourceFile &sourceFile)
92{
93    GetProgram()->SetSource(sourceFile);
94    auto lexer = std::make_unique<lexer::ETSLexer>(&GetContext());
95    SetLexer(lexer.get());
96    return lexer;
97}
98
99void ETSParser::ParseProgram(ScriptKind kind)
100{
101    lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
102    Lexer()->NextToken();
103    GetProgram()->SetKind(kind);
104
105    if (GetProgram()->SourceFilePath().Utf8()[0] == '@') {
106        // NOTE(user): handle multiple sourceFiles
107    }
108
109    ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
110    auto decl = ParsePackageDeclaration();
111    if (decl != nullptr) {
112        statements.emplace_back(decl);
113        // If we found a package declaration, then add all files with the same package to the package parse list
114        AddPackageSourcesToParseList();
115    }
116
117    auto script = ParseETSGlobalScript(startLoc, statements);
118
119    AddExternalSource(ParseSources(true));
120    GetProgram()->SetAst(script);
121    GetProgram()->SetDeclarationModuleInfo();
122}
123
124ir::ETSScript *ETSParser::ParseETSGlobalScript(lexer::SourcePosition startLoc, ArenaVector<ir::Statement *> &statements)
125{
126    ETSNolintParser etsnolintParser(this);
127    etsnolintParser.CollectETSNolints();
128
129    auto imports = ParseImportDeclarations();
130    statements.insert(statements.end(), imports.begin(), imports.end());
131
132    auto topLevelStatements = ParseTopLevelDeclaration();
133    statements.insert(statements.end(), topLevelStatements.begin(), topLevelStatements.end());
134
135    etsnolintParser.ApplyETSNolintsToStatements(statements);
136
137    auto *etsScript = AllocNode<ir::ETSScript>(Allocator(), std::move(statements), GetProgram());
138    etsScript->SetRange({startLoc, Lexer()->GetToken().End()});
139    return etsScript;
140}
141
142void ETSParser::AddExternalSource(const std::vector<Program *> &programs)
143{
144    auto &extSources = globalProgram_->ExternalSources();
145
146    for (auto *newProg : programs) {
147        const util::StringView moduleName = newProg->ModuleName();
148        if (extSources.count(moduleName) == 0) {
149            extSources.try_emplace(moduleName, Allocator()->Adapter());
150        }
151
152        extSources.at(moduleName).emplace_back(newProg);
153    }
154}
155
156ArenaVector<ir::ETSImportDeclaration *> ETSParser::ParseDefaultSources(std::string_view srcFile,
157                                                                       std::string_view importSrc)
158{
159    auto isp = InnerSourceParser(this);
160    SourceFile source(srcFile, importSrc);
161    auto lexer = InitLexer(source);
162
163    Lexer()->NextToken();
164
165    GetContext().Status() |= ParserStatus::IN_DEFAULT_IMPORTS;
166    auto statements = ParseImportDeclarations();
167    GetContext().Status() &= ~ParserStatus::IN_DEFAULT_IMPORTS;
168
169    AddExternalSource(ParseSources());
170    return statements;
171}
172
173void ETSParser::AddDirectImportsToDirectExternalSources(
174    const ArenaVector<util::StringView> &directImportsFromMainSource, parser::Program *const newProg) const
175{
176    if (std::find_if(directImportsFromMainSource.begin(), directImportsFromMainSource.end(),
177                     [newProg](const util::StringView &sv) { return sv == newProg->AbsoluteName(); }) ==
178        directImportsFromMainSource.end()) {
179        return;
180    }
181
182    const util::StringView name = newProg->Ast()->Statements().empty() ? newProg->FileName() : newProg->ModuleName();
183    if (GetProgram()->DirectExternalSources().count(name) == 0) {
184        GetProgram()->DirectExternalSources().try_emplace(name, Allocator()->Adapter());
185    }
186    GetProgram()->DirectExternalSources().at(name).emplace_back(newProg);
187}
188
189void ETSParser::TryParseSource(const util::ImportPathManager::ParseInfo &parseListIdx, util::UString *extSrc,
190                               const ArenaVector<util::StringView> &directImportsFromMainSource,
191                               std::vector<Program *> &programs)
192{
193    try {
194        parser::Program *newProg =
195            ParseSource({parseListIdx.sourcePath.Utf8(), extSrc->View().Utf8(), parseListIdx.sourcePath.Utf8(), false});
196
197        if (!parseListIdx.isImplicitPackageImported || newProg->IsPackageModule()) {
198            AddDirectImportsToDirectExternalSources(directImportsFromMainSource, newProg);
199            // don't insert the separate modules into the programs, when we collect implicit package imports
200            programs.emplace_back(newProg);
201        }
202    } catch (const Error &) {
203        // Here file is not a valid STS source. Ignore and continue if it's implicit package import, else throw
204        // the syntax error as usual
205
206        if (!parseListIdx.isImplicitPackageImported) {
207            throw;
208        }
209
210        util::Helpers::LogWarning("Error during parse of file '", parseListIdx.sourcePath,
211                                  "' in compiled package. File will be omitted.");
212    }
213}
214
215std::vector<Program *> ETSParser::ParseSources(bool firstSource)
216{
217    std::vector<Program *> programs;
218
219    auto &parseList = importPathManager_->ParseList();
220
221    ArenaVector<util::StringView> directImportsFromMainSource(Allocator()->Adapter());
222
223    if (firstSource) {
224        for (auto pl : parseList) {
225            if (pl.isParsed) {
226                // Handle excluded files, which are already set to be parsed before parsing them
227                continue;
228            }
229            directImportsFromMainSource.emplace_back(pl.sourcePath);
230        }
231    }
232
233    auto notParsedElement =
234        std::find_if(parseList.begin(), parseList.end(), [](const auto &parseInfo) { return !parseInfo.isParsed; });
235
236    // NOTE (mmartin): Need a more optimal solution here
237    // This is needed, as during a parsing of a file, programs can be re-added to the parseList, which needs to be
238    // re-parsed. This won't change the size of the list, so with only the 'for loop', there can be unparsed files
239    // remained.
240    // An example for this, is when a file is added as an implicit package import, but it's erroneous, so we just ignore
241    // the file. But when the same file is also added with an explicit import declaration, then we need to re-parse it,
242    // and throw the syntax error.
243    while (notParsedElement != parseList.end()) {
244        // This parse list `paths` can grow in the meantime, so keep this index-based iteration
245        // NOLINTNEXTLINE(modernize-loop-convert)
246        for (size_t idx = 0; idx < parseList.size(); idx++) {
247            // check if already parsed
248            if (parseList[idx].isParsed) {
249                continue;
250            }
251            std::ifstream inputStream(parseList[idx].sourcePath.Mutf8());
252            const auto data = importPathManager_->GetImportData(parseList[idx].sourcePath, Extension());
253            if (!data.hasDecl) {
254                importPathManager_->MarkAsParsed(parseList[idx].sourcePath);
255                continue;
256            }
257
258            if (GetProgram()->SourceFilePath().Is(parseList[idx].sourcePath.Mutf8())) {
259                return programs;
260            }
261
262            if (inputStream.fail()) {
263                ThrowSyntaxError({"Failed to open file: ", parseList[idx].sourcePath.Mutf8()});
264            }
265
266            std::stringstream ss;
267            ss << inputStream.rdbuf();
268            auto externalSource = ss.str();
269
270            auto currentLang = GetContext().SetLanguage(data.lang);
271            auto extSrc = Allocator()->New<util::UString>(externalSource, Allocator());
272            importPathManager_->MarkAsParsed(parseList[idx].sourcePath);
273
274            // In case of implicit package import, if we find a malformed STS file in the package's directory, instead
275            // of aborting compilation we just ignore the file
276
277            // NOTE (mmartin): after the multiple syntax error handling in the parser is implemented, this try-catch
278            // must be changed, as exception throwing will be removed
279
280            TryParseSource(parseList[idx], extSrc, directImportsFromMainSource, programs);
281
282            GetContext().SetLanguage(currentLang);
283        }
284
285        notParsedElement =
286            std::find_if(parseList.begin(), parseList.end(), [](const auto &parseInfo) { return !parseInfo.isParsed; });
287    }
288
289    return programs;
290}
291
292parser::Program *ETSParser::ParseSource(const SourceFile &sourceFile)
293{
294    importPathManager_->MarkAsParsed(sourceFile.filePath);
295    auto *program = Allocator()->New<parser::Program>(Allocator(), GetProgram()->VarBinder());
296    auto esp = ExternalSourceParser(this, program);
297    auto lexer = InitLexer(sourceFile);
298
299    lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
300    Lexer()->NextToken();
301
302    ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
303    auto decl = ParsePackageDeclaration();
304    if (decl != nullptr) {
305        statements.emplace_back(decl);
306    }
307    auto script = ParseETSGlobalScript(startLoc, statements);
308    program->SetAst(script);
309    GetProgram()->SetDeclarationModuleInfo();
310    return program;
311}
312
313ir::Statement *ETSParser::ParseIdentKeyword()
314{
315    const auto token = Lexer()->GetToken();
316    ASSERT(token.Type() == lexer::TokenType::LITERAL_IDENT);
317    switch (token.KeywordType()) {
318        case lexer::TokenType::KEYW_STRUCT: {
319            // Remove this ThrowSyntaxError when struct is implemented in #12726
320            ThrowSyntaxError("Struct types are not supported yet!");
321        }
322        case lexer::TokenType::KEYW_TYPE: {
323            return ParseTypeAliasDeclaration();
324        }
325        default: {
326            break;
327        }
328    }
329    return nullptr;
330}
331
332ir::ScriptFunction *ETSParser::ParseFunction(ParserStatus newStatus, ir::Identifier *className)
333{
334    FunctionContext functionContext(this, newStatus | ParserStatus::FUNCTION);
335    lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
336    auto [signature, throwMarker] = ParseFunctionSignature(newStatus, className);
337
338    ir::AstNode *body = nullptr;
339    lexer::SourcePosition endLoc = startLoc;
340    bool isOverload = false;
341    bool isArrow = (newStatus & ParserStatus::ARROW_FUNCTION) != 0;
342
343    if ((newStatus & ParserStatus::ASYNC_FUNCTION) != 0) {
344        functionContext.AddFlag(ir::ScriptFunctionFlags::ASYNC);
345    }
346
347    if (isArrow) {
348        if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) {
349            ThrowSyntaxError("'=>' expected");
350        }
351
352        functionContext.AddFlag(ir::ScriptFunctionFlags::ARROW);
353        Lexer()->NextToken();
354    }
355
356    if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
357        std::tie(std::ignore, body, endLoc, isOverload) =
358            ParseFunctionBody(signature.Params(), newStatus, GetContext().Status());
359    } else if (isArrow) {
360        body = ParseExpression();
361        endLoc = body->AsExpression()->End();
362        functionContext.AddFlag(ir::ScriptFunctionFlags::EXPRESSION);
363    }
364
365    if ((GetContext().Status() & ParserStatus::FUNCTION_HAS_RETURN_STATEMENT) != 0) {
366        functionContext.AddFlag(ir::ScriptFunctionFlags::HAS_RETURN);
367        GetContext().Status() ^= ParserStatus::FUNCTION_HAS_RETURN_STATEMENT;
368    }
369    functionContext.AddFlag(throwMarker);
370
371    bool isDeclare = InAmbientContext();
372    if (functionContext.IsAsync() && isDeclare) {
373        ThrowSyntaxError("The modifier async cannot be used in an ambient context.");
374    }
375
376    // clang-format off
377    ir::ModifierFlags mFlags = isDeclare ? ir::ModifierFlags::DECLARE : ir::ModifierFlags::NONE;
378    ir::ScriptFunctionFlags funcFlags =
379        isDeclare ? (functionContext.Flags() | ir::ScriptFunctionFlags::EXTERNAL) : functionContext.Flags();
380    auto *funcNode = AllocNode<ir::ScriptFunction>(
381        Allocator(), ir::ScriptFunction::ScriptFunctionData {body, std::move(signature), funcFlags, mFlags, isDeclare,
382                                                             GetContext().GetLanguage()});
383    funcNode->SetRange({startLoc, endLoc});
384    // clang-format on
385
386    return funcNode;
387}
388
389std::tuple<bool, ir::BlockStatement *, lexer::SourcePosition, bool> ETSParser::ParseFunctionBody(
390    [[maybe_unused]] const ArenaVector<ir::Expression *> &params, [[maybe_unused]] ParserStatus newStatus,
391    [[maybe_unused]] ParserStatus contextStatus)
392{
393    if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
394        LogSyntaxError({"Expected token '{', got '", TokenToString(Lexer()->GetToken().Type()), "'"});
395        return {false, nullptr, Lexer()->GetToken().End(), false};
396    }
397
398    ir::BlockStatement *body = ParseBlockStatement();
399
400    return {true, body, body->End(), false};
401}
402
403ir::ScriptFunctionFlags ETSParser::ParseFunctionThrowMarker(bool isRethrowsAllowed)
404{
405    ir::ScriptFunctionFlags throwMarker = ir::ScriptFunctionFlags::NONE;
406
407    if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) {
408        if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_THROWS) {
409            Lexer()->NextToken();  // eat 'throws'
410            throwMarker = ir::ScriptFunctionFlags::THROWS;
411        } else if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_RETHROWS) {
412            if (isRethrowsAllowed) {
413                Lexer()->NextToken();  // eat 'rethrows'
414                throwMarker = ir::ScriptFunctionFlags::RETHROWS;
415            } else {
416                ThrowSyntaxError("Only 'throws' can be used with function types");
417            }
418        }
419    }
420
421    return throwMarker;
422}
423
424ir::AstNode *ETSParser::ParseInnerTypeDeclaration(ir::ModifierFlags memberModifiers, lexer::LexerPosition savedPos,
425                                                  bool isStepToken, bool seenStatic)
426{
427    if ((GetContext().Status() & ParserStatus::IN_NAMESPACE) == 0) {
428        ThrowSyntaxError("Local type declaration (class, struct, interface and enum) support is not yet implemented.");
429    }
430
431    // remove saved_pos nolint
432    Lexer()->Rewind(savedPos);
433    if (isStepToken) {
434        Lexer()->NextToken();
435    }
436
437    Lexer()->GetToken().SetTokenType(Lexer()->GetToken().KeywordType());
438    ir::AstNode *typeDecl = ParseTypeDeclaration(true);
439    memberModifiers &= (ir::ModifierFlags::PUBLIC | ir::ModifierFlags::PROTECTED | ir::ModifierFlags::PRIVATE |
440                        ir::ModifierFlags::INTERNAL);
441    typeDecl->AddModifier(memberModifiers);
442
443    if (!seenStatic) {
444        if (typeDecl->IsClassDeclaration()) {
445            typeDecl->AsClassDeclaration()->Definition()->AsClassDefinition()->SetInnerModifier();
446        } else if (typeDecl->IsETSStructDeclaration()) {
447            typeDecl->AsETSStructDeclaration()->Definition()->AsClassDefinition()->SetInnerModifier();
448        }
449    }
450
451    return typeDecl;
452}
453
454ir::AstNode *ETSParser::ParseInnerConstructorDeclaration(ir::ModifierFlags memberModifiers,
455                                                         const lexer::SourcePosition &startLoc)
456{
457    if ((GetContext().Status() & ParserStatus::IN_NAMESPACE) != 0) {
458        ThrowSyntaxError({"Namespaces should not have a constructor"});
459    }
460    if ((memberModifiers & (~(ir::ModifierFlags::ACCESS | ir::ModifierFlags::DECLARE))) != 0) {
461        ThrowSyntaxError(
462            {"The modifier for a constructor should be limited to access modifiers(private, internal, protected, "
463             "public)."});
464    }
465    auto *memberName = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
466    memberModifiers |= ir::ModifierFlags::CONSTRUCTOR;
467    Lexer()->NextToken();
468    auto *classMethod = ParseClassMethodDefinition(memberName, memberModifiers);
469    classMethod->SetStart(startLoc);
470
471    return classMethod;
472}
473
474ir::Identifier *ETSParser::CreateInvokeIdentifier()
475{
476    util::StringView tokenName = util::StringView {compiler::Signatures::STATIC_INVOKE_METHOD};
477    auto ident = AllocNode<ir::Identifier>(tokenName, Allocator());
478    ident->SetReference(false);
479    ident->SetRange({Lexer()->GetToken().Start(), Lexer()->GetToken().End()});
480    return ident;
481}
482
483void ETSParser::CheckAccessorDeclaration(ir::ModifierFlags memberModifiers)
484{
485    ir::ModifierFlags methodModifiersNotAccessorModifiers = ir::ModifierFlags::NATIVE | ir::ModifierFlags::ASYNC;
486    if ((memberModifiers & methodModifiersNotAccessorModifiers) != 0) {
487        ThrowSyntaxError("Modifiers of getter and setter are limited to ('abstract', 'static', 'final', 'override').");
488    }
489}
490
491ir::AstNode *ETSParser::ParseInnerRest(const ArenaVector<ir::AstNode *> &properties,
492                                       ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags memberModifiers,
493                                       const lexer::SourcePosition &startLoc)
494{
495    if (Lexer()->Lookahead() != lexer::LEX_CHAR_LEFT_PAREN && Lexer()->Lookahead() != lexer::LEX_CHAR_LESS_THAN &&
496        (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_GET ||
497         Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_SET)) {
498        CheckAccessorDeclaration(memberModifiers);
499        return ParseClassGetterSetterMethod(properties, modifiers, memberModifiers);
500    }
501
502    if ((GetContext().Status() & ParserStatus::IN_NAMESPACE) != 0) {
503        auto type = Lexer()->GetToken().Type();
504        if (type == lexer::TokenType::KEYW_FUNCTION || type == lexer::TokenType::KEYW_LET ||
505            type == lexer::TokenType::KEYW_CONST) {
506            Lexer()->NextToken();
507        }
508    }
509
510    auto parseClassMethod = [&memberModifiers, &startLoc, this](ir::Identifier *methodName) {
511        auto *classMethod = ParseClassMethodDefinition(methodName, memberModifiers, nullptr);
512        classMethod->SetStart(startLoc);
513        return classMethod;
514    };
515
516    if (InAmbientContext()) {
517        if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS &&
518            (GetContext().Status() & ParserStatus::IN_CLASS_BODY) != 0U) {
519            // Special case for processing of special '(param: type): returnType` identifier using in ambient context
520            auto ident = CreateInvokeIdentifier();
521            memberModifiers |= ir::ModifierFlags::STATIC;
522            return parseClassMethod(ident);
523        }
524        if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) {
525            auto const savePos = Lexer()->Save();
526            Lexer()->NextToken();
527            if (Lexer()->GetToken().Ident().Is("Symbol")) {
528                Lexer()->Rewind(savePos);
529            } else {
530                return ParseAmbientSignature();
531            }
532        }
533    }
534
535    auto *memberName = ExpectIdentifier();
536    if (memberName == nullptr) {  // Error processing.
537        return nullptr;
538    }
539
540    if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS ||
541        Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
542        return parseClassMethod(memberName);
543    }
544
545    ArenaVector<ir::AstNode *> fieldDeclarations(Allocator()->Adapter());
546    auto *placeholder = AllocNode<ir::TSInterfaceBody>(std::move(fieldDeclarations));
547    ParseClassFieldDefinition(memberName, memberModifiers, placeholder->BodyPtr());
548    return placeholder;
549}
550
551ir::Statement *ETSParser::ParseTypeDeclarationAbstractFinal(bool allowStatic, ir::ClassDefinitionModifiers modifiers)
552{
553    auto flags = ParseClassModifiers();
554    if (allowStatic && (flags & ir::ModifierFlags::STATIC) == 0U) {
555        modifiers |= ir::ClassDefinitionModifiers::INNER;
556    }
557
558    if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS) {
559        return ParseClassDeclaration(modifiers, flags);
560    }
561
562    if (IsStructKeyword()) {
563        return ParseStructDeclaration(modifiers, flags);
564    }
565
566    ThrowUnexpectedToken(Lexer()->GetToken().Type());
567}
568
569ir::Statement *ETSParser::ParseTypeDeclaration(bool allowStatic)
570{
571    auto savedPos = Lexer()->Save();
572
573    auto modifiers = ir::ClassDefinitionModifiers::ID_REQUIRED | ir::ClassDefinitionModifiers::CLASS_DECL;
574
575    auto tokenType = Lexer()->GetToken().Type();
576    switch (tokenType) {
577        case lexer::TokenType::KEYW_STATIC: {
578            if (!allowStatic) {
579                ThrowUnexpectedToken(Lexer()->GetToken().Type());
580            }
581
582            Lexer()->NextToken();
583
584            if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_INTERFACE) {
585                return ParseInterfaceDeclaration(true);
586            }
587
588            Lexer()->Rewind(savedPos);
589            [[fallthrough]];
590        }
591        case lexer::TokenType::KEYW_ABSTRACT:
592        case lexer::TokenType::KEYW_FINAL: {
593            return ParseTypeDeclarationAbstractFinal(allowStatic, modifiers);
594        }
595        case lexer::TokenType::KEYW_ENUM: {
596            return ParseEnumDeclaration(false);
597        }
598        case lexer::TokenType::KEYW_INTERFACE: {
599            return ParseInterfaceDeclaration(false);
600        }
601        case lexer::TokenType::KEYW_NAMESPACE: {
602            if (!InAmbientContext()) {
603                ThrowSyntaxError("Namespaces are declare only");
604            }
605            GetContext().Status() |= ParserStatus::IN_NAMESPACE;
606            auto *ns = ParseNamespaceDeclaration(ir::ModifierFlags::DECLARE | ir::ModifierFlags::EXPORT);
607            GetContext().Status() &= ~ParserStatus::IN_NAMESPACE;
608            return ns;
609        }
610        case lexer::TokenType::KEYW_CLASS: {
611            return ParseClassDeclaration(modifiers);
612        }
613        case lexer::TokenType::LITERAL_IDENT: {
614            if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STRUCT) {
615                return ParseStructDeclaration(modifiers);
616            }
617            [[fallthrough]];
618        }
619        default: {
620            ThrowUnexpectedToken(Lexer()->GetToken().Type());
621        }
622    }
623}
624
625ir::TSTypeAliasDeclaration *ETSParser::ParseTypeAliasDeclaration()
626{
627    ASSERT(Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_TYPE);
628
629    lexer::SourcePosition typeStart = Lexer()->GetToken().Start();
630    Lexer()->NextToken();  // eat type keyword
631
632    if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
633        ThrowSyntaxError("Identifier expected");
634    }
635
636    if (Lexer()->GetToken().IsReservedTypeName()) {
637        std::string errMsg("Type alias name cannot be '");
638        errMsg.append(TokenToString(Lexer()->GetToken().KeywordType()));
639        errMsg.append("'");
640        ThrowSyntaxError(errMsg.c_str());
641    }
642
643    const util::StringView ident = Lexer()->GetToken().Ident();
644    auto *id = AllocNode<ir::Identifier>(ident, Allocator());
645    id->SetRange(Lexer()->GetToken().Loc());
646
647    auto *typeAliasDecl = AllocNode<ir::TSTypeAliasDeclaration>(Allocator(), id);
648
649    Lexer()->NextToken();  // eat alias name
650
651    if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
652        auto options =
653            TypeAnnotationParsingOptions::REPORT_ERROR | TypeAnnotationParsingOptions::ALLOW_DECLARATION_SITE_VARIANCE;
654        ir::TSTypeParameterDeclaration *params = ParseTypeParameterDeclaration(&options);
655        typeAliasDecl->SetTypeParameters(params);
656        params->SetParent(typeAliasDecl);
657    }
658
659    if (!Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_SUBSTITUTION)) {
660        ThrowSyntaxError("'=' expected");
661    }
662
663    TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
664    ir::TypeNode *typeAnnotation = ParseTypeAnnotation(&options);
665    if (typeAnnotation != nullptr) {  // Error processing.
666        typeAliasDecl->SetTsTypeAnnotation(typeAnnotation);
667        typeAnnotation->SetParent(typeAliasDecl);
668    }
669
670    typeAliasDecl->SetRange({typeStart, Lexer()->GetToken().End()});
671    return typeAliasDecl;
672}
673
674std::pair<bool, std::size_t> ETSParser::CheckDefaultParameters(const ir::ScriptFunction *const function) const
675{
676    bool hasDefaultParameter = false;
677    bool hasRestParameter = false;
678    std::size_t requiredParametersNumber = 0U;
679
680    for (auto *const it : function->Params()) {
681        auto const *const param = it->AsETSParameterExpression();
682
683        if (param->IsRestParameter()) {
684            hasRestParameter = true;
685            continue;
686        }
687
688        if (hasRestParameter) {
689            ThrowSyntaxError("Rest parameter should be the last one.", param->Start());
690        }
691
692        if (param->IsDefault()) {
693            hasDefaultParameter = true;
694            continue;
695        }
696
697        if (hasDefaultParameter) {
698            ThrowSyntaxError("Required parameter follows default parameter(s).", param->Start());
699        }
700
701        ++requiredParametersNumber;
702    }
703
704    if (hasDefaultParameter && hasRestParameter) {
705        ThrowSyntaxError("Both optional and rest parameters are not allowed in function's parameter list.",
706                         function->Start());
707    }
708
709    return std::make_pair(hasDefaultParameter, requiredParametersNumber);
710}
711
712std::string ETSParser::PrimitiveTypeToName(ir::PrimitiveType type)
713{
714    switch (type) {
715        case ir::PrimitiveType::BYTE:
716            return "byte";
717        case ir::PrimitiveType::INT:
718            return "int";
719        case ir::PrimitiveType::LONG:
720            return "long";
721        case ir::PrimitiveType::SHORT:
722            return "short";
723        case ir::PrimitiveType::FLOAT:
724            return "float";
725        case ir::PrimitiveType::DOUBLE:
726            return "double";
727        case ir::PrimitiveType::BOOLEAN:
728            return "boolean";
729        case ir::PrimitiveType::CHAR:
730            return "char";
731        case ir::PrimitiveType::VOID:
732            return "void";
733        default:
734            UNREACHABLE();
735    }
736}
737
738std::string ETSParser::GetNameForETSUnionType(const ir::TypeNode *typeAnnotation) const
739{
740    ASSERT(typeAnnotation->IsETSUnionType());
741    std::string newstr;
742    for (size_t i = 0; i < typeAnnotation->AsETSUnionType()->Types().size(); i++) {
743        auto type = typeAnnotation->AsETSUnionType()->Types()[i];
744        std::string str = GetNameForTypeNode(type);
745        newstr += str;
746        if (i != typeAnnotation->AsETSUnionType()->Types().size() - 1) {
747            newstr += "|";
748        }
749    }
750    return newstr;
751}
752
753std::string ETSParser::GetNameForTypeNode(const ir::TypeNode *typeAnnotation) const
754{
755    if (typeAnnotation->IsETSUnionType()) {
756        return GetNameForETSUnionType(typeAnnotation);
757    }
758    if (typeAnnotation->IsETSPrimitiveType()) {
759        return PrimitiveTypeToName(typeAnnotation->AsETSPrimitiveType()->GetPrimitiveType());
760    }
761
762    if (typeAnnotation->IsETSTypeReference()) {
763        std::string typeParamNames;
764        auto typeParam = typeAnnotation->AsETSTypeReference()->Part()->TypeParams();
765        if (typeParam != nullptr && typeParam->IsTSTypeParameterInstantiation()) {
766            typeParamNames = "<";
767            auto paramList = typeParam->Params();
768            for (auto param : paramList) {
769                std::string typeParamName = GetNameForTypeNode(param);
770                typeParamNames += typeParamName + ",";
771            }
772            typeParamNames.pop_back();
773            typeParamNames += ">";
774        }
775        return typeAnnotation->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Name().Mutf8() + typeParamNames;
776    }
777
778    if (typeAnnotation->IsETSFunctionType()) {
779        std::string lambdaParams = " ";
780
781        for (const auto *const param : typeAnnotation->AsETSFunctionType()->Params()) {
782            lambdaParams += param->AsETSParameterExpression()->Ident()->Name().Mutf8();
783            lambdaParams += ":";
784            lambdaParams += GetNameForTypeNode(param->AsETSParameterExpression()->Ident()->TypeAnnotation());
785            lambdaParams += ",";
786        }
787
788        lambdaParams.pop_back();
789        const std::string returnTypeName = GetNameForTypeNode(typeAnnotation->AsETSFunctionType()->ReturnType());
790
791        return "((" + lambdaParams + ") => " + returnTypeName + ")";
792    }
793
794    if (typeAnnotation->IsTSArrayType()) {
795        // Note! array is required for the rest parameter.
796        return GetNameForTypeNode(typeAnnotation->AsTSArrayType()->ElementType()) + "[]";
797    }
798
799    if (typeAnnotation->IsETSNullType()) {
800        return "null";
801    }
802
803    if (typeAnnotation->IsETSUndefinedType()) {
804        return "undefined";
805    }
806
807    UNREACHABLE();
808}
809
810void ETSParser::ValidateRestParameter(ir::Expression *param)
811{
812    if (param->IsETSParameterExpression()) {
813        if (param->AsETSParameterExpression()->IsRestParameter()) {
814            GetContext().Status() |= ParserStatus::HAS_COMPLEX_PARAM;
815
816            if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
817                ThrowSyntaxError("Rest parameter must be the last formal parameter.");
818            }
819        }
820    }
821}
822
823bool ETSParser::ValidateBreakLabel([[maybe_unused]] util::StringView label)
824{
825    // For ETS validate labels in checker via variables
826    return true;
827}
828
829bool ETSParser::ValidateContinueLabel([[maybe_unused]] util::StringView label)
830{
831    // For ETS validate labels in checker via variables
832    return true;
833}
834
835std::tuple<ir::Expression *, ir::TSTypeParameterInstantiation *> ETSParser::ParseTypeReferencePart(
836    TypeAnnotationParsingOptions *options)
837{
838    ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS;
839
840    if (((*options) & TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL) != 0) {
841        flags |= ExpressionParseFlags::POTENTIAL_CLASS_LITERAL;
842    }
843
844    if (((*options) & TypeAnnotationParsingOptions::POTENTIAL_NEW_ARRAY) != 0) {
845        flags |= ExpressionParseFlags::POTENTIAL_NEW_ARRAY;
846    }
847
848    auto *typeName = ParseQualifiedName(flags);
849    if (typeName == nullptr) {
850        return {nullptr, nullptr};
851    }
852
853    if (((*options) & TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL) != 0 &&
854        (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS || IsStructKeyword())) {
855        return {typeName, nullptr};
856    }
857
858    ir::TSTypeParameterInstantiation *typeParamInst = nullptr;
859    if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT ||
860        Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
861        if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT) {
862            Lexer()->BackwardToken(lexer::TokenType::PUNCTUATOR_LESS_THAN, 1);
863        }
864        *options |= TypeAnnotationParsingOptions::ALLOW_WILDCARD;
865        typeParamInst = ParseTypeParameterInstantiation(options);
866        *options &= ~TypeAnnotationParsingOptions::ALLOW_WILDCARD;
867    }
868
869    return {typeName, typeParamInst};
870}
871
872ir::TypeNode *ETSParser::ParseTypeReference(TypeAnnotationParsingOptions *options)
873{
874    auto startPos = Lexer()->GetToken().Start();
875    ir::ETSTypeReferencePart *typeRefPart = nullptr;
876
877    if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_FORMAT) {
878        return ParseTypeFormatPlaceholder();
879    }
880
881    while (true) {
882        auto partPos = Lexer()->GetToken().Start();
883        auto [typeName, typeParams] = ParseTypeReferencePart(options);
884        if (typeName == nullptr) {
885            return nullptr;
886        }
887
888        typeRefPart = AllocNode<ir::ETSTypeReferencePart>(typeName, typeParams, typeRefPart);
889        typeRefPart->SetRange({partPos, Lexer()->GetToken().End()});
890
891        if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_PERIOD) {
892            break;
893        }
894
895        Lexer()->NextToken();
896
897        if (((*options) & TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL) != 0 &&
898            (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS || IsStructKeyword())) {
899            break;
900        }
901    }
902
903    auto *typeReference = AllocNode<ir::ETSTypeReference>(typeRefPart);
904    typeReference->SetRange({startPos, Lexer()->GetToken().End()});
905    return typeReference;
906}
907
908ir::TypeNode *ETSParser::ParseBaseTypeReference(TypeAnnotationParsingOptions *options)
909{
910    ir::TypeNode *typeAnnotation = nullptr;
911
912    switch (Lexer()->GetToken().KeywordType()) {
913        case lexer::TokenType::KEYW_BOOLEAN: {
914            typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::BOOLEAN);
915            break;
916        }
917        case lexer::TokenType::KEYW_BYTE: {
918            typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::BYTE);
919            break;
920        }
921        case lexer::TokenType::KEYW_CHAR: {
922            typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::CHAR);
923            break;
924        }
925        case lexer::TokenType::KEYW_DOUBLE: {
926            typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::DOUBLE);
927            break;
928        }
929        case lexer::TokenType::KEYW_FLOAT: {
930            typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::FLOAT);
931            break;
932        }
933        case lexer::TokenType::KEYW_INT: {
934            typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::INT);
935            break;
936        }
937        case lexer::TokenType::KEYW_LONG: {
938            typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::LONG);
939            break;
940        }
941        case lexer::TokenType::KEYW_SHORT: {
942            typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::SHORT);
943            break;
944        }
945
946        default: {
947            break;
948        }
949    }
950
951    return typeAnnotation;
952}
953
954std::optional<lexer::SourcePosition> ETSParser::GetDefaultParamPosition(ArenaVector<ir::Expression *> params)
955{
956    for (auto &param : params) {
957        if (param->IsETSParameterExpression() && param->AsETSParameterExpression()->IsDefault()) {
958            return param->AsETSParameterExpression()->Initializer()->Start();
959        }
960    }
961    return {};
962}
963
964ir::TypeNode *ETSParser::ParseLiteralIdent(TypeAnnotationParsingOptions *options)
965{
966    if (const auto keyword = Lexer()->GetToken().KeywordType();
967        keyword == lexer::TokenType::KEYW_IN || keyword == lexer::TokenType::KEYW_OUT) {
968        return ParseWildcardType(options);
969    }
970
971    if (Lexer()->GetToken().IsDefinableTypeName()) {
972        return GetTypeAnnotationOfPrimitiveType(Lexer()->GetToken().KeywordType(), options);
973    }
974
975    return ParseTypeReference(options);
976}
977
978void ETSParser::ParseRightParenthesis(TypeAnnotationParsingOptions *options, ir::TypeNode *&typeAnnotation,
979                                      lexer::LexerPosition savedPos)
980{
981    if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
982        if (((*options) & TypeAnnotationParsingOptions::REPORT_ERROR) != 0) {
983            ThrowExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS);
984        }
985
986        Lexer()->Rewind(savedPos);
987        typeAnnotation = nullptr;
988    } else {
989        Lexer()->NextToken();  // eat ')'
990    }
991}
992
993void ETSParser::ThrowIfVarDeclaration(VariableParsingFlags flags)
994{
995    if ((flags & VariableParsingFlags::VAR) != 0) {
996        ThrowUnexpectedToken(lexer::TokenType::KEYW_VAR);
997    }
998}
999
1000ir::Statement *ETSParser::ParseExport(lexer::SourcePosition startLoc, ir::ModifierFlags modifiers)
1001{
1002    ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY ||
1003           Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE ||
1004           Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT);
1005    ArenaVector<ir::AstNode *> specifiers(Allocator()->Adapter());
1006
1007    if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) {
1008        ParseNameSpaceSpecifier(&specifiers, true);
1009    } else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
1010        auto specs = ParseNamedSpecifiers();
1011
1012        if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_FROM) {
1013            specifiers = util::Helpers::ConvertVector<ir::AstNode>(specs.first);
1014        } else {
1015            ArenaVector<ir::ExportSpecifier *> exports(Allocator()->Adapter());
1016            for (auto spec : specs.first) {
1017                exports.emplace_back(AllocNode<ir::ExportSpecifier>(spec->Local(), spec->Imported()));
1018            }
1019            auto result = AllocNode<ir::ExportNamedDeclaration>(Allocator(), static_cast<ir::StringLiteral *>(nullptr),
1020                                                                std::move(exports));
1021            result->AddModifier(modifiers);
1022            return result;
1023        }
1024    } else {
1025        return ParseSingleExport(modifiers);
1026    }
1027
1028    // re-export directive
1029    ir::ImportSource *reExportSource = ParseSourceFromClause(true);
1030
1031    lexer::SourcePosition endLoc = reExportSource->Source()->End();
1032    auto *reExportDeclaration = AllocNode<ir::ETSImportDeclaration>(reExportSource, std::move(specifiers));
1033    reExportDeclaration->SetRange({startLoc, endLoc});
1034
1035    ConsumeSemicolon(reExportDeclaration);
1036
1037    auto reExport = AllocNode<ir::ETSReExportDeclaration>(reExportDeclaration, std::vector<std::string>(),
1038                                                          GetProgram()->SourceFilePath(), Allocator());
1039    reExport->AddModifier(modifiers);
1040    return reExport;
1041}
1042
1043ir::ETSPackageDeclaration *ETSParser::ParsePackageDeclaration()
1044{
1045    auto startLoc = Lexer()->GetToken().Start();
1046
1047    if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_PACKAGE) {
1048        // NOTE(rsipka): Unclear behavior/code. Currently, all entry programs omit the module name if it is not a
1049        // package module and the '--ets-module' option is not specified during compilation
1050        GetProgram()->SetModuleInfo(GetProgram()->FileName(), false, GetProgram()->IsEntryPoint() && !IsETSModule());
1051        return nullptr;
1052    }
1053
1054    Lexer()->NextToken();
1055
1056    ir::Expression *name = ParseQualifiedName();
1057
1058    auto *packageDeclaration = AllocNode<ir::ETSPackageDeclaration>(name);
1059    packageDeclaration->SetRange({startLoc, Lexer()->GetToken().End()});
1060
1061    ConsumeSemicolon(packageDeclaration);
1062
1063    auto packageName =
1064        name->IsIdentifier() ? name->AsIdentifier()->Name() : name->AsTSQualifiedName()->ToString(Allocator());
1065
1066    GetProgram()->SetModuleInfo(packageName, true);
1067
1068    return packageDeclaration;
1069}
1070
1071ir::ImportSource *ETSParser::ParseSourceFromClause(bool requireFrom)
1072{
1073    if (Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_FROM) {
1074        if (requireFrom) {
1075            ThrowSyntaxError("Unexpected token.");
1076        }
1077    } else {
1078        Lexer()->NextToken();  // eat `from`
1079    }
1080
1081    if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_STRING) {
1082        ThrowSyntaxError("Unexpected token.");
1083    }
1084
1085    ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_STRING);
1086    auto importPath = Lexer()->GetToken().Ident();
1087
1088    auto resolvedImportPath = importPathManager_->ResolvePath(GetProgram()->AbsoluteName(), importPath);
1089    if (globalProgram_->AbsoluteName() != resolvedImportPath) {
1090        importPathManager_->AddToParseList(resolvedImportPath,
1091                                           (GetContext().Status() & ParserStatus::IN_DEFAULT_IMPORTS) != 0U
1092                                               ? util::ImportFlags::DEFAULT_IMPORT
1093                                               : util::ImportFlags::NONE);
1094    } else if (!IsETSModule()) {
1095        ThrowSyntaxError("Please compile `" + globalProgram_->FileName().Mutf8() + "." +
1096                         globalProgram_->SourceFile().GetExtension().Mutf8() +
1097                         "` with `--ets-module` option. It is being imported by another file.");
1098    }
1099
1100    auto *resolvedSource = AllocNode<ir::StringLiteral>(resolvedImportPath);
1101    auto importData = importPathManager_->GetImportData(resolvedImportPath, Extension());
1102    auto *source = AllocNode<ir::StringLiteral>(importPath);
1103    source->SetRange(Lexer()->GetToken().Loc());
1104
1105    Lexer()->NextToken();
1106
1107    return Allocator()->New<ir::ImportSource>(source, resolvedSource, importData.lang, importData.hasDecl);
1108}
1109
1110ArenaVector<ir::ETSImportDeclaration *> ETSParser::ParseImportDeclarations()
1111{
1112    std::vector<std::string> userPaths;
1113    ArenaVector<ir::ETSImportDeclaration *> statements(Allocator()->Adapter());
1114
1115    while (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_IMPORT) {
1116        auto startLoc = Lexer()->GetToken().Start();
1117        Lexer()->NextToken();  // eat import
1118
1119        ir::ImportKinds importKind =
1120            Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_TYPE) ? ir::ImportKinds::TYPE : ir::ImportKinds::VALUE;
1121
1122        ArenaVector<ir::AstNode *> specifiers(Allocator()->Adapter());
1123        ArenaVector<ir::AstNode *> defaultSpecifiers(Allocator()->Adapter());
1124
1125        if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) {
1126            if (importKind == ir::ImportKinds::TYPE) {
1127                ThrowSyntaxError("Type import requires selective binding to define the required imported elements.");
1128            }
1129            ParseNameSpaceSpecifier(&specifiers);
1130        } else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
1131            auto specs = ParseNamedSpecifiers();
1132            specifiers = util::Helpers::ConvertVector<ir::AstNode>(specs.first);
1133            defaultSpecifiers = util::Helpers::ConvertVector<ir::AstNode>(specs.second);
1134        } else {
1135            ParseImportDefaultSpecifier(&specifiers);
1136        }
1137        auto pos = Lexer()->Save();
1138        if (!specifiers.empty()) {
1139            ir::ImportSource *importSource = ParseSourceFromClause(true);
1140
1141            lexer::SourcePosition endLoc = importSource->Source()->End();
1142            auto *importDeclaration =
1143                AllocNode<ir::ETSImportDeclaration>(importSource, std::move(specifiers), importKind);
1144            importDeclaration->SetRange({startLoc, endLoc});
1145
1146            ConsumeSemicolon(importDeclaration);
1147            statements.push_back(importDeclaration);
1148        }
1149
1150        if (!defaultSpecifiers.empty()) {
1151            Lexer()->Rewind(pos);
1152            ir::ImportSource *importSourceDefault = ParseSourceFromClause(true);
1153
1154            lexer::SourcePosition endLocDef = importSourceDefault->Source()->End();
1155            auto *importDeclarationDefault =
1156                AllocNode<ir::ETSImportDeclaration>(importSourceDefault, std::move(defaultSpecifiers), importKind);
1157            importDeclarationDefault->SetRange({startLoc, endLocDef});
1158
1159            ConsumeSemicolon(importDeclarationDefault);
1160            util::Helpers::CheckDefaultImport(statements);
1161            statements.push_back(importDeclarationDefault);
1162        }
1163    }
1164
1165    std::sort(statements.begin(), statements.end(), [](const auto *s1, const auto *s2) -> bool {
1166        return s1->Specifiers()[0]->IsImportNamespaceSpecifier() && !s2->Specifiers()[0]->IsImportNamespaceSpecifier();
1167    });
1168    return statements;
1169}
1170
1171ir::ExportNamedDeclaration *ETSParser::ParseSingleExport(ir::ModifierFlags modifiers)
1172{
1173    lexer::Token token = Lexer()->GetToken();
1174    auto *exported = AllocNode<ir::Identifier>(token.Ident(), Allocator());
1175    exported->SetReference();
1176    exported->SetRange(Lexer()->GetToken().Loc());
1177
1178    Lexer()->NextToken();  // eat exported variable name
1179
1180    ArenaVector<ir::ExportSpecifier *> exports(Allocator()->Adapter());
1181
1182    exports.emplace_back(AllocNode<ir::ExportSpecifier>(exported, ParseNamedExport(token)));
1183    auto result = AllocNode<ir::ExportNamedDeclaration>(Allocator(), static_cast<ir::StringLiteral *>(nullptr),
1184                                                        std::move(exports));
1185    result->AddModifier(modifiers);
1186    ConsumeSemicolon(result);
1187
1188    return result;
1189}
1190
1191bool ETSParser::IsDefaultImport()
1192{
1193    if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_DEFAULT) {
1194        Lexer()->NextToken();
1195        if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_AS) {
1196            Lexer()->NextToken();
1197            return true;
1198        }
1199        ThrowSyntaxError("Unexpected token. 'as' keyword is expected.");
1200    }
1201    return false;
1202}
1203
1204using ImportSpecifierVector = ArenaVector<ir::ImportSpecifier *>;
1205using ImportDefaultSpecifierVector = ArenaVector<ir::ImportDefaultSpecifier *>;
1206std::pair<ImportSpecifierVector, ImportDefaultSpecifierVector> ETSParser::ParseNamedSpecifiers()
1207{
1208    // NOTE(user): handle qualifiedName in file bindings: qualifiedName '.' '*'
1209    if (!Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_LEFT_BRACE)) {
1210        ThrowExpectedToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE);
1211    }
1212
1213    auto fileName = GetProgram()->SourceFilePath().Mutf8();
1214
1215    ArenaVector<ir::ImportSpecifier *> result(Allocator()->Adapter());
1216    ArenaVector<ir::ImportDefaultSpecifier *> resultDefault(Allocator()->Adapter());
1217
1218    while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) {
1219        if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) {
1220            ThrowSyntaxError("The '*' token is not allowed as a selective binding (between braces)");
1221        }
1222
1223        if (!IsDefaultImport()) {
1224            if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
1225                ThrowSyntaxError("Unexpected token");
1226            }
1227
1228            lexer::Token importedToken = Lexer()->GetToken();
1229            auto *imported = AllocNode<ir::Identifier>(importedToken.Ident(), Allocator());
1230            ir::Identifier *local = nullptr;
1231            imported->SetReference();
1232            imported->SetRange(Lexer()->GetToken().Loc());
1233
1234            Lexer()->NextToken();
1235
1236            if (CheckModuleAsModifier() && Lexer()->TryEatTokenType(lexer::TokenType::KEYW_AS)) {
1237                local = ParseNamedImport(Lexer()->GetToken());
1238                Lexer()->NextToken();
1239            } else {
1240                local = ParseNamedImport(importedToken);
1241            }
1242
1243            auto *specifier = AllocNode<ir::ImportSpecifier>(imported, local);
1244            specifier->SetRange({imported->Start(), local->End()});
1245
1246            util::Helpers::CheckImportedName(result, specifier, fileName);
1247
1248            result.emplace_back(specifier);
1249        } else {
1250            auto *imported = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
1251            imported->SetReference();
1252            imported->SetRange(Lexer()->GetToken().Loc());
1253            Lexer()->NextToken();
1254            auto *specifier = AllocNode<ir::ImportDefaultSpecifier>(imported);
1255            specifier->SetRange({imported->Start(), imported->End()});
1256
1257            util::Helpers::CheckDefaultImportedName(resultDefault, specifier, fileName);
1258
1259            resultDefault.emplace_back(specifier);
1260        }
1261        if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) {
1262            Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);  // eat comma
1263        }
1264    }
1265    Lexer()->NextToken();  // eat '}'
1266    std::pair<ArenaVector<ir::ImportSpecifier *>, ArenaVector<ir::ImportDefaultSpecifier *>> resultSpecifiers(
1267        result, resultDefault);
1268
1269    return resultSpecifiers;
1270}
1271
1272void ETSParser::ParseNameSpaceSpecifier(ArenaVector<ir::AstNode *> *specifiers, bool isReExport)
1273{
1274    lexer::SourcePosition namespaceStart = Lexer()->GetToken().Start();
1275    Lexer()->NextToken();  // eat `*` character
1276
1277    if (!CheckModuleAsModifier()) {
1278        ThrowSyntaxError("Unexpected token.");
1279    }
1280
1281    // Note (oeotvos) As a temporary solution we allow the stdlib to use namespace import without an alias, but this
1282    // should be handled at some point.
1283    if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_FROM && !isReExport &&
1284        (GetContext().Status() & ParserStatus::IN_DEFAULT_IMPORTS) == 0) {
1285        ThrowSyntaxError("Unexpected token, expected 'as' but found 'from'");
1286    }
1287
1288    auto *local = AllocNode<ir::Identifier>(util::StringView(""), Allocator());
1289    if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA ||
1290        Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_FROM || isReExport) {
1291        local->SetReference();
1292        auto *specifier = AllocNode<ir::ImportNamespaceSpecifier>(local);
1293        specifier->SetRange({namespaceStart, Lexer()->GetToken().End()});
1294        specifiers->push_back(specifier);
1295        return;
1296    }
1297
1298    ExpectToken(lexer::TokenType::KEYW_AS, true);  // eat `as` literal
1299    local = ParseNamedImport(Lexer()->GetToken());
1300
1301    auto *specifier = AllocNode<ir::ImportNamespaceSpecifier>(local);
1302    specifier->SetRange({namespaceStart, Lexer()->GetToken().End()});
1303    specifiers->push_back(specifier);
1304
1305    Lexer()->NextToken();  // eat local name
1306}
1307
1308ir::AstNode *ETSParser::ParseImportDefaultSpecifier(ArenaVector<ir::AstNode *> *specifiers)
1309{
1310    if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
1311        ThrowSyntaxError("Unexpected token, expected an identifier");
1312    }
1313
1314    auto *imported = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
1315    imported->SetReference();
1316    imported->SetRange(Lexer()->GetToken().Loc());
1317    Lexer()->NextToken();  // Eat import specifier.
1318
1319    if (Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_FROM) {
1320        ThrowSyntaxError("Unexpected token, expected 'from'");
1321    }
1322
1323    auto *specifier = AllocNode<ir::ImportDefaultSpecifier>(imported);
1324    specifier->SetRange({imported->Start(), imported->End()});
1325    specifiers->push_back(specifier);
1326
1327    return nullptr;
1328}
1329
1330bool ETSParser::CheckModuleAsModifier()
1331{
1332    if ((Lexer()->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) != 0U) {
1333        ThrowSyntaxError("Escape sequences are not allowed in 'as' keyword");
1334    }
1335
1336    return true;
1337}
1338
1339ir::AnnotatedExpression *ETSParser::GetAnnotatedExpressionFromParam()
1340{
1341    ir::AnnotatedExpression *parameter;
1342
1343    switch (Lexer()->GetToken().Type()) {
1344        case lexer::TokenType::LITERAL_IDENT: {
1345            parameter = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
1346            if (parameter->AsIdentifier()->Decorators().empty()) {
1347                parameter->SetRange(Lexer()->GetToken().Loc());
1348            } else {
1349                parameter->SetRange(
1350                    {parameter->AsIdentifier()->Decorators().front()->Start(), Lexer()->GetToken().End()});
1351            }
1352            break;
1353        }
1354
1355        case lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD: {
1356            const auto startLoc = Lexer()->GetToken().Start();
1357            Lexer()->NextToken();
1358
1359            if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
1360                ThrowSyntaxError("Unexpected token, expected an identifier.");
1361            }
1362
1363            auto *const restIdent = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
1364            restIdent->SetRange(Lexer()->GetToken().Loc());
1365
1366            parameter = AllocNode<ir::SpreadElement>(ir::AstNodeType::REST_ELEMENT, Allocator(), restIdent);
1367            parameter->SetRange({startLoc, Lexer()->GetToken().End()});
1368            break;
1369        }
1370
1371        default: {
1372            ThrowSyntaxError("Unexpected token, expected an identifier.");
1373        }
1374    }
1375
1376    Lexer()->NextToken();
1377    return parameter;
1378}
1379
1380// NOLINTBEGIN(modernize-avoid-c-arrays)
1381static constexpr char const NO_DEFAULT_FOR_REST[] = "Rest parameter cannot have the default value.";
1382static constexpr char const ONLY_ARRAY_FOR_REST[] = "Rest parameter should be of an array type.";
1383static constexpr char const EXPLICIT_PARAM_TYPE[] = "Parameter declaration should have an explicit type annotation.";
1384// NOLINTEND(modernize-avoid-c-arrays)
1385
1386ir::ETSUnionType *ETSParser::CreateOptionalParameterTypeNode(ir::TypeNode *typeAnnotation,
1387                                                             ir::ETSUndefinedType *defaultUndef)
1388{
1389    ArenaVector<ir::TypeNode *> types(Allocator()->Adapter());
1390    if (typeAnnotation->IsETSUnionType()) {
1391        for (auto const &type : typeAnnotation->AsETSUnionType()->Types()) {
1392            types.push_back(type);
1393        }
1394    } else {
1395        types.push_back(typeAnnotation);
1396    }
1397    types.push_back(defaultUndef);
1398
1399    auto *const unionType = AllocNode<ir::ETSUnionType>(std::move(types));
1400    unionType->SetRange({typeAnnotation->Start(), typeAnnotation->End()});
1401    return unionType;
1402}
1403
1404ir::Expression *ETSParser::ParseFunctionParameter()
1405{
1406    auto *const paramIdent = GetAnnotatedExpressionFromParam();
1407
1408    ir::ETSUndefinedType *defaultUndef = nullptr;
1409
1410    if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) {
1411        if (paramIdent->IsRestElement()) {
1412            ThrowSyntaxError(NO_DEFAULT_FOR_REST);
1413        }
1414        defaultUndef = AllocNode<ir::ETSUndefinedType>();
1415        defaultUndef->SetRange({Lexer()->GetToken().Start(), Lexer()->GetToken().End()});
1416        Lexer()->NextToken();  // eat '?'
1417    }
1418
1419    const bool isArrow = (GetContext().Status() & ParserStatus::ARROW_FUNCTION) != 0;
1420
1421    if (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_COLON)) {
1422        TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
1423        ir::TypeNode *typeAnnotation = ParseTypeAnnotation(&options);
1424        if (typeAnnotation == nullptr) {  // Error processing.
1425            return nullptr;
1426        }
1427
1428        if (defaultUndef != nullptr) {
1429            typeAnnotation = CreateOptionalParameterTypeNode(typeAnnotation, defaultUndef);
1430        }
1431
1432        if (paramIdent->IsRestElement() && !typeAnnotation->IsTSArrayType()) {
1433            ThrowSyntaxError(ONLY_ARRAY_FOR_REST);
1434        }
1435
1436        typeAnnotation->SetParent(paramIdent);
1437        paramIdent->SetTsTypeAnnotation(typeAnnotation);
1438        paramIdent->SetEnd(typeAnnotation->End());
1439    } else if (!isArrow && defaultUndef == nullptr) {
1440        ThrowSyntaxError(EXPLICIT_PARAM_TYPE);
1441    }
1442
1443    return ParseFunctionParameterExpression(paramIdent, defaultUndef);
1444}
1445
1446ir::Expression *ETSParser::CreateParameterThis(const util::StringView className)
1447{
1448    auto *paramIdent = AllocNode<ir::Identifier>(varbinder::TypedBinder::MANDATORY_PARAM_THIS, Allocator());
1449    paramIdent->SetRange(Lexer()->GetToken().Loc());
1450
1451    ir::Expression *classTypeName = AllocNode<ir::Identifier>(className, Allocator());
1452    classTypeName->AsIdentifier()->SetReference();
1453    classTypeName->SetRange(Lexer()->GetToken().Loc());
1454
1455    auto typeRefPart = AllocNode<ir::ETSTypeReferencePart>(classTypeName, nullptr, nullptr);
1456    ir::TypeNode *typeAnnotation = AllocNode<ir::ETSTypeReference>(typeRefPart);
1457
1458    typeAnnotation->SetParent(paramIdent);
1459    paramIdent->SetTsTypeAnnotation(typeAnnotation);
1460
1461    auto *paramExpression = AllocNode<ir::ETSParameterExpression>(paramIdent, nullptr);
1462    paramExpression->SetRange({paramIdent->Start(), paramIdent->End()});
1463
1464    return paramExpression;
1465}
1466
1467ir::AnnotatedExpression *ETSParser::ParseVariableDeclaratorKey([[maybe_unused]] VariableParsingFlags flags)
1468{
1469    ir::Identifier *init = ExpectIdentifier();
1470    ir::TypeNode *typeAnnotation = nullptr;
1471    if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) {
1472        if ((flags & VariableParsingFlags::FOR_OF) != 0U) {
1473            ThrowSyntaxError("Optional variable is not allowed in for of statements");
1474        }
1475        Lexer()->NextToken();  // eat '?'
1476        init->AddModifier(ir::ModifierFlags::OPTIONAL);
1477    }
1478
1479    if (auto const tokenType = Lexer()->GetToken().Type(); tokenType == lexer::TokenType::PUNCTUATOR_COLON) {
1480        Lexer()->NextToken();  // eat ':'
1481        TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
1482        typeAnnotation = ParseTypeAnnotation(&options);
1483    } else if (tokenType != lexer::TokenType::PUNCTUATOR_SUBSTITUTION && (flags & VariableParsingFlags::FOR_OF) == 0U) {
1484        ThrowSyntaxError("Variable must be initialized or it's type must be declared");
1485    }
1486
1487    if (typeAnnotation != nullptr) {
1488        init->SetTsTypeAnnotation(typeAnnotation);
1489        typeAnnotation->SetParent(init);
1490    }
1491
1492    return init;
1493}
1494
1495ir::VariableDeclarator *ETSParser::ParseVariableDeclaratorInitializer(ir::Expression *init, VariableParsingFlags flags,
1496                                                                      const lexer::SourcePosition &startLoc)
1497{
1498    if ((flags & VariableParsingFlags::DISALLOW_INIT) != 0) {
1499        ThrowSyntaxError("for-await-of loop variable declaration may not have an initializer");
1500    }
1501
1502    Lexer()->NextToken();
1503
1504    ir::Expression *initializer = ParseExpression();
1505
1506    lexer::SourcePosition endLoc = initializer->End();
1507
1508    auto *declarator = AllocNode<ir::VariableDeclarator>(GetFlag(flags), init, initializer);
1509    declarator->SetRange({startLoc, endLoc});
1510
1511    return declarator;
1512}
1513
1514ir::VariableDeclarator *ETSParser::ParseVariableDeclarator(ir::Expression *init, lexer::SourcePosition startLoc,
1515                                                           VariableParsingFlags flags)
1516{
1517    if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
1518        return ParseVariableDeclaratorInitializer(init, flags, startLoc);
1519    }
1520
1521    if ((flags & VariableParsingFlags::CONST) != 0 &&
1522        static_cast<uint32_t>(flags & VariableParsingFlags::ACCEPT_CONST_NO_INIT) == 0U && !InAmbientContext()) {
1523        ThrowSyntaxError("Missing initializer in const declaration");
1524    }
1525
1526    if (init->AsIdentifier()->TypeAnnotation() == nullptr && (flags & VariableParsingFlags::FOR_OF) == 0U) {
1527        ThrowSyntaxError("Variable must be initialized or it's type must be declared");
1528    }
1529
1530    lexer::SourcePosition endLoc = init->End();
1531    auto declarator = AllocNode<ir::VariableDeclarator>(GetFlag(flags), init);
1532    declarator->SetRange({startLoc, endLoc});
1533
1534    // NOTE (psiket)  Transfer the OPTIONAL flag from the init to the declarator?
1535    return declarator;
1536}
1537
1538ir::Expression *ETSParser::ParseCatchParam()
1539{
1540    if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
1541        ThrowSyntaxError("Unexpected token, expected '('");
1542    }
1543
1544    ir::AnnotatedExpression *param = nullptr;
1545
1546    Lexer()->NextToken();  // eat left paren
1547
1548    if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) {
1549        CheckRestrictedBinding();
1550        param = ExpectIdentifier();
1551    } else {
1552        ThrowSyntaxError("Unexpected token in catch parameter, expected an identifier");
1553    }
1554
1555    ParseCatchParamTypeAnnotation(param);
1556
1557    if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
1558        ThrowSyntaxError("Unexpected token, expected ')'");
1559    }
1560
1561    Lexer()->NextToken();  // eat right paren
1562
1563    return param;
1564}
1565
1566void ETSParser::ParseCatchParamTypeAnnotation([[maybe_unused]] ir::AnnotatedExpression *param)
1567{
1568    if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
1569        Lexer()->NextToken();  // eat ':'
1570
1571        TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
1572        if (auto *typeAnnotation = ParseTypeAnnotation(&options); typeAnnotation != nullptr) {
1573            typeAnnotation->SetParent(param);
1574            param->SetTsTypeAnnotation(typeAnnotation);
1575        }
1576    }
1577
1578    if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
1579        ThrowSyntaxError("Catch clause variable cannot have an initializer");
1580    }
1581}
1582
1583ir::Statement *ETSParser::ParseImportDeclaration([[maybe_unused]] StatementParsingFlags flags)
1584{
1585    char32_t nextChar = Lexer()->Lookahead();
1586    if (nextChar == lexer::LEX_CHAR_LEFT_PAREN || nextChar == lexer::LEX_CHAR_DOT) {
1587        return ParseExpressionStatement();
1588    }
1589
1590    lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
1591    Lexer()->NextToken();  // eat import
1592
1593    ArenaVector<ir::AstNode *> specifiers(Allocator()->Adapter());
1594
1595    ir::ImportSource *importSource = nullptr;
1596
1597    if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_STRING) {
1598        ir::AstNode *astNode = ParseImportSpecifiers(&specifiers);
1599        if (astNode != nullptr) {
1600            ASSERT(astNode->IsTSImportEqualsDeclaration());
1601            astNode->SetRange({startLoc, Lexer()->GetToken().End()});
1602            ConsumeSemicolon(astNode->AsTSImportEqualsDeclaration());
1603            return astNode->AsTSImportEqualsDeclaration();
1604        }
1605        importSource = ParseSourceFromClause(true);
1606    } else {
1607        importSource = ParseSourceFromClause(false);
1608    }
1609
1610    lexer::SourcePosition endLoc = importSource->Source()->End();
1611    auto *importDeclaration = AllocNode<ir::ETSImportDeclaration>(importSource, std::move(specifiers));
1612    importDeclaration->SetRange({startLoc, endLoc});
1613
1614    ConsumeSemicolon(importDeclaration);
1615
1616    return importDeclaration;
1617}
1618
1619ir::Statement *ETSParser::ParseExportDeclaration([[maybe_unused]] StatementParsingFlags flags)
1620{
1621    ThrowUnexpectedToken(lexer::TokenType::KEYW_EXPORT);
1622}
1623
1624ir::Expression *ETSParser::ParseExpressionOrTypeAnnotation(lexer::TokenType type,
1625                                                           [[maybe_unused]] ExpressionParseFlags flags)
1626{
1627    if (type == lexer::TokenType::KEYW_INSTANCEOF) {
1628        TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
1629
1630        if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_NULL) {
1631            auto *typeAnnotation = AllocNode<ir::NullLiteral>();
1632            typeAnnotation->SetRange(Lexer()->GetToken().Loc());
1633            Lexer()->NextToken();
1634
1635            return typeAnnotation;
1636        }
1637
1638        return ParseTypeAnnotation(&options);
1639    }
1640
1641    return ParseExpression(ExpressionParseFlags::DISALLOW_YIELD);
1642}
1643
1644bool ETSParser::ParsePotentialGenericFunctionCall(ir::Expression *primaryExpr, ir::Expression **returnExpression,
1645                                                  [[maybe_unused]] const lexer::SourcePosition &startLoc,
1646                                                  bool ignoreCallExpression)
1647{
1648    if (Lexer()->Lookahead() == lexer::LEX_CHAR_LESS_THAN ||
1649        (!primaryExpr->IsIdentifier() && !primaryExpr->IsMemberExpression())) {
1650        return true;
1651    }
1652
1653    const auto savedPos = Lexer()->Save();
1654
1655    if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT) {
1656        Lexer()->BackwardToken(lexer::TokenType::PUNCTUATOR_LESS_THAN, 1);
1657    }
1658
1659    TypeAnnotationParsingOptions options =
1660        TypeAnnotationParsingOptions::ALLOW_WILDCARD | TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE;
1661    ir::TSTypeParameterInstantiation *typeParams = ParseTypeParameterInstantiation(&options);
1662
1663    if (typeParams == nullptr) {
1664        Lexer()->Rewind(savedPos);
1665        return true;
1666    }
1667
1668    if (Lexer()->GetToken().Type() == lexer::TokenType::EOS) {
1669        ThrowSyntaxError("'(' expected");
1670    }
1671
1672    if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
1673        if (!ignoreCallExpression) {
1674            *returnExpression = ParseCallExpression(*returnExpression, false, false);
1675            (*returnExpression)->AsCallExpression()->SetTypeParams(typeParams);
1676            return false;
1677        }
1678
1679        return true;
1680    }
1681
1682    Lexer()->Rewind(savedPos);
1683    return true;
1684}
1685
1686ir::ModifierFlags ETSParser::ParseTypeVarianceModifier(TypeAnnotationParsingOptions *const options)
1687{
1688    if ((*options & TypeAnnotationParsingOptions::ALLOW_WILDCARD) == 0 &&
1689        (*options & TypeAnnotationParsingOptions::ALLOW_DECLARATION_SITE_VARIANCE) == 0) {
1690        ThrowSyntaxError("Variance modifier is not allowed here.");
1691    }
1692
1693    switch (Lexer()->GetToken().KeywordType()) {
1694        case lexer::TokenType::KEYW_IN: {
1695            Lexer()->NextToken();
1696            return ir::ModifierFlags::IN;
1697        }
1698        case lexer::TokenType::KEYW_OUT: {
1699            Lexer()->NextToken();
1700            return ir::ModifierFlags::OUT;
1701        }
1702        default: {
1703            return ir::ModifierFlags::NONE;
1704        }
1705    }
1706}
1707
1708ir::AstNode *ETSParser::ParseAmbientSignature()
1709{
1710    auto const startPos = Lexer()->GetToken().Start();
1711
1712    if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
1713        ThrowSyntaxError("Unexpected token at", Lexer()->GetToken().Start());
1714    }
1715    auto const indexName = Lexer()->GetToken().Ident();
1716
1717    Lexer()->NextToken();
1718    if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) {
1719        ThrowSyntaxError("Index type expected in index signature", Lexer()->GetToken().Start());
1720    }
1721
1722    Lexer()->NextToken();  // eat ":"
1723    if (Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_NUMBER) {
1724        ThrowSyntaxError("Index type must be number in index signature", Lexer()->GetToken().Start());
1725    }
1726
1727    Lexer()->NextToken();  // eat indexType
1728    if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
1729        ThrowSyntaxError("] expected in index signature", Lexer()->GetToken().Start());
1730    }
1731
1732    Lexer()->NextToken();  // eat "]"
1733    if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) {
1734        ThrowSyntaxError("An index signature must have a type annotation.", Lexer()->GetToken().Start());
1735    }
1736
1737    Lexer()->NextToken();  // eat ":"
1738    if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
1739        ThrowSyntaxError("Return type of index signature from exported class or interface need to be identifier",
1740                         Lexer()->GetToken().Start());
1741    }
1742    auto const returnType =
1743        AllocNode<ir::ETSTypeReferencePart>(AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator()));
1744
1745    auto dummyNode = AllocNode<ir::DummyNode>(compiler::Signatures::AMBIENT_INDEXER, indexName, returnType,
1746                                              ir::DummyNodeFlag::INDEXER);
1747    dummyNode->SetRange({startPos, Lexer()->GetToken().End()});
1748    Lexer()->NextToken();  // eat return type
1749    return dummyNode;
1750}
1751
1752ir::TSTypeParameter *ETSParser::ParseTypeParameter([[maybe_unused]] TypeAnnotationParsingOptions *options)
1753{
1754    lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
1755
1756    const auto varianceModifier = [this, options] {
1757        switch (Lexer()->GetToken().KeywordType()) {
1758            case lexer::TokenType::KEYW_IN:
1759            case lexer::TokenType::KEYW_OUT:
1760                return ParseTypeVarianceModifier(options);
1761            default:
1762                return ir::ModifierFlags::NONE;
1763        }
1764    }();
1765
1766    auto *paramIdent = ExpectIdentifier();
1767
1768    ir::TypeNode *constraint = nullptr;
1769    if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS) {
1770        Lexer()->NextToken();
1771        TypeAnnotationParsingOptions newOptions =
1772            TypeAnnotationParsingOptions::REPORT_ERROR | TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE;
1773        constraint = ParseTypeAnnotation(&newOptions);
1774    }
1775
1776    ir::TypeNode *defaultType = nullptr;
1777
1778    if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
1779        Lexer()->NextToken();  // eat '='
1780        defaultType = ParseTypeAnnotation(options);
1781    }
1782
1783    auto *typeParam = AllocNode<ir::TSTypeParameter>(paramIdent, constraint, defaultType, varianceModifier);
1784
1785    typeParam->SetRange({startLoc, Lexer()->GetToken().End()});
1786    return typeParam;
1787}
1788
1789ir::Identifier *ETSParser::ParseClassIdent([[maybe_unused]] ir::ClassDefinitionModifiers modifiers)
1790{
1791    return ExpectIdentifier(false, true);
1792}
1793
1794bool ETSParser::IsStructKeyword() const
1795{
1796    return (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT &&
1797            Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STRUCT);
1798}
1799
1800void ETSParser::ParseTrailingBlock(ir::CallExpression *callExpr)
1801{
1802    if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
1803        callExpr->SetIsTrailingBlockInNewLine(Lexer()->GetToken().NewLine());
1804        callExpr->SetTrailingBlock(ParseBlockStatement());
1805    }
1806}
1807
1808ir::Expression *ETSParser::ParseCoercedNumberLiteral()
1809{
1810    if ((Lexer()->GetToken().Flags() & lexer::TokenFlags::NUMBER_FLOAT) != 0U) {
1811        auto *number = AllocNode<ir::NumberLiteral>(Lexer()->GetToken().GetNumber());
1812        number->SetRange(Lexer()->GetToken().Loc());
1813        auto *floatType = AllocNode<ir::ETSPrimitiveType>(ir::PrimitiveType::FLOAT);
1814        floatType->SetRange(Lexer()->GetToken().Loc());
1815        auto *asExpression = AllocNode<ir::TSAsExpression>(number, floatType, true);
1816        asExpression->SetRange(Lexer()->GetToken().Loc());
1817
1818        Lexer()->NextToken();
1819        return asExpression;
1820    }
1821    return ParseNumberLiteral();
1822}
1823
1824void ETSParser::CheckDeclare()
1825{
1826    ASSERT(Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_DECLARE);
1827
1828    if (InAmbientContext()) {
1829        ThrowSyntaxError("A 'declare' modifier cannot be used in an already ambient context.");
1830    }
1831
1832    GetContext().Status() |= ParserStatus::IN_AMBIENT_CONTEXT;
1833
1834    Lexer()->NextToken();  // eat 'declare'
1835
1836    switch (Lexer()->GetToken().KeywordType()) {
1837        case lexer::TokenType::KEYW_LET:
1838        case lexer::TokenType::KEYW_CONST:
1839        case lexer::TokenType::KEYW_FUNCTION:
1840        case lexer::TokenType::KEYW_CLASS:
1841        case lexer::TokenType::KEYW_NAMESPACE:
1842        case lexer::TokenType::KEYW_ENUM:
1843        case lexer::TokenType::KEYW_TYPE:
1844        case lexer::TokenType::KEYW_ABSTRACT:
1845        case lexer::TokenType::KEYW_FINAL:
1846        case lexer::TokenType::KEYW_INTERFACE:
1847        case lexer::TokenType::KEYW_ASYNC: {
1848            return;
1849        }
1850        default: {
1851            ThrowSyntaxError("Unexpected token.");
1852        }
1853    }
1854}
1855
1856ir::FunctionDeclaration *ETSParser::ParseFunctionDeclaration(bool canBeAnonymous, ir::ModifierFlags modifiers)
1857{
1858    lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
1859
1860    ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_FUNCTION);
1861    Lexer()->NextToken();
1862    auto newStatus = ParserStatus::NEED_RETURN_TYPE | ParserStatus::ALLOW_SUPER;
1863
1864    if ((modifiers & ir::ModifierFlags::ASYNC) != 0) {
1865        newStatus |= ParserStatus::ASYNC_FUNCTION;
1866    }
1867    if (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_MULTIPLY)) {
1868        newStatus |= ParserStatus::GENERATOR_FUNCTION;
1869    }
1870
1871    ir::Identifier *className = nullptr;
1872    ir::Identifier *identNode = nullptr;
1873    if (Lexer()->Lookahead() == lexer::LEX_CHAR_DOT) {
1874        className = ExpectIdentifier();
1875        if (className != nullptr) {
1876            newStatus |= ParserStatus::IN_EXTENSION_FUNCTION;
1877        }
1878        Lexer()->NextToken();
1879        identNode = ExpectIdentifier();
1880    } else if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) {
1881        identNode = ExpectIdentifier();
1882    } else if (!canBeAnonymous) {
1883        LogSyntaxError("Unexpected token, expected identifier after 'function' keyword");
1884    }
1885    newStatus |= ParserStatus::FUNCTION_DECLARATION;
1886    if (identNode != nullptr) {
1887        CheckRestrictedBinding(identNode->Name(), identNode->Start());
1888    }
1889
1890    ir::ScriptFunction *func = ParseFunction(newStatus, className);
1891    if (identNode != nullptr) {  // Error processing.
1892        func->SetIdent(identNode);
1893    }
1894
1895    auto *funcDecl = AllocNode<ir::FunctionDeclaration>(Allocator(), func);
1896    if (func->IsOverload() && Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) {
1897        Lexer()->NextToken();
1898    }
1899    funcDecl->SetRange(func->Range());
1900    func->AddModifier(modifiers);
1901    func->SetStart(startLoc);
1902
1903    if (className != nullptr) {
1904        func->AddFlag(ir::ScriptFunctionFlags::INSTANCE_EXTENSION_METHOD);
1905    }
1906
1907    return funcDecl;
1908}
1909
1910void ETSParser::AddPackageSourcesToParseList()
1911{
1912    importPathManager_->AddToParseList(GetProgram()->SourceFileFolder(), util::ImportFlags::IMPLICIT_PACKAGE_IMPORT);
1913
1914    // Global program file is always in the same folder that we scanned, but we don't need to parse it twice
1915    importPathManager_->MarkAsParsed(globalProgram_->SourceFilePath());
1916}
1917
1918//================================================================================================//
1919//  ExternalSourceParser class
1920//================================================================================================//
1921
1922ExternalSourceParser::ExternalSourceParser(ETSParser *parser, Program *newProgram)
1923    : parser_(parser),
1924      savedProgram_(parser_->GetProgram()),
1925      savedLexer_(parser_->Lexer()),
1926      savedTopScope_(parser_->GetProgram()->VarBinder()->TopScope())
1927{
1928    parser_->SetProgram(newProgram);
1929    parser_->GetContext().SetProgram(newProgram);
1930}
1931
1932ExternalSourceParser::~ExternalSourceParser()
1933{
1934    parser_->SetLexer(savedLexer_);
1935    parser_->SetProgram(savedProgram_);
1936    parser_->GetContext().SetProgram(savedProgram_);
1937    parser_->GetProgram()->VarBinder()->ResetTopScope(savedTopScope_);
1938}
1939
1940//================================================================================================//
1941//  InnerSourceParser class
1942//================================================================================================//
1943
1944InnerSourceParser::InnerSourceParser(ETSParser *parser)
1945    : parser_(parser),
1946      savedLexer_(parser_->Lexer()),
1947      savedSourceCode_(parser_->GetProgram()->SourceCode()),
1948      savedSourceFile_(parser_->GetProgram()->SourceFilePath()),
1949      savedSourceFilePath_(parser_->GetProgram()->SourceFileFolder())
1950{
1951}
1952
1953InnerSourceParser::~InnerSourceParser()
1954{
1955    parser_->SetLexer(savedLexer_);
1956    parser_->GetProgram()->SetSource(savedSourceCode_, savedSourceFile_, savedSourceFilePath_);
1957}
1958}  // namespace ark::es2panda::parser
1959