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}