From ea2c8828a3e6d0f03078a9c5b49cdde4659387f5 Mon Sep 17 00:00:00 2001 From: Igor Loginov Date: Fri, 27 Jun 2025 09:04:06 +0300 Subject: [PATCH 1/8] WIP --- ui2abc/libarkts/generator/options.json5 | 13 +- .../src/arkts-api/factory/nodeFactory.ts | 5 + .../src/arkts-api/node-utilities/ETSModule.ts | 44 ++++++ .../{method-definition.ts => extensions.ts} | 16 ++- .../src/arkts-api/utilities/public.ts | 8 +- ui2abc/libarkts/src/arkts-api/visitor.ts | 10 +- .../libarkts/src/generated/peers/ETSModule.ts | 2 + .../src/generated/peers/MethodDefinition.ts | 8 +- ui2abc/libarkts/src/reexport-for-generated.ts | 6 +- .../test/arkts-api/general/recheck.test.ts | 127 ++++++++++-------- 10 files changed, 164 insertions(+), 75 deletions(-) create mode 100644 ui2abc/libarkts/src/arkts-api/node-utilities/ETSModule.ts rename ui2abc/libarkts/src/arkts-api/utilities/{method-definition.ts => extensions.ts} (68%) diff --git a/ui2abc/libarkts/generator/options.json5 b/ui2abc/libarkts/generator/options.json5 index c7ab0e12a..9892bb886 100644 --- a/ui2abc/libarkts/generator/options.json5 +++ b/ui2abc/libarkts/generator/options.json5 @@ -261,13 +261,22 @@ methods: [ { name: "setChildrenParentPtr", - definition: "methodDefinitionSetChildrenParentPtr", + definition: "extension_MethodDefinitionSetChildrenParentPtr", }, { name: "onUpdate", - definition: "methodDefinitionOnUpdate", + definition: "extension_MethodDefinitionOnUpdate", }, ] }, + { + interface: "ETSModule", + methods: [ + { + name: "getFlag", + definition: "extension_ETSModuleGetFlag", + } + ] + } ], } diff --git a/ui2abc/libarkts/src/arkts-api/factory/nodeFactory.ts b/ui2abc/libarkts/src/arkts-api/factory/nodeFactory.ts index f783231da..88023f198 100644 --- a/ui2abc/libarkts/src/arkts-api/factory/nodeFactory.ts +++ b/ui2abc/libarkts/src/arkts-api/factory/nodeFactory.ts @@ -16,6 +16,7 @@ import { ClassDefinition, ETSImportDeclaration, + ETSModule, ETSStructDeclaration, ETSTuple, ETSTypeReferencePart, @@ -52,10 +53,14 @@ import { createTSTypeAliasDeclaration, updateTSTypeAliasDeclaration } from "../n import { createClassDeclaration, updateClassDeclaration } from "../node-utilities/ClassDeclaration" import { createBlockStatement, updateBlockStatement } from "../node-utilities/BlockStatement" import { updateAnnotationUsage } from "../node-utilities/AnnotationUsage" +import { updateETSModule } from "../node-utilities/ETSModule" export const factory = { ...generatedFactory, + createETSModule: ETSModule.createETSModule, + updateETSModule, + createCallExpression, updateCallExpression, diff --git a/ui2abc/libarkts/src/arkts-api/node-utilities/ETSModule.ts b/ui2abc/libarkts/src/arkts-api/node-utilities/ETSModule.ts new file mode 100644 index 000000000..f38127f74 --- /dev/null +++ b/ui2abc/libarkts/src/arkts-api/node-utilities/ETSModule.ts @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ETSModule, Identifier, Program, Statement } from "../../generated" +import { isSameNativeObject } from "../peers/ArktsObject" +import { updateNodeByNode } from "../utilities/private" +import { Es2pandaModuleFlag } from "../../generated/Es2pandaEnums" + +export function updateETSModule( + original: ETSModule, + statementList: readonly Statement[], + ident: Identifier | undefined, + flag: Es2pandaModuleFlag, + program?: Program, +) { + if (isSameNativeObject(statementList, original.statements) + && isSameNativeObject(ident, original.ident) + && isSameNativeObject(flag, original.getFlag()) + && isSameNativeObject(program, original.program) + ) { + return original + } + return updateNodeByNode( + ETSModule.createETSModule( + statementList, + ident, + flag, + program, + ), + original, + ) +} diff --git a/ui2abc/libarkts/src/arkts-api/utilities/method-definition.ts b/ui2abc/libarkts/src/arkts-api/utilities/extensions.ts similarity index 68% rename from ui2abc/libarkts/src/arkts-api/utilities/method-definition.ts rename to ui2abc/libarkts/src/arkts-api/utilities/extensions.ts index 03ce9107a..c1b02cbcd 100644 --- a/ui2abc/libarkts/src/arkts-api/utilities/method-definition.ts +++ b/ui2abc/libarkts/src/arkts-api/utilities/extensions.ts @@ -13,10 +13,20 @@ * limitations under the License. */ -import type { MethodDefinition } from "../../generated" +import type { + ETSModule, + MethodDefinition +} from "../../generated" +import { Es2pandaModuleFlag } from "../../generated/Es2pandaEnums" import { global } from "../../reexport-for-generated" -export function methodDefinitionSetChildrenParentPtr(this: MethodDefinition) { +export function extension_ETSModuleGetFlag(this: ETSModule): Es2pandaModuleFlag { + return (this.isETSScript ? Es2pandaModuleFlag.MODULE_FLAG_ETSSCRIPT : 0) + + (this.isNamespace ? Es2pandaModuleFlag.MODULE_FLAG_NAMESPACE : 0) + + (this.isNamespaceChainLastNode ? Es2pandaModuleFlag.MODULE_FLAG_NAMESPACE_CHAIN_LAST_NODE : 0) +} + +export function extension_MethodDefinitionSetChildrenParentPtr(this: MethodDefinition) { global.es2panda._AstNodeSetChildrenParentPtr(global.context, this.peer) const overloads = this.overloads for (const overload of overloads) { @@ -25,7 +35,7 @@ export function methodDefinitionSetChildrenParentPtr(this: MethodDefinition) { } } -export function methodDefinitionOnUpdate(this: MethodDefinition, original: MethodDefinition): void { +export function extension_MethodDefinitionOnUpdate(this: MethodDefinition, original: MethodDefinition): void { this.setChildrenParentPtr() // TODO Update modifiers only for specific AST nodes in the generated factory code this.modifierFlags = original.modifierFlags diff --git a/ui2abc/libarkts/src/arkts-api/utilities/public.ts b/ui2abc/libarkts/src/arkts-api/utilities/public.ts index 9b9d3b6db..356bc4469 100644 --- a/ui2abc/libarkts/src/arkts-api/utilities/public.ts +++ b/ui2abc/libarkts/src/arkts-api/utilities/public.ts @@ -116,13 +116,13 @@ export function rebindSubtree(node: AstNode): void { checkErrors() } -export function recheckContext(context: KNativePointer): void { +export function recheckContext(context?: KNativePointer): void { global.es2panda._AstNodeRecheck( - context, + context ?? global.context, global.es2panda._ProgramAst( - context, + context ?? global.context, global.es2panda._ContextProgram( - context + context ?? global.context, ) ) ) diff --git a/ui2abc/libarkts/src/arkts-api/visitor.ts b/ui2abc/libarkts/src/arkts-api/visitor.ts index 221521bae..e3263b062 100644 --- a/ui2abc/libarkts/src/arkts-api/visitor.ts +++ b/ui2abc/libarkts/src/arkts-api/visitor.ts @@ -65,7 +65,8 @@ import { isUpdateExpression, isVariableDeclaration, isVariableDeclarator, - isWhileStatement + isWhileStatement, + Statement } from "../generated" import { Es2pandaImportKinds } from "../generated/Es2pandaEnums" import { factory } from "./factory/nodeFactory" @@ -146,9 +147,12 @@ export function visitEachChild( ): AstNode { global.profiler.nodeVisited() if (isETSModule(node)) { - return updateETSModuleByStatements( + return factory.updateETSModule( node, - nodesVisitor(node.statements, visitor) + nodesVisitor(node.statements, visitor), + nodeVisitor(node.ident, visitor), + node.getFlag(), + node.program, ) } if (isCallExpression(node)) { diff --git a/ui2abc/libarkts/src/generated/peers/ETSModule.ts b/ui2abc/libarkts/src/generated/peers/ETSModule.ts index 2ab32b6db..13007aea5 100644 --- a/ui2abc/libarkts/src/generated/peers/ETSModule.ts +++ b/ui2abc/libarkts/src/generated/peers/ETSModule.ts @@ -41,6 +41,7 @@ import { Es2pandaModuleFlag } from "./../Es2pandaEnums" import { Identifier } from "./Identifier" import { Program } from "./Program" import { Statement } from "./Statement" +import { extension_ETSModuleGetFlag } from "./../../reexport-for-generated" export class ETSModule extends BlockStatement { constructor(pointer: KNativePointer) { @@ -121,6 +122,7 @@ export class ETSModule extends BlockStatement { global.generatedEs2panda._ETSModuleAddAnnotations(global.context, this.peer, passNode(annotations)) return this } + getFlag = extension_ETSModuleGetFlag protected readonly brandETSModule: undefined } export function isETSModule(node: object | undefined): node is ETSModule { diff --git a/ui2abc/libarkts/src/generated/peers/MethodDefinition.ts b/ui2abc/libarkts/src/generated/peers/MethodDefinition.ts index 734177998..f4b889f77 100644 --- a/ui2abc/libarkts/src/generated/peers/MethodDefinition.ts +++ b/ui2abc/libarkts/src/generated/peers/MethodDefinition.ts @@ -39,8 +39,8 @@ import { Es2pandaMethodDefinitionKind } from "./../Es2pandaEnums" import { Es2pandaModifierFlags } from "./../Es2pandaEnums" import { Expression } from "./Expression" import { ScriptFunction } from "./ScriptFunction" -import { methodDefinitionOnUpdate } from "./../../reexport-for-generated" -import { methodDefinitionSetChildrenParentPtr } from "./../../reexport-for-generated" +import { extension_MethodDefinitionOnUpdate } from "./../../reexport-for-generated" +import { extension_MethodDefinitionSetChildrenParentPtr } from "./../../reexport-for-generated" export class MethodDefinition extends ClassElement { constructor(pointer: KNativePointer) { @@ -135,8 +135,8 @@ export class MethodDefinition extends ClassElement { global.generatedEs2panda._MethodDefinitionSetValueOverloads(global.context, this.peer, passNode(overloads), index) return this } - setChildrenParentPtr = methodDefinitionSetChildrenParentPtr - onUpdate = methodDefinitionOnUpdate + setChildrenParentPtr = extension_MethodDefinitionSetChildrenParentPtr + onUpdate = extension_MethodDefinitionOnUpdate protected readonly brandMethodDefinition: undefined } export function isMethodDefinition(node: object | undefined): node is MethodDefinition { diff --git a/ui2abc/libarkts/src/reexport-for-generated.ts b/ui2abc/libarkts/src/reexport-for-generated.ts index 10b213eee..ab5d8492a 100644 --- a/ui2abc/libarkts/src/reexport-for-generated.ts +++ b/ui2abc/libarkts/src/reexport-for-generated.ts @@ -31,4 +31,8 @@ export { export { nodeByType } from "./arkts-api/class-by-peer" export { global } from "./arkts-api/static/global" export { Es2pandaMemberExpressionKind } from "./generated/Es2pandaEnums" -export { methodDefinitionSetChildrenParentPtr, methodDefinitionOnUpdate } from "./arkts-api/utilities/method-definition" +export { + extension_ETSModuleGetFlag, + extension_MethodDefinitionOnUpdate, + extension_MethodDefinitionSetChildrenParentPtr, +} from "./arkts-api/utilities/extensions" diff --git a/ui2abc/libarkts/test/arkts-api/general/recheck.test.ts b/ui2abc/libarkts/test/arkts-api/general/recheck.test.ts index 516e668ba..3591ddc9e 100644 --- a/ui2abc/libarkts/test/arkts-api/general/recheck.test.ts +++ b/ui2abc/libarkts/test/arkts-api/general/recheck.test.ts @@ -34,7 +34,8 @@ function createConfig() { } class RenameTestFunction extends arkts.AbstractVisitor { - visitor(beforeChildren: arkts.AstNode) { + visitor(node: arkts.BlockStatement): arkts.BlockStatement + visitor(beforeChildren: arkts.AstNode): arkts.AstNode { const node = this.visitEachChild(beforeChildren) // Don't change name at checked stage, add another import if (arkts.isImportDeclaration(node)) return node @@ -61,39 +62,45 @@ suite(util.basename(__filename), () => { arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED) - const importStorage = new arkts.ImportStorage(arkts.arktsGlobal.compilerContext.program, true) - const module = arkts.createETSModuleFromContext() - - arkts.updateETSModuleByStatements( - module, - [ - arkts.factory.createETSImportDeclaration( - arkts.factory.createStringLiteral( - './library' - ), - [ - arkts.factory.createImportSpecifier( - arkts.factory.createIdentifier( - 'testFunction' - ), - arkts.factory.createIdentifier( - 'testFunction' + const program = arkts.arktsGlobal.compilerContext.program + const importStorage = new arkts.ImportStorage(program, true) + const module = program.ast as arkts.ETSModule + + program.setAst( + arkts.factory.updateETSModule( + module, + [ + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './library' + ), + [ + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'testFunction' + ), + arkts.factory.createIdentifier( + 'testFunction' + ) ) - ) - ], - arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL, - ), - ...module.statements, - ] + ], + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL, + ), + ...module.statements, + ], + module.ident, + module.getFlag(), + module.program, + ) ) importStorage.update() - arkts.arktsGlobal.es2panda._AstNodeUpdateAll(arkts.arktsGlobal.context, module.peer) arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED) - arkts.recheckSubtree(module) + + arkts.recheckContext() util.assert.equal( - module.dumpSrc(), ` + program.ast.dumpSrc(), ` import { testFunction as testFunction } from "./library"; function main() {} @@ -101,7 +108,7 @@ function main() {} console.log("test"); `, - `invalid result: ${module.dumpSrc()}`) + `invalid result: ${program.ast.dumpSrc()}`) arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_BIN_GENERATED) }) @@ -119,49 +126,53 @@ console.log("test"); arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED) - const importStorage = new arkts.ImportStorage(arkts.arktsGlobal.compilerContext.program, true) - const module = arkts.createETSModuleFromContext() + const program = arkts.arktsGlobal.compilerContext.program + const importStorage = new arkts.ImportStorage(program, true) + const module = program.ast as arkts.ETSModule arkts.programGetExternalSources(arkts.arktsGlobal.compilerContext.program).forEach(it => { if (!it.getName().includes("library")) return it.programs.forEach(program => { - new RenameTestFunction().visitor(program.ast) - arkts.arktsGlobal.es2panda._AstNodeUpdateAll(program.ast.peer, module.peer) + program.setAst(new RenameTestFunction().visitor(program.ast)) }) }) - arkts.updateETSModuleByStatements( - module, - [ - arkts.factory.updateETSImportDeclaration( - module.statements[0] as arkts.ETSImportDeclaration, - arkts.factory.createStringLiteral( - './library' - ), - [ - arkts.factory.createImportSpecifier( - arkts.factory.createIdentifier( - 'testFunctionChanged' - ), - arkts.factory.createIdentifier( - 'testFunctionChanged' + program.setAst( + arkts.factory.updateETSModule( + module, + [ + arkts.factory.updateETSImportDeclaration( + module.statements[0] as arkts.ETSImportDeclaration, + arkts.factory.createStringLiteral( + './library' + ), + [ + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'testFunctionChanged' + ), + arkts.factory.createIdentifier( + 'testFunctionChanged' + ) ) - ) - ], - arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL, - ), - ...module.statements.slice(1), - ] + ], + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL, + ), + ...module.statements.slice(1), + ], + module.ident, + module.getFlag(), + module.program, + ) ) - new RenameTestFunction().visitor(module) + program.setAst(new RenameTestFunction().visitor(program.ast)) importStorage.update() - arkts.arktsGlobal.es2panda._AstNodeUpdateAll(arkts.arktsGlobal.context, module.peer) - arkts.recheckSubtree(module) + arkts.recheckContext() util.assert.equal( - module.dumpSrc(), ` + program.ast.dumpSrc(), ` import { testFunctionChanged as testFunctionChanged } from "./library"; function main() {} @@ -169,7 +180,7 @@ function main() {} testFunctionChanged(); `, - `invalid result: ${module.dumpSrc()}`) + `invalid result: ${program.ast.dumpSrc()}`) arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_BIN_GENERATED) }) -- Gitee From cb85b0191491eb5f8d632d8087e894dda3db2764 Mon Sep 17 00:00:00 2001 From: Igor Loginov Date: Fri, 27 Jun 2025 10:04:22 +0300 Subject: [PATCH 2/8] Work with ETSModule as with usual node --- .../src/arkts-api/ChainExpressionFilter.ts | 3 +- .../libarkts/src/arkts-api/ImportStorage.ts | 14 +- .../src/arkts-api/InferVoidReturnType.ts | 12 +- .../src/arkts-api/utilities/public.ts | 11 - ui2abc/libarkts/src/arkts-api/visitor.ts | 1 - ui2abc/libarkts/src/plugin-utils.ts | 15 +- .../expressions/call-expression.test.ts | 7 +- .../test/arkts-api/functions/create.test.ts | 14 +- .../test/arkts-api/general/basic.test.ts | 7 +- .../arkts-api/import-export/import.test.ts | 28 ++- .../test/arkts-api/recache/main.test.ts | 6 +- .../arkts-api/recheck/constructor/index.ts | 4 +- .../recheck/exports/add-export/index.ts | 106 +++++----- .../arkts-api/recheck/exports/basic/index.ts | 102 +++++----- .../recheck/exports/create-class/index.ts | 192 ++++++++++-------- .../recheck/exports/struct-to-class/index.ts | 110 +++++----- .../recheck/imports/add-new-file/index.ts | 40 ++-- .../recheck/imports/add-same-file/index.ts | 46 +++-- .../imports/add-use-same-file/index.ts | 68 ++++--- .../recheck/imports/recursive/index.ts | 4 +- .../recheck/optional/add-chain/index.ts | 3 +- .../recheck/overloads/getter-setter/index.ts | 4 +- .../test/arkts-api/recheck/recheck.test.ts | 6 +- .../test/arkts-api/recheck/simple/index.ts | 7 +- .../test/arkts-api/recheck/this/index.ts | 5 +- ui2abc/memo-plugin/src/MemoTransformer.ts | 9 +- ui2abc/memo-plugin/src/ParserTransformer.ts | 18 +- ui2abc/ui-plugins/src/checked-stage-plugin.ts | 3 +- .../ui-plugins/src/component-transformer.ts | 8 +- ui2abc/ui-plugins/src/imports-transformer.ts | 7 +- ui2abc/ui-plugins/src/parsed-stage-plugin.ts | 3 +- 31 files changed, 475 insertions(+), 388 deletions(-) diff --git a/ui2abc/libarkts/src/arkts-api/ChainExpressionFilter.ts b/ui2abc/libarkts/src/arkts-api/ChainExpressionFilter.ts index 4976aa6c7..3d22c7c46 100644 --- a/ui2abc/libarkts/src/arkts-api/ChainExpressionFilter.ts +++ b/ui2abc/libarkts/src/arkts-api/ChainExpressionFilter.ts @@ -13,7 +13,7 @@ * limitations under the License. */ -import { ChainExpression, Expression, isChainExpression, isMemberExpression, MemberExpression } from "src/generated"; +import { BlockStatement, ChainExpression, Expression, isChainExpression, isMemberExpression, MemberExpression } from "src/generated"; import { AbstractVisitor } from "./AbstractVisitor"; import { AstNode } from "./peers/AstNode" import { factory } from "./factory/nodeFactory"; @@ -65,6 +65,7 @@ export class ChainExpressionFilter extends AbstractVisitor { } + visitor(beforeChildren: BlockStatement): BlockStatement visitor(beforeChildren: AstNode): AstNode { const node = this.visitEachChild(beforeChildren) if (isChainExpression(node)) { diff --git a/ui2abc/libarkts/src/arkts-api/ImportStorage.ts b/ui2abc/libarkts/src/arkts-api/ImportStorage.ts index 50f7d3485..cd7172cb0 100644 --- a/ui2abc/libarkts/src/arkts-api/ImportStorage.ts +++ b/ui2abc/libarkts/src/arkts-api/ImportStorage.ts @@ -15,10 +15,10 @@ import { KNativePointer } from "@koalaui/interop" import { ETSModule, ImportDeclaration, isETSImportDeclaration, Program, Statement } from "../generated" -import { updateETSModuleByStatements } from "./utilities/public" import { passNode, passNodeArray, unpackNonNullableNode } from "./utilities/private" import { global } from "./static/global" import { Es2pandaImportFlags, Es2pandaImportKinds } from "../generated/Es2pandaEnums" +import { factory } from "./factory/nodeFactory" export class ImportStorage { // TODO: migrate to wrappers instead of pointers @@ -70,9 +70,15 @@ export class ImportStorage { } // Drop import statements generated by compiler in the beginning of the ETSModule - updateETSModuleByStatements( - this.program.ast as ETSModule, - newStatements, + const module = this.program.ast as ETSModule + this.program.setAst( + factory.updateETSModule( + module, + newStatements, + module.ident, + module.getFlag(), + module.program, + ) ) } } diff --git a/ui2abc/libarkts/src/arkts-api/InferVoidReturnType.ts b/ui2abc/libarkts/src/arkts-api/InferVoidReturnType.ts index 74ff219b6..f25337500 100644 --- a/ui2abc/libarkts/src/arkts-api/InferVoidReturnType.ts +++ b/ui2abc/libarkts/src/arkts-api/InferVoidReturnType.ts @@ -14,7 +14,7 @@ */ import { factory } from "./factory/nodeFactory" -import { isReturnStatement, isScriptFunction, ScriptFunction } from "../generated" +import { BlockStatement, isReturnStatement, isScriptFunction, Program, ScriptFunction } from "../generated" import { AbstractVisitor } from "./AbstractVisitor" import { AstNode } from "./peers/AstNode" import { Es2pandaPrimitiveType, Es2pandaScriptFunctionFlags } from "src/generated/Es2pandaEnums" @@ -50,6 +50,7 @@ function checkReturns(node: AstNode): boolean { } class InferVoidReturnType extends AbstractVisitor { + visitor(node: BlockStatement): BlockStatement visitor(node: AstNode): AstNode { const result = this.visitEachChild(node) if (isScriptFunction(result) && @@ -77,13 +78,8 @@ class InferVoidReturnType extends AbstractVisitor { } return result } - - static instance?: InferVoidReturnType } -export function inferVoidReturnType(node: AstNode) { - if (!InferVoidReturnType.instance) { - InferVoidReturnType.instance = new InferVoidReturnType() - } - InferVoidReturnType.instance.visitor(node) +export function inferVoidReturnType(program: Program) { + program.setAst(new InferVoidReturnType().visitor(program.ast)) } diff --git a/ui2abc/libarkts/src/arkts-api/utilities/public.ts b/ui2abc/libarkts/src/arkts-api/utilities/public.ts index 356bc4469..74ff43cc9 100644 --- a/ui2abc/libarkts/src/arkts-api/utilities/public.ts +++ b/ui2abc/libarkts/src/arkts-api/utilities/public.ts @@ -70,17 +70,6 @@ export function metaDatabase(fileName: string): string { return `${fileName}.meta.json` } -export function updateETSModuleByStatements( - node: ETSModule, - statements: readonly AstNode[], -): ETSModule { - if (isSameNativeObject(statements, node.statements)) { - return node - } - global.generatedEs2panda._BlockStatementSetStatements(global.context, node.peer, passNodeArray(statements), statements.length) - return node -} - export function checkErrors() { if (global.es2panda._ContextState(global.context) === Es2pandaContextState.ES2PANDA_STATE_ERROR) { console.log() diff --git a/ui2abc/libarkts/src/arkts-api/visitor.ts b/ui2abc/libarkts/src/arkts-api/visitor.ts index e3263b062..a02895343 100644 --- a/ui2abc/libarkts/src/arkts-api/visitor.ts +++ b/ui2abc/libarkts/src/arkts-api/visitor.ts @@ -72,7 +72,6 @@ import { Es2pandaImportKinds } from "../generated/Es2pandaEnums" import { factory } from "./factory/nodeFactory" import { AstNode } from "./peers/AstNode" import { global } from "./static/global" -import { updateETSModuleByStatements } from "./utilities/public" type Visitor = (node: AstNode, options?: object) => AstNode diff --git a/ui2abc/libarkts/src/plugin-utils.ts b/ui2abc/libarkts/src/plugin-utils.ts index 7a1a55654..71b270837 100644 --- a/ui2abc/libarkts/src/plugin-utils.ts +++ b/ui2abc/libarkts/src/plugin-utils.ts @@ -48,20 +48,17 @@ export function runTransformerOnProgram(program: Program, options: CompilationOp // Perform some additional actions before the transformation start hooks.onProgramTransformStart?.(options) - // AST to be transformed - const ast = program.ast - // Save currently existing imports in the program const importStorage = new ImportStorage(program, options.stage == Es2pandaContextState.ES2PANDA_STATE_PARSED) // Run some common plugins that should be run before plugin usage and depends on the current stage - stageSpecificPreFilters(ast, options.stage) + stageSpecificPreFilters(program, options.stage) // Run the plugin itself transform?.(program, options, pluginContext) // Run some common plugins that should be run after plugin usage and depends on the current stage - stageSpecificPostFilters(ast, options.stage) + stageSpecificPostFilters(program, options.stage) // Update internal import information based on import modification by plugin importStorage.update() @@ -101,14 +98,14 @@ function setAllParents(ast: AstNode) { arktsGlobal.es2panda._AstNodeUpdateAll(arktsGlobal.context, ast.peer) } -function stageSpecificPreFilters(script: AstNode, state: Es2pandaContextState) { +function stageSpecificPreFilters(program: Program, state: Es2pandaContextState) { if (state == Es2pandaContextState.ES2PANDA_STATE_CHECKED) { - inferVoidReturnType(script) + inferVoidReturnType(program) } } -function stageSpecificPostFilters(script: AstNode, state: Es2pandaContextState) { +function stageSpecificPostFilters(program: Program, state: Es2pandaContextState) { if (state == Es2pandaContextState.ES2PANDA_STATE_CHECKED) { - new ChainExpressionFilter().visitor(script) + program.setAst(new ChainExpressionFilter().visitor(program.ast)) } } diff --git a/ui2abc/libarkts/test/arkts-api/expressions/call-expression.test.ts b/ui2abc/libarkts/test/arkts-api/expressions/call-expression.test.ts index 175494dd8..23b13f1a8 100644 --- a/ui2abc/libarkts/test/arkts-api/expressions/call-expression.test.ts +++ b/ui2abc/libarkts/test/arkts-api/expressions/call-expression.test.ts @@ -31,7 +31,7 @@ suite(util.basename(__filename), () => { let script = arkts.createETSModuleFromSource(sample_in) - script = arkts.updateETSModuleByStatements( + script = arkts.factory.updateETSModule( script, [ script.statements[0], @@ -56,7 +56,10 @@ suite(util.basename(__filename), () => { undefined, ) ) - ] + ], + script.ident, + script.getFlag(), + script.program, ) util.ARKTS_TEST_ASSERTION( diff --git a/ui2abc/libarkts/test/arkts-api/functions/create.test.ts b/ui2abc/libarkts/test/arkts-api/functions/create.test.ts index b6e85b60d..d7e5fe18c 100644 --- a/ui2abc/libarkts/test/arkts-api/functions/create.test.ts +++ b/ui2abc/libarkts/test/arkts-api/functions/create.test.ts @@ -80,7 +80,7 @@ suite(util.basename(__filename), () => { ) funcDecl.updateModifiers(scriptFunc.modifierFlags) - script = arkts.updateETSModuleByStatements( + script = arkts.factory.updateETSModule( script, [ script.statements[0], @@ -94,7 +94,10 @@ suite(util.basename(__filename), () => { undefined, ) ) - ] + ], + script.ident, + script.getFlag(), + script.program, ) util.ARKTS_TEST_ASSERTION( @@ -215,7 +218,7 @@ suite(util.basename(__filename), () => { ) funcDecl.updateModifiers(scriptFunc.modifierFlags) - script = arkts.updateETSModuleByStatements( + script = arkts.factory.updateETSModule( script, [ script.statements[0], @@ -233,7 +236,10 @@ suite(util.basename(__filename), () => { undefined, ) ) - ] + ], + script.ident, + script.getFlag(), + script.program, ) util.ARKTS_TEST_ASSERTION( diff --git a/ui2abc/libarkts/test/arkts-api/general/basic.test.ts b/ui2abc/libarkts/test/arkts-api/general/basic.test.ts index 84e8044f3..0368ef02e 100644 --- a/ui2abc/libarkts/test/arkts-api/general/basic.test.ts +++ b/ui2abc/libarkts/test/arkts-api/general/basic.test.ts @@ -24,7 +24,7 @@ suite(util.basename(__filename), () => { let script = arkts.createETSModuleFromSource(sample_in) - script = arkts.updateETSModuleByStatements( + script = arkts.factory.updateETSModule( script, [ arkts.factory.createExpressionStatement( @@ -32,7 +32,10 @@ suite(util.basename(__filename), () => { 'abc' ) ) - ] + ], + script.ident, + script.getFlag(), + script.program, ) util.ARKTS_TEST_ASSERTION( diff --git a/ui2abc/libarkts/test/arkts-api/import-export/import.test.ts b/ui2abc/libarkts/test/arkts-api/import-export/import.test.ts index 72138030b..4cdb7ace2 100644 --- a/ui2abc/libarkts/test/arkts-api/import-export/import.test.ts +++ b/ui2abc/libarkts/test/arkts-api/import-export/import.test.ts @@ -26,7 +26,7 @@ suite(util.basename(__filename), () => { let script = arkts.createETSModuleFromSource(sample_in) - arkts.updateETSModuleByStatements( + script = arkts.factory.updateETSModule( script, [ arkts.factory.createETSImportDeclaration( @@ -45,7 +45,10 @@ suite(util.basename(__filename), () => { ], arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL, ) - ] + ], + script.ident, + script.getFlag(), + script.program, ) util.ARKTS_TEST_ASSERTION( @@ -66,7 +69,7 @@ suite(util.basename(__filename), () => { let script = arkts.createETSModuleFromSource(sample_in) const importDeclaration = script.statements[0] as arkts.ETSImportDeclaration - arkts.updateETSModuleByStatements( + script = arkts.factory.updateETSModule( script, [ arkts.factory.createETSImportDeclaration( @@ -86,7 +89,10 @@ suite(util.basename(__filename), () => { arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL, ), ...script.statements, - ] + ], + script.ident, + script.getFlag(), + script.program, ) util.ARKTS_TEST_ASSERTION( @@ -112,7 +118,7 @@ suite(util.basename(__filename), () => { let script = arkts.createETSModuleFromSource(sample_in) const importDeclaration = script.statements[0] as arkts.ETSImportDeclaration - arkts.updateETSModuleByStatements( + script = arkts.factory.updateETSModule( script, [ arkts.factory.createETSImportDeclaration( @@ -132,7 +138,10 @@ suite(util.basename(__filename), () => { arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL, ), ...script.statements, - ] + ], + script.ident, + script.getFlag(), + script.program, ) util.ARKTS_TEST_ASSERTION( @@ -200,12 +209,15 @@ suite(util.basename(__filename), () => { ) newFuncDecl.updateModifiers(newScriptFunc.modifierFlags) - script = arkts.updateETSModuleByStatements( + script = arkts.factory.updateETSModule( script, [ script.statements[0], newFuncDecl - ] + ], + script.ident, + script.getFlag(), + script.program, ) util.ARKTS_TEST_ASSERTION( diff --git a/ui2abc/libarkts/test/arkts-api/recache/main.test.ts b/ui2abc/libarkts/test/arkts-api/recache/main.test.ts index 97b3dfece..11a10ceee 100644 --- a/ui2abc/libarkts/test/arkts-api/recache/main.test.ts +++ b/ui2abc/libarkts/test/arkts-api/recache/main.test.ts @@ -24,6 +24,7 @@ function shouldModify(name: string) { } class VisitorParsed extends arkts.AbstractVisitor { + visitor(node: arkts.BlockStatement): arkts.BlockStatement visitor(node: arkts.AstNode) { if (arkts.isIdentifier(node)) { if (shouldModify(node.name)) return arkts.factory.createIdentifier(node.name + "_Parsed") @@ -33,6 +34,7 @@ class VisitorParsed extends arkts.AbstractVisitor { } class VisitorChecked extends arkts.AbstractVisitor { + visitor(node: arkts.BlockStatement): arkts.BlockStatement visitor(node: arkts.AstNode) { if (arkts.isIdentifier(node)) { if (shouldModify(node.name)) return arkts.factory.createIdentifier(node.name + "_Checked") @@ -48,10 +50,10 @@ class VisitorChecked extends arkts.AbstractVisitor { function visitor(program: arkts.Program, options: arkts.CompilationOptions) { arkts.dumpProgramInfo(program) if (options.stage == arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED) { - new VisitorParsed().visitor(program.ast) + program.setAst(new VisitorParsed().visitor(program.ast)) } if (options.stage == arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED) { - new VisitorChecked().visitor(program.ast) + program.setAst(new VisitorChecked().visitor(program.ast)) } } diff --git a/ui2abc/libarkts/test/arkts-api/recheck/constructor/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/constructor/index.ts index b43a54f3f..52b9b2e2e 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/constructor/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/constructor/index.ts @@ -16,7 +16,7 @@ import * as arkts from "../../../../src/arkts-api" class ConstructorWithOverload extends arkts.AbstractVisitor { - visitor(beforeChildren: arkts.ETSModule): arkts.ETSModule + visitor(beforeChildren: arkts.BlockStatement): arkts.BlockStatement visitor(beforeChildren: arkts.AstNode): arkts.AstNode { const node = this.visitEachChild(beforeChildren) if (arkts.isScriptFunction(node) && node.id?.name == "constructor") { @@ -48,5 +48,5 @@ class ConstructorWithOverload extends arkts.AbstractVisitor { } export function constructorWithOverload(program: arkts.Program) { - return new ConstructorWithOverload().visitor(program.ast as arkts.ETSModule) + program.setAst(new ConstructorWithOverload().visitor(program.ast)) } diff --git a/ui2abc/libarkts/test/arkts-api/recheck/exports/add-export/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/exports/add-export/index.ts index bc415a3e6..ca2df6cd5 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/exports/add-export/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/exports/add-export/index.ts @@ -16,7 +16,7 @@ import * as arkts from "../../../../../src/arkts-api" class ExportClass extends arkts.AbstractVisitor { - visitor(beforeChildren: arkts.ETSModule): arkts.ETSModule + visitor(beforeChildren: arkts.BlockStatement): arkts.BlockStatement visitor(beforeChildren: arkts.AstNode): arkts.AstNode { const node = this.visitEachChild(beforeChildren) if (arkts.isClassDeclaration(node) && node.definition?.ident?.name == "C") { @@ -28,62 +28,68 @@ class ExportClass extends arkts.AbstractVisitor { export function addUseImportClassSameFileAndExportClass(program: arkts.Program, options: arkts.CompilationOptions) { if (options.isMainProgram) { - arkts.updateETSModuleByStatements( - program.ast as arkts.ETSModule, - [ - // import { C as C } from "./library" - arkts.factory.createETSImportDeclaration( - arkts.factory.createStringLiteral( - './library' - ), - [ - arkts.factory.createImportSpecifier( - arkts.factory.createIdentifier( - 'C' - ), - arkts.factory.createIdentifier( - 'C' - ) - ) - ], - arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL - ), - ...program.ast.statements, - // class D { - // c = new C() - // } - arkts.factory.createClassDeclaration( - arkts.factory.createClassDefinition( - arkts.factory.createIdentifier("D"), - undefined, - undefined, - [], - undefined, - undefined, + const module = program.ast as arkts.ETSModule + program.setAst( + arkts.factory.updateETSModule( + module, + [ + // import { C as C } from "./library" + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './library' + ), [ - arkts.factory.createClassProperty( - arkts.factory.createIdentifier("c"), - arkts.factory.createETSNewClassInstanceExpression( - arkts.factory.createETSTypeReference( - arkts.factory.createETSTypeReferencePart( - arkts.factory.createIdentifier("C") - ) - ), - [] + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'C' ), - undefined, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, - false, + arkts.factory.createIdentifier( + 'C' + ) ) ], - arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_CLASS_DECL, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL + ), + ...module.statements, + // class D { + // c = new C() + // } + arkts.factory.createClassDeclaration( + arkts.factory.createClassDefinition( + arkts.factory.createIdentifier("D"), + undefined, + undefined, + [], + undefined, + undefined, + [ + arkts.factory.createClassProperty( + arkts.factory.createIdentifier("c"), + arkts.factory.createETSNewClassInstanceExpression( + arkts.factory.createETSTypeReference( + arkts.factory.createETSTypeReferencePart( + arkts.factory.createIdentifier("C") + ) + ), + [] + ), + undefined, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + false, + ) + ], + arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_CLASS_DECL, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + ) ) - ) - ] + ], + module.ident, + module.getFlag(), + module.program, + ) ) } else { - new ExportClass().visitor(program.ast as arkts.ETSModule) + program.setAst(new ExportClass().visitor(program.ast)) } return program } diff --git a/ui2abc/libarkts/test/arkts-api/recheck/exports/basic/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/exports/basic/index.ts index bbc7ef4cb..78af8a9ed 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/exports/basic/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/exports/basic/index.ts @@ -17,59 +17,65 @@ import * as arkts from "../../../../../src/arkts-api" export function addUseImportClassSameFile(program: arkts.Program, options: arkts.CompilationOptions) { if (options.isMainProgram) { - arkts.updateETSModuleByStatements( - program.ast as arkts.ETSModule, - [ - // import { C as C } from "./library" - arkts.factory.createETSImportDeclaration( - arkts.factory.createStringLiteral( - './library' - ), - [ - arkts.factory.createImportSpecifier( - arkts.factory.createIdentifier( - 'C' - ), - arkts.factory.createIdentifier( - 'C' - ) - ) - ], - arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL - ), - ...program.ast.statements, - // class D { - // c = new C() - // } - arkts.factory.createClassDeclaration( - arkts.factory.createClassDefinition( - arkts.factory.createIdentifier("D"), - undefined, - undefined, - [], - undefined, - undefined, + const module = program.ast as arkts.ETSModule + program.setAst( + arkts.factory.updateETSModule( + module, + [ + // import { C as C } from "./library" + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './library' + ), [ - arkts.factory.createClassProperty( - arkts.factory.createIdentifier("c"), - arkts.factory.createETSNewClassInstanceExpression( - arkts.factory.createETSTypeReference( - arkts.factory.createETSTypeReferencePart( - arkts.factory.createIdentifier("C") - ) - ), - [] + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'C' ), - undefined, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, - false, + arkts.factory.createIdentifier( + 'C' + ) ) ], - arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_CLASS_DECL, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL + ), + ...module.statements, + // class D { + // c = new C() + // } + arkts.factory.createClassDeclaration( + arkts.factory.createClassDefinition( + arkts.factory.createIdentifier("D"), + undefined, + undefined, + [], + undefined, + undefined, + [ + arkts.factory.createClassProperty( + arkts.factory.createIdentifier("c"), + arkts.factory.createETSNewClassInstanceExpression( + arkts.factory.createETSTypeReference( + arkts.factory.createETSTypeReferencePart( + arkts.factory.createIdentifier("C") + ) + ), + [] + ), + undefined, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + false, + ) + ], + arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_CLASS_DECL, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + ) ) - ) - ] + ], + module.ident, + module.getFlag(), + module.program, + ) ) } return program diff --git a/ui2abc/libarkts/test/arkts-api/recheck/exports/create-class/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/exports/create-class/index.ts index 6d7667ce8..e63ecb777 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/exports/create-class/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/exports/create-class/index.ts @@ -17,106 +17,118 @@ import * as arkts from "../../../../../src/arkts-api" export function addUseImportClassSameFileAndCreateClass(program: arkts.Program, options: arkts.CompilationOptions) { if (options.isMainProgram) { - arkts.updateETSModuleByStatements( - program.ast as arkts.ETSModule, - [ - // import { C as C } from "./library" - arkts.factory.createETSImportDeclaration( - arkts.factory.createStringLiteral( - './library' - ), - [ - arkts.factory.createImportSpecifier( - arkts.factory.createIdentifier( - 'C' - ), - arkts.factory.createIdentifier( - 'C' - ) - ) - ], - arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL - ), - ...program.ast.statements, - // class D { - // c = new C() - // } - arkts.factory.createClassDeclaration( - arkts.factory.createClassDefinition( - arkts.factory.createIdentifier("D"), - undefined, - undefined, - [], - undefined, - undefined, + const module = program.ast as arkts.ETSModule + program.setAst( + arkts.factory.updateETSModule( + module, + [ + // import { C as C } from "./library" + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './library' + ), [ - arkts.factory.createClassProperty( - arkts.factory.createIdentifier("c"), - arkts.factory.createETSNewClassInstanceExpression( - arkts.factory.createETSTypeReference( - arkts.factory.createETSTypeReferencePart( - arkts.factory.createIdentifier("C") - ) - ), - [] + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'C' ), - undefined, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, - false, + arkts.factory.createIdentifier( + 'C' + ) ) ], - arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_CLASS_DECL, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL + ), + ...module.statements, + // class D { + // c = new C() + // } + arkts.factory.createClassDeclaration( + arkts.factory.createClassDefinition( + arkts.factory.createIdentifier("D"), + undefined, + undefined, + [], + undefined, + undefined, + [ + arkts.factory.createClassProperty( + arkts.factory.createIdentifier("c"), + arkts.factory.createETSNewClassInstanceExpression( + arkts.factory.createETSTypeReference( + arkts.factory.createETSTypeReferencePart( + arkts.factory.createIdentifier("C") + ) + ), + [] + ), + undefined, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + false, + ) + ], + arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_CLASS_DECL, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + ) ) - ) - ] + ], + module.ident, + module.getFlag(), + module.program, + ) ) } else { - arkts.updateETSModuleByStatements( - program.ast as arkts.ETSModule, - [ - ...program.ast.statements, - arkts.factory.createClassDeclaration( - arkts.factory.createClassDefinition( - arkts.factory.createIdentifier( - "C" - ), - undefined, - undefined, - [], - undefined, - undefined, - [ - arkts.factory.createMethodDefinition( - arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_CONSTRUCTOR, - arkts.factory.createIdentifier("constructor"), - arkts.factory.createFunctionExpression( + const module = program.ast as arkts.ETSModule + program.setAst( + arkts.factory.updateETSModule( + module, + [ + ...module.statements, + arkts.factory.createClassDeclaration( + arkts.factory.createClassDefinition( + arkts.factory.createIdentifier( + "C" + ), + undefined, + undefined, + [], + undefined, + undefined, + [ + arkts.factory.createMethodDefinition( + arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_CONSTRUCTOR, arkts.factory.createIdentifier("constructor"), - arkts.factory.createScriptFunction( - arkts.factory.createBlockStatement( - [], - ), - undefined, - [], - undefined, - false, - arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_CONSTRUCTOR, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + arkts.factory.createFunctionExpression( arkts.factory.createIdentifier("constructor"), - [], - ) + arkts.factory.createScriptFunction( + arkts.factory.createBlockStatement( + [], + ), + undefined, + [], + undefined, + false, + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_CONSTRUCTOR, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + arkts.factory.createIdentifier("constructor"), + [], + ) + ), + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_CONSTRUCTOR, + false, + [], ), - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_CONSTRUCTOR, - false, - [], - ), - ], - arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_CLASS_DECL, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, - ), - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_EXPORT, - ) - ] + ], + arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_CLASS_DECL, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + ), + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_EXPORT, + ) + ], + module.ident, + module.getFlag(), + module.program, + ) ) } return program diff --git a/ui2abc/libarkts/test/arkts-api/recheck/exports/struct-to-class/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/exports/struct-to-class/index.ts index 7d55cceeb..c6eea84ef 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/exports/struct-to-class/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/exports/struct-to-class/index.ts @@ -16,7 +16,7 @@ import * as arkts from "../../../../../src/arkts-api" class StructToClass extends arkts.AbstractVisitor { - visitor(beforeChildren: arkts.ETSModule): arkts.ETSModule + visitor(beforeChildren: arkts.BlockStatement): arkts.BlockStatement visitor(beforeChildren: arkts.AstNode): arkts.AstNode { const node = this.visitEachChild(beforeChildren) if (arkts.isETSStructDeclaration(node)) { @@ -30,13 +30,13 @@ class StructToClass extends arkts.AbstractVisitor { export function rewriteStructToClass(program: arkts.Program, options: arkts.CompilationOptions) { if (!options.isMainProgram) { - new StructToClass().visitor(program.ast as arkts.ETSModule) + program.setAst(new StructToClass().visitor(program.ast)) } return program } class ExportClass extends arkts.AbstractVisitor { - visitor(beforeChildren: arkts.ETSModule): arkts.ETSModule + visitor(beforeChildren: arkts.BlockStatement): arkts.BlockStatement visitor(beforeChildren: arkts.AstNode): arkts.AstNode { const node = this.visitEachChild(beforeChildren) if (arkts.isClassDeclaration(node) && node.definition?.ident?.name == "C") { @@ -48,62 +48,68 @@ class ExportClass extends arkts.AbstractVisitor { export function addUseImportClassSameFileAfterRewritingStructToClass(program: arkts.Program, options: arkts.CompilationOptions) { if (options.isMainProgram) { - arkts.updateETSModuleByStatements( - program.ast as arkts.ETSModule, - [ - // import { C as C } from "./library" - arkts.factory.createETSImportDeclaration( - arkts.factory.createStringLiteral( - './library' - ), - [ - arkts.factory.createImportSpecifier( - arkts.factory.createIdentifier( - 'C' - ), - arkts.factory.createIdentifier( - 'C' - ) - ) - ], - arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL - ), - ...program.ast.statements, - // class D { - // c = new C() - // } - arkts.factory.createClassDeclaration( - arkts.factory.createClassDefinition( - arkts.factory.createIdentifier("D"), - undefined, - undefined, - [], - undefined, - undefined, + const module = program.ast as arkts.ETSModule + program.setAst( + arkts.factory.updateETSModule( + module, + [ + // import { C as C } from "./library" + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './library' + ), [ - arkts.factory.createClassProperty( - arkts.factory.createIdentifier("c"), - arkts.factory.createETSNewClassInstanceExpression( - arkts.factory.createETSTypeReference( - arkts.factory.createETSTypeReferencePart( - arkts.factory.createIdentifier("C") - ) - ), - [] + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'C' ), - undefined, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, - false, + arkts.factory.createIdentifier( + 'C' + ) ) ], - arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_CLASS_DECL, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL + ), + ...module.statements, + // class D { + // c = new C() + // } + arkts.factory.createClassDeclaration( + arkts.factory.createClassDefinition( + arkts.factory.createIdentifier("D"), + undefined, + undefined, + [], + undefined, + undefined, + [ + arkts.factory.createClassProperty( + arkts.factory.createIdentifier("c"), + arkts.factory.createETSNewClassInstanceExpression( + arkts.factory.createETSTypeReference( + arkts.factory.createETSTypeReferencePart( + arkts.factory.createIdentifier("C") + ) + ), + [] + ), + undefined, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + false, + ) + ], + arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_CLASS_DECL, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + ) ) - ) - ] + ], + module.ident, + module.getFlag(), + module.program, + ) ) } else { - new ExportClass().visitor(program.ast as arkts.ETSModule) + program.setAst(new ExportClass().visitor(program.ast as arkts.ETSModule)) } return program } diff --git a/ui2abc/libarkts/test/arkts-api/recheck/imports/add-new-file/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/imports/add-new-file/index.ts index 13b3821c6..51039274c 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/imports/add-new-file/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/imports/add-new-file/index.ts @@ -17,21 +17,33 @@ import * as arkts from "../../../../../src/arkts-api" export function addImportNewFile(program: arkts.Program, options: arkts.CompilationOptions) { if (options.isMainProgram) { - arkts.factory.createETSImportDeclaration( - arkts.factory.createStringLiteral( - './library' - ), - [ - arkts.factory.createImportSpecifier( - arkts.factory.createIdentifier( - 'testFunction' + const module = program.ast as arkts.ETSModule + program.setAst( + arkts.factory.updateETSModule( + module, + [ + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './library' + ), + [ + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'testFunction' + ), + arkts.factory.createIdentifier( + 'testFunction' + ) + ) + ], + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL ), - arkts.factory.createIdentifier( - 'testFunction' - ) - ) - ], - arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL + ...module.statements, + ], + module.ident, + module.getFlag(), + module.program, + ) ) } return program diff --git a/ui2abc/libarkts/test/arkts-api/recheck/imports/add-same-file/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/imports/add-same-file/index.ts index 59e2f607c..ec27c06ae 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/imports/add-same-file/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/imports/add-same-file/index.ts @@ -17,27 +17,33 @@ import * as arkts from "../../../../../src/arkts-api" export function addImportSameFile(program: arkts.Program, options: arkts.CompilationOptions) { if (options.isMainProgram) { - arkts.updateETSModuleByStatements( - program.ast as arkts.ETSModule, - [ - arkts.factory.createETSImportDeclaration( - arkts.factory.createStringLiteral( - './library' - ), - [ - arkts.factory.createImportSpecifier( - arkts.factory.createIdentifier( - 'testFunction' - ), - arkts.factory.createIdentifier( - 'testFunction' + const module = program.ast as arkts.ETSModule + program.setAst( + arkts.factory.updateETSModule( + module, + [ + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './library' + ), + [ + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'testFunction' + ), + arkts.factory.createIdentifier( + 'testFunction' + ) ) - ) - ], - arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL - ), - ...program.ast.statements, - ] + ], + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL + ), + ...module.statements, + ], + module.ident, + module.getFlag(), + module.program, + ) ) } return program diff --git a/ui2abc/libarkts/test/arkts-api/recheck/imports/add-use-same-file/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/imports/add-use-same-file/index.ts index 2ada6671e..8895db3c5 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/imports/add-use-same-file/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/imports/add-use-same-file/index.ts @@ -17,41 +17,43 @@ import * as arkts from "../../../../../src/arkts-api" export function addUseImportSameFile(program: arkts.Program, options: arkts.CompilationOptions) { if (options.isMainProgram) { - arkts.updateETSModuleByStatements( - program.ast as arkts.ETSModule, - [ - ...program.ast.statements, - arkts.factory.createCallExpression( - arkts.factory.createIdentifier("testFunction"), - [], - undefined, - false, - false, - undefined - ) - ] - ) - arkts.updateETSModuleByStatements( - program.ast as arkts.ETSModule, - [ - arkts.factory.createETSImportDeclaration( - arkts.factory.createStringLiteral( - './library' - ), - [ - arkts.factory.createImportSpecifier( - arkts.factory.createIdentifier( - 'testFunction' - ), - arkts.factory.createIdentifier( - 'testFunction' + const module = program.ast as arkts.ETSModule + program.setAst( + arkts.factory.updateETSModule( + module, + [ + arkts.factory.createETSImportDeclaration( + arkts.factory.createStringLiteral( + './library' + ), + [ + arkts.factory.createImportSpecifier( + arkts.factory.createIdentifier( + 'testFunction' + ), + arkts.factory.createIdentifier( + 'testFunction' + ) ) + ], + arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL + ), + ...module.statements, + arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression( + arkts.factory.createIdentifier("testFunction"), + [], + undefined, + false, + false, + undefined ) - ], - arkts.Es2pandaImportKinds.IMPORT_KINDS_ALL - ), - ...program.ast.statements, - ] + ) + ], + module.ident, + module.getFlag(), + module.program, + ) ) } return program diff --git a/ui2abc/libarkts/test/arkts-api/recheck/imports/recursive/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/imports/recursive/index.ts index 5f09c85c3..43a9433ed 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/imports/recursive/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/imports/recursive/index.ts @@ -16,7 +16,7 @@ import * as arkts from "../../../../../src/arkts-api" class InsertParameter extends arkts.AbstractVisitor { - visitor(beforeChildren: arkts.ETSModule): arkts.ETSModule + visitor(beforeChildren: arkts.BlockStatement): arkts.BlockStatement visitor(beforeChildren: arkts.AstNode): arkts.AstNode { const node = this.visitEachChild(beforeChildren) if (arkts.isScriptFunction(node) && @@ -47,5 +47,5 @@ class InsertParameter extends arkts.AbstractVisitor { } export function insertParameter(program: arkts.Program) { - return new InsertParameter().visitor(program.ast as arkts.ETSModule) + program.setAst(new InsertParameter().visitor(program.ast)) } diff --git a/ui2abc/libarkts/test/arkts-api/recheck/optional/add-chain/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/optional/add-chain/index.ts index 7594a46f2..b5aa8a49a 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/optional/add-chain/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/optional/add-chain/index.ts @@ -16,6 +16,7 @@ import * as arkts from "../../../../../src/arkts-api" class AddOptionalChain extends arkts.AbstractVisitor { + visitor(beforeChildren: arkts.BlockStatement): arkts.BlockStatement visitor(beforeChildren: arkts.AstNode): arkts.AstNode { const node = this.visitEachChild(beforeChildren) if (arkts.isVariableDeclarator(node) && arkts.isIdentifier(node.id) && node.id.name == "zzz") { @@ -42,5 +43,5 @@ class AddOptionalChain extends arkts.AbstractVisitor { export function addOptionalChain(program: arkts.Program) { const inserted = new AddOptionalChain().visitor(program.ast) - return new arkts.ChainExpressionFilter().visitor(inserted) + return program.setAst(new arkts.ChainExpressionFilter().visitor(inserted)) } diff --git a/ui2abc/libarkts/test/arkts-api/recheck/overloads/getter-setter/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/overloads/getter-setter/index.ts index 684abade6..f305ebeda 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/overloads/getter-setter/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/overloads/getter-setter/index.ts @@ -16,7 +16,7 @@ import * as arkts from "../../../../../src/arkts-api" class InsertParameterToType extends arkts.AbstractVisitor { - visitor(beforeChildren: arkts.ETSModule): arkts.ETSModule + visitor(beforeChildren: arkts.BlockStatement): arkts.BlockStatement visitor(beforeChildren: arkts.AstNode): arkts.AstNode { const node = this.visitEachChild(beforeChildren) if (arkts.isETSFunctionType(node)) { @@ -42,5 +42,5 @@ class InsertParameterToType extends arkts.AbstractVisitor { } export function insertParameterToType(program: arkts.Program) { - return new InsertParameterToType().visitor(program.ast as arkts.ETSModule) + program.setAst(new InsertParameterToType().visitor(program.ast)) } diff --git a/ui2abc/libarkts/test/arkts-api/recheck/recheck.test.ts b/ui2abc/libarkts/test/arkts-api/recheck/recheck.test.ts index c7ba12987..7949a3fbb 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/recheck.test.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/recheck.test.ts @@ -211,19 +211,19 @@ suite(util.basename(__filename), () => { suite('simple', () => { test('rename class', () => { runTest('simple/rename-class', (program: arkts.Program) => { - return updateTopLevelClass(program.ast as arkts.ETSModule, renameClass) + program.setAst(updateTopLevelClass(program.ast as arkts.ETSModule, renameClass)) }) }) test('add class method', () => { runTest('simple/add-class-method', (program: arkts.Program) => { - return updateTopLevelClass(program.ast as arkts.ETSModule, addClassMethod) + program.setAst(updateTopLevelClass(program.ast as arkts.ETSModule, addClassMethod)) }) }) test('add variable declaration', () => { runTest('simple/add-variable', (program: arkts.Program) => { - return updateTopLevelClass(program.ast as arkts.ETSModule, addVariableDeclaration) + program.setAst(updateTopLevelClass(program.ast as arkts.ETSModule, addVariableDeclaration)) }) }) }) diff --git a/ui2abc/libarkts/test/arkts-api/recheck/simple/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/simple/index.ts index bf6ee92f3..d910728f2 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/simple/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/simple/index.ts @@ -19,7 +19,7 @@ export function updateTopLevelClass( module: arkts.ETSModule, update: (node: arkts.ClassDefinition) => arkts.ClassDefinition ) { - return arkts.updateETSModuleByStatements( + return arkts.factory.updateETSModule( module, [ ...module.statements.map((node) => { @@ -37,6 +37,9 @@ export function updateTopLevelClass( } return node }) - ] + ], + module.ident, + module.getFlag(), + module.program, ) } diff --git a/ui2abc/libarkts/test/arkts-api/recheck/this/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/this/index.ts index d021e8d63..65a35d875 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/this/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/this/index.ts @@ -14,10 +14,9 @@ */ import * as arkts from "../../../../src/arkts-api" -import { ETSModule } from "../../../../src/arkts-api" class AddThisReference extends arkts.AbstractVisitor { - visitor(beforeChildren: arkts.ETSModule): arkts.ETSModule + visitor(beforeChildren: arkts.BlockStatement): arkts.BlockStatement visitor(beforeChildren: arkts.AstNode): arkts.AstNode { const node = this.visitEachChild(beforeChildren) if (arkts.isScriptFunction(node) && node.id?.name == "no_this") { @@ -47,5 +46,5 @@ class AddThisReference extends arkts.AbstractVisitor { } export function addThisReference(program: arkts.Program) { - return new AddThisReference().visitor(program.ast as ETSModule) + program.setAst(new AddThisReference().visitor(program.ast)) } diff --git a/ui2abc/memo-plugin/src/MemoTransformer.ts b/ui2abc/memo-plugin/src/MemoTransformer.ts index d4dd80f77..c0e2efb52 100644 --- a/ui2abc/memo-plugin/src/MemoTransformer.ts +++ b/ui2abc/memo-plugin/src/MemoTransformer.ts @@ -67,18 +67,21 @@ export default function memoTransformer( let result = functionTransformer.visitor(node) if (restart) { if ((functionTransformer.modified || signatureTransformer.modified)) { - result = arkts.updateETSModuleByStatements( + result = arkts.factory.updateETSModule( result, [ factory.createContextTypesImportDeclaration(userPluginOptions?.stableForTests ?? false, userPluginOptions?.contextImport), ...result.statements - ] + ], + result.ident, + result.getFlag(), + result.program, ) } } if (userPluginOptions?.keepTransformed && options.isMainProgram) { dumpAstToFile(result, userPluginOptions.keepTransformed, userPluginOptions?.stableForTests ?? false) } - return result + program.setAst(result) } } diff --git a/ui2abc/memo-plugin/src/ParserTransformer.ts b/ui2abc/memo-plugin/src/ParserTransformer.ts index 9abec3c62..992c7aa8f 100644 --- a/ui2abc/memo-plugin/src/ParserTransformer.ts +++ b/ui2abc/memo-plugin/src/ParserTransformer.ts @@ -52,12 +52,18 @@ export default function memoParserTransformer( return } - return arkts.updateETSModuleByStatements( - program.ast as arkts.ETSModule, - [ - factory.createContextTypesImportDeclaration(userPluginOptions?.stableForTests ?? false, userPluginOptions?.contextImport), - ...program.ast.statements, - ] + const module = program.ast as arkts.ETSModule + program.setAst( + arkts.factory.updateETSModule( + module, + [ + factory.createContextTypesImportDeclaration(userPluginOptions?.stableForTests ?? false, userPluginOptions?.contextImport), + ...module.statements, + ], + module.ident, + module.getFlag(), + module.program, + ) ) } } diff --git a/ui2abc/ui-plugins/src/checked-stage-plugin.ts b/ui2abc/ui-plugins/src/checked-stage-plugin.ts index 1d3f0b45f..b4ad61e03 100644 --- a/ui2abc/ui-plugins/src/checked-stage-plugin.ts +++ b/ui2abc/ui-plugins/src/checked-stage-plugin.ts @@ -29,12 +29,13 @@ export default function checkedTransformer( ): arkts.ProgramTransformer { return (program: arkts.Program, _compilationOptions: arkts.CompilationOptions, context: arkts.PluginContext) => { const structsResolver = context.parameter("structsTable")!; - [ + const result = [ new InstantiateFactoryHelper(), new EtsFirstArgTransformer(), new StyleTransformer(), new BuilderLambdaTransformer(structsResolver) ] .reduce((node: arkts.AstNode, transformer) => transformer.visitor(node), program.ast) + program.setAst(result as arkts.ETSModule) } } diff --git a/ui2abc/ui-plugins/src/component-transformer.ts b/ui2abc/ui-plugins/src/component-transformer.ts index 1452cab61..88313b349 100644 --- a/ui2abc/ui-plugins/src/component-transformer.ts +++ b/ui2abc/ui-plugins/src/component-transformer.ts @@ -76,7 +76,13 @@ export class ComponentTransformer extends arkts.AbstractVisitor { } private rewriteModule(node: arkts.ETSModule): arkts.ETSModule { - return arkts.updateETSModuleByStatements(node, this.transformStatements(node.statements)) + return arkts.factory.updateETSModule( + node, + this.transformStatements(node.statements), + node.ident, + node.getFlag(), + node.program, + ) } private optionsName(clazz: arkts.ClassDefinition): arkts.Identifier { diff --git a/ui2abc/ui-plugins/src/imports-transformer.ts b/ui2abc/ui-plugins/src/imports-transformer.ts index ed75b80cf..a3faa223f 100644 --- a/ui2abc/ui-plugins/src/imports-transformer.ts +++ b/ui2abc/ui-plugins/src/imports-transformer.ts @@ -23,9 +23,12 @@ export class ImportsTransformer extends arkts.AbstractVisitor { visitor(node: arkts.AstNode): arkts.AstNode { if (arkts.isETSModule(node)) { - return arkts.updateETSModuleByStatements( + return arkts.factory.updateETSModule( node, - this.imports.emit(node.statements) + this.imports.emit(node.statements), + node.ident, + node.getFlag(), + node.program, ) } throw new Error(`Must not be there`) diff --git a/ui2abc/ui-plugins/src/parsed-stage-plugin.ts b/ui2abc/ui-plugins/src/parsed-stage-plugin.ts index 037b3c52f..ae08c376e 100644 --- a/ui2abc/ui-plugins/src/parsed-stage-plugin.ts +++ b/ui2abc/ui-plugins/src/parsed-stage-plugin.ts @@ -52,6 +52,7 @@ export default function parsedTransformer( new CallTransformer(importer, userPluginOptions), new ImportsTransformer(importer) ] - transformers.reduce((node: arkts.AstNode, transformer: arkts.AbstractVisitor) => transformer.visitor(node), program.ast) + const result = transformers.reduce((node: arkts.AstNode, transformer: arkts.AbstractVisitor) => transformer.visitor(node), program.ast) + program.setAst(result as arkts.ETSModule) } } -- Gitee From facee99bedd9faf113b1562c9f472c6793cc5d87 Mon Sep 17 00:00:00 2001 From: Igor Loginov Date: Fri, 27 Jun 2025 10:44:43 +0300 Subject: [PATCH 3/8] Drop filters as we work better with AST now --- ui2abc/libarkts/src-host/es2panda.ts | 3 - ui2abc/libarkts/src/utils.ts | 157 --------------------------- 2 files changed, 160 deletions(-) diff --git a/ui2abc/libarkts/src-host/es2panda.ts b/ui2abc/libarkts/src-host/es2panda.ts index a32e540b7..8213e712e 100644 --- a/ui2abc/libarkts/src-host/es2panda.ts +++ b/ui2abc/libarkts/src-host/es2panda.ts @@ -369,8 +369,6 @@ function invokeSimultaneous( compilerConfig.destroy() } -const exportsFromInitialFile: string[] = [] - function generateDeclFromCurrentContext(filePath: string) { proceedToState(Es2pandaContextState.ES2PANDA_STATE_PARSED) console.log(`Emitting to ${filePath}`) @@ -380,7 +378,6 @@ function generateDeclFromCurrentContext(filePath: string) { .visitor(global.compilerContext!.program.ast) .dumpSrc() ), - ...exportsFromInitialFile ].join('\n') fs.mkdirSync(path.dirname(filePath), { recursive: true }) fs.writeFileSync(filePath, out) diff --git a/ui2abc/libarkts/src/utils.ts b/ui2abc/libarkts/src/utils.ts index d7544784c..993df2669 100644 --- a/ui2abc/libarkts/src/utils.ts +++ b/ui2abc/libarkts/src/utils.ts @@ -115,7 +115,6 @@ function replaceGensymWrappers(code: string): string { return code } - function addExports(code: string): string { const exportAstNodes = [" enum", "let", "const", "class", "abstract class", "@Entry() @Component() final class", "@Component() final class", "interface", "@interface", "type", "enum", "final class", "function", "declare interface", "@memo_stable() declare interface", "@memo_stable() interface", @@ -140,162 +139,12 @@ function addExports(code: string): string { return code.replaceAll("\nexport function main()", "\nfunction main()") } -function removeAbstractFromInterfaces(code: string): string { - const interfaces = [...code.matchAll(/interface([\s\S]*?){([\s\S]*?)\n}\n/g)].map(it => it[0]) - interfaces.forEach((content) => { - const newContent = content.replaceAll('abstract ', '') - code = code.replaceAll(content, newContent) - }) - return code -} - -function removeInvalidLambdaTyping(code: string): string { - const knownTypes = ['boolean', 'int64', 'void'] - return code.replaceAll(/\(([^\n\(\)]*?)\): ([\S]*?) => {/g, (match, p1, p2) => { - if (knownTypes.includes(p2)) { - return match - } - return `(${p1}) => {` - }) -} - -function returnOptionalParams(code: string): string { - const reduce = (line: string): string => { - if (line.includes("constructor")) { - return line - } - for (var i = 0; i < line.length; i++) { - if (line[i] == '(') { - let ignore = false - for (var k = i; k >= 0; k--) { - if (line[k].match(/[a-zA-Z<>_0-9]/)) { - break - } - if (line[k] == ':') { - ignore = true - } - } - if (ignore) { - continue - } - const initi = i - let j = i + 1, depth = 1 - let parts: string[] = [] - while (j < line.length) { - if (line[j] == '(') { - depth++ - } - if (line[j] == ')') { - depth-- - if (depth == 0) { - parts.push(line.substring(i + 1, j)) - break - } - } - if (line[j] == ',' && depth == 1) { - parts.push(line.substring(i + 1, j)) - i = j + 1 - } - j++ - } - if (depth == 0 && parts.length && parts.every(it => it.includes(": ") && !it.includes("? "))) { - let k = parts.length - 1 - while (k >= 0) { - if (parts[k].endsWith(" | undefined")) { - let w = parts[k].substring(0, parts[k].length - " | undefined".length) - let i = w.indexOf(':') - if (w[i - 1] != '?') { - parts[k] = w.substring(0, i) + "?" + w.substring(i) - } - } else { - break - } - k-- - } - if (k != parts.length - 1) { - let nline = line.substring(0, initi + 1) + parts.join(', ') + line.substring(j) - return nline - } - } - i = initi - } - } - return line - } - return code.split('\n').map((line) => { - let nline = reduce(line) - while (nline != line) { - line = nline - nline = reduce(line) - } - return line - }).join('\n') -} - -function fixPropertyLines(code: string): string { - /* - - for some properties the following construction is generated: - - private readonly name = false; - - public name(name) { // for readonly properties "setter" is also generated - (this).name = name = false; // sometimes there is a typing here - return; - } - - public name() { - return (this).name; - } - - this function wraps this back to `readonly name = false;` - - */ - return code.replaceAll(/(private|public)(.*)?(.*?)\n((.*?)\n){9}/g, (match, p1, p2, p3) => { - return `public ${p2} ${p3}` - }) -} - -function fixDuplicateSettersInInterfaces(code: string): string { - /* - - sometimes interfaces contains duplicate setters, this functions fixes it - - */ - code = code.replaceAll(/\n[ ]*(.*)interface(.*){\n([\s\S]*?)\n[ ]*}\n/g, (match, modifiers, p1, p2: string) => { - const keep = p2.split('\n').filter((it) => !it.trimStart().startsWith(`set`)) - const setters = [...new Set(p2.split('\n').filter((it) => it.trimStart().startsWith(`set`)))] - return `\n${modifiers}interface${p1}{\n${keep.join('\n')}\n${setters.join('\n')}\n}\n` - }) - return code -} - function excludePartialInterfaces(code: string): string { return code .replaceAll(/export interface (.*)\$partial<>([\s\S]*?)}/g, '') .replaceAll(/interface (.*)\$partial<>([\s\S]*?)}/g, '') } -function fixNamespace(code: string) { - /* - namespaces become abstract classes, and enums become final classes - enum in namespace -> class in class -> not supported - - we have only one such place, so fix manually - */ - code = code.replaceAll(/export (declare )?abstract class (Profiler|GestureControl|text|common2D|common|observer|unifiedDataChannel|uniformTypeDescriptor|drawing|uiEffect|intl|matrix4|image|pointer|promptAction|webview|window) {/g, `export $1 namespace $2 {`) - code = code.replaceAll(`public static _$init$_() {}`, ``) - code = code.replaceAll(`public static _$init$_(): void {}`, ``) - code = code.replaceAll(/.*_\$initializerBlockInit\$_.*/g, ``) - code = code.replaceAll(/public static ((?:un)?registerVsyncCallback)/g, "export function $1") - code = code.replaceAll(/public static (setCursor)/g, "export function $1") - code = code.replaceAll(/public static (restoreDefault)/g, "export function $1") - code = code.replaceAll(/public static (requestFocus\(value)/g, "export function $1") - code = code.replaceAll(/public static (getSystemFontFullNamesByType|getFontDescriptorByFullName|matchFontDescriptors|createEffect|createBrightnessBlender)/g, "export function $1") - code = code.replaceAll('\n type Blender =', '\n export type Blender = ') - return code -} - function fixEnums(code: string) { const lines = code.split('\n') const enums = [] @@ -344,10 +193,7 @@ export function filterSource(text: string): string { // console.error(text.split('\n').map((it, index) => `${`${index + 1}`.padStart(4)} |${it}`).join('\n')) const dumperUnwrappers = [ addExports, - fixNamespace, fixEnums, - fixDuplicateSettersInInterfaces, - removeAbstractFromInterfaces, replaceGensymWrappers, // nested replaceGensymWrappers, // nested replaceGensymWrappers, @@ -356,9 +202,6 @@ export function filterSource(text: string): string { excludePartialInterfaces, (code: string) => code.replaceAll("", "_cctor_"), (code: string) => code.replaceAll("public constructor() {}", ""), - (code: string) => code.replaceAll("@Module()", ""), - (code: string) => code.replaceAll("export * as from", "export * from"), - fixPropertyLines ] // console.error("====") // console.error(dumperUnwrappers.reduceRight((code, f) => f(code), text).split('\n').map((it, index) => `${`${index + 1}`.padStart(4)} |${it}`).join('\n')) -- Gitee From ba6f727bb5e84e1cff4804f8e90946e08e338d4b Mon Sep 17 00:00:00 2001 From: Igor Loginov Date: Fri, 27 Jun 2025 12:21:29 +0300 Subject: [PATCH 4/8] deprecations --- ui2abc/libarkts/src/arkts-api/utilities/public.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ui2abc/libarkts/src/arkts-api/utilities/public.ts b/ui2abc/libarkts/src/arkts-api/utilities/public.ts index 74ff43cc9..df96fda2b 100644 --- a/ui2abc/libarkts/src/arkts-api/utilities/public.ts +++ b/ui2abc/libarkts/src/arkts-api/utilities/public.ts @@ -37,6 +37,11 @@ import { Context } from "../peers/Context" import { NodeCache } from "../node-cache" import { listPrograms } from "../plugins" +/** + * TODO: Replace or remove with better naming + * + * @deprecated + */ export function createETSModuleFromContext(): ETSModule { let program = global.es2panda._ContextProgram(global.context) if (program == nullptr) { @@ -50,6 +55,12 @@ export function createETSModuleFromContext(): ETSModule { return new ETSModule(ast) } +/** + * Now used only in tests + * TODO: Remove or replace with better method + * + * @deprecated + */ export function createETSModuleFromSource( source: string, state: Es2pandaContextState = Es2pandaContextState.ES2PANDA_STATE_PARSED, -- Gitee From 9bd2aaf1455838beb51cb68dd2fdd25a1eceb764 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Wed, 25 Jun 2025 19:10:07 +0300 Subject: [PATCH 5/8] two way dependency support with binary search --- incremental/runtime/src/states/Dependency.ts | 258 +++++++++++++++--- incremental/runtime/src/states/State.ts | 75 ++--- .../runtime/test-arkts/states/State.test.ts | 43 +++ incremental/runtime/test/states/State.test.ts | 43 +++ 4 files changed, 343 insertions(+), 76 deletions(-) diff --git a/incremental/runtime/src/states/Dependency.ts b/incremental/runtime/src/states/Dependency.ts index 5d62e2457..9bc5206d5 100644 --- a/incremental/runtime/src/states/Dependency.ts +++ b/incremental/runtime/src/states/Dependency.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 Huawei Device Co., Ltd. + * Copyright (c) 2022-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,24 +13,31 @@ * limitations under the License. */ -const SKIP_FRAMES = 10 +import { int32 } from "@koalaui/common" + +type ID = int32 +let UID: ID = 0 + +interface Identifiable { + readonly id: ID +} /** This interface represents an unique observer that can be notified that some changes. */ export interface Dependency { - /** Returns `true` if the dependency is no longer actual. */ - readonly obsolete: boolean - - /** Notifies the dependency that it should be invalidated. */ - invalidate(): void + /** Returns dependencies to all used states. */ + readonly states: ScopeToStates | undefined } -/** This class allows to store and update all dependencies. */ -export class Dependencies { - private frame = 0 - private dependencies: Array | undefined = undefined - private latest: Dependency | undefined = undefined +/** This class is intended to store dependencies to all scopes. */ +export class StateToScopes implements Identifiable { + private readonly uid: ID = ++UID + private dependencies: Array | undefined = undefined + private latest: ScopeToStates | undefined = undefined + + get id(): ID { + return this.uid + } - /** Returns `true` if there are no dependencies to invalidate. */ get empty(): boolean { const dependencies = this.dependencies return dependencies @@ -38,57 +45,218 @@ export class Dependencies { : (this.latest === undefined) } - /** @param dependency - a dependency to invalidate */ - register(dependency?: Dependency): void { - if (dependency === undefined || dependency == this.latest || dependency.obsolete) return + /** @param dependency - a dependency to add */ + add(dependency: ScopeToStates) { + const latest = this.latest + if (latest === dependency) return // already added + this.latest = dependency + let dependencies = this.dependencies if (dependencies) { - // Array includes repeated elements, they will be processed in updateDependencies - dependencies.push(dependency) + const index = find(dependencies, dependency.id) + if (!found(dependencies, dependency.id, index)) { + dependencies.splice(index, 0, dependency) + } + } else if (latest) { + dependencies = new Array() + dependencies.push(latest) + dependencies.splice(find(dependencies, dependency.id), 0, dependency) + this.dependencies = dependencies + } + } + + /** @param dependency - a dependency to remove */ + remove(dependency: ScopeToStates) { + const dependencies = this.dependencies + if (dependencies) { + const index = find(dependencies, dependency.id) + if (found(dependencies, dependency.id, index)) { + dependencies.splice(index, 1) + } + } + if (this.latest === dependency) { + this.latest = undefined + } + } + + /** Removes all dependecies. */ + clear() { + const dependencies = this.dependencies + if (dependencies) { + this.dependencies = undefined + this.latest = undefined + let index = dependencies.length + while (0 < index--) { + dependencies[index].remove(this) + } } else { const latest = this.latest if (latest) { - dependencies = new Array() - dependencies.push(latest) - dependencies.push(dependency) - this.dependencies = dependencies + latest.remove(this) + this.latest = undefined } } - this.latest = dependency } - /** Invalidates all dependencies and removes obsolete ones. */ - updateDependencies(invalidate: boolean, modifiedTrackedScopes?: ReadonlySet): void { - if (++this.frame < SKIP_FRAMES && !invalidate) return - this.frame = 0 + /** Iterates through all dependecies and invalidates them. */ + invalidate() { + const dependencies = this.dependencies + if (dependencies) { + let index = dependencies.length + while (0 < index--) { + dependencies[index].invalidate() + } + } else { + const latest = this.latest + if (latest) { + latest.invalidate() + } + } + } + + /** @param dependency - a dependency to register */ + register(dependency?: Dependency) { + const that = dependency?.states + if (that) { + this.add(that) + that.add(this) + } + } +} + +/** This class is intended to store dependencies to all used states. */ +export class ScopeToStates implements Identifiable { + private readonly uid: ID = ++UID + private marker: boolean = false + private dependencies: Array> | undefined = undefined + private latest: MarkableEntry | undefined = undefined + + readonly invalidate: () => void + + constructor(invalidate: () => void) { + this.invalidate = invalidate + } + + get id(): ID { + return this.uid + } + + /** @param dependency - a dependency to add */ + add(dependency: StateToScopes) { + const latest = this.latest + if (latest && latest.dependency === dependency) { + latest.marker = this.marker + return // already added + } + let dependencies = this.dependencies + if (dependencies) { + const index = find(dependencies, dependency.id) + if (found(dependencies, dependency.id, index)) { + dependencies[index].marker = this.marker + } else { + dependencies.splice(index, 0, entry(dependency, this.marker)) + } + this.latest = dependencies[index] + } else if (latest) { + dependencies = new Array> + dependencies.push(latest) + dependencies.splice(find(dependencies, dependency.id), 0, entry(dependency, this.marker)) + this.dependencies = dependencies + + } else { + this.latest = entry(dependency, this.marker) + } + } + + /** @param dependency - a dependency to remove */ + remove(dependency: StateToScopes) { + const dependencies = this.dependencies + if (dependencies) { + const index = find(dependencies, dependency.id) + if (found(dependencies, dependency.id, index)) { + dependencies.splice(index, 1) + } + } + if (this.latest?.dependency === dependency) { + this.latest = undefined + } + } + + /** Removes all dependecies. */ + clear() { const dependencies = this.dependencies if (dependencies) { - let dependenciesSet = new Set(dependencies); - this.dependencies = []; - const newDependencies = this.dependencies; - if (newDependencies) { - dependenciesSet.forEach((dependency: Dependency) => { - if (updateDependency(invalidate, dependency, modifiedTrackedScopes)) { - newDependencies.push(dependency); - } - }); + this.dependencies = undefined + this.latest = undefined + let index = dependencies.length + while (0 < index--) { + dependencies[index].dependency.remove(this) } } else { const latest = this.latest - if (latest !== undefined && !updateDependency(invalidate, latest, modifiedTrackedScopes)) { + if (latest) { + this.latest = undefined + latest.dependency.remove(this) + } + } + } + + /** Removes all dependecies, which were not used since previous call. */ + reset() { + const marker = !this.marker + this.marker = marker + const dependencies = this.dependencies + if (dependencies) { + this.latest = undefined + let index = dependencies.length + while (0 < index--) { + const element = dependencies[index] + if (element.marker == marker) { + element.dependency.remove(this) + dependencies.splice(index, 1) + } + } + } else { + const latest = this.latest + if (latest && (latest.marker == marker)) { this.latest = undefined + latest.dependency.remove(this) } } } } -function updateDependency(invalidate: boolean, - dependency: Dependency, - modifiedTrackedScopes?: ReadonlySet): boolean { - if (modifiedTrackedScopes && !modifiedTrackedScopes.has(dependency)) { - return false +class MarkableEntry implements Identifiable { + readonly dependency: T + marker: boolean + constructor(dependency: T, marker: boolean) { + this.dependency = dependency + this.marker = marker + } + get id(): ID { + return this.dependency.id + } +} + +function entry(dependency: T, marker: boolean): MarkableEntry { + return new MarkableEntry(dependency, marker) +} + +function found(array: Array, id: ID, index: number): T | undefined { + if (index < array.length) { + const element = array[index] + if (element.id == id) return element + } + return undefined +} + +function find(array: Array, id: ID): number { + let left = 0 + let right = array.length + while (left < right) { + const center = ((left + right) >>> 1) as int32 + if (array[center].id < id) left = center + 1 + else right = center } - if (dependency.obsolete) return false - if (invalidate) dependency.invalidate() - return true + return left } diff --git a/incremental/runtime/src/states/State.ts b/incremental/runtime/src/states/State.ts index fbc4632d2..2b1b5b0a3 100644 --- a/incremental/runtime/src/states/State.ts +++ b/incremental/runtime/src/states/State.ts @@ -14,7 +14,7 @@ */ import { Array_from_set, className, float64ToInt, int32, KoalaCallsiteKey, KoalaCallsiteKeys, KoalaProfiler, MarkableQueue, markableQueue, Observable, ObservableHandler, refEqual, uint32 } from "@koalaui/common" -import { Dependencies, Dependency } from "./Dependency" +import { Dependency, ScopeToStates, StateToScopes } from "./Dependency" import { Disposable, disposeContent, disposeContentBackward } from "./Disposable" import { Changes, Journal } from "./Journal" import { IncrementalNode } from "../tree/IncrementalNode" @@ -226,7 +226,7 @@ interface ManagedScope extends Disposable, Dependency, ReadonlyTreeNode { class StateImpl implements Observable, ManagedState, MutableState { protected manager: StateManagerImpl | undefined = undefined - private dependencies: Dependencies | undefined = undefined + private dependencies: StateToScopes | undefined = undefined protected snapshot: Value protected myModified: boolean = false protected myUpdated: boolean = true @@ -250,7 +250,7 @@ class StateImpl implements Observable, ManagedState, MutableState this.tracker = tracker this.name = name this.manager = manager - this.dependencies = new Dependencies() + this.dependencies = new StateToScopes() this.snapshot = initial ObservableHandler.attach(initial, this) manager.addCreatedState(this) @@ -287,7 +287,7 @@ class StateImpl implements Observable, ManagedState, MutableState onAccess(propertyName?: string): void { const dependency = this.manager?.dependency - if (propertyName && !this.disposed) { + if (dependency && propertyName) { this.trackedScopes.register(propertyName, dependency) } this.dependencies?.register(dependency) @@ -330,7 +330,7 @@ class StateImpl implements Observable, ManagedState, MutableState this.applyStateSnapshot(this.current(changes)) this.myUpdated = true } - this.dependencies?.updateDependencies(this.myModified, modifiedTrackedScopes) + if (this.myModified) this.dependencies?.invalidate() } protected applyStateSnapshot(newValue: Value) { @@ -356,6 +356,7 @@ class StateImpl implements Observable, ManagedState, MutableState manager.checkForStateDisposing() this.manager = undefined this.tracker = undefined + this.dependencies?.clear() this.dependencies = undefined manager.removeCreatedState(this, this.name) this.trackedScopes.clear() @@ -463,7 +464,7 @@ class ArrayStateImpl extends StateImpl> implements ArrayState< class ParameterImpl implements MutableState { private manager: StateManagerImpl | undefined = undefined - private dependencies: Dependencies | undefined = undefined + private dependencies: StateToScopes | undefined = undefined private name: string | undefined = undefined private _value: Value private _modified: boolean = false @@ -475,7 +476,7 @@ class ParameterImpl implements MutableState { */ constructor(manager: StateManagerImpl, value: Value, name?: string) { this.manager = manager - this.dependencies = new Dependencies() + this.dependencies = new StateToScopes() this.name = name this._value = value } @@ -502,7 +503,7 @@ class ParameterImpl implements MutableState { } else { this._modified = isModified } - this.dependencies?.updateDependencies(this._modified) + if (this._modified) this.dependencies?.invalidate() } get disposed(): boolean { @@ -514,6 +515,7 @@ class ParameterImpl implements MutableState { if (manager === undefined) return // already disposed manager.checkForStateDisposing() this.manager = undefined + this.dependencies?.clear() this.dependencies = undefined } @@ -617,7 +619,7 @@ class StateManagerImpl implements StateManager { scope.manager = this scope.node = node scope.nodeRef = node - scope.dependencies = new Dependencies() + scope.dependencies = new StateToScopes() scope.setNamedState(CONTEXT_ROOT_SCOPE, new StateImpl>(this, scope, false)) scope.setNamedState(CONTEXT_ROOT_NODE, new StateImpl(this, node, false)) return scope @@ -630,7 +632,7 @@ class StateManagerImpl implements StateManager { cleanup?.(this, value) }) scope.manager = this - scope.dependencies = new Dependencies() + scope.dependencies = new StateToScopes() this.current?.addCreatedState(scope) return scope } @@ -797,7 +799,8 @@ class StateManagerImpl implements StateManager { class ScopeImpl implements ManagedScope, InternalScope, ComputableState { recomputeNeeded: boolean = true manager: StateManagerImpl | undefined = undefined - dependencies: Dependencies | undefined = undefined + dependencies: StateToScopes | undefined = undefined + private _states: ScopeToStates | undefined private myCompute: (() => Value) | undefined = undefined private myCleanup: ((value: Value | undefined) => void) | undefined = undefined @@ -825,7 +828,14 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable // Constructor with (compute?: () => Value, cleanup?: (value: Value | undefined) => void) // signature causes es2panda recheck crash, so I have introduced a create - private constructor() {} + private constructor() { + this._states = new ScopeToStates(() => { this.invalidate() }) + } + + get states(): ScopeToStates | undefined { + return this._states + } + static create(id: KoalaCallsiteKey, paramCount: int32, compute?: () => V, cleanup?: (value: V | undefined) => void, reuseKey?: string): ScopeImpl { const instance = new ScopeImpl() instance._id = id // special type to distinguish scopes @@ -978,6 +988,7 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable } get unchanged(): boolean { + if (!this.parentScope) this.dependencies?.register(this.manager?.dependency) if (this.recomputeNeeded) { this.incremental = undefined this.nodeCount = 0 @@ -995,7 +1006,10 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable recache(newValue?: Value): Value { const manager = this.manager - if (manager) manager.current = this.scopeInternal + if (manager) { + manager.current = this.scopeInternal + this._states?.reset() + } const oldValue = this.myValue this.myValue = newValue this.myModified = this.myComputed && !refEqual(newValue, oldValue) @@ -1004,12 +1018,11 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable this.detachChildScopes() this.parent?.increment(this.node ? 1 : this.nodeCount, false) this.node?.incrementalUpdateDone(this.parent?.nodeRef) + if (this.myModified && this.parentScope === undefined) this.dependencies?.invalidate() return this.cached } get cached(): Value { - this.dependencies?.register(this.manager?.dependency) - this.dependencies?.updateDependencies(this.myModified) return this.myValue as Value } @@ -1033,15 +1046,11 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable get modified(): boolean { if (this.recomputeNeeded) this.value - else this.dependencies?.register(this.manager?.dependency) + else if (!this.parentScope) this.dependencies?.register(this.manager?.dependency) return this.myModified } - get obsolete(): boolean { - return this.manager === undefined - } - - invalidate(): void { + private invalidate() { const current = this.manager?.current // parameters can update snapshot during recomposition let scope: ManagedScope = this while (true) { @@ -1071,7 +1080,7 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable // TEMP: explicit compares to avoid compiler bug const recycled = child.reuseKey !== undefined && this._nodeRef?.recycle(child.reuseKey!!, child, child.id) == true if (recycled) { - // if parent node is also disposed, the recycled scopes would dispose in the ReusablePool + // if parent node is also disposed, the recycled scopes would dispose in the ReusablePool if (!child.node) throw Error("reusable scope doesn't have a node") child.node!.detach() } else { @@ -1089,6 +1098,9 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable manager.checkForStateDisposing() let error: Error | undefined = undefined this.manager = undefined + this._states?.clear() + this._states = undefined + this.dependencies?.clear() this.dependencies = undefined const scope = manager.current manager.current = this @@ -1141,23 +1153,23 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable class ControlledScopeImpl implements Dependency, ControlledScope { private manager: StateManagerImpl | undefined private old: Dependency | undefined = undefined - private readonly _invalidate: () => void + private _states: ScopeToStates | undefined constructor(manager: StateManagerImpl, invalidate: () => void) { this.manager = manager - this._invalidate = invalidate + this._states = new ScopeToStates(invalidate) } - invalidate(): void { - this._invalidate() + get states(): ScopeToStates | undefined { + return this._states } static cleanup(scope?: ControlledScopeImpl): void { - if (scope) scope.manager = undefined - } - - get obsolete(): boolean { - return this.manager === undefined + if (scope) { + scope.manager = undefined + scope._states?.clear() + scope._states = undefined + } } enter(): void { @@ -1173,6 +1185,7 @@ class ControlledScopeImpl implements Dependency, ControlledScope { if (manager.external !== this) throw new Error("ControlledScope is not valid") manager.external = this.old this.old = undefined + this._states?.reset() } } diff --git a/incremental/runtime/test-arkts/states/State.test.ts b/incremental/runtime/test-arkts/states/State.test.ts index 6a33d17c7..58e065f61 100644 --- a/incremental/runtime/test-arkts/states/State.test.ts +++ b/incremental/runtime/test-arkts/states/State.test.ts @@ -903,6 +903,49 @@ suite("State", () => { Assert.equal(computableCounter, 2) // computable is not recomputed Assert.equal(stateCounter, 2) // state is recomputed by request but it is not modified }) + test("do not recompute by state if it was not used during last computation", () => { + const manager = createStateManager() + const stateB = manager.mutableState(true) + const stateT = manager.mutableState(1) + const stateF = manager.mutableState(2) + const computing = new Array() + const computable = manager.computableState(() => { + computing.push("recomputed") + return stateB.value ? stateT.value : stateF.value + }) + // initial computation + Assert.equal(computable.value, 1) + assertStringsAndCleanup(computing, "recomputed") + // do not recompute if nothing changed + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(computable.value, 1) + Assert.isEmpty(computing) + // recompute if used stateT changed + stateT.value = -1 + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(computable.value, -1) + assertStringsAndCleanup(computing, "recomputed") + // do not recompute if stateF changed + stateF.value = -2 + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(computable.value, -1) + Assert.isEmpty(computing) + // switch flag and recompute + stateB.value = false + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(computable.value, -2) + assertStringsAndCleanup(computing, "recomputed") + // recompute if used stateF changed + stateF.value = 2 + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(computable.value, 2) + assertStringsAndCleanup(computing, "recomputed") + // do not recompute if stateT changed + stateT.value = 1 + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(computable.value, 2) + Assert.isEmpty(computing) + }) test("build and update simple tree", () => { let manager = createStateManager() let count = manager.mutableState(30) diff --git a/incremental/runtime/test/states/State.test.ts b/incremental/runtime/test/states/State.test.ts index ab06e7ffb..038ae7786 100644 --- a/incremental/runtime/test/states/State.test.ts +++ b/incremental/runtime/test/states/State.test.ts @@ -932,6 +932,49 @@ suite("State", () => { assert.equal(computableCounter, 2) // computable is not recomputed assert.equal(stateCounter, 2) // state is recomputed by request but it is not modified }) + test("do not recompute by state if it was not used during last computation", () => { + const manager = createStateManager() + const stateB = manager.mutableState(true) + const stateT = manager.mutableState(1) + const stateF = manager.mutableState(2) + const computing = new Array() + const computable = manager.computableState(() => { + computing.push("recomputed") + return stateB.value ? stateT.value : stateF.value + }) + // initial computation + assertState(computable, 1) + assertStringsAndCleanup(computing, "recomputed") + // do not recompute if nothing changed + assert.equal(testUpdate(false, manager), 0) + assert.equal(computable.value, 1) + assert.isEmpty(computing) + // recompute if used stateT changed + stateT.value = -1 + assert.equal(testUpdate(false, manager), 1) + assert.equal(computable.value, -1) + assertStringsAndCleanup(computing, "recomputed") + // do not recompute if stateF changed + stateF.value = -2 + assert.equal(testUpdate(false, manager), 1) + assert.equal(computable.value, -1) + assert.isEmpty(computing) + // switch flag and recompute + stateB.value = false + assert.equal(testUpdate(false, manager), 1) + assert.equal(computable.value, -2) + assertStringsAndCleanup(computing, "recomputed") + // recompute if used stateF changed + stateF.value = 2 + assert.equal(testUpdate(false, manager), 1) + assert.equal(computable.value, 2) + assertStringsAndCleanup(computing, "recomputed") + // do not recompute if stateT changed + stateT.value = 1 + assert.equal(testUpdate(false, manager), 1) + assert.equal(computable.value, 2) + assert.isEmpty(computing) + }) test("build and update simple tree", () => { let manager = createStateManager() let count = manager.mutableState(30) -- Gitee From 2cf4d9bb6371e346070b174bb7fd22bcfda07ebc Mon Sep 17 00:00:00 2001 From: Igor Loginov Date: Fri, 27 Jun 2025 16:48:51 +0300 Subject: [PATCH 6/8] Rename get flag --- ui2abc/libarkts/generator/options.json5 | 4 ++-- ui2abc/libarkts/src/arkts-api/ImportStorage.ts | 2 +- ui2abc/libarkts/src/arkts-api/node-utilities/ETSModule.ts | 2 +- ui2abc/libarkts/src/arkts-api/utilities/extensions.ts | 2 +- ui2abc/libarkts/src/arkts-api/visitor.ts | 2 +- ui2abc/libarkts/src/generated/peers/ETSModule.ts | 4 ++-- ui2abc/libarkts/src/reexport-for-generated.ts | 2 +- .../test/arkts-api/expressions/call-expression.test.ts | 2 +- ui2abc/libarkts/test/arkts-api/functions/create.test.ts | 4 ++-- ui2abc/libarkts/test/arkts-api/general/basic.test.ts | 2 +- ui2abc/libarkts/test/arkts-api/general/recheck.test.ts | 4 ++-- .../libarkts/test/arkts-api/import-export/import.test.ts | 8 ++++---- .../test/arkts-api/recheck/exports/add-export/index.ts | 2 +- .../test/arkts-api/recheck/exports/basic/index.ts | 2 +- .../test/arkts-api/recheck/exports/create-class/index.ts | 4 ++-- .../arkts-api/recheck/exports/struct-to-class/index.ts | 2 +- .../test/arkts-api/recheck/imports/add-new-file/index.ts | 2 +- .../test/arkts-api/recheck/imports/add-same-file/index.ts | 2 +- .../arkts-api/recheck/imports/add-use-same-file/index.ts | 2 +- ui2abc/libarkts/test/arkts-api/recheck/simple/index.ts | 2 +- ui2abc/memo-plugin/src/MemoTransformer.ts | 2 +- ui2abc/memo-plugin/src/ParserTransformer.ts | 2 +- ui2abc/ui-plugins/src/component-transformer.ts | 2 +- ui2abc/ui-plugins/src/imports-transformer.ts | 2 +- 24 files changed, 32 insertions(+), 32 deletions(-) diff --git a/ui2abc/libarkts/generator/options.json5 b/ui2abc/libarkts/generator/options.json5 index 9892bb886..80bd512f7 100644 --- a/ui2abc/libarkts/generator/options.json5 +++ b/ui2abc/libarkts/generator/options.json5 @@ -273,8 +273,8 @@ interface: "ETSModule", methods: [ { - name: "getFlag", - definition: "extension_ETSModuleGetFlag", + name: "getNamespaceFlag", + definition: "extension_ETSModuleGetNamespaceFlag", } ] } diff --git a/ui2abc/libarkts/src/arkts-api/ImportStorage.ts b/ui2abc/libarkts/src/arkts-api/ImportStorage.ts index cd7172cb0..f5cfa3272 100644 --- a/ui2abc/libarkts/src/arkts-api/ImportStorage.ts +++ b/ui2abc/libarkts/src/arkts-api/ImportStorage.ts @@ -76,7 +76,7 @@ export class ImportStorage { module, newStatements, module.ident, - module.getFlag(), + module.getNamespaceFlag(), module.program, ) ) diff --git a/ui2abc/libarkts/src/arkts-api/node-utilities/ETSModule.ts b/ui2abc/libarkts/src/arkts-api/node-utilities/ETSModule.ts index f38127f74..c875efab0 100644 --- a/ui2abc/libarkts/src/arkts-api/node-utilities/ETSModule.ts +++ b/ui2abc/libarkts/src/arkts-api/node-utilities/ETSModule.ts @@ -27,7 +27,7 @@ export function updateETSModule( ) { if (isSameNativeObject(statementList, original.statements) && isSameNativeObject(ident, original.ident) - && isSameNativeObject(flag, original.getFlag()) + && isSameNativeObject(flag, original.getNamespaceFlag()) && isSameNativeObject(program, original.program) ) { return original diff --git a/ui2abc/libarkts/src/arkts-api/utilities/extensions.ts b/ui2abc/libarkts/src/arkts-api/utilities/extensions.ts index c1b02cbcd..e0f421fe5 100644 --- a/ui2abc/libarkts/src/arkts-api/utilities/extensions.ts +++ b/ui2abc/libarkts/src/arkts-api/utilities/extensions.ts @@ -20,7 +20,7 @@ import type { import { Es2pandaModuleFlag } from "../../generated/Es2pandaEnums" import { global } from "../../reexport-for-generated" -export function extension_ETSModuleGetFlag(this: ETSModule): Es2pandaModuleFlag { +export function extension_ETSModuleGetNamespaceFlag(this: ETSModule): Es2pandaModuleFlag { return (this.isETSScript ? Es2pandaModuleFlag.MODULE_FLAG_ETSSCRIPT : 0) + (this.isNamespace ? Es2pandaModuleFlag.MODULE_FLAG_NAMESPACE : 0) + (this.isNamespaceChainLastNode ? Es2pandaModuleFlag.MODULE_FLAG_NAMESPACE_CHAIN_LAST_NODE : 0) diff --git a/ui2abc/libarkts/src/arkts-api/visitor.ts b/ui2abc/libarkts/src/arkts-api/visitor.ts index a02895343..bf91de16b 100644 --- a/ui2abc/libarkts/src/arkts-api/visitor.ts +++ b/ui2abc/libarkts/src/arkts-api/visitor.ts @@ -150,7 +150,7 @@ export function visitEachChild( node, nodesVisitor(node.statements, visitor), nodeVisitor(node.ident, visitor), - node.getFlag(), + node.getNamespaceFlag(), node.program, ) } diff --git a/ui2abc/libarkts/src/generated/peers/ETSModule.ts b/ui2abc/libarkts/src/generated/peers/ETSModule.ts index 13007aea5..f41254c6f 100644 --- a/ui2abc/libarkts/src/generated/peers/ETSModule.ts +++ b/ui2abc/libarkts/src/generated/peers/ETSModule.ts @@ -41,7 +41,7 @@ import { Es2pandaModuleFlag } from "./../Es2pandaEnums" import { Identifier } from "./Identifier" import { Program } from "./Program" import { Statement } from "./Statement" -import { extension_ETSModuleGetFlag } from "./../../reexport-for-generated" +import { extension_ETSModuleGetNamespaceFlag } from "./../../reexport-for-generated" export class ETSModule extends BlockStatement { constructor(pointer: KNativePointer) { @@ -122,7 +122,7 @@ export class ETSModule extends BlockStatement { global.generatedEs2panda._ETSModuleAddAnnotations(global.context, this.peer, passNode(annotations)) return this } - getFlag = extension_ETSModuleGetFlag + getNamespaceFlag = extension_ETSModuleGetNamespaceFlag protected readonly brandETSModule: undefined } export function isETSModule(node: object | undefined): node is ETSModule { diff --git a/ui2abc/libarkts/src/reexport-for-generated.ts b/ui2abc/libarkts/src/reexport-for-generated.ts index ab5d8492a..22b9296eb 100644 --- a/ui2abc/libarkts/src/reexport-for-generated.ts +++ b/ui2abc/libarkts/src/reexport-for-generated.ts @@ -32,7 +32,7 @@ export { nodeByType } from "./arkts-api/class-by-peer" export { global } from "./arkts-api/static/global" export { Es2pandaMemberExpressionKind } from "./generated/Es2pandaEnums" export { - extension_ETSModuleGetFlag, + extension_ETSModuleGetNamespaceFlag, extension_MethodDefinitionOnUpdate, extension_MethodDefinitionSetChildrenParentPtr, } from "./arkts-api/utilities/extensions" diff --git a/ui2abc/libarkts/test/arkts-api/expressions/call-expression.test.ts b/ui2abc/libarkts/test/arkts-api/expressions/call-expression.test.ts index 23b13f1a8..4e3a6005f 100644 --- a/ui2abc/libarkts/test/arkts-api/expressions/call-expression.test.ts +++ b/ui2abc/libarkts/test/arkts-api/expressions/call-expression.test.ts @@ -58,7 +58,7 @@ suite(util.basename(__filename), () => { ) ], script.ident, - script.getFlag(), + script.getNamespaceFlag(), script.program, ) diff --git a/ui2abc/libarkts/test/arkts-api/functions/create.test.ts b/ui2abc/libarkts/test/arkts-api/functions/create.test.ts index d7e5fe18c..bc2fdaa9c 100644 --- a/ui2abc/libarkts/test/arkts-api/functions/create.test.ts +++ b/ui2abc/libarkts/test/arkts-api/functions/create.test.ts @@ -96,7 +96,7 @@ suite(util.basename(__filename), () => { ) ], script.ident, - script.getFlag(), + script.getNamespaceFlag(), script.program, ) @@ -238,7 +238,7 @@ suite(util.basename(__filename), () => { ) ], script.ident, - script.getFlag(), + script.getNamespaceFlag(), script.program, ) diff --git a/ui2abc/libarkts/test/arkts-api/general/basic.test.ts b/ui2abc/libarkts/test/arkts-api/general/basic.test.ts index 0368ef02e..e76d7c4bb 100644 --- a/ui2abc/libarkts/test/arkts-api/general/basic.test.ts +++ b/ui2abc/libarkts/test/arkts-api/general/basic.test.ts @@ -34,7 +34,7 @@ suite(util.basename(__filename), () => { ) ], script.ident, - script.getFlag(), + script.getNamespaceFlag(), script.program, ) diff --git a/ui2abc/libarkts/test/arkts-api/general/recheck.test.ts b/ui2abc/libarkts/test/arkts-api/general/recheck.test.ts index 3591ddc9e..36fe47183 100644 --- a/ui2abc/libarkts/test/arkts-api/general/recheck.test.ts +++ b/ui2abc/libarkts/test/arkts-api/general/recheck.test.ts @@ -89,7 +89,7 @@ suite(util.basename(__filename), () => { ...module.statements, ], module.ident, - module.getFlag(), + module.getNamespaceFlag(), module.program, ) ) @@ -161,7 +161,7 @@ console.log("test"); ...module.statements.slice(1), ], module.ident, - module.getFlag(), + module.getNamespaceFlag(), module.program, ) ) diff --git a/ui2abc/libarkts/test/arkts-api/import-export/import.test.ts b/ui2abc/libarkts/test/arkts-api/import-export/import.test.ts index 4cdb7ace2..f79f6ea8d 100644 --- a/ui2abc/libarkts/test/arkts-api/import-export/import.test.ts +++ b/ui2abc/libarkts/test/arkts-api/import-export/import.test.ts @@ -47,7 +47,7 @@ suite(util.basename(__filename), () => { ) ], script.ident, - script.getFlag(), + script.getNamespaceFlag(), script.program, ) @@ -91,7 +91,7 @@ suite(util.basename(__filename), () => { ...script.statements, ], script.ident, - script.getFlag(), + script.getNamespaceFlag(), script.program, ) @@ -140,7 +140,7 @@ suite(util.basename(__filename), () => { ...script.statements, ], script.ident, - script.getFlag(), + script.getNamespaceFlag(), script.program, ) @@ -216,7 +216,7 @@ suite(util.basename(__filename), () => { newFuncDecl ], script.ident, - script.getFlag(), + script.getNamespaceFlag(), script.program, ) diff --git a/ui2abc/libarkts/test/arkts-api/recheck/exports/add-export/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/exports/add-export/index.ts index ca2df6cd5..61f8b09c3 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/exports/add-export/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/exports/add-export/index.ts @@ -84,7 +84,7 @@ export function addUseImportClassSameFileAndExportClass(program: arkts.Program, ) ], module.ident, - module.getFlag(), + module.getNamespaceFlag(), module.program, ) ) diff --git a/ui2abc/libarkts/test/arkts-api/recheck/exports/basic/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/exports/basic/index.ts index 78af8a9ed..5dd16e1b8 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/exports/basic/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/exports/basic/index.ts @@ -73,7 +73,7 @@ export function addUseImportClassSameFile(program: arkts.Program, options: arkts ) ], module.ident, - module.getFlag(), + module.getNamespaceFlag(), module.program, ) ) diff --git a/ui2abc/libarkts/test/arkts-api/recheck/exports/create-class/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/exports/create-class/index.ts index e63ecb777..ad9b79316 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/exports/create-class/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/exports/create-class/index.ts @@ -73,7 +73,7 @@ export function addUseImportClassSameFileAndCreateClass(program: arkts.Program, ) ], module.ident, - module.getFlag(), + module.getNamespaceFlag(), module.program, ) ) @@ -126,7 +126,7 @@ export function addUseImportClassSameFileAndCreateClass(program: arkts.Program, ) ], module.ident, - module.getFlag(), + module.getNamespaceFlag(), module.program, ) ) diff --git a/ui2abc/libarkts/test/arkts-api/recheck/exports/struct-to-class/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/exports/struct-to-class/index.ts index c6eea84ef..6b1ef41e4 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/exports/struct-to-class/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/exports/struct-to-class/index.ts @@ -104,7 +104,7 @@ export function addUseImportClassSameFileAfterRewritingStructToClass(program: ar ) ], module.ident, - module.getFlag(), + module.getNamespaceFlag(), module.program, ) ) diff --git a/ui2abc/libarkts/test/arkts-api/recheck/imports/add-new-file/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/imports/add-new-file/index.ts index 51039274c..6c9e31fa1 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/imports/add-new-file/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/imports/add-new-file/index.ts @@ -41,7 +41,7 @@ export function addImportNewFile(program: arkts.Program, options: arkts.Compilat ...module.statements, ], module.ident, - module.getFlag(), + module.getNamespaceFlag(), module.program, ) ) diff --git a/ui2abc/libarkts/test/arkts-api/recheck/imports/add-same-file/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/imports/add-same-file/index.ts index ec27c06ae..773887453 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/imports/add-same-file/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/imports/add-same-file/index.ts @@ -41,7 +41,7 @@ export function addImportSameFile(program: arkts.Program, options: arkts.Compila ...module.statements, ], module.ident, - module.getFlag(), + module.getNamespaceFlag(), module.program, ) ) diff --git a/ui2abc/libarkts/test/arkts-api/recheck/imports/add-use-same-file/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/imports/add-use-same-file/index.ts index 8895db3c5..1085785d5 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/imports/add-use-same-file/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/imports/add-use-same-file/index.ts @@ -51,7 +51,7 @@ export function addUseImportSameFile(program: arkts.Program, options: arkts.Comp ) ], module.ident, - module.getFlag(), + module.getNamespaceFlag(), module.program, ) ) diff --git a/ui2abc/libarkts/test/arkts-api/recheck/simple/index.ts b/ui2abc/libarkts/test/arkts-api/recheck/simple/index.ts index d910728f2..1966eff8e 100644 --- a/ui2abc/libarkts/test/arkts-api/recheck/simple/index.ts +++ b/ui2abc/libarkts/test/arkts-api/recheck/simple/index.ts @@ -39,7 +39,7 @@ export function updateTopLevelClass( }) ], module.ident, - module.getFlag(), + module.getNamespaceFlag(), module.program, ) } diff --git a/ui2abc/memo-plugin/src/MemoTransformer.ts b/ui2abc/memo-plugin/src/MemoTransformer.ts index c0e2efb52..d16bcd46f 100644 --- a/ui2abc/memo-plugin/src/MemoTransformer.ts +++ b/ui2abc/memo-plugin/src/MemoTransformer.ts @@ -74,7 +74,7 @@ export default function memoTransformer( ...result.statements ], result.ident, - result.getFlag(), + result.getNamespaceFlag(), result.program, ) } diff --git a/ui2abc/memo-plugin/src/ParserTransformer.ts b/ui2abc/memo-plugin/src/ParserTransformer.ts index 992c7aa8f..b7f67716d 100644 --- a/ui2abc/memo-plugin/src/ParserTransformer.ts +++ b/ui2abc/memo-plugin/src/ParserTransformer.ts @@ -61,7 +61,7 @@ export default function memoParserTransformer( ...module.statements, ], module.ident, - module.getFlag(), + module.getNamespaceFlag(), module.program, ) ) diff --git a/ui2abc/ui-plugins/src/component-transformer.ts b/ui2abc/ui-plugins/src/component-transformer.ts index 88313b349..84270970a 100644 --- a/ui2abc/ui-plugins/src/component-transformer.ts +++ b/ui2abc/ui-plugins/src/component-transformer.ts @@ -80,7 +80,7 @@ export class ComponentTransformer extends arkts.AbstractVisitor { node, this.transformStatements(node.statements), node.ident, - node.getFlag(), + node.getNamespaceFlag(), node.program, ) } diff --git a/ui2abc/ui-plugins/src/imports-transformer.ts b/ui2abc/ui-plugins/src/imports-transformer.ts index a3faa223f..9236f3e11 100644 --- a/ui2abc/ui-plugins/src/imports-transformer.ts +++ b/ui2abc/ui-plugins/src/imports-transformer.ts @@ -27,7 +27,7 @@ export class ImportsTransformer extends arkts.AbstractVisitor { node, this.imports.emit(node.statements), node.ident, - node.getFlag(), + node.getNamespaceFlag(), node.program, ) } -- Gitee From 0b6b6bebdc6e4a22dcaca664871a237cbe3c4b65 Mon Sep 17 00:00:00 2001 From: Igor Loginov Date: Fri, 27 Jun 2025 17:30:04 +0300 Subject: [PATCH 7/8] Revert "two way dependency support with binary search" This reverts commit 6ffc16de7f8c453c7100c686dca65e80ed96bed7. --- incremental/runtime/src/states/Dependency.ts | 258 +++--------------- incremental/runtime/src/states/State.ts | 75 +++-- .../runtime/test-arkts/states/State.test.ts | 43 --- incremental/runtime/test/states/State.test.ts | 43 --- 4 files changed, 76 insertions(+), 343 deletions(-) diff --git a/incremental/runtime/src/states/Dependency.ts b/incremental/runtime/src/states/Dependency.ts index 9bc5206d5..5d62e2457 100644 --- a/incremental/runtime/src/states/Dependency.ts +++ b/incremental/runtime/src/states/Dependency.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2025 Huawei Device Co., Ltd. + * Copyright (c) 2022-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,31 +13,24 @@ * limitations under the License. */ -import { int32 } from "@koalaui/common" - -type ID = int32 -let UID: ID = 0 - -interface Identifiable { - readonly id: ID -} +const SKIP_FRAMES = 10 /** This interface represents an unique observer that can be notified that some changes. */ export interface Dependency { - /** Returns dependencies to all used states. */ - readonly states: ScopeToStates | undefined -} + /** Returns `true` if the dependency is no longer actual. */ + readonly obsolete: boolean -/** This class is intended to store dependencies to all scopes. */ -export class StateToScopes implements Identifiable { - private readonly uid: ID = ++UID - private dependencies: Array | undefined = undefined - private latest: ScopeToStates | undefined = undefined + /** Notifies the dependency that it should be invalidated. */ + invalidate(): void +} - get id(): ID { - return this.uid - } +/** This class allows to store and update all dependencies. */ +export class Dependencies { + private frame = 0 + private dependencies: Array | undefined = undefined + private latest: Dependency | undefined = undefined + /** Returns `true` if there are no dependencies to invalidate. */ get empty(): boolean { const dependencies = this.dependencies return dependencies @@ -45,218 +38,57 @@ export class StateToScopes implements Identifiable { : (this.latest === undefined) } - /** @param dependency - a dependency to add */ - add(dependency: ScopeToStates) { - const latest = this.latest - if (latest === dependency) return // already added - this.latest = dependency - - let dependencies = this.dependencies - if (dependencies) { - const index = find(dependencies, dependency.id) - if (!found(dependencies, dependency.id, index)) { - dependencies.splice(index, 0, dependency) - } - } else if (latest) { - dependencies = new Array() - dependencies.push(latest) - dependencies.splice(find(dependencies, dependency.id), 0, dependency) - this.dependencies = dependencies - } - } - - /** @param dependency - a dependency to remove */ - remove(dependency: ScopeToStates) { - const dependencies = this.dependencies - if (dependencies) { - const index = find(dependencies, dependency.id) - if (found(dependencies, dependency.id, index)) { - dependencies.splice(index, 1) - } - } - if (this.latest === dependency) { - this.latest = undefined - } - } - - /** Removes all dependecies. */ - clear() { - const dependencies = this.dependencies - if (dependencies) { - this.dependencies = undefined - this.latest = undefined - let index = dependencies.length - while (0 < index--) { - dependencies[index].remove(this) - } - } else { - const latest = this.latest - if (latest) { - latest.remove(this) - this.latest = undefined - } - } - } - - /** Iterates through all dependecies and invalidates them. */ - invalidate() { - const dependencies = this.dependencies - if (dependencies) { - let index = dependencies.length - while (0 < index--) { - dependencies[index].invalidate() - } - } else { - const latest = this.latest - if (latest) { - latest.invalidate() - } - } - } - - /** @param dependency - a dependency to register */ - register(dependency?: Dependency) { - const that = dependency?.states - if (that) { - this.add(that) - that.add(this) - } - } -} - -/** This class is intended to store dependencies to all used states. */ -export class ScopeToStates implements Identifiable { - private readonly uid: ID = ++UID - private marker: boolean = false - private dependencies: Array> | undefined = undefined - private latest: MarkableEntry | undefined = undefined - - readonly invalidate: () => void - - constructor(invalidate: () => void) { - this.invalidate = invalidate - } - - get id(): ID { - return this.uid - } - - /** @param dependency - a dependency to add */ - add(dependency: StateToScopes) { - const latest = this.latest - if (latest && latest.dependency === dependency) { - latest.marker = this.marker - return // already added - } + /** @param dependency - a dependency to invalidate */ + register(dependency?: Dependency): void { + if (dependency === undefined || dependency == this.latest || dependency.obsolete) return let dependencies = this.dependencies if (dependencies) { - const index = find(dependencies, dependency.id) - if (found(dependencies, dependency.id, index)) { - dependencies[index].marker = this.marker - } else { - dependencies.splice(index, 0, entry(dependency, this.marker)) - } - this.latest = dependencies[index] - } else if (latest) { - dependencies = new Array> - dependencies.push(latest) - dependencies.splice(find(dependencies, dependency.id), 0, entry(dependency, this.marker)) - this.dependencies = dependencies - - } else { - this.latest = entry(dependency, this.marker) - } - } - - /** @param dependency - a dependency to remove */ - remove(dependency: StateToScopes) { - const dependencies = this.dependencies - if (dependencies) { - const index = find(dependencies, dependency.id) - if (found(dependencies, dependency.id, index)) { - dependencies.splice(index, 1) - } - } - if (this.latest?.dependency === dependency) { - this.latest = undefined - } - } - - /** Removes all dependecies. */ - clear() { - const dependencies = this.dependencies - if (dependencies) { - this.dependencies = undefined - this.latest = undefined - let index = dependencies.length - while (0 < index--) { - dependencies[index].dependency.remove(this) - } + // Array includes repeated elements, they will be processed in updateDependencies + dependencies.push(dependency) } else { const latest = this.latest if (latest) { - this.latest = undefined - latest.dependency.remove(this) + dependencies = new Array() + dependencies.push(latest) + dependencies.push(dependency) + this.dependencies = dependencies } } + this.latest = dependency } - /** Removes all dependecies, which were not used since previous call. */ - reset() { - const marker = !this.marker - this.marker = marker + /** Invalidates all dependencies and removes obsolete ones. */ + updateDependencies(invalidate: boolean, modifiedTrackedScopes?: ReadonlySet): void { + if (++this.frame < SKIP_FRAMES && !invalidate) return + this.frame = 0 const dependencies = this.dependencies if (dependencies) { - this.latest = undefined - let index = dependencies.length - while (0 < index--) { - const element = dependencies[index] - if (element.marker == marker) { - element.dependency.remove(this) - dependencies.splice(index, 1) - } + let dependenciesSet = new Set(dependencies); + this.dependencies = []; + const newDependencies = this.dependencies; + if (newDependencies) { + dependenciesSet.forEach((dependency: Dependency) => { + if (updateDependency(invalidate, dependency, modifiedTrackedScopes)) { + newDependencies.push(dependency); + } + }); } } else { const latest = this.latest - if (latest && (latest.marker == marker)) { + if (latest !== undefined && !updateDependency(invalidate, latest, modifiedTrackedScopes)) { this.latest = undefined - latest.dependency.remove(this) } } } } -class MarkableEntry implements Identifiable { - readonly dependency: T - marker: boolean - constructor(dependency: T, marker: boolean) { - this.dependency = dependency - this.marker = marker - } - get id(): ID { - return this.dependency.id - } -} - -function entry(dependency: T, marker: boolean): MarkableEntry { - return new MarkableEntry(dependency, marker) -} - -function found(array: Array, id: ID, index: number): T | undefined { - if (index < array.length) { - const element = array[index] - if (element.id == id) return element - } - return undefined -} - -function find(array: Array, id: ID): number { - let left = 0 - let right = array.length - while (left < right) { - const center = ((left + right) >>> 1) as int32 - if (array[center].id < id) left = center + 1 - else right = center +function updateDependency(invalidate: boolean, + dependency: Dependency, + modifiedTrackedScopes?: ReadonlySet): boolean { + if (modifiedTrackedScopes && !modifiedTrackedScopes.has(dependency)) { + return false } - return left + if (dependency.obsolete) return false + if (invalidate) dependency.invalidate() + return true } diff --git a/incremental/runtime/src/states/State.ts b/incremental/runtime/src/states/State.ts index 2b1b5b0a3..fbc4632d2 100644 --- a/incremental/runtime/src/states/State.ts +++ b/incremental/runtime/src/states/State.ts @@ -14,7 +14,7 @@ */ import { Array_from_set, className, float64ToInt, int32, KoalaCallsiteKey, KoalaCallsiteKeys, KoalaProfiler, MarkableQueue, markableQueue, Observable, ObservableHandler, refEqual, uint32 } from "@koalaui/common" -import { Dependency, ScopeToStates, StateToScopes } from "./Dependency" +import { Dependencies, Dependency } from "./Dependency" import { Disposable, disposeContent, disposeContentBackward } from "./Disposable" import { Changes, Journal } from "./Journal" import { IncrementalNode } from "../tree/IncrementalNode" @@ -226,7 +226,7 @@ interface ManagedScope extends Disposable, Dependency, ReadonlyTreeNode { class StateImpl implements Observable, ManagedState, MutableState { protected manager: StateManagerImpl | undefined = undefined - private dependencies: StateToScopes | undefined = undefined + private dependencies: Dependencies | undefined = undefined protected snapshot: Value protected myModified: boolean = false protected myUpdated: boolean = true @@ -250,7 +250,7 @@ class StateImpl implements Observable, ManagedState, MutableState this.tracker = tracker this.name = name this.manager = manager - this.dependencies = new StateToScopes() + this.dependencies = new Dependencies() this.snapshot = initial ObservableHandler.attach(initial, this) manager.addCreatedState(this) @@ -287,7 +287,7 @@ class StateImpl implements Observable, ManagedState, MutableState onAccess(propertyName?: string): void { const dependency = this.manager?.dependency - if (dependency && propertyName) { + if (propertyName && !this.disposed) { this.trackedScopes.register(propertyName, dependency) } this.dependencies?.register(dependency) @@ -330,7 +330,7 @@ class StateImpl implements Observable, ManagedState, MutableState this.applyStateSnapshot(this.current(changes)) this.myUpdated = true } - if (this.myModified) this.dependencies?.invalidate() + this.dependencies?.updateDependencies(this.myModified, modifiedTrackedScopes) } protected applyStateSnapshot(newValue: Value) { @@ -356,7 +356,6 @@ class StateImpl implements Observable, ManagedState, MutableState manager.checkForStateDisposing() this.manager = undefined this.tracker = undefined - this.dependencies?.clear() this.dependencies = undefined manager.removeCreatedState(this, this.name) this.trackedScopes.clear() @@ -464,7 +463,7 @@ class ArrayStateImpl extends StateImpl> implements ArrayState< class ParameterImpl implements MutableState { private manager: StateManagerImpl | undefined = undefined - private dependencies: StateToScopes | undefined = undefined + private dependencies: Dependencies | undefined = undefined private name: string | undefined = undefined private _value: Value private _modified: boolean = false @@ -476,7 +475,7 @@ class ParameterImpl implements MutableState { */ constructor(manager: StateManagerImpl, value: Value, name?: string) { this.manager = manager - this.dependencies = new StateToScopes() + this.dependencies = new Dependencies() this.name = name this._value = value } @@ -503,7 +502,7 @@ class ParameterImpl implements MutableState { } else { this._modified = isModified } - if (this._modified) this.dependencies?.invalidate() + this.dependencies?.updateDependencies(this._modified) } get disposed(): boolean { @@ -515,7 +514,6 @@ class ParameterImpl implements MutableState { if (manager === undefined) return // already disposed manager.checkForStateDisposing() this.manager = undefined - this.dependencies?.clear() this.dependencies = undefined } @@ -619,7 +617,7 @@ class StateManagerImpl implements StateManager { scope.manager = this scope.node = node scope.nodeRef = node - scope.dependencies = new StateToScopes() + scope.dependencies = new Dependencies() scope.setNamedState(CONTEXT_ROOT_SCOPE, new StateImpl>(this, scope, false)) scope.setNamedState(CONTEXT_ROOT_NODE, new StateImpl(this, node, false)) return scope @@ -632,7 +630,7 @@ class StateManagerImpl implements StateManager { cleanup?.(this, value) }) scope.manager = this - scope.dependencies = new StateToScopes() + scope.dependencies = new Dependencies() this.current?.addCreatedState(scope) return scope } @@ -799,8 +797,7 @@ class StateManagerImpl implements StateManager { class ScopeImpl implements ManagedScope, InternalScope, ComputableState { recomputeNeeded: boolean = true manager: StateManagerImpl | undefined = undefined - dependencies: StateToScopes | undefined = undefined - private _states: ScopeToStates | undefined + dependencies: Dependencies | undefined = undefined private myCompute: (() => Value) | undefined = undefined private myCleanup: ((value: Value | undefined) => void) | undefined = undefined @@ -828,14 +825,7 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable // Constructor with (compute?: () => Value, cleanup?: (value: Value | undefined) => void) // signature causes es2panda recheck crash, so I have introduced a create - private constructor() { - this._states = new ScopeToStates(() => { this.invalidate() }) - } - - get states(): ScopeToStates | undefined { - return this._states - } - + private constructor() {} static create(id: KoalaCallsiteKey, paramCount: int32, compute?: () => V, cleanup?: (value: V | undefined) => void, reuseKey?: string): ScopeImpl { const instance = new ScopeImpl() instance._id = id // special type to distinguish scopes @@ -988,7 +978,6 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable } get unchanged(): boolean { - if (!this.parentScope) this.dependencies?.register(this.manager?.dependency) if (this.recomputeNeeded) { this.incremental = undefined this.nodeCount = 0 @@ -1006,10 +995,7 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable recache(newValue?: Value): Value { const manager = this.manager - if (manager) { - manager.current = this.scopeInternal - this._states?.reset() - } + if (manager) manager.current = this.scopeInternal const oldValue = this.myValue this.myValue = newValue this.myModified = this.myComputed && !refEqual(newValue, oldValue) @@ -1018,11 +1004,12 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable this.detachChildScopes() this.parent?.increment(this.node ? 1 : this.nodeCount, false) this.node?.incrementalUpdateDone(this.parent?.nodeRef) - if (this.myModified && this.parentScope === undefined) this.dependencies?.invalidate() return this.cached } get cached(): Value { + this.dependencies?.register(this.manager?.dependency) + this.dependencies?.updateDependencies(this.myModified) return this.myValue as Value } @@ -1046,11 +1033,15 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable get modified(): boolean { if (this.recomputeNeeded) this.value - else if (!this.parentScope) this.dependencies?.register(this.manager?.dependency) + else this.dependencies?.register(this.manager?.dependency) return this.myModified } - private invalidate() { + get obsolete(): boolean { + return this.manager === undefined + } + + invalidate(): void { const current = this.manager?.current // parameters can update snapshot during recomposition let scope: ManagedScope = this while (true) { @@ -1080,7 +1071,7 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable // TEMP: explicit compares to avoid compiler bug const recycled = child.reuseKey !== undefined && this._nodeRef?.recycle(child.reuseKey!!, child, child.id) == true if (recycled) { - // if parent node is also disposed, the recycled scopes would dispose in the ReusablePool + // if parent node is also disposed, the recycled scopes would dispose in the ReusablePool if (!child.node) throw Error("reusable scope doesn't have a node") child.node!.detach() } else { @@ -1098,9 +1089,6 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable manager.checkForStateDisposing() let error: Error | undefined = undefined this.manager = undefined - this._states?.clear() - this._states = undefined - this.dependencies?.clear() this.dependencies = undefined const scope = manager.current manager.current = this @@ -1153,23 +1141,23 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable class ControlledScopeImpl implements Dependency, ControlledScope { private manager: StateManagerImpl | undefined private old: Dependency | undefined = undefined - private _states: ScopeToStates | undefined + private readonly _invalidate: () => void constructor(manager: StateManagerImpl, invalidate: () => void) { this.manager = manager - this._states = new ScopeToStates(invalidate) + this._invalidate = invalidate } - get states(): ScopeToStates | undefined { - return this._states + invalidate(): void { + this._invalidate() } static cleanup(scope?: ControlledScopeImpl): void { - if (scope) { - scope.manager = undefined - scope._states?.clear() - scope._states = undefined - } + if (scope) scope.manager = undefined + } + + get obsolete(): boolean { + return this.manager === undefined } enter(): void { @@ -1185,7 +1173,6 @@ class ControlledScopeImpl implements Dependency, ControlledScope { if (manager.external !== this) throw new Error("ControlledScope is not valid") manager.external = this.old this.old = undefined - this._states?.reset() } } diff --git a/incremental/runtime/test-arkts/states/State.test.ts b/incremental/runtime/test-arkts/states/State.test.ts index 58e065f61..6a33d17c7 100644 --- a/incremental/runtime/test-arkts/states/State.test.ts +++ b/incremental/runtime/test-arkts/states/State.test.ts @@ -903,49 +903,6 @@ suite("State", () => { Assert.equal(computableCounter, 2) // computable is not recomputed Assert.equal(stateCounter, 2) // state is recomputed by request but it is not modified }) - test("do not recompute by state if it was not used during last computation", () => { - const manager = createStateManager() - const stateB = manager.mutableState(true) - const stateT = manager.mutableState(1) - const stateF = manager.mutableState(2) - const computing = new Array() - const computable = manager.computableState(() => { - computing.push("recomputed") - return stateB.value ? stateT.value : stateF.value - }) - // initial computation - Assert.equal(computable.value, 1) - assertStringsAndCleanup(computing, "recomputed") - // do not recompute if nothing changed - Assert.equal(testUpdate(false, manager), 0) - Assert.equal(computable.value, 1) - Assert.isEmpty(computing) - // recompute if used stateT changed - stateT.value = -1 - Assert.equal(testUpdate(false, manager), 1) - Assert.equal(computable.value, -1) - assertStringsAndCleanup(computing, "recomputed") - // do not recompute if stateF changed - stateF.value = -2 - Assert.equal(testUpdate(false, manager), 1) - Assert.equal(computable.value, -1) - Assert.isEmpty(computing) - // switch flag and recompute - stateB.value = false - Assert.equal(testUpdate(false, manager), 1) - Assert.equal(computable.value, -2) - assertStringsAndCleanup(computing, "recomputed") - // recompute if used stateF changed - stateF.value = 2 - Assert.equal(testUpdate(false, manager), 1) - Assert.equal(computable.value, 2) - assertStringsAndCleanup(computing, "recomputed") - // do not recompute if stateT changed - stateT.value = 1 - Assert.equal(testUpdate(false, manager), 1) - Assert.equal(computable.value, 2) - Assert.isEmpty(computing) - }) test("build and update simple tree", () => { let manager = createStateManager() let count = manager.mutableState(30) diff --git a/incremental/runtime/test/states/State.test.ts b/incremental/runtime/test/states/State.test.ts index 038ae7786..ab06e7ffb 100644 --- a/incremental/runtime/test/states/State.test.ts +++ b/incremental/runtime/test/states/State.test.ts @@ -932,49 +932,6 @@ suite("State", () => { assert.equal(computableCounter, 2) // computable is not recomputed assert.equal(stateCounter, 2) // state is recomputed by request but it is not modified }) - test("do not recompute by state if it was not used during last computation", () => { - const manager = createStateManager() - const stateB = manager.mutableState(true) - const stateT = manager.mutableState(1) - const stateF = manager.mutableState(2) - const computing = new Array() - const computable = manager.computableState(() => { - computing.push("recomputed") - return stateB.value ? stateT.value : stateF.value - }) - // initial computation - assertState(computable, 1) - assertStringsAndCleanup(computing, "recomputed") - // do not recompute if nothing changed - assert.equal(testUpdate(false, manager), 0) - assert.equal(computable.value, 1) - assert.isEmpty(computing) - // recompute if used stateT changed - stateT.value = -1 - assert.equal(testUpdate(false, manager), 1) - assert.equal(computable.value, -1) - assertStringsAndCleanup(computing, "recomputed") - // do not recompute if stateF changed - stateF.value = -2 - assert.equal(testUpdate(false, manager), 1) - assert.equal(computable.value, -1) - assert.isEmpty(computing) - // switch flag and recompute - stateB.value = false - assert.equal(testUpdate(false, manager), 1) - assert.equal(computable.value, -2) - assertStringsAndCleanup(computing, "recomputed") - // recompute if used stateF changed - stateF.value = 2 - assert.equal(testUpdate(false, manager), 1) - assert.equal(computable.value, 2) - assertStringsAndCleanup(computing, "recomputed") - // do not recompute if stateT changed - stateT.value = 1 - assert.equal(testUpdate(false, manager), 1) - assert.equal(computable.value, 2) - assert.isEmpty(computing) - }) test("build and update simple tree", () => { let manager = createStateManager() let count = manager.mutableState(30) -- Gitee From 6ad7d0008cc7120c9235a9c2bd982dad19b60490 Mon Sep 17 00:00:00 2001 From: Igor Loginov Date: Fri, 27 Jun 2025 20:46:06 +0300 Subject: [PATCH 8/8] Keep track of updates in visitor --- .../src/arkts-api/factory/nodeFactory.ts | 4 +- .../node-utilities/ClassDefinition.ts | 41 ++++- .../libarkts/src/arkts-api/static/global.ts | 19 ++ ui2abc/libarkts/src/arkts-api/visitor.ts | 170 +++++++++++++----- 4 files changed, 179 insertions(+), 55 deletions(-) diff --git a/ui2abc/libarkts/src/arkts-api/factory/nodeFactory.ts b/ui2abc/libarkts/src/arkts-api/factory/nodeFactory.ts index 88023f198..b6e26ca80 100644 --- a/ui2abc/libarkts/src/arkts-api/factory/nodeFactory.ts +++ b/ui2abc/libarkts/src/arkts-api/factory/nodeFactory.ts @@ -36,7 +36,7 @@ import { updateTSTypeParameter } from "../node-utilities/TSTypeParameter" import { updateETSTypeReferencePart } from "../node-utilities/TSTypeReferencePart" import { updateETSImportDeclaration } from "../node-utilities/ETSImportDeclaration" import { updateVariableDeclarator } from "../node-utilities/VariableDeclarator" -import { updateClassDefinition } from "../node-utilities/ClassDefinition" +import { createClassDefinition, updateClassDefinition } from "../node-utilities/ClassDefinition" import { updateETSStructDeclaration } from "../node-utilities/ETSStructDeclaration" import { createClassProperty, updateClassProperty } from "../node-utilities/ClassProperty" import { createETSFunctionType, updateETSFunctionType } from "../node-utilities/ETSFunctionType" @@ -94,7 +94,7 @@ export const factory = { createETSStructDeclaration: ETSStructDeclaration.createETSStructDeclaration, updateETSStructDeclaration, - createClassDefinition: ClassDefinition.createClassDefinition, + createClassDefinition, updateClassDefinition, createClassDeclaration, diff --git a/ui2abc/libarkts/src/arkts-api/node-utilities/ClassDefinition.ts b/ui2abc/libarkts/src/arkts-api/node-utilities/ClassDefinition.ts index 9f7cc78c2..eeaa79bd7 100644 --- a/ui2abc/libarkts/src/arkts-api/node-utilities/ClassDefinition.ts +++ b/ui2abc/libarkts/src/arkts-api/node-utilities/ClassDefinition.ts @@ -14,6 +14,7 @@ */ import { + AnnotationUsage, ClassDefinition, Expression, Identifier, @@ -29,6 +30,35 @@ import { AstNode } from "../peers/AstNode" import { Es2pandaClassDefinitionModifiers, Es2pandaModifierFlags } from "../../generated/Es2pandaEnums" import { throwError } from "../../utils" +export function createClassDefinition( + ident: Identifier | undefined, + typeParams: TSTypeParameterDeclaration | undefined, + superTypeParams: TSTypeParameterInstantiation | undefined, + _implements: readonly TSClassImplements[], + ctor: MethodDefinition | undefined, + superClass: Expression | undefined, + body: readonly AstNode[], + modifiers: Es2pandaClassDefinitionModifiers, + flags: Es2pandaModifierFlags, + annotations?: readonly AnnotationUsage[], +) { + const res = ClassDefinition.createClassDefinition( + ident, + typeParams, + superTypeParams, + _implements, + ctor, + superClass, + body, + modifiers, + flags, + ) + if (annotations) { + res.setAnnotations(annotations) + } + return res +} + export function updateClassDefinition( original: ClassDefinition, ident: Identifier | undefined, @@ -39,7 +69,8 @@ export function updateClassDefinition( superClass: Expression | undefined, body: readonly AstNode[], modifiers: Es2pandaClassDefinitionModifiers, - flags: Es2pandaModifierFlags + flags: Es2pandaModifierFlags, + annotations?: readonly AnnotationUsage[], ): ClassDefinition { if (original.ctor !== undefined && !isMethodDefinition(original.ctor)) { throwError(`class definition constructor is not method definition: ${ctor?.dump()}`) @@ -53,11 +84,12 @@ export function updateClassDefinition( && (isSameNativeObject(body, original.body)) && (isSameNativeObject(modifiers, original.modifiers)) && (isSameNativeObject(flags, original.modifierFlags)) + && (isSameNativeObject(annotations, original.annotations)) ) { return original } return updateNodeByNode( - ClassDefinition.createClassDefinition( + createClassDefinition( ident, typeParams, superTypeParams, @@ -66,8 +98,9 @@ export function updateClassDefinition( superClass, body, modifiers, - flags - ).setAnnotations(original.annotations), + flags, + annotations + ), original ) } diff --git a/ui2abc/libarkts/src/arkts-api/static/global.ts b/ui2abc/libarkts/src/arkts-api/static/global.ts index 24929ad50..84e7ff3d8 100644 --- a/ui2abc/libarkts/src/arkts-api/static/global.ts +++ b/ui2abc/libarkts/src/arkts-api/static/global.ts @@ -22,6 +22,22 @@ import { Context } from "../peers/Context" import { Profiler } from "./profiler" import { ArkTsConfig } from "../../generated" +export class UpdateTracker { + stack: boolean[] = [] + + push() { + this.stack.push(false) + } + + update() { + this.stack[this.stack.length - 1] = true + } + + check() { + return this.stack.pop() + } +} + export class global { public static filePath: string = "./plugins/input/main.ets" @@ -76,4 +92,7 @@ export class global { // Check node type values during node creation public static validatePeerTypes = false + + // Keep track of update info to optimize performance + public static updateTracker: UpdateTracker = new UpdateTracker() } diff --git a/ui2abc/libarkts/src/arkts-api/visitor.ts b/ui2abc/libarkts/src/arkts-api/visitor.ts index bf91de16b..27101c806 100644 --- a/ui2abc/libarkts/src/arkts-api/visitor.ts +++ b/ui2abc/libarkts/src/arkts-api/visitor.ts @@ -14,6 +14,8 @@ */ import { + AnnotationUsage, + Expression, isArrayExpression, isArrowFunctionExpression, isAssignmentExpression, @@ -66,7 +68,9 @@ import { isVariableDeclaration, isVariableDeclarator, isWhileStatement, - Statement + MethodDefinition, + Statement, + TSClassImplements } from "../generated" import { Es2pandaImportKinds } from "../generated/Es2pandaEnums" import { factory } from "./factory/nodeFactory" @@ -129,7 +133,11 @@ function nodeVisitor(node: T, visitor: Visitor): if (node === undefined) { return node } - return visitor(node) as T + const result = visitor(node) as T + if (node != result) { + global.updateTracker.update() + } + return result } // TODO: rethink (remove as) @@ -137,7 +145,13 @@ function nodesVisitor(n if (nodes === undefined) { return nodes } - return nodes.map(node => visitor(node) as T) + return nodes.map(node => { + const result = visitor(node) as T + if (node != result) { + global.updateTracker.update() + } + return result + }) } export function visitEachChild( @@ -146,93 +160,151 @@ export function visitEachChild( ): AstNode { global.profiler.nodeVisited() if (isETSModule(node)) { - return factory.updateETSModule( - node, - nodesVisitor(node.statements, visitor), - nodeVisitor(node.ident, visitor), + global.updateTracker.push() + const newStatements: readonly Statement[] = nodesVisitor(node.statements, visitor) + const newIdent = nodeVisitor(node.ident, visitor) + if (!global.updateTracker.check()) { + return node + } + return factory.createETSModule( + newStatements, + newIdent, node.getNamespaceFlag(), node.program, ) } if (isCallExpression(node)) { - return factory.updateCallExpression( - node, - nodeVisitor(node.callee, visitor), - nodesVisitor(node.arguments, visitor), - nodeVisitor(node.typeParams, visitor), + global.updateTracker.push() + const newCallee = nodeVisitor(node.callee, visitor) + const newArguments: readonly Expression[] = nodesVisitor(node.arguments, visitor) + const newTypeParams = nodeVisitor(node.typeParams, visitor) + const newTrailingBlock = nodeVisitor(node.trailingBlock, visitor) + if (!global.updateTracker.check()) { + return node + } + return factory.createCallExpression( + newCallee, + newArguments, + newTypeParams, node.isOptional, node.hasTrailingComma, - nodeVisitor(node.trailingBlock, visitor) + newTrailingBlock, ) } if (isFunctionDeclaration(node)) { - return factory.updateFunctionDeclaration( - node, - nodeVisitor(node.function, visitor), - nodesVisitor(node.annotations, visitor), + global.updateTracker.push() + const newFunction = nodeVisitor(node.function, visitor) + const newAnnotations: readonly AnnotationUsage[] = nodesVisitor(node.annotations, visitor) + if (!global.updateTracker.check()) { + return node + } + return factory.createFunctionDeclaration( + newFunction, + newAnnotations, node.isAnonymous, ) } if (isBlockStatement(node)) { - return factory.updateBlockStatement( - node, - nodesVisitor(node.statements, visitor), + global.updateTracker.push() + const newStatements: readonly Statement[] = nodesVisitor(node.statements, visitor) + if (!global.updateTracker.check()) { + return node + } + return factory.createBlockStatement( + newStatements, ) } if (isBlockExpression(node)) { - return factory.updateBlockExpression( - node, - nodesVisitor(node.statements, visitor), + global.updateTracker.push() + const newStatements: readonly Statement[] = nodesVisitor(node.statements, visitor) + if (!global.updateTracker.check()) { + return node + } + return factory.createBlockExpression( + newStatements, ) } if (isChainExpression(node)) { - return factory.updateChainExpression( - node, - nodeVisitor(node.expression, visitor), + global.updateTracker.push() + const newExpression = nodeVisitor(node.expression, visitor) + if (!global.updateTracker.check()) { + return node + } + return factory.createChainExpression( + newExpression, ) } if (isExpressionStatement(node)) { - return factory.updateExpressionStatement( - node, - nodeVisitor(node.expression, visitor) + global.updateTracker.push() + const newExpression = nodeVisitor(node.expression, visitor) + if (!global.updateTracker.check()) { + return node + } + return factory.createExpressionStatement( + newExpression, ) } if (isETSStructDeclaration(node)) { - return factory.updateETSStructDeclaration( - node, - nodeVisitor(node.definition, visitor) + global.updateTracker.push() + const newDefinition = nodeVisitor(node.definition, visitor) + if (!global.updateTracker.check()) { + return node + } + return factory.createETSStructDeclaration( + newDefinition ) } if (isClassDeclaration(node)) { - return factory.updateClassDeclaration( - node, - nodeVisitor(node.definition, visitor), + global.updateTracker.push() + const newDefinition = nodeVisitor(node.definition, visitor) + if (!global.updateTracker.check()) { + return node + } + return factory.createClassDeclaration( + newDefinition, node.modifierFlags, ) } if (isClassDefinition(node)) { - return factory.updateClassDefinition( - node, - nodeVisitor(node.ident, visitor), - nodeVisitor(node.typeParams, visitor), - nodeVisitor(node.superTypeParams, visitor), - nodesVisitor(node.implements, visitor), + global.updateTracker.push() + const newIdent = nodeVisitor(node.ident, visitor) + const newTypeParams = nodeVisitor(node.typeParams, visitor) + const newSuperTypeParams = nodeVisitor(node.superTypeParams, visitor) + const newImplements: readonly TSClassImplements[] = nodesVisitor(node.implements, visitor) + const newSuper = nodeVisitor(node.super, visitor) + const newBody = nodesVisitor(node.body, visitor) + const newAnnotations: readonly AnnotationUsage[] = nodesVisitor(node.annotations, visitor) + if (!global.updateTracker.check()) { + return node + } + return factory.createClassDefinition( + newIdent, + newTypeParams, + newSuperTypeParams, + newImplements, undefined, /* can not pass node.ctor here because of mismatching types */ - nodeVisitor(node.super, visitor), - nodesVisitor(node.body, visitor), + newSuper, + newBody, node.modifiers, - node.modifierFlags + node.modifierFlags, + newAnnotations, ) } if (isMethodDefinition(node)) { - return factory.updateMethodDefinition( - node, + global.updateTracker.push() + const newId = nodeVisitor(node.id, visitor) + const newValue = nodeVisitor(node.value, visitor) + const newOverloads: readonly MethodDefinition[] = nodesVisitor(node.overloads, visitor) + if (!global.updateTracker.check()) { + return node + } + return factory.createMethodDefinition( node.kind, - nodeVisitor(node.id, visitor), - nodeVisitor(node.value, visitor), + newId, + newValue, node.modifierFlags, node.isComputed, - nodesVisitor(node.overloads, visitor) + newOverloads, ) } if (isScriptFunction(node)) { -- Gitee