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 MODULE, 30 CLASS 31} 32 33export abstract class Variable { 34 private vreg: VReg | undefined; 35 private name: string; 36 private typeIndex: number; 37 isLexVar: boolean = false; 38 idxLex: number = 0; 39 constructor( 40 readonly declKind: VarDeclarationKind, 41 name: string 42 ) { 43 this.name = name; 44 this.vreg = undefined; 45 this.typeIndex = 0; 46 } 47 48 bindVreg(vreg: VReg) { 49 this.vreg = vreg; 50 this.vreg.setTypeIndex(this.typeIndex); 51 this.vreg.setVariableName(this.name); 52 } 53 54 hasAlreadyBinded(): boolean { 55 return this.vreg !== undefined; 56 } 57 58 getVreg(): VReg { 59 if (!this.vreg) { 60 throw new Error("variable has not been binded") 61 } 62 return this.vreg; 63 } 64 65 getName() { 66 return this.name; 67 } 68 69 getTypeIndex() { 70 return this.typeIndex; 71 } 72 73 setTypeIndex(typeIndex: number) { 74 return this.typeIndex = typeIndex; 75 } 76 77 setLexVar(scope: VariableScope | LoopScope) { 78 this.idxLex = scope.getLexVarIdx() 79 scope.pendingCreateEnv(); 80 this.isLexVar = true; 81 return this.idxLex; 82 } 83 84 clearLexVar() { 85 this.isLexVar = false; 86 this.idxLex = 0; 87 } 88 89 isLet(): boolean { 90 return this.declKind == VarDeclarationKind.LET; 91 } 92 93 isConst(): boolean { 94 return this.declKind == VarDeclarationKind.CONST; 95 } 96 97 isLetOrConst(): boolean { 98 return this.declKind == VarDeclarationKind.LET || this.declKind == VarDeclarationKind.CONST; 99 } 100 101 isVar(): boolean { 102 return this.declKind == VarDeclarationKind.VAR; 103 } 104 105 isNone(): boolean { 106 return this.declKind == VarDeclarationKind.NONE; 107 } 108 109 isClass(): boolean { 110 return this.declKind == VarDeclarationKind.CLASS; 111 } 112} 113 114export class LocalVariable extends Variable { 115 status: InitStatus | null; 116 isExport: boolean = false; 117 exportedName: string = ""; 118 119 constructor(declKind: VarDeclarationKind, name: string, status?: InitStatus) { 120 super(declKind, name); 121 this.status = status ? status : null; 122 } 123 124 initialize() { 125 this.status = InitStatus.INITIALIZED; 126 } 127 128 isInitialized() { 129 if (this.status != null) { 130 return this.status == InitStatus.INITIALIZED; 131 } 132 return true; 133 } 134 135 setExport() { 136 this.isExport = true; 137 } 138 139 isExportVar() { 140 return this.isExport; 141 } 142 143 setExportedName(name: string) { 144 this.exportedName = name; 145 } 146 147 getExportedName() { 148 if (!this.exportedName) { 149 throw new Error("Exported Variable " + this.getName() + " doesn't have exported name"); 150 } 151 return this.exportedName; 152 } 153} 154 155export class GlobalVariable extends Variable { 156 constructor(declKind: VarDeclarationKind, name: string) { 157 super(declKind, name); 158 } 159}