1/* 2 * Copyright (c) 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 { 17 expect 18} from 'chai'; 19import 'mocha'; 20import { 21 EcmaDefinefuncdyn, 22 EcmaIstrue, 23 EcmaReturnundefined, 24 EcmaStglobalvar, 25 EcmaThrowundefinedifhole, 26 Imm, 27 Jeqz, 28 Label, 29 LdaDyn, 30 LdaiDyn, 31 LdaStr, 32 ResultType, 33 StaDyn, 34 VReg 35} from "../src/irnodes"; 36import { checkInstructions, compileMainSnippet, SnippetCompiler } from "./utils/base"; 37 38describe("HoistTest", function () { 39 40 // case 1: hoist var declared variable ((declared in global scope)) in global scope 41 it('case 1;', function () { 42 let insns = compileMainSnippet("var a = 1;"); 43 let expected = [ 44 new LdaDyn(new VReg()), 45 new EcmaStglobalvar("a"), 46 new LdaiDyn(new Imm(1)), 47 new EcmaStglobalvar("a"), 48 new EcmaReturnundefined() 49 ] 50 51 expect(checkInstructions(insns, expected)).to.be.true; 52 }); 53 54 // case 2: hoist var declared variable (declared in local scope) in global scope 55 it('case 2', function () { 56 let insns = compileMainSnippet(`if (true) { 57 var a = 2; 58 }`); 59 let endLabel = new Label(); 60 61 let expected = [ 62 new LdaDyn(new VReg()), 63 new EcmaStglobalvar("a"), 64 new LdaDyn(new VReg()), 65 new EcmaIstrue(), 66 new Jeqz(endLabel), 67 new LdaiDyn(new Imm(2)), 68 new EcmaStglobalvar("a"), 69 endLabel, 70 new EcmaReturnundefined() 71 ] 72 expect(checkInstructions(insns, expected)).to.be.true; 73 }); 74 75 // case 3: hoist function declaration in global scope 76 it('case 3', function () { 77 let snippetCompiler = new SnippetCompiler(); 78 snippetCompiler.compile(`function a() {};`); 79 80 let insns = snippetCompiler.getGlobalInsns(); 81 let expected = [ 82 new EcmaDefinefuncdyn("a", new Imm(0), new VReg()), 83 new EcmaStglobalvar("a"), 84 new EcmaReturnundefined() 85 ] 86 expect(checkInstructions(insns, expected)).to.be.true; 87 }); 88 89 // case 4: In case that two function declared directly in global scope with the same name, hoist the later one. 90 it('case 4', function () { 91 let snippetCompiler = new SnippetCompiler(); 92 snippetCompiler.compile(`function a() {}; function a() {}`); 93 94 let insns = snippetCompiler.getGlobalInsns(); 95 let expected = [ 96 new EcmaDefinefuncdyn("#2#a", new Imm(0), new VReg()), 97 new EcmaStglobalvar("a"), 98 new EcmaReturnundefined() 99 ] 100 101 expect(checkInstructions(insns, expected)).to.be.true; 102 }); 103 104 // case 5: hoisting of function declaration is of higher priority than var declared variables with a same name in global scope 105 it('case 5', function () { 106 let snippetCompiler = new SnippetCompiler(); 107 snippetCompiler.compile(`var a = 1; function a() {}`); 108 let insns = snippetCompiler.getGlobalInsns(); 109 let expected = [ 110 new EcmaDefinefuncdyn("a", new Imm(0), new VReg()), 111 new EcmaStglobalvar("a"), 112 new LdaiDyn(new Imm(1)), 113 new EcmaStglobalvar("a"), 114 new EcmaReturnundefined() 115 ] 116 117 expect(checkInstructions(insns, expected)).to.be.true; 118 }); 119 120 // case 6: hoist var declared variable in function scope 121 it('case 6', function () { 122 let snippetCompiler = new SnippetCompiler(); 123 snippetCompiler.compile(`function a() {var a = 1;}`); 124 let funcPg = snippetCompiler.getPandaGenByName("a"); 125 let insns = funcPg!.getInsns(); 126 127 let a = new VReg(); 128 let expected = [ 129 new LdaDyn(a), 130 new StaDyn(new VReg()), 131 new LdaiDyn(new Imm(1)), 132 new StaDyn(a), 133 134 new EcmaReturnundefined() 135 ] 136 expect(checkInstructions(insns!, expected)).to.be.true; 137 }); 138 139 // case 7: hoist function declaration in function scope 140 it('case 7', function () { 141 let snippetCompiler = new SnippetCompiler(); 142 snippetCompiler.compile(`function a() {function b() {}};`); 143 let funcPg = snippetCompiler.getPandaGenByName("a"); 144 let insns = funcPg!.getInsns(); 145 let a = new VReg(); 146 let expected = [ 147 new EcmaDefinefuncdyn("b", new Imm(0), new VReg()), 148 new StaDyn(a), 149 150 new EcmaReturnundefined() 151 ] 152 153 expect(checkInstructions(insns!, expected)).to.be.true; 154 }); 155 156 // case 8: temporary dead zone of let in global scope 157 it('case 8', function () { 158 let snippetCompiler = new SnippetCompiler(); 159 snippetCompiler.compile(`a = 1; 160 let a;`); 161 let funcPg = snippetCompiler.getPandaGenByName("func_main_0"); 162 let insns = funcPg!.getInsns(); 163 let idReg = new VReg(); 164 let expected = [ 165 new LdaStr("a"), 166 new StaDyn(idReg), 167 new EcmaThrowundefinedifhole(new VReg(), idReg) 168 ] 169 170 expect(checkInstructions(insns.slice(3, 5), expected)); 171 }); 172 173 // case 9: temporary dead zone of let in function scope 174 it('case 9', function () { 175 let snippetCompiler = new SnippetCompiler(); 176 snippetCompiler.compile(`function b() { 177 a = 1; 178 let a; 179 }`); 180 let funcPg = snippetCompiler.getPandaGenByName("b"); 181 let insns = funcPg!.getInsns(); 182 let idReg = new VReg(); 183 184 let expected = [ 185 new LdaStr("a"), 186 new StaDyn(idReg), 187 new EcmaThrowundefinedifhole(new VReg(), idReg) 188 ] 189 190 expect(checkInstructions(insns.slice(3, 5), expected)); 191 }); 192 193 // case 10: temporary dead zone of let in local scope 194 it('case 10', function () { 195 let snippetCompiler = new SnippetCompiler(); 196 snippetCompiler.compile(`{ 197 a = 1; 198 let a; 199 }`); 200 let funcPg = snippetCompiler.getPandaGenByName("func_main_0"); 201 let insns = funcPg!.getInsns(); 202 let idReg = new VReg(); 203 204 let expected = [ 205 new LdaStr("a"), 206 new StaDyn(idReg), 207 new EcmaThrowundefinedifhole(new VReg(), idReg) 208 ] 209 210 expect(checkInstructions(insns.slice(3, 5), expected)); 211 }) 212}) 213