• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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    Inc,
22    Less,
23    Returnundefined,
24    Tonumeric,
25    Imm,
26    Jeqz,
27    Jmp,
28    Label,
29    Lda,
30    Ldai,
31    Sta,
32    VReg,
33    IRNode
34} from "../../src/irnodes";
35import { checkInstructions, compileMainSnippet } from "../utils/base";
36import { creatAstFromSnippet } from "../utils/asthelper"
37import { PandaGen } from '../../src/pandagen';
38
39describe("ForLoopTest", function () {
40    it('forLoopEmpty', function () {
41        let insns = compileMainSnippet("for (;;) {}");
42        let labelPre = new Label();
43        let labelPost = new Label();
44        let labelIncr = new Label();
45        IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined);
46        let expected = [
47            labelPre,
48            labelIncr,
49            new Jmp(labelPre),
50            labelPost,
51            new Returnundefined()
52        ];
53        let jumps = insns.filter(item => item instanceof Jmp);
54
55        expect(jumps.length).to.equal(1);
56
57        let jmpLabel = (<Jmp>jumps[0]).getTarget();
58
59        expect(checkInstructions(insns, expected)).to.be.true;
60        expect(jmpLabel).to.equal(insns[0]);
61    });
62
63    it('forLoopWithInitializer', function () {
64        let insns = compileMainSnippet("for (let i = 0;;) {}");
65        let jumps = insns.filter(item => item instanceof Jmp);
66
67        expect(jumps.length).to.equal(1);
68
69        let jmpLabel = (<Jmp>jumps[0]).getTarget();
70
71        expect(insns[4]).to.equal(jumps[0]);
72        expect(jmpLabel).to.equal(insns[2]);
73    });
74
75    it('forLoopWithInitializerAndCondition', function () {
76        let insns = compileMainSnippet("for (let i = 0; i < 5;) {}");
77        let jumps = insns.filter(item => (item instanceof Jmp || item instanceof Jeqz));
78
79        expect(jumps.length).to.equal(2);
80
81        let jgezLabel = (<Jmp>jumps[0]).getTarget();
82        let jmpLabel = (<Jmp>jumps[1]).getTarget();
83
84        expect(jmpLabel).to.equal(insns[2]);
85        expect(jgezLabel).to.equal(insns[10]);
86
87        expect(insns[7]).to.equal(jumps[0]);
88        expect(insns[9]).to.equal(jumps[1]);
89    });
90
91    it('forLoopWithInitializerAndConditionAndIncrementor', function () {
92        let insns = compileMainSnippet("for (let i = 0; i < 5; i++) {}");
93        let jumps = insns.filter(item => (item instanceof Jmp || item instanceof Jeqz));
94
95        expect(jumps.length).to.equal(2);
96
97        let jgezLabel = (<Jmp>jumps[0]).getTarget();
98        let jmpLabel = (<Jmp>jumps[1]).getTarget();
99
100        expect(jmpLabel).to.equal(insns[2]);
101        expect(jgezLabel).to.equal(insns[17]);
102
103        expect(insns[7]).to.equal(jumps[0]);
104        expect(insns[16]).to.equal(jumps[1]);
105    });
106
107    it('forLoopWithContinue', function () {
108        let insns = compileMainSnippet("for (let i = 0; i < 5; ++i) { continue; }");
109        let i = new VReg();
110        let lhs = new VReg();
111        let operand = new VReg();
112        let labelPre = new Label();
113        let labelPost = new Label();
114        let labelIncr = new Label();
115        IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined);
116        let expected = [
117            // initializer
118            new Ldai(new Imm(0)),
119            new Sta(i),
120            labelPre,
121            // condition
122            new Lda(i),
123            new Sta(lhs),
124            new Ldai(new Imm(5)),
125            new Less(new Imm(0), lhs),
126            new Jeqz(labelPost),
127            // body
128            new Jmp(labelIncr), // continue
129            labelIncr,
130            // incrementor
131            new Lda(i),
132            new Sta(operand),
133            new Lda(operand),
134            new Inc(new Imm(1)),
135            new Sta(i),
136            // jump to the loop header
137            new Jmp(new Label()),
138            labelPost,
139            new Returnundefined()
140        ];
141        // check the instruction kinds are the same as we expect
142        expect(checkInstructions(insns, expected)).to.be.true;
143        // check continue jumps to the expected instruction
144        let jmp = <Jmp>insns[8];
145        let targetLabel = (jmp).getTarget();
146        expect(targetLabel).to.equal(insns[9]);
147    });
148
149    it('forLoopWithBreak', function () {
150        let insns = compileMainSnippet("for (let i = 0; i < 5; ++i) {break; }");
151        let i = new VReg();
152        let lhs = new VReg();
153        let operand = new VReg();
154        let labelPre = new Label();
155        let labelPost = new Label();
156        let labelIncr = new Label();
157        IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined);
158        let expected = [
159            // initializer
160            new Ldai(new Imm(0)),
161            new Sta(i),
162            labelPre,
163            // condition
164            new Lda(i),
165            new Sta(lhs),
166            new Ldai(new Imm(5)),
167            new Less(new Imm(0), lhs),
168            new Jeqz(labelPost),
169            // body
170            new Jmp(labelPost), // break
171            // incrementor
172            labelIncr,
173            new Lda(i),
174            new Sta(operand),
175            new Lda(operand),
176            new Inc(new Imm(1)),
177            new Sta(i),
178            // jump to the loop header
179            new Jmp(labelPre),
180            labelPost,
181            new Returnundefined()
182        ];
183        // check the instruction kinds are the same as we expect
184        expect(checkInstructions(insns, expected)).to.be.true;
185        // check continue jumps to the expected instruction
186        let jmp = <Jmp>insns[8];
187        let targetLabel = (jmp).getTarget();
188        expect(targetLabel).to.equal(insns[16]);
189    });
190});
191
192describe("LoopWithLabelTests", function () {
193    it('forLoopWithBreakWithLabel', function () {
194        let insns = compileMainSnippet(`loop1:
195                                for (let i = 0; i < 5; ++i) {
196                                    for (let j = 0; j < 6; j++) {
197                                        break loop1;
198                                    }
199                                }`);
200        let i = new VReg();
201        let j = new VReg();
202        let lhs = new VReg();
203        let labelPre = new Label();
204        let labelPost = new Label();
205        let labelIncr = new Label();
206        let labelPre1 = new Label();
207        let labelPost1 = new Label();
208        let labelIncr1 = new Label();
209        IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined);
210        let expected = [
211            // initializer
212            new Ldai(new Imm(0.0)),
213            new Sta(i),
214            labelPre,
215            // condition
216            new Lda(i),
217            new Sta(lhs),
218            new Ldai(new Imm(5.0)),
219            new Less(new Imm(0), lhs),
220            new Jeqz(labelPost),
221
222            // second for
223            new Ldai(new Imm(0.0)),
224            new Sta(j),
225            labelPre1,
226            // condition
227            new Lda(j),
228            new Sta(lhs),
229            new Ldai(new Imm(6.0)),
230            new Less(new Imm(1), lhs),
231            new Jeqz(labelPost1),
232            new Jmp(labelPost),
233            labelIncr1,
234            // incrementor
235            new Lda(j),
236            new Sta(j),
237            new Lda(j),
238            new Inc(new Imm(2)),
239            new Sta(j),
240            new Lda(j),
241            new Tonumeric(new Imm(3)),
242            // jump to the loop header
243            new Jmp(labelPre1),
244            labelPost1,
245            labelIncr,
246            // incrementor
247            new Lda(i),
248            new Sta(i),
249            new Lda(i),
250            new Inc(new Imm(4)),
251            new Sta(i),
252            // jump to the loop header
253            new Jmp(labelPre),
254            labelPost,
255            new Returnundefined()
256        ];
257
258        // check the instruction kinds are the same as we expect
259        expect(checkInstructions(insns, expected)).to.be.true;
260        // check break jumps to the expected instruction
261        let jmp = <Jmp>insns[16];
262        let targetLabel = (jmp).getTarget();
263        expect(targetLabel).to.equal(insns[34]);
264    });
265
266    it('forLoopWithContinueWithLabel', function () {
267        let insns = compileMainSnippet(`loop1:
268                                loop2:
269                                loop3:
270                                for (let i = 0; i < 5; ++i) {
271                                    for (let j = 0; j < 6; j++) {
272                                        continue loop2;
273                                    }
274                                }`);
275        let i = new VReg();
276        let j = new VReg();
277        let lhs = new VReg();
278        let labelPre = new Label();
279        let labelPost = new Label();
280        let labelIncr = new Label();
281        let labelPre1 = new Label();
282        let labelPost1 = new Label();
283        let labelIncr1 = new Label();
284        IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined);
285        let expected = [
286            // initializer
287            new Ldai(new Imm(0.0)),
288            new Sta(i),
289            labelPre,
290            // condition
291            new Lda(i),
292            new Sta(lhs),
293            new Ldai(new Imm(5.0)),
294            new Less(new Imm(0), lhs),
295            new Jeqz(labelPost),
296
297            // second for
298            new Ldai(new Imm(0.0)),
299            new Sta(j),
300            labelPre1,
301            // condition
302            new Lda(j),
303            new Sta(lhs),
304            new Ldai(new Imm(6.0)),
305            new Less(new Imm(1), lhs),
306            new Jeqz(labelPost1),
307            new Jmp(labelIncr),
308            labelIncr1,
309            // incrementor
310            new Lda(j),
311            new Sta(j),
312            new Lda(j),
313            new Inc(new Imm(2)),
314            new Sta(j),
315            new Lda(j),
316            new Tonumeric(new Imm(3)),
317            // jump to the loop header
318            new Jmp(labelPre1),
319            labelPost1,
320            labelIncr,
321            // incrementor
322            new Lda(i),
323            new Sta(i),
324            new Lda(i),
325            new Inc(new Imm(4)),
326            new Sta(i),
327            // jump to the loop header
328            new Jmp(labelPre),
329            labelPost,
330            new Returnundefined()
331        ];
332
333        // check the instruction kinds are the same as we expect
334        expect(checkInstructions(insns, expected)).to.be.true;
335        // check break jumps to the expected instruction
336        let jmp = <Jmp>insns[16];
337        let targetLabel = (jmp).getTarget();
338        expect(targetLabel).to.equal(insns[27]);
339    });
340});
341