mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-09 09:34:57 +09:00
Everywhere: Hoist the Libraries folder to the top-level
This commit is contained in:
parent
950e819ee7
commit
93712b24bf
Notes:
github-actions[bot]
2024-11-10 11:51:52 +00:00
Author: https://github.com/trflynn89
Commit: 93712b24bf
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2256
Reviewed-by: https://github.com/sideshowbarker
4547 changed files with 104 additions and 113 deletions
294
Libraries/LibJS/Tests/syntax/async-await.js
Normal file
294
Libraries/LibJS/Tests/syntax/async-await.js
Normal file
|
@ -0,0 +1,294 @@
|
|||
describe("parsing freestanding async functions", () => {
|
||||
test("simple", () => {
|
||||
expect(`async function foo() {}`).toEval();
|
||||
// Although it does not create an async function it is valid.
|
||||
expect(`async
|
||||
function foo() {}`).toEval();
|
||||
|
||||
expect(`async function await() {}`).toEval();
|
||||
expect(`async function yield() {}`).toEval();
|
||||
});
|
||||
test("await expression", () => {
|
||||
expect(`async function foo() { await bar(); }`).toEval();
|
||||
expect(`async function foo() { await; }`).not.toEval();
|
||||
expect(`function foo() { await bar(); }`).not.toEval();
|
||||
expect(`function foo() { await; }`).toEval();
|
||||
|
||||
expect(`\\u0061sync function foo() { await bar(); }`).not.toEval();
|
||||
expect(`\\u0061sync function foo() { \\u0061wait bar(); }`).not.toEval();
|
||||
expect(`async function foo() { \\u0061wait bar(); }`).not.toEval();
|
||||
});
|
||||
});
|
||||
|
||||
describe("parsing object literal async functions", () => {
|
||||
test("simple", () => {
|
||||
expect(`x = { async foo() { } }`).toEval();
|
||||
expect(`x = { async
|
||||
foo() { } }`).not.toEval();
|
||||
});
|
||||
|
||||
test("property on object called async", () => {
|
||||
expect(`x = { async() { } }`).toEval();
|
||||
expect(`x = { async() { await 4; } }`).not.toEval();
|
||||
expect(`x = { async: 3 }`).toEval();
|
||||
expect(`x = { async: await 3, }`).not.toEval();
|
||||
});
|
||||
|
||||
test("await expression", () => {
|
||||
expect(`x = { foo() { await bar(); } }`).not.toEval();
|
||||
expect(`x = { foo() { await; } }`).toEval();
|
||||
expect(`x = { async foo() { await bar(); } }`).toEval();
|
||||
expect(`x = { async foo() { await; } }`).not.toEval();
|
||||
});
|
||||
});
|
||||
|
||||
describe("parsing classes with async methods", () => {
|
||||
test("simple", () => {
|
||||
expect(`class Foo { async foo() {} }`).toEval();
|
||||
expect(`class Foo { static async foo() {} }`).toEval();
|
||||
expect(`class Foo { async foo() { await bar(); } }`).toEval();
|
||||
expect(`class Foo { async foo() { await; } }`).not.toEval();
|
||||
expect(`class Foo { async constructor() {} }`).not.toEval();
|
||||
});
|
||||
});
|
||||
|
||||
test("function expression names equal to 'await'", () => {
|
||||
expect(`async function foo() { (function await() {}); }`).toEval();
|
||||
expect(`async function foo() { function await() {} }`).not.toEval();
|
||||
});
|
||||
|
||||
test("async function cannot use await in default parameters", () => {
|
||||
expect("async function foo(x = await 3) {}").not.toEval();
|
||||
expect("async function foo(x = await 3) {}").not.toEval();
|
||||
|
||||
// Even as a reference to some variable it is not allowed
|
||||
expect(`
|
||||
var await = 4;
|
||||
async function foo(x = await) {}
|
||||
`).not.toEval();
|
||||
});
|
||||
|
||||
describe("async arrow functions", () => {
|
||||
test("basic syntax", () => {
|
||||
expect("async () => await 3;").toEval();
|
||||
expect("async param => await param();").toEval();
|
||||
expect("async (param) => await param();").toEval();
|
||||
expect("async (a, b) => await a();").toEval();
|
||||
|
||||
expect("async () => { await 3; }").toEval();
|
||||
expect("async param => { await param(); }").toEval();
|
||||
expect("async (param) => { await param(); }").toEval();
|
||||
expect("async (a, b) => { await a(); }").toEval();
|
||||
|
||||
expect(`async
|
||||
() => await 3;`).not.toEval();
|
||||
|
||||
expect("async async => await async()").toEval();
|
||||
expect("async => async").toEval();
|
||||
expect("async => await async()").not.toEval();
|
||||
|
||||
expect("async (b = await) => await b;").not.toEval();
|
||||
expect("async (b = await 3) => await b;").not.toEval();
|
||||
|
||||
// Cannot escape the async keyword and get an async arrow function.
|
||||
expect("\\u0061sync () => await 3").not.toEval();
|
||||
|
||||
expect("for (async of => {};false;) {}").toEval();
|
||||
expect("for (async of []) {}").not.toEval();
|
||||
|
||||
expect("for (\\u0061sync of []) {}").toEval();
|
||||
expect("for (\\u0061sync of => {};false;) {}").not.toEval();
|
||||
expect("for (\\u0061sync => {};false;) {}").toEval();
|
||||
});
|
||||
|
||||
test("async within a for-loop", () => {
|
||||
let called = false;
|
||||
// Unfortunately we cannot really test the more horrible case above.
|
||||
for (
|
||||
const f = async of => {
|
||||
return of;
|
||||
};
|
||||
;
|
||||
|
||||
) {
|
||||
expect(f(43)).toBeInstanceOf(Promise);
|
||||
|
||||
called = true;
|
||||
break;
|
||||
}
|
||||
expect(called).toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
test("basic functionality", () => {
|
||||
test("simple", () => {
|
||||
let executionValue = null;
|
||||
let resultValue = null;
|
||||
async function foo() {
|
||||
executionValue = "someValue";
|
||||
return "otherValue";
|
||||
}
|
||||
const returnValue = foo();
|
||||
expect(returnValue).toBeInstanceOf(Promise);
|
||||
returnValue.then(result => {
|
||||
resultValue = result;
|
||||
});
|
||||
runQueuedPromiseJobs();
|
||||
expect(executionValue).toBe("someValue");
|
||||
expect(resultValue).toBe("otherValue");
|
||||
});
|
||||
|
||||
test("await", () => {
|
||||
let resultValue = null;
|
||||
async function foo() {
|
||||
return "someValue";
|
||||
}
|
||||
async function bar() {
|
||||
resultValue = await foo();
|
||||
}
|
||||
bar();
|
||||
runQueuedPromiseJobs();
|
||||
expect(resultValue).toBe("someValue");
|
||||
});
|
||||
});
|
||||
|
||||
describe("non async function declaration usage of async still works", () => {
|
||||
test("async as a function", () => {
|
||||
function async(value = 4) {
|
||||
return value;
|
||||
}
|
||||
|
||||
expect(async(0)).toBe(0);
|
||||
|
||||
// We use eval here since it otherwise cannot find the async function.
|
||||
const evalResult = eval("async(1)");
|
||||
expect(evalResult).toBe(1);
|
||||
});
|
||||
|
||||
test("async as a variable", () => {
|
||||
let async = 3;
|
||||
|
||||
const evalResult = eval("async >= 2");
|
||||
expect(evalResult).toBeTrue();
|
||||
});
|
||||
|
||||
test("async with line ending does not create a function", () => {
|
||||
expect(() => {
|
||||
// The ignore is needed otherwise prettier puts a ';' after async.
|
||||
// prettier-ignore
|
||||
async
|
||||
function f() {}
|
||||
}).toThrowWithMessage(ReferenceError, "'async' is not defined");
|
||||
|
||||
expect(`async
|
||||
function f() { await 3; }`).not.toEval();
|
||||
});
|
||||
});
|
||||
|
||||
describe("await cannot be used in class static init blocks", () => {
|
||||
test("directly", () => {
|
||||
expect("class A{ static { await; } }").not.toEval();
|
||||
expect("class A{ static { let await = 3; } }").not.toEval();
|
||||
expect("class A{ static { call(await); } }").not.toEval();
|
||||
expect("class A{ static { for(const await = 1; false ;) {} } }").not.toEval();
|
||||
});
|
||||
|
||||
test("via declaration", () => {
|
||||
expect("class A{ static { class await {} } }").not.toEval();
|
||||
expect("class A{ static { function await() {} } }").not.toEval();
|
||||
expect("class A{ static { function* await() {} } }").not.toEval();
|
||||
expect("class A{ static { async function* await() {} } }").not.toEval();
|
||||
});
|
||||
});
|
||||
|
||||
describe("await thenables", () => {
|
||||
test("async returning a thanable variable without fulfilling", () => {
|
||||
let isCalled = false;
|
||||
const obj = {
|
||||
then() {
|
||||
isCalled = true;
|
||||
},
|
||||
};
|
||||
|
||||
const f = async () => await obj;
|
||||
f();
|
||||
runQueuedPromiseJobs();
|
||||
expect(isCalled).toBe(true);
|
||||
});
|
||||
|
||||
test("async returning a thanable variable that fulfills", () => {
|
||||
let isCalled = false;
|
||||
const obj = {
|
||||
then(fulfill) {
|
||||
isCalled = true;
|
||||
fulfill(isCalled);
|
||||
},
|
||||
};
|
||||
|
||||
const f = async () => await obj;
|
||||
f();
|
||||
runQueuedPromiseJobs();
|
||||
expect(isCalled).toBe(true);
|
||||
});
|
||||
|
||||
test("async returning a thenable directly without fulfilling", () => {
|
||||
let isCalled = false;
|
||||
const f = async () => ({
|
||||
then() {
|
||||
isCalled = true;
|
||||
},
|
||||
});
|
||||
f();
|
||||
runQueuedPromiseJobs();
|
||||
expect(isCalled).toBe(true);
|
||||
});
|
||||
|
||||
test("async returning a thenable directly that fulfills", () => {
|
||||
let isCalled = false;
|
||||
const f = async () => ({
|
||||
then(fulfill) {
|
||||
isCalled = true;
|
||||
fulfill(isCalled);
|
||||
},
|
||||
});
|
||||
f();
|
||||
runQueuedPromiseJobs();
|
||||
expect(isCalled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("await observably looks up constructor of Promise objects", () => {
|
||||
let calls = 0;
|
||||
function makeConstructorObservable(promise) {
|
||||
Object.defineProperty(promise, "constructor", {
|
||||
get() {
|
||||
calls++;
|
||||
return Promise;
|
||||
},
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
|
||||
async function test() {
|
||||
await makeConstructorObservable(Promise.resolve(1));
|
||||
await makeConstructorObservable(
|
||||
new Promise(resolve => {
|
||||
resolve();
|
||||
})
|
||||
);
|
||||
await makeConstructorObservable(new Boolean(true));
|
||||
await makeConstructorObservable({});
|
||||
await makeConstructorObservable(new Number(2));
|
||||
try {
|
||||
await makeConstructorObservable(Promise.reject(3));
|
||||
} catch {}
|
||||
try {
|
||||
return makeConstructorObservable(Promise.reject(1));
|
||||
} catch {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
test();
|
||||
runQueuedPromiseJobs();
|
||||
expect(calls).toBe(4);
|
||||
});
|
58
Libraries/LibJS/Tests/syntax/async-generators.js
Normal file
58
Libraries/LibJS/Tests/syntax/async-generators.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
describe("parsing freestanding generators", () => {
|
||||
test("simple", () => {
|
||||
expect(`async function* foo() {}`).toEval();
|
||||
expect(`async function *foo() {}`).toEval();
|
||||
expect(`async function
|
||||
*foo() {}`).toEval();
|
||||
|
||||
expect(`async function *await() {}`).not.toEval();
|
||||
expect(`async function *yield() {}`).not.toEval();
|
||||
});
|
||||
test("yield & await expression", () => {
|
||||
expect(`async function* foo() { yield; await 1; }`).toEval();
|
||||
expect(`async function* foo() { yield (yield); await (yield); }`).toEval();
|
||||
expect(`async function* foo() { yield (yield foo); yield (await foo); }`).toEval();
|
||||
|
||||
expect(`async function foo() { yield; }`).toEval();
|
||||
expect(`async function foo() { yield 3; }`).not.toEval();
|
||||
expect(`function* foo() { await 3; }`).not.toEval();
|
||||
});
|
||||
test("yield-from expression", () => {
|
||||
expect(`async function* foo() { yield *bar; }`).toEval();
|
||||
expect(`async function* foo() { yield *(yield); }`).toEval();
|
||||
expect(`async function* foo() { yield
|
||||
*bar; }`).not.toEval();
|
||||
expect(`async function foo() { yield
|
||||
*bar; }`).toEval();
|
||||
});
|
||||
});
|
||||
|
||||
describe("parsing object literal generator functions", () => {
|
||||
test("simple", () => {
|
||||
expect(`x = { async *foo() { } }`).toEval();
|
||||
expect(`x = { async * foo() { } }`).toEval();
|
||||
expect(`x = { async *
|
||||
foo() { } }`).toEval();
|
||||
});
|
||||
test("yield & await", () => {
|
||||
expect(`x = { async foo() { yield; await 3;} }`).toEval();
|
||||
expect(`x = { async *foo() { yield; await 3; } }`).toEval();
|
||||
expect(`x = { async *foo() { yield 42; await 3; } }`).toEval();
|
||||
expect(`x = { async *foo() { yield (yield); await (yield); } }`).toEval();
|
||||
expect(`x = { async *
|
||||
foo() { yield (yield); await 4; } }`).toEval();
|
||||
|
||||
expect(`x = { async foo() { yield 42; } }`).not.toEval();
|
||||
expect(`x = { *foo() { await 42; } }`).not.toEval();
|
||||
});
|
||||
});
|
||||
|
||||
describe("parsing classes with generator methods", () => {
|
||||
test("simple", () => {
|
||||
expect(`class Foo { async *foo() {} }`).toEval();
|
||||
expect(`class Foo { static async *foo() {} }`).toEval();
|
||||
expect(`class Foo { async *foo() { yield; } }`).toEval();
|
||||
expect(`class Foo { async *foo() { yield 42; } }`).toEval();
|
||||
expect(`class Foo { async *constructor() { yield 42; } }`).not.toEval();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,41 @@
|
|||
test("mixing coalescing and logical operators isn't allowed", () => {
|
||||
expect("if (0) a ?? b || c").not.toEval();
|
||||
expect("if (0) a ?? b && c").not.toEval();
|
||||
expect("if (0) a ?? b * c || d").not.toEval();
|
||||
expect("if (0) a ?? b * c && d").not.toEval();
|
||||
expect("if (0) a && b ?? c").not.toEval();
|
||||
expect("if (0) a || b ?? c").not.toEval();
|
||||
expect("if (0) a && b * c ?? d").not.toEval();
|
||||
expect("if (0) a || b * c ?? d").not.toEval();
|
||||
});
|
||||
|
||||
test("mixing coalescing and logical operators with parens", () => {
|
||||
expect("if (0) a ?? (b || c)").toEval();
|
||||
expect("if (0) (a ?? b) && c").toEval();
|
||||
expect("if (0) a ?? (b * c || d)").toEval();
|
||||
expect("if (0) (a ?? b * c) && d").toEval();
|
||||
expect("if (0) a && (b ?? c)").toEval();
|
||||
expect("if (0) (a || b) ?? c").toEval();
|
||||
expect("if (0) a && (b * c) ?? d").not.toEval();
|
||||
expect("if (0) a || (b * c) ?? d").not.toEval();
|
||||
});
|
||||
|
||||
test("mixing coalescing and logical operators in ternary expressions", () => {
|
||||
expect("0 || 0 ? 0 : 0 ?? 0").toEval();
|
||||
expect("0 ?? 0 ? 0 : 0 || 0").toEval();
|
||||
expect("0 ? 0 || 0 : 0 ?? 0").toEval();
|
||||
expect("0 ? 0 ?? 0 : 0 || 0").toEval();
|
||||
expect("0 && 0 ? 0 ?? 0 : 0 || 0").toEval();
|
||||
expect("0 ?? 0 ? 0 && 0 : 0 || 0").toEval();
|
||||
expect("0 ?? 0 ? 0 || 0 : 0 && 0").toEval();
|
||||
expect("0 || 0 ? 0 ?? 0 : 0 && 0").toEval();
|
||||
expect("0 && 0 ? 0 || 0 : 0 ?? 0").toEval();
|
||||
expect("0 || 0 ? 0 && 0 : 0 ?? 0").toEval();
|
||||
});
|
||||
|
||||
test("mixing coalescing and logical operators when 'in' isn't allowed", () => {
|
||||
expect("for (a ?? b || c in a; false;);").not.toEval();
|
||||
expect("for (a ?? b && c in a; false;);").not.toEval();
|
||||
expect("for (a || b ?? c in a; false;);").not.toEval();
|
||||
expect("for (a && b ?? c in a; false;);").not.toEval();
|
||||
});
|
233
Libraries/LibJS/Tests/syntax/destructuring-assignment.js
Normal file
233
Libraries/LibJS/Tests/syntax/destructuring-assignment.js
Normal file
|
@ -0,0 +1,233 @@
|
|||
describe("parsing", () => {
|
||||
test("single name", () => {
|
||||
expect(`var { a } = {};`).toEval();
|
||||
expect(`const { a } = {};`).toEval();
|
||||
expect(`let { a } = {};`).toEval();
|
||||
});
|
||||
|
||||
test("single name with rest values", () => {
|
||||
expect(`var { a, ...rest } = {};`).toEval();
|
||||
expect(`const { a, ...rest } = {};`).toEval();
|
||||
expect(`let { a, ...rest } = {};`).toEval();
|
||||
});
|
||||
|
||||
test("single aliased name", () => {
|
||||
expect(`var { a: b } = {};`).toEval();
|
||||
expect(`const { a: b } = {};`).toEval();
|
||||
expect(`let { a: b } = {};`).toEval();
|
||||
});
|
||||
|
||||
test("single aliased name with rest values", () => {
|
||||
expect(`var { a: b, ...rest } = {};`).toEval();
|
||||
expect(`const { a: b, ...rest } = {};`).toEval();
|
||||
expect(`let { a: b, ...rest } = {};`).toEval();
|
||||
});
|
||||
|
||||
test("array destructuring patterns", () => {
|
||||
expect(`var [ a ] = [];`).toEval();
|
||||
expect(`const [ a ] = [];`).toEval();
|
||||
expect(`let [ a ] = [];`).toEval();
|
||||
});
|
||||
|
||||
test("destructuring assignment with rest assignments, array patterns", () => {
|
||||
expect(`var [ a, ...rest ] = [];`).toEval();
|
||||
expect(`const [ a, ...rest ] = [];`).toEval();
|
||||
expect(`let [ a, ...rest ] = [];`).toEval();
|
||||
});
|
||||
|
||||
test("destructuring assignment with rest names, array patterns with recursive patterns", () => {
|
||||
expect(`var [ a, [ ...rest ] ] = [];`).toEval();
|
||||
expect(`const [ a, [ ...rest ] ] = [];`).toEval();
|
||||
expect(`let [ a, [ ...rest ] ] = [];`).toEval();
|
||||
});
|
||||
|
||||
test("destructuring assignment with rest names, array patterns with recursive patterns 2", () => {
|
||||
expect(`var [ a, [ ...{length} ] ] = [];`).toEval();
|
||||
expect(`const [ a, [ ...{length} ] ] = [];`).toEval();
|
||||
expect(`let [ a, [ ...{length} ] ] = [];`).toEval();
|
||||
});
|
||||
|
||||
test("function parameters cannot use member expressions", () => {
|
||||
expect("function f([a.b]) {}").not.toEval();
|
||||
expect("function f([b[0]]) {}").not.toEval();
|
||||
|
||||
expect("function f({c:a.b}) {}").not.toEval();
|
||||
expect("function f({a:b[0]}) {}").not.toEval();
|
||||
|
||||
expect("([a.b]) => 1").not.toEval();
|
||||
expect("([b[0]]) => 2").not.toEval();
|
||||
|
||||
expect("({c:a.b}) => 3").not.toEval();
|
||||
expect("({a:b[0]}) => 4").not.toEval();
|
||||
});
|
||||
});
|
||||
|
||||
describe("evaluating", () => {
|
||||
test("single name", () => {
|
||||
let o = { a: 1 };
|
||||
{
|
||||
var { a } = o;
|
||||
expect(a).toBe(o.a);
|
||||
}
|
||||
{
|
||||
const { a } = o;
|
||||
expect(a).toBe(o.a);
|
||||
}
|
||||
{
|
||||
let { a } = o;
|
||||
expect(a).toBe(o.a);
|
||||
}
|
||||
});
|
||||
|
||||
test("single name with rest values", () => {
|
||||
let o = { a: 1, b: 2 };
|
||||
{
|
||||
var { a, ...b } = o;
|
||||
expect(a).toBe(o.a);
|
||||
expect(b).toEqual({ b: 2 });
|
||||
}
|
||||
{
|
||||
const { a, ...b } = o;
|
||||
expect(a).toBe(o.a);
|
||||
expect(b).toEqual({ b: 2 });
|
||||
}
|
||||
{
|
||||
let { a, ...b } = o;
|
||||
expect(a).toBe(o.a);
|
||||
expect(b).toEqual({ b: 2 });
|
||||
}
|
||||
});
|
||||
|
||||
test("single aliased name", () => {
|
||||
let o = { a: 1 };
|
||||
{
|
||||
var { a: x } = o;
|
||||
expect(x).toBe(o.a);
|
||||
}
|
||||
{
|
||||
const { a: x } = o;
|
||||
expect(x).toBe(o.a);
|
||||
}
|
||||
{
|
||||
let { a: x } = o;
|
||||
expect(x).toBe(o.a);
|
||||
}
|
||||
});
|
||||
|
||||
test("single aliased name with rest values", () => {
|
||||
let o = { a: 1, b: 2 };
|
||||
{
|
||||
var { a: x, ...b } = o;
|
||||
expect(x).toBe(o.a);
|
||||
expect(b).toEqual({ b: 2 });
|
||||
}
|
||||
{
|
||||
const { a: x, ...b } = o;
|
||||
expect(x).toBe(o.a);
|
||||
expect(b).toEqual({ b: 2 });
|
||||
}
|
||||
{
|
||||
let { a: x, ...b } = o;
|
||||
expect(x).toBe(o.a);
|
||||
expect(b).toEqual({ b: 2 });
|
||||
}
|
||||
});
|
||||
|
||||
test("array patterns", () => {
|
||||
let o = [1, 2, 3, 4];
|
||||
{
|
||||
var [a, b] = o;
|
||||
expect(a).toBe(o[0]);
|
||||
expect(b).toBe(o[1]);
|
||||
}
|
||||
{
|
||||
const [a, b] = o;
|
||||
expect(a).toBe(o[0]);
|
||||
expect(b).toBe(o[1]);
|
||||
}
|
||||
{
|
||||
let [a, b] = o;
|
||||
expect(a).toBe(o[0]);
|
||||
expect(b).toBe(o[1]);
|
||||
}
|
||||
});
|
||||
|
||||
test("destructuring assignment with rest names, array patterns", () => {
|
||||
let o = [1, 2, 3, 4];
|
||||
{
|
||||
var [a, ...b] = o;
|
||||
expect(a).toBe(o[0]);
|
||||
expect(b).toEqual(o.slice(1));
|
||||
}
|
||||
{
|
||||
const [a, ...b] = o;
|
||||
expect(a).toBe(o[0]);
|
||||
expect(b).toEqual(o.slice(1));
|
||||
}
|
||||
{
|
||||
let [a, ...b] = o;
|
||||
expect(a).toBe(o[0]);
|
||||
expect(b).toEqual(o.slice(1));
|
||||
}
|
||||
});
|
||||
|
||||
test("destructuring assignment with rest names, array patterns with recursive patterns", () => {
|
||||
let o = [1, [2, 3, 4]];
|
||||
{
|
||||
var [a, [b, ...c]] = o;
|
||||
expect(a).toBe(o[0]);
|
||||
expect(b).toBe(o[1][0]);
|
||||
expect(c).toEqual(o[1].slice(1));
|
||||
}
|
||||
{
|
||||
const [a, [b, ...c]] = o;
|
||||
expect(a).toBe(o[0]);
|
||||
expect(b).toBe(o[1][0]);
|
||||
expect(c).toEqual(o[1].slice(1));
|
||||
}
|
||||
{
|
||||
let [a, [b, ...c]] = o;
|
||||
expect(a).toBe(o[0]);
|
||||
expect(b).toBe(o[1][0]);
|
||||
expect(c).toEqual(o[1].slice(1));
|
||||
}
|
||||
});
|
||||
|
||||
test("destructuring assignment with rest names, array patterns with recursive patterns 2", () => {
|
||||
let o = [1, [2, 3, 4]];
|
||||
{
|
||||
var [a, [...{ length }]] = o;
|
||||
expect(a).toBe(o[0]);
|
||||
expect(length).toBe(o[1].length);
|
||||
}
|
||||
{
|
||||
const [a, [...{ length }]] = o;
|
||||
expect(a).toBe(o[0]);
|
||||
expect(length).toBe(o[1].length);
|
||||
}
|
||||
{
|
||||
let [a, [...{ length }]] = o;
|
||||
expect(a).toBe(o[0]);
|
||||
expect(length).toBe(o[1].length);
|
||||
}
|
||||
{
|
||||
expect(() => {
|
||||
let [a, b, [...{ length }]] = o;
|
||||
}).toThrowWithMessage(TypeError, "ToObject on null or undefined");
|
||||
}
|
||||
});
|
||||
|
||||
test("patterns with default", () => {
|
||||
let o = { a: 1 };
|
||||
let { x = "foo", a = "bar" } = o;
|
||||
expect(x).toBe("foo");
|
||||
expect(a).toBe(o.a);
|
||||
});
|
||||
|
||||
test("can use big int values as number-like properties", () => {
|
||||
let o = { "99999999999999999": 1 };
|
||||
let { 123n: a = "foo", 99999999999999999n: b = "bar" } = o;
|
||||
expect(a).toBe("foo");
|
||||
expect(b).toBe(1);
|
||||
});
|
||||
});
|
18
Libraries/LibJS/Tests/syntax/dynamic-import-usage.js
Normal file
18
Libraries/LibJS/Tests/syntax/dynamic-import-usage.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
describe("parsing", () => {
|
||||
test("can parse call import call", () => {
|
||||
expect("import('a')").toEval();
|
||||
expect("import('a', )").toEval();
|
||||
expect("import('a', {options: true})").toEval();
|
||||
});
|
||||
|
||||
test("does not crash on unexpected tokens after import", () => {
|
||||
expect("f = import('a')").toEval();
|
||||
|
||||
expect("f= import").not.toEval();
|
||||
expect("f= import;").not.toEval();
|
||||
expect("f= import?").not.toEval();
|
||||
expect("f= import'").not.toEval();
|
||||
expect("f= import 'a'").not.toEval();
|
||||
expect("f= import['a']").not.toEval();
|
||||
});
|
||||
});
|
19
Libraries/LibJS/Tests/syntax/for-loop-invalid-in.js
Normal file
19
Libraries/LibJS/Tests/syntax/for-loop-invalid-in.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
test("The use of the 'in' keyword is restricted in for loop headers", () => {
|
||||
expect("for (a ? a : a in a; false; ) ;").not.toEval();
|
||||
expect("for (a + a in b);").not.toEval();
|
||||
expect("for (a in a of a);").not.toEval();
|
||||
expect("for(a = a in a; false;);").not.toEval();
|
||||
expect("for(a += a in a; false;);").not.toEval();
|
||||
expect("for(a -= a in a; false;);").not.toEval();
|
||||
expect("for(a *= a in a; false;);").not.toEval();
|
||||
expect("for(a /= a in a; false;);").not.toEval();
|
||||
expect("for(a &= a in a; false;);").not.toEval();
|
||||
expect("for(a |= a in a; false;);").not.toEval();
|
||||
expect("for(a ^= a in a; false;);").not.toEval();
|
||||
expect("for(a ^^= a in a; false;);").not.toEval();
|
||||
expect("for(a == a in a; false;);").not.toEval();
|
||||
expect("for(a != a in a; false;);").not.toEval();
|
||||
expect("for(a === a in a; false;);").not.toEval();
|
||||
expect("for(a !== a in a; false;);").not.toEval();
|
||||
expect("for (a ?? b in c;;);").not.toEval();
|
||||
});
|
352
Libraries/LibJS/Tests/syntax/function-hoisting.js
Normal file
352
Libraries/LibJS/Tests/syntax/function-hoisting.js
Normal file
|
@ -0,0 +1,352 @@
|
|||
const noHoistLexTopLevel = false;
|
||||
let canCallNonHoisted = 0;
|
||||
|
||||
expect(basicHoistTopLevel()).toEqual("basicHoistTopLevel");
|
||||
|
||||
function basicHoistTopLevel() {
|
||||
return "basicHoistTopLevel";
|
||||
}
|
||||
|
||||
expect(typeof noHoistLexTopLevel).toBe("boolean");
|
||||
expect(typeof hoistInBlockTopLevel).toBe("undefined");
|
||||
|
||||
{
|
||||
expect(noHoistLexTopLevel()).toEqual("noHoistLexTopLevel");
|
||||
++canCallNonHoisted;
|
||||
|
||||
expect(basicHoistTopLevel()).toEqual("basicHoistTopLevelInBlock");
|
||||
++canCallNonHoisted;
|
||||
|
||||
expect(hoistInBlockTopLevel()).toEqual("hoistInBlockTopLevel");
|
||||
|
||||
function hoistInBlockTopLevel() {
|
||||
return "hoistInBlockTopLevel";
|
||||
}
|
||||
|
||||
function noHoistLexTopLevel() {
|
||||
return "noHoistLexTopLevel";
|
||||
}
|
||||
|
||||
function basicHoistTopLevel() {
|
||||
return "basicHoistTopLevelInBlock";
|
||||
}
|
||||
}
|
||||
|
||||
expect(canCallNonHoisted).toBe(2);
|
||||
|
||||
expect(hoistInBlockTopLevel()).toEqual("hoistInBlockTopLevel");
|
||||
|
||||
{
|
||||
{
|
||||
expect(nestedBlocksTopLevel()).toEqual("nestedBlocksTopLevel");
|
||||
|
||||
function nestedBlocksTopLevel() {
|
||||
return "nestedBlocksTopLevel";
|
||||
}
|
||||
}
|
||||
expect(nestedBlocksTopLevel()).toEqual("nestedBlocksTopLevel");
|
||||
}
|
||||
expect(nestedBlocksTopLevel()).toEqual("nestedBlocksTopLevel");
|
||||
expect(hoistInBlockTopLevel()).toEqual("hoistInBlockTopLevel");
|
||||
|
||||
expect(typeof hoistSecondOneTopLevel).toBe("undefined");
|
||||
{
|
||||
expect(typeof hoistSecondOneTopLevel).toBe("undefined");
|
||||
|
||||
{
|
||||
expect(hoistSecondOneTopLevel()).toEqual("hoistSecondOneTopLevel");
|
||||
|
||||
function hoistSecondOneTopLevel() {
|
||||
return "hoistFirstOneTopLevel";
|
||||
}
|
||||
|
||||
expect(hoistSecondOneTopLevel()).toEqual("hoistSecondOneTopLevel");
|
||||
|
||||
function hoistSecondOneTopLevel() {
|
||||
return "hoistSecondOneTopLevel";
|
||||
}
|
||||
|
||||
expect(hoistSecondOneTopLevel()).toEqual("hoistSecondOneTopLevel");
|
||||
|
||||
{
|
||||
expect(hoistSecondOneTopLevel()).toEqual("hoistThirdOneTopLevel");
|
||||
|
||||
function hoistSecondOneTopLevel() {
|
||||
return "hoistThirdOneTopLevel";
|
||||
}
|
||||
|
||||
expect(hoistSecondOneTopLevel()).toEqual("hoistThirdOneTopLevel");
|
||||
}
|
||||
|
||||
expect(hoistSecondOneTopLevel()).toEqual("hoistSecondOneTopLevel");
|
||||
}
|
||||
|
||||
expect(hoistSecondOneTopLevel()).toEqual("hoistSecondOneTopLevel");
|
||||
}
|
||||
|
||||
expect(hoistSecondOneTopLevel()).toEqual("hoistSecondOneTopLevel");
|
||||
|
||||
test("Non-strict function does hoist", () => {
|
||||
const noHoistLexFunction = false;
|
||||
let canCallNonHoisted = 0;
|
||||
|
||||
expect(basicHoistFunction()).toEqual("basicHoistFunction");
|
||||
|
||||
function basicHoistFunction() {
|
||||
return "basicHoistFunction";
|
||||
}
|
||||
|
||||
expect(typeof noHoistLexFunction).toBe("boolean");
|
||||
expect(typeof hoistInBlockFunction).toBe("undefined");
|
||||
|
||||
{
|
||||
expect(noHoistLexFunction()).toEqual("noHoistLexFunction");
|
||||
++canCallNonHoisted;
|
||||
|
||||
expect(basicHoistFunction()).toEqual("basicHoistFunctionInBlock");
|
||||
++canCallNonHoisted;
|
||||
|
||||
expect(hoistInBlockFunction()).toEqual("hoistInBlockFunction");
|
||||
|
||||
function hoistInBlockFunction() {
|
||||
return "hoistInBlockFunction";
|
||||
}
|
||||
|
||||
function noHoistLexFunction() {
|
||||
return "noHoistLexFunction";
|
||||
}
|
||||
|
||||
function basicHoistFunction() {
|
||||
return "basicHoistFunctionInBlock";
|
||||
}
|
||||
}
|
||||
|
||||
expect(canCallNonHoisted).toBe(2);
|
||||
|
||||
expect(hoistInBlockFunction()).toEqual("hoistInBlockFunction");
|
||||
|
||||
{
|
||||
{
|
||||
expect(nestedBlocksFunction()).toEqual("nestedBlocksFunction");
|
||||
|
||||
function nestedBlocksFunction() {
|
||||
return "nestedBlocksFunction";
|
||||
}
|
||||
}
|
||||
expect(nestedBlocksFunction()).toEqual("nestedBlocksFunction");
|
||||
}
|
||||
expect(nestedBlocksFunction()).toEqual("nestedBlocksFunction");
|
||||
expect(hoistInBlockFunction()).toEqual("hoistInBlockFunction");
|
||||
|
||||
expect(typeof hoistSecondOneFunction).toBe("undefined");
|
||||
{
|
||||
expect(typeof hoistSecondOneFunction).toBe("undefined");
|
||||
|
||||
{
|
||||
expect(hoistSecondOneFunction()).toEqual("hoistSecondOneFunction");
|
||||
|
||||
function hoistSecondOneFunction() {
|
||||
return "hoistFirstOneFunction";
|
||||
}
|
||||
|
||||
expect(hoistSecondOneFunction()).toEqual("hoistSecondOneFunction");
|
||||
|
||||
function hoistSecondOneFunction() {
|
||||
return "hoistSecondOneFunction";
|
||||
}
|
||||
|
||||
expect(hoistSecondOneFunction()).toEqual("hoistSecondOneFunction");
|
||||
|
||||
{
|
||||
expect(hoistSecondOneFunction()).toEqual("hoistThirdOneFunction");
|
||||
|
||||
function hoistSecondOneFunction() {
|
||||
return "hoistThirdOneFunction";
|
||||
}
|
||||
|
||||
expect(hoistSecondOneFunction()).toEqual("hoistThirdOneFunction");
|
||||
}
|
||||
|
||||
expect(hoistSecondOneFunction()).toEqual("hoistSecondOneFunction");
|
||||
}
|
||||
|
||||
expect(hoistSecondOneFunction()).toEqual("hoistSecondOneFunction");
|
||||
}
|
||||
|
||||
expect(hoistSecondOneFunction()).toEqual("hoistSecondOneFunction");
|
||||
|
||||
expect(notBlockFunctionTopLevel()).toBe("second");
|
||||
|
||||
function notBlockFunctionTopLevel() {
|
||||
return "first";
|
||||
}
|
||||
|
||||
expect(notBlockFunctionTopLevel()).toBe("second");
|
||||
|
||||
function notBlockFunctionTopLevel() {
|
||||
return "second";
|
||||
}
|
||||
|
||||
expect(notBlockFunctionTopLevel()).toBe("second");
|
||||
});
|
||||
|
||||
test("Strict function does not hoist", () => {
|
||||
"use strict";
|
||||
|
||||
const noHoistLexStrictFunction = false;
|
||||
let canCallNonHoisted = 0;
|
||||
|
||||
expect(basicHoistStrictFunction()).toEqual("basicHoistStrictFunction");
|
||||
|
||||
function basicHoistStrictFunction() {
|
||||
return "basicHoistStrictFunction";
|
||||
}
|
||||
|
||||
expect(typeof noHoistLexStrictFunction).toBe("boolean");
|
||||
// We cannot use expect(() => ).toThrow because that introduces extra scoping
|
||||
try {
|
||||
hoistInBlockStrictFunction;
|
||||
expect().fail();
|
||||
} catch (e) {
|
||||
expect(e).toBeInstanceOf(ReferenceError);
|
||||
expect(e.message).toEqual("'hoistInBlockStrictFunction' is not defined");
|
||||
}
|
||||
|
||||
{
|
||||
expect(noHoistLexStrictFunction()).toEqual("noHoistLexStrictFunction");
|
||||
++canCallNonHoisted;
|
||||
|
||||
expect(basicHoistStrictFunction()).toEqual("basicHoistStrictFunctionInBlock");
|
||||
++canCallNonHoisted;
|
||||
|
||||
expect(hoistInBlockStrictFunction()).toEqual("hoistInBlockStrictFunction");
|
||||
|
||||
function hoistInBlockStrictFunction() {
|
||||
return "hoistInBlockStrictFunction";
|
||||
}
|
||||
|
||||
function noHoistLexStrictFunction() {
|
||||
return "noHoistLexStrictFunction";
|
||||
}
|
||||
|
||||
function basicHoistStrictFunction() {
|
||||
return "basicHoistStrictFunctionInBlock";
|
||||
}
|
||||
}
|
||||
|
||||
expect(canCallNonHoisted).toBe(2);
|
||||
|
||||
try {
|
||||
hoistInBlockStrictFunction;
|
||||
expect().fail();
|
||||
} catch (e) {
|
||||
expect(e).toBeInstanceOf(ReferenceError);
|
||||
expect(e.message).toEqual("'hoistInBlockStrictFunction' is not defined");
|
||||
}
|
||||
|
||||
{
|
||||
try {
|
||||
nestedBlocksStrictFunction;
|
||||
expect().fail();
|
||||
} catch (e) {
|
||||
expect(e).toBeInstanceOf(ReferenceError);
|
||||
expect(e.message).toEqual("'nestedBlocksStrictFunction' is not defined");
|
||||
}
|
||||
|
||||
{
|
||||
expect(nestedBlocksStrictFunction()).toEqual("nestedBlocksStrictFunction");
|
||||
|
||||
function nestedBlocksStrictFunction() {
|
||||
return "nestedBlocksStrictFunction";
|
||||
}
|
||||
}
|
||||
try {
|
||||
nestedBlocksStrictFunction;
|
||||
expect().fail();
|
||||
} catch (e) {
|
||||
expect(e).toBeInstanceOf(ReferenceError);
|
||||
expect(e.message).toEqual("'nestedBlocksStrictFunction' is not defined");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
nestedBlocksStrictFunction;
|
||||
expect().fail();
|
||||
} catch (e) {
|
||||
expect(e).toBeInstanceOf(ReferenceError);
|
||||
expect(e.message).toEqual("'nestedBlocksStrictFunction' is not defined");
|
||||
}
|
||||
|
||||
expect(notBlockStrictFunctionTopLevel()).toBe("second");
|
||||
|
||||
function notBlockStrictFunctionTopLevel() {
|
||||
return "first";
|
||||
}
|
||||
|
||||
expect(notBlockStrictFunctionTopLevel()).toBe("second");
|
||||
|
||||
function notBlockStrictFunctionTopLevel() {
|
||||
return "second";
|
||||
}
|
||||
|
||||
{
|
||||
expect(notBlockStrictFunctionTopLevel()).toBe("third");
|
||||
|
||||
function notBlockStrictFunctionTopLevel() {
|
||||
return "third";
|
||||
}
|
||||
|
||||
expect(notBlockStrictFunctionTopLevel()).toBe("third");
|
||||
}
|
||||
|
||||
expect(notBlockStrictFunctionTopLevel()).toBe("second");
|
||||
|
||||
// Inside a block inside a strict function gives a syntax error
|
||||
let didNotRunEval = true;
|
||||
expect(`
|
||||
didNotRunEval = false;
|
||||
() => {
|
||||
"use strict";
|
||||
|
||||
{
|
||||
function f() {
|
||||
return "first";
|
||||
}
|
||||
|
||||
function f() {
|
||||
return "second";
|
||||
}
|
||||
}
|
||||
};
|
||||
`).not.toEval();
|
||||
|
||||
expect(didNotRunEval).toBeTrue();
|
||||
|
||||
// However, in eval it's fine but the function does not escape the eval
|
||||
{
|
||||
let ranEval = false;
|
||||
eval(`
|
||||
expect(hoistSecondOneStrictFunction()).toBe("hoistSecondOneStrictFunction");
|
||||
|
||||
function hoistSecondOneStrictFunction() {
|
||||
return "hoistFirstOneStrictFunction";
|
||||
}
|
||||
|
||||
function hoistSecondOneStrictFunction() {
|
||||
return "hoistSecondOneStrictFunction";
|
||||
}
|
||||
|
||||
ranEval = true;
|
||||
`);
|
||||
|
||||
expect(ranEval).toBeTrue();
|
||||
|
||||
try {
|
||||
hoistSecondOneStrictFunction;
|
||||
expect().fail();
|
||||
} catch (e) {
|
||||
expect(e).toBeInstanceOf(ReferenceError);
|
||||
expect(e.message).toEqual("'hoistSecondOneStrictFunction' is not defined");
|
||||
}
|
||||
}
|
||||
});
|
|
@ -0,0 +1,143 @@
|
|||
// Note: This must be checked at script level because that is the only place
|
||||
// where function order is visible. We introduce some test(...) with
|
||||
// names to make sure the file does have some tests and a suite.
|
||||
|
||||
const evalViaArrow = x => eval(x);
|
||||
const evalRef = eval;
|
||||
const expectedBeforeEval = "1256MNQR3478CDHIOP";
|
||||
const expectedAfterEval = "1256MNQR3478CDHIOPA9B";
|
||||
const expectedAfterEvalRef = "1256MNQR3478CDHIOPA9BKJL";
|
||||
const expectOrderToBe = expectedOrder => {
|
||||
const currentOrder = Object.getOwnPropertyNames(this)
|
||||
.filter(s => s.length === 2 && s[0] === "f")
|
||||
.map(s => s[1])
|
||||
.join("");
|
||||
expect(currentOrder).toBe(expectedOrder);
|
||||
};
|
||||
|
||||
test("function order should be in tree order and nothing in eval should be included", () => {
|
||||
expectOrderToBe(expectedBeforeEval);
|
||||
});
|
||||
|
||||
{
|
||||
function f1() {}
|
||||
|
||||
expectOrderToBe(expectedBeforeEval);
|
||||
|
||||
function f2() {}
|
||||
}
|
||||
|
||||
expectOrderToBe(expectedBeforeEval);
|
||||
|
||||
function f3() {}
|
||||
|
||||
expectOrderToBe(expectedBeforeEval);
|
||||
|
||||
function f4() {}
|
||||
|
||||
expectOrderToBe(expectedBeforeEval);
|
||||
|
||||
{
|
||||
function f5() {}
|
||||
|
||||
function f6() {}
|
||||
}
|
||||
|
||||
function f7() {}
|
||||
|
||||
function f8() {}
|
||||
|
||||
expectOrderToBe(expectedBeforeEval);
|
||||
eval(`
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
|
||||
function f9() {}
|
||||
|
||||
{
|
||||
function fA() {}
|
||||
}
|
||||
|
||||
function fB() {}
|
||||
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
`);
|
||||
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
|
||||
function fC() {}
|
||||
|
||||
function fD() {}
|
||||
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
|
||||
// This eval does not do anything because it goes via a function, this means
|
||||
// its parent environment is not the global environment so it does not have
|
||||
// a global var environment and does not put the functions on `this`.
|
||||
evalViaArrow(`
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
|
||||
function fE() {}
|
||||
|
||||
{
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
function fF() {}
|
||||
}
|
||||
|
||||
function fG() {}
|
||||
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
`);
|
||||
|
||||
test("function order should be in tree order, functions in eval should be in order but at the back", () => {
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
});
|
||||
|
||||
function fH() {}
|
||||
|
||||
function fI() {}
|
||||
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
|
||||
// This is an indirect eval, but still has the global scope as immediate
|
||||
// parent so it does influence the global `this`.
|
||||
evalRef(`
|
||||
expectOrderToBe(expectedAfterEvalRef);
|
||||
console.log(2, JSON.stringify(Object.getOwnPropertyNames(this).filter(s => s.length === 2)));
|
||||
|
||||
function fJ() {}
|
||||
|
||||
{
|
||||
expectOrderToBe(expectedAfterEvalRef);
|
||||
function fK() {}
|
||||
}
|
||||
|
||||
function fL() {}
|
||||
|
||||
expectOrderToBe(expectedAfterEvalRef);
|
||||
`);
|
||||
|
||||
{
|
||||
function fM() {}
|
||||
|
||||
function fN() {}
|
||||
}
|
||||
|
||||
test("function order should be in tree order, functions in evalRef should be in order but at the back", () => {
|
||||
expectOrderToBe(expectedAfterEvalRef);
|
||||
});
|
||||
|
||||
function fO() {}
|
||||
|
||||
function fP() {}
|
||||
|
||||
{
|
||||
function fQ() {}
|
||||
|
||||
{
|
||||
expectOrderToBe(expectedAfterEvalRef);
|
||||
}
|
||||
|
||||
function fR() {}
|
||||
}
|
||||
|
||||
expectOrderToBe(expectedAfterEvalRef);
|
148
Libraries/LibJS/Tests/syntax/functions-in-tree-order-strict.js
Normal file
148
Libraries/LibJS/Tests/syntax/functions-in-tree-order-strict.js
Normal file
|
@ -0,0 +1,148 @@
|
|||
"use strict";
|
||||
// Note: This must be checked at script level because that is the only place
|
||||
// where function order is visible. We introduce some test(...) with
|
||||
// names to make sure the file does have some tests and a suite.
|
||||
|
||||
// Note: In strict mode we expect almost the same result except that the
|
||||
// functions in blocks do not get hoisted up.
|
||||
// Only the indirect eval copy gets the global var environment.
|
||||
|
||||
const evalViaArrow = x => eval(x);
|
||||
const evalRef = eval;
|
||||
const expectedBeforeEval = "3478CDHIOP";
|
||||
const expectedAfterEval = "3478CDHIOP";
|
||||
const expectedAfterEvalRef = "3478CDHIOPKJL";
|
||||
const expectOrderToBe = expectedOrder => {
|
||||
const currentOrder = Object.getOwnPropertyNames(this)
|
||||
.filter(s => s.length === 2 && s[0] === "f")
|
||||
.map(s => s[1])
|
||||
.join("");
|
||||
expect(currentOrder).toBe(expectedOrder);
|
||||
};
|
||||
|
||||
test("in strict mode: function order should be in tree order and nothing in eval should be included, in strict mode functions should not be hoisted", () => {
|
||||
expectOrderToBe(expectedBeforeEval);
|
||||
});
|
||||
|
||||
{
|
||||
function f1() {}
|
||||
|
||||
expectOrderToBe(expectedBeforeEval);
|
||||
|
||||
function f2() {}
|
||||
}
|
||||
|
||||
expectOrderToBe(expectedBeforeEval);
|
||||
|
||||
function f3() {}
|
||||
|
||||
expectOrderToBe(expectedBeforeEval);
|
||||
|
||||
function f4() {}
|
||||
|
||||
expectOrderToBe(expectedBeforeEval);
|
||||
|
||||
{
|
||||
function f5() {}
|
||||
|
||||
function f6() {}
|
||||
}
|
||||
|
||||
function f7() {}
|
||||
|
||||
function f8() {}
|
||||
|
||||
expectOrderToBe(expectedBeforeEval);
|
||||
eval(`
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
|
||||
function f9() {}
|
||||
|
||||
{
|
||||
function fA() {}
|
||||
}
|
||||
|
||||
function fB() {}
|
||||
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
`);
|
||||
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
|
||||
function fC() {}
|
||||
|
||||
function fD() {}
|
||||
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
|
||||
// This eval does not do anything because it goes via a function, this means
|
||||
// its parent environment is not the global environment so it does not have
|
||||
// a global var environment and does not put the functions on `this`.
|
||||
evalViaArrow(`
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
|
||||
function fE() {}
|
||||
|
||||
{
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
function fF() {}
|
||||
}
|
||||
|
||||
function fG() {}
|
||||
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
`);
|
||||
|
||||
test("in strict mode: function order should be in tree order, functions in eval should be in order but at the back, in strict mode functions should not be hoisted", () => {
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
});
|
||||
|
||||
function fH() {}
|
||||
|
||||
function fI() {}
|
||||
|
||||
expectOrderToBe(expectedAfterEval);
|
||||
|
||||
// This is an indirect eval, but still has the global scope as immediate
|
||||
// parent so it does influence the global `this`.
|
||||
evalRef(`
|
||||
expectOrderToBe(expectedAfterEvalRef);
|
||||
console.log(2, JSON.stringify(Object.getOwnPropertyNames(this).filter(s => s.length === 2)));
|
||||
|
||||
function fJ() {}
|
||||
|
||||
{
|
||||
expectOrderToBe(expectedAfterEvalRef);
|
||||
function fK() {}
|
||||
}
|
||||
|
||||
function fL() {}
|
||||
|
||||
expectOrderToBe(expectedAfterEvalRef);
|
||||
`);
|
||||
|
||||
{
|
||||
function fM() {}
|
||||
|
||||
function fN() {}
|
||||
}
|
||||
|
||||
test("in strict mode: function order should be in tree order, functions in evalRef should be in order but at the back, in strict mode functions should not be hoisted", () => {
|
||||
expectOrderToBe(expectedAfterEvalRef);
|
||||
});
|
||||
|
||||
function fO() {}
|
||||
|
||||
function fP() {}
|
||||
|
||||
{
|
||||
function fQ() {}
|
||||
|
||||
{
|
||||
expectOrderToBe(expectedAfterEvalRef);
|
||||
}
|
||||
|
||||
function fR() {}
|
||||
}
|
||||
|
||||
expectOrderToBe(expectedAfterEvalRef);
|
65
Libraries/LibJS/Tests/syntax/generators.js
Normal file
65
Libraries/LibJS/Tests/syntax/generators.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
describe("parsing freestanding generators", () => {
|
||||
test("simple", () => {
|
||||
expect(`function* foo() {}`).toEval();
|
||||
expect(`function *foo() {}`).toEval();
|
||||
expect(`function
|
||||
*foo() {}`).toEval();
|
||||
|
||||
expect(`function *await() {}`).toEval();
|
||||
expect(`function *yield() {}`).toEval();
|
||||
});
|
||||
test("yield expression", () => {
|
||||
expect(`function* foo() { yield; }`).toEval();
|
||||
expect(`function* foo() { yield (yield); }`).toEval();
|
||||
expect(`function* foo() { yield (yield foo); }`).toEval();
|
||||
expect(`function foo() { yield; }`).toEval();
|
||||
expect(`function foo() { yield 3; }`).not.toEval();
|
||||
});
|
||||
|
||||
test("yield expression only gets the first expression", () => {
|
||||
expect("function* foo() { yield 2,3 }").toEval();
|
||||
expect("function* foo() { ({...yield yield, }) }").toEval();
|
||||
});
|
||||
|
||||
test("yield-from expression", () => {
|
||||
expect(`function* foo() { yield *bar; }`).toEval();
|
||||
expect(`function* foo() { yield *(yield); }`).toEval();
|
||||
expect(`function* foo() { yield
|
||||
*bar; }`).not.toEval();
|
||||
expect(`function foo() { yield
|
||||
*bar; }`).toEval();
|
||||
});
|
||||
});
|
||||
|
||||
describe("parsing object literal generator functions", () => {
|
||||
test("simple", () => {
|
||||
expect(`x = { *foo() { } }`).toEval();
|
||||
expect(`x = { * foo() { } }`).toEval();
|
||||
expect(`x = { *
|
||||
foo() { } }`).toEval();
|
||||
});
|
||||
test("yield", () => {
|
||||
expect(`x = { foo() { yield; } }`).toEval();
|
||||
expect(`x = { *foo() { yield; } }`).toEval();
|
||||
expect(`x = { *foo() { yield 42; } }`).toEval();
|
||||
expect(`x = { foo() { yield 42; } }`).not.toEval();
|
||||
expect(`x = { *foo() { yield (yield); } }`).toEval();
|
||||
expect(`x = { *
|
||||
foo() { yield (yield); } }`).toEval();
|
||||
});
|
||||
});
|
||||
|
||||
describe("parsing classes with generator methods", () => {
|
||||
test("simple", () => {
|
||||
expect(`class Foo { *foo() {} }`).toEval();
|
||||
expect(`class Foo { static *foo() {} }`).toEval();
|
||||
expect(`class Foo { *foo() { yield; } }`).toEval();
|
||||
expect(`class Foo { *foo() { yield 42; } }`).toEval();
|
||||
expect(`class Foo { *constructor() { yield 42; } }`).not.toEval();
|
||||
});
|
||||
});
|
||||
|
||||
test("function expression names equal to 'yield'", () => {
|
||||
expect(`function *foo() { (function yield() {}); }`).toEval();
|
||||
expect(`function *foo() { function yield() {} }`).not.toEval();
|
||||
});
|
|
@ -0,0 +1,4 @@
|
|||
test("if statement consequent/alternate expression returns empty completion", () => {
|
||||
expect(eval("1; if (true) {}")).toBeUndefined();
|
||||
expect(eval("1; if (false) {} else {}")).toBeUndefined();
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
describe("parsing new expressions with optional chaining", () => {
|
||||
expect("new Object()?.foo").toEval();
|
||||
expect("new Object?.foo").not.toEval();
|
||||
expect("(new Object)?.foo").toEval();
|
||||
});
|
26
Libraries/LibJS/Tests/syntax/numeric-separator.js
Normal file
26
Libraries/LibJS/Tests/syntax/numeric-separator.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
describe("numeric separators", () => {
|
||||
test("numeric separator works for 'normal' number", () => {
|
||||
expect("1_2").toEvalTo(12);
|
||||
expect("4_2.4_2").toEvalTo(42.42);
|
||||
expect("1_2e0_2").toEvalTo(1200);
|
||||
|
||||
expect("1_2E+_1").not.toEval();
|
||||
expect("1_2E+0_1").toEvalTo(120);
|
||||
});
|
||||
|
||||
test("cannot use numeric separator after .", () => {
|
||||
expect("4._3").not.toEval();
|
||||
expect("0._3").not.toEval();
|
||||
expect("1_.3._3").not.toEval();
|
||||
|
||||
// Actually a valid attempt to get property '_3' on 1.3 which fails but does parse.
|
||||
expect("1.3._3").toEval();
|
||||
});
|
||||
|
||||
test("cannot use numeric separator in octal escaped number", () => {
|
||||
expect("00_1").not.toEval();
|
||||
expect("01_1").not.toEval();
|
||||
expect("07_3").not.toEval();
|
||||
expect("00_1").not.toEval();
|
||||
});
|
||||
});
|
39
Libraries/LibJS/Tests/syntax/optional-chaining.js
Normal file
39
Libraries/LibJS/Tests/syntax/optional-chaining.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
test("parse optional-chaining", () => {
|
||||
expect(`a?.b`).toEval();
|
||||
expect(`a?.4:.5`).toEval();
|
||||
expect(`a?.[b]`).toEval();
|
||||
expect(`a?.b[b]`).toEval();
|
||||
expect(`a?.b(c)`).toEval();
|
||||
expect(`a?.b?.(c, d)`).toEval();
|
||||
expect(`a?.b?.()`).toEval();
|
||||
expect("a?.b``").not.toEval();
|
||||
expect("a?.b?.``").not.toEval();
|
||||
expect("new Foo?.bar").not.toEval();
|
||||
expect("new (Foo?.bar)").toEval();
|
||||
expect("(new Foo)?.bar").toEval();
|
||||
});
|
||||
|
||||
test("evaluate optional-chaining", () => {
|
||||
for (let nullishObject of [null, undefined]) {
|
||||
expect((() => nullishObject?.b)()).toBeUndefined();
|
||||
}
|
||||
|
||||
expect(
|
||||
(() => {
|
||||
let a = {};
|
||||
return a?.foo?.bar?.baz;
|
||||
})()
|
||||
).toBeUndefined();
|
||||
|
||||
expect(
|
||||
(() => {
|
||||
let a = { foo: { bar: () => 42 } };
|
||||
return `${a?.foo?.bar?.()}-${a?.foo?.baz?.()}`;
|
||||
})()
|
||||
).toBe("42-undefined");
|
||||
|
||||
expect(() => {
|
||||
let a = { foo: { bar: () => 42 } };
|
||||
return a.foo?.baz.nonExistentProperty;
|
||||
}).toThrow();
|
||||
});
|
52
Libraries/LibJS/Tests/syntax/slash-after-block.js
Normal file
52
Libraries/LibJS/Tests/syntax/slash-after-block.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
test("slash token resolution in lexer", () => {
|
||||
expect(`{ blah.blah; }\n/foo/`).toEval();
|
||||
expect("``/foo/").not.toEval();
|
||||
expect("1/foo/").not.toEval();
|
||||
expect("1/foo").toEval();
|
||||
|
||||
expect("{} /foo/").toEval();
|
||||
expect("{} /=/").toEval();
|
||||
expect("{} /=a/").toEval();
|
||||
expect("{} /* */ /=a/").toEval();
|
||||
expect("{} /* /a/ */ /=a/").toEval();
|
||||
|
||||
expect("(function () {} / 1)").toEval();
|
||||
expect("(function () {} / 1)").toEval();
|
||||
|
||||
expect("+a++ / 1").toEval();
|
||||
expect("+a-- / 1").toEval();
|
||||
expect("a.in / b").toEval();
|
||||
expect("a.instanceof / b").toEval();
|
||||
expect("class A { #name; d = a.#name / b; }").toEval();
|
||||
|
||||
expect("async / b").toEval();
|
||||
expect("a.delete / b").toEval();
|
||||
expect("delete / b/").toEval();
|
||||
expect("a.in / b").toEval();
|
||||
expect("for (a in / b/) {}").toEval();
|
||||
expect("a.instanceof / b").toEval();
|
||||
expect("a instanceof / b/").toEval();
|
||||
expect("new / b/").toEval();
|
||||
expect("null / b").toEval();
|
||||
expect("for (a of / b/) {}").toEval();
|
||||
expect("a.return / b").toEval();
|
||||
expect("function foo() { return / b/ }").toEval();
|
||||
expect("throw / b/").toEval();
|
||||
expect("a.typeof / b").toEval();
|
||||
expect("a.void / b").toEval();
|
||||
expect("void / b/").toEval();
|
||||
|
||||
expect("await / b").toEval();
|
||||
expect("await / b/").not.toEval();
|
||||
expect("async function foo() { await / b }").not.toEval();
|
||||
expect("async function foo() { await / b/ }").toEval();
|
||||
|
||||
expect("yield / b").toEval();
|
||||
expect("yield / b/").not.toEval();
|
||||
expect("function* foo() { yield / b }").not.toEval();
|
||||
expect("function* foo() { yield / b/ }").toEval();
|
||||
|
||||
expect("this / 1").toEval();
|
||||
expect("this / 1 /").not.toEval();
|
||||
expect("this / 1 / 1").toEval();
|
||||
});
|
69
Libraries/LibJS/Tests/syntax/switch-as-statement.js
Normal file
69
Libraries/LibJS/Tests/syntax/switch-as-statement.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
describe("switch statement is a valid statement and gets executed", () => {
|
||||
test("switch statement in a block", () => {
|
||||
let hit = false;
|
||||
{
|
||||
switch (true) {
|
||||
case true:
|
||||
hit = true;
|
||||
}
|
||||
expect(hit).toBeTrue();
|
||||
}
|
||||
});
|
||||
|
||||
test("switch statement in an if statement when true", () => {
|
||||
let hit = false;
|
||||
var a = true;
|
||||
if (a)
|
||||
switch (true) {
|
||||
case true:
|
||||
hit = true;
|
||||
}
|
||||
else
|
||||
switch (true) {
|
||||
case true:
|
||||
expect().fail();
|
||||
}
|
||||
|
||||
expect(hit).toBeTrue();
|
||||
});
|
||||
|
||||
test("switch statement in an if statement when false", () => {
|
||||
let hit = false;
|
||||
var a = false;
|
||||
if (a)
|
||||
switch (a) {
|
||||
default:
|
||||
expect().fail();
|
||||
}
|
||||
else
|
||||
switch (a) {
|
||||
default:
|
||||
hit = true;
|
||||
}
|
||||
|
||||
expect(hit).toBeTrue();
|
||||
});
|
||||
|
||||
test("switch statement in an while statement", () => {
|
||||
var a = 0;
|
||||
var loops = 0;
|
||||
while (a < 1 && loops++ < 5)
|
||||
switch (a) {
|
||||
case 0:
|
||||
a = 1;
|
||||
}
|
||||
|
||||
expect(a).toBe(1);
|
||||
});
|
||||
|
||||
test("switch statement in an for statement", () => {
|
||||
var loops = 0;
|
||||
for (let a = 0; a < 1 && loops++ < 5; )
|
||||
switch (a) {
|
||||
case 0:
|
||||
a = 1;
|
||||
}
|
||||
|
||||
expect(loops).toBe(1);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,9 @@
|
|||
test("syntax error for an unary expression before exponentiation", () => {
|
||||
expect(`!5 ** 2`).not.toEval();
|
||||
expect(`~5 ** 2`).not.toEval();
|
||||
expect(`+5 ** 2`).not.toEval();
|
||||
expect(`-5 ** 2`).not.toEval();
|
||||
expect(`typeof 5 ** 2`).not.toEval();
|
||||
expect(`void 5 ** 2`).not.toEval();
|
||||
expect(`delete 5 ** 2`).not.toEval();
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue