• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2022 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 * as ts from "typescript";
17import { CacheList, getVregisterCache } from "../base/vregisterCache";
18import { Compiler, ControlFlowChange } from "../compiler";
19import { AsyncFunctionBuilder } from "../function/asyncFunctionBuilder";
20import { AsyncGeneratorFunctionBuilder } from "../function/asyncGeneratorFunctionBuilder";
21import { Label, VReg } from "../irnodes";
22import * as jshelpers from "../jshelpers";
23import { checkValidUseSuperBeforeSuper } from "./classStatement";
24
25export function compileReturnStatement(stmt: ts.ReturnStatement, compiler: Compiler) {
26    let pandaGen = compiler.getPandaGen();
27    let returnValue = pandaGen.getTemp();
28
29    if (isReturnInDerivedCtor(stmt)) {
30        compileReturnInDerivedCtor(stmt, returnValue, compiler);
31    } else {
32        compileNormalReturn(stmt, returnValue, compiler);
33    }
34    pandaGen.freeTemps(returnValue);
35}
36
37function compileReturnInDerivedCtor(stmt: ts.ReturnStatement, returnValue: VReg, compiler: Compiler) {
38    let pandaGen = compiler.getPandaGen();
39    let expr = stmt.expression;
40
41    let need2CheckSuper = pandaGen.getTemp();
42
43    if (!expr) {
44        pandaGen.moveVreg(stmt, need2CheckSuper, getVregisterCache(pandaGen, CacheList.True));
45    } else {
46        if (ts.isCallExpression(expr) && expr.expression.kind == ts.SyntaxKind.SuperKeyword) {
47            compileNormalReturn(stmt, returnValue, compiler);
48            pandaGen.freeTemps(need2CheckSuper);
49            return;
50        }
51
52        if (expr.kind == ts.SyntaxKind.ThisKeyword) {
53            pandaGen.moveVreg(stmt, need2CheckSuper, getVregisterCache(pandaGen, CacheList.True));
54        } else {
55            compiler.compileExpression(expr);
56            pandaGen.binary(stmt, ts.SyntaxKind.EqualsEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.undefined));
57            pandaGen.storeAccumulator(stmt, need2CheckSuper);
58        }
59    }
60
61    let compile = new Label();
62    let notCompile = new Label();
63    pandaGen.loadAccumulator(stmt, need2CheckSuper);
64    pandaGen.condition(stmt, ts.SyntaxKind.ExclamationEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.False), compile);
65
66    // load this
67    let thisReg = pandaGen.getTemp();
68    compiler.getThis(stmt, thisReg);
69    pandaGen.loadAccumulator(stmt, thisReg);
70    pandaGen.branch(stmt, notCompile);
71
72    // compile return expression
73    pandaGen.label(stmt, compile);
74    if (expr) {
75        compiler.compileExpression(expr);
76    } else {
77        pandaGen.loadAccumulator(stmt, getVregisterCache(pandaGen, CacheList.undefined));
78    }
79
80    pandaGen.label(stmt, notCompile);
81    pandaGen.storeAccumulator(stmt, returnValue);
82
83    compiler.compileFinallyBeforeCFC(
84        undefined,
85        ControlFlowChange.Break,
86        undefined
87    );
88
89    let returnLabel = new Label();
90    let normalLabel = new Label();
91    pandaGen.loadAccumulator(stmt, need2CheckSuper);
92    pandaGen.condition(stmt, ts.SyntaxKind.ExclamationEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.False), normalLabel);
93    // check if super has been called
94    checkValidUseSuperBeforeSuper(compiler, stmt);
95    pandaGen.branch(stmt, returnLabel);
96
97    pandaGen.label(stmt, normalLabel);
98    // load returnValue to acc
99    pandaGen.loadAccumulator(stmt, returnValue);
100
101    pandaGen.label(stmt, returnLabel);
102    pandaGen.return(stmt);
103
104    pandaGen.freeTemps(need2CheckSuper, thisReg);
105}
106
107function compileNormalReturn(stmt: ts.ReturnStatement, returnValue: VReg, compiler: Compiler) {
108    let expr = stmt.expression;
109    let pandaGen = compiler.getPandaGen();
110    let empty : boolean = false;
111
112    if (expr) {
113        compiler.compileExpression(expr);
114    } else {
115        empty = true;
116        pandaGen.loadAccumulator(stmt, getVregisterCache(pandaGen, CacheList.undefined));
117    }
118    pandaGen.storeAccumulator(stmt, returnValue);
119
120    compiler.compileFinallyBeforeCFC(
121        undefined,
122        ControlFlowChange.Break,
123        undefined
124    );
125
126    pandaGen.loadAccumulator(stmt, returnValue);
127    compiler.getFuncBuilder().explicitReturn(stmt, empty);
128}
129
130function isReturnInDerivedCtor(stmt: ts.ReturnStatement) {
131    let funcNode = jshelpers.getContainingFunctionDeclaration(stmt);
132    if (!funcNode || !ts.isConstructorDeclaration(funcNode)) {
133        return false;
134    }
135
136    if (funcNode && funcNode.parent) {
137        let classNode = <ts.ClassLikeDeclaration>funcNode.parent;
138        if (classNode.heritageClauses) {
139            return true;
140        }
141    }
142
143    return false;
144}