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