• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}