• 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
16import { VReg } from "./irnodes";
17import {
18    InitStatus,
19    LoopScope,
20    VariableScope
21} from "./scope";
22
23export enum VarDeclarationKind {
24    NONE,
25    LET,
26    CONST,
27    VAR,
28    FUNCTION,
29    CLASS
30}
31
32export abstract class Variable {
33    private vreg: VReg | undefined;
34    private name: string;
35    private typeIndex: number;
36    isLexVar: boolean = false;
37    idxLex: number = 0;
38    constructor(
39        readonly declKind: VarDeclarationKind,
40        name: string
41    ) {
42        this.name = name;
43        this.vreg = undefined;
44        this.typeIndex = 0;
45    }
46
47    bindVreg(vreg: VReg): void {
48        this.vreg = vreg;
49        this.vreg.setTypeIndex(this.typeIndex);
50        this.vreg.setVariableName(this.name);
51    }
52
53    hasAlreadyBinded(): boolean {
54        return this.vreg !== undefined;
55    }
56
57    getVreg(): VReg {
58        if (!this.vreg) {
59            throw new Error("variable has not been binded");
60        }
61        return this.vreg;
62    }
63
64    getName(): string {
65        return this.name;
66    }
67
68    getTypeIndex(): number {
69        return this.typeIndex;
70    }
71
72    setTypeIndex(typeIndex: number): number {
73        return this.typeIndex = typeIndex;
74    }
75
76    setLexVar(scope: VariableScope | LoopScope): number {
77        if (this.lexical()) {
78            return;
79        }
80        this.idxLex = scope.getLexVarIdx();
81        scope.pendingCreateEnv();
82        this.isLexVar = true;
83        scope.addLexVarInfo(this.name, this.idxLex);
84        return this.idxLex;
85    }
86
87    clearLexVar(): void {
88        this.isLexVar = false;
89        this.idxLex = 0;
90    }
91
92    lexical(): boolean {
93        return this.isLexVar;
94    }
95
96    lexIndex(): number {
97        return this.idxLex;
98    }
99
100    isLet(): boolean {
101        return this.declKind === VarDeclarationKind.LET;
102    }
103
104    isConst(): boolean {
105        return this.declKind === VarDeclarationKind.CONST;
106    }
107
108    isLetOrConst(): boolean {
109        return this.declKind === VarDeclarationKind.LET || this.declKind === VarDeclarationKind.CONST;
110    }
111
112    isVar(): boolean {
113        return this.declKind === VarDeclarationKind.VAR;
114    }
115
116    isNone(): boolean {
117        return this.declKind === VarDeclarationKind.NONE;
118    }
119
120    isClass(): boolean {
121        return this.declKind === VarDeclarationKind.CLASS;
122    }
123}
124
125export class LocalVariable extends Variable {
126    status: InitStatus | null;
127
128    constructor(declKind: VarDeclarationKind, name: string, status?: InitStatus) {
129        super(declKind, name);
130        this.status = status ? status : null;
131    }
132
133    initialize(): void {
134        this.status = InitStatus.INITIALIZED;
135    }
136
137    isInitialized(): boolean {
138        if (this.status != null) {
139            return this.status === InitStatus.INITIALIZED;
140        }
141        return true;
142    }
143}
144
145export class ModuleVariable extends Variable {
146    private isExport: boolean = false;
147    private status: InitStatus | null;
148    private index: number;
149
150
151    constructor(declKind: VarDeclarationKind, name: string, status?: InitStatus) {
152        super(declKind, name);
153        this.status = status ? status : null;
154    }
155
156    initialize(): void {
157        this.status = InitStatus.INITIALIZED;
158    }
159
160    isInitialized(): boolean {
161        if (this.status != null) {
162            return this.status === InitStatus.INITIALIZED;
163        }
164        return true;
165    }
166
167    setExport(): void {
168        this.isExport = true;
169    }
170
171    isExportVar(): boolean {
172        return this.isExport;
173    }
174
175    assignIndex(index: number): void {
176        this.index = index;
177    }
178
179    getIndex(): number {
180        return this.index;
181    }
182}
183
184export class GlobalVariable extends Variable {
185    constructor(declKind: VarDeclarationKind, name: string) {
186        super(declKind, name);
187    }
188}
189
190export const MandatoryFuncObj = "4funcObj";
191export const MandatoryNewTarget = "4newTarget";
192export const MandatoryThis = "this";
193export const MandatoryArguments = "arguments";
194
195export function isMandatoryParam(name: string): boolean {
196    if (name === MandatoryFuncObj || name === MandatoryArguments ||
197        name === MandatoryNewTarget || name === MandatoryThis) {
198        return true;
199    }
200
201    return false;
202}