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 * as astutils from "./astutils"; 18import { isAnonymousFunctionDefinition } from "./base/util"; 19import { CmdOptions } from "./cmdOptions"; 20import { CompilerDriver } from "./compilerDriver"; 21import { DiagnosticCode, DiagnosticError } from "./diagnostic"; 22import { findOuterNodeOfParenthesis } from "./expression/parenthesizedExpression"; 23import * as jshelpers from "./jshelpers"; 24import { LOGD } from "./log"; 25import { ModuleStmt } from "./modules"; 26import { 27 CatchParameter, 28 ClassDecl, 29 ConstDecl, 30 Decl, 31 FuncDecl, 32 FunctionParameter, 33 FunctionScope, 34 GlobalScope, 35 LetDecl, 36 LocalScope, 37 LoopScope, 38 ModuleScope, 39 Scope, 40 VarDecl, 41 VariableScope 42} from "./scope"; 43import { 44 AddCtor2Class, 45 getClassNameForConstructor, 46 extractCtorOfClass 47} from "./statement/classStatement"; 48import { checkSyntaxError } from "./syntaxChecker"; 49import { isGlobalIdentifier } from "./syntaxCheckHelper"; 50import { TypeChecker } from "./typeChecker"; 51import { VarDeclarationKind } from "./variable"; 52import { TypeRecorder } from "./typeRecorder"; 53import { PandaGen } from "./pandagen"; 54 55export class Recorder { 56 node: ts.Node; 57 scope: Scope; 58 compilerDriver: CompilerDriver; 59 recordType: boolean; 60 private scopeMap: Map<ts.Node, Scope> = new Map<ts.Node, Scope>(); 61 private hoistMap: Map<Scope, Decl[]> = new Map<Scope, Decl[]>(); 62 private parametersMap: Map<ts.FunctionLikeDeclaration, FunctionParameter[]> = new Map<ts.FunctionLikeDeclaration, FunctionParameter[]>(); 63 private funcNameMap: Map<string, number>; 64 private class2Ctor: Map<ts.ClassLikeDeclaration, ts.ConstructorDeclaration> = new Map<ts.ClassLikeDeclaration, ts.ConstructorDeclaration>(); 65 private importStmts: Array<ModuleStmt> = []; 66 private exportStmts: Array<ModuleStmt> = []; 67 private defaultUsed: boolean = false; 68 private isTsFile: boolean; 69 private syntaxCheckStatus: boolean; 70 71 constructor(node: ts.Node, scope: Scope, compilerDriver: CompilerDriver, recordType: boolean, isTsFile: boolean, syntaxCheckStatus: boolean) { 72 this.node = node; 73 this.scope = scope; 74 this.compilerDriver = compilerDriver; 75 this.recordType = recordType; 76 this.funcNameMap = new Map<string, number>(); 77 this.funcNameMap.set("main", 1); 78 this.isTsFile = isTsFile; 79 this.syntaxCheckStatus = syntaxCheckStatus; 80 } 81 82 record() { 83 this.setParent(this.node); 84 this.setScopeMap(this.node, this.scope); 85 this.recordInfo(this.node, this.scope); 86 if (this.recordType) { 87 TypeRecorder.getInstance().setTypeSummary(); 88 if (CmdOptions.enableTypeLog()) { 89 TypeRecorder.getInstance().getLog(); 90 } 91 } else { 92 PandaGen.clearLiteralArrayBuffer(); 93 } 94 return this.node; 95 } 96 97 getCtorOfClass(node: ts.ClassLikeDeclaration) { 98 return this.class2Ctor.get(node); 99 } 100 101 setCtorOfClass(node: ts.ClassLikeDeclaration, ctor: ts.ConstructorDeclaration) { 102 if (!this.class2Ctor.has(node)) { 103 this.class2Ctor.set(node, ctor); 104 } 105 } 106 107 private setParent(node: ts.Node) { 108 node.forEachChild(childNode => { 109 if (!this.isTsFile || childNode!.parent == undefined || childNode.parent.kind != node.kind) { 110 childNode = jshelpers.setParent(childNode, node)!; 111 let originNode = ts.getOriginalNode(childNode); 112 childNode = ts.setTextRange(childNode, originNode); 113 } 114 this.setParent(childNode); 115 }); 116 } 117 118 private recordInfo(node: ts.Node, scope: Scope) { 119 node.forEachChild(childNode => { 120 if (this.syntaxCheckStatus) { 121 checkSyntaxError(childNode); 122 } 123 switch (childNode.kind) { 124 case ts.SyntaxKind.FunctionExpression: 125 case ts.SyntaxKind.MethodDeclaration: 126 case ts.SyntaxKind.Constructor: 127 case ts.SyntaxKind.GetAccessor: 128 case ts.SyntaxKind.SetAccessor: 129 case ts.SyntaxKind.ArrowFunction: { 130 let functionScope = this.buildVariableScope(scope, <ts.FunctionLikeDeclaration>childNode); 131 this.recordOtherFunc(<ts.FunctionLikeDeclaration>childNode, functionScope); 132 this.recordInfo(childNode, functionScope); 133 break; 134 } 135 case ts.SyntaxKind.FunctionDeclaration: { 136 let functionScope = this.buildVariableScope(scope, <ts.FunctionLikeDeclaration>childNode); 137 this.recordFuncDecl(<ts.FunctionDeclaration>childNode, scope); 138 if (this.recordType) { 139 TypeChecker.getInstance().formatNodeType(childNode); 140 } 141 this.recordInfo(childNode, functionScope); 142 break; 143 } 144 case ts.SyntaxKind.Block: 145 case ts.SyntaxKind.IfStatement: 146 case ts.SyntaxKind.SwitchStatement: 147 case ts.SyntaxKind.LabeledStatement: 148 case ts.SyntaxKind.ThrowStatement: 149 case ts.SyntaxKind.TryStatement: 150 case ts.SyntaxKind.CatchClause: { 151 let localScope = new LocalScope(scope); 152 this.setScopeMap(childNode, localScope); 153 this.recordInfo(childNode, localScope); 154 break; 155 } 156 case ts.SyntaxKind.DoStatement: 157 case ts.SyntaxKind.WhileStatement: 158 case ts.SyntaxKind.ForStatement: 159 case ts.SyntaxKind.ForInStatement: 160 case ts.SyntaxKind.ForOfStatement: { 161 let loopScope: LoopScope = new LoopScope(scope);; 162 this.setScopeMap(childNode, loopScope); 163 this.recordInfo(childNode, loopScope); 164 break; 165 } 166 case ts.SyntaxKind.ClassDeclaration: 167 case ts.SyntaxKind.ClassExpression: { 168 this.recordClassInfo(<ts.ClassLikeDeclaration>childNode, scope); 169 if (this.recordType) { 170 TypeChecker.getInstance().formatNodeType(childNode); 171 } 172 break; 173 } 174 case ts.SyntaxKind.InterfaceDeclaration: { 175 if (this.recordType) { 176 TypeChecker.getInstance().formatNodeType(childNode); 177 } 178 break; 179 } 180 case ts.SyntaxKind.Identifier: { 181 this.recordVariableDecl(<ts.Identifier>childNode, scope); 182 break; 183 } 184 case ts.SyntaxKind.ImportDeclaration: { 185 if (!CmdOptions.isModules()) { 186 throw new DiagnosticError(childNode, DiagnosticCode.An_import_declaration_can_only_be_used_in_a_namespace_or_module, jshelpers.getSourceFileOfNode(childNode)); 187 } 188 if (!(scope instanceof ModuleScope)) { 189 throw new Error("SyntaxError: import statement cannot in other scope except ModuleScope"); 190 } 191 let importStmt = this.recordImportInfo(<ts.ImportDeclaration>childNode, scope); 192 if (this.recordType) { 193 TypeChecker.getInstance().formatNodeType(childNode, importStmt); 194 } 195 break; 196 } 197 case ts.SyntaxKind.ExportDeclaration: { 198 if (!CmdOptions.isModules()) { 199 throw new DiagnosticError(childNode, DiagnosticCode.An_export_declaration_can_only_be_used_in_a_module, jshelpers.getSourceFileOfNode(childNode)); 200 } 201 if (!(scope instanceof ModuleScope)) { 202 throw new Error("SyntaxError: export statement cannot in other scope except ModuleScope"); 203 } 204 let exportStmt = this.recordExportInfo(<ts.ExportDeclaration>childNode); 205 if (this.recordType) { 206 TypeChecker.getInstance().formatNodeType(childNode, exportStmt); 207 } 208 break; 209 } 210 case ts.SyntaxKind.ExportAssignment: { 211 if (this.defaultUsed) { 212 throw new DiagnosticError(childNode, DiagnosticCode.Duplicate_identifier_0, jshelpers.getSourceFileOfNode(childNode), ["default"]); 213 } 214 this.defaultUsed = true; 215 this.recordInfo(childNode, scope); 216 if (this.recordType) { 217 TypeChecker.getInstance().formatNodeType(childNode); 218 } 219 break; 220 } 221 case ts.SyntaxKind.VariableStatement: { 222 if (this.recordType) { 223 TypeChecker.getInstance().formatNodeType(childNode); 224 } 225 this.recordInfo(childNode, scope); 226 break; 227 } 228 default: 229 this.recordInfo(childNode, scope); 230 } 231 }); 232 } 233 234 private recordClassInfo(childNode: ts.ClassLikeDeclaration, scope: Scope) { 235 let localScope = new LocalScope(scope); 236 this.setScopeMap(childNode, localScope); 237 let ctor = extractCtorOfClass(childNode); 238 if (!ctor) { 239 AddCtor2Class(this, childNode, localScope); 240 } else { 241 this.setCtorOfClass(childNode, ctor); 242 } 243 if (childNode.name) { 244 let name = jshelpers.getTextOfIdentifierOrLiteral(childNode.name); 245 let calssDecl = new ClassDecl(name, childNode); 246 scope.setDecls(calssDecl); 247 } 248 this.recordInfo(childNode, localScope); 249 } 250 251 buildVariableScope(curScope: Scope, node: ts.FunctionLikeDeclaration) { 252 let functionScope = new FunctionScope(curScope, <ts.FunctionLikeDeclaration>node); 253 let parentVariableScope = <VariableScope>curScope.getNearestVariableScope(); 254 functionScope.setParentVariableScope(parentVariableScope); 255 parentVariableScope.addChildVariableScope(functionScope); 256 this.setScopeMap(node, functionScope); 257 return functionScope; 258 } 259 260 private recordVariableDecl(id: ts.Identifier, scope: Scope) { 261 let name = jshelpers.getTextOfIdentifierOrLiteral(id); 262 let parent = this.getDeclarationNodeOfId(id); 263 264 if (parent) { 265 let declKind = astutils.getVarDeclarationKind(<ts.VariableDeclaration>parent); 266 267 // collect declaration information to corresponding scope 268 let decl = this.addVariableDeclToScope(scope, id, parent, name, declKind); 269 if (declKind == VarDeclarationKind.VAR) { 270 let variableScopeParent = <VariableScope>scope.getNearestVariableScope(); 271 this.collectHoistDecls(id, variableScopeParent, decl); 272 } 273 } else { 274 let declScope = scope.findDeclPos(name); 275 if (declScope) { 276 let decl = <Decl>declScope.getDecl(name); 277 278 if ((decl instanceof LetDecl || decl instanceof ConstDecl)) { 279 let nearestRefVariableScope = <VariableScope>scope.getNearestVariableScope(); 280 let nearestDefLexicalScope = <VariableScope | LoopScope>declScope.getNearestLexicalScope(); 281 282 let tmp: Scope | undefined = nearestRefVariableScope.getNearestLexicalScope(); 283 let needCreateLoopEnv: boolean = false; 284 if (nearestDefLexicalScope instanceof LoopScope) { 285 while (tmp) { 286 if (tmp == nearestDefLexicalScope) { 287 needCreateLoopEnv = true; 288 break; 289 } 290 291 tmp = tmp.getParent(); 292 } 293 294 if (needCreateLoopEnv) { 295 nearestDefLexicalScope.pendingCreateEnv(); 296 } 297 } 298 } 299 } 300 } 301 302 if (name == "arguments") { 303 let varialbeScope = scope.getNearestVariableScope(); 304 varialbeScope?.setUseArgs(true); 305 } 306 } 307 308 private addVariableDeclToScope(scope: Scope, node: ts.Node, parent: ts.Node, name: string, declKind: VarDeclarationKind): Decl { 309 let decl = new VarDecl(name, node); 310 switch (declKind) { 311 case VarDeclarationKind.VAR: 312 break; 313 case VarDeclarationKind.LET: 314 if (parent.parent.kind == ts.SyntaxKind.CatchClause) { 315 decl = new CatchParameter(name, node); 316 } else { 317 decl = new LetDecl(name, node); 318 } 319 break; 320 case VarDeclarationKind.CONST: 321 decl = new ConstDecl(name, node); 322 break; 323 default: 324 throw new Error("Wrong type of declaration"); 325 } 326 scope.setDecls(decl); 327 return decl; 328 } 329 330 private getDeclarationNodeOfId(id: ts.Identifier): ts.VariableDeclaration | undefined { 331 let parent = id.parent; 332 if (ts.isVariableDeclaration(parent) && 333 parent.name == id) { 334 return <ts.VariableDeclaration>parent; 335 } else if (ts.isBindingElement(parent) && 336 parent.name == id) { 337 while (parent && !ts.isVariableDeclaration(parent)) { 338 parent = parent.parent; 339 } 340 341 return parent ? <ts.VariableDeclaration>parent : undefined; 342 } else { 343 return undefined; 344 } 345 } 346 347 private recordImportInfo(node: ts.ImportDeclaration, scope: ModuleScope): ModuleStmt { 348 if (!ts.isStringLiteral(node.moduleSpecifier)) { 349 throw new Error("moduleSpecifier must be a stringLiteral"); 350 } 351 let importStmt: ModuleStmt; 352 if (node.moduleSpecifier) { 353 let moduleRequest = jshelpers.getTextOfIdentifierOrLiteral(node.moduleSpecifier); 354 importStmt = new ModuleStmt(node, moduleRequest); 355 } else { 356 importStmt = new ModuleStmt(node); 357 } 358 if (node.importClause) { 359 let importClause: ts.ImportClause = node.importClause; 360 361 // import defaultExport from "a.js" 362 if (importClause.name) { 363 let name = jshelpers.getTextOfIdentifierOrLiteral(importClause.name); 364 scope.setDecls(new ConstDecl(name, importClause.name)); 365 importStmt.addLocalName(name, "default"); 366 importStmt.addNodeMap(importClause.name, importClause.name); 367 } 368 369 // import { ... } from "a.js" 370 // import * as a from "a.js" 371 // import defaultExport, * as a from "a.js" 372 if (importClause.namedBindings) { 373 let namedBindings = importClause.namedBindings; 374 // import * as a from "a.js" 375 if (ts.isNamespaceImport(namedBindings)) { 376 let nameSpace = jshelpers.getTextOfIdentifierOrLiteral((<ts.NamespaceImport>namedBindings).name); 377 scope.setDecls(new ConstDecl(nameSpace, namedBindings)); 378 importStmt.setNameSpace(nameSpace); 379 } 380 381 // import { ... } from "a.js" 382 if (ts.isNamedImports(namedBindings)) { 383 namedBindings.elements.forEach((element) => { 384 let name: string = jshelpers.getTextOfIdentifierOrLiteral(element.name); 385 let exoticName: string = element.propertyName ? jshelpers.getTextOfIdentifierOrLiteral(element.propertyName) : name; 386 scope.setDecls(new ConstDecl(name, element)); 387 importStmt.addLocalName(name, exoticName); 388 importStmt.addNodeMap(element.name, element.propertyName ? element.propertyName : element.name); 389 }); 390 } 391 } 392 } 393 394 this.importStmts.push(importStmt); 395 return importStmt; 396 } 397 398 private recordExportInfo(node: ts.ExportDeclaration): ModuleStmt { 399 let origNode = <ts.ExportDeclaration>ts.getOriginalNode(node); 400 let exportStmt: ModuleStmt; 401 if (origNode.moduleSpecifier) { 402 if (!ts.isStringLiteral(origNode.moduleSpecifier)) { 403 throw new Error("moduleSpecifier must be a stringLiteral"); 404 } 405 exportStmt = new ModuleStmt(origNode, jshelpers.getTextOfIdentifierOrLiteral(origNode.moduleSpecifier)); 406 } else { 407 exportStmt = new ModuleStmt(origNode); 408 } 409 410 if (origNode.exportClause) { 411 exportStmt.setCopyFlag(false); 412 let namedBindings: ts.NamedExportBindings = origNode.exportClause; 413 if (ts.isNamespaceExport(namedBindings)) { 414 exportStmt.setNameSpace(jshelpers.getTextOfIdentifierOrLiteral((<ts.NamespaceExport>namedBindings).name)); 415 } 416 417 if (ts.isNamedExports(namedBindings)) { 418 namedBindings.elements.forEach((element) => { 419 let name: string = jshelpers.getTextOfIdentifierOrLiteral(element.name); 420 if (name == 'default') { 421 if (this.defaultUsed) { 422 throw new DiagnosticError(origNode, DiagnosticCode.Duplicate_identifier_0, jshelpers.getSourceFileOfNode(origNode), [name]); 423 } else { 424 this.defaultUsed = true; 425 } 426 } 427 let exoticName: string = element.propertyName ? jshelpers.getTextOfIdentifierOrLiteral(element.propertyName) : name; 428 exportStmt.addLocalName(name, exoticName); 429 exportStmt.addNodeMap(element.name, element.propertyName ? element.propertyName : element.name); 430 }); 431 } 432 } 433 this.exportStmts.push(exportStmt); 434 return exportStmt; 435 } 436 437 private recordFuncDecl(node: ts.FunctionDeclaration, scope: Scope) { 438 this.recordFuncInfo(node); 439 440 let funcId = <ts.Identifier>(node).name; 441 if (!funcId) { 442 // function declaration without name doesn't need to record hoisting. 443 return; 444 } 445 let funcName = jshelpers.getTextOfIdentifierOrLiteral(funcId); 446 let funcDecl = new FuncDecl(funcName, node); 447 let hoistScope = scope; 448 let need2AddDecls: boolean = true; 449 if (scope instanceof GlobalScope || scope instanceof ModuleScope) { 450 this.collectHoistDecls(node, <GlobalScope | ModuleScope>hoistScope, funcDecl); 451 } else if (scope instanceof LocalScope) { 452 hoistScope = <Scope>scope.getNearestVariableScope(); 453 let expectHoistScope = this.getScopeOfNode(node.parent.parent); 454 if ((hoistScope == expectHoistScope) && (hoistScope instanceof FunctionScope)) { 455 need2AddDecls = this.collectHoistDecls(node, hoistScope, funcDecl); 456 } 457 } else { 458 LOGD("Function declaration", " in function is collected in its body block"); 459 } 460 if (need2AddDecls) { 461 scope.setDecls(funcDecl); 462 } 463 } 464 465 private recordOtherFunc(node: ts.FunctionLikeDeclaration, scope: Scope) { // functionlikedecalration except function declaration 466 this.recordFuncInfo(node); 467 if (!ts.isFunctionExpression(node) && !ts.isMethodDeclaration(node)) { 468 return; 469 } 470 if (node.name && ts.isIdentifier(node.name)) { 471 let funcName = jshelpers.getTextOfIdentifierOrLiteral(node.name); 472 let funcDecl = new FuncDecl(funcName, node); 473 scope.setDecls(funcDecl); 474 } 475 } 476 477 private recordFuncInfo(node: ts.FunctionLikeDeclaration) { 478 this.recordFunctionParameters(node); 479 this.recordFuncName(node); 480 } 481 482 recordFuncName(node: ts.FunctionLikeDeclaration) { 483 let name: string = ''; 484 if (ts.isConstructorDeclaration(node)) { 485 let classNode = node.parent; 486 name = getClassNameForConstructor(classNode); 487 } else { 488 if (isAnonymousFunctionDefinition(node)) { 489 let outerNode = findOuterNodeOfParenthesis(node); 490 491 if (ts.isVariableDeclaration(outerNode)) { 492 // @ts-ignore 493 let id = outerNode.name; 494 if (ts.isIdentifier(id)) { 495 name = jshelpers.getTextOfIdentifierOrLiteral(id); 496 } 497 } else if (ts.isBinaryExpression(outerNode)) { 498 // @ts-ignore 499 if (outerNode.operatorToken.kind == ts.SyntaxKind.EqualsToken && ts.isIdentifier(outerNode.left)) { 500 // @ts-ignore 501 name = jshelpers.getTextOfIdentifierOrLiteral(outerNode.left); 502 } 503 } else if (ts.isPropertyAssignment(outerNode)) { 504 // @ts-ignore 505 let propName = outerNode.name; 506 if (ts.isIdentifier(propName) || ts.isStringLiteral(propName) || ts.isNumericLiteral(propName)) { 507 name = jshelpers.getTextOfIdentifierOrLiteral(propName); 508 if (name == "__proto__") { 509 name = ''; 510 } 511 } 512 } 513 } else { 514 if (ts.isIdentifier(node.name!)) { 515 name = jshelpers.getTextOfIdentifierOrLiteral(node.name); 516 } 517 } 518 } 519 520 (<FunctionScope>this.getScopeOfNode(node)).setFuncName(name); 521 522 if (name != '') { 523 let funcNameMap = this.funcNameMap; 524 if (funcNameMap.has(name)) { 525 let nums = <number>funcNameMap.get(name); 526 funcNameMap.set(name, ++nums); 527 } else { 528 funcNameMap.set(name, 1); 529 } 530 } 531 } 532 533 recordFunctionParameters(node: ts.FunctionLikeDeclaration) { 534 let parameters = node.parameters; 535 let funcParams: FunctionParameter[] = []; 536 let length = 0; 537 let lengthFlag = true; 538 539 if (parameters) { 540 parameters.forEach(parameter => { 541 // record function.length 542 if (parameter.initializer || this.isRestParameter(parameter)) { 543 lengthFlag = false; 544 } 545 if (lengthFlag) { 546 length++; 547 } 548 549 if (ts.isIdentifier(parameter.name)) { 550 let name = jshelpers.getTextOfIdentifierOrLiteral(<ts.Identifier>parameter.name); 551 funcParams.push(new FunctionParameter(name, parameter.name)); 552 } else { // parameter is binding pattern 553 this.recordPatternParameter(<ts.BindingPattern>parameter.name, funcParams); 554 } 555 }); 556 } 557 (<FunctionScope>this.getScopeOfNode(node)).setParameterLength(length); 558 this.setParametersMap(node, funcParams); 559 } 560 561 recordPatternParameter(pattern: ts.BindingPattern, funcParams: Array<FunctionParameter>) { 562 let name: string = ''; 563 pattern.elements.forEach(bindingElement => { 564 if (ts.isOmittedExpression(bindingElement)) { 565 return; 566 } 567 568 bindingElement = <ts.BindingElement>bindingElement; 569 if (ts.isIdentifier(bindingElement.name)) { 570 name = jshelpers.getTextOfIdentifierOrLiteral(bindingElement.name); 571 funcParams.push(new FunctionParameter(name, bindingElement.name)); 572 } else { // case of binding pattern 573 let innerPattern = <ts.BindingPattern>bindingElement.name; 574 this.recordPatternParameter(innerPattern, funcParams); 575 } 576 }); 577 } 578 579 580 isRestParameter(parameter: ts.ParameterDeclaration) { 581 return parameter.dotDotDotToken ? true : false; 582 } 583 584 private collectHoistDecls(node: ts.Node, scope: VariableScope, decl: Decl): boolean { 585 let declName = decl.name; 586 587 // if variable share a same name with the parameter of its contained function, it should not be hoisted 588 if (scope instanceof FunctionScope) { 589 let nearestFunc = jshelpers.getContainingFunctionDeclaration(node); 590 let functionParameters = this.getParametersOfFunction(<ts.FunctionLikeDeclaration>nearestFunc); 591 if (functionParameters) { 592 for (let i = 0; i < functionParameters.length; i++) { 593 if (functionParameters[i].name == declName) { 594 return false; 595 } 596 } 597 } 598 } 599 600 // Variable named of global identifier should not be hoisted. 601 if (isGlobalIdentifier(declName) && (scope instanceof GlobalScope)) { 602 return true; 603 } 604 605 this.setHoistMap(scope, decl); 606 return false; 607 } 608 609 setScopeMap(node: ts.Node, scope: Scope) { 610 this.scopeMap.set(node, scope); 611 } 612 613 getScopeMap() { 614 return this.scopeMap; 615 } 616 617 getScopeOfNode(node: ts.Node) { 618 return this.scopeMap.get(node); 619 } 620 621 getImportStmts() { 622 return this.importStmts; 623 } 624 625 getExportStmts() { 626 return this.exportStmts; 627 } 628 629 setHoistMap(scope: VariableScope, decl: Decl) { 630 if (!this.hoistMap.has(scope)) { 631 this.hoistMap.set(scope, [decl]); 632 return; 633 } 634 635 let hoistDecls = <Decl[]>this.hoistMap.get(scope); 636 for (let i = 0; i < hoistDecls.length; i++) { 637 if (decl.name == hoistDecls[i].name) { 638 if (decl instanceof FuncDecl) { 639 hoistDecls[i] = decl; 640 } 641 return; 642 } 643 } 644 hoistDecls.push(decl); 645 } 646 647 getHoistMap() { 648 return this.hoistMap; 649 } 650 651 getHoistDeclsOfScope(scope: VariableScope) { 652 return this.hoistMap.get(scope); 653 } 654 655 setParametersMap(node: ts.FunctionLikeDeclaration, parameters: FunctionParameter[]) { 656 this.parametersMap.set(node, parameters); 657 } 658 659 getParametersOfFunction(node: ts.FunctionLikeDeclaration) { 660 return this.parametersMap.get(node); 661 } 662 663 getFuncNameMap() { 664 return this.funcNameMap; 665 } 666}