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 EcmaCreateemptyobject, 23 EcmaGetnextpropname, 24 EcmaGetpropiterator, 25 EcmaReturnundefined, 26 EcmaStrictnoteqdyn, 27 EcmaTryldglobalbyname, 28 EcmaTrystglobalbyname, 29 Jeqz, 30 Jmp, 31 Label, 32 LdaDyn, 33 StaDyn, 34 VReg 35} from "../../src/irnodes"; 36import { checkInstructions, compileMainSnippet } from "../utils/base"; 37 38describe("forInLoopTest", function () { 39 it("forInLoopwithEmptyObject", function () { 40 let insns = compileMainSnippet("for (let prop in {}) {}"); 41 let prop = new VReg(); 42 let temp = new VReg(); 43 let objInstance = new VReg(); 44 let iterReg = new VReg(); 45 let rhs = new VReg(); 46 47 let loopStartLabel = new Label(); 48 let loopEndLabel = new Label(); 49 let expected = [ 50 new EcmaCreateemptyobject(), 51 new StaDyn(objInstance), 52 new EcmaGetpropiterator(), 53 new StaDyn(iterReg), 54 55 loopStartLabel, 56 new EcmaGetnextpropname(iterReg), 57 new StaDyn(rhs), 58 new EcmaStrictnoteqdyn(temp), 59 new Jeqz(loopEndLabel), 60 new LdaDyn(rhs), 61 new StaDyn(prop), 62 new Jmp(loopStartLabel), 63 64 loopEndLabel, 65 new EcmaReturnundefined() 66 ]; 67 expect(checkInstructions(insns, expected)).to.be.true; 68 69 let jumps = insns.filter(item => (item instanceof Jmp || item instanceof Jeqz)); 70 71 expect(jumps.length).to.equal(2); 72 }); 73 74 it("forInLoopWithExpressionAsLoopVariable", function () { 75 let insns = compileMainSnippet(` 76 let prop; 77 let obj; 78 for (prop in obj) { 79 } 80 `); 81 let temp = new VReg(); 82 let iterReg = new VReg(); 83 let rhs = new VReg(); 84 85 let loopStartLabel = new Label(); 86 let loopEndLabel = new Label(); 87 let expected = [ 88 new EcmaTryldglobalbyname('obj'), 89 new EcmaGetpropiterator(), 90 new StaDyn(iterReg), 91 92 loopStartLabel, 93 new EcmaGetnextpropname(iterReg), 94 new StaDyn(rhs), 95 new EcmaStrictnoteqdyn(temp), 96 new Jeqz(loopEndLabel), 97 new LdaDyn(rhs), 98 new EcmaTrystglobalbyname('prop'), 99 new Jmp(loopStartLabel), 100 101 loopEndLabel, 102 ]; 103 104 insns = insns.slice(4, insns.length - 1); 105 expect(checkInstructions(insns, expected)).to.be.true; 106 107 let jmp = <Jmp>insns.find(item => (item instanceof Jmp)); 108 let jeqz = <Jeqz>insns.find(item => (item instanceof Jeqz)); 109 expect(jmp.getTarget()).to.equal(insns[3]); 110 expect(jeqz.getTarget()).to.equal(insns[insns.length - 1]); 111 }); 112 113 it("forInLoopwithObjectwithContinue", function () { 114 let insns = compileMainSnippet("for (let prop in {}) {continue; }"); 115 let prop = new VReg(); 116 let temp = new VReg(); 117 let objInstance = new VReg(); 118 let iterReg = new VReg(); 119 let rhs = new VReg(); 120 121 let loopStartLabel = new Label(); 122 let loopEndLabel = new Label(); 123 let expected = [ 124 new EcmaCreateemptyobject(), 125 new StaDyn(objInstance), 126 new EcmaGetpropiterator(), 127 new StaDyn(iterReg), 128 129 loopStartLabel, 130 new EcmaGetnextpropname(iterReg), 131 new StaDyn(rhs), 132 new EcmaStrictnoteqdyn(temp), 133 new Jeqz(loopEndLabel), 134 new LdaDyn(rhs), 135 new StaDyn(prop), 136 new Jmp(loopStartLabel), 137 new Jmp(loopStartLabel), 138 139 loopEndLabel, 140 new EcmaReturnundefined() 141 ]; 142 expect(checkInstructions(insns, expected)).to.be.true; 143 144 let jumps = insns.filter(item => (item instanceof Jmp || item instanceof Jeqz)); 145 146 expect(jumps.length).to.equal(3); 147 }); 148 149 it("forInLoopwithObjectwithBreak", function () { 150 let insns = compileMainSnippet("for (let prop in {}) {break; }"); 151 let prop = new VReg(); 152 let temp = new VReg(); 153 let objInstance = new VReg(); 154 let iterReg = new VReg(); 155 let rhs = new VReg(); 156 157 let loopStartLabel = new Label(); 158 let loopEndLabel = new Label(); 159 let expected = [ 160 new EcmaCreateemptyobject(), 161 new StaDyn(objInstance), 162 new EcmaGetpropiterator(), 163 new StaDyn(iterReg), 164 165 loopStartLabel, 166 new EcmaGetnextpropname(iterReg), 167 new StaDyn(rhs), 168 new EcmaStrictnoteqdyn(temp), 169 new Jeqz(loopEndLabel), 170 new LdaDyn(rhs), 171 new StaDyn(prop), 172 new Jmp(loopEndLabel), 173 new Jmp(loopStartLabel), 174 175 loopEndLabel, 176 new EcmaReturnundefined() 177 ]; 178 expect(checkInstructions(insns, expected)).to.be.true; 179 180 let jumps = insns.filter(item => (item instanceof Jmp || item instanceof Jeqz)); 181 182 expect(jumps.length).to.equal(3); 183 }); 184 185 it("ForIn SyntaxError", function () { 186 let source: string = `for ([(x, y)] in {}) { }`; 187 let errorThrown = false; 188 try { 189 compileMainSnippet(source); 190 } catch (err) { 191 expect(err instanceof DiagnosticError).to.be.true; 192 expect((<DiagnosticError>err).code).to.equal(DiagnosticCode.Property_destructuring_pattern_expected); 193 errorThrown = true; 194 } 195 expect(errorThrown).to.be.true; 196 }); 197}); 198