• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 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 {
17    expect
18} from 'chai';
19import 'mocha';
20import {
21    Definefunc,
22    Istrue,
23    Returnundefined,
24    Stglobalvar,
25    ThrowUndefinedifhole,
26    Imm,
27    Jeqz,
28    Label,
29    Lda,
30    Ldai,
31    LdaStr,
32    Sta,
33    VReg,
34    IRNode
35} from "../src/irnodes";
36import { checkInstructions, compileMainSnippet, SnippetCompiler } from "./utils/base";
37import { creatAstFromSnippet } from "./utils/asthelper";
38import { PandaGen } from '../src/pandagen';
39
40describe("HoistTest", function () {
41
42    // case 1: hoist var declared variable ((declared in global scope)) in global scope
43    it('case 1;', function () {
44        let insns = compileMainSnippet("var a = 1;");
45        IRNode.pg = new PandaGen("foo", creatAstFromSnippet("var a = 1;"), 0, undefined);
46        let expected = [
47            new Lda(new VReg()),
48            new Stglobalvar(new Imm(0), "a"),
49            new Ldai(new Imm(1)),
50            new Stglobalvar(new Imm(1), "a"),
51            new Returnundefined()
52        ]
53
54        expect(checkInstructions(insns, expected)).to.be.true;
55    });
56
57    // case 2: hoist var declared variable (declared in local scope) in global scope
58    it('case 2', function () {
59        let insns = compileMainSnippet(`if (true) {
60                                  var a = 2;
61                                }`);
62        IRNode.pg = new PandaGen("foo", creatAstFromSnippet(`if (true) {
63            var a = 2;
64          }`), 0, undefined);
65        let endLabel = new Label();
66
67        let expected = [
68            new Lda(new VReg()),
69            new Stglobalvar(new Imm(0), "a"),
70            new Lda(new VReg()),
71            new Istrue(),
72            new Jeqz(endLabel),
73            new Ldai(new Imm(2)),
74            new Stglobalvar(new Imm(1), "a"),
75            endLabel,
76            new Returnundefined()
77        ]
78        expect(checkInstructions(insns, expected)).to.be.true;
79    });
80
81    // case 3: hoist function declaration in global scope
82    it('case 3', function () {
83        let snippetCompiler = new SnippetCompiler();
84        snippetCompiler.compile(`function a() {};`);
85        IRNode.pg = new PandaGen("foo", creatAstFromSnippet(`function a() {};`), 0, undefined);
86
87        let insns = snippetCompiler.getGlobalInsns();
88        let expected = [
89            new Definefunc(new Imm(0), "UnitTest.a", new Imm(0)),
90            new Stglobalvar(new Imm(1), "a"),
91            new Returnundefined()
92        ]
93        expect(checkInstructions(insns, expected)).to.be.true;
94    });
95
96    // case 4: In case that two function declared directly in global scope with the same name, hoist the later one.
97    it('case 4', function () {
98        let snippetCompiler = new SnippetCompiler();
99        snippetCompiler.compile(`function a() {}; function a() {}`);
100        IRNode.pg = new PandaGen("foo", creatAstFromSnippet(`function a() {}; function a() {}`), 0, undefined);
101
102        let insns = snippetCompiler.getGlobalInsns();
103        let expected = [
104            new Definefunc(new Imm(0), "UnitTest.#2#a", new Imm(0)),
105            new Stglobalvar(new Imm(1), "a"),
106            new Returnundefined()
107        ]
108
109        expect(checkInstructions(insns, expected)).to.be.true;
110    });
111
112    // case 5: hoisting of function declaration is of higher priority than var declared variables with a same name in global scope
113    it('case 5', function () {
114        let snippetCompiler = new SnippetCompiler();
115        snippetCompiler.compile(`var a = 1; function a() {}`);
116        IRNode.pg = new PandaGen("foo", creatAstFromSnippet(`var a = 1; function a() {}`), 0, undefined);
117
118        let insns = snippetCompiler.getGlobalInsns();
119        let expected = [
120            new Definefunc(new Imm(0), "UnitTest.a", new Imm(0)),
121            new Stglobalvar(new Imm(1), "a"),
122            new Ldai(new Imm(1)),
123            new Stglobalvar(new Imm(2), "a"),
124            new Returnundefined()
125        ]
126
127        expect(checkInstructions(insns, expected)).to.be.true;
128    });
129
130    // case 6: hoist var declared variable in function scope
131    it('case 6', function () {
132        let snippetCompiler = new SnippetCompiler();
133        snippetCompiler.compile(`function a() {var a = 1;}`);
134        IRNode.pg = new PandaGen("foo", creatAstFromSnippet(`function a() {var a = 1;}`), 0, undefined);
135        let funcPg = snippetCompiler.getPandaGenByName("UnitTest.a");
136        let insns = funcPg!.getInsns();
137
138        let a = new VReg();
139        let expected = [
140            new Lda(a),
141            new Sta(new VReg()),
142            new Ldai(new Imm(1)),
143            new Sta(a),
144
145            new Returnundefined()
146        ]
147        expect(checkInstructions(insns!, expected)).to.be.true;
148    });
149
150    // case 7: hoist function declaration in function scope
151    it('case 7', function () {
152        let snippetCompiler = new SnippetCompiler();
153        snippetCompiler.compile(`function a() {function b() {}};`);
154        IRNode.pg = new PandaGen("foo", creatAstFromSnippet(`function a() {function b() {}};`), 0, undefined);
155        let funcPg = snippetCompiler.getPandaGenByName("UnitTest.a");
156        let insns = funcPg!.getInsns();
157        let a = new VReg();
158        let expected = [
159            new Definefunc(new Imm(0), "UnitTest.b", new Imm(0)),
160            new Sta(a),
161
162            new Returnundefined()
163        ]
164
165        expect(checkInstructions(insns!, expected)).to.be.true;
166    });
167
168    // case 8: temporary dead zone of let in global scope
169    it('case 8', function () {
170        let snippetCompiler = new SnippetCompiler();
171        snippetCompiler.compile(`a = 1;
172                                 let a;`);
173        let funcPg = snippetCompiler.getPandaGenByName("UnitTest.func_main_0");
174        let insns = funcPg!.getInsns();
175        let idReg = new VReg();
176        let expected = [
177            new LdaStr("a"),
178            new Sta(idReg),
179            new ThrowUndefinedifhole(new VReg(), idReg)
180        ]
181
182        expect(checkInstructions(insns.slice(3, 5), expected));
183    });
184
185    // case 9: temporary dead zone of let in function scope
186    it('case 9', function () {
187        let snippetCompiler = new SnippetCompiler();
188        snippetCompiler.compile(`function b() {
189                                 a = 1;
190                                 let a;
191                                 }`);
192        let funcPg = snippetCompiler.getPandaGenByName("UnitTest.b");
193        let insns = funcPg!.getInsns();
194        let idReg = new VReg();
195
196        let expected = [
197            new LdaStr("a"),
198            new Sta(idReg),
199            new ThrowUndefinedifhole(new VReg(), idReg)
200        ]
201
202        expect(checkInstructions(insns.slice(3, 5), expected));
203    });
204
205    // case 10: temporary dead zone of let in local scope
206    it('case 10', function () {
207        let snippetCompiler = new SnippetCompiler();
208        snippetCompiler.compile(`{
209                                    a = 1;
210                                    let a;
211                                 }`);
212        let funcPg = snippetCompiler.getPandaGenByName("UnitTest.func_main_0");
213        let insns = funcPg!.getInsns();
214        let idReg = new VReg();
215
216        let expected = [
217            new LdaStr("a"),
218            new Sta(idReg),
219            new ThrowUndefinedifhole(new VReg(), idReg)
220        ]
221
222        expect(checkInstructions(insns.slice(3, 5), expected));
223    })
224})
225