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 { 17 expect 18} from 'chai'; 19import 'mocha'; 20import { DiagnosticCode, DiagnosticError } from '../../src/diagnostic'; 21import { 22 EcmaCallithisrangedyn, 23 EcmaCreateemptyarray, 24 EcmaGetiterator, 25 EcmaIsfalse, 26 EcmaLdobjbyname, 27 EcmaReturnundefined, 28 EcmaStrictnoteqdyn, 29 EcmaThrowdyn, 30 EcmaThrowifnotobject, 31 Imm, 32 Jeqz, 33 Jmp, 34 Label, 35 LdaDyn, ResultType, 36 StaDyn, 37 VReg 38} from "../../src/irnodes"; 39import { checkInstructions, compileMainSnippet } from "../utils/base"; 40 41describe("ForOfLoopTest", function () { 42 it("forOfLoopWithEmptyArray", function () { 43 let insns = compileMainSnippet("for (let a of []) {}"); 44 let a = new VReg(); 45 let arrInstance = new VReg(); 46 let iterReg = new VReg(); 47 let nextMethodReg = new VReg(); 48 let resultObj = new VReg(); 49 let exceptionVreg = new VReg(); 50 let trueReg = new VReg(); 51 let done = new VReg(); 52 let value = new VReg(); 53 54 let loopStartLabel = new Label(); 55 let loopEndLabel = new Label(); 56 let tryBeginLabel = new Label(); 57 let tryEndLabel = new Label(); 58 let catchBeginLabel = new Label(); 59 let isDone = new Label(); 60 61 let expected = [ 62 new EcmaCreateemptyarray(), 63 new StaDyn(arrInstance), 64 new EcmaGetiterator(), 65 new StaDyn(iterReg), 66 new EcmaLdobjbyname("next", iterReg), 67 new StaDyn(nextMethodReg), 68 69 new LdaDyn(new VReg()), 70 new StaDyn(done), 71 72 tryBeginLabel, 73 new LdaDyn(trueReg), 74 new StaDyn(done), 75 loopStartLabel, 76 new EcmaCallithisrangedyn(new Imm(1), [nextMethodReg, iterReg]), 77 new StaDyn(resultObj), 78 new EcmaThrowifnotobject(resultObj), 79 new EcmaLdobjbyname("done", resultObj), 80 new EcmaIsfalse(), 81 new Jeqz(loopEndLabel), 82 new EcmaLdobjbyname("value", resultObj), 83 new StaDyn(value), 84 85 new LdaDyn(new VReg()), 86 new StaDyn(done), 87 88 new LdaDyn(value), 89 new StaDyn(a), 90 tryEndLabel, 91 92 new Jmp(loopStartLabel), 93 94 catchBeginLabel, 95 new StaDyn(exceptionVreg), 96 new LdaDyn(done), 97 new EcmaStrictnoteqdyn(trueReg), 98 new Jeqz(isDone), 99 new EcmaLdobjbyname("return", iterReg), 100 new StaDyn(nextMethodReg), 101 new EcmaStrictnoteqdyn(new VReg()), 102 new Jeqz(isDone), 103 new EcmaCallithisrangedyn(new Imm(1), [nextMethodReg, iterReg]), 104 isDone, 105 new LdaDyn(exceptionVreg), 106 new EcmaThrowdyn(), 107 108 loopEndLabel, 109 new EcmaReturnundefined() 110 ]; 111 expect(checkInstructions(insns, expected)).to.be.true; 112 113 let jumps = insns.filter(item => (item instanceof Jmp || item instanceof Jeqz)); 114 115 expect(jumps.length).to.equal(4); 116 }); 117 118 it("forOfLoopWithContinue", function () { 119 let insns = compileMainSnippet("for (let a of []) {continue;}"); 120 let a = new VReg(); 121 let arrInstance = new VReg(); 122 let resultObj = new VReg(); 123 let trueReg = new VReg(); 124 let iterReg = new VReg(); 125 let exceptionVreg = new VReg(); 126 let nextMethodReg = new VReg(); 127 let done = new VReg(); 128 let value = new VReg(); 129 130 let loopStartLabel = new Label(); 131 let loopEndLabel = new Label(); 132 let tryBeginLabel = new Label(); 133 let tryEndLabel = new Label(); 134 let catchBeginLabel = new Label(); 135 let isDone = new Label(); 136 let insertedtryBeginLabel = new Label(); 137 let insertedtryEndLabel = new Label(); 138 139 let expected = [ 140 new EcmaCreateemptyarray(), 141 new StaDyn(arrInstance), 142 new EcmaGetiterator(), 143 new StaDyn(iterReg), 144 new EcmaLdobjbyname("next", iterReg), 145 new StaDyn(nextMethodReg), 146 147 new LdaDyn(new VReg()), 148 new StaDyn(done), 149 150 tryBeginLabel, 151 new LdaDyn(trueReg), 152 new StaDyn(done), 153 loopStartLabel, 154 new EcmaCallithisrangedyn(new Imm(1), [nextMethodReg, iterReg]), 155 new StaDyn(resultObj), 156 new EcmaThrowifnotobject(resultObj), 157 new EcmaLdobjbyname("done", resultObj), 158 new EcmaIsfalse(), 159 new Jeqz(loopEndLabel), 160 new EcmaLdobjbyname("value", resultObj), 161 new StaDyn(value), 162 163 new LdaDyn(new VReg()), 164 new StaDyn(done), 165 166 new LdaDyn(value), 167 new StaDyn(a), 168 169 insertedtryBeginLabel, 170 insertedtryEndLabel, 171 new Jmp(loopStartLabel), 172 173 tryEndLabel, 174 175 new Jmp(loopStartLabel), 176 177 catchBeginLabel, 178 new StaDyn(exceptionVreg), 179 new LdaDyn(done), 180 new EcmaStrictnoteqdyn(trueReg), 181 new Jeqz(isDone), 182 new EcmaLdobjbyname("return", iterReg), 183 new StaDyn(nextMethodReg), 184 new EcmaStrictnoteqdyn(new VReg()), 185 new Jeqz(isDone), 186 new EcmaCallithisrangedyn(new Imm(1), [nextMethodReg, iterReg]), 187 isDone, 188 new LdaDyn(exceptionVreg), 189 new EcmaThrowdyn(), 190 191 loopEndLabel, 192 new EcmaReturnundefined() 193 ]; 194 expect(checkInstructions(insns, expected)).to.be.true; 195 196 let jumps = insns.filter(item => (item instanceof Jmp || item instanceof Jeqz)); 197 198 expect(jumps.length).to.equal(5); 199 }); 200 201 it("forOfLoopWithBreak", function () { 202 let insns = compileMainSnippet("for (let a of []) {break;}"); 203 let a = new VReg(); 204 let arrInstance = new VReg(); 205 let resultObj = new VReg(); 206 let exceptionVreg = new VReg(); 207 let iterReg = new VReg(); 208 let trueReg = new VReg(); 209 let nextMethodReg = new VReg(); 210 let done = new VReg(); 211 let value = new VReg(); 212 let loopStartLabel = new Label(); 213 let loopEndLabel = new Label(); 214 let tryBeginLabel = new Label(); 215 let tryEndLabel = new Label(); 216 let catchBeginLabel = new Label(); 217 let isDone = new Label(); 218 let noReturn = new Label(); 219 let insertedtryBeginLabel = new Label(); 220 let insertedtryEndLabel = new Label(); 221 222 let expected = [ 223 new EcmaCreateemptyarray(), 224 new StaDyn(arrInstance), 225 new EcmaGetiterator(), 226 new StaDyn(iterReg), 227 new EcmaLdobjbyname("next", iterReg), 228 new StaDyn(nextMethodReg), 229 230 new LdaDyn(new VReg()), 231 new StaDyn(done), 232 233 tryBeginLabel, 234 new LdaDyn(trueReg), 235 new StaDyn(done), 236 loopStartLabel, 237 new EcmaCallithisrangedyn(new Imm(1), [nextMethodReg, iterReg]), 238 new StaDyn(resultObj), 239 new EcmaThrowifnotobject(resultObj), 240 new EcmaLdobjbyname("done", resultObj), 241 new EcmaIsfalse(), 242 new Jeqz(loopEndLabel), 243 new EcmaLdobjbyname("value", resultObj), 244 new StaDyn(value), 245 246 new LdaDyn(new VReg()), 247 new StaDyn(done), 248 249 new LdaDyn(value), 250 new StaDyn(a), 251 252 insertedtryBeginLabel, 253 new EcmaLdobjbyname("return", iterReg), 254 new StaDyn(nextMethodReg), 255 new EcmaStrictnoteqdyn(new VReg()), // undefined 256 new Jeqz(noReturn), 257 new EcmaCallithisrangedyn(new Imm(1), [nextMethodReg, iterReg]), 258 new StaDyn(new VReg()), 259 new EcmaThrowifnotobject(new VReg()), 260 noReturn, 261 insertedtryEndLabel, 262 new Jmp(loopEndLabel), 263 264 tryEndLabel, 265 266 new Jmp(loopStartLabel), 267 268 catchBeginLabel, 269 new StaDyn(exceptionVreg), 270 new LdaDyn(done), 271 new EcmaStrictnoteqdyn(trueReg), 272 new Jeqz(isDone), 273 new EcmaLdobjbyname("return", iterReg), 274 new StaDyn(nextMethodReg), 275 new EcmaStrictnoteqdyn(new VReg()), 276 new Jeqz(isDone), 277 new EcmaCallithisrangedyn(new Imm(1), [nextMethodReg, iterReg]), 278 isDone, 279 new LdaDyn(exceptionVreg), 280 new EcmaThrowdyn(), 281 282 loopEndLabel, 283 new EcmaReturnundefined() 284 ]; 285 286 expect(checkInstructions(insns, expected)).to.be.true; 287 288 let jumps = insns.filter(item => (item instanceof Jmp || item instanceof Jeqz)); 289 290 expect(jumps.length).to.equal(6); 291 }); 292 293 it("ForOf SyntaxError", function () { 294 let source: string = `for ([(x, y)] of []) {}`; 295 let errorThrown = false; 296 try { 297 compileMainSnippet(source); 298 } catch (err) { 299 expect(err instanceof DiagnosticError).to.be.true; 300 expect((<DiagnosticError>err).code).to.equal(DiagnosticCode.Property_destructuring_pattern_expected); 301 errorThrown = true; 302 } 303 expect(errorThrown).to.be.true; 304 }); 305}); 306