• 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    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