mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 14:47:44 +00:00
LibJS: Add using declaration support in for and for of loops
The using declarations have kind of special behavior in for loops so this is seperated.
This commit is contained in:
parent
541637e15a
commit
bff038411a
6 changed files with 447 additions and 77 deletions
239
Userland/Libraries/LibJS/Tests/using-for-loops.js
Normal file
239
Userland/Libraries/LibJS/Tests/using-for-loops.js
Normal file
|
@ -0,0 +1,239 @@
|
|||
describe("basic usage", () => {
|
||||
test("using in normal for loop", () => {
|
||||
let isDisposed = false;
|
||||
let lastI = -1;
|
||||
for (
|
||||
using x = {
|
||||
i: 0,
|
||||
tick() {
|
||||
this.i++;
|
||||
},
|
||||
done() {
|
||||
return this.i === 3;
|
||||
},
|
||||
[Symbol.dispose]() {
|
||||
isDisposed = true;
|
||||
},
|
||||
};
|
||||
!x.done();
|
||||
x.tick()
|
||||
) {
|
||||
expect(isDisposed).toBeFalse();
|
||||
expect(x.i).toBeGreaterThan(lastI);
|
||||
lastI = x.i;
|
||||
}
|
||||
|
||||
expect(isDisposed).toBeTrue();
|
||||
expect(lastI).toBe(2);
|
||||
});
|
||||
|
||||
test("using in normal for loop with expression body", () => {
|
||||
let isDisposed = false;
|
||||
let outerI = 0;
|
||||
for (
|
||||
using x = {
|
||||
i: 0,
|
||||
tick() {
|
||||
this.i++;
|
||||
outerI++;
|
||||
},
|
||||
done() {
|
||||
return this.i === 3;
|
||||
},
|
||||
[Symbol.dispose]() {
|
||||
isDisposed = true;
|
||||
},
|
||||
};
|
||||
!x.done();
|
||||
x.tick()
|
||||
)
|
||||
expect(isDisposed).toBeFalse();
|
||||
|
||||
expect(isDisposed).toBeTrue();
|
||||
expect(outerI).toBe(3);
|
||||
});
|
||||
|
||||
test("using in for of loop", () => {
|
||||
const disposable = [];
|
||||
const values = [];
|
||||
|
||||
function createDisposable(value) {
|
||||
return {
|
||||
value: value,
|
||||
[Symbol.dispose]() {
|
||||
expect(this.value).toBe(value);
|
||||
disposable.push(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
for (using a of [createDisposable('a'), createDisposable('b'), createDisposable('c')]) {
|
||||
expect(disposable).toEqual(values);
|
||||
values.push(a.value);
|
||||
}
|
||||
|
||||
expect(disposable).toEqual(['a', 'b', 'c']);
|
||||
});
|
||||
|
||||
test("using in for of loop with expression body", () => {
|
||||
let disposableCalls = 0;
|
||||
let i = 0;
|
||||
|
||||
const obj = {
|
||||
[Symbol.dispose]() {
|
||||
disposableCalls++;
|
||||
}
|
||||
};
|
||||
|
||||
for (using a of [obj, obj, obj])
|
||||
expect(disposableCalls).toBe(i++);
|
||||
|
||||
expect(disposableCalls).toBe(3);
|
||||
});
|
||||
|
||||
test("can have multiple declaration in normal for loop", () => {
|
||||
let disposed = 0;
|
||||
const a = {
|
||||
[Symbol.dispose]() {
|
||||
disposed++;
|
||||
}
|
||||
}
|
||||
|
||||
expect(disposed).toBe(0);
|
||||
for (using b = a, c = a; false;)
|
||||
expect().fail();
|
||||
|
||||
expect(disposed).toBe(2);
|
||||
});
|
||||
|
||||
test("can have using in block in for loop", () => {
|
||||
const disposed = [];
|
||||
const values = [];
|
||||
for (let i = 0; i < 3; i++) {
|
||||
using a = {
|
||||
val: i,
|
||||
[Symbol.dispose]() {
|
||||
expect(i).toBe(this.val);
|
||||
disposed.push(i);
|
||||
},
|
||||
};
|
||||
expect(disposed).toEqual(values);
|
||||
values.push(i);
|
||||
}
|
||||
expect(disposed).toEqual([0, 1, 2]);
|
||||
});
|
||||
|
||||
test("can have using in block in for-in loop", () => {
|
||||
const disposed = [];
|
||||
const values = [];
|
||||
for (const i in ['a', 'b', 'c']) {
|
||||
using a = {
|
||||
val: i,
|
||||
[Symbol.dispose]() {
|
||||
expect(i).toBe(this.val);
|
||||
disposed.push(i);
|
||||
},
|
||||
};
|
||||
expect(disposed).toEqual(values);
|
||||
values.push(i);
|
||||
}
|
||||
expect(disposed).toEqual(["0", "1", "2"]);
|
||||
});
|
||||
|
||||
test("dispose is called even if throw in for of loop", () => {
|
||||
let disposableCalls = 0;
|
||||
|
||||
const obj = {
|
||||
[Symbol.dispose]() {
|
||||
expect()
|
||||
disposableCalls++;
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
for (using a of [obj])
|
||||
throw new ExpectationError("Expected in for-of");
|
||||
|
||||
expect().fail("Should have thrown");
|
||||
} catch (e) {
|
||||
expect(e).toBeInstanceOf(ExpectationError);
|
||||
expect(e.message).toBe("Expected in for-of");
|
||||
expect(disposableCalls).toBe(1);
|
||||
}
|
||||
|
||||
expect(disposableCalls).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("using is still a valid variable in loops", () => {
|
||||
test("for loops var", () => {
|
||||
let enteredLoop = false;
|
||||
for (var using = 1; using < 2; using++) {
|
||||
enteredLoop = true;
|
||||
}
|
||||
expect(enteredLoop).toBeTrue();
|
||||
});
|
||||
|
||||
test("for loops const", () => {
|
||||
let enteredLoop = false;
|
||||
for (const using = 1; using < 2; ) {
|
||||
enteredLoop = true;
|
||||
break;
|
||||
}
|
||||
expect(enteredLoop).toBeTrue();
|
||||
});
|
||||
|
||||
test("for loops let", () => {
|
||||
let enteredLoop = false;
|
||||
for (let using = 1; using < 2; using++) {
|
||||
enteredLoop = true;
|
||||
}
|
||||
expect(enteredLoop).toBeTrue();
|
||||
});
|
||||
|
||||
test("using in", () => {
|
||||
let enteredLoop = false;
|
||||
for (using in [1]) {
|
||||
enteredLoop = true;
|
||||
expect(using).toBe("0");
|
||||
}
|
||||
expect(enteredLoop).toBeTrue();
|
||||
});
|
||||
|
||||
test("using of", () => {
|
||||
let enteredLoop = false;
|
||||
for (using of [1]) {
|
||||
enteredLoop = true;
|
||||
expect(using).toBe(1);
|
||||
}
|
||||
expect(enteredLoop).toBeTrue();
|
||||
});
|
||||
|
||||
test("using using of", () => {
|
||||
let enteredLoop = false;
|
||||
for (using using of [null]) {
|
||||
enteredLoop = true;
|
||||
expect(using).toBeNull();
|
||||
}
|
||||
expect(enteredLoop).toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
describe("syntax errors", () => {
|
||||
test("cannot have using as for loop body", () => {
|
||||
expect("for (;;) using a = {};").not.toEval();
|
||||
expect("for (x in []) using a = {};").not.toEval();
|
||||
expect("for (x of []) using a = {};").not.toEval();
|
||||
});
|
||||
|
||||
test("must have one declaration without initializer in for loop", () => {
|
||||
expect("for (using x = {} of []) {}").not.toEval();
|
||||
expect("for (using x, y of []) {}").not.toEval();
|
||||
});
|
||||
|
||||
test("cannot have using in for-in loop", () => {
|
||||
expect("for (using x in []) {}").not.toEval();
|
||||
expect("for (using of in []) {}").not.toEval();
|
||||
expect("for (using in of []) {}").not.toEval();
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue