diff --git a/arkui-plugins/common/program-visitor.ts b/arkui-plugins/common/program-visitor.ts index 9327b9075aadf6c5ecde84d8f41361d1f7ae06de..6fc759e29fa9ca48aec66accb6a1672ed0cd06db 100644 --- a/arkui-plugins/common/program-visitor.ts +++ b/arkui-plugins/common/program-visitor.ts @@ -271,6 +271,9 @@ export class ProgramVisitor extends AbstractVisitor { } this.visitTransformer(transformer, script, externalSourceName, program); arkts.setAllParents(script); + if (!program?.absName.endsWith('.d.ets')) { + arkts.setAllRange(script); + } if (!transformer.isExternal) { debugDumpAstNode( script, diff --git a/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts b/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts index 6bffb9de5fcfd93f46ef6a760851c2a3faf93317..4be2ef2e6da2011885fb0c162f4cec23a11a6233 100644 --- a/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts +++ b/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts @@ -511,7 +511,8 @@ export class factory { static generateArgsInBuilderLambda( leaf: arkts.CallExpression, lambdaBodyInfo: BuilderLambdaStyleBodyInfo, - declInfo: BuilderLambdaDeclInfo + declInfo: BuilderLambdaDeclInfo, + node: arkts.CallExpression ): (arkts.AstNode | undefined)[] { const { isFunctionCall, params, returnType, moduleName, isFromCommonMethod } = declInfo; const type: arkts.Identifier | undefined = builderLambdaType(leaf); @@ -521,23 +522,40 @@ export class factory { const isTrailingCall = leaf.isTrailingCall; const typeArguments = leaf.typeArguments; const hasLastTrailingLambda = checkIsTrailingLambdaInLastParam(params); + console.log('yyy --- type: ', type?.name) + console.log('yyy --- isTrailingCall: ', isTrailingCall) + console.log('yyy --- hasLastTrailingLambda: ', hasLastTrailingLambda) forEachArgWithParam( leaf.arguments, params, (arg, param, index) => { + + let modifiedArg: arkts.AstNode | undefined; if (index === params.length - 2 && !arg) { modifiedArg = this.createSecondLastArgInBuilderLambda(secondLastArgInfo); } if (!modifiedArg) { + console.log('yyy --- arg: ', arg?.dumpSrc()) + console.log('yyy --- param: ', param?.dumpSrc()) + console.log('yyy --- params.length: ', params.length) + console.log('yyy --- index --type: ', index, type?.name) const memoableInfo = collectMemoableInfoInParameter(param); const canAddMemo = checkIsMemoFromMemoableInfo(memoableInfo, false); const fallback = arkts.factory.createUndefinedLiteral(); const updatedArg = this.createOrUpdateArgInBuilderLambda(fallback, arg, canAddMemo, declInfo); modifiedArg = factory.processModifiedArg(updatedArg, index, leaf.arguments, moduleName, type?.name); + console.log('yyy --- modifiedArg: ', modifiedArg?.dumpSrc()) } const shouldInsertToArgs = !isFunctionCall || (index === params.length - 1 && hasLastTrailingLambda); + console.log('yyy ---shouldInsertToArgs: ', shouldInsertToArgs) if (shouldInsertToArgs) { + if (!!modifiedArg) { + modifiedArg.range = node.range; + console.log('yyyy --- modifiedArg dump: ', modifiedArg.dumpSrc()) + console.log(`yy ---generateArgsInBuilderLambda--- node: , ${node.range.start().line()}: ${node.range.start().col()} ---> ${node.range.end().line()}: ${node.range.end().col()}`) + console.log(`yy ---generateArgsInBuilderLambda--- modifiedArg: , ${modifiedArg.range.start().line()}: ${modifiedArg.range.start().col()} ---> ${modifiedArg.range.end().line()}: ${modifiedArg.range.end().col()}`) + } args.push(modifiedArg); } else { modifiedArgs.push(modifiedArg); @@ -969,8 +987,19 @@ export class factory { }); } lambdaBodyInfo.lambdaBody = lambdaBody; - const args: (arkts.AstNode | undefined)[] = this.generateArgsInBuilderLambda(leaf, lambdaBodyInfo, declInfo); + const args: (arkts.AstNode | undefined)[] = this.generateArgsInBuilderLambda(leaf, lambdaBodyInfo, declInfo, node); const newNode = arkts.factory.updateCallExpression(node, replace, leaf.typeArguments, filterDefined(args)); + const isTrailingCall = leaf.isTrailingCall; + if (isTrailingCall && node.parent && node.parent.parent) { + newNode.range = node.parent.parent.range; + console.log('yyyy --- newNode dump: ', newNode.dumpSrc()) + console.log('yyyy --- node.parent dump: ', node.parent.parent.dumpSrc()) + console.log('yyyy --- node dump: ', node.dumpSrc()) + console.log(`yy ---builderLambda--- newNode: , ${newNode.range.start().line()}: ${newNode.range.start().col()} ---> ${newNode.range.end().line()}: ${newNode.range.end().col()}`) + } else { + newNode.range = node.range; + } + arkts.NodeCache.getInstance().collect(newNode); return newNode; } diff --git a/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts b/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts index 9c4a7531a4476202982d16b8cf0eca804e5583f9..9d9c23920532df0aa0c5c58a78d665cc88de7c33 100644 --- a/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts +++ b/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts @@ -588,7 +588,6 @@ export function collectComponentAttributeImport(type: arkts.TypeNode | undefined ) { return; } - const regex: RegExp = /(?\w+Attribute)(?:<.*>)?$/; const name: string = type.part.name.name; const match: RegExpExecArray | null = regex.exec(name); diff --git a/arkui-plugins/ui-plugins/component-transformer.ts b/arkui-plugins/ui-plugins/component-transformer.ts index ae383cc166a70560623afcb07714d182192f6777..31ed4b061d3be882bea5b7507a3c39dc2e7a5dc3 100644 --- a/arkui-plugins/ui-plugins/component-transformer.ts +++ b/arkui-plugins/ui-plugins/component-transformer.ts @@ -28,6 +28,7 @@ import { isCustomDialogControllerOptions, getComponentExtendsName, ComponentType, + EntryAnnoInfo, } from './utils'; import { backingField, @@ -75,7 +76,7 @@ export interface InteropContext { export class ComponentTransformer extends AbstractVisitor { private scopeInfos: ScopeInfo[] = []; private componentInterfaceCollection: arkts.TSInterfaceDeclaration[] = []; - private entryNames: string[] = []; + private entryAnnoInfo: EntryAnnoInfo[] = []; private structMembersMap: Map = new Map(); private isCustomComponentImported: boolean = false; private isCustomComponentV2Imported: boolean = false; @@ -106,7 +107,7 @@ export class ComponentTransformer extends AbstractVisitor { super.reset(); this.scopeInfos = []; this.componentInterfaceCollection = []; - this.entryNames = []; + this.entryAnnoInfo = []; this.structMembersMap = new Map(); this.isCustomComponentImported = false; this.isCustomComponentV2Imported = false; @@ -208,7 +209,7 @@ export class ComponentTransformer extends AbstractVisitor { navInterface.modifiers = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_EXPORT; return arkts.factory.updateEtsScript(node, [...node.statements, navInterface]); } - if (this.isExternal && this.componentInterfaceCollection.length === 0 && this.entryNames.length === 0) { + if (this.isExternal && this.componentInterfaceCollection.length === 0 && this.entryAnnoInfo.length === 0) { return node; } const updateStatements: arkts.AstNode[] = []; @@ -221,15 +222,23 @@ export class ComponentTransformer extends AbstractVisitor { updateStatements.push(...this.componentInterfaceCollection); } - if (this.entryNames.length > 0) { + if (this.entryAnnoInfo.length > 0) { if (!this.isEntryPointImported) entryFactory.createAndInsertEntryPointImport(this.program); // normally, we should only have at most one @Entry component in a single file. // probably need to handle error message here. - if (!this.isPageLifeCycleImported) + if (!this.isPageLifeCycleImported) { this.createImportDeclaration(CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, CustomComponentNames.PAGE_LIFE_CYCLE); - updateStatements.push(...this.entryNames.map(entryFactory.generateEntryWrapper)); + } + updateStatements.push(...this.entryAnnoInfo.map(entryFactory.generateEntryWrapper)); updateStatements.push( - entryFactory.callRegisterNamedRouter(this.entryRouteName, this.projectConfig, this.program?.absName) + ...this.entryAnnoInfo.map((item: EntryAnnoInfo) => + entryFactory.callRegisterNamedRouter( + this.entryRouteName, + this.projectConfig, + this.program?.absName, + item.range + ) + ) ); this.createImportDeclaration(ENTRY_POINT_IMPORT_SOURCE_NAME, NavigationNames.NAVINTERFACE); } @@ -334,11 +343,12 @@ export class ComponentTransformer extends AbstractVisitor { node.modifiers | arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_EXPORT, Object.values(scopeInfo.annotations ?? {}).map((anno) => anno.clone()) ); + customComponentInterface.range = node.range; this.componentInterfaceCollection.push(customComponentInterface); const definition: arkts.ClassDefinition = node.definition!; const newDefinitionBody: arkts.AstNode[] = []; if (!!scopeInfo.annotations?.entry) { - this.entryNames.push(className); + this.entryAnnoInfo.push({ name: className, range: scopeInfo.annotations.entry.range }); const { storage, useSharedStorage, routeName } = getEntryParams(definition); entryFactory.transformStorageParams(storage, useSharedStorage, definition); if (routeName && routeName.value && arkts.isStringLiteral(routeName.value)) { @@ -546,6 +556,17 @@ export class ComponentTransformer extends AbstractVisitor { isComponentStruct(newNode, this.scopeInfos[this.scopeInfos.length - 1]) ) { const updateNode = this.processComponent(newNode); + updateNode.range = newNode.range; + console.log( + `yy --- update: , ${updateNode.range.start().line()}: ${updateNode.range + .start() + .col()} ---> ${updateNode.range.end().line()}: ${updateNode.range.end().col()}` + ); + console.log( + `yy --- newNode: , ${newNode.range.start().line()}: ${newNode.range.start().col()} ---> ${newNode.range + .end() + .line()}: ${newNode.range.end().col()}` + ); this.exit(newNode); return updateNode; } diff --git a/arkui-plugins/ui-plugins/entry-translators/factory.ts b/arkui-plugins/ui-plugins/entry-translators/factory.ts index e4dd29d224a73bb929913285ac9d5fb2cb602a91..32550bb5fa3b30d4ffa23418f32d49caa35cc39d 100644 --- a/arkui-plugins/ui-plugins/entry-translators/factory.ts +++ b/arkui-plugins/ui-plugins/entry-translators/factory.ts @@ -21,6 +21,7 @@ import { ProjectConfig } from '../../common/plugin-context'; import { factory as uiFactory } from '../ui-factory'; import { getRelativePagePath } from './utils'; import { addMemoAnnotation } from '../../collectors/memo-collectors/utils'; +import { EntryAnnoInfo } from '../utils'; export class factory { /** @@ -181,7 +182,7 @@ export class factory { * * @param name class/struct name that has `@Entry` annotation. */ - static generateEntryWrapper(name: string): arkts.ClassDeclaration { + static generateEntryWrapper(entryAnnoInfo: EntryAnnoInfo): arkts.ClassDeclaration { const ctor = factory.generateConstructor(); const definition: arkts.ClassDefinition = arkts.factory .createClassDefinition( @@ -195,7 +196,7 @@ export class factory { arkts.factory.createIdentifier(EntryWrapperNames.ENTRY_POINT_CLASS_NAME) ) ), - [factory.generateEntryFunction(name), ctor], + [factory.generateEntryFunction(entryAnnoInfo.name), ctor], arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_CLASS_DECL | arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_DECLARATION | arkts.Es2pandaClassDefinitionModifiers.CLASS_DEFINITION_MODIFIERS_ID_REQUIRED, @@ -204,6 +205,7 @@ export class factory { .setCtor(ctor as any); const newClass = arkts.factory.createClassDeclaration(definition); newClass.modifiers = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE; + newClass.range = entryAnnoInfo.range; return newClass; } @@ -372,9 +374,10 @@ export class factory { static callRegisterNamedRouter( entryRouteName: string | undefined, projectConfig: ProjectConfig | undefined, - fileAbsName: string | undefined + fileAbsName: string | undefined, + range: arkts.SourceRange ): arkts.ExpressionStatement { - return arkts.factory.createExpressionStatement( + const registerCall = arkts.factory.createExpressionStatement( arkts.factory.createCallExpression( arkts.factory.createMemberExpression( arkts.factory.createIdentifier(EntryWrapperNames.WRAPPER_CLASS_NAME), @@ -398,6 +401,8 @@ export class factory { ] ) ); + registerCall.range = range; + return registerCall; } /** diff --git a/arkui-plugins/ui-plugins/entry-translators/utils.ts b/arkui-plugins/ui-plugins/entry-translators/utils.ts index 5783f94ca15adc497d89193fc661530bfbed2a6e..1f8edb2eae7a326a5ecb7dabe85570d1d37cead0 100644 --- a/arkui-plugins/ui-plugins/entry-translators/utils.ts +++ b/arkui-plugins/ui-plugins/entry-translators/utils.ts @@ -15,42 +15,9 @@ import * as arkts from '@koalaui/libarkts'; import * as path from 'path'; -import { factory } from './factory'; import { isAnnotation } from '../../common/arkts-utils'; import { StructDecoratorNames, EntryParamNames, EntryWrapperNames } from '../../common/predefines'; -/** - * @deprecated - */ -export class EntryHandler { - private entryDefClassName: Set; - - private static instance: EntryHandler; - - private constructor() { - this.entryDefClassName = new Set(); - } - - public static getInstance(): EntryHandler { - if (!this.instance) { - this.instance = new EntryHandler(); - } - return this.instance; - } - - public rememberEntryFunction(classname: string): void { - this.entryDefClassName.add(classname); - } - - public createEntryWrapper(): arkts.ClassDeclaration[] { - let result: arkts.ClassDeclaration[] = []; - this.entryDefClassName.forEach((classname) => { - result.push(factory.generateEntryWrapper(classname)); - }); - return result; - } -} - export function isEntryWrapperClass(node: arkts.AstNode): node is arkts.ClassDeclaration { if (!arkts.isClassDeclaration(node)) return false; const className = node?.definition?.ident?.name; diff --git a/arkui-plugins/ui-plugins/property-translators/link.ts b/arkui-plugins/ui-plugins/property-translators/link.ts index cd1b149bd59d5ec759e56f6889dbd8bec0e1253a..44a36a9a696b08ff6df7b22d4ce843f6b60e7c3f 100644 --- a/arkui-plugins/ui-plugins/property-translators/link.ts +++ b/arkui-plugins/ui-plugins/property-translators/link.ts @@ -43,6 +43,7 @@ export class LinkTranslator extends PropertyTranslator implements InitializerCon cacheTranslatedInitializer(newName: string, originalName: string): void { const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); + initializeStruct.range = this.property.range; PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); if (!!this.structInfo.annotations?.reusable) { const toRecord = generateToRecord(newName, originalName); @@ -97,7 +98,6 @@ export class LinkTranslator extends PropertyTranslator implements InitializerCon ); const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); const setter: arkts.MethodDefinition = this.translateSetter(originalName, this.propertyType, thisSet); - return [field, getter, setter]; } diff --git a/arkui-plugins/ui-plugins/property-translators/propRef.ts b/arkui-plugins/ui-plugins/property-translators/propRef.ts index 750b1a5d9e3bb559e8b93ffb9172659b895f0a96..0fd08c3dd27c7078aae90a9b1d860f1149c3143c 100644 --- a/arkui-plugins/ui-plugins/property-translators/propRef.ts +++ b/arkui-plugins/ui-plugins/property-translators/propRef.ts @@ -44,8 +44,10 @@ export class PropRefTranslator extends PropertyTranslator implements Initializer cacheTranslatedInitializer(newName: string, originalName: string): void { const mutableThis: arkts.Expression = generateThisBacking(newName); const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); + initializeStruct.range = this.property.range; PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); const updateStruct: arkts.AstNode = this.generateUpdateStruct(mutableThis, originalName); + updateStruct.range = this.property.range; PropertyCache.getInstance().collectUpdateStruct(this.structInfo.name, [updateStruct]); if (!!this.structInfo.annotations?.reusable) { const toRecord = generateToRecord(newName, originalName); @@ -67,7 +69,7 @@ export class PropRefTranslator extends PropertyTranslator implements Initializer ); const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); const setter: arkts.MethodDefinition = this.translateSetter(originalName, this.propertyType, thisSet); - + field.range = this.property.range; return [field, getter, setter]; } diff --git a/arkui-plugins/ui-plugins/property-translators/state.ts b/arkui-plugins/ui-plugins/property-translators/state.ts index 20df22709c73a8de83689a51bad060c8368cc84c..8cae8572f66dcef381013b7c2cf0b6675ca21815 100644 --- a/arkui-plugins/ui-plugins/property-translators/state.ts +++ b/arkui-plugins/ui-plugins/property-translators/state.ts @@ -42,6 +42,7 @@ export class StateTranslator extends PropertyTranslator implements InitializerCo cacheTranslatedInitializer(newName: string, originalName: string): void { const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); + initializeStruct.range = this.property.range; PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); if (!!this.structInfo.annotations?.reusable) { const toRecord = generateToRecord(newName, originalName); @@ -63,7 +64,7 @@ export class StateTranslator extends PropertyTranslator implements InitializerCo ); const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); const setter: arkts.MethodDefinition = this.translateSetter(originalName, this.propertyType, thisSet); - + field.range = this.property.range; return [field, getter, setter]; } diff --git a/arkui-plugins/ui-plugins/struct-translators/factory.ts b/arkui-plugins/ui-plugins/struct-translators/factory.ts index a7ebee0c7d42b7c9377d8c09958d755b5ee92911..7fbd65b875fbeedab5ab508db6e156416ae31e91 100644 --- a/arkui-plugins/ui-plugins/struct-translators/factory.ts +++ b/arkui-plugins/ui-plugins/struct-translators/factory.ts @@ -502,14 +502,16 @@ export class factory { classOptionsName = getTypeNameFromTypeParameter(classOptions); } const definition: arkts.ClassDefinition = node.definition; - const className: string | undefined = node.definition.ident?.name; - if (!className) { + const classIdent: arkts.Identifier | undefined = node.definition.ident; + if (!classIdent) { throw new Error('Non Empty className expected for Component'); } + const className: string = classIdent.name; const body: readonly arkts.AstNode[] = definition.body; const propertyTranslators: (PropertyTranslator | MethodTranslator)[] = filterDefined( body.map((member) => classifyStructMembers(member, scope)) ); + scope.keyRange = classIdent.range; const translatedMembers: arkts.AstNode[] = this.tranformPropertyMembers( propertyTranslators, classOptionsName ?? getCustomComponentOptionsName(className), diff --git a/arkui-plugins/ui-plugins/struct-translators/utils.ts b/arkui-plugins/ui-plugins/struct-translators/utils.ts index a25c5bf5cb682c69ace9925d3c9e2bb053a27619..0a729a72d50af366221446b7220482f12f047bbd 100644 --- a/arkui-plugins/ui-plugins/struct-translators/utils.ts +++ b/arkui-plugins/ui-plugins/struct-translators/utils.ts @@ -42,6 +42,7 @@ export type CustomComponentScopeInfo = CustomComponentInfo & { hasInitializeStruct?: boolean; hasUpdateStruct?: boolean; hasReusableRebind?: boolean; + keyRange?: arkts.SourceRange; }; type ResourceMap = Map>; diff --git a/arkui-plugins/ui-plugins/utils.ts b/arkui-plugins/ui-plugins/utils.ts index 9c2960d1b9d9ef9808404b7c747df6f0451dbdeb..65a7895c475c4693d917fe5d91d77887506273ba 100644 --- a/arkui-plugins/ui-plugins/utils.ts +++ b/arkui-plugins/ui-plugins/utils.ts @@ -154,6 +154,11 @@ export type CustomComponentInfo = { annotations: CustomComponentAnontations; }; +export type EntryAnnoInfo = { + range: arkts.SourceRange; + name: string; +} + export type CustomComponentAnontations = { component?: arkts.AnnotationUsage; componentV2?: arkts.AnnotationUsage; diff --git a/koala-wrapper/native/src/bridges.cc b/koala-wrapper/native/src/bridges.cc index 380cab265664a6d45de5f175cbd550fb8eb935d3..e88a6e43b833fbd05b1ae1115f2e8e1bcc15bd07 100644 --- a/koala-wrapper/native/src/bridges.cc +++ b/koala-wrapper/native/src/bridges.cc @@ -633,6 +633,16 @@ void impl_AstNodeSetStart(KNativePointer context, KNativePointer receiver, KNati } KOALA_INTEROP_V3(AstNodeSetStart, KNativePointer, KNativePointer, KNativePointer) +void impl_AstNodeSetRange(KNativePointer context, KNativePointer receiver, KNativePointer range) +{ + const auto _context = reinterpret_cast(context); + const auto _receiver = reinterpret_cast(receiver); + const auto _range = reinterpret_cast(range); + GetImpl()->AstNodeSetRange(_context, _receiver, _range); + return; +} +KOALA_INTEROP_V3(AstNodeSetRange, KNativePointer, KNativePointer, KNativePointer); + KNativePointer impl_AstNodeEndConst(KNativePointer context, KNativePointer receiver) { const auto _context = reinterpret_cast(context); diff --git a/koala-wrapper/native/src/common.cc b/koala-wrapper/native/src/common.cc index 29baa82db80f92c41980e9f36373686a97da7f75..5458f7b25a9ee75a42b5bcf3998dde5394585bf5 100644 --- a/koala-wrapper/native/src/common.cc +++ b/koala-wrapper/native/src/common.cc @@ -363,6 +363,110 @@ KBoolean impl_ProgramCanSkipPhases(KNativePointer context, KNativePointer progra } KOALA_INTEROP_2(ProgramCanSkipPhases, KBoolean, KNativePointer, KNativePointer) +// 1. 线程局部变量只保留 context 指针 +thread_local es2panda_Context *cachedCtx; + +// 2. 全局(或局部)指针,指向当前父节点的 range +static es2panda_SourceRange *cachedParentRange = nullptr; + +// 3. 给子节点设置 range(带行列号判断) +static void SetChildRange(es2panda_AstNode *child) +{ + /*---------- 取子节点自己的 range ----------*/ + es2panda_SourceRange *childRange = + GetImpl()->AstNodeRangeConst(cachedCtx, child); + if (!childRange) return; // 容错 + + KNativePointer childStart = + GetImpl()->SourceRangeStart(cachedCtx, childRange); + KNativePointer childEnd = + GetImpl()->SourceRangeEnd(cachedCtx, childRange); + + KNativePointer parentStart = + GetImpl()->SourceRangeStart(cachedCtx, cachedParentRange); + KNativePointer parentEnd = + GetImpl()->SourceRangeEnd(cachedCtx, cachedParentRange); + + /*---------- 强转为 es2panda_SourcePosition * ----------*/ + auto *startPos = reinterpret_cast(childStart); + auto *endPos = reinterpret_cast(childEnd); + auto *startPos1 = reinterpret_cast(parentStart); + auto *endPos1 = reinterpret_cast(parentEnd); + + /*---------- 取行列号 ----------*/ + auto startLine = GetImpl()->SourcePositionLine(cachedCtx, startPos); + auto startCol = GetImpl()->SourcePositionCol(cachedCtx, startPos); + auto endLine = GetImpl()->SourcePositionLine(cachedCtx, endPos); + auto endCol = GetImpl()->SourcePositionCol(cachedCtx, endPos); + + auto startLine1 = GetImpl()->SourcePositionLine(cachedCtx, startPos1); + auto startCol1 = GetImpl()->SourcePositionCol(cachedCtx, startPos1); + auto endLine1 = GetImpl()->SourcePositionLine(cachedCtx, endPos1); + auto endCol1 = GetImpl()->SourcePositionCol(cachedCtx, endPos1); + + std::cout << "out range node: " << GetImpl()->AstNodeDumpEtsSrcConst(cachedCtx, child) << std::endl; + std::cout << "out range: " << startLine << ',' << startCol << " -> " << endLine << ',' << endCol << std::endl; + + /*---------- 只有行列均为 1 才用父 range ----------*/ + if (startLine == 0 && startCol == 1 && + endLine == 0 && endCol == 1) + { + std::cout << GetImpl()->AstNodeDumpEtsSrcConst(cachedCtx, child) << std::endl; + std::cout << "child range: " << startLine << ',' << startCol << " -> " + << endLine << ',' << endCol << std::endl; + + std::cout << "parent range: " << startLine1 << ',' << startCol1 << " -> " + << endLine1 << ',' << endCol1 << std::endl; + + GetImpl()->AstNodeSetRange(cachedCtx, child, cachedParentRange); + + es2panda_SourceRange *childRange11 = + GetImpl()->AstNodeRangeConst(cachedCtx, child); + if (!childRange11) return; // 容错 + + KNativePointer childStart11 = + GetImpl()->SourceRangeStart(cachedCtx, childRange11); + KNativePointer childEnd11 = + GetImpl()->SourceRangeEnd(cachedCtx, childRange11); + + auto *startPos11 = reinterpret_cast(childStart11); + auto *endPos11 = reinterpret_cast(childEnd11); + + auto startLine11 = GetImpl()->SourcePositionLine(cachedCtx, startPos11); + auto startCol11 = GetImpl()->SourcePositionCol(cachedCtx, startPos11); + auto endLine11 = GetImpl()->SourcePositionLine(cachedCtx, endPos11); + auto endCol11 = GetImpl()->SourcePositionCol(cachedCtx, endPos11); + std::cout << "child range11 new: " << startLine11 << ',' << startCol11 << " -> " + << endLine11 << ',' << endCol11 << std::endl; + } +} + +// 4. 对每个父节点执行的回调 +static void PropagateParentRange(es2panda_AstNode *parent, void *arg) +{ + cachedCtx = static_cast(arg); + + // 拿到父节点的 range 指针 + es2panda_SourceRange *parentRange = GetImpl()->AstNodeRangeConst(cachedCtx, parent); + cachedParentRange = parentRange; // 只用指针,不拷贝值 + + GetImpl()->AstNodeIterateConst(cachedCtx, parent, SetChildRange); +} + +// 5. 导出函数保持不变 +KNativePointer impl_AstNodeSetAllRange(KNativePointer contextPtr, + KNativePointer programPtr) +{ + auto context = reinterpret_cast(contextPtr); + auto program = reinterpret_cast(programPtr); + + GetImpl()->AstNodeForEach(program, PropagateParentRange, context); + return program; +} + +KOALA_INTEROP_2(AstNodeSetAllRange, + KNativePointer, KNativePointer, KNativePointer) + /* ----------------------------------------------------------------------------------------------------------------------------- */ diff --git a/koala-wrapper/src/Es2pandaNativeModule.ts b/koala-wrapper/src/Es2pandaNativeModule.ts index 2ade57a5adb790745ec5c02ff8685ff204062eb0..2235ccb844e9216c4423f84c4f00cfa5b69f3ab9 100644 --- a/koala-wrapper/src/Es2pandaNativeModule.ts +++ b/koala-wrapper/src/Es2pandaNativeModule.ts @@ -684,6 +684,9 @@ export class Es2pandaNativeModule { _AstNodeUpdateAll(context: KPtr, node: KPtr): void { throw new Error('Not implemented'); } + _AstNodeSetAllRange(context: KPtr, node: KPtr): void { + throw new Error('Not implemented'); + } _AstNodeSetOriginalNode(context: KPtr, ast: KPtr, originalNode: KPtr): void { throw new Error('Not implemented'); } @@ -741,6 +744,9 @@ export class Es2pandaNativeModule { _IsETSUnionType(ast: KPtr): KBoolean { throw new Error('Not implemented'); } + _AstNodeSetRange(context: KNativePointer, node: KNativePointer, range: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } _IsETSFunctionType(ast: KPtr): KBoolean { throw new Error('Not implemented'); diff --git a/koala-wrapper/src/arkts-api/peers/AstNode.ts b/koala-wrapper/src/arkts-api/peers/AstNode.ts index 6d49f5da998e17e29a875d811c038959fc96cb90..b98bfb61704fc32d8aa35ad854a5326c716e9def 100644 --- a/koala-wrapper/src/arkts-api/peers/AstNode.ts +++ b/koala-wrapper/src/arkts-api/peers/AstNode.ts @@ -20,6 +20,7 @@ import { throwError } from '../../utils'; import { Es2pandaModifierFlags } from '../../generated/Es2pandaEnums'; import { ArktsObject } from './ArktsObject'; import { SourcePosition } from './SourcePosition'; +import { SourceRange } from './SourceRange'; export abstract class AstNode extends ArktsObject { protected constructor(peer: KNativePointer) { @@ -152,6 +153,14 @@ export abstract class AstNode extends ArktsObject { public set endPosition(end: SourcePosition) { global.es2panda._AstNodeSetEnd(global.context, this.peer, end.peer); } + + public get range(): SourceRange { + return new SourceRange(global.es2panda._AstNodeRangeConst(global.context, this.peer)); + } + + public set range(range: SourceRange) { + global.es2panda._AstNodeSetRange(global.context, this.peer, range.peer); + } } export class UnsupportedNode extends AstNode { diff --git a/koala-wrapper/src/arkts-api/utilities/public.ts b/koala-wrapper/src/arkts-api/utilities/public.ts index b7e5706196b31a9e5c0fc00c8dfb2a3f2595f542..c619f83dc495cfdd92b810f703b13262c50b8a01 100644 --- a/koala-wrapper/src/arkts-api/utilities/public.ts +++ b/koala-wrapper/src/arkts-api/utilities/public.ts @@ -261,6 +261,10 @@ export function setAllParents(ast: AstNode): void { global.es2panda._AstNodeUpdateAll(global.context, ast.peer); } +export function setAllRange(ast: AstNode): void { + global.es2panda._AstNodeSetAllRange(global.context, ast.peer); +} + export function generateTsDeclarationsFromContext( outputDeclEts: string, outputEts: string,