1/* 2 * Copyright (c) 2021 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 { isMemberExpression } from "../base/util"; 18import { CacheList, getVregisterCache } from "../base/vregisterCache"; 19import { Compiler } from "../compiler"; 20import { VReg } from "../irnodes"; 21import { compileSuperCall, compileSuperProperty } from "../statement/classStatement"; 22import { createArrayFromElements } from "./arrayLiteralExpression"; 23import { getObjAndProp } from "./memberAccessExpression"; 24 25 26// @ts-ignore 27export function compileCallExpression(expr: ts.CallExpression, compiler: Compiler, inTailPos?: boolean): void { 28 let pandaGen = compiler.getPandaGen(); 29 30 let innerExpression = ts.skipPartiallyEmittedExpressions(expr.expression); 31 32 if (innerExpression.kind === ts.SyntaxKind.ImportKeyword) { 33 compiler.compileExpression(expr.arguments[0]); 34 pandaGen.dynamicImportCall(expr); 35 return; 36 } 37 38 if (ts.isCallExpression(innerExpression) || ts.isNewExpression(innerExpression)) { 39 let processed = compiler.compileFunctionReturnThis(<ts.NewExpression | ts.CallExpression>innerExpression); 40 if (processed) { 41 return; 42 } 43 } 44 45 if (innerExpression.kind === ts.SyntaxKind.SuperKeyword) { 46 let args: VReg[] = []; 47 let hasSpread = emitCallArguments(compiler, expr, args); 48 compileSuperCall(compiler, expr, args, hasSpread); 49 pandaGen.freeTemps(...args); 50 return; 51 } 52 53 let { arguments: args, passThis: passThis } = getHiddenParameters(innerExpression, compiler); 54 55 // compile arguments of function call 56 emitCall(expr, args, passThis, compiler); 57 pandaGen.freeTemps(...args); 58} 59 60export function getHiddenParameters(expr: ts.Expression, compiler: Compiler) { 61 let pandaGen = compiler.getPandaGen(); 62 let passThis = false; 63 let args: VReg[] = []; 64 let funcReg = pandaGen.getTemp(); 65 if (isMemberExpression(expr)) { 66 passThis = true; 67 let thisReg = pandaGen.getTemp(); 68 let propReg = pandaGen.getTemp(); 69 // @ts-ignore 70 let { obj: obj, prop: prop } = getObjAndProp(<ts.PropertyAccessExpression | ts.ElementAccessExpression>expr, thisReg, propReg, compiler); 71 72 if ((<ts.PropertyAccessExpression | ts.ElementAccessExpression>expr).expression.kind === ts.SyntaxKind.SuperKeyword) { 73 compileSuperProperty(compiler, expr, thisReg, prop); 74 } else { 75 pandaGen.loadObjProperty( 76 ts.isPropertyAccessExpression(expr) ? expr.name : (<ts.ElementAccessExpression>expr).argumentExpression, 77 thisReg, 78 prop 79 ); 80 } 81 pandaGen.storeAccumulator(expr, funcReg); 82 args.push(...[funcReg, thisReg]); 83 84 pandaGen.freeTemps(propReg); 85 } else { 86 compiler.compileExpression(expr); 87 pandaGen.storeAccumulator(expr, funcReg); 88 args.push(funcReg); 89 } 90 return { arguments: args, passThis: passThis }; 91} 92 93function emitCallArguments(compiler: Compiler, expr: ts.CallExpression, args: VReg[]): boolean { 94 let pandaGen = compiler.getPandaGen(); 95 let hasSpread = false; 96 for (let i = 0; i < expr.arguments.length; i++) { 97 let argument = expr.arguments[i]; 98 hasSpread = ts.isSpreadElement(argument) ? true : false; 99 if (hasSpread) { 100 break; 101 } 102 } 103 104 if (!hasSpread) { 105 expr.arguments.forEach((argExpr: ts.Expression) => { 106 let arg = pandaGen.getTemp(); 107 compiler.compileExpression(argExpr); 108 pandaGen.storeAccumulator(argExpr, arg); 109 args.push(arg); 110 }); 111 } 112 113 return hasSpread; 114} 115 116export function emitCall(expr: ts.CallExpression, args: VReg[], passThis: boolean, compiler: Compiler): void { 117 let pandaGen = compiler.getPandaGen(); 118 let hasSpread = emitCallArguments(compiler, expr, args); 119 let callee = expr.expression; 120 let debugNode = undefined; 121 switch (callee.kind) { 122 case ts.SyntaxKind.ElementAccessExpression: { 123 debugNode = (<ts.ElementAccessExpression>callee).argumentExpression; 124 break; 125 } 126 case ts.SyntaxKind.PropertyAccessExpression: { 127 debugNode = (<ts.PropertyAccessExpression>callee).name; 128 break; 129 } 130 default: { 131 debugNode = expr; 132 } 133 } 134 135 if (!hasSpread) { 136 pandaGen.call(debugNode, [...args], passThis); 137 return; 138 } 139 140 // spread argument exist 141 let calleeReg = args[0]; 142 let thisReg = passThis ? args[1] : getVregisterCache(pandaGen, CacheList.UNDEFINED); 143 let argArray = pandaGen.getTemp(); 144 createArrayFromElements(expr, compiler, <ts.NodeArray<ts.Expression>>expr.arguments, argArray); 145 pandaGen.callSpread(debugNode, calleeReg, thisReg, argArray); 146 pandaGen.freeTemps(argArray); 147}