1/* 2 * Copyright (c) 2022-2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { global } from '../static/global'; 17import { isNumber, throwError } from '../../utils'; 18import { 19 KInt, 20 KNativePointer as KPtr, 21 KNativePointer, 22 nullptr, 23 withString, 24 withStringArray, 25 withStringResult, 26} from '@koalaui/interop'; 27import { NativePtrDecoder } from './nativePtrDecoder'; 28import { Es2pandaModifierFlags, Es2pandaScriptFunctionFlags } from '../../generated/Es2pandaEnums'; 29import { classByPeer } from '../class-by-peer'; 30import type { AstNode } from '../peers/AstNode'; 31import { ArktsObject } from '../peers/ArktsObject'; 32import { Es2pandaAstNodeType } from '../../Es2pandaEnums'; 33 34export const arrayOfNullptr = new BigUint64Array([nullptr]); 35 36export const allFlags = Object.values(Es2pandaModifierFlags) 37 .filter(isNumber) 38 .reduce((prev, next) => prev | next, 0); 39 40export function assertValidPeer(peer: KPtr, expectedKind: Es2pandaAstNodeType): void { 41 if (peer === nullptr) { 42 throwError(`invalid peer`); 43 } 44 const peerType = global.generatedEs2panda._AstNodeTypeConst(global.context, peer); 45 if (peerType !== expectedKind) { 46 throwError(`expected: ${Es2pandaAstNodeType[expectedKind]}, got: ${Es2pandaAstNodeType[peerType]}`); 47 } 48} 49 50export function acceptNativeObjectArrayResult<T extends ArktsObject>( 51 arrayObject: KNativePointer, 52 factory: (instance: KNativePointer) => T 53): T[] { 54 return new NativePtrDecoder().decode(arrayObject).map(factory); 55} 56 57export function unpackNonNullableNode<T extends AstNode>(peer: KNativePointer): T { 58 if (peer === nullptr) { 59 throwError('peer is NULLPTR (maybe you should use unpackNode)'); 60 } 61 return classByPeer(peer) as T; 62} 63 64export function unpackNode<T extends AstNode>(peer: KNativePointer): T | undefined { 65 if (peer === nullptr) { 66 return undefined; 67 } 68 return classByPeer(peer) as T; 69} 70 71export function passNode(node: ArktsObject | undefined): KNativePointer { 72 return node?.peer ?? nullptr; 73} 74 75// meaning unpackNonNullableNodeArray 76export function unpackNodeArray<T extends AstNode>(nodesPtr: KNativePointer): T[] { 77 if (nodesPtr === nullptr) { 78 throwError('nodesPtr is NULLPTR (maybe you should use unpackNodeArray)'); 79 } 80 return new NativePtrDecoder().decode(nodesPtr).map((peer: KNativePointer) => unpackNonNullableNode(peer)); 81} 82 83export function passNodeArray(nodes: readonly AstNode[] | undefined): BigUint64Array { 84 return new BigUint64Array(nodes?.map((node) => BigInt(node.peer)) ?? []); 85} 86 87export function unpackNonNullableObject<T extends ArktsObject>( 88 Type: { new (peer: KNativePointer): T }, 89 peer: KNativePointer 90): T { 91 if (peer === nullptr) { 92 throwError('peer is NULLPTR (maybe you should use unpackObject)'); 93 } 94 return new Type(peer); 95} 96 97export function unpackObject<T extends ArktsObject>( 98 Type: { new (peer: KNativePointer): T }, 99 peer: KNativePointer 100): T | undefined { 101 if (peer === nullptr) { 102 return undefined; 103 } 104 return new Type(peer); 105} 106 107export function unpackString(peer: KNativePointer): string { 108 return withStringResult(peer) ?? throwError(`failed to unpack (peer shouldn't be NULLPTR)`); 109} 110 111export function passString(str: string | undefined): string { 112 if (str === undefined) { 113 return ''; 114 } 115 return withString(str, (it: string) => it); 116} 117 118export function passStringArray(strings: readonly string[]): string[] { 119 return withStringArray(strings, (it: string[]) => it); 120} 121 122export function passNodeWithNewModifiers<T extends AstNode>(node: T, modifiers: KInt): T { 123 return (unpackNonNullableNode(node.peer) as T).updateModifiers(modifiers); 124} 125 126export function scriptFunctionHasBody(peer: KNativePointer): boolean { 127 const flags = global.generatedEs2panda._ScriptFunctionFlagsConst(global.context, peer); 128 return ( 129 (flags & Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_EXTERNAL) === 0 && 130 (flags & Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_EXTERNAL_OVERLOAD) === 0 131 ); 132} 133 134// TODO: remove this 135// TODO: update scopes and other data 136export function updatePeerByNode<T extends AstNode>(peer: KNativePointer, original: T | undefined): KNativePointer { 137 if (peer === nullptr) { 138 throwError('updatePeerByNode called on NULLPTR'); 139 } 140 if (original === undefined) { 141 return peer; 142 } 143 global.generatedEs2panda._AstNodeSetOriginalNode(global.context, peer, original.peer); 144 global.generatedEs2panda._AstNodeSetParent( 145 global.context, 146 peer, 147 global.generatedEs2panda._AstNodeParent(global.context, original.peer) 148 ); 149 global.es2panda._AstNodeUpdateChildren(global.context, peer); 150 global.generatedEs2panda._AstNodeClearModifier(global.context, peer, allFlags); 151 global.generatedEs2panda._AstNodeAddModifier(global.context, peer, original.modifiers); 152 global.es2panda._AstNodeUpdateChildren(global.context, peer); 153 return peer; 154} 155 156// TODO: update scopes and other data 157export function updateNodeByNode<T extends AstNode>(node: T, original: AstNode): T { 158 if (original.peer === nullptr) { 159 throwError('update called on NULLPTR'); 160 } 161 global.generatedEs2panda._AstNodeSetOriginalNode(global.context, node.peer, original.peer); 162 global.generatedEs2panda._AstNodeSetParent( 163 global.context, 164 node.peer, 165 global.generatedEs2panda._AstNodeParent(global.context, original.peer) 166 ); 167 global.es2panda._AstNodeUpdateChildren(global.context, node.peer); 168 return node; 169} 170 171export function nodeType(node: AstNode): Es2pandaAstNodeType { 172 return global.generatedEs2panda._AstNodeTypeConst(global.context, passNode(node)); 173} 174 175/** 176 * @deprecated 177 */ 178export function compose<T extends AstNode, ARGS extends any[]>( 179 create: (...args: ARGS) => T, 180 update: (node: T, original: T) => T = updateNodeByNode 181): (node: T, ...args: ARGS) => T { 182 return (node: T, ...args: ARGS) => update(create(...args), node); 183} 184 185export function updateThenAttach<T extends AstNode, ARGS extends any[]>( 186 update: (original: T, ...args: ARGS) => T, 187 ...attachFuncs: ((node: T, original: T) => T)[] 188): (node: T, ...args: ARGS) => T { 189 return (node: T, ...args: ARGS) => { 190 let _node: T = update(node, ...args); 191 attachFuncs.forEach((attach) => { 192 _node = attach(_node, node); 193 }); 194 return _node; 195 }; 196} 197 198export function attachModifiers<T extends AstNode>(node: T, original: T): T { 199 node.modifiers = original.modifiers; 200 return node; 201} 202