• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2024-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 { Constant } from '../../core/base/Constant';
17import {
18    ArkInstanceInvokeExpr,
19    ArkNewArrayExpr,
20    ArkNewExpr,
21    ArkStaticInvokeExpr,
22    NormalBinaryOperator
23} from '../../core/base/Expr';
24import { Local } from '../../core/base/Local';
25import {
26    ArkArrayRef,
27    ArkInstanceFieldRef,
28    ArkParameterRef,
29    ArkStaticFieldRef,
30    ClosureFieldRef
31} from '../../core/base/Ref';
32import {
33    ArkAliasTypeDefineStmt,
34    ArkAssignStmt,
35    ArkIfStmt,
36    ArkInvokeStmt,
37    ArkReturnStmt,
38    ArkReturnVoidStmt,
39    ArkThrowStmt,
40    Stmt
41} from '../../core/base/Stmt';
42import { AliasType, ClassType, Type } from '../../core/base/Type';
43import { Value } from '../../core/base/Value';
44import { BasicBlock } from '../../core/graph/BasicBlock';
45import Logger, { LOG_MODULE_TYPE } from '../../utils/logger';
46import { ArkCodeBuffer } from '../ArkStream';
47import { StmtReader } from './SourceBody';
48import { SourceTransformer, TransformerContext } from './SourceTransformer';
49import { CLASS_CATEGORY_COMPONENT, PrinterUtils } from '../base/PrinterUtils';
50import { ValueUtil } from '../../core/common/ValueUtil';
51import { ArkClass, ClassCategory } from '../../core/model/ArkClass';
52import { modifiers2stringArray } from '../../core/model/ArkBaseModel';
53import { ArkMetadataKind, CommentsMetadata } from '../../core/model/ArkMetadata';
54import { ImportInfo } from '../../core/model/ArkImport';
55import { ArkMethod } from '../../core/model/ArkMethod';
56import { Dump } from '../base/BasePrinter';
57
58const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'SourceStmt');
59const IGNOR_TYPES = new Set<string>(['any', 'Map', 'Set']);
60
61export interface StmtPrinterContext extends TransformerContext {
62    getStmtReader(): StmtReader;
63
64    setTempCode(temp: string, code: string): void;
65
66    hasTempVisit(temp: string): boolean;
67
68    setTempVisit(temp: string): void;
69
70    setSkipStmt(stmt: Stmt): void;
71
72    getLocals(): Map<string, Local>;
73
74    defineLocal(local: Local): void;
75
76    isLocalDefined(local: Local): boolean;
77
78    isInDefaultMethod(): boolean;
79}
80
81export abstract class SourceStmt implements Dump {
82    original: Stmt;
83    context: StmtPrinterContext;
84    line: number;
85    text: string = '';
86    transformer: SourceTransformer;
87
88    constructor(context: StmtPrinterContext, original: Stmt) {
89        this.original = original;
90        this.context = context;
91        this.line = original.getOriginPositionInfo().getLineNo();
92        this.transformer = new SourceTransformer(context);
93    }
94
95    public getLine(): number {
96        return this.line;
97    }
98
99    public setLine(line: number): void {
100        this.line = line;
101    }
102
103    public dump(): string {
104        this.beforeDump();
105        let code = this.dumpTs();
106        this.afterDump();
107        return code;
108    }
109
110    protected beforeDump(): void {}
111
112    protected afterDump(): void {}
113
114    protected dumpTs(): string {
115        let content: string[] = [];
116        const commentsMetadata = this.original.getMetadata(ArkMetadataKind.LEADING_COMMENTS);
117        if (commentsMetadata instanceof CommentsMetadata) {
118            const comments = commentsMetadata.getComments();
119            comments.forEach(comment => {
120                content.push(`${this.printer.getIndent()}${comment.content}\n`);
121            });
122        }
123        if (this.text.length > 0) {
124            content.push(`${this.printer.getIndent()}${this.text}\n`);
125        }
126        return content.join('');
127    }
128
129    protected get printer(): ArkCodeBuffer {
130        return this.context.getPrinter();
131    }
132
133    public toString(): string {
134        return this.text;
135    }
136
137    protected setText(text: string): void {
138        this.text = text;
139    }
140
141    protected getIntent(): string {
142        return this.context.getPrinter().getIndent();
143    }
144
145    public abstract transfer2ts(): void;
146
147    protected isLocalTempValue(value: Value): boolean {
148        if (!(value instanceof Local)) {
149            return false;
150        }
151
152        return PrinterUtils.isTemp(value.getName());
153    }
154}
155
156enum AssignStmtDumpType {
157    NORMAL,
158    TEMP_REPLACE,
159    COMPONENT_CREATE,
160}
161
162export class SourceAssignStmt extends SourceStmt {
163    private leftOp: Value = ValueUtil.getUndefinedConst();
164    private rightOp: Value = ValueUtil.getUndefinedConst();
165    private leftCode: string = '';
166    private rightCode: string = '';
167    private dumpType?: AssignStmtDumpType;
168    private leftTypeCode: string;
169
170    constructor(context: StmtPrinterContext, original: ArkAssignStmt) {
171        super(context, original);
172        this.leftTypeCode = '';
173    }
174
175    public transfer2ts(): void {
176        this.leftOp = (this.original as ArkAssignStmt).getLeftOp();
177        this.rightOp = (this.original as ArkAssignStmt).getRightOp();
178
179        if (
180            (this.leftOp instanceof Local && this.leftOp.getName() === 'this') ||
181            (this.rightOp instanceof Constant && this.rightOp.getValue() === 'undefined') ||
182            this.rightOp instanceof ArkParameterRef ||
183            this.rightOp instanceof ClosureFieldRef
184        ) {
185            this.setText('');
186            this.dumpType = AssignStmtDumpType.NORMAL;
187            return;
188        }
189
190        this.leftCode = this.transformer.valueToString(this.leftOp, true);
191
192        if (this.leftOp instanceof Local && this.rightOp instanceof ArkNewExpr) {
193            this.transferRightNewExpr();
194        } else if (this.leftOp instanceof Local && this.rightOp instanceof ArkNewArrayExpr) {
195            this.transferRightNewArrayExpr();
196        } else if (this.rightOp instanceof ArkStaticInvokeExpr && PrinterUtils.isComponentCreate(this.rightOp)) {
197            this.transferRightComponentCreate();
198        } else if (this.rightOp instanceof ArkInstanceInvokeExpr && PrinterUtils.isComponentAttributeInvoke(this.rightOp)) {
199            this.transferRightComponentAttribute();
200        } else {
201            this.rightCode = this.transformer.valueToString(this.rightOp);
202        }
203
204        if (this.isLocalTempValue(this.leftOp)) {
205            this.context.setTempCode((this.leftOp as Local).getName(), this.rightCode);
206        }
207
208        if ((this.leftOp instanceof ArkInstanceFieldRef && this.leftOp.getBase().getName() === 'this') || this.leftOp instanceof ArkStaticFieldRef) {
209            this.context.setTempCode(this.leftOp.getFieldName(), this.rightCode);
210        }
211
212        if (this.dumpType === undefined) {
213            this.setText(`${this.leftCode} = ${this.rightCode}`);
214            this.dumpType = AssignStmtDumpType.TEMP_REPLACE;
215        }
216
217        let leftOpType = this.leftOp.getType();
218        if (leftOpType instanceof ClassType) {
219            let name = leftOpType.getClassSignature().getClassName();
220            if (PrinterUtils.isAnonymousClass(name)) {
221                this.leftTypeCode = 'any';
222            } else {
223                this.leftTypeCode = name;
224            }
225        } else {
226            this.leftTypeCode = this.transformer.typeToString(leftOpType);
227        }
228        if (IGNOR_TYPES.has(this.leftTypeCode)) {
229            this.leftTypeCode = '';
230        }
231    }
232
233    protected beforeDump(): void {
234        if (this.dumpType !== AssignStmtDumpType.TEMP_REPLACE) {
235            return;
236        }
237
238        if (this.context.hasTempVisit(this.leftCode)) {
239            this.setText('');
240            return;
241        } else if (PrinterUtils.isTemp(this.leftCode)) {
242            this.setText(`${this.rightCode};`);
243            return;
244        }
245        if (this.leftOp instanceof Local && this.context.getLocals().has(this.leftOp.getName()) && !this.isLocalTempValue(this.leftOp)) {
246            if (this.context.isLocalDefined(this.leftOp)) {
247                this.setText(`${this.leftCode} = ${this.rightCode};`);
248                return;
249            }
250            let flag = this.leftOp.getConstFlag() ? 'const' : 'let';
251            if (this.context.getArkFile().getExportInfoBy(this.leftCode) && this.context.isInDefaultMethod()) {
252                this.setText(`export ${flag} ${this.leftCode} = ${this.rightCode};`);
253            } else {
254                if (this.leftTypeCode.length > 0) {
255                    this.setText(`${flag} ${this.leftCode}: ${this.leftTypeCode} = ${this.rightCode};`);
256                } else {
257                    this.setText(`${flag} ${this.leftCode} = ${this.rightCode};`);
258                }
259            }
260            this.context.defineLocal(this.leftOp);
261        } else {
262            this.setText(`${this.leftCode} = ${this.rightCode};`);
263        }
264    }
265
266    protected afterDump(): void {
267        if (this.dumpType === AssignStmtDumpType.COMPONENT_CREATE) {
268            this.printer.incIndent();
269        }
270    }
271
272    private getClassOriginType(type: Type): number | undefined {
273        if (!(type instanceof ClassType)) {
274            return undefined;
275        }
276
277        let signature = type.getClassSignature();
278        let cls = this.context.getClass(signature);
279        if (!cls) {
280            return undefined;
281        }
282        return PrinterUtils.getOriginType(cls);
283    }
284
285    /**
286     * temp1 = new Person
287     * temp1.constructor(10)
288     */
289    private transferRightNewExpr(): void {
290        let originType = this.getClassOriginType(this.rightOp.getType());
291        if (this.context.getStmtReader().hasNext()) {
292            let stmt = this.context.getStmtReader().next();
293            let rollback = true;
294            if (stmt instanceof ArkInvokeStmt && (stmt.getInvokeExpr() as ArkInstanceInvokeExpr)) {
295                let instanceInvokeExpr = stmt.getInvokeExpr() as ArkInstanceInvokeExpr;
296                if (
297                    'constructor' === instanceInvokeExpr.getMethodSignature().getMethodSubSignature().getMethodName() &&
298                    instanceInvokeExpr.getBase().getName() === (this.leftOp as Local).getName()
299                ) {
300                    this.handleConstructorInvoke(instanceInvokeExpr, originType);
301                    return;
302                }
303            }
304            if (rollback) {
305                this.context.getStmtReader().rollback();
306            }
307        }
308
309        if (originType === CLASS_CATEGORY_COMPONENT) {
310            this.rightCode = `${this.transformer.typeToString(this.rightOp.getType())}()`;
311        } else if (originType === ClassCategory.TYPE_LITERAL || originType === ClassCategory.OBJECT) {
312            this.rightCode = `${this.transformer.typeToString(this.rightOp.getType())}`;
313        } else {
314            this.rightCode = `new ${this.transformer.typeToString(this.rightOp.getType())}()`;
315        }
316    }
317
318    private handleConstructorInvoke(instanceInvokeExpr: ArkInstanceInvokeExpr, originType?: number): void {
319        let args: string[] = [];
320        instanceInvokeExpr.getArgs().forEach(v => {
321            args.push(this.transformer.valueToString(v));
322        });
323
324        if (originType === CLASS_CATEGORY_COMPONENT) {
325            this.rightCode = `${this.transformer.typeToString(this.rightOp.getType())}(${args.join(', ')})`;
326        } else if (originType === ClassCategory.TYPE_LITERAL || originType === ClassCategory.OBJECT) {
327            this.rightCode = `${this.transformer.literalObjectToString(this.rightOp.getType() as ClassType)}`;
328        } else {
329            this.rightCode = `new ${this.transformer.typeToString(this.rightOp.getType())}(${args.join(', ')})`;
330        }
331    }
332
333    /**
334     * $temp0 = newarray[4]
335     * $temp0[0] = 1
336     * $temp0[1] = 2
337     * $temp0[2] = 3
338     */
339    private transferRightNewArrayExpr(): void {
340        let arrayExpr = new SourceNewArrayExpr(this.rightOp as ArkNewArrayExpr);
341        let localName = (this.leftOp as Local).getName();
342        while (this.context.getStmtReader().hasNext()) {
343            let stmt = this.context.getStmtReader().next();
344            if (stmt instanceof ArkAssignStmt) {
345                let left = stmt.getLeftOp();
346                if (left instanceof ArkArrayRef && left.getBase().getName() === localName) {
347                    arrayExpr.addInitValue(this.transformer.valueToString(stmt.getRightOp()));
348                } else {
349                    this.context.getStmtReader().rollback();
350                    break;
351                }
352            } else {
353                this.context.getStmtReader().rollback();
354                break;
355            }
356        }
357        this.rightCode = arrayExpr.toString();
358    }
359
360    private transferRightComponentCreate(): void {
361        this.rightCode = this.transformer.valueToString(this.rightOp);
362        if (this.context.getStmtReader().hasNext()) {
363            let stmt = this.context.getStmtReader().next();
364            if (stmt instanceof ArkInvokeStmt) {
365                let expr = stmt.getInvokeExpr();
366                if (expr instanceof ArkStaticInvokeExpr && PrinterUtils.isComponentPop(expr)) {
367                    this.setText(`${this.rightCode}`);
368                    this.dumpType = AssignStmtDumpType.NORMAL;
369                    return;
370                }
371            }
372
373            this.context.getStmtReader().rollback();
374        }
375        this.setText(`${this.rightCode} {`);
376        this.dumpType = AssignStmtDumpType.COMPONENT_CREATE;
377    }
378
379    private transferRightComponentAttribute(): void {
380        this.rightCode = this.transformer.valueToString(this.rightOp);
381        this.setText(`${this.rightCode}`);
382        this.dumpType = AssignStmtDumpType.NORMAL;
383    }
384}
385
386export class SourceInvokeStmt extends SourceStmt {
387    constructor(context: StmtPrinterContext, original: ArkInvokeStmt) {
388        super(context, original);
389    }
390
391    public transfer2ts(): void {
392        let invokeExpr = this.original.getInvokeExpr();
393        let code = '';
394        let isAttr = false;
395        if (invokeExpr instanceof ArkStaticInvokeExpr) {
396            if (PrinterUtils.isComponentPop(invokeExpr)) {
397                code = '}';
398                isAttr = true;
399            } else {
400                code = this.transformer.staticInvokeExprToString(invokeExpr);
401                isAttr = PrinterUtils.isComponentIfElseInvoke(invokeExpr);
402            }
403        } else if (invokeExpr instanceof ArkInstanceInvokeExpr) {
404            isAttr = PrinterUtils.isComponentAttributeInvoke(invokeExpr);
405            code = this.transformer.instanceInvokeExprToString(invokeExpr, isAttr);
406        }
407
408        if (code.length > 0 && !isAttr) {
409            this.setText(`${code};`);
410        } else {
411            this.setText(`${code}`);
412        }
413    }
414
415    protected beforeDump(): void {
416        let invokeExpr = this.original.getInvokeExpr();
417        if (
418            (invokeExpr instanceof ArkStaticInvokeExpr && PrinterUtils.isComponentPop(invokeExpr)) ||
419            (invokeExpr instanceof ArkStaticInvokeExpr && PrinterUtils.isComponentIfElseInvoke(invokeExpr))
420        ) {
421            this.printer.decIndent();
422            return;
423        }
424    }
425
426    protected afterDump(): void {
427        let invokeExpr = this.original.getInvokeExpr();
428        if (invokeExpr instanceof ArkStaticInvokeExpr && PrinterUtils.isComponentIfElseInvoke(invokeExpr)) {
429            this.printer.incIndent();
430            return;
431        }
432    }
433}
434
435export class SourceIfStmt extends SourceStmt {
436    constructor(context: StmtPrinterContext, original: ArkIfStmt) {
437        super(context, original);
438    }
439
440    public transfer2ts(): void {
441        let code: string;
442        let expr = (this.original as ArkIfStmt).getConditionExpr();
443        code = `if (${this.transformer.valueToString(expr.getOp1())}`;
444        code += ` ${expr.getOperator()} `;
445        code += `${this.transformer.valueToString(expr.getOp2())}) {`;
446        this.setText(code);
447    }
448
449    protected afterDump(): void {
450        this.printer.incIndent();
451    }
452}
453
454export class SourceWhileStmt extends SourceStmt {
455    block: BasicBlock;
456
457    constructor(context: StmtPrinterContext, original: ArkIfStmt, block: BasicBlock) {
458        super(context, original);
459        this.block = block;
460    }
461
462    protected afterDump(): void {
463        this.printer.incIndent();
464    }
465
466    /**
467     * $temp2 = $temp1.next()
468     * $temp3 = $temp2.done()
469     * if $temp3 === true
470     *  $temp4 = $temp2.value
471     *  $temp5 = <> cast
472     * @returns
473     */
474    private forOf2ts(): boolean {
475        let expr = (this.original as ArkIfStmt).getConditionExpr();
476        let temp3 = expr.getOp1();
477        let op2 = expr.getOp2();
478        let firstStmt = this.context.getStmtReader().first();
479        if (!(firstStmt instanceof ArkAssignStmt)) {
480            return false;
481        }
482
483        if (!(this.isLocalTempValue(temp3) && op2 instanceof Constant && (op2 as Constant).getValue() === 'true')) {
484            return false;
485        }
486
487        let stmt = (temp3 as Local).getDeclaringStmt();
488        if (!(stmt instanceof ArkAssignStmt)) {
489            return false;
490        }
491
492        let done = stmt.getRightOp();
493        if (!(done instanceof ArkInstanceFieldRef)) {
494            return false;
495        }
496
497        if (done.getFieldSignature().toString() !== '@ES2015/BuiltinClass: IteratorResult.done') {
498            return false;
499        }
500
501        let temp2 = done.getBase();
502        if (!(temp2 instanceof Local)) {
503            return false;
504        }
505
506        stmt = temp2.getDeclaringStmt();
507        if (!(stmt instanceof ArkAssignStmt)) {
508            return false;
509        }
510
511        let next = stmt.getRightOp();
512        if (!(next instanceof ArkInstanceInvokeExpr)) {
513            return false;
514        }
515
516        if (next.getMethodSignature().getMethodSubSignature().getMethodName() !== 'next') {
517            return false;
518        }
519
520        let temp1 = next.getBase();
521        if (!(temp1 instanceof Local)) {
522            return false;
523        }
524
525        stmt = temp1.getDeclaringStmt();
526        if (!(stmt instanceof ArkAssignStmt)) {
527            return false;
528        }
529
530        let iterator = stmt.getRightOp();
531        if (!(iterator instanceof ArkInstanceInvokeExpr)) {
532            return false;
533        }
534
535        if (iterator.getMethodSignature().getMethodSubSignature().getMethodName() !== 'Symbol.iterator') {
536            return false;
537        }
538
539        let successors = this.block.getSuccessors();
540        if (successors.length !== 2) {
541            return false;
542        }
543
544        let stmts = successors[0].getStmts();
545        if (stmts.length < 2) {
546            return false;
547        }
548
549        stmt = stmts[1];
550        if (!(stmt instanceof ArkAssignStmt)) {
551            return false;
552        }
553
554        this.context.setSkipStmt(stmts[0]);
555        this.context.setSkipStmt(stmts[1]);
556
557        while (this.context.getStmtReader().hasNext()) {
558            this.context.getStmtReader().next();
559        }
560
561        let v = stmt.getLeftOp() as Local;
562        let valueName = v.getName();
563        if (!this.isLocalTempValue(v)) {
564            this.setText(`for (let ${valueName} of ${this.transformer.valueToString(iterator.getBase())}) {`);
565            this.context.setTempVisit((temp1 as Local).getName());
566            this.context.setTempVisit((temp3 as Local).getName());
567            return true;
568        }
569
570        // iterate map 'for (let [key, value] of map)'
571        let stmtReader = new StmtReader(stmts);
572        stmtReader.next();
573        stmtReader.next();
574
575        let arrayValueNames = [];
576        while (stmtReader.hasNext()) {
577            stmt = stmtReader.next();
578            if (!(stmt instanceof ArkAssignStmt)) {
579                break;
580            }
581            let ref = stmt.getRightOp();
582            if (!(ref instanceof ArkArrayRef)) {
583                break;
584            }
585            if (ref.getBase().getName() !== valueName) {
586                break;
587            }
588            let name = (stmt.getLeftOp() as Local).getName();
589            arrayValueNames.push(name);
590            this.context.setTempVisit(name);
591        }
592
593        this.setText(`for (let [${arrayValueNames.join(', ')}] of ${this.transformer.valueToString(iterator.getBase())}) {`);
594        this.context.setTempVisit((temp3 as Local).getName());
595
596        return true;
597    }
598
599    public transfer2ts(): void {
600        if (this.forOf2ts()) {
601            return;
602        }
603        let code: string;
604        let expr = (this.original as ArkIfStmt).getConditionExpr();
605        code = `while (${this.valueToString(expr.getOp1())}`;
606        code += ` ${expr.getOperator().trim()} `;
607        code += `${this.valueToString(expr.getOp2())}) {`;
608        this.setText(code);
609    }
610
611    protected valueToString(value: Value): string {
612        if (!(value instanceof Local)) {
613            return this.transformer.valueToString(value);
614        }
615
616        for (const stmt of this.block.getStmts()) {
617            if (!(stmt instanceof ArkAssignStmt)) {
618                continue;
619            }
620            if (PrinterUtils.isDeIncrementStmt(stmt, NormalBinaryOperator.Addition) && (stmt.getLeftOp() as Local).getName() === value.getName()) {
621                this.context.setSkipStmt(stmt);
622                return `${value.getName()}++`;
623            }
624
625            if (PrinterUtils.isDeIncrementStmt(stmt, NormalBinaryOperator.Subtraction) && (stmt.getLeftOp() as Local).getName() === value.getName()) {
626                this.context.setSkipStmt(stmt);
627                return `${value.getName()}--`;
628            }
629        }
630
631        return this.transformer.valueToString(value);
632    }
633}
634
635export class SourceForStmt extends SourceWhileStmt {
636    incBlock: BasicBlock;
637
638    constructor(context: StmtPrinterContext, original: ArkIfStmt, block: BasicBlock, incBlock: BasicBlock) {
639        super(context, original, block);
640        this.incBlock = incBlock;
641    }
642
643    public transfer2ts(): void {
644        let code: string;
645        let expr = (this.original as ArkIfStmt).getConditionExpr();
646        code = `for (; ${this.transformer.valueToString(expr.getOp1())}`;
647        code += ` ${expr.getOperator().trim()} `;
648        code += `${this.transformer.valueToString(expr.getOp2())}; `;
649
650        let stmtReader = new StmtReader(this.incBlock.getStmts());
651        while (stmtReader.hasNext()) {
652            let sourceStmt = stmt2SourceStmt(this.context, stmtReader.next());
653            sourceStmt.transfer2ts();
654            code += sourceStmt.toString();
655            if (stmtReader.hasNext()) {
656                code += ', ';
657            }
658        }
659        code += `) {`;
660        this.setText(code);
661    }
662}
663
664export class SourceDoStmt extends SourceStmt {
665    constructor(context: StmtPrinterContext, stmt: Stmt) {
666        super(context, stmt);
667    }
668
669    public transfer2ts(): void {
670        this.setText('do {');
671    }
672
673    protected afterDump(): void {
674        this.printer.incIndent();
675    }
676}
677
678export class SourceDoWhileStmt extends SourceWhileStmt {
679    constructor(context: StmtPrinterContext, stmt: ArkIfStmt, block: BasicBlock) {
680        super(context, stmt, block);
681    }
682
683    public transfer2ts(): void {
684        let code: string;
685        let expr = (this.original as ArkIfStmt).getConditionExpr();
686        code = `} while (${this.valueToString(expr.getOp1())}`;
687        code += ` ${expr.getOperator().trim()} `;
688        code += `${this.valueToString(expr.getOp2())})`;
689        this.setText(code);
690    }
691
692    protected beforeDump(): void {
693        this.printer.decIndent();
694    }
695
696    protected afterDump(): void {}
697}
698
699export class SourceElseStmt extends SourceStmt {
700    constructor(context: StmtPrinterContext, original: Stmt) {
701        super(context, original);
702    }
703
704    public transfer2ts(): void {
705        this.setText('} else {');
706    }
707
708    protected beforeDump(): void {
709        this.printer.decIndent();
710    }
711
712    protected afterDump(): void {
713        this.printer.incIndent();
714    }
715}
716
717export class SourceContinueStmt extends SourceStmt {
718    constructor(context: StmtPrinterContext, original: Stmt) {
719        super(context, original);
720    }
721
722    // trans 2 break or continue
723    public transfer2ts(): void {
724        this.setText('continue;');
725    }
726}
727
728export class SourceBreakStmt extends SourceStmt {
729    constructor(context: StmtPrinterContext, original: Stmt) {
730        super(context, original);
731    }
732
733    // trans 2 break or continue
734    public transfer2ts(): void {
735        this.setText('break;');
736    }
737}
738
739export class SourceReturnStmt extends SourceStmt {
740    constructor(context: StmtPrinterContext, original: ArkReturnStmt) {
741        super(context, original);
742    }
743
744    public transfer2ts(): void {
745        this.setText(`return ${this.transformer.valueToString((this.original as ArkReturnStmt).getOp())};`);
746    }
747}
748
749export class SourceReturnVoidStmt extends SourceStmt {
750    constructor(context: StmtPrinterContext, original: ArkReturnVoidStmt) {
751        super(context, original);
752    }
753
754    public transfer2ts(): void {
755        if (this.original.getOriginPositionInfo().getLineNo() <= 0) {
756            this.setText('');
757        } else {
758            this.setText('return;');
759        }
760    }
761}
762
763export class SourceCompoundEndStmt extends SourceStmt {
764    constructor(context: StmtPrinterContext, stmt: Stmt, text: string) {
765        super(context, stmt);
766        this.setText(text);
767    }
768
769    public transfer2ts(): void {}
770
771    protected beforeDump(): void {
772        this.printer.decIndent();
773    }
774}
775
776export class SourceCommonStmt extends SourceStmt {
777    constructor(context: StmtPrinterContext, stmt: Stmt) {
778        super(context, stmt);
779    }
780
781    public transfer2ts(): void {
782        this.setText(this.original.toString());
783    }
784}
785
786export class SourceThrowStmt extends SourceStmt {
787    constructor(context: StmtPrinterContext, original: ArkThrowStmt) {
788        super(context, original);
789    }
790
791    public transfer2ts(): void {
792        this.setText(`throw ${this.transformer.valueToString((this.original as ArkThrowStmt).getOp())};`);
793    }
794}
795
796export class SourceTypeAliasStmt extends SourceStmt {
797    aliasType: AliasType;
798    constructor(context: StmtPrinterContext, original: Stmt, aliasType: AliasType) {
799        super(context, original);
800        this.aliasType = aliasType;
801    }
802
803    public transfer2ts(): void {
804        let modifiersArray: string[] = modifiers2stringArray(this.aliasType.getModifiers());
805        let modifier = modifiersArray.length > 0 ? `${modifiersArray.join(' ')} ` : '';
806
807        const expr = (this.original as ArkAliasTypeDefineStmt).getAliasTypeExpr();
808        let typeOf = expr.getTransferWithTypeOf() ? 'typeof ' : '';
809        let realGenericTypes = expr.getRealGenericTypes() ? `<${expr.getRealGenericTypes()!.join(', ')}>` : '';
810        let genericTypes = this.aliasType.getGenericTypes() ? `<${this.transformer.typeArrayToString(this.aliasType.getGenericTypes()!)}>` : '';
811
812        let typeObject = expr.getOriginalObject();
813        if (typeObject instanceof Type) {
814            if (typeObject instanceof AliasType) {
815                this.setText(`${modifier}type ${this.aliasType.getName()}${genericTypes} = ${typeOf}${typeObject.getName()}${realGenericTypes};`);
816            } else {
817                this.setText(
818                    `${modifier}type ${this.aliasType.getName()}${genericTypes} = ${typeOf}${this.transformer.typeToString(typeObject)}${realGenericTypes};`
819                );
820            }
821            return;
822        }
823        if (typeObject instanceof ImportInfo) {
824            let exprStr = `import('${typeObject.getFrom()}')`;
825            if (typeObject.getImportClauseName() !== '') {
826                exprStr = `${exprStr}.${typeObject.getImportClauseName()}`;
827            }
828            this.setText(`${modifier}type ${this.aliasType.getName()}${genericTypes} = ${typeOf}${exprStr}${realGenericTypes};`);
829            return;
830        }
831        if (typeObject instanceof Local) {
832            this.setText(
833                `${modifier}type ${this.aliasType.getName()}${genericTypes} = ${typeOf}${this.transformer.valueToString(typeObject)}${realGenericTypes};`
834            );
835            return;
836        }
837        if (typeObject instanceof ArkClass) {
838            let classTS = this.generateClassTS(typeObject);
839            this.setText(`${modifier}type ${this.aliasType.getName()}${genericTypes} = ${typeOf}${classTS}${realGenericTypes};`);
840            return;
841        }
842        if (typeObject instanceof ArkMethod) {
843            this.setText(`${modifier}type ${this.aliasType.getName()}${genericTypes} = ${typeOf}${typeObject.getName()}${realGenericTypes};`);
844            return;
845        }
846        this.setText(`${modifier}type ${this.aliasType.getName()}${genericTypes} = ${typeOf}${typeObject.getName()}${realGenericTypes};`);
847    }
848
849    private generateClassTS(arkClass: ArkClass): string {
850        let res = '';
851        let classType = new ClassType(arkClass.getSignature());
852        if (arkClass.getCategory() === ClassCategory.TYPE_LITERAL || arkClass.getCategory() === ClassCategory.OBJECT) {
853            res = this.transformer.literalObjectToString(classType);
854        } else {
855            res = this.transformer.typeToString(classType);
856        }
857        return res;
858    }
859}
860
861export class SourceTryStmt extends SourceStmt {
862    constructor(context: StmtPrinterContext, stmt: Stmt) {
863        super(context, stmt);
864    }
865
866    public transfer2ts(): void {
867        this.setText('try {');
868    }
869
870    protected afterDump(): void {
871        this.printer.incIndent();
872    }
873}
874
875export class SourceCatchStmt extends SourceStmt {
876    block: BasicBlock | undefined;
877    constructor(context: StmtPrinterContext, stmt: Stmt, block?: BasicBlock) {
878        super(context, stmt);
879        this.block = block;
880    }
881
882    public transfer2ts(): void {
883        if (this.block) {
884            let stmt = this.block!.getStmts()[0];
885            if (stmt instanceof ArkAssignStmt) {
886                if (stmt.getLeftOp() instanceof Local) {
887                    let name = (stmt.getLeftOp() as Local).getName();
888                    this.setText(`} catch (${name}) {`);
889                    this.context.setSkipStmt(stmt);
890                    return;
891                }
892            }
893        }
894        this.setText('} catch (e) {');
895    }
896
897    protected beforeDump(): void {
898        this.printer.decIndent();
899    }
900
901    protected afterDump(): void {
902        this.printer.incIndent();
903    }
904}
905
906export class SourceFinallyStmt extends SourceStmt {
907    constructor(context: StmtPrinterContext, stmt: Stmt) {
908        super(context, stmt);
909    }
910
911    public transfer2ts(): void {
912        this.setText('} finally {');
913    }
914
915    protected beforeDump(): void {
916        this.printer.decIndent();
917    }
918
919    protected afterDump(): void {
920        this.printer.incIndent();
921    }
922}
923
924export class SourceNewArrayExpr {
925    expr: ArkNewArrayExpr;
926    values: string[];
927
928    constructor(expr: ArkNewArrayExpr) {
929        this.expr = expr;
930        this.values = [];
931    }
932
933    public addInitValue(value: string): void {
934        this.values.push(value);
935    }
936
937    public toString(): string {
938        return `[${this.values.join(', ')}]`;
939    }
940}
941
942export function stmt2SourceStmt(context: StmtPrinterContext, stmt: Stmt): SourceStmt {
943    if (stmt instanceof ArkAssignStmt) {
944        return new SourceAssignStmt(context, stmt);
945    }
946    if (stmt instanceof ArkInvokeStmt) {
947        return new SourceInvokeStmt(context, stmt);
948    }
949    if (stmt instanceof ArkReturnVoidStmt) {
950        return new SourceReturnVoidStmt(context, stmt);
951    }
952    if (stmt instanceof ArkReturnStmt) {
953        return new SourceReturnStmt(context, stmt);
954    }
955    if (stmt instanceof ArkThrowStmt) {
956        return new SourceThrowStmt(context, stmt);
957    }
958    if (stmt instanceof ArkAliasTypeDefineStmt) {
959        return new SourceTypeAliasStmt(context, stmt, stmt.getAliasType());
960    }
961    logger.info(`stmt2SourceStmt ${stmt.constructor} not support.`);
962    return new SourceCommonStmt(context, stmt);
963}
964