1/* 2 * Copyright (c) 2021-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 16/** 17 * The compiler implementation. 18 * The compiler traverses TypeScript's AST, splits operations into sinmple ones 19 * and asks Pandagen to generate bytecode. 20 * 21 * This file should not contain import from irnodes.ts. 22 * The interface of PandaGen should be enough. 23 */ 24 25import * as ts from "typescript"; 26import { AssignmentOperator } from "typescript"; 27import * as astutils from "./astutils"; 28import { LReference } from "./base/lreference"; 29import { 30 hasExportKeywordModifier, 31 isBindingPattern, 32} from "./base/util"; 33import { CacheList, getVregisterCache } from "./base/vregisterCache"; 34import { CmdOptions } from "./cmdOptions"; 35import { CompilerDriver } from "./compilerDriver"; 36import { DebugInfo, NodeKind } from "./debuginfo"; 37import { DiagnosticCode, DiagnosticError } from "./diagnostic"; 38import { compileArrayLiteralExpression } from "./expression/arrayLiteralExpression"; 39import { compileBigIntLiteral } from "./expression/bigIntLiteral"; 40import { 41 compileCallExpression, 42 getHiddenParameters 43} from "./expression/callExpression"; 44import { 45 compileMemberAccessExpression, 46 getObjAndProp 47} from "./expression/memberAccessExpression"; 48import { compileMetaProperty } from "./expression/metaProperty"; 49import { compileNewExpression } from "./expression/newExpression"; 50import { compileNumericLiteral } from "./expression/numericLiteral"; 51import { compileObjectLiteralExpression } from "./expression/objectLiteralExpression"; 52import { 53 findInnerExprOfParenthesis, 54 findOuterNodeOfParenthesis 55} from "./expression/parenthesizedExpression"; 56import { compileRegularExpressionLiteral } from "./expression/regularExpression"; 57import { compileStringLiteral } from "./expression/stringLiteral"; 58import { getTemplateObject } from "./expression/templateExpression"; 59import { compileYieldExpression } from "./expression/yieldExpression"; 60import { AsyncFunctionBuilder } from "./function/asyncFunctionBuilder"; 61import { AsyncGeneratorFunctionBuilder } from "./function/asyncGeneratorFunctionBuilder"; 62import { FunctionBuilder } from "./function/functionBuilder"; 63import { GeneratorFunctionBuilder } from "./function/generatorFunctionBuilder"; 64 65import { 66 hoistFunctionInBlock 67} from "./hoisting"; 68import { 69 Label, 70 VReg 71} from "./irnodes"; 72import * as jshelpers from "./jshelpers"; 73import { LOGD } from "./log"; 74import { 75 PandaGen 76} from "./pandagen"; 77import { Recorder } from "./recorder"; 78import { 79 FunctionScope, 80 GlobalScope, 81 LoopScope, 82 ModuleScope, 83 Scope, 84 VariableScope 85} from "./scope"; 86import { 87 checkValidUseSuperBeforeSuper, 88 compileClassDeclaration, 89 compileDefaultConstructor, 90 compileDefaultInitClassMembers, 91 compileReturnThis4Ctor, 92 extractCtorOfClass 93} from "./statement/classStatement"; 94import { compileForOfStatement } from "./statement/forOfStatement"; 95import { LabelTarget } from "./statement/labelTarget"; 96import { 97 compileDoStatement, 98 compileForInStatement, 99 compileForStatement, 100 compileWhileStatement 101} from "./statement/loopStatement"; 102import { compileReturnStatement } from "./statement/returnStatement"; 103import { compileSwitchStatement } from "./statement/switchStatement"; 104import { 105 CatchTable, 106 LabelPair, 107 transformTryCatchFinally, 108 TryBuilder, 109 TryBuilderBase, 110 TryStatement 111} from "./statement/tryStatement"; 112import { isStrictMode } from "./strictMode"; 113import { isAssignmentOperator } from "./syntaxCheckHelper"; 114import { 115 GlobalVariable, 116 LocalVariable, 117 MandatoryArguments, 118 MandatoryFuncObj, 119 MandatoryNewTarget, 120 MandatoryThis, 121 ModuleVariable, 122 VarDeclarationKind, 123 Variable 124} from "./variable"; 125import { 126 compileCommaListExpression 127} from "./expression/compileCommaListExpression"; 128 129export enum ControlFlowChange { Continue, Break } 130export class Compiler { 131 private debugTag = "compiler"; 132 private rootNode: ts.SourceFile | ts.FunctionLikeDeclaration; 133 private pandaGen: PandaGen; 134 private scope: Scope; 135 private compilerDriver: CompilerDriver; 136 private funcBuilder: FunctionBuilder; 137 private recorder: Recorder; 138 private envUnion: Array<VReg> = new Array<VReg>(); 139 140 constructor(node: ts.SourceFile | ts.FunctionLikeDeclaration, pandaGen: PandaGen, compilerDriver: CompilerDriver, recorder: Recorder) { 141 this.rootNode = node; 142 this.pandaGen = pandaGen; 143 this.compilerDriver = compilerDriver; 144 this.recorder = recorder; 145 this.funcBuilder = new FunctionBuilder(pandaGen); 146 147 // At the beginning of function compile, alloc pandagen.local for 4funcObj/newTarget/this/parameters, because of 148 // maybe no one used this parameter, will get undefined for RA 149 this.scope = this.pandaGen.getScope()!; 150 let parameters = (<VariableScope>this.scope).getParameters(); 151 152 for (let i = 0; i < parameters.length; ++i) { 153 this.pandaGen.getVregForVariable(parameters[i]); 154 } 155 156 // spare v3 to save the currrent lexcial env 157 getVregisterCache(this.pandaGen, CacheList.LEXENV); 158 159 this.pandaGen.loadAccFromArgs(this.rootNode); 160 } 161 162 compile(): void { 163 this.storeFuncObj2LexEnvIfNeeded(); 164 this.compileLexicalBindingForArrowFunction(); 165 166 if (this.rootNode.kind === ts.SyntaxKind.SourceFile) { 167 this.compileSourceFileOrBlock(<ts.SourceFile>this.rootNode); 168 } else { 169 this.compileFunctionLikeDeclaration(<ts.FunctionLikeDeclaration>this.rootNode); 170 } 171 } 172 173 pushEnv(env: VReg): void { 174 this.envUnion.push(env); 175 } 176 177 popEnv(): void { 178 this.envUnion.pop(); 179 } 180 181 getCurrentEnv(): VReg { 182 return this.envUnion[this.envUnion.length - 1]; 183 } 184 185 private storeFuncObj2LexEnvIfNeeded(): void { 186 let rootNode = this.rootNode; 187 if (!ts.isFunctionExpression(rootNode) && !ts.isMethodDeclaration(rootNode)) { 188 return; 189 } 190 let functionScope = this.recorder.getScopeOfNode(rootNode); 191 if ((<ts.FunctionLikeDeclaration>rootNode).name) { 192 let funcName = jshelpers.getTextOfIdentifierOrLiteral((<ts.FunctionLikeDeclaration>rootNode).name); 193 let v = functionScope.find(funcName); 194 if (v.scope === functionScope) { 195 this.pandaGen.loadAccumulator(NodeKind.FIRST_NODE_OF_FUNCTION, 196 getVregisterCache(this.pandaGen, CacheList.FUNC)); 197 this.pandaGen.storeAccToLexEnv(NodeKind.FIRST_NODE_OF_FUNCTION, v.scope, v.level, v.v, true); 198 } 199 } 200 } 201 202 private compileLexicalBindingForArrowFunction(): void { 203 let rootNode = this.rootNode; 204 if (ts.isArrowFunction(rootNode)) { 205 return; 206 } 207 208 this.storeMandatoryArgToLexEnv(MandatoryFuncObj); 209 this.storeMandatoryArgToLexEnv(MandatoryNewTarget); 210 this.storeMandatoryArgToLexEnv(MandatoryThis); 211 212 let rootScope: VariableScope = <VariableScope>this.recorder.getScopeOfNode(rootNode); 213 if (rootScope.getUseArgs()) { 214 this.storeMandatoryArgToLexEnv(MandatoryArguments); 215 } 216 } 217 218 private storeMandatoryArgToLexEnv(arg: string): void { 219 let v = this.scope.findLocal(arg); 220 if (!v) { 221 throw new Error("Mandatory Arguments should be found locally"); 222 } 223 if (!v.lexical()) { 224 return; 225 } 226 227 let vreg = arg === MandatoryFuncObj ? getVregisterCache(this.pandaGen, CacheList.FUNC) : 228 this.pandaGen.getVregForVariable(v); 229 this.pandaGen.storeLexicalVar(this.rootNode, 0, v.lexIndex(), vreg); 230 } 231 232 private compileSourceFileOrBlock(body: ts.SourceFile | ts.Block): void { 233 let statements = body.statements; 234 let unreachableFlag = false; 235 236 if (body.parent && ts.isConstructorDeclaration(body.parent)) { 237 compileDefaultInitClassMembers(this, body.parent); 238 } 239 240 statements.forEach((stmt) => { 241 this.compileStatement(stmt); 242 if (stmt.kind === ts.SyntaxKind.ReturnStatement) { 243 unreachableFlag = true; 244 } 245 }); 246 247 if (body.parent && ts.isConstructorDeclaration(body.parent)) { 248 compileReturnThis4Ctor(this, body.parent, unreachableFlag); 249 return; 250 } 251 if (unreachableFlag) { 252 return ; 253 } 254 // exit GlobalScopefunction or Function Block return 255 this.funcBuilder.implicitReturn(NodeKind.INVALID); 256 } 257 258 private compileFunctionBody(kind: number, body: ts.ConciseBody): void { 259 let pandaGen = this.pandaGen; 260 261 if (body.kind === ts.SyntaxKind.Block) { 262 this.pushScope(body); 263 this.compileSourceFileOrBlock(<ts.Block>body); 264 this.popScope(); 265 } else if (kind === ts.SyntaxKind.ArrowFunction) { 266 this.compileExpression(<ts.Expression>body); 267 268 let retValue = pandaGen.getTemp(); 269 pandaGen.storeAccumulator(body, retValue); 270 271 if (this.funcBuilder instanceof AsyncFunctionBuilder || this.funcBuilder instanceof AsyncGeneratorFunctionBuilder) { 272 this.funcBuilder.resolve(body, retValue); 273 pandaGen.return(NodeKind.INVALID); 274 } else { 275 pandaGen.loadAccumulator(body, retValue); 276 } 277 pandaGen.freeTemps(retValue); 278 pandaGen.return(NodeKind.INVALID); 279 } else { 280 throw new Error("Node " + this.getNodeName(body) + " is unimplemented as a function body"); 281 } 282 } 283 284 private compileFunctionParameterDeclaration(decl: ts.FunctionLikeDeclaration): void { 285 let pandaGen = this.pandaGen; 286 287 for (let index = 0; index < decl.parameters.length; ++index) { 288 let param = decl.parameters[index]; 289 let parameter = param.name; 290 let paramRef = LReference.generateLReference(this, parameter, true); 291 292 let variable: Variable; 293 if (ts.isIdentifier(parameter)) { 294 variable = <Variable>paramRef.variable!.v; 295 } else if (isBindingPattern(parameter)) { 296 let paramName = index.toString() + "pattern"; 297 variable = <Variable>this.scope.find(paramName).v; 298 } 299 300 let paramReg = pandaGen.getVregForVariable(variable!); 301 if (param.dotDotDotToken) { 302 let scope = this.pandaGen.getScope(); 303 if (scope instanceof FunctionScope) { 304 scope.setArgumentsOrRestargs(); 305 } 306 pandaGen.copyRestArgs(param, index); 307 pandaGen.storeAccumulator(param, paramReg); 308 } 309 310 if (param.initializer) { 311 let endLabel = new Label(); 312 313 pandaGen.loadAccumulator(decl, paramReg); 314 pandaGen.condition( 315 decl, 316 ts.SyntaxKind.EqualsEqualsEqualsToken, 317 getVregisterCache(pandaGen, CacheList.UNDEFINED), 318 endLabel); 319 this.compileExpression(param.initializer); 320 pandaGen.storeAccumulator(param, paramReg); 321 pandaGen.label(decl, endLabel); 322 } 323 324 if (isBindingPattern(parameter) || 325 (ts.isIdentifier(parameter) && (variable!.isLexVar))) { 326 pandaGen.loadAccumulator(param, paramReg); 327 paramRef.setValue(); 328 } 329 } 330 } 331 332 private createFuncBuilder(decl: ts.FunctionLikeDeclaration): FunctionBuilder { 333 let pandaGen = this.pandaGen; 334 335 if (decl.modifiers) { 336 for (let i = 0; i < decl.modifiers.length; i++) { 337 if (decl.modifiers[i].kind === ts.SyntaxKind.AsyncKeyword) { 338 // async generator 339 if (decl.asteriskToken) { 340 return new AsyncGeneratorFunctionBuilder(pandaGen, this); 341 } else { // async 342 return new AsyncFunctionBuilder(pandaGen); 343 } 344 } 345 } 346 } 347 348 if (decl.asteriskToken) { 349 return new GeneratorFunctionBuilder(pandaGen, this); 350 } 351 352 return new FunctionBuilder(pandaGen); 353 } 354 355 private compileFunctionLikeDeclaration(decl: ts.FunctionLikeDeclaration): void { 356 let pandaGen = this.pandaGen; 357 this.compileFunctionParameterDeclaration(decl); 358 359 if (ts.isConstructorDeclaration(decl)) { 360 let classNode = <ts.ClassLikeDeclaration>decl.parent; 361 if (jshelpers.getClassExtendsHeritageElement(classNode) && !extractCtorOfClass(classNode)) { 362 compileDefaultConstructor(this, decl); 363 return; 364 } 365 } 366 367 if (decl.kind === ts.SyntaxKind.FunctionExpression) { 368 if (decl.name) { 369 let funcName = jshelpers.getTextOfIdentifierOrLiteral(decl.name); 370 (<VariableScope>pandaGen.getScope()!).addFuncName(funcName); 371 } 372 } 373 374 this.funcBuilder = this.createFuncBuilder(decl); 375 this.funcBuilder.prepare(decl); 376 if (decl.body) { 377 this.compileFunctionBody(decl.kind, decl.body); 378 } 379 380 this.funcBuilder.cleanUp(decl); 381 } 382 383 384 compileStatement(stmt: ts.Statement): void { 385 // for debug info 386 this.pandaGen.setFirstStmt(stmt); 387 388 // Please keep order of cases the same as in types.ts 389 LOGD(this.debugTag, "compile statement: " + this.getNodeName(stmt)); 390 switch (stmt.kind) { 391 case ts.SyntaxKind.Block: // line 273 392 this.compileBlock(<ts.Block>stmt); 393 break; 394 case ts.SyntaxKind.EmptyStatement: // line 274 395 break; 396 case ts.SyntaxKind.VariableStatement: // line 275 397 this.compileVariableStatement(<ts.VariableStatement>stmt); 398 break; 399 case ts.SyntaxKind.ExpressionStatement: // line 276 400 this.compileExpression((<ts.ExpressionStatement>stmt).expression); 401 break; 402 case ts.SyntaxKind.IfStatement: // line 277 403 this.compileIfStatement(<ts.IfStatement>stmt); 404 break; 405 case ts.SyntaxKind.DoStatement: // line 278 406 compileDoStatement(<ts.DoStatement>stmt, this); 407 break; 408 case ts.SyntaxKind.WhileStatement: // line 279 409 compileWhileStatement(<ts.WhileStatement>stmt, this); 410 break; 411 case ts.SyntaxKind.ForStatement: // line 280 412 compileForStatement(<ts.ForStatement>stmt, this); 413 break; 414 case ts.SyntaxKind.ForInStatement: //line 281 415 compileForInStatement(<ts.ForInStatement>stmt, this); 416 break; 417 case ts.SyntaxKind.ForOfStatement: //line 282 418 compileForOfStatement(<ts.ForOfStatement>stmt, this); 419 break; 420 case ts.SyntaxKind.ContinueStatement: // line 283 421 this.compileContinueStatement(<ts.ContinueStatement>stmt); 422 break; 423 case ts.SyntaxKind.BreakStatement: // line 284 424 this.compileBreakStatement(<ts.BreakStatement>stmt); 425 break; 426 case ts.SyntaxKind.ReturnStatement: // line 285 427 compileReturnStatement(<ts.ReturnStatement>stmt, this); 428 break; 429 case ts.SyntaxKind.SwitchStatement: // line 287 430 compileSwitchStatement(<ts.SwitchStatement>stmt, this); 431 break; 432 case ts.SyntaxKind.LabeledStatement: // line 288 433 this.compileLabeledStatement(<ts.LabeledStatement>stmt); 434 break; 435 case ts.SyntaxKind.ThrowStatement: // line 289 436 this.compileThrowStatement(<ts.ThrowStatement>stmt); 437 break; 438 case ts.SyntaxKind.TryStatement: // line 290 439 this.compileTryStatement(<ts.TryStatement>stmt); 440 break; 441 case ts.SyntaxKind.DebuggerStatement: // line 291 442 this.pandaGen.debugger(stmt); 443 break; 444 case ts.SyntaxKind.FunctionDeclaration: // line 294 445 this.compileFunctionDeclaration(<ts.FunctionDeclaration>stmt); 446 break; 447 case ts.SyntaxKind.ClassDeclaration: 448 compileClassDeclaration(this, <ts.ClassLikeDeclaration>stmt); 449 case ts.SyntaxKind.ImportDeclaration: 450 break; 451 case ts.SyntaxKind.ExportAssignment: 452 this.compileExportAssignment(<ts.ExportAssignment>stmt); 453 break; 454 case ts.SyntaxKind.ExportDeclaration: 455 case ts.SyntaxKind.NotEmittedStatement: 456 case ts.SyntaxKind.InterfaceDeclaration: 457 case ts.SyntaxKind.EndOfDeclarationMarker: 458 case ts.SyntaxKind.ModuleDeclaration: 459 case ts.SyntaxKind.TypeAliasDeclaration: 460 case ts.SyntaxKind.MergeDeclarationMarker: 461 break; 462 default: 463 throw new Error("Statement " + this.getNodeName(stmt) + " is unimplemented"); 464 } 465 } 466 467 private compileBlock(block: ts.Block): void { 468 this.pushScope(block); 469 hoistFunctionInBlock(this.scope, this.pandaGen, isStrictMode(block), this); 470 471 block.statements.forEach((stmt) => this.compileStatement(stmt)); 472 473 this.popScope(); 474 } 475 476 private compileVariableStatement(stmt: ts.VariableStatement): void { 477 let declList = stmt.declarationList; 478 declList.declarations.forEach((decl) => { 479 this.compileVariableDeclaration(decl) 480 }); 481 } 482 483 compileVariableDeclaration(decl: ts.VariableDeclaration): void { 484 let lref = LReference.generateLReference(this, decl.name, true); 485 if (decl.initializer) { 486 this.compileExpression(decl.initializer); 487 } else { 488 // global var without init should not be assigned undefined twice 489 if (astutils.getVarDeclarationKind(decl) === VarDeclarationKind.VAR) { 490 return; 491 } 492 493 if ((astutils.getVarDeclarationKind(decl) === VarDeclarationKind.LET) && 494 decl.parent.kind != ts.SyntaxKind.CatchClause) { 495 this.pandaGen.loadAccumulator(decl, getVregisterCache(this.pandaGen, CacheList.UNDEFINED)); 496 } 497 } 498 lref.setValue(); 499 } 500 501 private compileIfStatement(stmt: ts.IfStatement): void { 502 this.pushScope(stmt); 503 let ifElseLabel = new Label(); 504 let ifEndLabel = new Label(); 505 506 this.compileCondition(stmt.expression, stmt.elseStatement ? ifElseLabel : ifEndLabel); 507 this.compileStatement(stmt.thenStatement); 508 if (stmt.elseStatement) { 509 this.pandaGen.branch(DebugInfo.getLastNode(), ifEndLabel); 510 this.pandaGen.label(stmt, ifElseLabel); 511 this.compileStatement(stmt.elseStatement); 512 } 513 this.pandaGen.label(stmt, ifEndLabel); 514 this.popScope(); 515 } 516 517 private popLoopEnv(node: ts.Node, times: number): void { 518 while(times--) { 519 this.pandaGen.popLexicalEnv(node); 520 } 521 } 522 523 private popLoopEnvWhenContinueOrBreak(labelTarget: LabelTarget, isContinue: boolean): void { 524 let node: ts.Node = labelTarget.getCorrespondingNode(); 525 let loopEnvLevel = labelTarget.getLoopEnvLevel(); 526 switch (node.kind) { 527 case ts.SyntaxKind.DoStatement: 528 case ts.SyntaxKind.ForStatement: { 529 this.popLoopEnv(node, loopEnvLevel - 1); 530 break; 531 } 532 case ts.SyntaxKind.WhileStatement: 533 case ts.SyntaxKind.ForInStatement: 534 case ts.SyntaxKind.ForOfStatement: { 535 let popTimes = isContinue ? loopEnvLevel : loopEnvLevel - 1; 536 this.popLoopEnv(node, popTimes); 537 break; 538 } 539 case ts.SyntaxKind.SwitchStatement: { 540 if (!isContinue) { 541 return; 542 } 543 this.popLoopEnv(node, loopEnvLevel); 544 break; 545 } 546 /** 547 * BlockStatement could also have break labelTarget which changes the control flow 548 * out of their inner env loop. We should pop Loop env with such cases either. 549 */ 550 default: { 551 this.popLoopEnv(node, loopEnvLevel); 552 } 553 } 554 } 555 556 private compileContinueStatement(stmt: ts.ContinueStatement): void { 557 let continueLabelTarget = LabelTarget.getLabelTarget(stmt); 558 559 this.compileFinallyBeforeCFC( 560 continueLabelTarget.getTryStatement(), 561 ControlFlowChange.Continue, 562 continueLabelTarget.getContinueTargetLabel()! 563 ); 564 565 // before jmp out of loops, pop the loops env 566 if (continueLabelTarget.getLoopEnvLevel()) { 567 this.popLoopEnvWhenContinueOrBreak(continueLabelTarget, true); 568 } 569 570 this.pandaGen.branch(stmt, continueLabelTarget.getContinueTargetLabel()!); 571 } 572 573 private compileBreakStatement(stmt: ts.BreakStatement): void { 574 let breakLabelTarget = LabelTarget.getLabelTarget(stmt); 575 576 this.compileFinallyBeforeCFC( 577 breakLabelTarget.getTryStatement(), 578 ControlFlowChange.Break, 579 undefined 580 ); 581 582 // before jmp out of loops, pop the loops env 583 if (breakLabelTarget.getLoopEnvLevel()) { 584 this.popLoopEnvWhenContinueOrBreak(breakLabelTarget, false); 585 } 586 587 this.pandaGen.branch(stmt, breakLabelTarget.getBreakTargetLabel()); 588 } 589 590 private compileLabeledStatement(stmt: ts.LabeledStatement): void { 591 this.pushScope(stmt); 592 let labelName: string = jshelpers.getTextOfIdentifierOrLiteral(stmt.label); 593 let blockEndLabel = undefined; 594 595 // because there is no label in the block/if statement, we need to add the end label. 596 if (stmt.statement.kind === ts.SyntaxKind.Block || stmt.statement.kind === ts.SyntaxKind.IfStatement) { 597 blockEndLabel = new Label(); 598 599 let labelTarget = new LabelTarget(stmt, blockEndLabel, undefined); 600 601 LabelTarget.updateName2LabelTarget(stmt, labelTarget); 602 } 603 604 this.compileStatement(stmt.statement); 605 606 if (blockEndLabel) { 607 this.pandaGen.label(stmt, blockEndLabel); 608 } 609 610 // because the scope of the label is just in labeled statement, we need to delete it. 611 LabelTarget.deleteName2LabelTarget(labelName); 612 this.popScope(); 613 } 614 615 private compileThrowStatement(stmt: ts.ThrowStatement): void { 616 let pandaGen = this.pandaGen; 617 if (stmt.expression) { 618 this.compileExpression(stmt.expression); 619 } else { 620 throw new DiagnosticError(stmt, DiagnosticCode.Line_break_not_permitted_here); 621 } 622 623 // before CFG, pop the loops env 624 let popTimes = TryStatement.getCurrentTryStatement() ? TryStatement.getCurrentTryStatement().getLoopEnvLevel() : 0; 625 this.popLoopEnv(stmt, popTimes); 626 627 pandaGen.throw(stmt); 628 } 629 630 // compile finally before control flow change 631 compileFinallyBeforeCFC(endTry: TryStatement | undefined, cfc: ControlFlowChange, continueTargetLabel: Label | undefined): void { 632 let startTry = TryStatement.getCurrentTryStatement(); 633 let originTry = startTry; 634 let currentScope = this.scope; 635 for (; startTry != endTry; startTry = startTry?.getOuterTryStatement()) { 636 637 if (startTry && startTry.trybuilder) { 638 let inlineFinallyBegin = new Label(); 639 let inlineFinallyEnd = new Label(); 640 let inlinedLabelPair = new LabelPair(inlineFinallyBegin, inlineFinallyEnd); 641 // adjust the current tryStatement before inlining finallyBlock 642 let saveTry = TryStatement.getCurrentTryStatement(); 643 TryStatement.setCurrentTryStatement(startTry.getOuterTryStatement()); 644 645 this.pandaGen.label(startTry.getStatement(), inlineFinallyBegin); 646 startTry.trybuilder.compileFinalizer(cfc, continueTargetLabel); 647 this.pandaGen.label(startTry.getStatement(), inlineFinallyEnd); 648 // restore pandaGen.tryStatement 649 TryStatement.setCurrentTryStatement(saveTry); 650 651 /* 652 * split the catchZone in most Inner try & add the insertedZone by the finally-nearset TryZone. 653 * the inserted innerTry's FinallyBlock can only be catched by the outer's tryBlock. so here just 654 * need append the inserted finally's Zone into the outerTry's catchTable in order. 655 * OuterTryBegin ---- 656 * <outerTry_0> | 657 * InnerTryBegin ---- 658 * 659 * ---- InnerTry's FinallyBegin -- 660 * <outerTry_2> | | 661 * ---- InnerTry's FinallyEnd -- 662 * return; 663 * InnerTryEnd ---- 664 * <outerTry_1> | 665 * OuterTryEnd ---- 666 */ 667 originTry.getCatchTable().splitLabelPair(inlinedLabelPair); 668 if (startTry.getOuterTryStatement()) { 669 let outerLabelPairs: LabelPair[] = startTry.getOuterTryStatement().getCatchTable().getLabelPairs(); 670 outerLabelPairs.splice(outerLabelPairs.length - 2, 0, inlinedLabelPair); 671 } 672 } 673 } 674 this.scope = currentScope; 675 } 676 677 constructTry(node: ts.Node, tryBuilder: TryBuilderBase, endLabel?: Label): void { 678 let pandaGen = this.pandaGen; 679 let tryBeginLabel = new Label(); 680 let tryEndLabel = new Label(); 681 let catchBeginLabel = new Label(); 682 let catchEndLabel = endLabel ? endLabel : new Label(); 683 684 let catchTable = new CatchTable( 685 pandaGen, 686 catchBeginLabel, 687 new LabelPair(tryBeginLabel, tryEndLabel)); 688 689 // TryBlock begins 690 pandaGen.label(node, tryBeginLabel); 691 tryBuilder.compileTryBlock(catchTable); 692 pandaGen.label(node, tryEndLabel); 693 694 // Finally after normal try 695 tryBuilder.compileFinallyBlockIfExisted(); 696 if (ts.isForOfStatement(node)) { 697 let loopScope = <LoopScope>this.getRecorder().getScopeOfNode(node); 698 let needCreateLoopEnv = loopScope.need2CreateLexEnv(); 699 if (needCreateLoopEnv) { 700 pandaGen.popLexicalEnv(node); 701 } 702 } 703 pandaGen.branch(node, catchEndLabel); 704 705 // exception Handler 706 pandaGen.label(node, catchBeginLabel); 707 tryBuilder.compileExceptionHandler(); 708 if (!endLabel) { 709 pandaGen.label(node, catchEndLabel); 710 } 711 } 712 713 private compileTryStatement(stmt: ts.TryStatement): void { 714 this.pushScope(stmt); 715 // try-catch-finally statements must have been transformed into 716 // two nested try statements with only "catch" or "finally" each. 717 if (stmt.catchClause && stmt.finallyBlock) { 718 stmt = transformTryCatchFinally(stmt, this.recorder); 719 } 720 721 let tryBuilder = new TryBuilder(this, this.pandaGen, stmt); 722 this.constructTry(stmt, tryBuilder); 723 this.popScope(); 724 } 725 726 private compileFunctionDeclaration(decl: ts.FunctionDeclaration): void { 727 if (!decl.name) { 728 if (hasExportKeywordModifier(decl) && this.scope instanceof ModuleScope) { 729 return; 730 } 731 throw new Error("Function declaration without name is unimplemented"); 732 } 733 } 734 735 private compileExportAssignment(stmt: ts.ExportAssignment): void { 736 this.compileExpression(stmt.expression); 737 let defaultV: ModuleVariable = <ModuleVariable>(this.pandaGen.getScope().findLocal("*default*")); 738 this.pandaGen.storeModuleVariable(stmt, defaultV); 739 } 740 741 compileCondition(expr: ts.Expression, ifFalseLabel: Label): void { 742 let pandaGen = this.pandaGen; 743 if (expr.kind === ts.SyntaxKind.BinaryExpression) { 744 let binExpr = <ts.BinaryExpression>expr; 745 746 switch (binExpr.operatorToken.kind) { 747 case ts.SyntaxKind.LessThanToken: // line 57 748 case ts.SyntaxKind.GreaterThanToken: // line 59 749 case ts.SyntaxKind.LessThanEqualsToken: // line 60 750 case ts.SyntaxKind.GreaterThanEqualsToken: // line 61 751 case ts.SyntaxKind.EqualsEqualsToken: // line 62 752 case ts.SyntaxKind.ExclamationEqualsToken: // line 63 753 case ts.SyntaxKind.EqualsEqualsEqualsToken: // line 64 754 case ts.SyntaxKind.ExclamationEqualsEqualsToken: { // line 65 755 // This is a special case 756 // These operators are expressed via cmp instructions and the following 757 // if-else branches. Condition also expressed via cmp instruction and 758 // the following if-else. 759 // the goal of this method is to merge these two sequences of instructions. 760 let lhs = pandaGen.getTemp(); 761 this.compileExpression(binExpr.left); 762 pandaGen.storeAccumulator(binExpr, lhs); 763 this.compileExpression(binExpr.right); 764 pandaGen.condition(binExpr, binExpr.operatorToken.kind, lhs, ifFalseLabel); 765 pandaGen.freeTemps(lhs); 766 return; 767 } 768 case ts.SyntaxKind.AmpersandAmpersandToken: { 769 this.compileExpression(binExpr.left); 770 pandaGen.jumpIfFalse(binExpr, ifFalseLabel); 771 this.compileExpression(binExpr.right); 772 pandaGen.jumpIfFalse(binExpr, ifFalseLabel); 773 return; 774 } 775 case ts.SyntaxKind.BarBarToken: { 776 let endLabel = new Label(); 777 this.compileExpression(binExpr.left); 778 pandaGen.jumpIfTrue(binExpr, endLabel); 779 this.compileExpression(binExpr.right); 780 pandaGen.jumpIfFalse(binExpr, ifFalseLabel); 781 pandaGen.label(binExpr, endLabel); 782 return; 783 } 784 default: 785 break; 786 } 787 } 788 789 // General case including some binExpr i.e.(a+b) 790 this.compileExpression(expr); 791 pandaGen.jumpIfFalse(expr, ifFalseLabel); 792 } 793 794 compileExpression(expr: ts.Expression): void { 795 // Please keep order of cases the same as in types.ts 796 LOGD(this.debugTag, "compile expr: " + ts.SyntaxKind[expr.kind] + " " + expr.kind); 797 switch (expr.kind) { 798 case ts.SyntaxKind.NumericLiteral: // line 34 799 compileNumericLiteral(this.pandaGen, <ts.NumericLiteral>expr); 800 break; 801 case ts.SyntaxKind.BigIntLiteral: // line 35 802 compileBigIntLiteral(this.pandaGen, <ts.BigIntLiteral>expr); 803 break; 804 case ts.SyntaxKind.StringLiteral: // line 36 805 compileStringLiteral(this.pandaGen, <ts.StringLiteral>expr); 806 break; 807 case ts.SyntaxKind.RegularExpressionLiteral: // line 39 808 compileRegularExpressionLiteral(this, <ts.RegularExpressionLiteral>expr); 809 break; 810 case ts.SyntaxKind.Identifier: // line 109 811 this.compileIdentifier(<ts.Identifier>expr); 812 break; 813 case ts.SyntaxKind.TrueKeyword: // line 114 814 case ts.SyntaxKind.FalseKeyword: // line 126 815 this.compileBooleanLiteral(<ts.BooleanLiteral>expr); 816 break; 817 case ts.SyntaxKind.CallExpression: // line 243 818 compileCallExpression(<ts.CallExpression>expr, this); 819 break; 820 case ts.SyntaxKind.NullKeyword: // line 135 821 this.pandaGen.loadAccumulator(expr, getVregisterCache(this.pandaGen, CacheList.NULL)); 822 break; 823 case ts.SyntaxKind.ThisKeyword: // line 139 824 this.compileThisKeyword(expr); 825 break; 826 case ts.SyntaxKind.MetaProperty: 827 compileMetaProperty(<ts.MetaProperty>expr, this); 828 break; 829 case ts.SyntaxKind.ArrayLiteralExpression: // line 239 830 compileArrayLiteralExpression(this, <ts.ArrayLiteralExpression>expr); 831 break; 832 case ts.SyntaxKind.ObjectLiteralExpression: // line 240 833 compileObjectLiteralExpression(this, <ts.ObjectLiteralExpression>expr); 834 break; 835 case ts.SyntaxKind.PropertyAccessExpression: // line 241 836 case ts.SyntaxKind.ElementAccessExpression: // line 242 837 compileMemberAccessExpression(<ts.ElementAccessExpression | ts.PropertyAccessExpression>expr, this); 838 break; 839 case ts.SyntaxKind.NewExpression: // line 244 840 compileNewExpression(<ts.NewExpression>expr, this); 841 break; 842 case ts.SyntaxKind.ParenthesizedExpression: // line 247 843 this.compileExpression(findInnerExprOfParenthesis(<ts.ParenthesizedExpression>expr)); 844 break; 845 case ts.SyntaxKind.FunctionExpression: // line 248 846 this.compileFunctionExpression(<ts.FunctionExpression>expr); 847 break; 848 case ts.SyntaxKind.DeleteExpression: // line 250 849 this.compileDeleteExpression(<ts.DeleteExpression>expr); 850 break; 851 case ts.SyntaxKind.TypeOfExpression: // line 251 852 this.compileTypeOfExpression(<ts.TypeOfExpression>expr); 853 break; 854 case ts.SyntaxKind.VoidExpression: // line 252 855 this.compileVoidExpression(<ts.VoidExpression>expr); 856 break; 857 case ts.SyntaxKind.AwaitExpression: 858 this.compileAwaitExpression(<ts.AwaitExpression>expr); 859 break; 860 case ts.SyntaxKind.PrefixUnaryExpression: // line 254 861 this.compilePrefixUnaryExpression(<ts.PrefixUnaryExpression>expr); 862 break; 863 case ts.SyntaxKind.PostfixUnaryExpression: // line 255 864 this.compilePostfixUnaryExpression(<ts.PostfixUnaryExpression>expr); 865 break; 866 case ts.SyntaxKind.BinaryExpression: // line 256 867 this.compileBinaryExpression(<ts.BinaryExpression>expr); 868 break; 869 case ts.SyntaxKind.ConditionalExpression: // line 257 870 this.compileConditionalExpression(<ts.ConditionalExpression>expr); 871 break; 872 case ts.SyntaxKind.YieldExpression: // line 259 873 compileYieldExpression(this, <ts.YieldExpression>expr); 874 break; 875 case ts.SyntaxKind.ArrowFunction: //line 249 876 this.compileArrowFunction(<ts.ArrowFunction>expr); 877 break; 878 case ts.SyntaxKind.TemplateExpression: 879 this.compileTemplateExpression(<ts.TemplateExpression>expr); 880 break; 881 case ts.SyntaxKind.NoSubstitutionTemplateLiteral: 882 case ts.SyntaxKind.FirstTemplateToken: 883 case ts.SyntaxKind.LastLiteralToken: 884 this.compileNoSubstitutionTemplateLiteral(<ts.NoSubstitutionTemplateLiteral>expr); 885 break; 886 case ts.SyntaxKind.TaggedTemplateExpression: 887 this.compileTaggedTemplateExpression(<ts.TaggedTemplateExpression>expr); 888 break; 889 case ts.SyntaxKind.Constructor: 890 break; 891 case ts.SyntaxKind.PropertyDeclaration: 892 break; 893 case ts.SyntaxKind.ClassExpression: 894 compileClassDeclaration(this, <ts.ClassLikeDeclaration>expr); 895 break; 896 case ts.SyntaxKind.PartiallyEmittedExpression: 897 this.compileExpression((<ts.PartiallyEmittedExpression>expr).expression); 898 break; 899 case ts.SyntaxKind.CommaListExpression: 900 compileCommaListExpression(this, <ts.CommaListExpression>expr); 901 break; 902 default: 903 throw new Error("Expression of type " + this.getNodeName(expr) + " is unimplemented"); 904 } 905 } 906 907 private compileIdentifier(id: ts.Identifier): void { 908 let name = jshelpers.getTextOfIdentifierOrLiteral(id); 909 let { scope, level, v } = this.scope.find(name); 910 if (!v) { 911 // the variable may appear after function call 912 // any way it is a global variable. 913 this.compileUnscopedIdentifier(id); 914 } else { 915 this.loadTarget(id, { scope, level, v }); 916 } 917 } 918 919 private compileUnscopedIdentifier(id: ts.Identifier): void { 920 let name = jshelpers.getTextOfIdentifierOrLiteral(id); 921 let pandaGen = this.pandaGen; 922 switch (name) { 923 // Those identifier are Built-In value properties 924 case "NaN": 925 pandaGen.loadAccumulator(id, getVregisterCache(this.pandaGen, CacheList.NAN)); 926 return; 927 case "Infinity": 928 pandaGen.loadAccumulator(id, getVregisterCache(this.pandaGen, CacheList.INFINITY)); 929 return; 930 case "globalThis": 931 pandaGen.loadAccumulator(id, getVregisterCache(this.pandaGen, CacheList.GLOBAL)); 932 return; 933 case "undefined": 934 pandaGen.loadAccumulator(id, getVregisterCache(this.pandaGen, CacheList.UNDEFINED)); 935 return; 936 default: { 937 // typeof an undeclared variable will return undefined instead of throwing reference error 938 let parent = findOuterNodeOfParenthesis(id); 939 if ((parent.kind === ts.SyntaxKind.TypeOfExpression)) { 940 CmdOptions.isWatchEvaluateExpressionMode() ? 941 pandaGen.loadByNameViaDebugger(id, name, CacheList.FALSE) : 942 pandaGen.loadObjProperty(id, getVregisterCache(pandaGen, CacheList.GLOBAL), name); 943 } else { 944 pandaGen.tryLoadGlobalByName(id, name); 945 } 946 break; 947 } 948 } 949 } 950 951 private compileBooleanLiteral(lit: ts.BooleanLiteral): void { 952 if (lit.kind === ts.SyntaxKind.TrueKeyword) { 953 this.pandaGen.loadAccumulator(lit, getVregisterCache(this.pandaGen, CacheList.TRUE)); 954 } else { 955 this.pandaGen.loadAccumulator(lit, getVregisterCache(this.pandaGen, CacheList.FALSE)); 956 } 957 } 958 959 compileFunctionReturnThis(expr: ts.NewExpression | ts.CallExpression): boolean { 960 if (expr.expression.kind === ts.SyntaxKind.Identifier) { 961 let identifier = <ts.Identifier>expr.expression; 962 let args = expr.arguments; 963 if (identifier.escapedText === "Function") { 964 if (args && args.length > 0) { 965 if (!ts.isStringLiteral(args[args.length - 1])) { 966 return false; 967 } 968 let arg = <ts.StringLiteral>args[args.length - 1]; 969 if (arg.text.match(/ *return +this[;]? *$/) === null) { 970 return false; 971 } else { 972 this.pandaGen.loadAccumulator(expr, getVregisterCache(this.pandaGen, CacheList.GLOBAL)); 973 return true; 974 } 975 } 976 } 977 } 978 return false; 979 } 980 981 private compileThisKeyword(node: ts.Node): void { 982 let pandaGen = this.pandaGen; 983 984 checkValidUseSuperBeforeSuper(this, node); 985 986 let { scope, level, v } = this.scope.find(MandatoryThis); 987 988 if (!v) { 989 throw new Error("\"this\" not found"); 990 } 991 992 if (v instanceof LocalVariable) { 993 if (CmdOptions.isWatchEvaluateExpressionMode()) { 994 pandaGen.loadByNameViaDebugger(node, MandatoryThis, CacheList.TRUE); 995 return; 996 } 997 998 pandaGen.loadAccFromLexEnv(node, scope!, level, v); 999 return; 1000 } 1001 1002 throw new Error("\"this\" must be a local variable"); 1003 } 1004 1005 private compileFunctionExpression(expr: ts.FunctionExpression): void { 1006 let internalName = this.compilerDriver.getFuncInternalName(expr, this.recorder); 1007 this.pandaGen.defineFunction(expr, expr, internalName); 1008 } 1009 1010 private compileDeleteExpression(expr: ts.DeleteExpression): void { 1011 let pandaGen = this.pandaGen; 1012 let objReg: VReg; 1013 let propReg: VReg; 1014 let unaryExpr = expr.expression; 1015 switch (unaryExpr.kind) { 1016 case ts.SyntaxKind.Identifier: { 1017 // Check if this is a known variable. 1018 let name = jshelpers.getTextOfIdentifierOrLiteral(<ts.Identifier>unaryExpr); 1019 let { scope, v } = this.scope.find(name); 1020 1021 if (!v || ((scope instanceof GlobalScope) && (v instanceof GlobalVariable))) { 1022 // If the variable doesn't exist or if it is global, we must generate 1023 // a delete global property instruction. 1024 objReg = getVregisterCache(pandaGen, CacheList.GLOBAL); 1025 pandaGen.loadAccumulatorString(unaryExpr, name); 1026 pandaGen.deleteObjProperty(expr, objReg); 1027 } else { 1028 // Otherwise it is a local variable which can't be deleted and we just 1029 // return false. 1030 pandaGen.loadAccumulator(unaryExpr, getVregisterCache(pandaGen, CacheList.FALSE)); 1031 } 1032 break; 1033 } 1034 case ts.SyntaxKind.PropertyAccessExpression: 1035 case ts.SyntaxKind.ElementAccessExpression: { 1036 objReg = pandaGen.getTemp(); 1037 propReg = pandaGen.getTemp(); 1038 1039 if (jshelpers.isSuperProperty(unaryExpr)) { 1040 pandaGen.throwDeleteSuperProperty(unaryExpr); 1041 pandaGen.freeTemps(objReg, propReg); 1042 return; 1043 } 1044 1045 let { prop: prop } = getObjAndProp(<ts.PropertyAccessExpression | ts.ElementAccessExpression>unaryExpr, objReg, propReg, this); 1046 switch (typeof prop) { 1047 case "string": 1048 pandaGen.loadAccumulatorString(expr, prop); 1049 break; 1050 case "number": 1051 pandaGen.loadAccumulatorInt(expr, prop); 1052 break; 1053 default: 1054 pandaGen.loadAccumulator(expr, prop); 1055 break; 1056 } 1057 1058 pandaGen.deleteObjProperty(expr, objReg); 1059 pandaGen.freeTemps(objReg, propReg); 1060 break; 1061 } 1062 default: { 1063 // compile the delete operand. 1064 this.compileExpression(unaryExpr); 1065 // Deleting any value or a result of an expression returns True. 1066 pandaGen.loadAccumulator(expr, getVregisterCache(pandaGen, CacheList.TRUE)); 1067 } 1068 } 1069 } 1070 1071 private compileTypeOfExpression(expr: ts.TypeOfExpression): void { 1072 // expr -> acc 1073 this.compileExpression(expr.expression); 1074 this.pandaGen.typeOf(expr); 1075 } 1076 1077 private compileVoidExpression(expr: ts.VoidExpression): void { 1078 let pandaGen = this.pandaGen; 1079 // compileExpression() must be called even though its value is not used 1080 // because it may have observable sideeffects. 1081 this.compileExpression(expr.expression); 1082 pandaGen.loadAccumulator(expr, getVregisterCache(pandaGen, CacheList.UNDEFINED)); 1083 } 1084 1085 private compileAwaitExpression(expr: ts.AwaitExpression): void { 1086 let pandaGen = this.pandaGen; 1087 1088 if (!(this.funcBuilder instanceof AsyncFunctionBuilder || this.funcBuilder instanceof AsyncGeneratorFunctionBuilder)) { 1089 throw new DiagnosticError(expr.parent, DiagnosticCode.await_expressions_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules); 1090 } 1091 1092 if (expr.expression) { 1093 this.compileExpression(expr.expression); 1094 this.funcBuilder.await(expr); 1095 } else { 1096 pandaGen.loadAccumulator(expr, getVregisterCache(pandaGen, CacheList.UNDEFINED)); 1097 this.funcBuilder.await(expr); 1098 } 1099 } 1100 1101 private compilePrefixUnaryExpression(expr: ts.PrefixUnaryExpression): void { 1102 let pandaGen = this.pandaGen; 1103 let operandReg = pandaGen.getTemp(); 1104 // acc -> op(acc) 1105 switch (expr.operator) { 1106 case ts.SyntaxKind.PlusPlusToken: // line 73 1107 case ts.SyntaxKind.MinusMinusToken: { 1108 // line 74 1109 let lref = LReference.generateLReference(this, expr.operand, false); 1110 lref.getValue(); 1111 pandaGen.storeAccumulator(expr, operandReg); 1112 pandaGen.unary(expr, expr.operator, operandReg); 1113 lref.setValue(); 1114 break; 1115 } 1116 case ts.SyntaxKind.PlusToken: // line 67 1117 case ts.SyntaxKind.MinusToken: // line 68 1118 case ts.SyntaxKind.ExclamationToken: // line 81 1119 case ts.SyntaxKind.TildeToken: { // line 82 1120 this.compileExpression(expr.operand); 1121 pandaGen.storeAccumulator(expr, operandReg); 1122 pandaGen.unary(expr, expr.operator, operandReg); 1123 break; 1124 } 1125 default: 1126 break; 1127 } 1128 pandaGen.freeTemps(operandReg); 1129 } 1130 1131 private compilePostfixUnaryExpression(expr: ts.PostfixUnaryExpression): void { 1132 let pandaGen = this.pandaGen; 1133 let operandReg = pandaGen.getTemp(); 1134 // expr -> acc 1135 let lref = LReference.generateLReference(this, expr.operand, false); 1136 lref.getValue(); 1137 // operand = acc 1138 pandaGen.storeAccumulator(expr, operandReg); 1139 // acc +/- 1 1140 switch (expr.operator) { 1141 case ts.SyntaxKind.PlusPlusToken: 1142 case ts.SyntaxKind.MinusMinusToken: 1143 pandaGen.unary(expr, expr.operator, operandReg); 1144 break; 1145 default: 1146 break; 1147 } 1148 // lvalue var = acc +/- 1 1149 lref.setValue(); 1150 // acc = operand_old 1151 pandaGen.toNumeric(expr, operandReg); 1152 pandaGen.freeTemps(operandReg); 1153 } 1154 1155 private compileLogicalExpression(expr: ts.BinaryExpression): void { 1156 let pandaGen = this.pandaGen; 1157 let lhs = pandaGen.getTemp(); 1158 switch (expr.operatorToken.kind) { 1159 case ts.SyntaxKind.AmpersandAmpersandToken: { // line 83 1160 let leftFalseLabel = new Label(); 1161 let endLabel = new Label(); 1162 1163 // left -> acc 1164 this.compileExpression(expr.left); 1165 pandaGen.storeAccumulator(expr, lhs); 1166 pandaGen.jumpIfFalse(expr, leftFalseLabel); 1167 1168 // left is true then right -> acc 1169 this.compileExpression(expr.right); 1170 pandaGen.branch(expr, endLabel); 1171 1172 // left is false then lhs -> acc 1173 pandaGen.label(expr, leftFalseLabel); 1174 pandaGen.loadAccumulator(expr, lhs); 1175 pandaGen.label(expr, endLabel); 1176 break; 1177 } 1178 case ts.SyntaxKind.BarBarToken: { // line 84 1179 let leftTrueLabel = new Label(); 1180 let endLabel = new Label(); 1181 1182 // left -> acc 1183 this.compileExpression(expr.left); 1184 pandaGen.storeAccumulator(expr, lhs); 1185 pandaGen.jumpIfTrue(expr, leftTrueLabel); 1186 1187 // left is false then right -> acc 1188 this.compileExpression(expr.right); 1189 pandaGen.branch(expr, endLabel); 1190 1191 // left is true then lhs -> acc 1192 pandaGen.label(expr, leftTrueLabel); 1193 pandaGen.loadAccumulator(expr, lhs); 1194 pandaGen.label(expr, endLabel); 1195 break; 1196 } 1197 case ts.SyntaxKind.QuestionQuestionToken: { // line 90 1198 let leftNullishLabel = new Label(); 1199 let endLabel = new Label(); 1200 // left -> acc -> lhs 1201 this.compileExpression(expr.left); 1202 pandaGen.storeAccumulator(expr, lhs); 1203 // equality comparasion between lhs and null, if true, load right 1204 pandaGen.condition(expr, ts.SyntaxKind.ExclamationEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.NULL), leftNullishLabel); 1205 // equality comparasion between lhs and undefined, if true, load right 1206 pandaGen.loadAccumulator(expr.left, lhs); 1207 pandaGen.condition(expr, ts.SyntaxKind.ExclamationEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.UNDEFINED), leftNullishLabel); 1208 // lhs is either null or undefined, load left 1209 pandaGen.loadAccumulator(expr, lhs); 1210 pandaGen.branch(expr, endLabel); 1211 pandaGen.label(expr, leftNullishLabel); 1212 this.compileExpression(expr.right); 1213 pandaGen.label(expr, endLabel); 1214 break; 1215 } 1216 default: 1217 throw new Error("BinaryExpression with operatorToken " + this.getNodeName(expr.operatorToken) + " is not Logical Operator"); 1218 } 1219 pandaGen.freeTemps(lhs); 1220 } 1221 1222 private compileBinaryExpression(expr: ts.BinaryExpression): void { 1223 if (isAssignmentOperator(expr.operatorToken.kind)) { 1224 this.compileAssignmentExpression(expr.left, expr.right, <AssignmentOperator>expr.operatorToken.kind); 1225 return; 1226 } 1227 // LogicAnd, LogicOr and Coalesce are Short-circuiting 1228 if (expr.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || 1229 expr.operatorToken.kind === ts.SyntaxKind.BarBarToken || 1230 expr.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken) { 1231 this.compileLogicalExpression(expr); 1232 return; 1233 } 1234 1235 let pandaGen = this.pandaGen; 1236 let lhs = pandaGen.getTemp(); 1237 this.compileExpression(expr.left); 1238 pandaGen.storeAccumulator(expr, lhs); 1239 this.compileExpression(expr.right); 1240 1241 if (expr.operatorToken.kind != ts.SyntaxKind.CommaToken) { 1242 pandaGen.binary(expr, expr.operatorToken.kind, lhs); 1243 } 1244 1245 pandaGen.freeTemps(lhs); 1246 } 1247 1248 private compileConditionalExpression(expr: ts.ConditionalExpression): void { 1249 let falseLabel = new Label(); 1250 let endLabel = new Label(); 1251 1252 this.compileCondition(expr.condition, falseLabel); 1253 this.compileExpression(expr.whenTrue); 1254 this.pandaGen.branch(expr, endLabel); 1255 this.pandaGen.label(expr, falseLabel); 1256 this.compileExpression(expr.whenFalse); 1257 this.pandaGen.label(expr, endLabel); 1258 } 1259 1260 private compileArrowFunction(expr: ts.ArrowFunction): void { 1261 let internalName = this.compilerDriver.getFuncInternalName(expr, this.recorder); 1262 this.pandaGen.defineFunction(expr, expr, internalName); 1263 } 1264 1265 private compileTemplateSpan(expr: ts.TemplateSpan): void { 1266 let span = expr.expression; 1267 this.compileExpression(span); 1268 let literal = expr.literal; 1269 let lrh = this.pandaGen.getTemp(); 1270 let text = literal.text; 1271 1272 if (text.length != 0) { 1273 this.pandaGen.storeAccumulator(expr, lrh); 1274 this.pandaGen.loadAccumulatorString(expr, text); 1275 this.pandaGen.binary(expr, ts.SyntaxKind.PlusToken, lrh); 1276 } 1277 1278 this.pandaGen.freeTemps(lrh); 1279 } 1280 1281 private compileTemplateExpression(expr: ts.TemplateExpression): void { 1282 let pandaGen = this.pandaGen; 1283 let head = expr.head; 1284 let spans = expr.templateSpans; 1285 1286 let lrh = pandaGen.getTemp(); 1287 pandaGen.loadAccumulatorString(expr, head.text); 1288 1289 if (spans && spans.length > 0) { 1290 spans.forEach((spanExp: ts.TemplateSpan) => { 1291 pandaGen.storeAccumulator(expr, lrh); 1292 this.compileTemplateSpan(spanExp); 1293 pandaGen.binary(expr, ts.SyntaxKind.PlusToken, lrh); 1294 }); 1295 } 1296 1297 pandaGen.freeTemps(lrh); 1298 } 1299 1300 private compileNoSubstitutionTemplateLiteral(expr: ts.NoSubstitutionTemplateLiteral): void { 1301 let text = expr.text; 1302 this.pandaGen.loadAccumulatorString(expr, text); 1303 } 1304 1305 private compileTaggedTemplateExpression(expr: ts.TaggedTemplateExpression): void { 1306 let pandaGen = this.pandaGen; 1307 let spans = undefined; 1308 if (ts.isTemplateExpression(expr.template)) { 1309 spans = expr.template.templateSpans; 1310 } 1311 1312 let { arguments: argRegs, passThis: passThis } = getHiddenParameters(expr.tag, this); // +3 for function and this 1313 getTemplateObject(pandaGen, expr); 1314 let templateObj = pandaGen.getTemp(); 1315 pandaGen.storeAccumulator(expr, templateObj); 1316 argRegs.push(templateObj); 1317 1318 if (spans && spans.length) { 1319 spans.forEach((spanExp: ts.TemplateSpan) => { 1320 let exprReg = pandaGen.getTemp(); 1321 this.compileExpression(spanExp.expression); 1322 pandaGen.storeAccumulator(spanExp, exprReg); 1323 argRegs.push(exprReg); 1324 }); 1325 } 1326 1327 pandaGen.call(expr, argRegs, passThis); 1328 pandaGen.freeTemps(...argRegs); 1329 1330 return; 1331 } 1332 1333 private compileAssignmentExpression(lhs: ts.Expression, rhs: ts.Expression, operator: AssignmentOperator): void { 1334 let lref = LReference.generateLReference(this, lhs, false); 1335 1336 if (operator != ts.SyntaxKind.EqualsToken) { 1337 let lhsVreg = this.pandaGen.getTemp(); 1338 1339 lref.getValue(); 1340 this.pandaGen.storeAccumulator(lhs, lhsVreg); 1341 this.compileExpression(rhs); 1342 this.pandaGen.binary(lhs.parent, operator, lhsVreg); 1343 this.pandaGen.freeTemps(lhsVreg); 1344 } else { 1345 this.compileExpression(rhs); 1346 } 1347 1348 lref.setValue(); 1349 } 1350 1351 pushScope(node: ts.Node): void { 1352 let scope = <Scope>this.recorder.getScopeOfNode(node); 1353 this.scope = scope; 1354 // for debug info 1355 DebugInfo.addDebugIns(scope, this.pandaGen, true); 1356 } 1357 1358 popScope(): void { 1359 // for debug info 1360 DebugInfo.addDebugIns(this.scope, this.pandaGen, false); 1361 this.scope = <Scope>this.scope.getParent(); 1362 } 1363 1364 private getNodeName(node: ts.Node): string { 1365 return ts.SyntaxKind[node.kind]; 1366 } 1367 1368 getThis(node: ts.Node, res: VReg): void { 1369 let pandaGen = this.pandaGen; 1370 let thisInfo = this.getCurrentScope().find(MandatoryThis); 1371 let level = thisInfo.level; 1372 let v = <Variable>thisInfo.v; 1373 1374 if (v.isLexVar) { 1375 let slot = v.idxLex; 1376 pandaGen.loadLexicalVar(node, level, slot); 1377 pandaGen.storeAccumulator(node, res); 1378 } else { 1379 pandaGen.moveVreg(node, res, pandaGen.getVregForVariable(v)); 1380 } 1381 } 1382 1383 setThis(node: ts.Node): void { 1384 let pandaGen = this.pandaGen; 1385 let thisInfo = this.getCurrentScope().find(MandatoryThis); 1386 1387 if (thisInfo.v!.isLexVar) { 1388 let slot = (<Variable>thisInfo.v).idxLex; 1389 let value = pandaGen.getTemp(); 1390 pandaGen.storeAccumulator(node, value); 1391 pandaGen.storeLexicalVar(node, thisInfo.level, slot, value); 1392 pandaGen.freeTemps(value); 1393 } else { 1394 pandaGen.storeAccumulator(node, pandaGen.getVregForVariable(<Variable>thisInfo.v)); 1395 } 1396 } 1397 1398 getPandaGen(): PandaGen { 1399 return this.pandaGen; 1400 } 1401 1402 getCurrentScope(): Scope { 1403 return this.scope; 1404 } 1405 1406 getCompilerDriver(): CompilerDriver { 1407 return this.compilerDriver; 1408 } 1409 1410 getRecorder(): Recorder { 1411 return this.recorder; 1412 } 1413 1414 getFuncBuilder(): FunctionBuilder { 1415 return this.funcBuilder; 1416 } 1417 1418 storeTarget(node: ts.Node, 1419 variable: { scope: Scope | undefined, level: number, v: Variable | undefined }, 1420 isDeclaration: boolean): void { 1421 if (variable.v instanceof LocalVariable) { 1422 if (isDeclaration && variable.v.isLetOrConst()) { 1423 variable.v.initialize(); 1424 if (variable.scope instanceof GlobalScope) { 1425 if (variable.v.isLet()) { 1426 this.pandaGen.stLetOrClassToGlobalRecord(node, variable.v.getName()); 1427 } else { 1428 this.pandaGen.stConstToGlobalRecord(node, variable.v.getName()); 1429 } 1430 return; 1431 } 1432 } 1433 1434 if (variable.v.isLetOrConst() && variable.scope instanceof GlobalScope) { 1435 this.pandaGen.tryStoreGlobalByName(node, variable.v.getName()); 1436 return; 1437 } 1438 1439 this.pandaGen.storeAccToLexEnv(node, variable.scope!, variable.level, variable.v, isDeclaration); 1440 } else if (variable.v instanceof GlobalVariable) { 1441 if (variable.v.isNone() && isStrictMode(node)) { 1442 this.pandaGen.tryStoreGlobalByName(node, variable.v.getName()); 1443 } else { 1444 this.pandaGen.storeGlobalVar(node, variable.v.getName()); 1445 } 1446 } else if (variable.v instanceof ModuleVariable) { 1447 // import module variable is const, throw `const assignment error` 1448 if (!isDeclaration && variable.v.isConst()) { 1449 let nameReg = this.pandaGen.getTemp(); 1450 this.pandaGen.loadAccumulatorString(node, variable.v.getName()); 1451 this.pandaGen.storeAccumulator(node, nameReg); 1452 this.pandaGen.throwConstAssignment(node, nameReg); 1453 this.pandaGen.freeTemps(nameReg); 1454 return; 1455 } 1456 1457 if (isDeclaration) { 1458 variable.v.initialize(); 1459 } 1460 1461 if ((variable.v.isLet() || variable.v.isClass()) && !variable.v.isInitialized()) { 1462 let valueReg = this.pandaGen.getTemp(); 1463 this.pandaGen.storeAccumulator(node, valueReg); 1464 this.pandaGen.loadModuleVariable(node, variable.v, true); 1465 this.pandaGen.throwUndefinedIfHole(node, variable.v.getName()); 1466 this.pandaGen.loadAccumulator(node, valueReg); 1467 this.pandaGen.freeTemps(valueReg); 1468 } 1469 1470 this.pandaGen.storeModuleVariable(node, variable.v); 1471 } else { 1472 throw new Error("invalid lhsRef to store"); 1473 } 1474 } 1475 1476 loadTarget(node: ts.Node, variable: { scope: Scope | undefined, level: number, v: Variable | undefined }): void { 1477 if (variable.v instanceof LocalVariable) { 1478 if (!CmdOptions.isCommonJs() && (variable.v.isLetOrConst() || variable.v.isClass())) { 1479 if (variable.scope instanceof GlobalScope) { 1480 this.pandaGen.tryLoadGlobalByName(node, variable.v.getName()); 1481 return; 1482 } 1483 } 1484 1485 this.pandaGen.loadAccFromLexEnv(node, variable.scope!, variable.level, (<LocalVariable>variable.v)); 1486 } else if (variable.v instanceof GlobalVariable) { 1487 if (variable.v.isNone()) { 1488 let parent = findOuterNodeOfParenthesis(node); 1489 if ((parent.kind === ts.SyntaxKind.TypeOfExpression)) { 1490 CmdOptions.isWatchEvaluateExpressionMode() ? 1491 this.pandaGen.loadByNameViaDebugger(node, variable.v.getName(), CacheList.FALSE) : 1492 this.pandaGen.loadObjProperty(node, getVregisterCache(this.pandaGen, CacheList.GLOBAL), 1493 variable.v.getName()); 1494 } else { 1495 this.pandaGen.tryLoadGlobalByName(node, variable.v.getName()); 1496 } 1497 } else { 1498 this.pandaGen.loadGlobalVar(node, variable.v.getName()); 1499 } 1500 } else if (variable.v instanceof ModuleVariable) { 1501 let isLocal: boolean = variable.v.isExportVar() ? true : false; 1502 this.pandaGen.loadModuleVariable(node, variable.v, isLocal); 1503 if ((variable.v.isLetOrConst() || variable.v.isClass()) && !variable.v.isInitialized()) { 1504 this.pandaGen.throwUndefinedIfHole(node, variable.v.getName()); 1505 } 1506 } else { 1507 // Handle the variables from lexical scope 1508 throw new Error("Only local and global variables are implemented"); 1509 } 1510 } 1511} 1512