diff --git a/ets2panda/bindings/native/src/bridges.cpp b/ets2panda/bindings/native/src/bridges.cpp index 2757d4b9efc5081982efaa7c6d2959a303405bd9..756bf102b4123694726e6b092c4aaec32f1556a7 100644 --- a/ets2panda/bindings/native/src/bridges.cpp +++ b/ets2panda/bindings/native/src/bridges.cpp @@ -36,6 +36,14 @@ KNativePointer impl_CreateContextFromString(KNativePointer configPtr, KStringPtr } TS_INTEROP_3(CreateContextFromString, KNativePointer, KNativePointer, KStringPtr, KStringPtr) +KNativePointer impl_CreateContextFromStringWithHistory(KNativePointer configPtr, KStringPtr &sourcePtr, + KStringPtr &filenamePtr) +{ + auto config = reinterpret_cast(configPtr); + return GetPublicImpl()->CreateContextFromStringWithHistory(config, sourcePtr.data(), filenamePtr.data(), true); +} +TS_INTEROP_3(CreateContextFromStringWithHistory, KNativePointer, KNativePointer, KStringPtr, KStringPtr) + KInt impl_GenerateTsDeclarationsFromContext(KNativePointer contextPtr, KStringPtr &outputDeclEts, KStringPtr &outputEts, KBoolean exportAll) { diff --git a/ets2panda/bindings/src/Es2pandaNativeModule.ts b/ets2panda/bindings/src/Es2pandaNativeModule.ts index 210ad83e1cdbc4ee92919e027e49b61c61c67017..b86f8b7113e40f9a776df47a46cf13341f1dfeab 100644 --- a/ets2panda/bindings/src/Es2pandaNativeModule.ts +++ b/ets2panda/bindings/src/Es2pandaNativeModule.ts @@ -61,6 +61,9 @@ export class Es2pandaNativeModule { _CreateContextFromString(config: KPtr, source: String, filename: String): KPtr { throw new Error('Not implemented'); } + _CreateContextFromStringWithHistory(config: KPtr, source: String, filename: String, isEnableHistory: KBoolean): KPtr { + throw new Error('Not implemented'); + } _GenerateTsDeclarationsFromContext( config: KPtr, outputDeclEts: String, diff --git a/ets2panda/bindings/src/types.ts b/ets2panda/bindings/src/types.ts index 2a34d968b7c5a540cb7d7cfa7f17e0c7622eb623..f0624cdcf70f0c9255a8c40063a0c2bec15909ea 100644 --- a/ets2panda/bindings/src/types.ts +++ b/ets2panda/bindings/src/types.ts @@ -103,6 +103,15 @@ export class Context extends ArktsObject { ); } + static createFromStringWithHistory(source: string): Context { + if (!global.configIsInitialized()) { + throwError(`Config not initialized`); + } + return new Context( + global.es2panda._CreateContextFromStringWithHistory(global.config, passString(source), passString(global.filePath), 1) + ); + } + static lspCreateFromString(source: string, filePath: string, cfg: Config): KPtr { if (cfg === undefined) { throwError(`Config not initialized`); diff --git a/ets2panda/compiler/lowering/phase.h b/ets2panda/compiler/lowering/phase.h index 63c3e493f413c60c1113510a05d91575cc0c8feb..fcc41492ae16d6ada9d65b31d49c86077f72cd0c 100644 --- a/ets2panda/compiler/lowering/phase.h +++ b/ets2panda/compiler/lowering/phase.h @@ -145,6 +145,15 @@ public: curr_.minor = phaseId; } + void SetCurrentPhaseIdWithoutReCheck(int32_t phaseId) + { + if (phaseId == curr_.minor) { + return; + } + prev_ = curr_; + curr_.minor = phaseId; + } + ArenaAllocator *Allocator() const { return allocator_; diff --git a/ets2panda/declgen_ets2ts/declgenEts2Ts.cpp b/ets2panda/declgen_ets2ts/declgenEts2Ts.cpp index 6dd04a39169bc1a6322c4ae0f50be0252214ab9c..02e4a9bfda23812c62cf05d1d12f5688c664ed0c 100644 --- a/ets2panda/declgen_ets2ts/declgenEts2Ts.cpp +++ b/ets2panda/declgen_ets2ts/declgenEts2Ts.cpp @@ -17,6 +17,7 @@ #include #include "checker/types/ets/etsTupleType.h" +#include "compiler/lowering/phase.h" #include "generated/diagnostic.h" #include "ir/base/classProperty.h" #include "ir/base/methodDefinition.h" @@ -27,10 +28,7 @@ #include "ir/ets/etsUnionType.h" #include "ir/expressions/identifier.h" #include "ir/expressions/literals/numberLiteral.h" -#include "ir/module/importSpecifier.h" -#include "ir/statements/blockStatement.h" #include "ir/statements/classDeclaration.h" -#include "ir/ts/tsEnumMember.h" #include "ir/ts/tsInterfaceBody.h" #include "ir/ts/tsTypeAliasDeclaration.h" #include "ir/ts/tsTypeParameter.h" @@ -283,6 +281,15 @@ type Record = { } } +void TSDeclGen::GenExportNamedDeclarations() +{ + for (auto *globalStatement : program_->Ast()->Statements()) { + if (globalStatement->IsExportNamedDeclaration()) { + GenExportNamedDeclaration(globalStatement->AsExportNamedDeclaration()); + } + } +} + void TSDeclGen::GenImportDeclarations() { for (auto *globalStatement : program_->Ast()->Statements()) { @@ -1020,6 +1027,18 @@ void TSDeclGen::GenAnnotationPropertyValue(ir::Expression *propValue) } } +void TSDeclGen::GenExportNamedDeclaration(const ir::ExportNamedDeclaration *exportDeclaration) +{ + DebugPrint("GenExportNamedDeclaration"); + const auto &specifiers = exportDeclaration->Specifiers(); + if (specifiers.empty()) { + return; + } + GenNamedExports(exportDeclaration, specifiers); + OutEndlDts(); + OutEndlTs(); +} + void TSDeclGen::GenImportDeclaration(const ir::ETSImportDeclaration *importDeclaration) { DebugPrint("GenImportDeclaration"); @@ -1086,6 +1105,26 @@ void TSDeclGen::GenNamedImports(const ir::ETSImportDeclaration *importDeclaratio OutTs(" } from \"", source, "\";"); } +void TSDeclGen::GenNamedExports(const ir::ExportNamedDeclaration *exportDeclaration, + const ArenaVector &specifiers) +{ + auto exportSpecifiers = FilterValidExportSpecifiers(specifiers); + if (exportSpecifiers.empty()) { + return; + } + + OutDts("export ", "{ "); + OutTs("export ", "{ "); + + GenSeparated( + exportSpecifiers, + [this, &exportDeclaration](ir::AstNode *specifier) { GenSingleNamedExport(specifier, exportDeclaration); }, + ", ", true); + + OutDts(" };"); + OutTs(" };"); +} + void TSDeclGen::GenSingleNamedImport(ir::AstNode *specifier, const ir::ETSImportDeclaration *importDeclaration) { if (!specifier->IsImportSpecifier()) { @@ -1102,6 +1141,36 @@ void TSDeclGen::GenSingleNamedImport(ir::AstNode *specifier, const ir::ETSImport } } +void TSDeclGen::GenSingleNamedExport(ir::AstNode *specifier, const ir::ExportNamedDeclaration *exportDeclaration) +{ + if (!specifier->IsExportSpecifier()) { + LogError(diagnostic::IMPORT_SPECIFIERS_SUPPORT, {}, exportDeclaration->Start()); + } + const auto local = specifier->AsExportSpecifier()->Local()->Name().Mutf8(); + const auto exported = specifier->AsExportSpecifier()->Exported()->Name().Mutf8(); + if (local != exported) { + importSet_.insert(exported); + OutDts(exported, " as ", local); + OutTs(exported, " as ", local); + } else { + importSet_.insert(local); + OutDts(local); + OutTs(local); + } +} + +std::vector TSDeclGen::FilterValidExportSpecifiers(const ArenaVector &specifiers) +{ + std::vector exportSpecifiers; + for (auto specifier : specifiers) { + const auto local = specifier->Local()->Name().Mutf8(); + if (importSet_.find(local) == importSet_.end()) { + exportSpecifiers.push_back(specifier); + } + } + return exportSpecifiers; +} + std::vector TSDeclGen::FilterValidImportSpecifiers(const ArenaVector &specifiers) { std::vector importSpecifiers; @@ -1344,6 +1413,7 @@ void TSDeclGen::ProcessTSArrayType(const ir::TSArrayType *tsArrayType) void TSDeclGen::ProcessETSFunctionType(const ir::ETSFunctionType *etsFunction) { + GenTypeParameters(etsFunction->TypeParams()); bool inUnionBody = !state_.inUnionBodyStack.empty() && state_.inUnionBodyStack.top(); OutDts(inUnionBody ? "((" : "("); GenSeparated(etsFunction->Params(), [this](ir::Expression *param) { @@ -1470,10 +1540,10 @@ void TSDeclGen::GenInterfaceDeclaration(const ir::TSInterfaceDeclaration *interf void TSDeclGen::ProcessInterfaceBody(const ir::TSInterfaceBody *body) { - std::unordered_set processedMethods; + // std::unordered_set processedMethods; for (auto *prop : body->Body()) { if (prop->IsMethodDefinition()) { - ProcessMethodDefinition(prop->AsMethodDefinition(), processedMethods); + ProcessInterfaceMethodDefinition(prop->AsMethodDefinition()); } else if (prop->IsClassProperty()) { GenPropDeclaration(prop->AsClassProperty()); } @@ -1505,6 +1575,46 @@ void TSDeclGen::ProcessMethodDefinition(const ir::MethodDefinition *methodDef, } } +void TSDeclGen::ProcessInterfaceMethodDefinition(const ir::MethodDefinition *methodDef) +{ + const auto methodName = GetKeyIdent(methodDef->Key())->Name().Mutf8(); + bool isReadOnly = true; + if (methodDef->IsGetter() && !methodDef->Overloads().empty()) { + isReadOnly = false; + } + if (methodDef->IsGetter()) { + const auto *sig = GetFuncSignature(methodDef->TsType()->AsETSFunctionType(), methodDef); + bool hasUndefinedType = HasUndefinedType(sig->ReturnType()); + OutDts(GetIndent(), isReadOnly ? "readonly " : "", methodName, hasUndefinedType ? "?: " : ": "); + GenType(sig->ReturnType()); + OutDts(";"); + OutEndlDts(); + } + if (!methodDef->IsGetter() && !methodDef->IsSetter()) { + GenMethodDeclaration(methodDef); + } +} + +bool TSDeclGen::HasUndefinedType(const checker::Type *checkerType) +{ + if (checkerType == nullptr) { + return false; + } + + if (checker::ETSChecker::ETSType(checkerType) == checker::TypeFlag::ETS_UNDEFINED) { + return true; + } + + if (checker::ETSChecker::ETSType(checkerType) == checker::TypeFlag::ETS_UNION) { + for (const checker::Type *memberType : checkerType->AsETSUnionType()->ConstituentTypes()) { + if (HasUndefinedType(memberType)) { + return true; + } + } + } + return false; +} + void TSDeclGen::PrepareClassDeclaration(const ir::ClassDefinition *classDef) { std::string classDescriptor = "L" + classDef->InternalName().Mutf8() + ";"; @@ -2086,13 +2196,22 @@ bool GenerateTsDeclarations(checker::ETSChecker *checker, const ark::es2panda::p declBuilder.ResetTsOutput(); declBuilder.ResetDtsOutput(); + compiler::GetPhaseManager()->SetCurrentPhaseIdWithoutReCheck(1); + declBuilder.GenExportNamedDeclarations(); + + std::string exportOutputEts = declBuilder.GetTsOutput(); + std::string exportOutputDEts = declBuilder.GetDtsOutput(); + + declBuilder.ResetTsOutput(); + declBuilder.ResetDtsOutput(); + declBuilder.GenImportDeclarations(); std::string importOutputEts = declBuilder.GetTsOutput(); std::string importOutputDEts = declBuilder.GetDtsOutput(); - std::string combineEts = importOutputEts + outputEts; - std::string combinedDEts = importOutputDEts + outputDEts; + std::string combineEts = importOutputEts + outputEts + exportOutputEts; + std::string combinedDEts = importOutputDEts + outputDEts + exportOutputDEts; if (!declBuilder.GetDeclgenOptions().outputDeclEts.empty()) { auto outDtsPath = declBuilder.GetDeclgenOptions().outputDeclEts; diff --git a/ets2panda/declgen_ets2ts/declgenEts2Ts.h b/ets2panda/declgen_ets2ts/declgenEts2Ts.h index fda8c826a15d05038efc471d48d552d46139fdf6..f111ad959011a00010dc52724cd2e7c870b4544d 100644 --- a/ets2panda/declgen_ets2ts/declgenEts2Ts.h +++ b/ets2panda/declgen_ets2ts/declgenEts2Ts.h @@ -16,13 +16,13 @@ #ifndef ES2PANDA_DECLGEN_ETS2TS_H #define ES2PANDA_DECLGEN_ETS2TS_H -#include "parser/program/program.h" #include "checker/ETSchecker.h" +#include "compiler/lowering/phase.h" #include "libpandabase/os/file.h" #include "libpandabase/utils/arena_containers.h" +#include "parser/program/program.h" #include "util/options.h" #include "util/diagnosticEngine.h" - namespace ark::es2panda::declgen_ets2ts { struct DeclgenOptions { @@ -62,6 +62,7 @@ public: bool Generate(); void GenImportDeclarations(); + void GenExportNamedDeclarations(); std::string GetDtsOutput() const { @@ -95,6 +96,7 @@ private: const checker::Signature *GetFuncSignature(const checker::ETSFunctionType *etsFunctionType, const ir::MethodDefinition *methodDef); + bool HasUndefinedType(const checker::Type *checkerType); void SplitUnionTypes(std::string &unionTypeString); void GenType(const checker::Type *checkerType); void GenFunctionType(const checker::ETSFunctionType *functionType, const ir::MethodDefinition *methodDef = nullptr); @@ -118,12 +120,16 @@ private: std::vector FilterUnionTypes(const ArenaVector &originTypes); void GenImportDeclaration(const ir::ETSImportDeclaration *importDeclaration); + void GenExportNamedDeclaration(const ir::ExportNamedDeclaration *exportDeclaration); void GenNamespaceImport(const ir::AstNode *specifier, const std::string &source); void GenDefaultImport(const ir::AstNode *specifier, const std::string &source, const std::string &typeStr); void GenNamedImports(const ir::ETSImportDeclaration *importDeclaration, const ArenaVector &specifiers, const std::string &source, const std::string &typeStr); + void GenNamedExports(const ir::ExportNamedDeclaration *exportDeclaration, + const ArenaVector &specifiers); void GenSingleNamedImport(ir::AstNode *specifier, const ir::ETSImportDeclaration *importDeclaration); + void GenSingleNamedExport(ir::AstNode *specifier, const ir::ExportNamedDeclaration *exportDeclaration); void GenReExportDeclaration(const ir::ETSReExportDeclaration *reExportDeclaration); void GenTypeAliasDeclaration(const ir::TSTypeAliasDeclaration *typeAlias); void GenEnumDeclaration(const ir::ClassProperty *enumMember); @@ -169,6 +175,7 @@ private: void ProcessFuncParameters(const checker::Signature *sig); void ProcessClassPropertyType(const ir::ClassProperty *classProp); std::vector FilterValidImportSpecifiers(const ArenaVector &specifiers); + std::vector FilterValidExportSpecifiers(const ArenaVector &specifiers); std::string ReplaceETSGLOBAL(const std::string &typeName); std::string GetIndent() const; std::string RemoveModuleExtensionName(const std::string &filepath); @@ -209,6 +216,7 @@ private: void ProcessInterfaceBody(const ir::TSInterfaceBody *body); void ProcessMethodDefinition(const ir::MethodDefinition *methodDef, std::unordered_set &processedMethods); + void ProcessInterfaceMethodDefinition(const ir::MethodDefinition *methodDef); void ProcessMethodsFromInterfaces(std::unordered_set &processedMethods, const ArenaVector &interfaces); diff --git a/ets2panda/declgen_ets2ts/main.cpp b/ets2panda/declgen_ets2ts/main.cpp index 385e9f37c8d4ff9dc87a97495ca2986f25d0e736..73732e26dc2f71f893efa4480e04847c20c87699 100644 --- a/ets2panda/declgen_ets2ts/main.cpp +++ b/ets2panda/declgen_ets2ts/main.cpp @@ -17,6 +17,7 @@ #include "public/es2panda_lib.h" #include "public/public.h" #include "declgenEts2Ts.h" +#include "ir/astNodeHistory.h" namespace ark::es2panda::declgen_ets2ts { @@ -101,9 +102,8 @@ static int Run(int argc, const char **argv) } auto *cfgImpl = reinterpret_cast(cfg); auto parserInputCStr = cfgImpl->options->CStrParserInputContents().first; - es2panda_Context *ctx = - impl->CreateContextFromString(cfg, parserInputCStr, cfgImpl->options->SourceFileName().c_str()); - + es2panda_Context *ctx = impl->CreateContextFromStringWithHistory(cfg, parserInputCStr, + cfgImpl->options->SourceFileName().c_str(), true); auto *ctxImpl = reinterpret_cast(ctx); auto *checker = reinterpret_cast(ctxImpl->GetChecker()); diff --git a/ets2panda/driver/build_system/src/build/base_mode.ts b/ets2panda/driver/build_system/src/build/base_mode.ts index e1d65f97f6fe1fe2db58868c9de4ba6bfe8dfc66..998cd10aad295d201dedea04bfca1e4aeafa4f26 100644 --- a/ets2panda/driver/build_system/src/build/base_mode.ts +++ b/ets2panda/driver/build_system/src/build/base_mode.ts @@ -176,7 +176,7 @@ export abstract class BaseMode { fileInfo.arktsConfigFile, fileInfo.filePath ]).peer; - arktsGlobal.compilerContext = arkts.Context.createFromString(source); + arktsGlobal.compilerContext = arkts.Context.createFromStringWithHistory(source); PluginDriver.getInstance().getPluginContext().setArkTSProgram(arktsGlobal.compilerContext.program); arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED, arktsGlobal.compilerContext.peer, true); diff --git a/ets2panda/driver/build_system/src/build/declgen_worker.ts b/ets2panda/driver/build_system/src/build/declgen_worker.ts index 63968d0d15f648925d1c2121ed6144717caa5e27..e8774a917894dd802cd98de56ca7149f0ddf80c4 100644 --- a/ets2panda/driver/build_system/src/build/declgen_worker.ts +++ b/ets2panda/driver/build_system/src/build/declgen_worker.ts @@ -76,7 +76,7 @@ process.on('message', (message: { fileInfo.arktsConfigFile, fileInfo.filePath ]).peer; - arktsGlobal.compilerContext = arkts.Context.createFromString(source); + arktsGlobal.compilerContext = arkts.Context.createFromStringWithHistory(source); pluginDriver.getPluginContext().setArkTSProgram(arktsGlobal.compilerContext.program); arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED, arktsGlobal.compilerContext.peer, true); diff --git a/ets2panda/driver/build_system/src/types.ts b/ets2panda/driver/build_system/src/types.ts index 0afb84da0714b559931641d5547c43b6dd7c234e..ed71fc9488d3fd97b50a7ec45357e196dfc8aa9b 100644 --- a/ets2panda/driver/build_system/src/types.ts +++ b/ets2panda/driver/build_system/src/types.ts @@ -67,6 +67,7 @@ export interface ArkTS { }; Context: { createFromString: Function; + createFromStringWithHistory: Function; }; EtsScript: { fromContext: Function; diff --git a/ets2panda/public/es2panda_lib.cpp b/ets2panda/public/es2panda_lib.cpp index 8df91d24aff6942c01c70ef14542a277129967cd..b53cd2ae070094ab71b1c74e21b6f9bb92f3bbe6 100644 --- a/ets2panda/public/es2panda_lib.cpp +++ b/ets2panda/public/es2panda_lib.cpp @@ -473,6 +473,19 @@ extern "C" __attribute__((unused)) es2panda_Context *CreateContextFromString(es2 return CreateContext(config, std::string(source), fileName, nullptr, false, false); } +extern "C" __attribute__((unused)) es2panda_Context *CreateContextFromStringWithHistory(es2panda_Config *config, + const char *source, + char const *fileName, + bool isEnableContextHistory) +{ + // NOTE: gogabr. avoid copying source. + es2panda_Context *context = CreateContextFromString(config, source, fileName); + if (isEnableContextHistory) { + ir::EnableContextHistory(); + } + return context; +} + __attribute__((unused)) static Context *Parse(Context *ctx) { if (ctx->state != ES2PANDA_STATE_NEW) { @@ -1245,6 +1258,7 @@ es2panda_Impl g_impl = { CreateContextFromFile, CreateCacheContextFromFile, CreateContextFromString, + CreateContextFromStringWithHistory, ProceedToState, DestroyContext, CreateGlobalContext, diff --git a/ets2panda/public/es2panda_lib.h b/ets2panda/public/es2panda_lib.h index cf927443b4f8927ae3bde32e4da2d471051bb38c..fb80f6ef5cfcb84810ff48ed0fce33315952a845 100644 --- a/ets2panda/public/es2panda_lib.h +++ b/ets2panda/public/es2panda_lib.h @@ -187,6 +187,8 @@ 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 *(*CreateContextFromStringWithHistory)(es2panda_Config *config, const char *source, + char const *file_name, bool isEnableContextHistory); es2panda_Context *(*ProceedToState)(es2panda_Context *context, es2panda_ContextState state); // context is consumed void (*DestroyContext)(es2panda_Context *context); diff --git a/ets2panda/public/es2panda_lib.idl.erb b/ets2panda/public/es2panda_lib.idl.erb index c884938c36bc0cfcc2990d1184791e6fe8dff87b..b60c54538f97febcc460c9360afe64298b8dbb3c 100644 --- a/ets2panda/public/es2panda_lib.idl.erb +++ b/ets2panda/public/es2panda_lib.idl.erb @@ -172,6 +172,7 @@ interface es2panda_Impl { es2panda_Context CreateContextFromFile(es2panda_Config config, String source_file_name); es2panda_Context CreateContextFromString(es2panda_Config config, String source, String file_name); + es2panda_Context CreateContextFromStringWithHistory(es2panda_Config config, String source, String file_name, boolean isEnableContextHistory); es2panda_Context ProceedToState(es2panda_Context context, es2panda_ContextState state); // context is consumed void DestroyContext(es2panda_Context context);