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}