• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2022 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 { expect } from 'chai';
17import { DiagnosticCode, DiagnosticError } from '../../src/diagnostic';
18import { creatAstFromSnippet } from "../utils/asthelper"
19import { PandaGen } from '../../src/pandagen';
20import {
21    Add2,
22    Asyncfunctionawaituncaught,
23    Asyncfunctionenter,
24    Asyncfunctionreject,
25    Asyncfunctionresolve,
26    Callarg0,
27    Creategeneratorobj,
28    Createiterresultobj,
29    Definefunc,
30    Eq,
31    Getresumemode,
32    Resumegenerator,
33    Returnundefined,
34    Suspendgenerator,
35    Throw,
36    Ldfunction,
37    Imm,
38    Jeqz,
39    Label,
40    Lda,
41    Ldai,
42    Return,
43    Sta,
44    VReg,
45    IRNode
46} from "../../src/irnodes";
47import { CacheExpander } from '../../src/pass/cacheExpander';
48import { checkInstructions, compileAllSnippet } from "../utils/base";
49
50describe("compileFunctionExpression", function () {
51    it("FunctionExpression with name", function () {
52        let source: string = `
53        var a = function test() {
54            test();
55        }`;
56        let passes = [new CacheExpander()];
57        let pandaGens = compileAllSnippet(source, passes);
58        IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined);
59
60        let expected_func = [
61            new Ldfunction(),
62            new Sta(new VReg()),
63            new Lda(new VReg()),
64            new Sta(new VReg()),
65            new Lda(new VReg()),
66            new Sta(new VReg()),
67            new Lda(new VReg()),
68            new Callarg0(new Imm(0)),
69            new Returnundefined()
70        ];
71
72        let checkCount = 0;
73        pandaGens.forEach((pg) => {
74            if (pg.internalName == "UnitTest.test") {
75                expect(checkInstructions(pg.getInsns(), expected_func), "check func insns").to.be.true;
76                checkCount++;
77            }
78        });
79
80        expect(checkCount).to.equals(1);
81    });
82
83    it("FunctionExpression without name", function () {
84        let source: string = `
85        var a = function () {
86        }`;
87
88        let pandaGens = compileAllSnippet(source);
89
90        let checkCount = 0;
91        pandaGens.forEach((pg) => {
92            if (pg.internalName == "UnitTest.a") {
93                checkCount++;
94            }
95
96            if (pg.internalName == "UnitTest.func_main_0") {
97
98                pg.getInsns().forEach((insns) => {
99                    if (insns instanceof Definefunc) {
100                        expect(insns.operands[1]).to.equal('UnitTest.a');
101                        checkCount++;
102                    }
103                });
104            }
105        });
106
107        expect(checkCount).to.equals(2);
108    });
109
110    it("FunctionExpression without name in binary expression", function () {
111        let source: string = `
112        var a;
113        a = function () {
114        }`;
115
116        let pandaGens = compileAllSnippet(source);
117
118        let checkCount = 0;
119        pandaGens.forEach((pg) => {
120            if (pg.internalName == "UnitTest.a") {
121                checkCount++;
122            }
123
124            if (pg.internalName == "UnitTest.func_main_0") {
125
126                pg.getInsns().forEach((insns) => {
127                    if (insns instanceof Definefunc) {
128                        expect(insns.operands[1]).to.equal('UnitTest.a');
129                        checkCount++;
130                    }
131                });
132            }
133        });
134
135        expect(checkCount).to.equals(2);
136    });
137
138
139    it("ArrowFunction", function () {
140        let source: string = `
141        var a = ()=> {
142        }`;
143        IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined);
144
145        let pandaGens = compileAllSnippet(source);
146        let checkCount = 0;
147
148        pandaGens.forEach((pg) => {
149            if (pg.internalName == "UnitTest.a") {
150                checkCount++;
151            }
152
153            if (pg.internalName == "UnitTest.func_main_0") {
154
155                pg.getInsns().forEach((insns) => {
156                    if (insns instanceof Definefunc) {
157                        expect(insns.operands[1]).to.equal('UnitTest.a');
158                        checkCount++;
159                    }
160                });
161            }
162        });
163
164        expect(checkCount).to.equals(2);
165    });
166
167    it("ArrowFunctionWithExpression", function () {
168        let source: string = `
169        var p = (x, y) => x + y;`;
170
171        let pandaGens = compileAllSnippet(source);
172        let checkCount = 0;
173        IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined);
174
175        let expected_func = [
176            new Lda(new VReg()),
177            new Sta(new VReg()),
178            new Lda(new VReg()),
179            new Add2(new Imm(0), new VReg()),
180            new Sta(new VReg()),
181            new Lda(new VReg()),
182            new Return()
183        ];
184
185        pandaGens.forEach((pg) => {
186            if (pg.internalName == "UnitTest.p") {
187                expect(checkInstructions(pg.getInsns(), expected_func), "check arrow func insns").to.be.true;
188                checkCount++;
189            }
190
191            if (pg.internalName == "UnitTest.func_main_0") {
192
193                pg.getInsns().forEach((insns) => {
194                    if (insns instanceof Definefunc) {
195                        expect(insns.operands[1]).to.equal('UnitTest.p');
196                        checkCount++;
197                    }
198                });
199            }
200        });
201
202        expect(checkCount).to.equals(2);
203    });
204
205    it("ArrowFunctionSyntaxError", function () {
206        let source: string = `
207            var af = x
208                => {};`;
209        let errorThrown = false;
210        try {
211            compileAllSnippet(source);
212        } catch (err) {
213            expect(err instanceof DiagnosticError).to.be.true;
214            expect((<DiagnosticError>err).code).to.equal(DiagnosticCode.Line_terminator_not_permitted_before_arrow);
215            errorThrown = true;
216        }
217        expect(errorThrown).to.be.true;
218    });
219
220    it("GeneratorFunction", function () {
221        let source: string = `
222            function* a() {
223                yield 1;
224            }`;
225
226        IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined);
227        let notRetLabel0 = new Label();
228        let notThrowLabel0 = new Label();
229        let notRetLabel1 = new Label();
230        let notThrowLabel1 = new Label();
231
232        let expected_func = [
233            new Creategeneratorobj(new VReg()),
234            new Sta(new VReg()),
235            new Lda(new VReg()),
236            new Suspendgenerator(new VReg()),
237            new Lda(new VReg()),
238            new Resumegenerator(),
239            new Sta(new VReg()),
240            new Lda(new VReg()),
241            new Getresumemode(),
242            new Sta(new VReg()),
243
244            new Ldai(new Imm(0)),
245            new Eq(new Imm(0), new VReg()),
246            new Jeqz(notRetLabel0),
247            new Lda(new VReg()),
248            new Return(),
249
250            notRetLabel0,
251            new Ldai(new Imm(1)),
252            new Eq(new Imm(1), new VReg()),
253            new Jeqz(notThrowLabel0),
254            new Lda(new VReg()),
255            new Throw(),
256
257            notThrowLabel0,
258            new Lda(new VReg()),
259            new Ldai(new Imm(1)),
260            new Sta(new VReg()),
261            new Createiterresultobj(new VReg(), new VReg()),
262            new Suspendgenerator(new VReg()),
263            new Lda(new VReg()),
264            new Resumegenerator(),
265            new Sta(new VReg()),
266            new Lda(new VReg()),
267            new Getresumemode(),
268            new Sta(new VReg()),
269
270            new Ldai(new Imm(0)),
271            new Eq(new Imm(2), new VReg()),
272            new Jeqz(notRetLabel1),
273            new Lda(new VReg()),
274            new Return(),
275
276            notRetLabel1,
277            new Ldai(new Imm(1)),
278            new Eq(new Imm(3), new VReg()),
279            new Jeqz(notThrowLabel1),
280            new Lda(new VReg()),
281            new Throw(),
282
283            notThrowLabel1,
284            new Lda(new VReg()),
285            new Returnundefined()
286        ];
287
288        let pandaGens = compileAllSnippet(source);
289        let checkCount = 0;
290
291        pandaGens.forEach((pg) => {
292            if (pg.internalName == "UnitTest.a") {
293                expect(checkInstructions(pg.getInsns(), expected_func), "check generator func insns").to.be.true;
294                checkCount++;
295            }
296
297            if (pg.internalName == "UnitTest.func_main_0") {
298                pg.getInsns().forEach((insns) => {
299                    if (insns instanceof Definefunc) {
300                        expect(insns.operands[1]).to.equal('UnitTest.a');
301                        checkCount++;
302                    }
303                });
304            }
305        });
306
307        expect(checkCount).to.equals(2);
308    });
309
310    it("AsyncFunction", function () {
311        let source: string = `
312            async function a() {
313                await 1;
314            }`;
315
316        IRNode.pg = new PandaGen("", creatAstFromSnippet(``), 0, undefined);
317        let beginLabel = new Label();
318        let endLabel = new Label();
319        let nextLabel = new Label();
320
321        let expected_func = [
322            new Asyncfunctionenter(),
323            new Sta(new VReg()),
324            beginLabel,
325            new Ldai(new Imm(1)),
326            new Asyncfunctionawaituncaught(new VReg()),
327            new Suspendgenerator(new VReg()),
328            new Lda(new VReg()),
329            new Resumegenerator(),
330            new Sta(new VReg()),
331            new Lda(new VReg()),
332            new Getresumemode(),
333            new Sta(new VReg()),
334            new Ldai(new Imm(1)),
335            new Eq(new Imm(0), new VReg()),
336            new Jeqz(nextLabel),
337            new Lda(new VReg()),
338            new Throw(),
339            nextLabel,
340            new Lda(new VReg()),
341            new Lda(new VReg()),
342            new Asyncfunctionresolve(new VReg()),
343            new Return(),
344            endLabel,
345            new Asyncfunctionreject(new VReg()),
346            new Return(),
347        ];
348
349        let pandaGens = compileAllSnippet(source);
350        let checkCount = 0;
351
352        pandaGens.forEach((pg) => {
353            if (pg.internalName == "UnitTest.a") {
354                pg.getInsns().forEach(ins => {
355                    console.log(ins.toString());
356                })
357                expect(checkInstructions(pg.getInsns(), expected_func), "check async func insns").to.be.true;
358                checkCount++;
359            }
360
361            if (pg.internalName == "UnitTest.func_main_0") {
362                pg.getInsns().forEach((insns) => {
363                    if (insns instanceof Definefunc) {
364                        expect(insns.operands[1]).to.equal('UnitTest.a');
365                        checkCount++;
366                    }
367                });
368            }
369        });
370
371        expect(checkCount).to.equals(2);
372    });
373
374    it("FunctionWithRestParameterSyntaxError", function () {
375        let source: string = `function func(...a,)`;
376        let errorThrown = false;
377        try {
378            compileAllSnippet(source);
379        } catch (err) {
380            expect(err instanceof DiagnosticError).to.be.true;
381            expect((<DiagnosticError>err).code).to.equal(DiagnosticCode.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma);
382            errorThrown = true;
383        }
384        expect(errorThrown).to.be.true;
385    });
386})
387