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() { 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) { 174 this.envUnion.push(env); 175 } 176 177 popEnv() { 178 this.envUnion.pop(); 179 } 180 181 getCurrentEnv() { 182 return this.envUnion[this.envUnion.length - 1]; 183 } 184 185 private storeFuncObj2LexEnvIfNeeded() { 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.FirstNodeOfFunction, 196 getVregisterCache(this.pandaGen, CacheList.FUNC)); 197 this.pandaGen.storeAccToLexEnv(NodeKind.FirstNodeOfFunction, v.scope, v.level, v.v, true); 198 } 199 } 200 } 201 202 private compileLexicalBindingForArrowFunction() { 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) { 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) { 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) { 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) { 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) { 477 let declList = stmt.declarationList; 478 declList.declarations.forEach((decl) => { 479 this.compileVariableDeclaration(decl) 480 }); 481 } 482 483 compileVariableDeclaration(decl: ts.VariableDeclaration) { 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) { 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) { 518 while(times--) { 519 this.pandaGen.popLexicalEnv(node); 520 } 521 } 522 523 private popLoopEnvWhenContinueOrBreak(labelTarget: LabelTarget, isContinue: boolean) { 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) { 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) { 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) { 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) { 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 compileFinallyBeforeCFC(endTry: TryStatement | undefined, cfc: ControlFlowChange, continueTargetLabel: Label | undefined) {// compile finally before control flow change 631 let startTry = TryStatement.getCurrentTryStatement(); 632 let originTry = startTry; 633 let currentScope = this.scope; 634 for (; startTry != endTry; startTry = startTry?.getOuterTryStatement()) { 635 636 if (startTry && startTry.trybuilder) { 637 let inlineFinallyBegin = new Label(); 638 let inlineFinallyEnd = new Label(); 639 let inlinedLabelPair = new LabelPair(inlineFinallyBegin, inlineFinallyEnd); 640 // adjust the current tryStatement before inlining finallyBlock 641 let saveTry = TryStatement.getCurrentTryStatement(); 642 TryStatement.setCurrentTryStatement(startTry.getOuterTryStatement()) 643 644 this.pandaGen.label(startTry.getStatement(), inlineFinallyBegin); 645 startTry.trybuilder.compileFinalizer(cfc, continueTargetLabel); 646 this.pandaGen.label(startTry.getStatement(), inlineFinallyEnd); 647 // restore pandaGen.tryStatement 648 TryStatement.setCurrentTryStatement(saveTry); 649 650 /* 651 * split the catchZone in most Inner try & add the insertedZone by the finally-nearset TryZone. 652 * the inserted innerTry's FinallyBlock can only be catched by the outer's tryBlock. so here just 653 * need append the inserted finally's Zone into the outerTry's catchTable in order. 654 * OuterTryBegin ---- 655 * <outerTry_0> | 656 * InnerTryBegin ---- 657 * 658 * ---- InnerTry's FinallyBegin -- 659 * <outerTry_2> | | 660 * ---- InnerTry's FinallyEnd -- 661 * return; 662 * InnerTryEnd ---- 663 * <outerTry_1> | 664 * OuterTryEnd ---- 665 */ 666 originTry.getCatchTable().splitLabelPair(inlinedLabelPair); 667 if (startTry.getOuterTryStatement()) { 668 let outerLabelPairs: LabelPair[] = startTry.getOuterTryStatement().getCatchTable().getLabelPairs(); 669 outerLabelPairs.splice(outerLabelPairs.length - 2, 0, inlinedLabelPair); 670 } 671 } 672 } 673 this.scope = currentScope; 674 } 675 676 constructTry(node: ts.Node, tryBuilder: TryBuilderBase, endLabel?: Label) { 677 let pandaGen = this.pandaGen; 678 let tryBeginLabel = new Label(); 679 let tryEndLabel = new Label(); 680 let catchBeginLabel = new Label(); 681 let catchEndLabel = endLabel ? endLabel : new Label(); 682 683 let catchTable = new CatchTable( 684 pandaGen, 685 catchBeginLabel, 686 new LabelPair(tryBeginLabel, tryEndLabel)); 687 688 // TryBlock begins 689 pandaGen.label(node, tryBeginLabel); 690 tryBuilder.compileTryBlock(catchTable); 691 pandaGen.label(node, tryEndLabel); 692 693 // Finally after normal try 694 tryBuilder.compileFinallyBlockIfExisted(); 695 if (ts.isForOfStatement(node)) { 696 let loopScope = <LoopScope>this.getRecorder().getScopeOfNode(node); 697 let needCreateLoopEnv = loopScope.need2CreateLexEnv(); 698 if (needCreateLoopEnv) { 699 pandaGen.popLexicalEnv(node); 700 } 701 } 702 pandaGen.branch(node, catchEndLabel); 703 704 // exception Handler 705 pandaGen.label(node, catchBeginLabel); 706 tryBuilder.compileExceptionHandler(); 707 if (!endLabel) { 708 pandaGen.label(node, catchEndLabel); 709 } 710 } 711 712 private compileTryStatement(stmt: ts.TryStatement) { 713 this.pushScope(stmt); 714 // try-catch-finally statements must have been transformed into 715 // two nested try statements with only "catch" or "finally" each. 716 if (stmt.catchClause && stmt.finallyBlock) { 717 stmt = transformTryCatchFinally(stmt, this.recorder); 718 } 719 720 let tryBuilder = new TryBuilder(this, this.pandaGen, stmt); 721 this.constructTry(stmt, tryBuilder); 722 this.popScope(); 723 } 724 725 private compileFunctionDeclaration(decl: ts.FunctionDeclaration) { 726 if (!decl.name) { 727 if (hasExportKeywordModifier(decl) && this.scope instanceof ModuleScope) { 728 return; 729 } 730 throw new Error("Function declaration without name is unimplemented"); 731 } 732 } 733 734 private compileExportAssignment(stmt: ts.ExportAssignment) { 735 this.compileExpression(stmt.expression); 736 let defaultV: ModuleVariable = <ModuleVariable>(this.pandaGen.getScope().findLocal("*default*")); 737 this.pandaGen.storeModuleVariable(stmt, defaultV); 738 } 739 740 compileCondition(expr: ts.Expression, ifFalseLabel: Label) { 741 let pandaGen = this.pandaGen; 742 if (expr.kind == ts.SyntaxKind.BinaryExpression) { 743 let binExpr = <ts.BinaryExpression>expr; 744 745 switch (binExpr.operatorToken.kind) { 746 case ts.SyntaxKind.LessThanToken: // line 57 747 case ts.SyntaxKind.GreaterThanToken: // line 59 748 case ts.SyntaxKind.LessThanEqualsToken: // line 60 749 case ts.SyntaxKind.GreaterThanEqualsToken: // line 61 750 case ts.SyntaxKind.EqualsEqualsToken: // line 62 751 case ts.SyntaxKind.ExclamationEqualsToken: // line 63 752 case ts.SyntaxKind.EqualsEqualsEqualsToken: // line 64 753 case ts.SyntaxKind.ExclamationEqualsEqualsToken: { // line 65 754 // This is a special case 755 // These operators are expressed via cmp instructions and the following 756 // if-else branches. Condition also expressed via cmp instruction and 757 // the following if-else. 758 // the goal of this method is to merge these two sequences of instructions. 759 let lhs = pandaGen.getTemp(); 760 this.compileExpression(binExpr.left); 761 pandaGen.storeAccumulator(binExpr, lhs); 762 this.compileExpression(binExpr.right); 763 pandaGen.condition(binExpr, binExpr.operatorToken.kind, lhs, ifFalseLabel); 764 pandaGen.freeTemps(lhs); 765 return; 766 } 767 case ts.SyntaxKind.AmpersandAmpersandToken: { 768 this.compileExpression(binExpr.left); 769 pandaGen.jumpIfFalse(binExpr, ifFalseLabel); 770 this.compileExpression(binExpr.right); 771 pandaGen.jumpIfFalse(binExpr, ifFalseLabel); 772 return; 773 } 774 case ts.SyntaxKind.BarBarToken: { 775 let endLabel = new Label(); 776 this.compileExpression(binExpr.left); 777 pandaGen.jumpIfTrue(binExpr, endLabel); 778 this.compileExpression(binExpr.right); 779 pandaGen.jumpIfFalse(binExpr, ifFalseLabel); 780 pandaGen.label(binExpr, endLabel); 781 return; 782 } 783 default: 784 break; 785 } 786 } 787 788 // General case including some binExpr i.e.(a+b) 789 this.compileExpression(expr); 790 pandaGen.jumpIfFalse(expr, ifFalseLabel); 791 } 792 793 compileExpression(expr: ts.Expression) { 794 // Please keep order of cases the same as in types.ts 795 LOGD(this.debugTag, "compile expr: " + ts.SyntaxKind[expr.kind] + " " + expr.kind); 796 switch (expr.kind) { 797 case ts.SyntaxKind.NumericLiteral: // line 34 798 compileNumericLiteral(this.pandaGen, <ts.NumericLiteral>expr); 799 break; 800 case ts.SyntaxKind.BigIntLiteral: // line 35 801 compileBigIntLiteral(this.pandaGen, <ts.BigIntLiteral>expr); 802 break; 803 case ts.SyntaxKind.StringLiteral: // line 36 804 compileStringLiteral(this.pandaGen, <ts.StringLiteral>expr); 805 break; 806 case ts.SyntaxKind.RegularExpressionLiteral: // line 39 807 compileRegularExpressionLiteral(this, <ts.RegularExpressionLiteral>expr); 808 break; 809 case ts.SyntaxKind.Identifier: // line 109 810 this.compileIdentifier(<ts.Identifier>expr); 811 break; 812 case ts.SyntaxKind.TrueKeyword: // line 114 813 case ts.SyntaxKind.FalseKeyword: // line 126 814 this.compileBooleanLiteral(<ts.BooleanLiteral>expr); 815 break; 816 case ts.SyntaxKind.CallExpression: // line 243 817 compileCallExpression(<ts.CallExpression>expr, this); 818 break; 819 case ts.SyntaxKind.NullKeyword: // line 135 820 this.pandaGen.loadAccumulator(expr, getVregisterCache(this.pandaGen, CacheList.Null)); 821 break; 822 case ts.SyntaxKind.ThisKeyword: // line 139 823 this.compileThisKeyword(expr); 824 break; 825 case ts.SyntaxKind.MetaProperty: 826 compileMetaProperty(<ts.MetaProperty>expr, this); 827 break; 828 case ts.SyntaxKind.ArrayLiteralExpression: // line 239 829 compileArrayLiteralExpression(this, <ts.ArrayLiteralExpression>expr); 830 break; 831 case ts.SyntaxKind.ObjectLiteralExpression: // line 240 832 compileObjectLiteralExpression(this, <ts.ObjectLiteralExpression>expr); 833 break; 834 case ts.SyntaxKind.PropertyAccessExpression: // line 241 835 case ts.SyntaxKind.ElementAccessExpression: // line 242 836 compileMemberAccessExpression(<ts.ElementAccessExpression | ts.PropertyAccessExpression>expr, this); 837 break; 838 case ts.SyntaxKind.NewExpression: // line 244 839 compileNewExpression(<ts.NewExpression>expr, this); 840 break; 841 case ts.SyntaxKind.ParenthesizedExpression: // line 247 842 this.compileExpression(findInnerExprOfParenthesis(<ts.ParenthesizedExpression>expr)); 843 break; 844 case ts.SyntaxKind.FunctionExpression: // line 248 845 this.compileFunctionExpression(<ts.FunctionExpression>expr); 846 break; 847 case ts.SyntaxKind.DeleteExpression: // line 250 848 this.compileDeleteExpression(<ts.DeleteExpression>expr); 849 break; 850 case ts.SyntaxKind.TypeOfExpression: // line 251 851 this.compileTypeOfExpression(<ts.TypeOfExpression>expr); 852 break; 853 case ts.SyntaxKind.VoidExpression: // line 252 854 this.compileVoidExpression(<ts.VoidExpression>expr); 855 break; 856 case ts.SyntaxKind.AwaitExpression: 857 this.compileAwaitExpression(<ts.AwaitExpression>expr); 858 break; 859 case ts.SyntaxKind.PrefixUnaryExpression: // line 254 860 this.compilePrefixUnaryExpression(<ts.PrefixUnaryExpression>expr); 861 break; 862 case ts.SyntaxKind.PostfixUnaryExpression: // line 255 863 this.compilePostfixUnaryExpression(<ts.PostfixUnaryExpression>expr); 864 break; 865 case ts.SyntaxKind.BinaryExpression: // line 256 866 this.compileBinaryExpression(<ts.BinaryExpression>expr); 867 break; 868 case ts.SyntaxKind.ConditionalExpression: // line 257 869 this.compileConditionalExpression(<ts.ConditionalExpression>expr); 870 break; 871 case ts.SyntaxKind.YieldExpression: // line 259 872 compileYieldExpression(this, <ts.YieldExpression>expr); 873 break; 874 case ts.SyntaxKind.ArrowFunction: //line 249 875 this.compileArrowFunction(<ts.ArrowFunction>expr); 876 break; 877 case ts.SyntaxKind.TemplateExpression: 878 this.compileTemplateExpression(<ts.TemplateExpression>expr); 879 break; 880 case ts.SyntaxKind.NoSubstitutionTemplateLiteral: 881 case ts.SyntaxKind.FirstTemplateToken: 882 case ts.SyntaxKind.LastLiteralToken: 883 this.compileNoSubstitutionTemplateLiteral(<ts.NoSubstitutionTemplateLiteral>expr); 884 break; 885 case ts.SyntaxKind.TaggedTemplateExpression: 886 this.compileTaggedTemplateExpression(<ts.TaggedTemplateExpression>expr); 887 break; 888 case ts.SyntaxKind.Constructor: 889 break; 890 case ts.SyntaxKind.PropertyDeclaration: 891 break; 892 case ts.SyntaxKind.ClassExpression: 893 compileClassDeclaration(this, <ts.ClassLikeDeclaration>expr); 894 break; 895 case ts.SyntaxKind.PartiallyEmittedExpression: 896 this.compileExpression((<ts.PartiallyEmittedExpression>expr).expression); 897 break; 898 case ts.SyntaxKind.CommaListExpression: 899 compileCommaListExpression(this, <ts.CommaListExpression>expr); 900 break; 901 default: 902 throw new Error("Expression of type " + this.getNodeName(expr) + " is unimplemented"); 903 } 904 } 905 906 private compileIdentifier(id: ts.Identifier) { 907 let name = jshelpers.getTextOfIdentifierOrLiteral(id); 908 let { scope, level, v } = this.scope.find(name); 909 if (!v) { 910 // the variable may appear after function call 911 // any way it is a global variable. 912 this.compileUnscopedIdentifier(id); 913 } else { 914 this.loadTarget(id, { scope, level, v }); 915 } 916 } 917 918 private compileUnscopedIdentifier(id: ts.Identifier) { 919 let name = jshelpers.getTextOfIdentifierOrLiteral(id); 920 let pandaGen = this.pandaGen; 921 switch (name) { 922 // Those identifier are Built-In value properties 923 case "NaN": 924 pandaGen.loadAccumulator(id, getVregisterCache(this.pandaGen, CacheList.NaN)); 925 return; 926 case "Infinity": 927 pandaGen.loadAccumulator(id, getVregisterCache(this.pandaGen, CacheList.Infinity)); 928 return; 929 case "globalThis": 930 pandaGen.loadAccumulator(id, getVregisterCache(this.pandaGen, CacheList.Global)); 931 return; 932 case "undefined": 933 pandaGen.loadAccumulator(id, getVregisterCache(this.pandaGen, CacheList.undefined)); 934 return; 935 default: { 936 // typeof an undeclared variable will return undefined instead of throwing reference error 937 let parent = findOuterNodeOfParenthesis(id); 938 if ((parent.kind == ts.SyntaxKind.TypeOfExpression)) { 939 CmdOptions.isWatchEvaluateExpressionMode() ? 940 pandaGen.loadByNameViaDebugger(id, name, CacheList.False) : 941 pandaGen.loadObjProperty(id, getVregisterCache(pandaGen, CacheList.Global), name); 942 } else { 943 pandaGen.tryLoadGlobalByName(id, name); 944 } 945 break; 946 } 947 } 948 } 949 950 private compileBooleanLiteral(lit: ts.BooleanLiteral) { 951 if (lit.kind == ts.SyntaxKind.TrueKeyword) { 952 this.pandaGen.loadAccumulator(lit, getVregisterCache(this.pandaGen, CacheList.True)); 953 } else { 954 this.pandaGen.loadAccumulator(lit, getVregisterCache(this.pandaGen, CacheList.False)); 955 } 956 } 957 958 compileFunctionReturnThis(expr: ts.NewExpression | ts.CallExpression): boolean { 959 if (expr.expression.kind == ts.SyntaxKind.Identifier) { 960 let identifier = <ts.Identifier>expr.expression; 961 let args = expr.arguments; 962 if (identifier.escapedText == "Function") { 963 if (args && args.length > 0) { 964 if (!ts.isStringLiteral(args[args.length - 1])) { 965 return false; 966 } 967 let arg = <ts.StringLiteral>args[args.length - 1]; 968 if (arg.text.match(/ *return +this[;]? *$/) == null) { 969 return false; 970 } else { 971 this.pandaGen.loadAccumulator(expr, getVregisterCache(this.pandaGen, CacheList.Global)) 972 return true; 973 } 974 } 975 } 976 } 977 return false; 978 } 979 980 private compileThisKeyword(node: ts.Node) { 981 let pandaGen = this.pandaGen; 982 983 checkValidUseSuperBeforeSuper(this, node); 984 985 let { scope, level, v } = this.scope.find(MandatoryThis); 986 987 if (!v) { 988 throw new Error("\"this\" not found"); 989 } 990 991 if (v instanceof LocalVariable) { 992 if (CmdOptions.isWatchEvaluateExpressionMode()) { 993 pandaGen.loadByNameViaDebugger(node, MandatoryThis, CacheList.True); 994 return; 995 } 996 997 pandaGen.loadAccFromLexEnv(node, scope!, level, v); 998 return; 999 } 1000 1001 throw new Error("\"this\" must be a local variable"); 1002 } 1003 1004 private compileFunctionExpression(expr: ts.FunctionExpression) { 1005 let internalName = this.compilerDriver.getFuncInternalName(expr, this.recorder); 1006 this.pandaGen.defineFunction(expr, expr, internalName); 1007 } 1008 1009 private compileDeleteExpression(expr: ts.DeleteExpression) { 1010 let pandaGen = this.pandaGen; 1011 let objReg: VReg; 1012 let propReg: VReg; 1013 let unaryExpr = expr.expression; 1014 switch (unaryExpr.kind) { 1015 case ts.SyntaxKind.Identifier: { 1016 // Check if this is a known variable. 1017 let name = jshelpers.getTextOfIdentifierOrLiteral(<ts.Identifier>unaryExpr); 1018 let { scope, v } = this.scope.find(name); 1019 1020 if (!v || ((scope instanceof GlobalScope) && (v instanceof GlobalVariable))) { 1021 // If the variable doesn't exist or if it is global, we must generate 1022 // a delete global property instruction. 1023 objReg = getVregisterCache(pandaGen, CacheList.Global); 1024 pandaGen.loadAccumulatorString(unaryExpr, name); 1025 pandaGen.deleteObjProperty(expr, objReg); 1026 } else { 1027 // Otherwise it is a local variable which can't be deleted and we just 1028 // return false. 1029 pandaGen.loadAccumulator(unaryExpr, getVregisterCache(pandaGen, CacheList.False)); 1030 } 1031 break; 1032 } 1033 case ts.SyntaxKind.PropertyAccessExpression: 1034 case ts.SyntaxKind.ElementAccessExpression: { 1035 objReg = pandaGen.getTemp(); 1036 propReg = pandaGen.getTemp(); 1037 1038 if (jshelpers.isSuperProperty(unaryExpr)) { 1039 pandaGen.throwDeleteSuperProperty(unaryExpr); 1040 pandaGen.freeTemps(objReg, propReg); 1041 return; 1042 } 1043 1044 let { prop: prop } = getObjAndProp(<ts.PropertyAccessExpression | ts.ElementAccessExpression>unaryExpr, objReg, propReg, this); 1045 switch (typeof prop) { 1046 case "string": 1047 pandaGen.loadAccumulatorString(expr, prop); 1048 break; 1049 case "number": 1050 pandaGen.loadAccumulatorInt(expr, prop); 1051 break; 1052 default: 1053 pandaGen.loadAccumulator(expr, prop); 1054 break; 1055 } 1056 1057 pandaGen.deleteObjProperty(expr, objReg); 1058 pandaGen.freeTemps(objReg, propReg); 1059 break; 1060 } 1061 default: { 1062 // compile the delete operand. 1063 this.compileExpression(unaryExpr); 1064 // Deleting any value or a result of an expression returns True. 1065 pandaGen.loadAccumulator(expr, getVregisterCache(pandaGen, CacheList.True)); 1066 } 1067 } 1068 } 1069 1070 private compileTypeOfExpression(expr: ts.TypeOfExpression) { 1071 // expr -> acc 1072 this.compileExpression(expr.expression); 1073 this.pandaGen.typeOf(expr); 1074 } 1075 1076 private compileVoidExpression(expr: ts.VoidExpression) { 1077 let pandaGen = this.pandaGen; 1078 // compileExpression() must be called even though its value is not used 1079 // because it may have observable sideeffects. 1080 this.compileExpression(expr.expression); 1081 pandaGen.loadAccumulator(expr, getVregisterCache(pandaGen, CacheList.undefined)); 1082 } 1083 1084 private compileAwaitExpression(expr: ts.AwaitExpression) { 1085 let pandaGen = this.pandaGen; 1086 1087 if (!(this.funcBuilder instanceof AsyncFunctionBuilder || this.funcBuilder instanceof AsyncGeneratorFunctionBuilder)) { 1088 throw new DiagnosticError(expr.parent, DiagnosticCode.await_expressions_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules); 1089 } 1090 1091 if (expr.expression) { 1092 this.compileExpression(expr.expression); 1093 this.funcBuilder.await(expr); 1094 } else { 1095 pandaGen.loadAccumulator(expr, getVregisterCache(pandaGen, CacheList.undefined)); 1096 this.funcBuilder.await(expr); 1097 } 1098 } 1099 1100 private compilePrefixUnaryExpression(expr: ts.PrefixUnaryExpression) { 1101 let pandaGen = this.pandaGen; 1102 let operandReg = pandaGen.getTemp(); 1103 // acc -> op(acc) 1104 switch (expr.operator) { 1105 case ts.SyntaxKind.PlusPlusToken: // line 73 1106 case ts.SyntaxKind.MinusMinusToken: { 1107 // line 74 1108 let lref = LReference.generateLReference(this, expr.operand, false); 1109 lref.getValue(); 1110 pandaGen.storeAccumulator(expr, operandReg); 1111 pandaGen.unary(expr, expr.operator, operandReg); 1112 lref.setValue(); 1113 break; 1114 } 1115 case ts.SyntaxKind.PlusToken: // line 67 1116 case ts.SyntaxKind.MinusToken: // line 68 1117 case ts.SyntaxKind.ExclamationToken: // line 81 1118 case ts.SyntaxKind.TildeToken: { // line 82 1119 this.compileExpression(expr.operand); 1120 pandaGen.storeAccumulator(expr, operandReg); 1121 pandaGen.unary(expr, expr.operator, operandReg); 1122 break; 1123 } 1124 default: 1125 break; 1126 } 1127 pandaGen.freeTemps(operandReg); 1128 } 1129 1130 private compilePostfixUnaryExpression(expr: ts.PostfixUnaryExpression) { 1131 let pandaGen = this.pandaGen; 1132 let operandReg = pandaGen.getTemp(); 1133 // expr -> acc 1134 let lref = LReference.generateLReference(this, expr.operand, false); 1135 lref.getValue(); 1136 // operand = acc 1137 pandaGen.storeAccumulator(expr, operandReg); 1138 // acc +/- 1 1139 switch (expr.operator) { 1140 case ts.SyntaxKind.PlusPlusToken: 1141 case ts.SyntaxKind.MinusMinusToken: 1142 pandaGen.unary(expr, expr.operator, operandReg); 1143 break; 1144 default: 1145 break; 1146 } 1147 // lvalue var = acc +/- 1 1148 lref.setValue(); 1149 // acc = operand_old 1150 pandaGen.toNumeric(expr, operandReg); 1151 pandaGen.freeTemps(operandReg); 1152 } 1153 1154 private compileLogicalExpression(expr: ts.BinaryExpression) { 1155 let pandaGen = this.pandaGen; 1156 let lhs = pandaGen.getTemp(); 1157 switch (expr.operatorToken.kind) { 1158 case ts.SyntaxKind.AmpersandAmpersandToken: { // line 83 1159 let leftFalseLabel = new Label(); 1160 let endLabel = new Label(); 1161 1162 // left -> acc 1163 this.compileExpression(expr.left); 1164 pandaGen.storeAccumulator(expr, lhs); 1165 pandaGen.jumpIfFalse(expr, leftFalseLabel); 1166 1167 // left is true then right -> acc 1168 this.compileExpression(expr.right); 1169 pandaGen.branch(expr, endLabel); 1170 1171 // left is false then lhs -> acc 1172 pandaGen.label(expr, leftFalseLabel); 1173 pandaGen.loadAccumulator(expr, lhs); 1174 pandaGen.label(expr, endLabel); 1175 break; 1176 } 1177 case ts.SyntaxKind.BarBarToken: { // line 84 1178 let leftTrueLabel = new Label(); 1179 let endLabel = new Label(); 1180 1181 // left -> acc 1182 this.compileExpression(expr.left); 1183 pandaGen.storeAccumulator(expr, lhs); 1184 pandaGen.jumpIfTrue(expr, leftTrueLabel); 1185 1186 // left is false then right -> acc 1187 this.compileExpression(expr.right); 1188 pandaGen.branch(expr, endLabel); 1189 1190 // left is true then lhs -> acc 1191 pandaGen.label(expr, leftTrueLabel); 1192 pandaGen.loadAccumulator(expr, lhs); 1193 pandaGen.label(expr, endLabel); 1194 break; 1195 } 1196 case ts.SyntaxKind.QuestionQuestionToken: { // line 90 1197 let leftNullishLabel = new Label(); 1198 let endLabel = new Label(); 1199 // left -> acc -> lhs 1200 this.compileExpression(expr.left); 1201 pandaGen.storeAccumulator(expr, lhs); 1202 // equality comparasion between lhs and null, if true, load right 1203 pandaGen.condition(expr, ts.SyntaxKind.ExclamationEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.Null), leftNullishLabel); 1204 // equality comparasion between lhs and undefined, if true, load right 1205 pandaGen.loadAccumulator(expr.left, lhs); 1206 pandaGen.condition(expr, ts.SyntaxKind.ExclamationEqualsEqualsToken, getVregisterCache(pandaGen, CacheList.undefined), leftNullishLabel); 1207 // lhs is either null or undefined, load left 1208 pandaGen.loadAccumulator(expr, lhs); 1209 pandaGen.branch(expr, endLabel); 1210 pandaGen.label(expr, leftNullishLabel); 1211 this.compileExpression(expr.right); 1212 pandaGen.label(expr, endLabel); 1213 break; 1214 } 1215 default: 1216 throw new Error("BinaryExpression with operatorToken " + this.getNodeName(expr.operatorToken) + " is not Logical Operator"); 1217 } 1218 pandaGen.freeTemps(lhs); 1219 } 1220 1221 private compileBinaryExpression(expr: ts.BinaryExpression) { 1222 if (isAssignmentOperator(expr.operatorToken.kind)) { 1223 this.compileAssignmentExpression(expr.left, expr.right, <AssignmentOperator>expr.operatorToken.kind); 1224 return; 1225 } 1226 // LogicAnd, LogicOr and Coalesce are Short-circuiting 1227 if (expr.operatorToken.kind == ts.SyntaxKind.AmpersandAmpersandToken 1228 || expr.operatorToken.kind == ts.SyntaxKind.BarBarToken 1229 || expr.operatorToken.kind == ts.SyntaxKind.QuestionQuestionToken) { 1230 this.compileLogicalExpression(expr); 1231 return; 1232 } 1233 1234 let pandaGen = this.pandaGen; 1235 let lhs = pandaGen.getTemp(); 1236 this.compileExpression(expr.left); 1237 pandaGen.storeAccumulator(expr, lhs); 1238 this.compileExpression(expr.right); 1239 1240 if (expr.operatorToken.kind != ts.SyntaxKind.CommaToken) { 1241 pandaGen.binary(expr, expr.operatorToken.kind, lhs); 1242 } 1243 1244 pandaGen.freeTemps(lhs); 1245 } 1246 1247 private compileConditionalExpression(expr: ts.ConditionalExpression) { 1248 let falseLabel = new Label(); 1249 let endLabel = new Label(); 1250 1251 this.compileCondition(expr.condition, falseLabel); 1252 this.compileExpression(expr.whenTrue); 1253 this.pandaGen.branch(expr, endLabel); 1254 this.pandaGen.label(expr, falseLabel); 1255 this.compileExpression(expr.whenFalse); 1256 this.pandaGen.label(expr, endLabel); 1257 } 1258 1259 private compileArrowFunction(expr: ts.ArrowFunction) { 1260 let internalName = this.compilerDriver.getFuncInternalName(expr, this.recorder); 1261 this.pandaGen.defineFunction(expr, expr, internalName); 1262 } 1263 1264 private compileTemplateSpan(expr: ts.TemplateSpan) { 1265 let span = expr.expression; 1266 this.compileExpression(span); 1267 let literal = expr.literal; 1268 let lrh = this.pandaGen.getTemp(); 1269 let text = literal.text; 1270 1271 if (text.length != 0) { 1272 this.pandaGen.storeAccumulator(expr, lrh); 1273 this.pandaGen.loadAccumulatorString(expr, text); 1274 this.pandaGen.binary(expr, ts.SyntaxKind.PlusToken, lrh); 1275 } 1276 1277 this.pandaGen.freeTemps(lrh); 1278 } 1279 1280 private compileTemplateExpression(expr: ts.TemplateExpression) { 1281 let pandaGen = this.pandaGen; 1282 let head = expr.head; 1283 let spans = expr.templateSpans; 1284 1285 let lrh = pandaGen.getTemp(); 1286 pandaGen.loadAccumulatorString(expr, head.text); 1287 1288 if (spans && spans.length > 0) { 1289 spans.forEach((spanExp: ts.TemplateSpan) => { 1290 pandaGen.storeAccumulator(expr, lrh); 1291 this.compileTemplateSpan(spanExp); 1292 pandaGen.binary(expr, ts.SyntaxKind.PlusToken, lrh); 1293 }); 1294 } 1295 1296 pandaGen.freeTemps(lrh); 1297 } 1298 1299 private compileNoSubstitutionTemplateLiteral(expr: ts.NoSubstitutionTemplateLiteral) { 1300 let text = expr.text; 1301 this.pandaGen.loadAccumulatorString(expr, text); 1302 } 1303 1304 private compileTaggedTemplateExpression(expr: ts.TaggedTemplateExpression) { 1305 let pandaGen = this.pandaGen; 1306 let spans = undefined; 1307 if (ts.isTemplateExpression(expr.template)) { 1308 spans = expr.template.templateSpans; 1309 } 1310 1311 let { arguments: argRegs, passThis: passThis } = getHiddenParameters(expr.tag, this); // +3 for function and this 1312 getTemplateObject(pandaGen, expr); 1313 let templateObj = pandaGen.getTemp(); 1314 pandaGen.storeAccumulator(expr, templateObj) 1315 argRegs.push(templateObj); 1316 1317 if (spans && spans.length) { 1318 spans.forEach((spanExp: ts.TemplateSpan) => { 1319 let exprReg = pandaGen.getTemp(); 1320 this.compileExpression(spanExp.expression); 1321 pandaGen.storeAccumulator(spanExp, exprReg); 1322 argRegs.push(exprReg); 1323 }); 1324 } 1325 1326 pandaGen.call(expr, argRegs, passThis); 1327 pandaGen.freeTemps(...argRegs); 1328 1329 return; 1330 } 1331 1332 private compileAssignmentExpression(lhs: ts.Expression, rhs: ts.Expression, operator: AssignmentOperator) { 1333 let lref = LReference.generateLReference(this, lhs, false); 1334 1335 if (operator != ts.SyntaxKind.EqualsToken) { 1336 let lhsVreg = this.pandaGen.getTemp(); 1337 1338 lref.getValue(); 1339 this.pandaGen.storeAccumulator(lhs, lhsVreg); 1340 this.compileExpression(rhs); 1341 this.pandaGen.binary(lhs.parent, operator, lhsVreg); 1342 this.pandaGen.freeTemps(lhsVreg); 1343 } else { 1344 this.compileExpression(rhs); 1345 } 1346 1347 lref.setValue(); 1348 } 1349 1350 pushScope(node: ts.Node) { 1351 let scope = <Scope>this.recorder.getScopeOfNode(node); 1352 this.scope = scope; 1353 // for debug info 1354 DebugInfo.addDebugIns(scope, this.pandaGen, true); 1355 } 1356 1357 popScope() { 1358 // for debug info 1359 DebugInfo.addDebugIns(this.scope, this.pandaGen, false); 1360 this.scope = <Scope>this.scope.getParent(); 1361 } 1362 1363 private getNodeName(node: ts.Node): string { 1364 return ts.SyntaxKind[node.kind]; 1365 } 1366 1367 getThis(node: ts.Node, res: VReg) { 1368 let pandaGen = this.pandaGen; 1369 let thisInfo = this.getCurrentScope().find(MandatoryThis); 1370 let level = thisInfo.level; 1371 let v = <Variable>thisInfo.v; 1372 1373 if (v.isLexVar) { 1374 let slot = v.idxLex; 1375 pandaGen.loadLexicalVar(node, level, slot); 1376 pandaGen.storeAccumulator(node, res); 1377 } else { 1378 pandaGen.moveVreg(node, res, pandaGen.getVregForVariable(v)); 1379 } 1380 } 1381 1382 setThis(node: ts.Node) { 1383 let pandaGen = this.pandaGen; 1384 let thisInfo = this.getCurrentScope().find(MandatoryThis); 1385 1386 if (thisInfo.v!.isLexVar) { 1387 let slot = (<Variable>thisInfo.v).idxLex; 1388 let value = pandaGen.getTemp(); 1389 pandaGen.storeAccumulator(node, value); 1390 pandaGen.storeLexicalVar(node, thisInfo.level, slot, value); 1391 pandaGen.freeTemps(value); 1392 } else { 1393 pandaGen.storeAccumulator(node, pandaGen.getVregForVariable(<Variable>thisInfo.v)) 1394 } 1395 } 1396 1397 getPandaGen() { 1398 return this.pandaGen; 1399 } 1400 1401 getCurrentScope() { 1402 return this.scope; 1403 } 1404 1405 getCompilerDriver() { 1406 return this.compilerDriver; 1407 } 1408 1409 getRecorder() { 1410 return this.recorder; 1411 } 1412 1413 getFuncBuilder() { 1414 return this.funcBuilder; 1415 } 1416 1417 storeTarget(node: ts.Node, 1418 variable: { scope: Scope | undefined, level: number, v: Variable | undefined }, 1419 isDeclaration: boolean) { 1420 if (variable.v instanceof LocalVariable) { 1421 if (isDeclaration && variable.v.isLetOrConst()) { 1422 variable.v.initialize(); 1423 if (variable.scope instanceof GlobalScope) { 1424 if (variable.v.isLet()) { 1425 this.pandaGen.stLetOrClassToGlobalRecord(node, variable.v.getName()); 1426 } else { 1427 this.pandaGen.stConstToGlobalRecord(node, variable.v.getName()); 1428 } 1429 return; 1430 } 1431 } 1432 1433 if (variable.v.isLetOrConst() && variable.scope instanceof GlobalScope) { 1434 this.pandaGen.tryStoreGlobalByName(node, variable.v.getName()); 1435 return; 1436 } 1437 1438 this.pandaGen.storeAccToLexEnv(node, variable.scope!, variable.level, variable.v, isDeclaration); 1439 } else if (variable.v instanceof GlobalVariable) { 1440 if (variable.v.isNone() && isStrictMode(node)) { 1441 this.pandaGen.tryStoreGlobalByName(node, variable.v.getName()); 1442 } else { 1443 this.pandaGen.storeGlobalVar(node, variable.v.getName()); 1444 } 1445 } else if (variable.v instanceof ModuleVariable) { 1446 // import module variable is const, throw `const assignment error` 1447 if (!isDeclaration && variable.v.isConst()) { 1448 let nameReg = this.pandaGen.getTemp(); 1449 this.pandaGen.loadAccumulatorString(node, variable.v.getName()); 1450 this.pandaGen.storeAccumulator(node, nameReg); 1451 this.pandaGen.throwConstAssignment(node, nameReg); 1452 this.pandaGen.freeTemps(nameReg); 1453 return; 1454 } 1455 1456 if (isDeclaration) { 1457 variable.v.initialize(); 1458 } 1459 1460 if ((variable.v.isLet() || variable.v.isClass()) && !variable.v.isInitialized()) { 1461 let valueReg = this.pandaGen.getTemp(); 1462 this.pandaGen.storeAccumulator(node, valueReg); 1463 this.pandaGen.loadModuleVariable(node, variable.v, true); 1464 this.pandaGen.throwUndefinedIfHole(node, variable.v.getName()); 1465 this.pandaGen.loadAccumulator(node, valueReg); 1466 this.pandaGen.freeTemps(valueReg); 1467 } 1468 1469 this.pandaGen.storeModuleVariable(node, variable.v); 1470 } else { 1471 throw new Error("invalid lhsRef to store"); 1472 } 1473 } 1474 1475 loadTarget(node: ts.Node, variable: { scope: Scope | undefined, level: number, v: Variable | undefined }) { 1476 if (variable.v instanceof LocalVariable) { 1477 if (!CmdOptions.isCommonJs() && (variable.v.isLetOrConst() || variable.v.isClass())) { 1478 if (variable.scope instanceof GlobalScope) { 1479 this.pandaGen.tryLoadGlobalByName(node, variable.v.getName()); 1480 return; 1481 } 1482 } 1483 1484 this.pandaGen.loadAccFromLexEnv(node, variable.scope!, variable.level, (<LocalVariable>variable.v)); 1485 } else if (variable.v instanceof GlobalVariable) { 1486 if (variable.v.isNone()) { 1487 let parent = findOuterNodeOfParenthesis(node); 1488 if ((parent.kind == ts.SyntaxKind.TypeOfExpression)) { 1489 CmdOptions.isWatchEvaluateExpressionMode() ? 1490 this.pandaGen.loadByNameViaDebugger(node, variable.v.getName(), CacheList.False) : 1491 this.pandaGen.loadObjProperty(node, getVregisterCache(this.pandaGen, CacheList.Global), 1492 variable.v.getName()); 1493 } else { 1494 this.pandaGen.tryLoadGlobalByName(node, variable.v.getName()); 1495 } 1496 } else { 1497 this.pandaGen.loadGlobalVar(node, variable.v.getName()); 1498 } 1499 } else if (variable.v instanceof ModuleVariable) { 1500 let isLocal: boolean = variable.v.isExportVar() ? true : false; 1501 this.pandaGen.loadModuleVariable(node, variable.v, isLocal); 1502 if ((variable.v.isLetOrConst() || variable.v.isClass()) && !variable.v.isInitialized()) { 1503 this.pandaGen.throwUndefinedIfHole(node, variable.v.getName()); 1504 } 1505 } else { 1506 // Handle the variables from lexical scope 1507 throw new Error("Only local and global variables are implemented"); 1508 } 1509 } 1510} 1511