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 { 21 Add2, 22 Istrue, 23 Less, 24 Returnundefined, 25 Sttoglobalrecord, 26 Tryldglobalbyname, 27 Trystglobalbyname, 28 Imm, 29 Jeqz, 30 Jmp, 31 Label, 32 Lda, 33 Ldai, 34 Sta, 35 VReg, 36 IRNode 37} from "../../src/irnodes"; 38import { checkInstructions, compileMainSnippet } from "../utils/base"; 39import { creatAstFromSnippet } from "../utils/asthelper" 40import { PandaGen } from '../../src/pandagen'; 41 42describe("WhileLoopTest", function () { 43 it("while (true) {}", function () { 44 let insns = compileMainSnippet("while (true) {}"); 45 let labelPre = new Label(); 46 let labelPost = new Label(); 47 let expected = [ 48 labelPre, 49 new Lda(new VReg()), 50 new Istrue(), 51 new Jeqz(labelPost), 52 new Jmp(labelPre), 53 labelPost, 54 new Returnundefined() 55 ]; 56 57 expect(checkInstructions(insns, expected)).to.be.true; 58 }); 59 60 it("while (a + b) {}", function () { 61 let insns = compileMainSnippet("let a, b; while (a + b) {}"); 62 IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined); 63 (<PandaGen>(IRNode.pg)).updateIcSize(2); 64 let loopBegin = new Label(); 65 let loopEnd = new Label(); 66 let lhs = new VReg(); 67 let expected = [ 68 loopBegin, 69 // a + b 70 new Tryldglobalbyname(new Imm(0), 'a'), 71 new Sta(lhs), 72 new Tryldglobalbyname(new Imm(1), 'b'), 73 new Add2(new Imm(2), lhs), 74 new Istrue(), 75 new Jeqz(loopEnd), 76 // body 77 new Jmp(loopBegin), 78 loopEnd 79 ]; 80 81 insns = insns.slice(4, insns.length - 1); // skip let a, b and return. 82 expect(checkInstructions(insns, expected)).to.be.true; 83 }); 84 85 it('whileLoopWithBody', function () { 86 let insns = compileMainSnippet(` 87 let a; 88 while (a < 0) { a = 1; } 89 `); 90 91 IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined); 92 (<PandaGen>(IRNode.pg)).updateIcSize(1); 93 let lhs = new VReg(); 94 let loopBegin = new Label(); 95 let loopEnd = new Label(); 96 let expected = [ 97 loopBegin, 98 // condition 99 // compute lhs 100 new Tryldglobalbyname(new Imm(0), 'a'), 101 new Sta(lhs), 102 // compute rhs 103 new Ldai(new Imm(0)), 104 new Less(new Imm(1), lhs), 105 new Jeqz(loopEnd), 106 107 // body 108 new Ldai(new Imm(1)), 109 new Trystglobalbyname(new Imm(2), 'a'), 110 new Jmp(loopBegin), 111 112 loopEnd, 113 ]; 114 115 insns = insns.slice(2, insns.length - 1); // skip let a and return. 116 expect(checkInstructions(insns, expected)).to.be.true; 117 expect((<Jeqz>insns[5]).getTarget() === insns[insns.length - 1]).to.be.true; 118 expect((<Jmp>insns[insns.length - 2]).getTarget() === insns[0]).to.be.true; 119 }); 120 121 it('whileLoopWithContinue', function () { 122 let insns = compileMainSnippet("let a = 5;" + 123 "while (a < 1) { a = 2; continue; }"); 124 125 IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined); 126 let lhs = new VReg(); 127 let labelPre = new Label(); 128 let labelPost = new Label(); 129 let expected = [ 130 new Ldai(new Imm(5)), 131 new Sttoglobalrecord(new Imm(0), 'a'), 132 labelPre, 133 // condition 134 new Tryldglobalbyname(new Imm(1), 'a'), 135 new Sta(lhs), 136 new Ldai(new Imm(1)), 137 new Less(new Imm(2), lhs), 138 new Jeqz(labelPost), 139 //body 140 new Ldai(new Imm(2)), 141 new Trystglobalbyname(new Imm(3), 'a'), 142 new Jmp(labelPre), // continue 143 new Jmp(labelPre), 144 labelPost, 145 new Returnundefined() 146 ] 147 // check the instruction kinds are the same as we expect 148 expect(checkInstructions(insns, expected)).to.be.true; 149 // check continue jumps to the expected instruction 150 let jmp = <Jmp>insns[11]; 151 let targetLabel = (jmp).getTarget(); 152 expect(targetLabel).to.equal(insns[2]); 153 }); 154 155 it('whileLoopWithBreak', function () { 156 let insns = compileMainSnippet("let a = 5;" + 157 "while (a < 1) { a = 2; break; }"); 158 IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined); 159 let lhs = new VReg(); 160 let labelPre = new Label(); 161 let labelPost = new Label(); 162 let expected = [ 163 new Ldai(new Imm(5)), 164 new Sttoglobalrecord(new Imm(0), 'a'), 165 labelPre, 166 // condition 167 new Tryldglobalbyname(new Imm(1), 'a'), 168 new Sta(lhs), 169 new Ldai(new Imm(1)), 170 new Less(new Imm(2), lhs), 171 new Jeqz(labelPost), 172 //body 173 new Ldai(new Imm(2)), 174 new Trystglobalbyname(new Imm(3), 'a'), 175 new Jmp(labelPost), //break 176 new Jmp(labelPre), 177 labelPost, 178 new Returnundefined() 179 ] 180 // check the instruction kinds are the same as we expect 181 expect(checkInstructions(insns, expected)).to.be.true; 182 // check continue jumps to the expected instruction 183 let jmp = <Jmp>insns[10]; 184 let targetLabel = (jmp).getTarget(); 185 expect(targetLabel).to.equal(insns[12]); 186 }); 187}); 188