• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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