diff --git a/ets2panda/checker/ETSchecker.cpp b/ets2panda/checker/ETSchecker.cpp index 3955fcc851bfab84788b8f51bdac0b368d59a38a..4991dd00e14a9e1309cc8cb0ab1eeeb54f3ab54b 100644 --- a/ets2panda/checker/ETSchecker.cpp +++ b/ets2panda/checker/ETSchecker.cpp @@ -386,6 +386,17 @@ void ETSChecker::CheckProgram(parser::Program *program, bool runAnalysis) } } + for (auto *projProg : program->ProjectSources()) { + if (projProg->IsASTChecked()) { + continue; + } + checker::SavedCheckerContext savedContext(this, Context().Status(), Context().ContainingClass()); + AddStatus(checker::CheckerStatus::IN_EXTERNAL); + ES2PANDA_ASSERT(!IsAnyError()); + CheckProgram(projProg, VarBinder()->IsGenStdLib()); + projProg->SetFlag(parser::ProgramFlags::AST_CHECK_PROCESSED); + } + ES2PANDA_ASSERT(Program()->Ast()->IsProgram()); Program()->Ast()->Check(this); @@ -395,7 +406,7 @@ void ETSChecker::CheckProgram(parser::Program *program, bool runAnalysis) AssignAnalyzer(this).Analyze(Program()->Ast()); } - ES2PANDA_ASSERT(VarBinder()->AsETSBinder()->GetExternalRecordTable().find(program)->second); + ES2PANDA_ASSERT(VarBinder()->AsETSBinder()->GetExternalRecordTable().find(Program())->second); SetProgram(savedProgram); } diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 79552cedb29fd6530fe53f5e3e4b2c7e37129572..6bfd295b4a1888263b6c3dd4278e3d902d9b24b4 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -92,6 +92,7 @@ public: invokeToArrowSignatures_(Allocator()->Adapter()), arrowToFuncInterfaces_(Allocator()->Adapter()), globalArraySignatures_(Allocator()->Adapter()), + cachedComputedAbstracts_(Allocator()->Adapter()), dynamicIntrinsics_ {DynamicCallIntrinsicsMap {Allocator()->Adapter()}, DynamicCallIntrinsicsMap {Allocator()->Adapter()}}, dynamicClasses_ {DynamicClassIntrinsicsMap(Allocator()->Adapter()), @@ -954,24 +955,7 @@ public: ComputedAbstracts *GetCachedComputedAbstracts() { - if (cachedComputedAbstracts_ == nullptr) { - InitCachedComputedAbstracts(); - } - return cachedComputedAbstracts_; - } - - void SetCachedComputedAbstracts(ComputedAbstracts *cachedComputedAbstracts) - { - cachedComputedAbstracts_ = cachedComputedAbstracts; - } - - void InitCachedComputedAbstracts() - { - // clang-format off - cachedComputedAbstracts_ = ProgramAllocator()->New, - ArenaUnorderedSet>>>(ProgramAllocator()->Adapter()); - // clang-format on + return &cachedComputedAbstracts_; } private: @@ -1097,7 +1081,7 @@ private: FunctionInterfaceMap arrowToFuncInterfaces_; size_t constraintCheckScopesCount_ {0}; GlobalArraySignatureMap globalArraySignatures_; - ComputedAbstracts *cachedComputedAbstracts_ {nullptr}; + ComputedAbstracts cachedComputedAbstracts_; // NOTE(aleksisch): Extract dynamic from checker to separate class std::array dynamicIntrinsics_; std::array dynamicClasses_; diff --git a/ets2panda/checker/ets/dynamic.cpp b/ets2panda/checker/ets/dynamic.cpp index f5d2544345b31dd7d9677a2248c32ca4b9186ba8..55e7482ebd61932bc80163f2107c13b5f7be391e 100644 --- a/ets2panda/checker/ets/dynamic.cpp +++ b/ets2panda/checker/ets/dynamic.cpp @@ -369,9 +369,26 @@ ir::ClassDeclaration *ETSChecker::BuildClass(util::StringView name, const ClassB classDecl->SetParent(VarBinder()->Program()->Ast()); auto varBinder = VarBinder()->AsETSBinder(); - bool isExternal = VarBinder()->Program() != varBinder->GetGlobalRecordTable()->Program(); - auto recordTable = isExternal ? varBinder->GetExternalRecordTable().at(varBinder->Program()) - : VarBinder()->AsETSBinder()->GetGlobalRecordTable(); + auto *globalProgram = varBinder->GetGlobalRecordTable()->Program(); + auto *program = VarBinder()->Program(); + bool isExternal = program != globalProgram; + bool isProject = false; + if (isExternal) { + for (auto *projProg : globalProgram->ProjectSources()) { + if (projProg == globalProgram) { + isProject = true; + break; + } + } + } + varbinder::RecordTable *recordTable; + if (isProject) { + recordTable = varBinder->GetProjectRecordTable().at(program); + } else if (isExternal) { + recordTable = varBinder->GetExternalRecordTable().at(program); + } else { + recordTable = VarBinder()->AsETSBinder()->GetGlobalRecordTable(); + } varbinder::BoundContext boundCtx(recordTable, classDef); ArenaVector classBody(ProgramAllocator()->Adapter()); diff --git a/ets2panda/checker/ets/utilityTypeHandlers.cpp b/ets2panda/checker/ets/utilityTypeHandlers.cpp index c267defa3c8f07b568c3720c739da8bc9d218139..e8be91e964d19c937f19dc18bd3f238a22b91085 100644 --- a/ets2panda/checker/ets/utilityTypeHandlers.cpp +++ b/ets2panda/checker/ets/utilityTypeHandlers.cpp @@ -102,9 +102,15 @@ static std::pair GetPartialClassPro ir::AstNode *typeNode) { auto classDefProgram = typeNode->GetTopStatement()->AsETSModule()->Program(); - if (classDefProgram == checker->VarBinder()->AsETSBinder()->GetGlobalRecordTable()->Program()) { + auto *program = checker->VarBinder()->AsETSBinder()->GetGlobalRecordTable()->Program(); + if (classDefProgram == program) { return {classDefProgram, checker->VarBinder()->AsETSBinder()->GetGlobalRecordTable()}; } + for (auto *projProg : program->ProjectSources()) { + if (classDefProgram == projProg) { + return {classDefProgram, checker->VarBinder()->AsETSBinder()->GetProjectRecordTable().at(classDefProgram)}; + } + } return {classDefProgram, checker->VarBinder()->AsETSBinder()->GetExternalRecordTable().at(classDefProgram)}; } diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index 1e5e752ae776abd6934cf31d8e127a3f69eb6587..131a9fb74b6f9a4f1813fb05fc9d9135345cd70c 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -177,13 +177,11 @@ static bool RunVerifierAndPhases(public_lib::Context &context, parser::Program & { auto &options = const_cast(*context.config->options); const auto verifierEachPhase = options.IsAstVerifierEachPhase(); - ast_verifier::ASTVerifier verifier(context, program); checker::IsolatedDeclgenChecker isolatedDeclgenChecker(*context.diagnosticEngine, program); if (options.IsGenerateDeclEnableIsolated()) { options.SetGenerateDeclEnabled(true); } - bool skipPhase = false; while (auto phase = context.phaseManager->NextPhase()) { const auto name = std::string {phase->Name()}; @@ -193,32 +191,26 @@ static bool RunVerifierAndPhases(public_lib::Context &context, parser::Program & if (skipPhase) { continue; } - if (options.IsGenerateDeclEnableIsolated() && name == "plugins-after-check") { return false; } - if (CheckOptionsBeforePhase(options, program, name) || !phase->Apply(&context, &program) || CheckOptionsAfterPhase(options, program, name)) { return false; } - if (!DoIsolatedDeclgenCheck(options, name, isolatedDeclgenChecker, context)) { return false; } - if (!options.IsGenerateDeclEnableIsolated()) { verifier.IntroduceNewInvariants(phase->Name()); } if (verifierEachPhase || options.HasVerifierPhase(phase->Name())) { verifier.Verify(phase->Name()); } - // Stop lowerings processing after Checker phase if any error happened. if (phase->Name() == compiler::CheckerPhase::NAME && context.diagnosticEngine->IsAnyError()) { return false; } - if (options.IsGenerateDeclEnabled() && name == compiler::CheckerPhase::NAME) { std::string path; if (!options.WasSetGenerateDeclPath()) { @@ -229,7 +221,6 @@ static bool RunVerifierAndPhases(public_lib::Context &context, parser::Program & HandleGenerateDecl(program, *context.diagnosticEngine, path, options.IsGenerateDeclEnableIsolated()); } } - return true; } @@ -273,39 +264,6 @@ static void CreateDebuggerEvaluationPlugin(checker::ETSChecker &checker, ArenaAl using EmitCb = std::function; using PhaseListGetter = std::function(ScriptExtension)>; -static void AddExternalPrograms(public_lib::Context *ctx, const CompilationUnit &unit, parser::Program *program) -{ - auto &extSources = program->ExternalSources(); - for (const auto &[moduleName, extPrograms] : ctx->externalSources) { - for (auto *const extProg : extPrograms) { - if (extProg->SourceFilePath() == unit.input.filePath) { - continue; - } - if (extSources.count(moduleName) == 0) { - extSources.emplace(moduleName, program->Allocator()->Adapter()); - } - extSources.at(moduleName).emplace_back(extProg); - } - } - auto varbinder = static_cast(ctx->transitionMemory->VarBinder()); - auto externalRecordTable = varbinder->GetExternalRecordTable(); - for (auto [extProg, recordTable] : externalRecordTable) { - if (program->SourceFilePath() == extProg->SourceFilePath()) { - externalRecordTable.erase(externalRecordTable.find(extProg)); - break; - } - } - auto &prevGlobalTypes = ctx->transitionMemory->GlobalTypes()->GlobalTypes(); - for (auto *gt : prevGlobalTypes) { - if (gt != nullptr && gt->IsETSObjectType()) { - auto *relation = gt->AsETSObjectType()->GetRelation(); - if (relation != nullptr) { - relation->SetChecker(ctx->GetChecker()); - } - } - } -} - [[maybe_unused]] static void MarkAsLowered(parser::Program &program) { for (auto &[name, extPrograms] : program.ExternalSources()) { @@ -317,104 +275,144 @@ static void AddExternalPrograms(public_lib::Context *ctx, const CompilationUnit } } -static void EmplaceProgram(public_lib::Context *ctx, util::StringView moduleName, parser::Program *extProg) +static bool IsFuncInProgram(varbinder::FunctionScope *function, parser::Program *program) { - auto &extSources = ctx->externalSources; - if (extSources.count(moduleName) == 0) { - extSources.emplace(moduleName, ctx->transitionMemory->PermanentAllocator()->Adapter()); + auto *parent = function->Node(); + for (; parent != nullptr && parent->Parent() != nullptr; parent = parent->Parent()) { } - bool found = false; - for (auto extSrc : extSources.at(moduleName)) { - if (extSrc->SourceFilePath() == extProg->SourceFilePath()) { - found = true; - break; + return program->Ast() == parent; +} + +static ArenaMap> *InitSavedSignatures( + public_lib::Context *context) +{ + auto *parserProgram = context->parserProgram; + auto *varbinder = static_cast(parserProgram->VarBinder()); + auto savedSignatures = + new ArenaMap>(context->Allocator()->Adapter()); + for (auto *projProg : parserProgram->ProjectSources()) { + savedSignatures->emplace(projProg, context->Allocator()->Adapter()); + for (auto *signature : varbinder->GetProjectRecordTable().at(projProg)->Signatures()) { + savedSignatures->at(projProg).insert(signature); } } - if (!found) { - extSources.at(moduleName).emplace_back(extProg); - } + return savedSignatures; } -static void SavePermanents(public_lib::Context *ctx, parser::Program *program) +static void InitProjectProgramSignatures(public_lib::Context *context) { - for (const auto &[moduleName, extPrograms] : program->ExternalSources()) { - for (auto *const extProg : extPrograms) { - EmplaceProgram(ctx, moduleName, extProg); + auto *parserProgram = context->parserProgram; + auto *varbinder = static_cast(parserProgram->VarBinder()); + auto &functions = varbinder->Functions(); + for (auto function : functions) { + for (auto *projProg : parserProgram->ProjectSources()) { + if (IsFuncInProgram(function, projProg)) { + varbinder->GetProjectRecordTable().at(projProg)->Signatures().insert(function); + } } } - ctx->transitionMemory->SetVarBinder(program->VarBinder()); - auto *topScope = ctx->transitionMemory->VarBinder()->TopScope(); - ES2PANDA_ASSERT(topScope->IsGlobalScope()); - auto decls = topScope->Decls(); - auto path = program->SourceFilePath(); - // clang-format off - decls.erase(std::remove_if(decls.begin(), decls.end(), - [path](varbinder::Decl *d) -> bool { - auto *n = d->Node(); - if (n == nullptr || n->Start().Program() == nullptr) { - return true; +} + +static void EmitMultiOutput(CompilerImpl *compilerImpl, public_lib::Context *context, + ArenaMap> *savedSignatures, + ArenaVector *savedFunctions) +{ + auto *parserProgram = context->parserProgram; + auto *varbinder = static_cast(parserProgram->VarBinder()); + auto *globalRecordTable = varbinder->GetGlobalRecordTable(); + auto &functions = varbinder->Functions(); + functions.clear(); + for (auto *projProg : parserProgram->ProjectSources()) { + parserProgram->SetAst(projProg->Ast()); + auto *projectRecordTable = varbinder->GetProjectRecordTable().at(projProg); + globalRecordTable->CleanUp(); + globalRecordTable->CopyRecordTable(projectRecordTable); + globalRecordTable->SetRecord(projectRecordTable->GetRecord()); + varbinder->GetRecordTable()->SetRecord(projectRecordTable->GetRecord()); + globalRecordTable->SetFlags(projectRecordTable->Flags()); + for (auto *func : *savedFunctions) { + if (IsFuncInProgram(func, projProg)) { + functions.emplace_back(func); } - auto sourceFile = n->Start().Program()->SourceFilePath(); - return sourceFile == "" || sourceFile == path; - }), - decls.end()); - // clang-format on - - auto res = topScope->Find(util::StringView("ETSGLOBAL")); - auto *var = res.variable; - var->SetTsType(nullptr); - auto moduleName = std::string(program->ModuleName()); - auto globalClassName = moduleName.substr(moduleName.find_last_of('.') + 1); - topScope->EraseBinding(util::StringView(globalClassName)); - - std::vector declaredKeys; - for (auto &&it : topScope->Bindings()) { - var = it.second; - if (var->Declaration() != nullptr && var->Declaration()->Node() != nullptr) { - auto *node = var->Declaration()->Node(); - if (node->Range().start.Program() == program) { - declaredKeys.emplace_back(it.first); + } + globalRecordTable->Signatures().clear(); + for (auto *signature : savedSignatures->at(projProg)) { + globalRecordTable->Signatures().insert(signature); + } + auto externalRecordTable = varbinder->GetExternalRecordTable(); + for (auto *extProjProg : parserProgram->ProjectSources()) { + if (extProjProg == projProg) { + continue; } + auto *projExtRecordTable = varbinder->GetProjectRecordTable().at(extProjProg); + varbinder->GetExternalRecordTable().insert({extProjProg, projExtRecordTable}); + } + context->emitter->GenAnnotation(); + auto *program = compilerImpl->Emit(context); + context->projectPrograms.emplace_back(program); + context->emitter->SetProgram(new pandasm::Program()); + functions.clear(); + for (auto *extProjProg : parserProgram->ProjectSources()) { + varbinder->GetExternalRecordTable().erase(extProjProg); } } - for (auto &&key : declaredKeys) { - topScope->EraseBinding(key); - } - - auto *varbinder = static_cast(program->VarBinder()); - varbinder->GetGlobalRecordTable()->CleanUp(); - varbinder->Functions().clear(); - - ctx->transitionMemory->SetGlobalTypes(ctx->GetChecker()->GetGlobalTypesHolder()); - ctx->transitionMemory->SetCachechedComputedAbstracts( - ctx->GetChecker()->AsETSChecker()->GetCachedComputedAbstracts()); - ctx->transitionMemory->AddCompiledProgram(ctx->parserProgram); } -static pandasm::Program *EmitProgram(CompilerImpl *compilerImpl, public_lib::Context *context, - const CompilationUnit &unit) +static pandasm::Program *EmitProgram(CompilerImpl *compilerImpl, public_lib::Context *context) { - context->emitter->GenAnnotation(); - auto result = compilerImpl->Emit(context); - if (unit.ext == ScriptExtension::ETS && context->compilingState != public_lib::CompilingState::SINGLE_COMPILING) { - SavePermanents(context, context->parserProgram); + if (context->compilingState != public_lib::CompilingState::MULTI_COMPILING) { + context->emitter->GenAnnotation(); + return compilerImpl->Emit(context); + } + auto *parserProgram = context->parserProgram; + auto *varbinder = static_cast(parserProgram->VarBinder()); + if (context->compilingOuput == public_lib::CompilingOutput::MULTI_OUTPUT) { + auto savedSignatures = InitSavedSignatures(context); + auto &functions = varbinder->Functions(); + auto savedFunctions = new ArenaVector(context->Allocator()->Adapter()); + for (auto function : functions) { + savedFunctions->emplace_back(function); + } + InitProjectProgramSignatures(context); + EmitMultiOutput(compilerImpl, context, savedSignatures, savedFunctions); + delete savedFunctions; + delete savedSignatures; + } else { + auto *globalRecordTable = varbinder->GetGlobalRecordTable(); + globalRecordTable->CleanUp(); + for (auto *projProg : parserProgram->ProjectSources()) { + auto *projectRecordTable = varbinder->GetProjectRecordTable().at(projProg); + globalRecordTable->CopyRecordTable(projectRecordTable); + } + context->emitter->GenAnnotation(); + auto *program = compilerImpl->Emit(context); + context->projectPrograms.emplace_back(program); } - return result; + return nullptr; } static bool ExecuteParsingAndCompiling(const CompilationUnit &unit, public_lib::Context *context) { parser::Program *program = context->parserProgram; - if (unit.ext == ScriptExtension::ETS && - context->compilingState == public_lib::CompilingState::MULTI_COMPILING_FOLLOW) { - AddExternalPrograms(context, unit, program); + + bool genStdLib = unit.options.GetCompilationMode() == CompilationMode::GEN_STD_LIB; + auto &projectSourceFiles = program->ProjectSourceFiles(); + for (auto *cu : context->compilationUnits) { + projectSourceFiles.emplace_back(cu->input); } + context->parser->ParseScript(unit.input, genStdLib); - context->parser->ParseScript(unit.input, unit.options.GetCompilationMode() == CompilationMode::GEN_STD_LIB); + if (!program->ProjectSources().empty()) { + auto extSources = program->ExternalSources(); + for (auto *projProg : program->ProjectSources()) { + projProg->SetFlag(parser::ProgramFlags::AST_FROM_PROJECT); + ES2PANDA_ASSERT(projProg->ExternalSources().empty()); + } + } - // We have to check the return status of 'RunVerifierAndPhase` and 'RunPhases` separately because there can be - // some internal errors (say, in Post-Conditional check) or terminate options (say in 'CheckOptionsAfterPhase') - // that were not reported to the log. + // We have to check the return status of 'RunVerifierAndPhase` and 'RunPhases` separately because there can + // be some internal errors (say, in Post-Conditional check) or terminate options (say in + // 'CheckOptionsAfterPhase') that were not reported to the log. if (unit.ext == ScriptExtension::ETS) { if (!RunVerifierAndPhases(*context, *program)) { return false; @@ -443,10 +441,7 @@ static pandasm::Program *Compile(const CompilationUnit &unit, CompilerImpl *comp context->sourceFile = &unit.input; context->queue = compilerImpl->Queue(); context->plugins = &compilerImpl->Plugins(); - auto program = parser::Program::NewProgram( - context->allocator, context->compilingState == public_lib::CompilingState::MULTI_COMPILING_FOLLOW - ? context->transitionMemory->VarBinder() - : nullptr); + auto program = parser::Program::NewProgram(context->allocator, nullptr); auto parser = Parser(&program, unit.options, unit.diagnosticEngine, static_cast(unit.rawParserStatus)); context->parser = &parser; @@ -463,13 +458,6 @@ static pandasm::Program *Compile(const CompilationUnit &unit, CompilerImpl *comp if constexpr (std::is_same_v) { CreateDebuggerEvaluationPlugin(checker, *context->allocator, &program, unit.options); - if (context->compilingState == public_lib::CompilingState::MULTI_COMPILING_FOLLOW) { - checker.SetCachedComputedAbstracts(context->transitionMemory->CachedComputedAbstracts()); - checker.SetGlobalTypesHolder(context->transitionMemory->GlobalTypes()); - checker.AddStatus(ark::es2panda::checker::CheckerStatus::BUILTINS_INITIALIZED); - } else { - checker.InitCachedComputedAbstracts(); - } } auto emitter = Emitter(context); context->emitter = &emitter; @@ -481,9 +469,8 @@ static pandasm::Program *Compile(const CompilationUnit &unit, CompilerImpl *comp if (!ExecuteParsingAndCompiling(unit, context)) { return nullptr; } - MarkAsLowered(program); - return EmitProgram(compilerImpl, context, unit); + return EmitProgram(compilerImpl, context); } pandasm::Program *CompilerImpl::Compile(const CompilationUnit &unit, public_lib::Context *context) diff --git a/ets2panda/compiler/core/emitter.h b/ets2panda/compiler/core/emitter.h index 84049be833c5801b44ffd519df33a6851417c1d1..a3d415ebc01bd234779b023aa02ca55f7b35d39a 100644 --- a/ets2panda/compiler/core/emitter.h +++ b/ets2panda/compiler/core/emitter.h @@ -117,6 +117,11 @@ public: return literalBufferIndex_; } + void SetProgram(pandasm::Program *prog) + { + prog_ = prog; + } + virtual void GenAnnotation() = 0; protected: diff --git a/ets2panda/compiler/lowering/checkerPhase.cpp b/ets2panda/compiler/lowering/checkerPhase.cpp index 7f820e81684e5f102610413e9dcaf64b829adc93..dcbbbc6db05689c2d98bde8b97f9b7c773397aa1 100644 --- a/ets2panda/compiler/lowering/checkerPhase.cpp +++ b/ets2panda/compiler/lowering/checkerPhase.cpp @@ -45,6 +45,11 @@ bool CheckerPhase::Perform(public_lib::Context *ctx, [[maybe_unused]] parser::Pr } } } + for (auto prog : program->ProjectSources()) { + if (!prog->IsASTLowered()) { + MarkStatementsNoCleanup(prog); + } + } for (auto stmt : program->Ast()->Statements()) { stmt->AddAstNodeFlags(ir::AstNodeFlags::NOCLEANUP); } diff --git a/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp b/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp index c88ab3572b51a831e15f60d1bffe3e22bae19a02..2eae22f350ac3da201d0a70ce5f2790177beba2d 100644 --- a/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp +++ b/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp @@ -449,6 +449,19 @@ bool InterfaceObjectLiteralLowering::Perform(public_lib::Context *ctx, parser::P } } + for (auto *projProg : program->ProjectSources()) { + auto *savedProgram = varbinder->Program(); + auto *savedRecordTable = varbinder->GetRecordTable(); + auto *savedTopScope = varbinder->TopScope(); + varbinder->ResetTopScope(projProg->GlobalScope()); + varbinder->SetRecordTable(varbinder->GetProjectRecordTable().at(projProg)); + varbinder->SetProgram(projProg); + TransfromInterfaceDecl(ctx, projProg); + varbinder->SetProgram(savedProgram); + varbinder->SetRecordTable(savedRecordTable); + varbinder->ResetTopScope(savedTopScope); + } + TransfromInterfaceDecl(ctx, program); for (auto &[_, extPrograms] : program->ExternalSources()) { @@ -461,6 +474,10 @@ bool InterfaceObjectLiteralLowering::Perform(public_lib::Context *ctx, parser::P } } + for (auto *projProg : program->ProjectSources()) { + TransfromInterfaceLiteral(ctx, projProg); + } + TransfromInterfaceLiteral(ctx, program); return true; diff --git a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp index d3ad50c52ab91206a19b5d2cc231200e6f2a965f..41be140dda5c5b68c9abe7b17f6a66ccde530940 100644 --- a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp +++ b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp @@ -1276,7 +1276,14 @@ static ir::AstNode *LowerTypeNodeIfNeeded(public_lib::Context *ctx, ir::AstNode bool LambdaConversionPhase::PerformForModule(public_lib::Context *ctx, parser::Program *program) { auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); - varbinder::RecordTableContext bctx {varBinder, program == ctx->parserProgram ? nullptr : program}; + parser::Program *recordProgram = nullptr; + auto projectSources = ctx->parserProgram->ProjectSources(); + if (program != ctx->parserProgram && + std::find(projectSources.begin(), projectSources.end(), program) == projectSources.end()) { + recordProgram = program; + } + varbinder::RecordTableContext bctx {varBinder, recordProgram}; + parser::SavedFormattingFileName savedFormattingName(ctx->parser->AsETSParser(), "lambda-conversion"); // For reproducibility of results when several compilation sessions are executed during diff --git a/ets2panda/compiler/lowering/ets/restTupleLowering.cpp b/ets2panda/compiler/lowering/ets/restTupleLowering.cpp index 36554fe955212ce3e679794bc205195106f145e5..9d388f9afb56042b054af752d5637168318934a4 100644 --- a/ets2panda/compiler/lowering/ets/restTupleLowering.cpp +++ b/ets2panda/compiler/lowering/ets/restTupleLowering.cpp @@ -268,7 +268,6 @@ ir::ScriptFunction *CreateNewScriptFunction(public_lib::Context *ctx, ir::Script for (auto *annotationUsage : scriptFunc->Annotations()) { annotationUsages.push_back(annotationUsage->Clone(allocator, newScriptFunc)->AsAnnotationUsage()); } - std::cerr << "CreateNewScriptFunction SetAnnotations for newScriptFunc " << newScriptFunc << std::endl; newScriptFunc->SetAnnotations(std::move(annotationUsages)); ir::Identifier *newScriptFuncId = scriptFunc->Id()->Clone(allocator, newScriptFunc); diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp index c30b85b05f929c09158a15aff144226fc7ebad43..2d7dc23ddc50960e3f1b09783f3dbe00c4a814d6 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp @@ -557,7 +557,9 @@ void GlobalClassHandler::SetupGlobalMethods(parser::Program *program, ArenaVecto ir::ClassDefinition *const globalClass = program->GlobalClass(); SetupGlobalMethods(program, std::move(initStatements), globalClass, program->IsDeclarationModule()); - if (program->IsSeparateModule() && !HasMethod(globalClass, compiler::Signatures::MAIN)) { + auto *ctx = program->VarBinder()->GetContext(); + if (program->IsSeparateModule() && !HasMethod(globalClass, compiler::Signatures::MAIN) && + ctx->compilingState != public_lib::CompilingState::MULTI_COMPILING) { ir::MethodDefinition *mainMethod = CreateGlobalMethod( compiler::Signatures::MAIN, ArenaVector(allocator_->Adapter()), program); InsertInGlobal(globalClass, mainMethod); diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/topLevelStmts.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/topLevelStmts.cpp index 80439e2effbc39e555c0bd3b0c9d36a44de94703..d848d50c90041b44cd5c6794886059b2d699bf1d 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/topLevelStmts.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/topLevelStmts.cpp @@ -111,6 +111,14 @@ bool TopLevelStatements::Perform(public_lib::Context *ctx, parser::Program *prog } } } + if (!program->ProjectSources().empty()) { + for (auto *projProg : program->ProjectSources()) { + ArenaVector projModule(ctx->Allocator()->Adapter()); + projModule.emplace_back(projProg); + auto moduleDependencies = imports.HandleGlobalStmts(projModule); + globalClass.SetupGlobalClass(projModule, &moduleDependencies); + } + } ArenaVector mainModule(ctx->Allocator()->Adapter()); mainModule.emplace_back(program); diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index 75256702000047ba0936a01fc7844c149bc726c9..d10d58c0dcba2c574a0444e67dfb19a6e787b4a8 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -255,6 +255,12 @@ bool PhaseForDeclarations::Precondition(public_lib::Context *ctx, const parser:: } } + for (auto *projProgram : program->ProjectSources()) { + if (!Precondition(ctx, projProgram)) { + return false; + }; + } + return PreconditionForModule(ctx, program); } @@ -271,6 +277,10 @@ bool PhaseForDeclarations::Perform(public_lib::Context *ctx, parser::Program *pr } } + for (auto *projProgram : program->ProjectSources()) { + result &= Perform(ctx, projProgram); + } + result &= PerformForModule(ctx, program); return result; } @@ -289,6 +299,12 @@ bool PhaseForDeclarations::Postcondition(public_lib::Context *ctx, const parser: } } + for (auto *projProgram : program->ProjectSources()) { + if (!Postcondition(ctx, projProgram)) { + return false; + }; + } + return PostconditionForModule(ctx, program); } @@ -312,6 +328,12 @@ bool PhaseForBodies::Precondition(public_lib::Context *ctx, const parser::Progra } } + for (auto *projProgram : program->ProjectSources()) { + if (!Precondition(ctx, projProgram)) { + return false; + }; + } + return PreconditionForModule(ctx, program); } @@ -337,6 +359,10 @@ bool PhaseForBodies::Perform(public_lib::Context *ctx, parser::Program *program) result &= ProcessExternalPrograms(ctx, program); } + for (auto *projProgram : program->ProjectSources()) { + result &= Perform(ctx, projProgram); + } + result &= PerformForModule(ctx, program); return result; } @@ -361,6 +387,12 @@ bool PhaseForBodies::Postcondition(public_lib::Context *ctx, const parser::Progr } } + for (auto *projProgram : program->ProjectSources()) { + if (!Postcondition(ctx, projProgram)) { + return false; + }; + } + return PostconditionForModule(ctx, program); } diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp index e19ee51185db89b778173f5c39394479b232df9b..69df54f1e58bbdbf8fca36b557774ff95669aa41 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp @@ -830,10 +830,6 @@ bool InitScopesPhaseETS::Perform(PhaseContext *ctx, parser::Program *program) program->VarBinder()->InitTopScope(); BindScopeNode(GetScope(), program->Ast()); AddGlobalToBinder(program); - } else if ((ctx->compilingState == public_lib::CompilingState::MULTI_COMPILING_FOLLOW) && - program->GlobalClass()->Scope() == nullptr) { - BindScopeNode(GetScope(), program->Ast()); - AddGlobalToBinder(program); } HandleProgram(program); Finalize(); @@ -868,6 +864,22 @@ void InitScopesPhaseETS::HandleProgram(parser::Program *program) } program->VarBinder()->ResetTopScope(savedTopScope); } + + if (!program->ProjectSources().empty()) { + auto savedTopScope(program->VarBinder()->TopScope()); + for (auto *projProg : program->ProjectSources()) { + ES2PANDA_ASSERT(projProg->Ast() != nullptr); + projProg->VarBinder()->InitTopScope(); + AddGlobalToBinder(projProg); + BindScopeNode(projProg->VarBinder()->GetScope(), projProg->Ast()); + SetProgram(projProg); + HandleProgram(projProg); + Finalize(); + } + SetProgram(program); + program->VarBinder()->ResetTopScope(savedTopScope); + } + ES2PANDA_ASSERT(program->Ast() != nullptr); auto *ast = program->Ast(); @@ -1207,20 +1219,6 @@ void InitScopesPhaseETS::AddGlobalToBinder(parser::Program *program) auto start = globalId->Start(); auto name = globalId->Name(); auto *varBinder = program->VarBinder(); - auto *ctx = varBinder->GetContext(); - if (ctx->compilingState == public_lib::CompilingState::MULTI_COMPILING_FOLLOW) { - auto *scope = varBinder->GetScope(); - auto bindings = scope->Bindings(); - auto res = bindings.find(name); - if (res != bindings.end()) { - auto classCtx = - LexicalScopeCreateOrEnter(program->VarBinder(), program->GlobalClass()); - classCtx.GetScope()->BindNode(program->GlobalClass()); - program->GlobalClass()->SetScope(classCtx.GetScope()); - globalId->SetVariable(res->second); - return; - } - } auto [decl2, var] = varBinder->NewVarDecl(start, name); auto classCtx = LexicalScopeCreateOrEnter(program->VarBinder(), program->GlobalClass()); diff --git a/ets2panda/es2panda.cpp b/ets2panda/es2panda.cpp index b2b63e0635fceb402425dc6bd9e747c1ccb65e5b..28e6b2c8768333012ec559e374f3686395d6b9de 100644 --- a/ets2panda/es2panda.cpp +++ b/ets2panda/es2panda.cpp @@ -104,27 +104,44 @@ unsigned int Compiler::CompileM(std::vector &inputs, util::Options & util::DiagnosticEngine &diagnosticEngine, std::vector &result) { public_lib::Context context; - context.transitionMemory = - new public_lib::TransitionMemory(new ThreadSafeArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true)); - context.allocator = context.transitionMemory->PermanentAllocator(); + ThreadSafeArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + context.allocator = &allocator; + context.compilingState = public_lib::CompilingState::MULTI_COMPILING; + std::string sourceFile = "__project__.ets"; + std::string_view parserInput {}; + auto output = options.GetOutput(); + if (output == ".abc") { + output = ""; + context.compilingOuput = public_lib::CompilingOutput::MULTI_OUTPUT; + } - context.compilingState = public_lib::CompilingState::MULTI_COMPILING_INIT; - unsigned int overallRes = 0; for (auto &input : inputs) { - try { + if (context.compilingOuput == public_lib::CompilingOutput::MULTI_OUTPUT) { options.SetOutput(std::string(input.dest)); - LOG_IF(options.IsListFiles(), INFO, ES2PANDA) - << "> es2panda: compiling from '" << input.filePath << "' to '" << input.dest << "'"; - auto program = - compiler_->Compile(compiler::CompilationUnit {input, options, 0, ext_, diagnosticEngine}, &context); - result.push_back(program); - } catch (const util::ThrowableDiagnostic &err) { - overallRes |= 1U; - diagnosticEngine.Log(err); + } else { + options.SetOutput(output); } - context.compilingState = public_lib::CompilingState::MULTI_COMPILING_FOLLOW; + auto *compilationUnit = new compiler::CompilationUnit(input, options, 0, ext_, diagnosticEngine); + context.compilationUnits.push_back(compilationUnit); + } + + unsigned int overallRes = 0; + es2panda::SourceFile input(sourceFile, parserInput, options.IsModule(), output); + try { + (void)compiler_->Compile(compiler::CompilationUnit {input, options, 0, ext_, diagnosticEngine}, &context); + } catch (const util::ThrowableDiagnostic &err) { + overallRes |= 1U; + diagnosticEngine.Log(err); + } + + for (auto &projectProgram : context.projectPrograms) { + result.emplace_back(projectProgram); + } + context.projectPrograms.clear(); + for (auto *cu : context.compilationUnits) { + delete cu; } - delete context.transitionMemory; + context.compilationUnits.clear(); return overallRes; } diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 36001a7946a083e80444d63fcd2b0a9da50d1cb3..c8bc51e936003aa94792bf58f914912d51932d03 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -102,6 +102,7 @@ bool ETSParser::IsETSParser() const noexcept std::unique_ptr ETSParser::InitLexer(const SourceFile &sourceFile) { GetProgram()->SetSource(sourceFile); + GetContext().SetProgram(GetProgram()); GetContext().Status() |= ParserStatus::ALLOW_JS_DOC_START; auto lexer = std::make_unique(&GetContext(), DiagnosticEngine()); GetContext().Status() ^= ParserStatus::ALLOW_JS_DOC_START; @@ -142,6 +143,11 @@ void ETSParser::ParseProgram(ScriptKind kind) } if (!GetOptions().IsGenerateDeclEnableIsolated()) { + if (!GetGlobalProgram()->VarBinder()->GetContext()->compilationUnits.empty()) { + ES2PANDA_ASSERT(GetProgram() == GetGlobalProgram()); + AddProjectSource(); + SetProgram(GetGlobalProgram()); + } AddExternalSource(ParseSources(true)); } @@ -206,16 +212,44 @@ ir::ETSModule *ETSParser::ParseImportsAndReExportOnly(lexer::SourcePosition star return etsModule; } +void ETSParser::AddProjectSource() +{ + std::vector programs {}; + auto &projSources = globalProgram_->ProjectSources(); + + for (auto &sf : globalProgram_->ProjectSourceFiles()) { + parser::Program *newProg = ParseSource(sf); + SetProgram(newProg); + auto lexer = InitLexer(sf); + Lexer()->NextToken(); + GetContext().Status() |= ParserStatus::IN_PROJECT_IMPORTS; + auto statements = ParseImportDeclarations(); + GetContext().Status() &= ~ParserStatus::IN_PROJECT_IMPORTS; + projSources.emplace_back(newProg); + importPathManager_->MarkAsParsed(sf.filePath); + } +} + void ETSParser::AddExternalSource(const std::vector &programs) { auto &extSources = globalProgram_->ExternalSources(); + auto &projSources = globalProgram_->ProjectSources(); for (auto *newProg : programs) { + bool found = false; + for (auto *prog : projSources) { + if (prog->SourceFilePath() == newProg->SourceFilePath()) { + found = true; + break; + } + } + if (found) { + continue; + } const util::StringView name = newProg->ModuleName(); if (extSources.count(name) == 0) { extSources.try_emplace(name, Allocator()->Adapter()); } - bool found = false; for (auto *prog : extSources.at(name)) { if (prog->SourceFilePath() == newProg->SourceFilePath()) { found = true; @@ -242,10 +276,6 @@ ArenaVector ETSParser::ParseDefaultSources(std::stri GetContext().Status() &= ~ParserStatus::IN_DEFAULT_IMPORTS; std::vector programs; - auto *ctx = GetProgram()->VarBinder()->GetContext(); - if (ctx->compilingState == public_lib::CompilingState::MULTI_COMPILING_FOLLOW) { - return statements; - } if (!Context()->compiledByCapi) { AddExternalSource(ParseSources()); @@ -291,22 +321,6 @@ void ETSParser::ParseParseListElement(const util::ImportPathManager::ParseInfo & } } -static bool SearchImportedExternalSources(ETSParser *parser, const std::string_view &path) -{ - auto *ctx = parser->GetGlobalProgram()->VarBinder()->GetContext(); - if (ctx->compilingState != public_lib::CompilingState::MULTI_COMPILING_FOLLOW) { - return false; - } - for (const auto &[moduleName, extPrograms] : ctx->externalSources) { - for (auto *const extProg : extPrograms) { - if (extProg->SourceFilePath() == path) { - return true; - } - } - } - return false; -} - bool ETSParser::TryMergeFromCache(size_t idx, ArenaVector &parseList) { if (Context()->globalContext == nullptr) { @@ -395,10 +409,6 @@ std::vector ETSParser::ParseSources(bool firstSource) // Handle excluded files, which are already set to be parsed before parsing them continue; } - if (SearchImportedExternalSources(this, parseList[idx].importData.resolvedSource)) { - parseList[idx].isParsed = true; - continue; - } directImportsFromMainSource.emplace_back(parseList[idx].importData.resolvedSource); } } diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index 1d7b1ee848ab4bda4cc268e993862210aa770d2f..54cae78635ac83c04cae8c9b7ca3e28a217112b4 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -140,6 +140,7 @@ public: ir::StringLiteral *pathToResolve, parser::Program *program, util::ImportFlags importFlag); + void AddProjectSource(); void AddExternalSource(const std::vector &programs); std::vector ParseSources(bool firstSource = false); diff --git a/ets2panda/parser/context/parserContext.h b/ets2panda/parser/context/parserContext.h index 80620c2c64470287090c67db64fe6ee7f2a2b237..7ab0848a1ad1259a2c93a8f67e88a656a1c55738 100644 --- a/ets2panda/parser/context/parserContext.h +++ b/ets2panda/parser/context/parserContext.h @@ -76,6 +76,8 @@ enum class ParserStatus : uint64_t { STATIC_BLOCK = 1ULL << 40ULL, ALLOW_JS_DOC_START = 1ULL << 41ULL, IN_PACKAGE = 1ULL << 42ULL, + + IN_PROJECT_IMPORTS = 1ULL << 43ULL, }; } // namespace ark::es2panda::parser diff --git a/ets2panda/parser/program/program.cpp b/ets2panda/parser/program/program.cpp index 572ce976dc019b2b7e56d904c9303874ed1e8ce9..5d91b76e8b54c335853ba55b4bf71ecf70349692 100644 --- a/ets2panda/parser/program/program.cpp +++ b/ets2panda/parser/program/program.cpp @@ -33,6 +33,8 @@ Program::Program(ArenaAllocator *allocator, varbinder::VarBinder *varbinder) : allocator_(allocator), externalSources_(allocator_->Adapter()), directExternalSources_(allocator_->Adapter()), + projectSourceFiles_(allocator_->Adapter()), + projectSources_(allocator_->Adapter()), extension_(varbinder->Extension()), etsnolintCollection_(allocator_->Adapter()), cfg_(allocator_->New(allocator_)), @@ -101,12 +103,14 @@ const varbinder::ClassScope *Program::GlobalClassScope() const varbinder::GlobalScope *Program::GlobalScope() { + ES2PANDA_ASSERT(ast_->Scope() != nullptr); ES2PANDA_ASSERT(ast_->Scope()->IsGlobalScope() || ast_->Scope()->IsModuleScope()); return static_cast(ast_->Scope()); } const varbinder::GlobalScope *Program::GlobalScope() const { + ES2PANDA_ASSERT(ast_->Scope() != nullptr); ES2PANDA_ASSERT(ast_->Scope()->IsGlobalScope() || ast_->Scope()->IsModuleScope()); return static_cast(ast_->Scope()); } @@ -157,8 +161,7 @@ void Program::SetFlag(ProgramFlags flag) { ES2PANDA_ASSERT(VarBinder() != nullptr && VarBinder()->GetContext() != nullptr); auto compilingState = VarBinder()->GetContext()->compilingState; - if (compilingState == public_lib::CompilingState::MULTI_COMPILING_INIT || - compilingState == public_lib::CompilingState::MULTI_COMPILING_FOLLOW) { + if (compilingState == public_lib::CompilingState::MULTI_COMPILING) { programFlags_ |= flag; } } diff --git a/ets2panda/parser/program/program.h b/ets2panda/parser/program/program.h index c29543942cadcf88358a2ac9db0e08e8f34a4169..f80f8987527fd263cce91a65992c3aa0098e9f61 100644 --- a/ets2panda/parser/program/program.h +++ b/ets2panda/parser/program/program.h @@ -22,6 +22,7 @@ #include "util/ustring.h" #include "util/path.h" #include "util/importPathManager.h" +#include "utils/arena_containers.h" #include "varbinder/varbinder.h" #include #include "util/enumbitops.h" @@ -67,6 +68,7 @@ enum class ProgramFlags : uint32_t { AST_IDENTIFIER_ANALYZED = 1U << 7U, AST_HAS_SCOPES_INITIALIZED = 1U << 8U, AST_HAS_OPTIONAL_PARAMETER_ANNOTATION = 1U << 9U, + AST_FROM_PROJECT = 1U << 10U, }; class Program { @@ -217,6 +219,21 @@ public: return directExternalSources_; } + ArenaVector &ProjectSources() + { + return projectSources_; + } + + ArenaVector &ProjectSourceFiles() + { + return projectSourceFiles_; + } + + const ArenaVector &ProjectSources() const + { + return projectSources_; + } + const lexer::SourcePosition &PackageStart() const { return packageStartPosition_; @@ -381,6 +398,8 @@ private: util::StringView relativeFilePath_ {}; ExternalSource externalSources_; DirectExternalSource directExternalSources_; + ArenaVector projectSourceFiles_; + ArenaVector projectSources_; ScriptKind kind_ {}; ScriptExtension extension_ {}; ETSNolintsCollectionMap etsnolintCollection_; diff --git a/ets2panda/public/es2panda_lib.cpp b/ets2panda/public/es2panda_lib.cpp index 8df91d24aff6942c01c70ef14542a277129967cd..0d880ed0047d9faf7a6e28867a5a162ad90f9efa 100644 --- a/ets2panda/public/es2panda_lib.cpp +++ b/ets2panda/public/es2panda_lib.cpp @@ -463,7 +463,64 @@ extern "C" __attribute__((unused)) es2panda_Context *CreateContextFromFile(es2pa ; } - return CreateContext(config, ss.str(), sourceFileName, nullptr, false, false); + auto context = reinterpret_cast(CreateContext(config, ss.str(), sourceFileName, nullptr, false, false)); + + //extra logic for compileM + auto options = context->config->options; + auto diagnosticEngine = context->diagnosticEngine; + + context->tmpDataCompilationList = FindProjectSources(options->ArkTSConfig()); + if (context->tmpDataCompilationList.empty()) { + diagnosticEngine->LogDiagnostic(diagnostic::NO_INPUT, util::DiagnosticMessageParams {}); + delete diagnosticEngine; + UNREACHABLE(); + } + + auto &inputs = context->tmpDataCapiInputs; + for (auto &[src, dst] : context->tmpDataCompilationList) { + std::ifstream inputStream(src); + if (inputStream.fail()) { + diagnosticEngine->LogDiagnostic(diagnostic::OPEN_FAILED, util::DiagnosticMessageParams {src}); + delete diagnosticEngine; + UNREACHABLE(); + } + std::stringstream ss1; + ss1 << inputStream.rdbuf(); + auto *parserInput = new std::string(ss1.str()); + inputStream.close(); + es2panda::SourceFile input(src, *parserInput, options->IsModule(), std::string_view(dst)); + inputs.push_back(input); + } + + context->compilingState = public_lib::CompilingState::MULTI_COMPILING; + context->tmpDataSourceFileName = "__project__.ets"; + auto output = options->GetOutput(); + if (output == ".abc") { + output = ""; + context->compilingOuput = public_lib::CompilingOutput::MULTI_OUTPUT; + } + + for (auto &input : inputs) { + if (context->compilingOuput == public_lib::CompilingOutput::MULTI_OUTPUT) { + const_cast(options)->SetOutput(std::string(input.dest)); + } else { + const_cast(options)->SetOutput(output); + } + auto *compilationUnit = new compiler::CompilationUnit(input, *options, 0, ark::es2panda::util::gen::extension::ETS, *diagnosticEngine); + context->compilationUnits.push_back(compilationUnit); + } + + // todo:EKKO memleak here, to fix + es2panda::SourceFile * input1 = new SourceFile(context->tmpDataSourceFileName, context->tmpDataParserInput, options->IsModule(), output); + context->sourceFile = input1; + + return reinterpret_cast(context); +} + +extern "C" __attribute__((unused)) es2panda_Context *CreateContextGenerateAbcForExternalSourceFiles( + es2panda_Config *config,[[maybe_unused]] int fileNamesCount, char const *const *fileNames) +{ + return CreateContextFromFile(config, fileNames[0]); } extern "C" __attribute__((unused)) es2panda_Context *CreateContextFromString(es2panda_Config *config, @@ -646,12 +703,39 @@ __attribute__((unused)) Context *GenerateBin(Context *ctx) ES2PANDA_ASSERT(ctx->state == ES2PANDA_STATE_ASM_GENERATED); - ES2PANDA_ASSERT(ctx->program != nullptr); - util::GenerateProgram(ctx->program, *ctx->config->options, - [ctx](const diagnostic::DiagnosticKind &kind, const util::DiagnosticMessageParams ¶ms) { - ctx->diagnosticEngine->LogDiagnostic(kind, params); - }); - ctx->state = !ctx->diagnosticEngine->IsAnyError() ? ES2PANDA_STATE_BIN_GENERATED : ES2PANDA_STATE_ERROR; + if (reinterpret_cast(ctx)->compilingState == CompilingState::MULTI_COMPILING) { + std::cout<<"-------ES2PANDA-EKKO------ enter generate bin multicompiling"<(ctx); + auto options = context->config->options; + auto diagnosticEngine = context->diagnosticEngine; + + auto &result = context->projectPrograms; + for (size_t i = 0; i < result.size(); i++) { + auto *program = result[i]; + if (program == nullptr) { + continue; + } + const_cast(options)->SetOutput(std::string(context->tmpDataCapiInputs[i].dest)); + util::GenerateProgram( + program, *options, + [&diagnosticEngine](const diagnostic::DiagnosticKind &kind, const util::DiagnosticMessageParams ¶ms) { + diagnosticEngine->LogDiagnostic(kind, params); + }); + } + context->projectPrograms.clear(); + for (auto *cu : context->compilationUnits) { + delete cu; + } + context->compilationUnits.clear(); + }else { + ES2PANDA_ASSERT(ctx->program != nullptr); + util::GenerateProgram(ctx->program, *ctx->config->options, + [ctx](const diagnostic::DiagnosticKind &kind, const util::DiagnosticMessageParams ¶ms) { + ctx->diagnosticEngine->LogDiagnostic(kind, params); + }); + ctx->state = !ctx->diagnosticEngine->IsAnyError() ? ES2PANDA_STATE_BIN_GENERATED : ES2PANDA_STATE_ERROR; + } + return ctx; } @@ -1245,6 +1329,7 @@ es2panda_Impl g_impl = { CreateContextFromFile, CreateCacheContextFromFile, CreateContextFromString, + CreateContextGenerateAbcForExternalSourceFiles, ProceedToState, DestroyContext, CreateGlobalContext, diff --git a/ets2panda/public/es2panda_lib.h b/ets2panda/public/es2panda_lib.h index cf927443b4f8927ae3bde32e4da2d471051bb38c..2cf857ee39d83f2d41ef466c6efda7774cb7924b 100644 --- a/ets2panda/public/es2panda_lib.h +++ b/ets2panda/public/es2panda_lib.h @@ -187,9 +187,12 @@ struct CAPI_EXPORT es2panda_Impl { es2panda_Context *(*CreateCacheContextFromFile)(es2panda_Config *config, char const *source_file_name, es2panda_GlobalContext *globalContext, bool isExternal); es2panda_Context *(*CreateContextFromString)(es2panda_Config *config, const char *source, char const *file_name); + es2panda_Context *(*CreateContextGenerateAbcForExternalSourceFiles)(es2panda_Config *config, int fileNamesCount, + char const *const *fileNames); es2panda_Context *(*ProceedToState)(es2panda_Context *context, es2panda_ContextState state); // context is consumed void (*DestroyContext)(es2panda_Context *context); + es2panda_GlobalContext *(*CreateGlobalContext)(es2panda_Config *config, const char **externalFileList, size_t fileNum, bool LspUsage); void (*DestroyGlobalContext)(es2panda_GlobalContext *globalContext); diff --git a/ets2panda/public/public.h b/ets2panda/public/public.h index 46ddf91b4cf5295d74d5a601958c7b5ac833a853..6a5f23be3ce66c4a017c90700dad83c732037f06 100644 --- a/ets2panda/public/public.h +++ b/ets2panda/public/public.h @@ -36,6 +36,7 @@ namespace ark::es2panda::compiler { class PhaseManager; void SetPhaseManager(PhaseManager *phaseManager); PhaseManager *GetPhaseManager(); +class CompilationUnit; } // namespace ark::es2panda::compiler namespace ark::es2panda::public_lib { @@ -43,8 +44,12 @@ namespace ark::es2panda::public_lib { enum class CompilingState : unsigned int { NONE_COMPILING = 0, SINGLE_COMPILING = 1, - MULTI_COMPILING_INIT = 2, - MULTI_COMPILING_FOLLOW = 3, + MULTI_COMPILING = 2, +}; + +enum class CompilingOutput : unsigned int { + SINGLE_OUTPUT = 0, + MULTI_OUTPUT = 1, }; struct ConfigImpl { @@ -59,92 +64,6 @@ using ComputedAbstracts = ArenaUnorderedMap, ArenaUnorderedSet>>; -class TransitionMemory { -public: - explicit TransitionMemory(ThreadSafeArenaAllocator *allocator) - : permanentAllocator_(allocator), compiledPrograms_(allocator->Adapter()) - { - compiledPrograms_ = {}; - } - - NO_COPY_SEMANTIC(TransitionMemory); - DEFAULT_MOVE_SEMANTIC(TransitionMemory); - - ~TransitionMemory() = default; - - ThreadSafeArenaAllocator *PermanentAllocator() const - { - return permanentAllocator_.get(); - } - - const varbinder::VarBinder *VarBinder() const - { - return varbinder_; - } - - varbinder::VarBinder *VarBinder() - { - return varbinder_; - } - - void SetVarBinder(varbinder::VarBinder *varbinder) - { - varbinder_ = varbinder; - } - - const checker::GlobalTypesHolder *GlobalTypes() const - { - return globalTypes_; - } - - checker::GlobalTypesHolder *GlobalTypes() - { - return globalTypes_; - } - - void SetGlobalTypes(checker::GlobalTypesHolder *globalTypes) - { - globalTypes_ = globalTypes; - } - - void AddCompiledProgram(parser::Program *program) - { - compiledPrograms_.push_back(program); - } - - ArenaVector &CompiledSources() - { - return compiledPrograms_; - } - - const ArenaVector &CompiledPrograms() const - { - return compiledPrograms_; - } - - const ComputedAbstracts *CachedComputedAbstracts() const - { - return cachedComputedAbstracts_; - } - - ComputedAbstracts *CachedComputedAbstracts() - { - return cachedComputedAbstracts_; - } - - void SetCachechedComputedAbstracts(ComputedAbstracts *cachedComputedAbstracts) - { - cachedComputedAbstracts_ = cachedComputedAbstracts; - } - -private: - std::unique_ptr permanentAllocator_; - ArenaVector compiledPrograms_; - varbinder::VarBinder *varbinder_ {nullptr}; - checker::GlobalTypesHolder *globalTypes_ {nullptr}; - ComputedAbstracts *cachedComputedAbstracts_ {nullptr}; -}; - struct GlobalContext { std::unordered_map externalProgramAllocators; std::unordered_map cachedExternalPrograms; @@ -222,11 +141,17 @@ struct Context { lexer::SourcePosition errorPos; CompilingState compilingState {CompilingState::NONE_COMPILING}; + CompilingOutput compilingOuput {CompilingOutput::SINGLE_OUTPUT}; ExternalSources externalSources; - TransitionMemory *transitionMemory {nullptr}; + std::vector compilationUnits {}; + std::vector projectPrograms {}; bool isExternal = false; bool compiledByCapi = false; checker::IsolatedDeclgenChecker *isolatedDeclgenChecker {nullptr}; + std::vector tmpDataCapiInputs {}; + std::vector> tmpDataCompilationList{}; + std::string tmpDataSourceFileName; + std::string_view tmpDataParserInput; // NOLINTEND(misc-non-private-member-variables-in-classes) private: diff --git a/ets2panda/util/importPathManager.cpp b/ets2panda/util/importPathManager.cpp index 7cf04669276b7b647c1a6d4a086c986641ad2d86..6bbf1311c3d7da6ee5c6c3983e369d8eafb4720d 100644 --- a/ets2panda/util/importPathManager.cpp +++ b/ets2panda/util/importPathManager.cpp @@ -443,13 +443,11 @@ util::StringView ImportPathManager::FormModuleName(const util::Path &path) if (!absoluteEtsPath_.empty()) { return FormModuleNameSolelyByAbsolutePath(path); } - - if (arktsConfig_->Package().empty() && !arktsConfig_->UseUrl()) { + if ((path.GetFileName() == util::StringView("__project__") || + (arktsConfig_->Package().empty() && !arktsConfig_->UseUrl()))) { return path.GetFileName(); } - std::string const filePath(path.GetAbsolutePath()); - // should be implemented with a stable name -> path mapping list auto const tryFormModuleName = [filePath](std::string_view unitName, std::string_view unitPath) -> std::optional { @@ -460,13 +458,11 @@ util::StringView ImportPathManager::FormModuleName(const util::Path &path) return FormUnitName(unitName) + (relativePath.empty() || FormUnitName(unitName).empty() ? relativePath : ("." + relativePath)); }; - for (auto const &[unitName, unitPath] : arktsConfig_->Entries()) { if (unitPath == filePath) { return util::UString(unitName, allocator_).View(); } } - if (auto res = tryFormModuleName(arktsConfig_->Package(), arktsConfig_->BaseUrl() + pathDelimiter_.data()); res) { return util::UString(res.value(), allocator_).View(); } @@ -490,7 +486,6 @@ util::StringView ImportPathManager::FormModuleName(const util::Path &path) if (auto res = tryFormModuleName(arktsConfig_->Package(), arktsConfig_->BaseUrl()); res) { return util::UString(res.value(), allocator_).View(); } - diagnosticEngine_.LogDiagnostic(diagnostic::UNRESOLVED_MODULE, util::DiagnosticMessageParams {util::StringView(filePath)}, *srcPos_); return ""; diff --git a/ets2panda/varbinder/ETSBinder.cpp b/ets2panda/varbinder/ETSBinder.cpp index f2983e06ca9e44054da91bbb320072f9c10867b8..f9437b5332107f870fe577c3c9b6953cacb20cc4 100644 --- a/ets2panda/varbinder/ETSBinder.cpp +++ b/ets2panda/varbinder/ETSBinder.cpp @@ -28,6 +28,15 @@ void ETSBinder::IdentifierAnalysis() ES2PANDA_ASSERT(GetScope() == TopScope()); ES2PANDA_ASSERT(VarScope() == TopScope()); + if (!Program()->ProjectSources().empty()) { + for (auto *projProg : Program()->ProjectSources()) { + auto *projRecordTable = Allocator()->New(Allocator(), projProg, RecordTableFlags::NONE); + projectRecordTable_.insert({projProg, projRecordTable}); + projectRecordTable_.at(projProg)->SetProgram(projProg); + projectRecordTable_.at(projProg)->SetClassDefinition(projProg->GlobalClass()); + } + } + recordTable_->SetProgram(Program()); globalRecordTable_.SetClassDefinition(Program()->GlobalClass()); @@ -1204,7 +1213,17 @@ void ETSBinder::BuildProgram() for (auto &[_, extPrograms] : Program()->ExternalSources()) { (void)_; for (auto *extProg : extPrograms) { - BuildExternalProgram(extProg); + if (!extProg->GetFlag(parser::ProgramFlags::AST_IDENTIFIER_ANALYZED)) { + BuildExternalProgram(extProg, true); + extProg->SetFlag(parser::ProgramFlags::AST_IDENTIFIER_ANALYZED); + } + } + } + + for (auto *projProg : Program()->ProjectSources()) { + if (!projProg->GetFlag(parser::ProgramFlags::AST_IDENTIFIER_ANALYZED)) { + BuildExternalProgram(projProg, false); + projProg->SetFlag(parser::ProgramFlags::AST_IDENTIFIER_ANALYZED); } } @@ -1232,26 +1251,35 @@ void ETSBinder::BuildProgram() } } -void ETSBinder::BuildExternalProgram(parser::Program *extProgram) +void ETSBinder::BuildExternalProgram(parser::Program *extProgram, bool isExternal) { auto *savedProgram = Program(); auto *savedRecordTable = recordTable_; auto *savedTopScope = TopScope(); auto flags = Program()->VarBinder()->IsGenStdLib() ? RecordTableFlags::NONE : RecordTableFlags::EXTERNAL; - auto *extRecordTable = Allocator()->New(Allocator(), extProgram, flags); - extRecordTable->SetClassDefinition(extProgram->GlobalClass()); - externalRecordTable_.insert({extProgram, extRecordTable}); + if (isExternal) { + auto *extRecordTable = Allocator()->New(Allocator(), extProgram, flags); + extRecordTable->SetClassDefinition(extProgram->GlobalClass()); + externalRecordTable_.insert({extProgram, extRecordTable}); + recordTable_ = extRecordTable; + } else { + recordTable_ = projectRecordTable_.at(extProgram); + } ResetTopScope(extProgram->GlobalScope()); - recordTable_ = extRecordTable; + SetProgram(extProgram); - if (!extProgram->IsASTLowered()) { - BuildProgram(); + if (isExternal) { + if (!extProgram->IsASTLowered()) { + BuildProgram(); + } else { + recordTable_->Merge(extProgram->VarBinder()->AsETSBinder()->GetExternalRecordTable().at(extProgram)); + } } else { - extRecordTable->Merge(extProgram->VarBinder()->AsETSBinder()->GetExternalRecordTable().at(extProgram)); + BuildProgram(); } SetProgram(savedProgram); @@ -1456,6 +1484,15 @@ ArenaVector ETSBinder::GetProgramList(const util::StringView } } + for (auto &projProg : globalProgram->ProjectSources()) { + if (projProg->SourceFilePath() == path) { + return ArenaVector({projProg}, Allocator()->Adapter()); + } + if (projProg->IsPackage() && projProg->SourceFileFolder() == path) { + return ArenaVector({projProg}, Allocator()->Adapter()); + } + } + if (globalProgram->IsPackage() && path.Compare(globalProgram->SourceFileFolder()) == 0) { return ArenaVector({GetContext()->parserProgram}, Allocator()->Adapter()); } diff --git a/ets2panda/varbinder/ETSBinder.h b/ets2panda/varbinder/ETSBinder.h index 140596eccdc48348626616e97dcf9b436d0b61b9..6d380d930eef72a731dca52d51945c1204076a5d 100644 --- a/ets2panda/varbinder/ETSBinder.h +++ b/ets2panda/varbinder/ETSBinder.h @@ -61,6 +61,7 @@ public: globalRecordTable_(allocator, Program(), RecordTableFlags::NONE), recordTable_(&globalRecordTable_), externalRecordTable_(Allocator()->Adapter()), + projectRecordTable_(Allocator()->Adapter()), defaultImports_(Allocator()->Adapter()), dynamicImports_(Allocator()->Adapter()), reExportImports_(Allocator()->Adapter()), @@ -111,6 +112,14 @@ public: return &globalRecordTable_; } + void SetGlobalRecordTable(RecordTable &rt) + { + globalRecordTable_.SetClassDefinition(rt.ClassDefinition()); + globalRecordTable_.SetAnnotationDeclaration(rt.AnnotationDeclaration()); + globalRecordTable_.SetInterfaceDeclaration(rt.InterfaceDeclaration()); + globalRecordTable_.SetProgram(rt.Program()); + } + [[nodiscard]] ArenaMap &GetExternalRecordTable() noexcept { return externalRecordTable_; @@ -121,6 +130,16 @@ public: return externalRecordTable_; } + [[nodiscard]] ArenaMap &GetProjectRecordTable() noexcept + { + return projectRecordTable_; + } + + [[nodiscard]] const ArenaMap &GetProjectRecordTable() const noexcept + { + return projectRecordTable_; + } + void HandleCustomNodes(ir::AstNode *childNode) override; void IdentifierAnalysis() override; @@ -179,7 +198,7 @@ public: LocalScope *ResolvePropertyReference(ir::ClassProperty *prop, ClassScope *scope); void ResolveEnumDeclaration(ir::TSEnumDeclaration *enumDecl); void InitializeInterfaceIdent(ir::TSInterfaceDeclaration *decl); - void BuildExternalProgram(parser::Program *extProgram); + void BuildExternalProgram(parser::Program *extProgram, bool isExternal); void BuildProgram(); void BuildFunctionName(const ir::ScriptFunction *func) const; @@ -269,6 +288,7 @@ public: { VarBinder::CleanUp(); externalRecordTable_.clear(); + projectRecordTable_.clear(); InitImplicitThisParam(); dynamicImports_.clear(); reexportedNames_.clear(); @@ -310,7 +330,8 @@ private: RecordTable globalRecordTable_; RecordTable *recordTable_; ArenaMap externalRecordTable_; - ArenaVector defaultImports_; // 1 + ArenaMap projectRecordTable_; + ArenaVector defaultImports_; ArenaVector dynamicImports_; ArenaUnorderedSet reExportImports_; ArenaSet reexportedNames_; diff --git a/ets2panda/varbinder/recordTable.h b/ets2panda/varbinder/recordTable.h index 437a2ffb79dd259f21257e6901141194fc991930..213c4327b61136b229ff6178f7907979d8707a24 100644 --- a/ets2panda/varbinder/recordTable.h +++ b/ets2panda/varbinder/recordTable.h @@ -57,6 +57,9 @@ struct enumbitops::IsAllowedType : s namespace ark::es2panda::varbinder { +using RecordHolder = + std::variant; + class RecordTable { public: explicit RecordTable(ArenaAllocator *allocator, parser::Program *program, RecordTableFlags flags) @@ -216,6 +219,26 @@ public: util::StringView RecordName() const; + void SetFlags(RecordTableFlags flags) + { + flags_ = flags; + } + + RecordTableFlags Flags() + { + return flags_; + } + + RecordHolder GetRecord() + { + return record_; + } + + void SetRecord(RecordHolder record) + { + record_ = record; + } + void CleanUp() { classDefinitions_.clear(); @@ -227,10 +250,24 @@ public: flags_ = RecordTableFlags::NONE; } + void CopyRecordTable(RecordTable *rt) + { + for (auto &classDef : rt->classDefinitions_) { + classDefinitions_.insert(classDef); + } + for (auto &interfaceDecl : rt->interfaceDeclarations_) { + interfaceDeclarations_.insert(interfaceDecl); + } + for (auto &annoDecl : rt->annotationDeclarations_) { + annotationDeclarations_.insert(annoDecl); + } + for (auto &signature : rt->signatures_) { + signatures_.insert(signature); + } + } + private: friend class BoundContext; - using RecordHolder = - std::variant; ArenaSet classDefinitions_; ArenaSet interfaceDeclarations_; @@ -260,8 +297,8 @@ public: private: BoundContext *prev_; RecordTable *recordTable_; - RecordTable::RecordHolder currentRecord_ {nullptr}; - RecordTable::RecordHolder savedRecord_ {nullptr}; + RecordHolder currentRecord_ {nullptr}; + RecordHolder savedRecord_ {nullptr}; ir::Identifier *recordIdent_ {nullptr}; };