• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 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 } from "./compiler";
19import { CompilerDriver } from "./compilerDriver";
20import { NodeKind } from "./debuginfo";
21import { PandaGen } from "./pandagen";
22import { Recorder } from "./recorder";
23import {
24    FuncDecl,
25    FunctionScope,
26    GlobalScope,
27    LocalScope,
28    ModuleScope,
29    ModuleVarKind,
30    Scope,
31    VarDecl,
32    VariableScope
33} from "./scope";
34import { ModuleVariable } from "./variable";
35
36export function hoisting(rootNode: ts.SourceFile | ts.FunctionLikeDeclaration, pandaGen: PandaGen,
37    recorder: Recorder, compiler: Compiler): void {
38    let variableScope = <VariableScope>recorder.getScopeOfNode(rootNode);
39    let hoistDecls = recorder.getHoistDeclsOfScope(variableScope);
40
41    hoistDecls ?.forEach((decl) => {
42        if (decl instanceof VarDecl) {
43            hoistVar(decl, variableScope, pandaGen);
44        } else if (decl instanceof FuncDecl) {
45            let compilerDriver = compiler.getCompilerDriver();
46            hoistFunction(decl, variableScope, pandaGen, compiler, compilerDriver);
47        } else {
48            throw new Error("Wrong declaration type to be hoisted");
49        }
50    });
51}
52
53export function hoistVar(decl: VarDecl, scope: Scope, pandaGen: PandaGen): void {
54    let name = decl.name;
55
56    if (scope instanceof GlobalScope) {
57        pandaGen.loadAccumulator(decl.node, getVregisterCache(pandaGen, CacheList.UNDEFINED));
58        pandaGen.storeGlobalVar(decl.node, name);
59    } else if (scope instanceof FunctionScope || scope instanceof ModuleScope) {
60        let v: ModuleVariable = <ModuleVariable>(scope.findLocal(name)!);
61        pandaGen.loadAccumulator(NodeKind.FIRST_NODE_OF_FUNCTION, getVregisterCache(pandaGen, CacheList.UNDEFINED));
62        if (decl.isModule !== ModuleVarKind.NOT) {
63            pandaGen.storeModuleVariable(NodeKind.FIRST_NODE_OF_FUNCTION, v);
64        } else {
65            pandaGen.storeAccToLexEnv(NodeKind.FIRST_NODE_OF_FUNCTION, scope, 0, v, true);
66        }
67    } else {
68        throw new Error("Wrong scope to hoist");
69    }
70}
71
72export function hoistFunction(decl: FuncDecl, scope: Scope, pandaGen: PandaGen, compiler: Compiler, compilerDriver: CompilerDriver): void {
73    let funcName = decl.name;
74    let internalName = compilerDriver.getFuncInternalName(<ts.FunctionLikeDeclaration>decl.node, compiler.getRecorder());
75    let env = compiler.getCurrentEnv();
76
77    if (scope instanceof GlobalScope) {
78        pandaGen.defineFunction(NodeKind.FIRST_NODE_OF_FUNCTION, <ts.FunctionDeclaration>decl.node, internalName);
79        pandaGen.storeGlobalVar(NodeKind.FIRST_NODE_OF_FUNCTION, funcName);
80    } else if ((scope instanceof FunctionScope) || (scope instanceof LocalScope) || (scope instanceof ModuleScope)) {
81        let v: ModuleVariable = <ModuleVariable>(scope.findLocal(funcName)!);
82        pandaGen.defineFunction(NodeKind.FIRST_NODE_OF_FUNCTION, <ts.FunctionDeclaration>decl.node, internalName);
83        if (decl.isModule !== ModuleVarKind.NOT) {
84            pandaGen.storeModuleVariable(NodeKind.FIRST_NODE_OF_FUNCTION, v);
85        } else {
86            pandaGen.storeAccToLexEnv(NodeKind.FIRST_NODE_OF_FUNCTION, scope, 0, v, true);
87        }
88    } else {
89        throw new Error("Wrong scope to hoist");
90    }
91}
92
93// this function is called when hoisting function inside blocks
94export function hoistFunctionInBlock(scope: Scope, pandaGen: PandaGen, strictMode: boolean, compiler: Compiler): void {
95    let decls = scope.getDecls();
96    let funcToHoist = new Array<FuncDecl>();
97    for (let i = 0; i < decls.length; i++) {
98        if (decls[i] instanceof FuncDecl) {
99            funcToHoist.push(<FuncDecl>decls[i]);
100        }
101    }
102
103    if (strictMode) {
104        funcToHoist.forEach(func => {
105            let compilerDriver = compiler.getCompilerDriver();
106            hoistFunction(func, scope, pandaGen, compiler, compilerDriver);
107        });
108    }
109}
110