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