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