* Copyright (c) 2021-2026 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ETSparser.h"
#include <string_view>
#include "ETSNolintParser.h"
#include "compiler/metadata/deserialization.h"
#include "program/program.h"
#include "program/ImportCache.h"
#include "public/public.h"
#include "driver/dependency_analyzer/dep_analyzer.h"
#include "parser/parserStatusContext.h"
#include "util/es2pandaMacros.h"
#include "util/helpers.h"
#include "util/language.h"
#include "varbinder/varbinder.h"
#include "varbinder/ETSBinder.h"
#include "lexer/lexer.h"
#include "lexer/ETSLexer.h"
#include "ir/astNode.h"
#include "ir/base/decorator.h"
#include "ir/base/catchClause.h"
#include "ir/base/scriptFunction.h"
#include "ir/base/methodDefinition.h"
#include "ir/base/spreadElement.h"
#include "ir/expressions/identifier.h"
#include "ir/expressions/functionExpression.h"
#include "ir/expressions/dummyNode.h"
#include "ir/module/importDeclaration.h"
#include "ir/module/importDefaultSpecifier.h"
#include "ir/module/importSpecifier.h"
#include "ir/module/exportSpecifier.h"
#include "ir/module/exportNamedDeclaration.h"
#include "ir/ets/etsPrimitiveType.h"
#include "ir/ets/etsPackageDeclaration.h"
#include "ir/ets/etsReExportDeclaration.h"
#include "ir/ets/etsTuple.h"
#include "ir/ets/etsFunctionType.h"
#include "ir/ets/etsModule.h"
#include "ir/ets/etsTypeReference.h"
#include "ir/ets/etsTypeReferencePart.h"
#include "ir/ets/etsUnionType.h"
#include "ir/ets/etsImportDeclaration.h"
#include "ir/ets/etsStructDeclaration.h"
#include "ir/module/importNamespaceSpecifier.h"
#include "ir/ts/tsInterfaceDeclaration.h"
#include "ir/ts/tsTypeParameterInstantiation.h"
#include "ir/ts/tsInterfaceBody.h"
#include "ir/ts/tsImportEqualsDeclaration.h"
#include "ir/ts/tsArrayType.h"
#include "ir/ts/tsTypeReference.h"
#include "ir/ts/tsTypeParameter.h"
#include "ir/ts/tsInterfaceHeritage.h"
#include "ir/ts/tsFunctionType.h"
#include "ir/ts/tsTypeAliasDeclaration.h"
#include "ir/ts/tsTypeParameterDeclaration.h"
#include "generated/signatures.h"
#include "generated/diagnostic.h"
namespace ark::es2panda::parser {
class FunctionContext;
using namespace std::literals::string_literals;
ETSParser::ETSParser(public_lib::Context *context, ParserStatus status)
: TypedParser(context, status), packageDeprecationWarned_(false)
{
}
Program *ETSParser::GetGlobalProgram() const
{
return Context()->parserProgram;
}
bool ETSParser::IsValidIdentifierName(const lexer::Token &token) const noexcept
{
return !token.IsPredefinedType() || util::Helpers::IsStdLib(GetProgram());
}
std::unique_ptr<lexer::Lexer> ETSParser::InitLexer()
{
ES2PANDA_ASSERT(GetProgram() == GetContext().GetProgram());
auto lexer = std::make_unique<lexer::ETSLexer>(&GetContext(), DiagnosticEngine());
if (GetProgram()->Is<util::ModuleKind::ETSCACHE_DECL>()) {
lexer->SetDefaultNextTokenFlags(lexer::NextTokenFlags::CHAR_PERCENT_ALLOWED);
}
SetLexer(lexer.get());
return lexer;
}
static void DoSomethingSpecificToMainProgram(ETSParser *parser)
{
#ifndef ENABLE_ISOLATED_DECLGEN
std::vector<parser::Program *> directImportsFromMainSource {};
for (auto directImport : parser->GetImportPathManager()->GetParseQueue()) {
if (directImport.program == parser->Context()->parserProgram) {
continue;
}
directImportsFromMainSource.emplace_back(directImport.program);
}
parser->AddDirectImportsToDirectExternalDecls(directImportsFromMainSource);
#endif
auto mainProg = parser->Context()->parserProgram;
if (mainProg->ModuleInfo().kind == util::ModuleKind::PACKAGE) {
auto *package = parser->GetImportPathManager()->SearchResolved(mainProg->GetImportInfo());
if (package->Is<util::ModuleKind::PACKAGE>()) {
ES2PANDA_ASSERT(package != mainProg);
[[maybe_unused]] auto &fractions = package->As<util::ModuleKind::PACKAGE>()->GetUnmergedPackagePrograms();
ES2PANDA_ASSERT(std::find(fractions.begin(), fractions.end(), mainProg) != fractions.end());
package->PromoteToMainProgram(parser->Context());
}
}
}
void ETSParser::ParseGlobalImpl()
{
ES2PANDA_ASSERT(GetProgram() != nullptr);
ES2PANDA_ASSERT(GetProgram() == Context()->parserProgram);
ParseSource(GetProgram());
GetImportPathManager()->GetParseQueue().front().isParsed = true;
ES2PANDA_ASSERT(GetImportPathManager()->GetParseQueue().front().program == GetProgram());
if (GetContext().IsIncrementalDependencyAnalyzerMode()) {
return;
}
DoSomethingSpecificToMainProgram(this);
ParseSources();
}
ir::ExpressionStatement *ETSParser::ParseFileHeaderFlag()
{
if (Lexer()->GetToken().KeywordType() != lexer::TokenType::LITERAL_STRING ||
Lexer()->GetToken().String() != compiler::Signatures::STATIC_PROGRAM_FLAG) {
return nullptr;
}
auto startLoc = Lexer()->GetToken().Start();
ir::Expression *fileHeaderFlag = ParseStringLiteral();
auto *exprStatementNode = AllocNode<ir::ExpressionStatement>(fileHeaderFlag);
ES2PANDA_ASSERT(exprStatementNode != nullptr);
exprStatementNode->SetRange({startLoc, fileHeaderFlag->End()});
ConsumeSemicolon(exprStatementNode);
return exprStatementNode;
}
ir::ETSModule *ETSParser::ParseETSGlobalScript(lexer::SourcePosition startLoc, ArenaVector<ir::Statement *> &statements)
{
ETSNolintParser etsnolintParser(this);
etsnolintParser.CollectETSNolints();
auto imports = ParseImportDeclarations();
statements.insert(statements.end(), imports.begin(), imports.end());
auto topLevelStatements = ParseTopLevelDeclaration();
statements.insert(statements.end(), topLevelStatements.begin(), topLevelStatements.end());
etsnolintParser.ApplyETSNolintsToStatements(statements);
auto ident = AllocNode<ir::Identifier>(compiler::Signatures::ETS_GLOBAL, Allocator());
auto *etsModule = AllocNode<ir::ETSModule>(Allocator(), std::move(statements), ident, ir::ModuleFlag::ETSSCRIPT,
GetContext().GetLanguage(), GetProgram());
ES2PANDA_ASSERT(etsModule != nullptr);
etsModule->SetRange({startLoc, Lexer()->GetToken().End()});
for (auto topLevelStatement : topLevelStatements) {
if (topLevelStatement->IsETSReExportDeclaration()) {
topLevelStatement->AsETSReExportDeclaration()->GetETSImportDeclarations()->SetParent(etsModule);
}
}
return etsModule;
}
ir::ETSModule *ETSParser::ParseImportsAndReExportOnly(lexer::SourcePosition startLoc,
ArenaVector<ir::Statement *> &statements)
{
ETSNolintParser etsnolintParser(this);
etsnolintParser.CollectETSNolints();
auto imports = ParseImportDeclarations();
statements.insert(statements.end(), imports.begin(), imports.end());
etsnolintParser.ApplyETSNolintsToStatements(statements);
auto ident = AllocNode<ir::Identifier>(compiler::Signatures::ETS_GLOBAL, Allocator());
auto *etsModule = AllocNode<ir::ETSModule>(Allocator(), std::move(statements), ident, ir::ModuleFlag::ETSSCRIPT,
GetContext().GetLanguage(), GetProgram());
ES2PANDA_ASSERT(etsModule != nullptr);
etsModule->SetRange({startLoc, Lexer()->GetToken().End()});
return etsModule;
}
parser::Program *ETSParser::IntroduceStdlibImportProgram(std::string &&importSrc)
{
auto *stdlibImportProgram = GetImportPathManager()->IntroduceStdlibImportProgram(std::move(importSrc));
if (stdlibImportProgram->Ast() != nullptr) {
return stdlibImportProgram;
}
ES2PANDA_ASSERT(GetImportPathManager()->GetParseQueue().back().program == stdlibImportProgram);
ES2PANDA_ASSERT(!GetImportPathManager()->GetParseQueue().back().isParsed);
GetContext().Status() |= ParserStatus::IN_DEFAULT_IMPORTS;
ParseSources();
GetContext().Status() &= ~ParserStatus::IN_DEFAULT_IMPORTS;
return stdlibImportProgram;
}
void ETSParser::AddDirectImportsToDirectExternalDecls(
const std::vector<parser::Program *> &directImportsFromMainSource) const
{
ES2PANDA_ASSERT(GetProgram() == GetGlobalProgram());
auto &directExtSourcesHolder = GetGlobalProgram()->GetExternalDecls()->Direct();
for (auto *prog : directImportsFromMainSource) {
auto key = prog->GetImportInfo().ResolvedSource();
directExtSourcesHolder.insert({ArenaString {key}, prog});
}
}
void ETSParser::IncrementalParse()
{
ES2PANDA_ASSERT(Context()->parserProgram != nullptr);
SetProgram(Context()->parserProgram);
GetContext().SetProgram(Context()->parserProgram);
GetContext().SetLanguage(ToLanguage(Context()->parserProgram->Extension()));
ES2PANDA_ASSERT(Context()->parserProgram == GetProgram());
ES2PANDA_ASSERT(GetProgram() != nullptr);
ParseSource(GetProgram());
GetImportPathManager()->GetParseQueue().front().isParsed = true;
ES2PANDA_ASSERT(GetImportPathManager()->GetParseQueue().front().program == GetProgram());
DoSomethingSpecificToMainProgram(this);
ParseSources();
}
void ETSParser::ParseInSimultMode()
{
ES2PANDA_ASSERT(Context()->parserProgram == nullptr);
ES2PANDA_ASSERT(GetImportPathManager()->GetParseQueue().empty());
GetImportPathManager()->InitParseQueueForSimult();
ES2PANDA_ASSERT(Context()->parserProgram != nullptr);
SetProgram(Context()->parserProgram);
GetContext().SetProgram(Context()->parserProgram);
GetContext().SetLanguage(ToLanguage(Context()->parserProgram->Extension()));
std::vector<parser::Program *> directImportsFromMainSource {};
for (auto directImport : GetImportPathManager()->GetParseQueue()) {
ES2PANDA_ASSERT(!directImport.isParsed);
directImportsFromMainSource.emplace_back(directImport.program);
}
ParseSources();
AddDirectImportsToDirectExternalDecls(directImportsFromMainSource);
}
void ETSParser::ParseSources()
{
auto &parseQueue = GetImportPathManager()->GetParseQueue();
for (size_t i = 0; i < parseQueue.size(); i++) {
if (!parseQueue[i].isParsed) {
ParseNotParsed(&parseQueue[i]);
}
}
}
void ETSParser::ParseNotParsed(util::ImportPathManager::ParseInfo *notParsedElement)
{
ES2PANDA_ASSERT(!notParsedElement->isParsed);
notParsedElement->isParsed = true;
const auto &data = notParsedElement->program->GetImportInfo();
ES2PANDA_ASSERT(notParsedElement->program != GetGlobalProgram());
ES2PANDA_ASSERT(data.Lang() != Language::Id::COUNT);
auto preservedLang = GetContext().SetLanguage(data.Lang());
if (GetContext().IsDependencyAnalyzerMode()) {
const auto *depAnalyzer = Context()->depAnalyzer;
ES2PANDA_ASSERT(depAnalyzer != nullptr);
if (depAnalyzer->GetAlreadyProcessedFiles().count(std::string {data.ResolvedSource()}) > 0) {
return;
}
}
ParseSource(notParsedElement->program);
GetContext().SetLanguage(preservedLang);
}
void ETSParser::ParseSource(parser::Program *program)
{
auto esp = ExternalSourceParser(this, program);
ES2PANDA_ASSERT(GetProgram() == program);
ES2PANDA_ASSERT(GetProgram()->Ast() == nullptr);
auto lexer = InitLexer();
lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
Lexer()->NextToken();
ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
ir::Statement *header = ParseFileHeaderFlag();
ir::Statement *packageDecl = ParsePackageDeclaration();
for (auto st : {header, packageDecl}) {
if (st != nullptr) {
statements.push_back(st);
}
}
ir::ETSModule *script = nullptr;
if (GetContext().IsDependencyAnalyzerMode()) {
script = ParseImportsAndReExportOnly(startLoc, statements);
} else {
script = ParseETSGlobalScript(startLoc, statements);
}
if ((GetContext().Status() & ParserStatus::IN_PACKAGE) != 0) {
GetContext().Status() &= ~ParserStatus::IN_PACKAGE;
}
program->SetAst(script);
}
ir::Statement *ETSParser::ParseIdentKeyword()
{
const auto token = Lexer()->GetToken();
ES2PANDA_ASSERT(token.Type() == lexer::TokenType::LITERAL_IDENT);
switch (token.KeywordType()) {
case lexer::TokenType::KEYW_STRUCT: {
return ParseTypeDeclaration(false);
}
case lexer::TokenType::KEYW_TYPE: {
return ParseTypeAliasDeclaration();
}
default: {
break;
}
}
return nullptr;
}
ir::ScriptFunction *ETSParser::ParseFunction(ParserStatus newStatus)
{
FunctionContext functionContext(this, newStatus | ParserStatus::FUNCTION);
lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
auto [signature, throwMarker] = ParseFunctionSignature(newStatus);
ir::AstNode *body = nullptr;
lexer::SourcePosition endLoc = Lexer()->GetToken().Start();
bool isOverload = false;
bool isArrow = (newStatus & ParserStatus::ARROW_FUNCTION) != 0;
if ((newStatus & ParserStatus::ASYNC_FUNCTION) != 0) {
functionContext.AddFlag(ir::ScriptFunctionFlags::ASYNC);
}
if (isArrow) {
ExpectToken(lexer::TokenType::PUNCTUATOR_ARROW);
functionContext.AddFlag(ir::ScriptFunctionFlags::ARROW);
}
auto &contextStatus = GetContext().Status();
contextStatus |= ParserStatus::ALLOW_SUPER;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
std::tie(std::ignore, body, endLoc, isOverload) =
ParseFunctionBody(signature.Params(), newStatus, contextStatus);
} else if (isArrow) {
body = ParseExpression();
endLoc = body->AsExpression()->End();
functionContext.AddFlag(ir::ScriptFunctionFlags::EXPRESSION);
}
contextStatus ^= ParserStatus::ALLOW_SUPER;
if ((GetContext().Status() & ParserStatus::FUNCTION_HAS_RETURN_STATEMENT) != 0) {
functionContext.AddFlag(ir::ScriptFunctionFlags::HAS_RETURN);
GetContext().Status() ^= ParserStatus::FUNCTION_HAS_RETURN_STATEMENT;
}
if ((GetContext().Status() & ParserStatus::FUNCTION_HAS_THROW_STATEMENT) != 0) {
functionContext.AddFlag(ir::ScriptFunctionFlags::HAS_THROW);
GetContext().Status() ^= ParserStatus::FUNCTION_HAS_THROW_STATEMENT;
}
functionContext.AddFlag(throwMarker);
bool isDeclare = InAmbientContext();
if (functionContext.IsAsync() && isDeclare) {
LogError(diagnostic::ASYNC_IN_AMBIENT_CONTEXT);
}
if (isDeclare && signature.ReturnType() != nullptr) {
endLoc = signature.ReturnType()->Range().end;
}
ir::ModifierFlags mFlags = isDeclare ? ir::ModifierFlags::DECLARE : ir::ModifierFlags::NONE;
ir::ScriptFunctionFlags funcFlags =
isDeclare ? (functionContext.Flags() | ir::ScriptFunctionFlags::EXTERNAL) : functionContext.Flags();
auto *funcNode = AllocNode<ir::ScriptFunction>(
Allocator(), ir::ScriptFunction::ScriptFunctionData {body, std::move(signature), funcFlags, mFlags,
GetContext().GetLanguage()});
ES2PANDA_ASSERT(funcNode != nullptr);
funcNode->SetRange({startLoc, endLoc});
return funcNode;
}
std::tuple<bool, ir::BlockStatement *, lexer::SourcePosition, bool> ETSParser::ParseFunctionBody(
[[maybe_unused]] const ArenaVector<ir::Expression *> ¶ms, [[maybe_unused]] ParserStatus newStatus,
[[maybe_unused]] ParserStatus contextStatus)
{
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
LogError(diagnostic::EXPECTED_PARAM_GOT_PARAM, {"{", TokenToString(Lexer()->GetToken().Type())});
return {false, nullptr, Lexer()->GetToken().End(), false};
}
if (InAmbientContext()) {
LogError(diagnostic::IMPLEMENTATION_IN_AMBIENT_CONTEXT, {}, Lexer()->GetToken().Start());
}
ir::BlockStatement *body = ParseBlockStatement();
ES2PANDA_ASSERT(body != nullptr);
return {true, body, body->End(), false};
}
ir::AstNode *ETSParser::ParseInnerTypeDeclaration(ir::ModifierFlags memberModifiers, lexer::LexerPosition savedPos,
bool isStepToken, bool seenStatic)
{
if ((GetContext().Status() & ParserStatus::IN_NAMESPACE) == 0) {
LogError(diagnostic::IMPROPER_NESTING_CLASS);
}
Lexer()->Rewind(savedPos);
if (isStepToken) {
Lexer()->NextToken();
}
Lexer()->GetToken().SetTokenType(Lexer()->GetToken().KeywordType());
ir::AstNode *typeDecl = ParseTypeDeclaration(true);
if (typeDecl == nullptr) {
return nullptr;
}
memberModifiers &= (ir::ModifierFlags::PUBLIC | ir::ModifierFlags::PROTECTED | ir::ModifierFlags::PRIVATE);
typeDecl->AddModifier(memberModifiers);
if (!seenStatic) {
if (typeDecl->IsClassDeclaration()) {
typeDecl->AsClassDeclaration()->Definition()->AsClassDefinition()->SetInnerModifier();
} else if (typeDecl->IsETSStructDeclaration()) {
typeDecl->AsETSStructDeclaration()->Definition()->AsClassDefinition()->SetInnerModifier();
}
}
return typeDecl;
}
ir::AstNode *ETSParser::ParseInnerConstructorDeclaration(ir::ModifierFlags memberModifiers,
const lexer::SourcePosition &startLoc, bool isDefault)
{
if ((memberModifiers & (~(ir::ModifierFlags::ACCESS | ir::ModifierFlags::DECLARE | ir::ModifierFlags::NATIVE))) !=
0) {
LogError(diagnostic::INVALID_DECORATOR_CONSTRUCTOR);
}
lexer::Token constructorToken = Lexer()->GetToken();
Lexer()->TryEatTokenType(lexer::TokenType::KEYW_CONSTRUCTOR);
memberModifiers |= ir::ModifierFlags::CONSTRUCTOR;
ir::Identifier *memberName = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) {
memberName = ExpectIdentifier(false, true);
} else {
memberName = AllocNode<ir::Identifier>(constructorToken.Ident(), Allocator());
memberName->SetRange(constructorToken.Loc());
}
auto *classMethod = ParseClassMethodDefinition(memberName, memberModifiers, isDefault);
ES2PANDA_ASSERT(classMethod != nullptr);
classMethod->SetStart(startLoc);
return classMethod;
}
ir::Identifier *ETSParser::CreateInvokeIdentifier()
{
util::StringView tokenName = util::StringView {compiler::Signatures::STATIC_INVOKE_METHOD};
auto ident = AllocNode<ir::Identifier>(tokenName, Allocator());
ES2PANDA_ASSERT(ident != nullptr);
ident->SetRange({Lexer()->GetToken().Start(), Lexer()->GetToken().End()});
return ident;
}
bool ETSParser::CheckAccessorDeclaration(ir::ModifierFlags memberModifiers)
{
if (Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_GET &&
Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_SET) {
return false;
}
ir::ModifierFlags methodModifiersNotAccessorModifiers = ir::ModifierFlags::ASYNC;
if ((memberModifiers & methodModifiersNotAccessorModifiers) != 0) {
LogError(diagnostic::MODIFIERS_OF_GET_SET_LIMITED);
}
auto pos = Lexer()->Save();
Lexer()->NextToken();
if (Lexer()->TryEatTokenType(lexer::TokenType::LITERAL_IDENT) ||
Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_FORMAT)) {
Lexer()->Rewind(pos);
return true;
}
Lexer()->Rewind(pos);
return false;
}
ir::AstNode *ETSParser::ParseInnerRest(const ArenaVector<ir::AstNode *> &properties,
ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags memberModifiers,
const lexer::SourcePosition &startLoc, bool isDefault)
{
if (CheckAccessorDeclaration(memberModifiers)) {
return ParseClassGetterSetterMethod(properties, modifiers, memberModifiers, isDefault);
}
auto parseClassMethod = [&memberModifiers, isDefault, this](ir::Identifier *methodName) {
auto *classMethod = ParseClassMethodDefinition(methodName, memberModifiers, isDefault);
ES2PANDA_ASSERT(classMethod != nullptr);
classMethod->SetStart(methodName->Start());
return classMethod;
};
if (InAmbientContext()) {
if (auto *property = HandleAmbientDeclaration(memberModifiers, parseClassMethod); property != nullptr) {
return property;
}
}
if (Lexer()->TryEatTokenFromKeywordType(lexer::TokenType::KEYW_OVERLOAD)) {
auto *classOverload = ParseClassOverloadDeclaration(memberModifiers);
classOverload->SetStart(startLoc);
return classOverload;
}
auto *memberName = ExpectIdentifier(false, false, TypeAnnotationParsingOptions::NO_OPTS);
if (memberName == nullptr) {
auto tokenType = Lexer()->GetToken().Type();
if (Lexer()->TryEatTokenType(lexer::TokenType::KEYW_NEW) ||
Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
LogError(diagnostic::CALL_SIG_IN_OBJECT,
{tokenType == lexer::TokenType::KEYW_NEW ? "Constructor" : "Call"});
auto *ident = AllocNode<ir::Identifier>("dummy", Allocator());
parseClassMethod(ident);
return AllocBrokenStatement(Lexer()->GetToken().Loc());
}
LogUnexpectedToken(Lexer()->GetToken());
const auto &rangeToken = Lexer()->GetToken().Loc();
Lexer()->NextToken();
return AllocBrokenStatement(rangeToken);
}
if (memberName->IsErrorPlaceHolder()) {
return AllocBrokenStatement(startLoc);
}
ThrowOptionalMethodErrorIfNeeded();
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS ||
Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
return parseClassMethod(memberName);
}
ArenaVector<ir::AstNode *> fieldDeclarations(Allocator()->Adapter());
auto *placeholder = AllocNode<ir::TSInterfaceBody>(std::move(fieldDeclarations));
ES2PANDA_ASSERT(placeholder != nullptr);
ParseClassFieldDefinition(memberName, memberModifiers, placeholder->BodyPtr(), isDefault);
return placeholder;
}
ir::Statement *ETSParser::ParseTypeDeclarationAbstractFinal(bool allowStatic, ir::ClassDefinitionModifiers modifiers)
{
auto flags = ParseClassModifiers();
if (allowStatic && (flags & ir::ModifierFlags::STATIC) == 0U) {
modifiers |= ir::ClassDefinitionModifiers::INNER;
}
if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS) {
return ParseClassDeclaration(modifiers, flags);
}
if (IsStructKeyword()) {
return ParseStructDeclaration(modifiers, flags);
}
LogUnexpectedToken(Lexer()->GetToken());
return AllocBrokenStatement(Lexer()->GetToken().Loc());
}
ir::Statement *ETSParser::ParseTypeDeclaration(bool allowStatic)
{
auto savedPos = Lexer()->Save();
auto modifiers = ir::ClassDefinitionModifiers::ID_REQUIRED | ir::ClassDefinitionModifiers::CLASS_DECL;
auto tokenType = Lexer()->GetToken().Type();
switch (tokenType) {
case lexer::TokenType::KEYW_STATIC:
if (!allowStatic) {
LogUnexpectedToken(Lexer()->GetToken());
}
Lexer()->NextToken();
if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_INTERFACE) {
return ParseInterfaceDeclaration(true);
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
Lexer()->Rewind(savedPos);
return ParseClassStaticBlock();
}
Lexer()->Rewind(savedPos);
[[fallthrough]];
case lexer::TokenType::KEYW_ABSTRACT:
case lexer::TokenType::KEYW_FINAL:
return ParseTypeDeclarationAbstractFinal(allowStatic, modifiers);
case lexer::TokenType::KEYW_ENUM:
return ParseEnumDeclaration(false);
case lexer::TokenType::KEYW_INTERFACE:
return ParseInterfaceDeclaration(false);
case lexer::TokenType::KEYW_CLASS:
return ParseClassDeclaration(modifiers);
case lexer::TokenType::KEYW_STRUCT:
return ParseStructDeclaration(modifiers);
case lexer::TokenType::LITERAL_IDENT:
if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STRUCT) {
return ParseStructDeclaration(modifiers);
}
[[fallthrough]];
default:
const auto &tokenNow = Lexer()->GetToken();
LogUnexpectedToken(tokenNow);
return AllocBrokenStatement(tokenNow.Loc());
}
}
ir::TSTypeAliasDeclaration *ETSParser::ParseTypeAliasDeclaration()
{
ES2PANDA_ASSERT(Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_TYPE);
const auto start = Lexer()->Save();
lexer::SourcePosition typeStart = Lexer()->GetToken().Start();
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
Lexer()->Rewind(start);
return nullptr;
}
if (Lexer()->GetToken().IsReservedTypeName() && !util::Helpers::IsStdLib(GetProgram())) {
LogError(diagnostic::TYPE_ALIAS_INVALID_NAME, {TokenToString(Lexer()->GetToken().KeywordType())});
}
ir::Identifier *id = ExpectIdentifier();
auto *typeAliasDecl = AllocNode<ir::TSTypeAliasDeclaration>(Allocator(), id);
ES2PANDA_ASSERT(typeAliasDecl != nullptr);
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
auto options =
TypeAnnotationParsingOptions::REPORT_ERROR | TypeAnnotationParsingOptions::ALLOW_DECLARATION_SITE_VARIANCE;
ir::TSTypeParameterDeclaration *params = ParseTypeParameterDeclaration(&options);
typeAliasDecl->SetTypeParameters(params);
params->SetParent(typeAliasDecl);
}
ExpectToken(lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
if (Lexer()->TryEatTokenFromKeywordType(lexer::TokenType::KEYW_NEW)) {
LogError(diagnostic::CONSTRUCTOR_FUNC_TYPE_NOT_SUPPORTED, {}, typeStart);
typeAliasDecl->SetTsTypeAnnotation(AllocBrokenType(typeStart));
}
TypeAnnotationParsingOptions options =
TypeAnnotationParsingOptions::REPORT_ERROR | TypeAnnotationParsingOptions::TYPE_ALIAS_CONTEXT;
ir::TypeNode *typeAnnotation = ParseTypeAnnotation(&options);
if (typeAnnotation == nullptr) {
return nullptr;
}
if (typeAliasDecl->TypeAnnotation() == nullptr) {
typeAliasDecl->SetTsTypeAnnotation(typeAnnotation);
}
typeAnnotation->SetParent(typeAliasDecl);
typeAliasDecl->SetRange({typeStart, typeAnnotation->End()});
return typeAliasDecl;
}
std::string ETSParser::PrimitiveTypeToName(ir::PrimitiveType type) const
{
switch (type) {
case ir::PrimitiveType::BYTE:
return "byte";
case ir::PrimitiveType::INT:
return "int";
case ir::PrimitiveType::LONG:
return "long";
case ir::PrimitiveType::SHORT:
return "short";
case ir::PrimitiveType::FLOAT:
return "float";
case ir::PrimitiveType::DOUBLE:
return "double";
case ir::PrimitiveType::BOOLEAN:
return "boolean";
case ir::PrimitiveType::CHAR:
return "char";
case ir::PrimitiveType::VOID:
return "void";
default:
ES2PANDA_UNREACHABLE();
}
}
std::string ETSParser::GetNameForETSUnionType(const ir::TypeNode *typeAnnotation) const
{
ES2PANDA_ASSERT(typeAnnotation->IsETSUnionType());
std::string newstr;
for (size_t i = 0; i < typeAnnotation->AsETSUnionType()->Types().size(); i++) {
auto type = typeAnnotation->AsETSUnionType()->Types()[i];
std::string str = GetNameForTypeNode(type);
newstr += str;
if (i != typeAnnotation->AsETSUnionType()->Types().size() - 1) {
newstr += "|";
}
}
return newstr;
}
std::string ETSParser::GetNameForTypeNode(const ir::TypeNode *typeAnnotation) const
{
if (typeAnnotation->IsETSUnionType()) {
return GetNameForETSUnionType(typeAnnotation);
}
if (typeAnnotation->IsETSPrimitiveType()) {
return PrimitiveTypeToName(typeAnnotation->AsETSPrimitiveType()->GetPrimitiveType());
}
if (typeAnnotation->IsETSTypeReference()) {
std::string typeParamNames;
auto typeParam = typeAnnotation->AsETSTypeReference()->Part()->TypeParams();
if (typeParam != nullptr && typeParam->IsTSTypeParameterInstantiation()) {
typeParamNames = "<";
auto paramList = typeParam->Params();
for (auto param : paramList) {
std::string typeParamName = GetNameForTypeNode(param);
typeParamNames += typeParamName + ",";
}
typeParamNames.pop_back();
typeParamNames += ">";
}
return typeAnnotation->AsETSTypeReference()->Part()->GetIdent()->Name().Mutf8() + typeParamNames;
}
if (typeAnnotation->IsETSFunctionType()) {
std::string lambdaParams = " ";
for (const auto *const param : typeAnnotation->AsETSFunctionType()->Params()) {
lambdaParams += param->AsETSParameterExpression()->Name().Mutf8();
lambdaParams += ":";
lambdaParams += GetNameForTypeNode(param->AsETSParameterExpression()->TypeAnnotation());
lambdaParams += ",";
}
lambdaParams.pop_back();
const std::string returnTypeName = GetNameForTypeNode(typeAnnotation->AsETSFunctionType()->ReturnType());
return "((" + lambdaParams + ") => " + returnTypeName + ")";
}
if (typeAnnotation->IsTSArrayType()) {
return GetNameForTypeNode(typeAnnotation->AsTSArrayType()->ElementType()) + "[]";
}
if (typeAnnotation->IsETSNullType()) {
return "null";
}
if (typeAnnotation->IsETSUndefinedType()) {
return "undefined";
}
ES2PANDA_UNREACHABLE();
}
void ETSParser::ValidateRestParameter(ir::Expression *param)
{
if (!param->IsETSParameterExpression()) {
return;
}
if (!param->AsETSParameterExpression()->IsRestParameter()) {
return;
}
GetContext().Status() |= ParserStatus::HAS_COMPLEX_PARAM;
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
LogError(diagnostic::REST_PARAM_NOT_LAST);
const auto pos = Lexer()->Save();
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
Lexer()->Rewind(pos);
Lexer()->GetToken().SetTokenType(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS);
}
}
}
bool ETSParser::ValidateBreakLabel([[maybe_unused]] util::StringView label)
{
return true;
}
bool ETSParser::ValidateContinueLabel([[maybe_unused]] util::StringView label)
{
return true;
}
std::tuple<ir::Expression *, ir::TSTypeParameterInstantiation *> ETSParser::ParseTypeReferencePart(
TypeAnnotationParsingOptions *options)
{
ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS;
if (((*options) & TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL) != 0) {
flags |= ExpressionParseFlags::POTENTIAL_CLASS_LITERAL;
}
if (((*options) & TypeAnnotationParsingOptions::POTENTIAL_NEW_ARRAY) != 0) {
flags |= ExpressionParseFlags::POTENTIAL_NEW_ARRAY;
}
auto *typeName = ParseQualifiedName(flags);
if (((*options) & TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL) != 0 &&
(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS || IsStructKeyword())) {
return {typeName, nullptr};
}
ir::TSTypeParameterInstantiation *typeParamInst = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT ||
(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN && Lexer()->HasMatchingGreaterThan())) {
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT) {
Lexer()->BackwardToken(lexer::TokenType::PUNCTUATOR_LESS_THAN, 1);
}
*options |= TypeAnnotationParsingOptions::ALLOW_WILDCARD;
typeParamInst = ParseTypeParameterInstantiation(options);
*options &= ~(TypeAnnotationParsingOptions::ALLOW_WILDCARD);
}
return {typeName, typeParamInst};
}
ir::TypeNode *ETSParser::ParseTypeReference(TypeAnnotationParsingOptions *options)
{
auto startPos = Lexer()->GetToken().Start();
ir::ETSTypeReferencePart *typeRefPart = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_FORMAT) {
return ParseTypeFormatPlaceholder();
}
while (true) {
auto partPos = Lexer()->GetToken().Start();
auto [typeName, typeParams] = ParseTypeReferencePart(options);
if (typeName == nullptr) {
typeName = AllocBrokenExpression(partPos);
}
typeRefPart = AllocNode<ir::ETSTypeReferencePart>(typeName, typeParams, typeRefPart, Allocator());
ES2PANDA_ASSERT(typeRefPart != nullptr);
auto endPos = typeParams == nullptr ? typeName->End() : typeParams->End();
typeRefPart->SetRange({partPos, endPos});
if (!Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_PERIOD)) {
if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_IS) {
auto isPos = Lexer()->GetToken().Start();
Lexer()->NextToken();
Lexer()->TryEatTokenType(lexer::TokenType::LITERAL_IDENT);
LogError(diagnostic::ERROR_ARKTS_NO_IS_OPERATOR, {}, isPos);
return AllocBrokenType({partPos, Lexer()->GetToken().End()});
}
break;
}
if (((*options) & TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL) != 0 &&
(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS || IsStructKeyword())) {
break;
}
}
auto *typeReference = AllocNode<ir::ETSTypeReference>(typeRefPart, Allocator());
ES2PANDA_ASSERT(typeReference != nullptr);
typeReference->SetRange({startPos, typeRefPart->End()});
return typeReference;
}
ir::TypeNode *ETSParser::ParseBaseTypeReference(TypeAnnotationParsingOptions *options)
{
switch (Lexer()->GetToken().KeywordType()) {
case lexer::TokenType::KEYW_BOOLEAN:
return ParsePrimitiveType(options, ir::PrimitiveType::BOOLEAN);
case lexer::TokenType::KEYW_BYTE:
return ParsePrimitiveType(options, ir::PrimitiveType::BYTE);
case lexer::TokenType::KEYW_CHAR:
return ParsePrimitiveType(options, ir::PrimitiveType::CHAR);
case lexer::TokenType::KEYW_DOUBLE:
return ParsePrimitiveType(options, ir::PrimitiveType::DOUBLE);
case lexer::TokenType::KEYW_FLOAT:
return ParsePrimitiveType(options, ir::PrimitiveType::FLOAT);
case lexer::TokenType::KEYW_INT:
return ParsePrimitiveType(options, ir::PrimitiveType::INT);
case lexer::TokenType::KEYW_LONG:
return ParsePrimitiveType(options, ir::PrimitiveType::LONG);
case lexer::TokenType::KEYW_SHORT:
return ParsePrimitiveType(options, ir::PrimitiveType::SHORT);
default:
return nullptr;
}
}
ir::TypeNode *ETSParser::ParseLiteralIdent(TypeAnnotationParsingOptions *options)
{
if (Lexer()->GetToken().IsPredefinedType()) {
return GetTypeAnnotationOfPrimitiveType(Lexer()->GetToken().KeywordType(), options);
}
if ((((*options) & TypeAnnotationParsingOptions::IGNORE_KEYW_KEYOF) == 0) &&
Lexer()->TryEatTokenFromKeywordType(lexer::TokenType::KEYW_KEYOF)) {
auto keyofOptions = *options | TypeAnnotationParsingOptions::REPORT_ERROR;
auto *typeAnnotation = ParseTypeAnnotationNoPreferParam(&keyofOptions);
ES2PANDA_ASSERT(typeAnnotation != nullptr);
typeAnnotation = AllocNode<ir::ETSKeyofType>(typeAnnotation, Allocator());
typeAnnotation->SetRange(Lexer()->GetToken().Loc());
return typeAnnotation;
}
return ParseTypeReference(options);
}
void ETSParser::ParseRightParenthesis(TypeAnnotationParsingOptions *options, ir::TypeNode *&typeAnnotation,
lexer::LexerPosition savedPos)
{
if (!Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS)) {
if (((*options) & TypeAnnotationParsingOptions::REPORT_ERROR) != 0) {
LogExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS);
Lexer()->NextToken();
return;
}
Lexer()->Rewind(savedPos);
typeAnnotation = nullptr;
}
}
void ETSParser::ReportIfVarDeclaration(VariableParsingFlags flags)
{
if ((flags & VariableParsingFlags::VAR) != 0) {
LogError(diagnostic::ERROR_ARKTS_NO_VAR);
}
}
ir::Statement *ETSParser::CreateReExportDeclarationNode(ir::ETSImportDeclaration *reExportDeclaration,
const lexer::SourcePosition &startLoc,
const ir::ModifierFlags &modifiers)
{
if (GetProgram()->AbsoluteName().Is(reExportDeclaration->ResolvedSource())) {
LogError(diagnostic::RE_EXPORTING_LOCAL_BINDINGS_IS_NOT_ALLOWED, {}, startLoc);
return AllocBrokenStatement(startLoc);
}
auto reExport = AllocNode<ir::ETSReExportDeclaration>(reExportDeclaration, std::vector<std::string>(),
GetProgram()->AbsoluteName(), Allocator());
ES2PANDA_ASSERT(reExport != nullptr);
reExport->AddModifier(modifiers);
reExport->SetRange(reExportDeclaration->Range());
return reExport;
}
ir::Statement *ETSParser::ParseDefaultIfSingleExport(ir::ModifierFlags modifiers)
{
auto tokenType = Lexer()->GetToken().Type();
if (tokenType != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
return ParseSingleExport(modifiers);
}
auto savePos = Lexer()->Save();
Lexer()->NextToken();
auto isSelectiveExport = Lexer()->TryEatTokenType(lexer::TokenType::LITERAL_IDENT) &&
(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA ||
Lexer()->GetToken().Type() == lexer::TokenType::KEYW_AS ||
Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE);
Lexer()->Rewind(savePos);
return !isSelectiveExport ? ParseSingleExport(modifiers) : nullptr;
}
ir::ExportNamedDeclaration *ETSParser::CreateExportNamedDeclaration(const SpecifiersInfo &specs,
const ir::ModifierFlags &modifiers,
const lexer::SourcePosition &startLoc)
{
const size_t exportDefaultMaxSize = 1;
ArenaVector<ir::ExportSpecifier *> exports(Allocator()->Adapter());
auto endLoc = startLoc;
for (auto spec : specs.result) {
auto exportSpec = AllocNode<ir::ExportSpecifier>(spec->Local(), spec->Imported());
exportSpec->SetRange(spec->Range());
exports.emplace_back(exportSpec);
endLoc = endLoc.index < spec->End().index ? spec->End() : endLoc;
}
if (specs.resultExportDefault.size() > exportDefaultMaxSize) {
LogError(diagnostic::EXPORT_DEFAULT_WITH_MUPLTIPLE_SPECIFIER, {}, startLoc);
}
for (auto spec : specs.resultExportDefault) {
exports.emplace_back(spec);
endLoc = endLoc.index < spec->End().index ? spec->End() : endLoc;
}
auto result = AllocNode<ir::ExportNamedDeclaration>(Allocator(), static_cast<ir::StringLiteral *>(nullptr),
std::move(exports));
ES2PANDA_ASSERT(result != nullptr);
result->AddModifier(modifiers);
result->SetRange({startLoc, endLoc});
return result;
}
ir::Statement *ETSParser::ParseExport(lexer::SourcePosition startLoc, ir::ModifierFlags modifiers)
{
if ((modifiers & ir::ModifierFlags::DEFAULT_EXPORT) != 0U &&
Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_MULTIPLY &&
Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
auto exportedExpression = ParseDefaultIfSingleExport(modifiers);
if (exportedExpression != nullptr) {
return exportedExpression;
}
}
ArenaVector<ir::AstNode *> specifiers(Allocator()->Adapter());
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) {
ParseNameSpaceSpecifier(&specifiers, true);
specifiers[0]->AddModifier(ir::ModifierFlags::EXPORT);
} else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
ir::ExportKinds exportKind =
(modifiers & ir::ModifierFlags::EXPORT_TYPE) != 0U ? ir::ExportKinds::TYPES : ir::ExportKinds::ALL;
auto specs = ParseExportNamedSpecifiers(exportKind);
if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_FROM) {
for (auto *spec : specs.resultExportDefault) {
LogError(diagnostic::EXPECTED_PARAM_GOT_PARAM, {"identifier", "default"}, spec->Start());
}
specifiers = util::Helpers::ConvertVector<ir::AstNode>(specs.result);
for (auto *spec : specs.resultExportDefault) {
auto *imported = AllocNode<ir::Identifier>(spec->Exported()->Name(), Allocator());
ES2PANDA_ASSERT(imported != nullptr);
imported->SetRange(spec->Exported()->Range());
auto *local =
AllocNode<ir::Identifier>(compiler::Signatures::REEXPORT_DEFAULT_ANONYMOUSLY, Allocator());
ES2PANDA_ASSERT(local != nullptr);
local->SetRange(spec->Range());
auto *importSpecifier = AllocNode<ir::ImportSpecifier>(imported, local);
ES2PANDA_ASSERT(importSpecifier != nullptr);
importSpecifier->SetRange(spec->Range());
specifiers.emplace_back(importSpecifier);
}
} else {
return CreateExportNamedDeclaration(specs, modifiers, startLoc);
}
} else {
return ParseSingleExport(modifiers);
}
if ((modifiers & ir::ModifierFlags::DEFAULT_EXPORT) != 0) {
LogError(diagnostic::EXPORT_DEFAULT_NO_REEXPORT);
}
auto *reExportDeclaration = ParseImportPathBuildImport(std::move(specifiers), true, startLoc, ir::ImportKinds::ALL);
return CreateReExportDeclarationNode(reExportDeclaration, startLoc, modifiers);
}
ir::ETSPackageDeclaration *ETSParser::ParsePackageDeclaration()
{
auto startLoc = Lexer()->GetToken().Start();
if (Lexer()->TryEatTokenType(lexer::TokenType::KEYW_PACKAGE)) {
RaisePackageDeprecatedMessage();
ir::Expression *packageNameNode = ParseQualifiedName();
auto *packageDeclaration = AllocNode<ir::ETSPackageDeclaration>(packageNameNode);
ES2PANDA_ASSERT(packageDeclaration != nullptr);
packageDeclaration->SetRange({startLoc, Lexer()->GetToken().End()});
ConsumeSemicolon(packageDeclaration);
EnsureContainingPackageIsRegistered(packageDeclaration);
GetContext().Status() |= ParserStatus::IN_PACKAGE;
return packageDeclaration;
}
return nullptr;
}
ir::ETSImportDeclaration *ETSParser::ParseImportPathBuildImport(ArenaVector<ir::AstNode *> &&specifiers,
bool requireFrom, lexer::SourcePosition startLoc,
ir::ImportKinds importKind)
{
util::StringView str = ERROR_LITERAL;
if (Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_FROM && requireFrom) {
LogExpectedToken(lexer::TokenType::KEYW_FROM);
if (Lexer()->GetToken().KeywordType() == lexer::TokenType::LITERAL_IDENT) {
str = Lexer()->GetToken().Ident();
} else if (Lexer()->GetToken().KeywordType() == lexer::TokenType::EOS) {
str = "";
}
}
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_STRING) {
LogExpectedToken(lexer::TokenType::LITERAL_STRING);
auto errorLiteral = AllocNode<ir::StringLiteral>(str);
ES2PANDA_ASSERT(errorLiteral != nullptr);
errorLiteral->SetRange(Lexer()->GetToken().Loc());
auto *const importDeclaration =
AllocNode<ir::ETSImportDeclaration>(errorLiteral, util::ImportInfo {}, std::move(specifiers), importKind);
ES2PANDA_ASSERT(importDeclaration != nullptr);
importDeclaration->SetRange({startLoc, errorLiteral->End()});
return importDeclaration;
}
ES2PANDA_ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_STRING);
auto pathToResolve = Lexer()->GetToken().Ident();
auto *importPathStringLiteral = AllocNode<ir::StringLiteral>(pathToResolve);
ES2PANDA_ASSERT(importPathStringLiteral != nullptr);
importPathStringLiteral->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
auto *const importDeclaration = BuildImportDeclaration(importKind, std::move(specifiers), importPathStringLiteral,
const_cast<parser::Program *>(GetContext().GetProgram()));
ES2PANDA_ASSERT(importDeclaration != nullptr);
importDeclaration->SetRange({startLoc, importPathStringLiteral->End()});
if (Lexer()->GetToken().Ident().Is("assert")) {
LogError(diagnostic::ERROR_ARKTS_NO_IMPORT_ASSERTIONS);
return importDeclaration;
}
ConsumeSemicolon(importDeclaration);
return importDeclaration;
}
ir::ETSImportDeclaration *ETSParser::BuildImportDeclaration(ir::ImportKinds importKind,
ArenaVector<ir::AstNode *> &&specifiers,
ir::StringLiteral *pathToResolve, parser::Program *program)
{
auto importedProg = GetImportPathManager()->GatherImportInfo(program, pathToResolve);
if (importedProg != nullptr) {
return AllocNode<ir::ETSImportDeclaration>(pathToResolve, importedProg->GetImportInfo(), std::move(specifiers),
importKind);
}
return AllocNode<ir::ETSImportDeclaration>(pathToResolve, std::move(specifiers), importKind);
}
ArenaVector<ir::ETSImportDeclaration *> ETSParser::ParseImportDeclarations()
{
std::vector<std::string> userPaths;
ArenaVector<ir::ETSImportDeclaration *> statements(Allocator()->Adapter());
while (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_IMPORT) {
auto startLoc = Lexer()->GetToken().Start();
Lexer()->NextToken();
ir::ImportKinds importKind = TryEatTypeKeyword() ? ir::ImportKinds::TYPES : ir::ImportKinds::ALL;
ArenaVector<ir::AstNode *> specifiers(Allocator()->Adapter());
ArenaVector<ir::AstNode *> defaultSpecifiers(Allocator()->Adapter());
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) {
ParseNameSpaceSpecifier(&specifiers);
} else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
auto saveLoc = Lexer()->GetToken().Start();
auto specs = ParseNamedSpecifiers(importKind);
specifiers = util::Helpers::ConvertVector<ir::AstNode>(specs.result);
defaultSpecifiers = util::Helpers::ConvertVector<ir::AstNode>(specs.resultDefault);
if (specifiers.empty() && defaultSpecifiers.empty()) {
specifiers.push_back(AllocBrokenExpression({saveLoc, specs.rightBackPos}));
LogError(diagnostic::EMPTY_IMPORT_SPECIFIER_LIST);
}
} else {
ParseImportDefaultSpecifier(&specifiers);
}
auto pos = Lexer()->Save();
if (!specifiers.empty()) {
auto *const importDecl = ParseImportPathBuildImport(std::move(specifiers), true, startLoc, importKind);
ES2PANDA_ASSERT(importDecl != nullptr);
statements.push_back(importDecl->AsETSImportDeclaration());
}
if (!defaultSpecifiers.empty()) {
Lexer()->Rewind(pos);
auto *const importDeclDefault =
ParseImportPathBuildImport(std::move(defaultSpecifiers), true, startLoc, importKind);
ES2PANDA_ASSERT(importDeclDefault != nullptr);
if (!importDeclDefault->IsBrokenStatement()) {
util::Helpers::CheckDefaultImport(statements);
statements.push_back(importDeclDefault->AsETSImportDeclaration());
}
}
}
std::sort(statements.begin(), statements.end(), [](const auto *s1, const auto *s2) -> bool {
return s1->Specifiers()[0]->IsImportNamespaceSpecifier() && !s2->Specifiers()[0]->IsImportNamespaceSpecifier();
});
return statements;
}
ir::ExportNamedDeclaration *ETSParser::ParseSingleExportForAnonymousConst(ir::ModifierFlags modifiers)
{
ir::Expression *constantExpression = ParseExpression();
auto *exported = AllocNode<ir::Identifier>(compiler::Signatures::REEXPORT_DEFAULT_ANONYMOUSLY, Allocator());
ES2PANDA_ASSERT(exported != nullptr);
exported->SetRange(Lexer()->GetToken().Loc());
ArenaVector<ir::ExportSpecifier *> exports(Allocator()->Adapter());
auto *exportSpecifier = AllocNode<ir::ExportSpecifier>(exported, exported->Clone(Allocator(), nullptr));
exportSpecifier->SetConstantExpression(constantExpression);
exportSpecifier->SetDefault();
exports.push_back(exportSpecifier);
auto result = AllocNode<ir::ExportNamedDeclaration>(Allocator(), static_cast<ir::StringLiteral *>(nullptr),
std::move(exports));
ES2PANDA_ASSERT(result != nullptr);
result->AddModifier(modifiers);
ConsumeSemicolon(result);
return result;
}
ir::ExportNamedDeclaration *ETSParser::ParseSingleExport(ir::ModifierFlags modifiers)
{
lexer::Token token = Lexer()->GetToken();
if (((modifiers & ir::ModifierFlags::DEFAULT_EXPORT) != 0) && token.Type() != lexer::TokenType::LITERAL_IDENT) {
return ParseSingleExportForAnonymousConst(modifiers);
}
if (token.KeywordType() == lexer::TokenType::KEYW_AS) {
LogError(diagnostic::ERROR_ARKTS_NO_UMD, {}, token.Start());
return nullptr;
}
if (token.Type() != lexer::TokenType::LITERAL_IDENT) {
LogError(diagnostic::EXPORT_NON_DECLARATION, {}, token.Start());
return nullptr;
}
auto *exported = AllocNode<ir::Identifier>(token.Ident(), Allocator());
exported->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
auto *specifier = AllocNode<ir::ExportSpecifier>(exported, ParseNamedExport(&token));
specifier->SetRange(exported->Range());
specifier->AddModifier(modifiers);
ArenaVector<ir::ExportSpecifier *> exports(Allocator()->Adapter());
exports.emplace_back(specifier);
auto result = AllocNode<ir::ExportNamedDeclaration>(Allocator(), static_cast<ir::StringLiteral *>(nullptr),
std::move(exports));
result->SetRange(exported->Range());
result->AddModifier(modifiers);
ConsumeSemicolon(result);
return result;
}
bool ETSParser::IsDefaultImport()
{
if (Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_DEFAULT)) {
if (Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_AS)) {
return true;
}
LogError(diagnostic::UNEXPECTED_TOKEN_AS);
}
return false;
}
bool ETSParser::IsDefaultExport()
{
if (Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_DEFAULT)) {
Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_AS);
return true;
}
return false;
}
bool ETSParser::IsPrimitiveType(const lexer::TokenType &tokenType)
{
switch (tokenType) {
case lexer::TokenType::KEYW_BIGINT:
case lexer::TokenType::KEYW_BOOLEAN:
case lexer::TokenType::KEYW_BYTE:
case lexer::TokenType::KEYW_CHAR:
case lexer::TokenType::KEYW_DOUBLE:
case lexer::TokenType::KEYW_FLOAT:
case lexer::TokenType::KEYW_INT:
case lexer::TokenType::KEYW_LONG:
case lexer::TokenType::KEYW_SHORT:
case lexer::TokenType::KEYW_VOID:
case lexer::TokenType::KEYW_ANY:
return true;
default:
return false;
}
}
void ETSParser::ParseNamedSpecifiesDefaultImport(ArenaVector<ir::ImportDefaultSpecifier *> *resultDefault,
const std::string &fileName)
{
auto *imported = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
ES2PANDA_ASSERT(imported != nullptr);
imported->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
auto *specifier = AllocNode<ir::ImportDefaultSpecifier>(imported);
ES2PANDA_ASSERT(specifier != nullptr);
specifier->SetRange({imported->Start(), imported->End()});
util::Helpers::CheckDefaultImportedName(*resultDefault, specifier, fileName);
resultDefault->emplace_back(specifier);
}
void ETSParser::ParseNamedSpecifiersDefaultExport(ArenaVector<ir::ImportSpecifier *> *result,
ArenaVector<ir::ImportDefaultSpecifier *> *resultDefault,
const std::string &fileName)
{
auto *local = AllocNode<ir::Identifier>(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE
? compiler::Signatures::REEXPORT_DEFAULT_ANONYMOUSLY
: Lexer()->GetToken().Ident(),
Allocator());
ES2PANDA_ASSERT(local != nullptr);
local->SetRange(Lexer()->GetToken().Loc());
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) {
Lexer()->NextToken();
}
auto *specifier = AllocNode<ir::ImportDefaultSpecifier>(local);
ES2PANDA_ASSERT(specifier != nullptr);
specifier->SetRange({local->Start(), local->End()});
util::Helpers::CheckDefaultImportedName(*resultDefault, specifier, fileName);
resultDefault->emplace_back(specifier);
auto *imported = AllocNode<ir::Identifier>(compiler::Signatures::REEXPORT_DEFAULT_ANONYMOUSLY, Allocator());
auto *specifierResult = AllocNode<ir::ImportSpecifier>(imported, local);
specifierResult->SetRange({local->Start(), local->End()});
result->emplace_back(specifierResult);
}
bool ETSParser::ParseNamedSpecifiesImport(ArenaVector<ir::ImportSpecifier *> *result,
ArenaVector<ir::ExportSpecifier *> *resultExportDefault)
{
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
ir::Expression *constantExpression = ParseUnaryOrPrefixUpdateExpression();
auto *exported = AllocNode<ir::Identifier>(compiler::Signatures::REEXPORT_DEFAULT_ANONYMOUSLY, Allocator());
ES2PANDA_ASSERT(exported != nullptr);
exported->SetRange(Lexer()->GetToken().Loc());
auto *exportedAnonyConst = AllocNode<ir::ExportSpecifier>(exported, exported->Clone(Allocator(), nullptr));
ES2PANDA_ASSERT(exportedAnonyConst != nullptr);
exportedAnonyConst->SetConstantExpression(constantExpression);
exportedAnonyConst->SetDefault();
resultExportDefault->emplace_back(exportedAnonyConst);
return Lexer()->TryEatTokenType(lexer::TokenType::KEYW_AS) &&
Lexer()->TryEatTokenType(lexer::TokenType::KEYW_DEFAULT);
}
lexer::Token importedToken = Lexer()->GetToken();
auto *imported = ExpectIdentifier();
ir::Identifier *local = nullptr;
CheckModuleAsModifier();
if (Lexer()->TryEatTokenType(lexer::TokenType::KEYW_AS)) {
if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_DEFAULT) {
auto *exportedAnonyConst = AllocNode<ir::ExportSpecifier>(imported, imported->Clone(Allocator(), nullptr));
exportedAnonyConst->SetDefault();
exportedAnonyConst->SetRange({Lexer()->GetToken().Start(), Lexer()->GetToken().End()});
Lexer()->NextToken();
resultExportDefault->emplace_back(exportedAnonyConst);
return true;
}
local = ParseNamedImport(&Lexer()->GetToken());
Lexer()->NextToken();
} else {
local = ParseNamedImport(&importedToken);
}
auto *specifier = AllocNode<ir::ImportSpecifier>(imported, local);
ES2PANDA_ASSERT(specifier != nullptr);
specifier->SetRange({imported->Start(), local->End()});
util::Helpers::CheckImportedName(*result, specifier, DiagnosticEngine());
result->emplace_back(specifier);
return true;
}
SpecifiersInfo ETSParser::ParseNamedSpecifiers(const ir::ImportKinds importKind)
{
if (!Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_LEFT_BRACE)) {
LogExpectedToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE);
Lexer()->NextToken();
}
auto fileName = GetProgram()->SourceFilePath().Mutf8();
ArenaVector<ir::ImportSpecifier *> result(Allocator()->Adapter());
ArenaVector<ir::ImportDefaultSpecifier *> resultDefault(Allocator()->Adapter());
ArenaVector<ir::ExportSpecifier *> resultExportDefault(Allocator()->Adapter());
lexer::SourcePosition sourceEnd;
auto token = Lexer()->GetToken();
if (token.Ident() == (lexer::TokenToString(lexer::TokenType::KEYW_IMPORT)) &&
token.Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) {
LogError(diagnostic::ERROR_ARKTS_NO_SIDE_EFFECT_IMPORT);
}
ParseList(
lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::KEYWORD_TO_IDENT,
[this, &result, &resultDefault, &resultExportDefault, &fileName, &importKind](bool &typeKeywordOnSpecifier) {
if (typeKeywordOnSpecifier && importKind == ir::ImportKinds::TYPES) {
LogError(diagnostic::REPEATED_TYPE_KEYWORD);
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) {
LogError(diagnostic::ASTERIKS_NOT_ALLOWED_IN_SELECTIVE_BINDING);
}
if (!IsDefaultImport()) {
typeKeywordOnSpecifier = false;
return ParseNamedSpecifiesImport(&result, &resultExportDefault);
}
ParseNamedSpecifiesDefaultImport(&resultDefault, fileName);
typeKeywordOnSpecifier = false;
return true;
},
&sourceEnd, ParseListOptions::ALLOW_TRAILING_SEP | ParseListOptions::ALLOW_TYPE_KEYWORD);
return {result, resultDefault, resultExportDefault, sourceEnd};
}
SpecifiersInfo ETSParser::ParseExportNamedSpecifiers(const ir::ExportKinds exportKind)
{
if (!Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_LEFT_BRACE)) {
LogExpectedToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE);
Lexer()->NextToken();
}
auto fileName = GetProgram()->SourceFilePath().Mutf8();
ArenaVector<ir::ImportSpecifier *> result(Allocator()->Adapter());
ArenaVector<ir::ImportDefaultSpecifier *> resultDefault(Allocator()->Adapter());
ArenaVector<ir::ExportSpecifier *> resultExportDefault(Allocator()->Adapter());
ParseList(
lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::KEYWORD_TO_IDENT,
[this, &result, &resultDefault, &resultExportDefault, &fileName, &exportKind](bool &typeKeywordOnSpecifier) {
if (typeKeywordOnSpecifier && exportKind == ir::ExportKinds::TYPES) {
LogError(diagnostic::REPEATED_TYPE_KEYWORD);
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) {
LogError(diagnostic::ASTERIKS_NOT_ALLOWED_IN_SELECTIVE_BINDING);
}
if (!IsDefaultExport()) {
typeKeywordOnSpecifier = false;
return ParseNamedSpecifiesImport(&result, &resultExportDefault);
}
ParseNamedSpecifiersDefaultExport(&result, &resultDefault, fileName);
typeKeywordOnSpecifier = false;
return true;
},
nullptr, ParseListOptions::ALLOW_TRAILING_SEP | ParseListOptions::ALLOW_TYPE_KEYWORD);
return {result, resultDefault, resultExportDefault};
}
void ETSParser::ParseNameSpaceSpecifier(ArenaVector<ir::AstNode *> *specifiers, bool isReExport)
{
lexer::SourcePosition namespaceStart = Lexer()->GetToken().Start();
Lexer()->NextToken();
CheckModuleAsModifier();
if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_FROM && !isReExport &&
(GetContext().Status() & ParserStatus::IN_DEFAULT_IMPORTS) == 0) {
LogExpectedToken(lexer::TokenType::KEYW_AS);
}
auto *local = AllocNode<ir::Identifier>(util::StringView(""), Allocator());
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA ||
Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_FROM) {
auto *specifier = AllocNode<ir::ImportNamespaceSpecifier>(local);
ES2PANDA_ASSERT(specifier != nullptr);
specifier->SetRange({namespaceStart, Lexer()->GetToken().End()});
specifiers->push_back(specifier);
return;
}
ExpectToken(lexer::TokenType::KEYW_AS, true);
local = ParseNamedImport(&Lexer()->GetToken());
auto *specifier = AllocNode<ir::ImportNamespaceSpecifier>(local);
ES2PANDA_ASSERT(specifier != nullptr);
specifier->SetRange({namespaceStart, Lexer()->GetToken().End()});
specifiers->push_back(specifier);
Lexer()->NextToken();
}
ir::AstNode *ETSParser::ParseImportDefaultSpecifier(ArenaVector<ir::AstNode *> *specifiers)
{
if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_STRING) {
LogError(diagnostic::ERROR_ARKTS_NO_SIDE_EFFECT_IMPORT);
return nullptr;
}
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
LogExpectedToken(lexer::TokenType::LITERAL_IDENT);
}
auto *imported = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
ES2PANDA_ASSERT(imported != nullptr);
imported->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
if (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_COMMA)) {
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) {
ParseNameSpaceSpecifier(specifiers);
} else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
const ir::ImportKinds importKind = Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_TYPE)
? ir::ImportKinds::TYPES
: ir::ImportKinds::ALL;
auto specs = ParseNamedSpecifiers(importKind);
auto importSpecifiers = util::Helpers::ConvertVector<ir::AstNode>(specs.result);
specifiers->insert(specifiers->end(), importSpecifiers.begin(), importSpecifiers.end());
}
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
LogError(diagnostic::ERROR_ARKTS_NO_REQUIRE);
return nullptr;
}
if (Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_FROM) {
LogExpectedToken(lexer::TokenType::KEYW_FROM);
Lexer()->NextToken();
}
auto *specifier = AllocNode<ir::ImportDefaultSpecifier>(imported);
ES2PANDA_ASSERT(specifier != nullptr);
specifier->SetRange({imported->Start(), imported->End()});
specifiers->push_back(specifier);
return nullptr;
}
void ETSParser::CheckModuleAsModifier()
{
if ((Lexer()->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) != 0U) {
LogError(diagnostic::ESCAPE_SEQUENCES_IN_AS);
}
}
ir::AnnotatedExpression *ETSParser::GetAnnotatedExpressionFromParam()
{
ir::AnnotatedExpression *parameter = nullptr;
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::LITERAL_IDENT: {
parameter = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
ES2PANDA_ASSERT(parameter != nullptr);
parameter->SetRange(Lexer()->GetToken().Loc());
break;
}
case lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD: {
const auto startLoc = Lexer()->GetToken().Start();
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
LogExpectedToken(lexer::TokenType::LITERAL_IDENT);
}
auto *const restIdent = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
ES2PANDA_ASSERT(restIdent != nullptr);
restIdent->SetRange(Lexer()->GetToken().Loc());
parameter = AllocNode<ir::SpreadElement>(ir::AstNodeType::REST_ELEMENT, Allocator(), restIdent);
ES2PANDA_ASSERT(parameter != nullptr);
parameter->SetRange({startLoc, Lexer()->GetToken().End()});
break;
}
default: {
LogError(diagnostic::UNEXPECTED_TOKEN_ID);
return AllocBrokenExpression(Lexer()->GetToken().Loc());
}
}
Lexer()->NextToken();
return parameter;
}
ir::Expression *ETSParser::ParseFunctionParameterAnnotations()
{
EatLeadingAtForAnnotation();
auto annotations = ParseAnnotations(false);
auto savePos = Lexer()->GetToken().Start();
ir::Expression *result = ParseFunctionParameter();
if (result != nullptr && !result->IsBrokenExpression()) {
ApplyAnnotationsToNode(result, std::move(annotations), savePos);
}
return result;
}
ir::Expression *ETSParser::ParseFunctionReceiver()
{
ES2PANDA_ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_THIS);
auto thisLoc = Lexer()->GetToken().Start();
Lexer()->NextToken();
if (!Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_COLON)) {
LogError(diagnostic::FUN_PARAM_THIS_MISSING_TYPE);
return AllocBrokenExpression(Lexer()->GetToken().Loc());
}
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
ir::TypeNode *typeAnnotation = ParseTypeAnnotation(&options);
if (!GetContext().AllowReceiver()) {
LogError(diagnostic::UNEXPECTED_THIS, {}, thisLoc);
return AllocBrokenExpression(thisLoc);
}
if (typeAnnotation->IsBrokenTypeNode()) {
return AllocBrokenExpression(thisLoc);
}
return CreateParameterThis(typeAnnotation);
}
void ETSParser::SkipInvalidType() const
{
int openParenthesisCount = 1;
int openBraceCount = 0;
while (Lexer()->GetToken().Type() != lexer::TokenType::EOS &&
!(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA && openBraceCount == 0)) {
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
openBraceCount++;
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) {
openBraceCount--;
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
openParenthesisCount++;
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
openParenthesisCount--;
}
if (openParenthesisCount == 0) {
break;
}
Lexer()->NextToken();
}
}
bool ETSParser::IsFixedArrayTypeNode(ir::AstNode *node)
{
return node->IsETSTypeReference() &&
node->AsETSTypeReference()->BaseName()->Name() == compiler::Signatures::FIXED_ARRAY_TYPE_NAME;
}
ir::ThisExpression *ETSParser::ParseThisExpression()
{
ES2PANDA_ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_THIS);
auto *thisExprNode = AllocNode<ir::ThisExpression>();
ES2PANDA_ASSERT(thisExprNode != nullptr);
thisExprNode->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_DOT) {
LogError(diagnostic::THIS_OPTIONAL_CHAIN_NOT_SUPPORTED);
}
return thisExprNode;
}
ir::Expression *ETSParser::ParseFunctionParameter()
{
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::KEYW_PRIVATE:
case lexer::TokenType::KEYW_PUBLIC:
case lexer::TokenType::KEYW_PROTECTED:
LogError(diagnostic::FIELD_IN_PARAM);
Lexer()->NextToken();
[[fallthrough]];
default:
break;
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_AT) {
return ParseFunctionParameterAnnotations();
}
if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_THIS) {
return ParseFunctionReceiver();
}
auto *const paramIdent = GetAnnotatedExpressionFromParam();
bool isOptional = false;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) {
isOptional = true;
if (paramIdent->IsRestElement()) {
LogError(diagnostic::NO_DEFAULT_FOR_REST);
}
Lexer()->NextToken();
}
const bool isArrow = (GetContext().Status() & ParserStatus::ARROW_FUNCTION) != 0;
if (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_COLON)) {
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
ir::TypeNode *typeAnnotation = ParseTypeAnnotation(&options);
ES2PANDA_ASSERT(typeAnnotation != nullptr);
if (typeAnnotation->IsBrokenTypeNode()) {
SkipInvalidType();
}
paramIdent->SetTypeAnnotation(typeAnnotation);
paramIdent->SetEnd(typeAnnotation->End());
}
if ((!isArrow || isOptional) && paramIdent->TypeAnnotation() == nullptr) {
LogError(diagnostic::EXPLICIT_PARAM_TYPE);
paramIdent->SetTsTypeAnnotation(AllocBrokenType(Lexer()->GetToken().Loc()));
}
return ParseFunctionParameterExpression(paramIdent, isOptional);
}
ir::Expression *ETSParser::CreateParameterThis(ir::TypeNode *typeAnnotation)
{
auto *paramIdent = AllocNode<ir::Identifier>(varbinder::TypedBinder::MANDATORY_PARAM_THIS, Allocator());
ES2PANDA_ASSERT(paramIdent != nullptr);
paramIdent->SetRange(Lexer()->GetToken().Loc());
paramIdent->SetTypeAnnotation(typeAnnotation);
auto *paramExpression = AllocNode<ir::ETSParameterExpression>(paramIdent, false, Allocator());
ES2PANDA_ASSERT(paramExpression != nullptr);
paramExpression->SetRange({paramIdent->Start(), paramIdent->End()});
return paramExpression;
}
ir::Expression *ETSParser::ParseVariableDeclaratorKey(VariableParsingFlags flags)
{
ir::Expression *init = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) {
init = ParseArrayOrDestructuringExpression(ExpressionParseFlags::MUST_BE_PATTERN);
} else {
init = ExpectIdentifier();
}
ES2PANDA_ASSERT(init != nullptr);
ir::TypeNode *typeAnnotation = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) {
Lexer()->NextToken();
if ((flags & VariableParsingFlags::FOR_OF) != 0U) {
LogError(diagnostic::OPTIONAL_VAR_IN_FOR_OF);
} else {
init->AddModifier(ir::ModifierFlags::OPTIONAL);
LogError(diagnostic::OPTIONAL_VARIABLE);
}
}
if (auto const tokenType = Lexer()->GetToken().Type(); tokenType == lexer::TokenType::PUNCTUATOR_COLON) {
Lexer()->NextToken();
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
typeAnnotation = ParseTypeAnnotation(&options);
} else if (InAmbientContext()) {
LogError(diagnostic::MISSING_TYPE_ANNOTATION, {init->AsIdentifier()->Name()}, init->Start());
}
if (init->IsAnnotatedExpression() && typeAnnotation != nullptr) {
init->AsAnnotatedExpression()->SetTypeAnnotation(typeAnnotation);
}
return init;
}
ir::VariableDeclarator *ETSParser::ParseVariableDeclaratorInitializer(ir::Expression *init, VariableParsingFlags flags,
const lexer::SourcePosition &startLoc)
{
if ((flags & VariableParsingFlags::DISALLOW_INIT) != 0) {
LogError(diagnostic::FOR_AWAIT_OF_VAR_NOT_INIT);
}
Lexer()->NextToken();
ir::Expression *initializer = ParseExpression();
lexer::SourcePosition endLoc = initializer->End();
if (InAmbientContext()) {
LogError(diagnostic::INITIALIZERS_IN_AMBIENT_CONTEXTS, {init->AsIdentifier()->Name()}, initializer->Start());
}
auto *declarator = AllocNode<ir::VariableDeclarator>(GetFlag(flags), init, initializer);
declarator->SetRange({startLoc, endLoc});
return declarator;
}
ir::VariableDeclarator *ETSParser::ParseVariableDeclarator(ir::Expression *init, lexer::SourcePosition startLoc,
VariableParsingFlags flags)
{
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
return ParseVariableDeclaratorInitializer(init, flags, startLoc);
}
if (init->IsETSDestructuring()) {
LogError(diagnostic::MISSING_INIT_IN_DEST_DEC);
} else if (!InAmbientContext() && init->AsIdentifier()->TypeAnnotation() == nullptr &&
(flags & VariableParsingFlags::FOR_OF) == 0U) {
LogError(diagnostic::MISSING_INIT_OR_TYPE);
} else if (!IsExternal() && (flags & VariableParsingFlags::CONST) != 0U && !InAmbientContext() &&
(flags & (VariableParsingFlags::FOR_OF | VariableParsingFlags::IN_FOR)) == 0U) {
LogError(diagnostic::CONST_WITHOUT_INIT, {}, startLoc);
}
lexer::SourcePosition endLoc = init->End();
auto declarator = AllocNode<ir::VariableDeclarator>(GetFlag(flags), init);
declarator->SetRange({startLoc, endLoc});
return declarator;
}
ir::Expression *ETSParser::ParseCatchParam()
{
ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS);
ir::AnnotatedExpression *param = nullptr;
bool checkRestrictedBinding = true;
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
LogError(diagnostic::UNEXPECTED_TOKEN_ID);
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
checkRestrictedBinding = false;
} else {
Lexer()->GetToken().SetTokenType(lexer::TokenType::LITERAL_IDENT);
Lexer()->GetToken().SetTokenStr(ERROR_LITERAL);
}
}
if (!checkRestrictedBinding) {
ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS);
return nullptr;
}
CheckRestrictedBinding();
param = ExpectIdentifier();
ParseCatchParamTypeAnnotation(param);
ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS);
return param;
}
void ETSParser::ParseCatchParamTypeAnnotation([[maybe_unused]] ir::AnnotatedExpression *param)
{
if (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_COLON)) {
LogError(diagnostic::MULTI_CATCH_DEPRECATED);
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
if (auto *typeAnnotation = ParseTypeAnnotation(&options); typeAnnotation != nullptr) {
ES2PANDA_ASSERT(param != nullptr);
param->SetTypeAnnotation(typeAnnotation);
}
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
LogError(diagnostic::CATCH_CLAUSE_VAR_HAS_INIT);
}
}
ir::Statement *ETSParser::ParseImportDeclaration([[maybe_unused]] StatementParsingFlags flags)
{
bool isError = false;
if ((flags & StatementParsingFlags::GLOBAL) == 0) {
LogError(diagnostic::IMPORT_TOP_LEVEL);
isError = true;
}
char32_t nextChar = Lexer()->Lookahead();
if (nextChar == lexer::LEX_CHAR_LEFT_PAREN || nextChar == lexer::LEX_CHAR_DOT) {
return ParseExpressionStatement();
}
lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
Lexer()->NextToken();
ArenaVector<ir::AstNode *> specifiers(Allocator()->Adapter());
ir::ETSImportDeclaration *importDeclaration {};
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_STRING) {
ir::AstNode *astNode = ParseImportSpecifiers(&specifiers);
if (astNode != nullptr) {
ES2PANDA_ASSERT(astNode->IsTSImportEqualsDeclaration());
astNode->SetRange({startLoc, Lexer()->GetToken().End()});
ConsumeSemicolon(astNode->AsTSImportEqualsDeclaration());
return astNode->AsTSImportEqualsDeclaration();
}
importDeclaration = ParseImportPathBuildImport(std::move(specifiers), true, startLoc, ir::ImportKinds::ALL);
} else {
importDeclaration = ParseImportPathBuildImport(std::move(specifiers), false, startLoc, ir::ImportKinds::ALL);
}
return isError ? AllocBrokenStatement(startLoc) : importDeclaration;
}
ir::Statement *ETSParser::ParseExportDeclaration([[maybe_unused]] StatementParsingFlags flags)
{
LogUnexpectedToken(lexer::TokenType::KEYW_EXPORT);
return AllocBrokenStatement(Lexer()->GetToken().Loc());
}
ir::Expression *ETSParser::ParseExpressionOrTypeAnnotation(lexer::TokenType type,
[[maybe_unused]] ExpressionParseFlags flags)
{
if (type == lexer::TokenType::KEYW_INSTANCEOF) {
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR |
TypeAnnotationParsingOptions::ANNOTATION_NOT_ALLOW |
TypeAnnotationParsingOptions::INSTANCEOF;
if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_NULL) {
auto *typeAnnotation = AllocNode<ir::NullLiteral>();
ES2PANDA_ASSERT(typeAnnotation != nullptr);
typeAnnotation->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
return typeAnnotation;
}
return ParseTypeAnnotation(&options);
}
return ParseExpression(ExpressionParseFlags::DISALLOW_YIELD);
}
bool ETSParser::ParsePotentialGenericFunctionCall(ir::Expression *primaryExpr, ir::Expression **returnExpression,
[[maybe_unused]] const lexer::SourcePosition &startLoc,
bool ignoreCallExpression)
{
if (Lexer()->Lookahead() == lexer::LEX_CHAR_LESS_THAN ||
(!primaryExpr->IsIdentifier() && !primaryExpr->IsMemberExpression())) {
return true;
}
const auto savedPos = Lexer()->Save();
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT) {
Lexer()->BackwardToken(lexer::TokenType::PUNCTUATOR_LESS_THAN, 1);
}
TypeAnnotationParsingOptions options =
TypeAnnotationParsingOptions::ALLOW_WILDCARD | TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE;
ir::TSTypeParameterInstantiation *typeParams = ParseTypeParameterInstantiation(&options);
if (typeParams == nullptr) {
Lexer()->Rewind(savedPos);
return true;
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD) {
Lexer()->Rewind(savedPos);
return true;
}
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
*returnExpression = AllocNode<ir::ETSGenericInstantiatedNode>(primaryExpr, typeParams);
(*returnExpression)->SetRange({startLoc, Lexer()->GetToken().Start()});
return false;
}
if (!ignoreCallExpression) {
*returnExpression = ParseCallExpression(*returnExpression, false, false);
(*returnExpression)->AsCallExpression()->SetTypeParams(typeParams);
return false;
}
Lexer()->Rewind(savedPos);
return true;
}
ir::ModifierFlags ETSParser::ParseTypeVarianceModifier(TypeAnnotationParsingOptions *const options)
{
if ((*options & TypeAnnotationParsingOptions::ALLOW_WILDCARD) == 0 &&
(*options & TypeAnnotationParsingOptions::ALLOW_DECLARATION_SITE_VARIANCE) == 0) {
LogError(diagnostic::VARIANCE_NOD_ALLOWED);
}
switch (Lexer()->GetToken().KeywordType()) {
case lexer::TokenType::KEYW_IN: {
Lexer()->NextToken();
return ir::ModifierFlags::IN;
}
case lexer::TokenType::KEYW_OUT: {
Lexer()->NextToken();
return ir::ModifierFlags::OUT;
}
default: {
return ir::ModifierFlags::NONE;
}
}
}
ir::AstNode *ETSParser::ParseAmbientSignature(const lexer::SourcePosition &startPos)
{
auto const indexName = ParseIndexName();
auto [typeAnno, returnType] = ParseIndexTypeAndReturnType();
if (returnType->IsBrokenTypeNode()) {
LogError(diagnostic::INDEX_MISSING_IDENTIFIER);
return AllocBrokenStatement({startPos, Lexer()->GetToken().End()});
}
auto dummyNode = AllocNode<ir::DummyNode>(compiler::Signatures::AMBIENT_INDEXER, indexName, returnType,
ir::DummyNodeFlag::INDEXER, typeAnno);
ES2PANDA_ASSERT(dummyNode != nullptr);
dummyNode->SetRange({startPos, Lexer()->GetToken().End()});
return dummyNode;
}
util::StringView ETSParser::ParseIndexName()
{
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
LogUnexpectedToken(Lexer()->GetToken());
auto pos = Lexer()->Save();
Lexer()->NextToken();
while (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
Lexer()->Rewind(pos);
Lexer()->NextToken();
pos = Lexer()->Save();
}
if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) {
Lexer()->GetToken().SetTokenType(lexer::TokenType::LITERAL_IDENT);
Lexer()->GetToken().SetTokenStr(ERROR_LITERAL);
}
}
auto const indexName = Lexer()->GetToken().Ident();
if (Lexer()->NextToken(); Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) {
LogError(diagnostic::INDEX_TYPE_EXPECTED);
Lexer()->GetToken().SetTokenType(lexer::TokenType::PUNCTUATOR_COLON);
}
return indexName;
}
std::pair<ir::TypeNode *, ir::TypeNode *> ETSParser::ParseIndexTypeAndReturnType()
{
if (Lexer()->NextToken(); Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_NUMBER &&
Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_STRING &&
Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_INT) {
LogError(diagnostic::INDEX_TYPE_NOT_NUMBER, {TokenToString(Lexer()->GetToken().Type())});
Lexer()->GetToken().SetTokenType(lexer::TokenType::KEYW_NUMBER);
}
TypeAnnotationParsingOptions typAnotationOptions = TypeAnnotationParsingOptions::NO_OPTS;
auto typeAnno = ParseTypeAnnotation(&typAnotationOptions);
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
LogError(diagnostic::EXPECTED_BRACKETS_IN_INDEX);
Lexer()->GetToken().SetTokenType(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET);
}
if (Lexer()->NextToken(); Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) {
LogError(diagnostic::INDEX_MISSING_TYPE);
}
if (!Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_COLON)) {
LogError(diagnostic::EXPECTED_PARAM_GOT_PARAM, {":", TokenToString(Lexer()->GetToken().Type())});
}
TypeAnnotationParsingOptions options =
TypeAnnotationParsingOptions::RETURN_TYPE | TypeAnnotationParsingOptions::REPORT_ERROR;
auto *returnType = ParseTypeAnnotation(&options);
return {typeAnno, returnType};
}
ir::TSTypeParameter *ETSParser::ParseTypeParameter([[maybe_unused]] TypeAnnotationParsingOptions *options)
{
lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
ArenaVector<ir::AnnotationUsage *> annotations {Allocator()->Adapter()};
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_AT) {
EatLeadingAtForAnnotation();
annotations = ParseAnnotations(false);
}
const auto varianceModifier = [this, options] {
switch (Lexer()->GetToken().KeywordType()) {
case lexer::TokenType::KEYW_IN:
case lexer::TokenType::KEYW_OUT:
return ParseTypeVarianceModifier(options);
default:
return ir::ModifierFlags::NONE;
}
}();
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_AT) {
EatLeadingAtForAnnotation();
auto moreAnnos = ParseAnnotations(false);
for (auto *anno : moreAnnos) {
annotations.push_back(anno);
}
}
auto saveLoc = Lexer()->GetToken().Start();
auto *paramIdent = ExpectIdentifier(false, false, *options | TypeAnnotationParsingOptions::REPORT_ERROR);
ir::TypeNode *constraint = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS) {
Lexer()->NextToken();
TypeAnnotationParsingOptions newOptions = TypeAnnotationParsingOptions::REPORT_ERROR;
constraint = ParseTypeAnnotation(&newOptions);
}
ir::TypeNode *defaultType = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
Lexer()->NextToken();
defaultType = ParseTypeAnnotation(options);
}
auto *typeParam =
AllocNode<ir::TSTypeParameter>(paramIdent, constraint, defaultType, varianceModifier, Allocator());
ES2PANDA_ASSERT(typeParam != nullptr);
ApplyAnnotationsToNode(typeParam, std::move(annotations), saveLoc);
typeParam->SetRange({startLoc, Lexer()->GetToken().End()});
return typeParam;
}
ir::Identifier *ETSParser::ParseClassIdent([[maybe_unused]] ir::ClassDefinitionModifiers modifiers)
{
return ExpectIdentifier(false, true);
}
bool ETSParser::IsStructKeyword() const
{
return (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT &&
Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STRUCT);
}
void ETSParser::ParseTrailingBlock(ir::CallExpression *callExpr)
{
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
SavedParserContext svCtx(this, ParserStatus::PARSE_TRAILING_BLOCK);
callExpr->SetIsTrailingBlockInNewLine(Lexer()->GetToken().NewLine());
callExpr->SetTrailingBlock(ParseBlockStatement());
}
}
void ETSParser::CheckDeclare()
{
ES2PANDA_ASSERT(Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_DECLARE);
if (InAmbientContext()) {
LogError(diagnostic::DECALRE_IN_AMBIENT_CONTEXT);
}
GetContext().Status() |= ParserStatus::IN_AMBIENT_CONTEXT;
Lexer()->NextToken();
if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT && Lexer()->GetToken().Ident().Is("module")) {
LogError(diagnostic::IMPLEMENTATION_IN_AMBIENT_CONTEXT);
return;
}
switch (Lexer()->GetToken().KeywordType()) {
case lexer::TokenType::KEYW_LET:
case lexer::TokenType::KEYW_CONST:
case lexer::TokenType::KEYW_FUNCTION:
case lexer::TokenType::KEYW_CLASS:
case lexer::TokenType::KEYW_NAMESPACE:
case lexer::TokenType::KEYW_ENUM:
case lexer::TokenType::KEYW_ABSTRACT:
case lexer::TokenType::KEYW_FINAL:
case lexer::TokenType::KEYW_INTERFACE:
case lexer::TokenType::KEYW_OVERLOAD:
case lexer::TokenType::KEYW_TYPE:
case lexer::TokenType::KEYW_ASYNC:
case lexer::TokenType::KEYW_STRUCT:
case lexer::TokenType::KEYW_GET:
case lexer::TokenType::KEYW_SET: {
return;
}
default: {
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_AT) {
return;
}
LogUnexpectedToken(Lexer()->GetToken());
}
}
}
void ETSParser::WarnPackageDeprecated()
{
if (!packageDeprecationWarned_) {
LogError(diagnostic::PACKAGE_DEPRECATED_WARNING);
packageDeprecationWarned_ = true;
}
}
void ETSParser::RaisePackageDeprecatedMessage()
{
if (util::Helpers::IsStdLib(GetProgram())) {
WarnPackageDeprecated();
} else {
LogError(diagnostic::PACKAGE_DEPRECATED);
}
}
void ETSParser::ValidateOverloadDeclarationModifiers(ir::ModifierFlags modifiers)
{
ir::ModifierFlags allowModifiers = ir::ModifierFlags::STATIC | ir::ModifierFlags::ASYNC |
ir::ModifierFlags::ACCESS | ir::ModifierFlags::EXPORTED |
ir::ModifierFlags::DECLARE;
if ((modifiers & ~allowModifiers) != 0) {
LogError(diagnostic::OVERLOAD_MODIFIERS);
}
}
bool ETSParser::ParseOverloadListElement(ArenaVector<ir::Expression *> &overloads,
ir::OverloadDeclaration *overloadDecl)
{
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
LogExpectedToken(lexer::TokenType::LITERAL_IDENT);
}
ir::Expression *qualifiedName = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
qualifiedName->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
while (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_PERIOD)) {
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
LogExpectedToken(lexer::TokenType::LITERAL_IDENT);
return false;
}
auto *identNode = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
identNode->SetRange(Lexer()->GetToken().Loc());
auto start = qualifiedName->Start();
qualifiedName = AllocNode<ir::MemberExpression>(qualifiedName, identNode,
ir::MemberExpressionKind::PROPERTY_ACCESS, false, false);
qualifiedName->SetRange({start, identNode->End()});
Lexer()->NextToken();
}
qualifiedName->SetParent(overloadDecl);
overloads.push_back(qualifiedName);
return true;
}
ir::OverloadDeclaration *ETSParser::ParseOverloadDeclaration(ir::ModifierFlags modifiers)
{
ValidateOverloadDeclarationModifiers(modifiers);
Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_OVERLOAD);
auto *overloadName = ExpectIdentifier(false, false, TypeAnnotationParsingOptions::REPORT_ERROR);
auto *overloadDef = AllocNode<ir::OverloadDeclaration>(overloadName->Clone(Allocator(), nullptr)->AsExpression(),
modifiers, Allocator());
overloadDef->AddOverloadDeclFlag(ir::OverloadDeclFlags::FUNCTION);
auto startLoc = overloadName->Start();
if (!Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_LEFT_BRACE)) {
LogExpectedToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE);
}
ArenaVector<ir::Expression *> overloads(Allocator()->Adapter());
lexer::SourcePosition endLoc;
ParseList(
lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::NONE,
[this, &overloads, overloadDef](bool &) { return ParseOverloadListElement(overloads, overloadDef); }, &endLoc,
ParseListOptions::ALLOW_TRAILING_SEP);
overloadDef->SetOverloadedList(std::move(overloads));
overloadDef->SetRange({startLoc, endLoc});
for (ir::Expression *overloadedName : overloadDef->OverloadedList()) {
std::function<bool(ir::Expression *)> checkQualifiedName = [&checkQualifiedName](ir::Expression *expr) -> bool {
if (expr->IsIdentifier()) {
return true;
}
if (expr->IsMemberExpression()) {
return expr->AsMemberExpression()->Property()->IsIdentifier() &&
checkQualifiedName(expr->AsMemberExpression()->Object());
}
return false;
};
if (!checkQualifiedName(overloadedName)) {
LogError(diagnostic::FUNCTION_OVERLOADED_NAME_MUST_QUALIFIED_NAME, {}, overloadedName->Start());
}
}
return overloadDef;
}
ir::FunctionDeclaration *ETSParser::ParseFunctionDeclaration(bool canBeAnonymous, ir::ModifierFlags modifiers)
{
lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
ES2PANDA_ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_FUNCTION);
Lexer()->NextToken();
auto newStatus = ParserStatus::NEED_RETURN_TYPE | ParserStatus::ALLOW_SUPER;
if ((modifiers & ir::ModifierFlags::ASYNC) != 0) {
newStatus |= ParserStatus::ASYNC_FUNCTION;
}
if (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_MULTIPLY)) {
LogError(diagnostic::GENERATOR_FUNCTION);
newStatus |= ParserStatus::GENERATOR_FUNCTION;
}
ir::Identifier *funcIdentNode = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) {
funcIdentNode = ExpectIdentifier();
} else if (!canBeAnonymous) {
LogError(diagnostic::UNEXPECTED_TOKEN_ID);
funcIdentNode = AllocBrokenExpression(Lexer()->GetToken().Loc());
}
if (funcIdentNode != nullptr) {
CheckRestrictedBinding(funcIdentNode->Name(), funcIdentNode->Start());
}
ir::ScriptFunction *func =
ParseFunction(newStatus | ParserStatus::FUNCTION_DECLARATION | ParserStatus::ALLOW_RECEIVER);
ES2PANDA_ASSERT(func != nullptr);
if (funcIdentNode != nullptr) {
func->SetIdent(funcIdentNode);
}
auto *funcDecl = AllocNode<ir::FunctionDeclaration>(Allocator(), func);
if (func->IsOverload() && Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) {
Lexer()->NextToken();
}
ES2PANDA_ASSERT(funcDecl != nullptr);
funcDecl->SetRange(func->Range());
func->AddModifier(modifiers);
func->SetStart(startLoc);
return funcDecl;
}
void ETSParser::ValidateGetterSetter(ir::MethodDefinitionKind methodDefinition, const ir::ScriptFunction *func,
bool hasReceiver)
{
const auto ¶ms = func->Params();
const size_t receiverOffset = hasReceiver ? 1 : 0;
if (methodDefinition == ir::MethodDefinitionKind::SET) {
if (func->ReturnTypeAnnotation() != nullptr) {
LogError(diagnostic::SETTER_NO_RETURN_TYPE, {}, func->Start());
}
if (params.size() != 1 + receiverOffset) {
LogError(hasReceiver ? diagnostic::EXTENSION_SETTER_WRONG_PARAM : diagnostic::SETTER_FORMAL_PARAMS, {},
func->Start());
return;
}
if (!params[0 + receiverOffset]->IsETSParameterExpression()) {
ES2PANDA_ASSERT(DiagnosticEngine().IsAnyError());
return;
}
auto setterParam = params[0 + receiverOffset]->AsETSParameterExpression();
if (setterParam->IsOptional()) {
LogError(diagnostic::SETTER_OPTIONAL_PARAM, {}, params[0 + receiverOffset]->Start());
} else if (setterParam->Spread() != nullptr) {
LogError(diagnostic::SETTER_REST_PARAM, {}, params[0 + receiverOffset]->Start());
}
} else if (methodDefinition == ir::MethodDefinitionKind::GET) {
if (params.size() != receiverOffset) {
LogError(hasReceiver ? diagnostic::EXTENSION_GETTER_WRONG_PARAM : diagnostic::GETTER_FORMAL_PARAMS, {},
func->Start());
}
}
}
ir::FunctionDeclaration *ETSParser::ParseTopLevelAccessor(ir::ModifierFlags modifiers)
{
ES2PANDA_ASSERT(Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_GET ||
Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_SET);
bool isGetter = Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_GET;
lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
Lexer()->NextToken();
auto newStatus = ParserStatus::ALLOW_SUPER | ParserStatus::FUNCTION_DECLARATION | ParserStatus::ALLOW_RECEIVER;
ir::Identifier *funcIdentNode = ExpectIdentifier();
ES2PANDA_ASSERT(funcIdentNode != nullptr);
CheckRestrictedBinding(funcIdentNode->Name(), funcIdentNode->Start());
ir::ScriptFunction *func =
isGetter ? ParseFunction(newStatus | ParserStatus::NEED_RETURN_TYPE) : ParseFunction(newStatus);
ES2PANDA_ASSERT(func != nullptr);
func->SetStart(startLoc);
auto params = func->Params();
bool hasReceiver = !params.empty() && params[0]->IsETSParameterExpression() &&
params[0]->AsETSParameterExpression()->Ident()->IsReceiver();
if (isGetter) {
func->AddFlag(ir::ScriptFunctionFlags::GETTER);
} else {
func->AddFlag(ir::ScriptFunctionFlags::SETTER);
}
ValidateGetterSetter(isGetter ? ir::MethodDefinitionKind::GET : ir::MethodDefinitionKind::SET, func, hasReceiver);
func->SetIdent(funcIdentNode);
auto *funcDecl = AllocNode<ir::FunctionDeclaration>(Allocator(), func);
ES2PANDA_ASSERT(funcDecl != nullptr);
funcDecl->SetRange(func->Range());
func->AddModifier(modifiers);
return funcDecl;
}
void ETSParser::EnsureContainingPackageIsRegistered(ir::ETSPackageDeclaration *packageDecl)
{
ES2PANDA_ASSERT(packageDecl->Range().start.Program() == GetProgram());
auto *packageFraction = GetProgram();
[[maybe_unused]] auto packageProg =
GetImportPathManager()->EnsurePackageIsRegisteredByPackageFraction(packageFraction, packageDecl);
ES2PANDA_ASSERT(packageFraction->GetModuleKind() == util::ModuleKind::MODULE);
ES2PANDA_ASSERT(packageProg->ModuleName() == packageFraction->ModuleName());
}
ExternalSourceParser::ExternalSourceParser(ETSParser *parser, Program *newProgram)
: parser_(parser),
savedProgram_(parser_->GetProgram()),
savedLexer_(parser_->Lexer()),
savedTopScope_(parser_->GetProgram()->VarBinder()->TopScope())
{
parser_->SetProgram(newProgram);
parser_->GetContext().SetProgram(newProgram);
}
ExternalSourceParser::~ExternalSourceParser()
{
parser_->SetLexer(savedLexer_);
parser_->SetProgram(savedProgram_);
parser_->GetContext().SetProgram(savedProgram_);
parser_->GetProgram()->VarBinder()->ResetTopScope(savedTopScope_);
}
InnerSourceParser::InnerSourceParser(ETSParser *parser) : parser_(parser), savedLexer_(parser_->Lexer()) {}
InnerSourceParser::~InnerSourceParser()
{
parser_->SetLexer(savedLexer_);
}
}