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