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