diff --git a/arkui-plugins/memo-plugins/index.ts b/arkui-plugins/memo-plugins/index.ts index aa5c2de65a05c30a87710b35e2cb346098076e43..72c2b577dd2f3aa67e5e0253ee06712ac919e064 100644 --- a/arkui-plugins/memo-plugins/index.ts +++ b/arkui-plugins/memo-plugins/index.ts @@ -27,77 +27,78 @@ import { SignatureTransformer } from './signature-transformer'; export function unmemoizeTransform(): Plugins { return { name: 'memo-plugin', - checked(this: PluginContext) { - console.log('[MEMO PLUGIN] AFTER CHECKED ENTER'); - const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; - if (!!contextPtr) { - let program = arkts.getOrUpdateGlobalContext(contextPtr).program; - let script = program.astNode; - - debugLog('[BEFORE MEMO SCRIPT] script: ', script.dumpSrc()); - const cachePath: string | undefined = this.getProjectConfig()?.cachePath; - debugDump( - script.dumpSrc(), - getDumpFileName(0, 'SRC', 5, 'MEMO_AfterCheck_Begin'), - true, - cachePath, - program.fileNameWithExtension - ); - - arkts.Performance.getInstance().createEvent('memo-checked'); - - const positionalIdTracker = new PositionalIdTracker(arkts.getFileName(), false); - const parameterTransformer = new ParameterTransformer({ - positionalIdTracker, - }); - const returnTransformer = new ReturnTransformer(); - const signatureTransformer = new SignatureTransformer(); - const functionTransformer = new FunctionTransformer({ - positionalIdTracker, - parameterTransformer, - returnTransformer, - signatureTransformer, - }); - - const programVisitor = new ProgramVisitor({ - pluginName: unmemoizeTransform.name, - state: arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, - visitors: [functionTransformer], - skipPrefixNames: EXTERNAL_SOURCE_PREFIX_NAMES, - pluginContext: this, - }); - - program = programVisitor.programVisitor(program); - script = program.astNode; - - arkts.Performance.getInstance().stopEvent('memo-checked', false); - - debugLog('[AFTER MEMO SCRIPT] script: ', script.dumpSrc()); - debugDump( - script.dumpSrc(), - getDumpFileName(0, 'SRC', 6, 'MEMO_AfterCheck_End'), - true, - cachePath, - program.fileNameWithExtension - ); - - arkts.Performance.getInstance().createEvent('memo-recheck'); - arkts.recheckSubtree(script); - arkts.Performance.getInstance().stopEvent('memo-recheck', false); - - arkts.Performance.getInstance().clearAllEvents(true); - arkts.Performance.getInstance().visualizeEvents(true); - arkts.Performance.getInstance().clearHistory(); - arkts.Performance.getInstance().clearTotalDuration(); - - this.setArkTSAst(script); - console.log('[MEMO PLUGIN] AFTER CHECKED EXIT'); - return script; - } - console.log('[MEMO PLUGIN] AFTER CHECKED EXIT WITH NO TRANSFORM'); - }, + checked: checkedTransform, clean() { arkts.arktsGlobal.clearContext(); }, }; } + +function checkedTransform(this: PluginContext): arkts.EtsScript | undefined { + console.log('[MEMO PLUGIN] AFTER CHECKED ENTER'); + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; + if (!!contextPtr) { + let program = arkts.getOrUpdateGlobalContext(contextPtr).program; + let script = program.astNode; + debugLog('[BEFORE MEMO SCRIPT] script: ', script.dumpSrc()); + const cachePath: string | undefined = this.getProjectConfig()?.cachePath; + debugDump( + script.dumpSrc(), + getDumpFileName(0, 'SRC', 5, 'MEMO_AfterCheck_Begin'), + true, + cachePath, + program.fileNameWithExtension + ); + arkts.Performance.getInstance().createEvent('memo-checked'); + program = checkedProgramVisit(program, this); + script = program.astNode; + arkts.Performance.getInstance().stopEvent('memo-checked', false); + debugLog('[AFTER MEMO SCRIPT] script: ', script.dumpSrc()); + debugDump( + script.dumpSrc(), + getDumpFileName(0, 'SRC', 6, 'MEMO_AfterCheck_End'), + true, + cachePath, + program.fileNameWithExtension + ); + arkts.Performance.getInstance().createEvent('memo-recheck'); + arkts.recheckSubtree(script); + arkts.Performance.getInstance().stopEvent('memo-recheck', false); + arkts.Performance.getInstance().clearAllEvents(false); + arkts.Performance.getInstance().visualizeEvents(true); + arkts.Performance.getInstance().clearHistory(); + arkts.Performance.getInstance().clearTotalDuration(); + this.setArkTSAst(script); + console.log('[MEMO PLUGIN] AFTER CHECKED EXIT'); + return script; + } + console.log('[MEMO PLUGIN] AFTER CHECKED EXIT WITH NO TRANSFORM'); + return undefined; +} + +function checkedProgramVisit(program: arkts.Program, context: PluginContext): arkts.Program { + if (program.canSkipPhases()) { + debugLog('[SKIP PHASE] phase: memo-checked, moduleName: ', program.moduleName); + } else { + debugLog('[CANT SKIP PHASE] phase: memo-checked, moduleName: ', program.moduleName); + const positionalIdTracker = new PositionalIdTracker(arkts.getFileName(), false); + const parameterTransformer = new ParameterTransformer({ positionalIdTracker }); + const returnTransformer = new ReturnTransformer(); + const signatureTransformer = new SignatureTransformer(); + const functionTransformer = new FunctionTransformer({ + positionalIdTracker, + parameterTransformer, + returnTransformer, + signatureTransformer, + }); + const programVisitor = new ProgramVisitor({ + pluginName: unmemoizeTransform.name, + state: arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, + visitors: [functionTransformer], + skipPrefixNames: EXTERNAL_SOURCE_PREFIX_NAMES, + pluginContext: context, + }); + program = programVisitor.programVisitor(program); + } + return program; +} diff --git a/arkui-plugins/ui-plugins/index.ts b/arkui-plugins/ui-plugins/index.ts index a50014ecfaaa4482de0f3059feb2b273b93a3327..e1131f9469b07db5ae9b4bed03af42299e69bea7 100644 --- a/arkui-plugins/ui-plugins/index.ts +++ b/arkui-plugins/ui-plugins/index.ts @@ -50,16 +50,7 @@ function parsedTransform(this: PluginContext): arkts.EtsScript | undefined { program.fileNameWithExtension ); arkts.Performance.getInstance().createEvent('ui-parsed'); - const componentTransformer = new ComponentTransformer(); - const preprocessorTransformer = new PreprocessorTransformer(); - const programVisitor = new ProgramVisitor({ - pluginName: uiTransform.name, - state: arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED, - visitors: [componentTransformer, preprocessorTransformer], - skipPrefixNames: EXTERNAL_SOURCE_PREFIX_NAMES, - pluginContext: this, - }); - program = programVisitor.programVisitor(program); + program = parsedProgramVisit(program, this); script = program.astNode; arkts.Performance.getInstance().stopEvent('ui-parsed', false); debugLog('[AFTER PARSED SCRIPT] script: ', script.dumpSrc()); @@ -78,6 +69,25 @@ function parsedTransform(this: PluginContext): arkts.EtsScript | undefined { return script; } +function parsedProgramVisit(program: arkts.Program, context: PluginContext): arkts.Program { + if (program.canSkipPhases()) { + debugLog('[SKIP PHASE] phase: ui-parsed, moduleName: ', program.moduleName); + } else { + debugLog('[CANT SKIP PHASE] phase: ui-parsed, moduleName: ', program.moduleName); + const componentTransformer = new ComponentTransformer(); + const preprocessorTransformer = new PreprocessorTransformer(); + const programVisitor = new ProgramVisitor({ + pluginName: uiTransform.name, + state: arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED, + visitors: [componentTransformer, preprocessorTransformer], + skipPrefixNames: EXTERNAL_SOURCE_PREFIX_NAMES, + pluginContext: context, + }); + program = programVisitor.programVisitor(program); + } + return program; +} + function checkedTransform(this: PluginContext): arkts.EtsScript | undefined { let script: arkts.EtsScript | undefined; console.log('[UI PLUGIN] AFTER CHECKED ENTER'); @@ -95,15 +105,7 @@ function checkedTransform(this: PluginContext): arkts.EtsScript | undefined { program.fileNameWithExtension ); arkts.Performance.getInstance().createEvent('ui-checked'); - const checkedTransformer = new CheckedTransformer(this.getProjectConfig()); - const programVisitor = new ProgramVisitor({ - pluginName: uiTransform.name, - state: arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, - visitors: [checkedTransformer], - skipPrefixNames: EXTERNAL_SOURCE_PREFIX_NAMES, - pluginContext: this, - }); - program = programVisitor.programVisitor(program); + program = checkedProgramVisit(program, this); script = program.astNode; arkts.Performance.getInstance().stopEvent('ui-checked', false); debugLog('[AFTER STRUCT SCRIPT] script: ', script.dumpSrc()); @@ -128,3 +130,21 @@ function checkedTransform(this: PluginContext): arkts.EtsScript | undefined { console.log('[UI PLUGIN] AFTER CHECKED EXIT WITH NO TRANSFORM'); return script; } + +function checkedProgramVisit(program: arkts.Program, context: PluginContext): arkts.Program { + if (program.canSkipPhases()) { + debugLog('[SKIP PHASE] phase: ui-checked, moduleName: ', program.moduleName); + } else { + debugLog('[CANT SKIP PHASE] phase: ui-checked, moduleName: ', program.moduleName); + const checkedTransformer = new CheckedTransformer(context.getProjectConfig()); + const programVisitor = new ProgramVisitor({ + pluginName: uiTransform.name, + state: arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, + visitors: [checkedTransformer], + skipPrefixNames: EXTERNAL_SOURCE_PREFIX_NAMES, + pluginContext: context, + }); + program = programVisitor.programVisitor(program); + } + return program; +} diff --git a/koala-wrapper/native/src/common.cc b/koala-wrapper/native/src/common.cc index 553a1079b72f7767f317fe0025f0a384f66bb1b7..17a4a0ea13527e6c3e2066fa034fd03674f6967b 100644 --- a/koala-wrapper/native/src/common.cc +++ b/koala-wrapper/native/src/common.cc @@ -40,6 +40,10 @@ static es2panda_Impl *impl = nullptr; #endif const char* LIB_ES2PANDA_PUBLIC = LIB_PREFIX "es2panda_public" LIB_SUFFIX; +constexpr const char* IS_UI_FLAG = "IS_UI_FLAG"; +constexpr const char* NOT_UI_FLAG = "NOT_UI_FLAG"; +const string MODULE_SUFFIX = ".d.ets"; +const string ARKUI = "arkui"; #ifdef KOALA_WINDOWS const char *SEPARATOR = "\\"; @@ -297,6 +301,92 @@ KNativePointer impl_AstNodeChildren( } KOALA_INTEROP_2(AstNodeChildren, KNativePointer, KNativePointer, KNativePointer) +void impl_ProgramAddSelfDefinedFlag(KNativePointer context, KNativePointer instance, KStringPtr& flag) { + const auto _context = reinterpret_cast(context); + const auto _instance = reinterpret_cast(instance); + GetImpl()->ProgramAddSelfDefinedFlag(_context, _instance, getStringCopy(flag)); +} +KOALA_INTEROP_V3(ProgramAddSelfDefinedFlag, KNativePointer, KNativePointer, KStringPtr) + +KBoolean impl_ProgramHasDefinedFlag(KNativePointer context, KNativePointer instance, KStringPtr& flag) +{ + const auto _context = reinterpret_cast(context); + const auto _instance = reinterpret_cast(instance); + std::size_t _length; + char **result = reinterpret_cast + (GetImpl()->ProgramGetSelfDefinedFlagsConst(_context, _instance, &_length)); + if (result != nullptr) { + for (std::size_t i = 0; i < _length; ++i) { + if (strcmp(flag.c_str(), result[i]) == 0) { + return true; + } + } + } + return false; +} +KOALA_INTEROP_3(ProgramHasDefinedFlag, KBoolean, KNativePointer, KNativePointer, KStringPtr) + +static bool isUIHeaderFile(es2panda_Context* context, es2panda_Program* program) +{ + auto result = GetImpl()->ProgramFileNameWithExtensionConst(context, program); + string fileNameWithExtension(result); + result = GetImpl()->ProgramModuleNameConst(context, program); + string moduleName(result); + + return fileNameWithExtension.length() >= MODULE_SUFFIX.length() + && fileNameWithExtension.substr(fileNameWithExtension.length() - MODULE_SUFFIX.length()) == MODULE_SUFFIX + && moduleName.find(ARKUI) != std::string::npos; +} + +static bool isUIHeaderOrUIFile(es2panda_Context* context, es2panda_Program* program) +{ + KStringPtr isUiFlag(IS_UI_FLAG); + KStringPtr notUiFlag(NOT_UI_FLAG); + if (impl_ProgramHasDefinedFlag(context, program, isUiFlag)) { + return true; + } + if (isUIHeaderFile(context, program)) { + impl_ProgramAddSelfDefinedFlag(context, program, notUiFlag); + return true; + } + return false; +} + +KBoolean impl_ProgramCanSkipPhases(KNativePointer context, KNativePointer program) +{ + KStringPtr isUiFlag(IS_UI_FLAG); + KStringPtr notUiFlag(NOT_UI_FLAG); + const auto _context = reinterpret_cast(context); + const auto _program = reinterpret_cast(program); + if (impl_ProgramHasDefinedFlag(_context, _program, isUiFlag)) { + return false; + } + if (impl_ProgramHasDefinedFlag(_context, _program, notUiFlag)) { + return true; + } + + if (isUIHeaderFile(_context, _program)) { + impl_ProgramAddSelfDefinedFlag(_context, _program, isUiFlag); + return false; + } + std::size_t source_len; + const auto external_sources = reinterpret_cast + (GetImpl()->ProgramExternalSources(_context, _program, &source_len)); + for (std::size_t i = 0; i < source_len; ++i) { + std::size_t program_len; + auto programs = GetImpl()->ExternalSourcePrograms(external_sources[i], &program_len); + for (std::size_t j = 0; j < program_len; ++j) { + if (isUIHeaderOrUIFile(_context, programs[j])) { + impl_ProgramAddSelfDefinedFlag(_context, _program, isUiFlag); + return false; + } + } + } + impl_ProgramAddSelfDefinedFlag(_context, _program, notUiFlag); + return true; +} +KOALA_INTEROP_2(ProgramCanSkipPhases, KBoolean, KNativePointer, KNativePointer) + /* ----------------------------------------------------------------------------------------------------------------------------- */ diff --git a/koala-wrapper/src/Es2pandaEnums.ts b/koala-wrapper/src/Es2pandaEnums.ts index bf2ce0783871630fbd77266c141a40a831a094df..6a16486a7bb965c1989e4a0bf594bb8710969746 100644 --- a/koala-wrapper/src/Es2pandaEnums.ts +++ b/koala-wrapper/src/Es2pandaEnums.ts @@ -181,7 +181,7 @@ export enum Es2pandaAstNodeType { AST_NODE_TYPE_OBJECT_PATTERN, AST_NODE_TYPE_SPREAD_ELEMENT, AST_NODE_TYPE_REST_ELEMENT, -} +}; export enum Es2pandaImportFlags { IMPORT_FLAGS_NONE, diff --git a/koala-wrapper/src/Es2pandaNativeModule.ts b/koala-wrapper/src/Es2pandaNativeModule.ts index 6c5b48e7d330356d41d068180c0b263f13838de7..c819a390ed56af33fcb2318e148d6e4fc6c643b2 100644 --- a/koala-wrapper/src/Es2pandaNativeModule.ts +++ b/koala-wrapper/src/Es2pandaNativeModule.ts @@ -750,6 +750,10 @@ export class Es2pandaNativeModule { throw new Error('Not implemented'); } + _ProgramCanSkipPhases(context: KNativePointer, program: KNativePointer): boolean { + throw new Error('Not implemented'); + } + _GenerateTsDeclarationsFromContext( config: KPtr, outputDeclEts: String, @@ -855,6 +859,14 @@ export class Es2pandaNativeModule { throw new Error('Not implemented'); } + _ProgramAddSelfDefinedFlag(context : KNativePointer, instance: KNativePointer, flag: string): void { + throw new Error('Not implemented'); + } + + _ProgramHasDefinedFlag(context : KNativePointer, instance: KNativePointer, flag: string): KBoolean { + throw new Error('Not implemented'); + } + _AstNodeRangeConst(context: KNativePointer, node: KNativePointer): KNativePointer { throw new Error('CreateFunctionDecl was not overloaded by native module initialization'); } diff --git a/koala-wrapper/src/arkts-api/peers/Program.ts b/koala-wrapper/src/arkts-api/peers/Program.ts index 5734dc4a49c3cd7ea1d897d1f00920d5dd032ab5..5b14665f0c70045287ba517d451c2eacba886472 100644 --- a/koala-wrapper/src/arkts-api/peers/Program.ts +++ b/koala-wrapper/src/arkts-api/peers/Program.ts @@ -61,6 +61,10 @@ export class Program extends ArktsObject { isASTLowered(): boolean { return global.es2panda._ProgramIsASTLoweredConst(global.context, this.peer); } + + canSkipPhases(): boolean { + return global.es2panda._ProgramCanSkipPhases(global.context, this.peer); + } } export class ExternalSource extends ArktsObject { diff --git a/koala-wrapper/src/arkts-api/utilities/public.ts b/koala-wrapper/src/arkts-api/utilities/public.ts index d7e2dfc3353ad0cd4acf5f2d4ea5013c493a8653..04ac973fe2a3f115265fd256ed11f74d7d1e5c9c 100644 --- a/koala-wrapper/src/arkts-api/utilities/public.ts +++ b/koala-wrapper/src/arkts-api/utilities/public.ts @@ -39,7 +39,7 @@ import { type AnnotationUsage, } from '../../generated'; import { Program } from '../peers/Program'; -import { clearNodeCache } from '../class-by-peer'; +import { clearNodeCache, nodeByType } from '../class-by-peer'; import { SourcePosition } from '../peers/SourcePosition'; import { MemberExpression } from '../to-be-generated/MemberExpression';