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