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