• 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 { factory } from './factory/nodeFactory';
18import {
19    Es2pandaClassDefinitionModifiers,
20    Es2pandaImportKinds,
21    Es2pandaModifierFlags,
22    Es2pandaVariableDeclaratorFlag,
23} from '../generated/Es2pandaEnums';
24import { AstNode } from './peers/AstNode';
25import {
26    isBlockStatement,
27    isConditionalExpression,
28    isTSInterfaceBody,
29    isTSInterfaceDeclaration,
30    isClassDeclaration,
31    isClassDefinition,
32    isTSAsExpression,
33    isETSImportDeclaration,
34    ImportSource,
35    isScriptFunction,
36    FunctionSignature,
37    Property,
38    isClassProperty,
39    isImportDeclaration,
40    isObjectExpression,
41    ObjectExpression,
42    isProperty,
43    Expression,
44    isETSNewClassInstanceExpression,
45    isTemplateLiteral,
46    isBlockExpression,
47    isReturnStatement,
48    isArrayExpression,
49    isTryStatement,
50    isBinaryExpression,
51    isForInStatement,
52    isForUpdateStatement,
53    isForOfStatement,
54    isTSTypeAliasDeclaration,
55    isETSFunctionType,
56} from '../generated';
57import {
58    isEtsScript,
59    isCallExpression,
60    isFunctionDeclaration,
61    isExpressionStatement,
62    isStructDeclaration,
63    isMethodDefinition,
64    // isScriptFunction,
65    isMemberExpression,
66    isIfStatement,
67    isVariableDeclaration,
68    isVariableDeclarator,
69    isArrowFunctionExpression,
70    isAssignmentExpression,
71    isEtsParameterExpression,
72} from './factory/nodeTests';
73import { classDefinitionFlags } from './utilities/public';
74import { Es2pandaAstNodeType } from '../Es2pandaEnums';
75
76type Visitor = (node: AstNode) => AstNode;
77
78export interface StructVariableMetadata {
79    name: string;
80    properties: string[];
81    modifiers: Es2pandaModifierFlags;
82    hasStateManagementType?: boolean;
83}
84
85export class StructInfo {
86    metadata: Record<string, StructVariableMetadata> = {};
87    initializeBody: AstNode[] = [];
88    updateBody: AstNode[] = [];
89    isReusable: boolean = false;
90    toRecordBody: Property[] = [];
91}
92
93export class GlobalInfo {
94    private _structCollection: Set<string>;
95    private static instance: GlobalInfo;
96    private _structMap: Map<string, StructInfo>;
97
98    private constructor() {
99        this._structCollection = new Set();
100        this._structMap = new Map();
101    }
102
103    public static getInfoInstance(): GlobalInfo {
104        if (!this.instance) {
105            this.instance = new GlobalInfo();
106        }
107        return this.instance;
108    }
109
110    public add(str: string): void {
111        this._structCollection.add(str);
112    }
113
114    public getStructCollection(): Set<string> {
115        return this._structCollection;
116    }
117
118    public getStructInfo(structName: string): StructInfo {
119        const structInfo = this._structMap.get(structName);
120        if (!structInfo) {
121            return new StructInfo();
122        }
123        return structInfo;
124    }
125
126    public setStructInfo(structName: string, info: StructInfo): void {
127        this._structMap.set(structName, info);
128    }
129
130    public reset(): void {
131        this._structMap.clear();
132        this._structCollection.clear();
133    }
134}
135
136// TODO: rethink (remove as)
137function nodeVisitor<T extends AstNode | undefined>(node: T, visitor: Visitor): T {
138    if (node === undefined) {
139        return node;
140    }
141    return visitor(node) as T;
142}
143
144// TODO: rethink (remove as)
145function nodesVisitor<T extends AstNode, TIn extends readonly T[] | undefined>(
146    nodes: TIn,
147    visitor: Visitor
148): T[] | TIn {
149    if (nodes === undefined) {
150        return nodes;
151    }
152    return nodes.map((node) => visitor(node) as T);
153}
154
155let updated: boolean = false;
156
157export function visitEachChild(node: AstNode, visitor: Visitor): AstNode {
158    updated = false;
159    let script: AstNode = node;
160    script = visitETSModule(script, visitor);
161    script = visitDeclaration(script, visitor);
162    script = visitDefinition(script, visitor);
163    script = visitDefinitionBody(script, visitor);
164    script = visitStatement(script, visitor);
165    script = visitForLoopStatement(script, visitor);
166    script = visitOuterExpression(script, visitor);
167    script = visitInnerExpression(script, visitor);
168    script = visitTrivialExpression(script, visitor);
169    script = visitLiteral(script, visitor);
170    // TODO
171    return visitWithoutUpdate(script, visitor);
172}
173
174function visitOuterExpression(node: AstNode, visitor: Visitor): AstNode {
175    if (updated) {
176        return node;
177    } else if (isBlockExpression(node)) {
178        updated = true;
179        return factory.updateBlockExpression(node, nodesVisitor(node.statements, visitor));
180    } else if (isCallExpression(node)) {
181        updated = true;
182        const call = factory.updateCallExpression(
183            node,
184            nodeVisitor(node.expression, visitor),
185            nodesVisitor(node.typeArguments, visitor),
186            nodesVisitor(node.arguments, visitor)
187        );
188        if (!!node.trailingBlock) {
189            call.setTralingBlock(nodeVisitor(node.trailingBlock, visitor));
190        }
191        return call;
192    } else if (isArrowFunctionExpression(node)) {
193        updated = true;
194        return factory.updateArrowFunction(node, nodeVisitor(node.scriptFunction, visitor));
195    } else if (isAssignmentExpression(node)) {
196        updated = true;
197        return factory.updateAssignmentExpression(
198            node,
199            nodeVisitor(node.left as Expression, visitor),
200            node.operatorType,
201            nodeVisitor(node.right as Expression, visitor)
202        );
203    } else if (isETSNewClassInstanceExpression(node)) {
204        updated = true;
205        return factory.updateETSNewClassInstanceExpression(
206            node,
207            node.getTypeRef,
208            nodesVisitor(node.getArguments, visitor)
209        );
210    }
211    if (isArrayExpression(node)) {
212        updated = true;
213        return factory.updateArrayExpression(node, nodesVisitor(node.elements, visitor));
214    }
215    return node;
216}
217
218function visitInnerExpression(node: AstNode, visitor: Visitor): AstNode {
219    if (updated) {
220        return node;
221    }
222    if (isMemberExpression(node)) {
223        updated = true;
224        return factory.updateMemberExpression(
225            node,
226            nodeVisitor(node.object, visitor),
227            nodeVisitor(node.property, visitor),
228            node.kind,
229            node.computed,
230            node.optional
231        );
232    }
233    if (isConditionalExpression(node)) {
234        updated = true;
235        return factory.updateConditionalExpression(
236            node,
237            nodeVisitor(node.test, visitor),
238            nodeVisitor(node.consequent, visitor),
239            nodeVisitor(node.alternate, visitor)
240        );
241    }
242    if (isTSAsExpression(node)) {
243        updated = true;
244        return factory.updateTSAsExpression(
245            node,
246            nodeVisitor(node.expr, visitor),
247            nodeVisitor(node.typeAnnotation, visitor),
248            node.isConst
249        );
250    }
251    if (isObjectExpression(node)) {
252        updated = true;
253        return factory.updateObjectExpression(
254            node,
255            Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION,
256            nodesVisitor(node.properties as Property[], visitor),
257            false
258        );
259    }
260    if (isProperty(node)) {
261        updated = true;
262        return factory.updateProperty(node, node.key, nodeVisitor(node.value, visitor));
263    }
264    // TODO
265    return node;
266}
267
268function visitTrivialExpression(node: AstNode, visitor: Visitor): AstNode {
269    if (updated) {
270        return node;
271    }
272    if (isBinaryExpression(node)) {
273        updated = true;
274        return factory.updateBinaryExpression(
275            node,
276            nodeVisitor(node.left, visitor),
277            nodeVisitor(node.right, visitor),
278            node.operatorType
279        );
280    }
281    // TODO
282    return node;
283}
284
285function visitDeclaration(node: AstNode, visitor: Visitor): AstNode {
286    if (updated) {
287        return node;
288    } else if (isFunctionDeclaration(node)) {
289        updated = true;
290        return factory.updateFunctionDeclaration(
291            node,
292            nodeVisitor(node.scriptFunction, visitor),
293            node.isAnon,
294            node.annotations
295        );
296    } else if (isClassDeclaration(node)) {
297        updated = true;
298        return factory.updateClassDeclaration(node, nodeVisitor(node.definition, visitor));
299    } else if (isStructDeclaration(node)) {
300        updated = true;
301        return factory.updateStructDeclaration(node, nodeVisitor(node.definition, visitor));
302    } else if (isTSInterfaceDeclaration(node)) {
303        updated = true;
304        return factory.updateInterfaceDeclaration(
305            node,
306            nodesVisitor(node.extends, visitor),
307            nodeVisitor(node.id, visitor),
308            nodeVisitor(node.typeParams, visitor),
309            nodeVisitor(node.body, visitor),
310            node.isStatic,
311            // TODO: how do I get it?
312            true
313        );
314    } else if (isVariableDeclaration(node)) {
315        updated = true;
316        return factory.updateVariableDeclaration(
317            node,
318            0,
319            node.declarationKind,
320            nodesVisitor(node.declarators, visitor)
321        );
322    } else if (isTSTypeAliasDeclaration(node)) {
323        updated = true;
324        return factory.updateTSTypeAliasDeclaration(
325            node,
326            node.id,
327            nodeVisitor(node.typeParams, visitor),
328            nodeVisitor(node.typeAnnotation, visitor)
329        );
330    }
331    // TODO
332    return node;
333}
334
335function visitDefinition(node: AstNode, visitor: Visitor): AstNode {
336    if (updated) {
337        return node;
338    }
339    if (isClassDefinition(node)) {
340        updated = true;
341        return factory.updateClassDefinition(
342            node,
343            node.ident,
344            node.typeParams,
345            node.superTypeParams,
346            node.implements,
347            undefined,
348            node.super,
349            nodesVisitor(node.body, visitor),
350            node.modifiers,
351            classDefinitionFlags(node)
352        );
353    }
354    if (isMethodDefinition(node)) {
355        updated = true;
356        return factory.updateMethodDefinition(
357            node,
358            node.kind,
359            node.name,
360            nodeVisitor(node.scriptFunction, visitor),
361            node.modifiers,
362            false
363        );
364    }
365    if (isTSInterfaceBody(node)) {
366        updated = true;
367        return factory.updateInterfaceBody(node, nodesVisitor(node.body, visitor));
368    }
369    if (isVariableDeclarator(node)) {
370        updated = true;
371        return factory.updateVariableDeclarator(
372            node,
373            global.generatedEs2panda._VariableDeclaratorFlag(global.context, node.peer),
374            nodeVisitor(node.name, visitor),
375            nodeVisitor(node.initializer, visitor)
376        );
377    }
378    return node;
379}
380
381function visitStatement(node: AstNode, visitor: Visitor): AstNode {
382    if (updated) {
383        return node;
384    }
385    if (isBlockStatement(node)) {
386        updated = true;
387        return factory.updateBlock(node, nodesVisitor(node.statements, visitor));
388    }
389    if (isExpressionStatement(node)) {
390        updated = true;
391        return factory.updateExpressionStatement(node, nodeVisitor(node.expression, visitor));
392    }
393    if (isIfStatement(node)) {
394        updated = true;
395        return factory.updateIfStatement(
396            node,
397            nodeVisitor(node.test, visitor),
398            nodeVisitor(node.consequent, visitor),
399            nodeVisitor(node.alternate, visitor)
400        );
401    }
402    if (isReturnStatement(node)) {
403        updated = true;
404        return factory.updateReturnStatement(node, nodeVisitor(node.argument, visitor));
405    }
406    if (isTryStatement(node)) {
407        updated = true;
408        return factory.updateTryStatement(
409            node,
410            nodeVisitor(node.block, visitor),
411            nodesVisitor(node.catchClauses, visitor),
412            nodeVisitor(node.finallyBlock, visitor),
413            [],
414            []
415        );
416    }
417    // TODO
418    return node;
419}
420
421function visitForLoopStatement(node: AstNode, visitor: Visitor): AstNode {
422    if (updated) {
423        return node;
424    }
425    if (isForUpdateStatement(node)) {
426        updated = true;
427        return factory.updateForUpdateStatement(
428            node,
429            nodeVisitor(node.init, visitor),
430            nodeVisitor(node.test, visitor),
431            nodeVisitor(node.update, visitor),
432            nodeVisitor(node.body, visitor)
433        );
434    }
435    if (isForInStatement(node)) {
436        updated = true;
437        return factory.updateForInStatement(
438            node,
439            nodeVisitor(node.left, visitor),
440            nodeVisitor(node.right, visitor),
441            nodeVisitor(node.body, visitor)
442        );
443    }
444    if (isForOfStatement(node)) {
445        updated = true;
446        return factory.updateForOfStatement(
447            node,
448            nodeVisitor(node.left, visitor),
449            nodeVisitor(node.right, visitor),
450            nodeVisitor(node.body, visitor),
451            node.isAwait
452        );
453    }
454    return node;
455}
456
457function visitETSModule(node: AstNode, visitor: Visitor): AstNode {
458    if (updated) {
459        return node;
460    }
461    if (isEtsScript(node)) {
462        updated = true;
463        return factory.updateEtsScript(node, nodesVisitor(node.statements, visitor));
464    }
465    return node;
466}
467
468function visitDefinitionBody(node: AstNode, visitor: Visitor): AstNode {
469    if (updated) {
470        return node;
471    }
472    if (isScriptFunction(node)) {
473        updated = true;
474        return factory.updateScriptFunction(
475            node,
476            nodeVisitor(node.body, visitor),
477            factory.createFunctionSignature(
478                nodeVisitor(node.typeParams, visitor),
479                nodesVisitor(node.params, visitor),
480                nodeVisitor(node.returnTypeAnnotation, visitor),
481                node.hasReceiver
482            ),
483            node.flags,
484            node.modifiers
485        );
486    }
487    if (isClassProperty(node)) {
488        updated = true;
489        return factory.updateClassProperty(
490            node,
491            node.key,
492            nodeVisitor(node.value, visitor),
493            node.typeAnnotation,
494            node.modifiers,
495            node.isComputed
496        );
497    }
498    // TODO
499    return node;
500}
501
502function visitLiteral(node: AstNode, visitor: Visitor): AstNode {
503    if (updated) {
504        return node;
505    }
506    if (isTemplateLiteral(node)) {
507        updated = true;
508        return factory.updateTemplateLiteral(
509            node,
510            nodesVisitor(node.quasis, visitor),
511            nodesVisitor(node.expressions, visitor),
512            node.multilineString
513        );
514    }
515    return node;
516}
517
518// TODO: apply this to all nodes that does not require updating
519function visitWithoutUpdate<T extends AstNode>(node: T, visitor: Visitor): T {
520    if (updated) {
521        return node;
522    }
523    if (isImportDeclaration(node)) {
524        nodesVisitor(node.specifiers, visitor);
525    }
526    if (isETSFunctionType(node)) {
527        nodesVisitor(node.params, visitor);
528    }
529    if (isEtsParameterExpression(node)) {
530        nodeVisitor(node.type, visitor);
531    }
532    return node;
533}
534