• 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 { DiagnosticCode, DiagnosticError } from '../../src/diagnostic';
21import {
22    EcmaCallithisrangedyn,
23    EcmaCreateemptyarray,
24    EcmaGetiterator,
25    EcmaIsfalse,
26    EcmaLdobjbyname,
27    EcmaReturnundefined,
28    EcmaStrictnoteqdyn,
29    EcmaThrowdyn,
30    EcmaThrowifnotobject,
31    Imm,
32    Jeqz,
33    Jmp,
34    Label,
35    LdaDyn, ResultType,
36    StaDyn,
37    VReg
38} from "../../src/irnodes";
39import { checkInstructions, compileMainSnippet } from "../utils/base";
40
41describe("ForOfLoopTest", function () {
42    it("forOfLoopWithEmptyArray", function () {
43        let insns = compileMainSnippet("for (let a of []) {}");
44        let a = new VReg();
45        let arrInstance = new VReg();
46        let iterReg = new VReg();
47        let nextMethodReg = new VReg();
48        let resultObj = new VReg();
49        let exceptionVreg = new VReg();
50        let trueReg = new VReg();
51        let done = new VReg();
52        let value = new VReg();
53
54        let loopStartLabel = new Label();
55        let loopEndLabel = new Label();
56        let tryBeginLabel = new Label();
57        let tryEndLabel = new Label();
58        let catchBeginLabel = new Label();
59        let isDone = new Label();
60
61        let expected = [
62            new EcmaCreateemptyarray(),
63            new StaDyn(arrInstance),
64            new EcmaGetiterator(),
65            new StaDyn(iterReg),
66            new EcmaLdobjbyname("next", iterReg),
67            new StaDyn(nextMethodReg),
68
69            new LdaDyn(new VReg()),
70            new StaDyn(done),
71
72            tryBeginLabel,
73            new LdaDyn(trueReg),
74            new StaDyn(done),
75            loopStartLabel,
76            new EcmaCallithisrangedyn(new Imm(1), [nextMethodReg, iterReg]),
77            new StaDyn(resultObj),
78            new EcmaThrowifnotobject(resultObj),
79            new EcmaLdobjbyname("done", resultObj),
80            new EcmaIsfalse(),
81            new Jeqz(loopEndLabel),
82            new EcmaLdobjbyname("value", resultObj),
83            new StaDyn(value),
84
85            new LdaDyn(new VReg()),
86            new StaDyn(done),
87
88            new LdaDyn(value),
89            new StaDyn(a),
90            tryEndLabel,
91
92            new Jmp(loopStartLabel),
93
94            catchBeginLabel,
95            new StaDyn(exceptionVreg),
96            new LdaDyn(done),
97            new EcmaStrictnoteqdyn(trueReg),
98            new Jeqz(isDone),
99            new EcmaLdobjbyname("return", iterReg),
100            new StaDyn(nextMethodReg),
101            new EcmaStrictnoteqdyn(new VReg()),
102            new Jeqz(isDone),
103            new EcmaCallithisrangedyn(new Imm(1), [nextMethodReg, iterReg]),
104            isDone,
105            new LdaDyn(exceptionVreg),
106            new EcmaThrowdyn(),
107
108            loopEndLabel,
109            new EcmaReturnundefined()
110        ];
111        expect(checkInstructions(insns, expected)).to.be.true;
112
113        let jumps = insns.filter(item => (item instanceof Jmp || item instanceof Jeqz));
114
115        expect(jumps.length).to.equal(4);
116    });
117
118    it("forOfLoopWithContinue", function () {
119        let insns = compileMainSnippet("for (let a of []) {continue;}");
120        let a = new VReg();
121        let arrInstance = new VReg();
122        let resultObj = new VReg();
123        let trueReg = new VReg();
124        let iterReg = new VReg();
125        let exceptionVreg = new VReg();
126        let nextMethodReg = new VReg();
127        let done = new VReg();
128        let value = new VReg();
129
130        let loopStartLabel = new Label();
131        let loopEndLabel = new Label();
132        let tryBeginLabel = new Label();
133        let tryEndLabel = new Label();
134        let catchBeginLabel = new Label();
135        let isDone = new Label();
136        let insertedtryBeginLabel = new Label();
137        let insertedtryEndLabel = new Label();
138
139        let expected = [
140            new EcmaCreateemptyarray(),
141            new StaDyn(arrInstance),
142            new EcmaGetiterator(),
143            new StaDyn(iterReg),
144            new EcmaLdobjbyname("next", iterReg),
145            new StaDyn(nextMethodReg),
146
147            new LdaDyn(new VReg()),
148            new StaDyn(done),
149
150            tryBeginLabel,
151            new LdaDyn(trueReg),
152            new StaDyn(done),
153            loopStartLabel,
154            new EcmaCallithisrangedyn(new Imm(1), [nextMethodReg, iterReg]),
155            new StaDyn(resultObj),
156            new EcmaThrowifnotobject(resultObj),
157            new EcmaLdobjbyname("done", resultObj),
158            new EcmaIsfalse(),
159            new Jeqz(loopEndLabel),
160            new EcmaLdobjbyname("value", resultObj),
161            new StaDyn(value),
162
163            new LdaDyn(new VReg()),
164            new StaDyn(done),
165
166            new LdaDyn(value),
167            new StaDyn(a),
168
169            insertedtryBeginLabel,
170            insertedtryEndLabel,
171            new Jmp(loopStartLabel),
172
173            tryEndLabel,
174
175            new Jmp(loopStartLabel),
176
177            catchBeginLabel,
178            new StaDyn(exceptionVreg),
179            new LdaDyn(done),
180            new EcmaStrictnoteqdyn(trueReg),
181            new Jeqz(isDone),
182            new EcmaLdobjbyname("return", iterReg),
183            new StaDyn(nextMethodReg),
184            new EcmaStrictnoteqdyn(new VReg()),
185            new Jeqz(isDone),
186            new EcmaCallithisrangedyn(new Imm(1), [nextMethodReg, iterReg]),
187            isDone,
188            new LdaDyn(exceptionVreg),
189            new EcmaThrowdyn(),
190
191            loopEndLabel,
192            new EcmaReturnundefined()
193        ];
194        expect(checkInstructions(insns, expected)).to.be.true;
195
196        let jumps = insns.filter(item => (item instanceof Jmp || item instanceof Jeqz));
197
198        expect(jumps.length).to.equal(5);
199    });
200
201    it("forOfLoopWithBreak", function () {
202        let insns = compileMainSnippet("for (let a of []) {break;}");
203        let a = new VReg();
204        let arrInstance = new VReg();
205        let resultObj = new VReg();
206        let exceptionVreg = new VReg();
207        let iterReg = new VReg();
208        let trueReg = new VReg();
209        let nextMethodReg = new VReg();
210        let done = new VReg();
211        let value = new VReg();
212        let loopStartLabel = new Label();
213        let loopEndLabel = new Label();
214        let tryBeginLabel = new Label();
215        let tryEndLabel = new Label();
216        let catchBeginLabel = new Label();
217        let isDone = new Label();
218        let noReturn = new Label();
219        let insertedtryBeginLabel = new Label();
220        let insertedtryEndLabel = new Label();
221
222        let expected = [
223            new EcmaCreateemptyarray(),
224            new StaDyn(arrInstance),
225            new EcmaGetiterator(),
226            new StaDyn(iterReg),
227            new EcmaLdobjbyname("next", iterReg),
228            new StaDyn(nextMethodReg),
229
230            new LdaDyn(new VReg()),
231            new StaDyn(done),
232
233            tryBeginLabel,
234            new LdaDyn(trueReg),
235            new StaDyn(done),
236            loopStartLabel,
237            new EcmaCallithisrangedyn(new Imm(1), [nextMethodReg, iterReg]),
238            new StaDyn(resultObj),
239            new EcmaThrowifnotobject(resultObj),
240            new EcmaLdobjbyname("done", resultObj),
241            new EcmaIsfalse(),
242            new Jeqz(loopEndLabel),
243            new EcmaLdobjbyname("value", resultObj),
244            new StaDyn(value),
245
246            new LdaDyn(new VReg()),
247            new StaDyn(done),
248
249            new LdaDyn(value),
250            new StaDyn(a),
251
252            insertedtryBeginLabel,
253            new EcmaLdobjbyname("return", iterReg),
254            new StaDyn(nextMethodReg),
255            new EcmaStrictnoteqdyn(new VReg()), // undefined
256            new Jeqz(noReturn),
257            new EcmaCallithisrangedyn(new Imm(1), [nextMethodReg, iterReg]),
258            new StaDyn(new VReg()),
259            new EcmaThrowifnotobject(new VReg()),
260            noReturn,
261            insertedtryEndLabel,
262            new Jmp(loopEndLabel),
263
264            tryEndLabel,
265
266            new Jmp(loopStartLabel),
267
268            catchBeginLabel,
269            new StaDyn(exceptionVreg),
270            new LdaDyn(done),
271            new EcmaStrictnoteqdyn(trueReg),
272            new Jeqz(isDone),
273            new EcmaLdobjbyname("return", iterReg),
274            new StaDyn(nextMethodReg),
275            new EcmaStrictnoteqdyn(new VReg()),
276            new Jeqz(isDone),
277            new EcmaCallithisrangedyn(new Imm(1), [nextMethodReg, iterReg]),
278            isDone,
279            new LdaDyn(exceptionVreg),
280            new EcmaThrowdyn(),
281
282            loopEndLabel,
283            new EcmaReturnundefined()
284        ];
285
286        expect(checkInstructions(insns, expected)).to.be.true;
287
288        let jumps = insns.filter(item => (item instanceof Jmp || item instanceof Jeqz));
289
290        expect(jumps.length).to.equal(6);
291    });
292
293    it("ForOf SyntaxError", function () {
294        let source: string = `for ([(x, y)] of []) {}`;
295        let errorThrown = false;
296        try {
297            compileMainSnippet(source);
298        } catch (err) {
299            expect(err instanceof DiagnosticError).to.be.true;
300            expect((<DiagnosticError>err).code).to.equal(DiagnosticCode.Property_destructuring_pattern_expected);
301            errorThrown = true;
302        }
303        expect(errorThrown).to.be.true;
304    });
305});
306