• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021 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
16import * as ts from "typescript";
17import {
18    Label,
19    VReg
20} from "../irnodes";
21import { PandaGen } from "../pandagen";
22import { Compiler } from "../compiler";
23import {
24    DiagnosticCode,
25    DiagnosticError
26} from "../diagnostic";
27import { LabelTarget } from "./labelTarget";
28export class SwitchBase {
29    private stmt: ts.SwitchStatement;
30    private compiler: Compiler;
31    private pandaGen: PandaGen;
32    private caseLabels: Label[] = [];
33    private switchEndLabel: Label;
34    constructor(stmt: ts.SwitchStatement, compiler: Compiler, caseNums: number, switchEndLabel: Label) {
35        this.stmt = stmt;
36        this.compiler = compiler;
37        this.pandaGen = compiler.getPandaGen();
38        this.switchEndLabel = switchEndLabel;
39
40        for (let i = 0; i < caseNums; i++) {
41            let caseLabel = new Label();
42            this.caseLabels.push(caseLabel);
43        }
44        let labelTarget = new LabelTarget(stmt, switchEndLabel, undefined);
45        LabelTarget.pushLabelTarget(labelTarget);
46        LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget);
47    }
48
49    setCasePosition(index: number) {
50        let caseTarget = this.stmt.caseBlock.clauses[index];
51        this.pandaGen.label(caseTarget, this.caseLabels[index]);
52    }
53
54    compileTagOfSwitch(tagReg: VReg) {
55        this.compiler.compileExpression(this.stmt.expression);
56        this.pandaGen.storeAccumulator(this.stmt.expression, tagReg);
57    }
58
59    compileCaseStatements(index: number) {
60        this.stmt.caseBlock.clauses[index].statements.forEach(statement => {
61            this.compiler.compileStatement(statement);
62        })
63    }
64
65    JumpIfCase(tag: VReg, index: number) {
66        let stmt = this.stmt;
67        let pandaGen = this.pandaGen;
68        let caseTarget = <ts.CaseClause>stmt.caseBlock.clauses[index];
69
70        this.compiler.compileExpression(caseTarget.expression);
71        pandaGen.condition(caseTarget, ts.SyntaxKind.ExclamationEqualsEqualsToken, tag, this.caseLabels[index]);
72    }
73
74    JumpToDefault(defaultIndex: number) {
75        let defaultTarget = <ts.DefaultClause>this.stmt.caseBlock.clauses[defaultIndex];
76        this.pandaGen.branch(defaultTarget, this.caseLabels[defaultIndex]);
77    }
78
79    checkDefaultNum(defaultCnt: number) {
80        if (defaultCnt > 1) {
81            throw new DiagnosticError(this.stmt, DiagnosticCode.A_default_clause_cannot_appear_more_than_once_in_a_switch_statement);
82        }
83    }
84
85    break() {
86        this.pandaGen.branch(this.stmt, this.switchEndLabel);
87    }
88
89    end() {
90        this.pandaGen.label(this.stmt, this.switchEndLabel);
91    }
92}
93
94export function compileSwitchStatement(stmt: ts.SwitchStatement, compiler: Compiler) {
95    let pandaGen = compiler.getPandaGen();
96    let caseNums = stmt.caseBlock.clauses.length;
97    let switchEndLabel = new Label();
98    let switchBuilder = new SwitchBase(stmt, compiler, caseNums, switchEndLabel);
99
100    let tagReg = pandaGen.getTemp();
101    switchBuilder.compileTagOfSwitch(tagReg);
102    compiler.pushScope(stmt);
103    let caseTargets = stmt.caseBlock.clauses;
104    let defaultIndex = 0;
105    let defaultCnt = 0;
106
107    for (let i = 0; i < caseTargets.length; i++) {
108        let caseTarget = caseTargets[i];
109        if (ts.isDefaultClause(caseTarget)) {
110            defaultIndex = i;
111            defaultCnt++;
112            continue;
113        }
114
115        switchBuilder.JumpIfCase(tagReg, i);
116    }
117
118    switchBuilder.checkDefaultNum(defaultCnt);
119    if (defaultIndex > 0) {
120        switchBuilder.JumpToDefault(defaultIndex);
121    } else {
122        switchBuilder.break();
123    }
124
125    for (let i = 0; i < caseTargets.length; i++) {
126        switchBuilder.setCasePosition(i);
127        switchBuilder.compileCaseStatements(i);
128    }
129
130    switchBuilder.end();
131    pandaGen.freeTemps(tagReg);
132    LabelTarget.popLabelTarget();
133    compiler.popScope();
134}