
This includes: - Parsing proper LabelledStatements with try_parse_labelled_statement() - Removing LabelableStatement - Implementing the LoopEvaluation semantics via loop_evaluation() in each IterationStatement subclass; and IterationStatement evaluation via {For,ForIn,ForOf,ForAwaitOf,While,DoWhile}Statement::execute() - Updating ReturnStatement, BreakStatement and ContinueStatement to return the appropriate completion types - Basically reimplementing TryStatement and SwitchStatement according to the spec, using completions - Honoring result completion types in AsyncBlockStart and OrdinaryCallEvaluateBody - Removing any uses of the VM unwind mechanism - most importantly, VM::throw_exception() now exclusively sets an exception and no longer triggers any unwinding mechanism. However, we already did a good job updating all of LibWeb and userland applications to not use it, and the few remaining uses elsewhere don't rely on unwinding AFAICT.
192 lines
3.8 KiB
JavaScript
192 lines
3.8 KiB
JavaScript
test("labelled plain scope", () => {
|
|
notused: test: alsonotused: {
|
|
let o = 1;
|
|
expect(o).toBe(1);
|
|
unused: break test;
|
|
expect().fail();
|
|
}
|
|
});
|
|
|
|
test("break on plain scope from inner scope", () => {
|
|
notused: outer: alsonotused: {
|
|
{
|
|
unused: break outer;
|
|
}
|
|
expect().fail();
|
|
}
|
|
});
|
|
|
|
test("labelled for loop with break", () => {
|
|
let counter = 0;
|
|
notused: outer: alsonotused: for (a of [1, 2, 3]) {
|
|
for (b of [4, 5, 6]) {
|
|
if (a === 2 && b === 5) break outer;
|
|
counter++;
|
|
}
|
|
}
|
|
expect(counter).toBe(4);
|
|
});
|
|
|
|
test("labelled for loop with continue", () => {
|
|
let counter = 0;
|
|
notused: outer: alsonotused: for (a of [1, 2, 3]) {
|
|
for (b of [4, 5, 6]) {
|
|
if (b === 6) continue outer;
|
|
counter++;
|
|
}
|
|
}
|
|
expect(counter).toBe(6);
|
|
});
|
|
|
|
test("continue label statement is not an iteration statement", () => {
|
|
expect(() =>
|
|
eval(`
|
|
outer: outer2: {
|
|
for (;;) {
|
|
continue outer;
|
|
}
|
|
}`)
|
|
).toThrowWithMessage(
|
|
SyntaxError,
|
|
"labelled continue statement cannot use non iterating statement (line: 4, column: 18)"
|
|
);
|
|
|
|
expect(() =>
|
|
eval(`
|
|
for (;;) {
|
|
outer: outer2: {
|
|
continue outer;
|
|
}
|
|
}`)
|
|
).toThrowWithMessage(
|
|
SyntaxError,
|
|
"labelled continue statement cannot use non iterating statement (line: 4, column: 18)"
|
|
);
|
|
});
|
|
|
|
test("break on try catch statement", () => {
|
|
let entered = false;
|
|
label1: label2: label3: try {
|
|
entered = true;
|
|
break label2;
|
|
expect().fail();
|
|
} catch (e) {
|
|
expect().fail();
|
|
}
|
|
expect(entered).toBeTrue();
|
|
});
|
|
|
|
test("can break on every label", () => {
|
|
let i = 0;
|
|
label0: label1: label2: for (; i < 3; i++) {
|
|
block: {
|
|
break block;
|
|
expect().fail();
|
|
}
|
|
if (i === 0) continue label0;
|
|
if (i === 1) continue label1;
|
|
if (i === 2) continue label2;
|
|
expect().fail();
|
|
}
|
|
expect(i).toBe(3);
|
|
});
|
|
|
|
test("can use certain 'keywords' as labels", () => {
|
|
let i = 0;
|
|
|
|
yield: {
|
|
i++;
|
|
break yield;
|
|
expect().fail();
|
|
}
|
|
|
|
await: {
|
|
i++;
|
|
break await;
|
|
expect().fail();
|
|
}
|
|
|
|
async: {
|
|
i++;
|
|
break async;
|
|
expect().fail();
|
|
}
|
|
|
|
let: {
|
|
i++;
|
|
break let;
|
|
expect().fail();
|
|
}
|
|
|
|
// prettier-ignore
|
|
l\u0065t: {
|
|
i++;
|
|
break let;
|
|
expect().fail();
|
|
}
|
|
|
|
private: {
|
|
i++;
|
|
break private;
|
|
expect().fail();
|
|
}
|
|
|
|
expect(i).toBe(6);
|
|
|
|
expect(`const: { break const; }`).not.toEval();
|
|
});
|
|
|
|
test("can use certain 'keywords' even in strict mode", () => {
|
|
"use strict";
|
|
|
|
let i = 0;
|
|
await: {
|
|
i++;
|
|
break await;
|
|
expect().fail();
|
|
}
|
|
|
|
async: {
|
|
i++;
|
|
break async;
|
|
expect().fail();
|
|
}
|
|
expect(i).toBe(2);
|
|
|
|
expect(`'use strict'; let: { break let; }`).not.toEval();
|
|
|
|
expect(`'use strict'; l\u0065t: { break l\u0065t; }`).not.toEval();
|
|
});
|
|
|
|
test("invalid label usage", () => {
|
|
expect(() =>
|
|
eval(`
|
|
label: {
|
|
(() => {
|
|
break label;
|
|
});
|
|
}
|
|
`)
|
|
).toThrowWithMessage(SyntaxError, "Label 'label' not found");
|
|
|
|
expect(() =>
|
|
eval(`
|
|
label: {
|
|
while (false) {
|
|
continue label;
|
|
}
|
|
}
|
|
`)
|
|
).toThrowWithMessage(
|
|
SyntaxError,
|
|
"labelled continue statement cannot use non iterating statement"
|
|
);
|
|
|
|
expect(() =>
|
|
eval(`
|
|
label: label: {
|
|
break label;
|
|
}
|
|
`)
|
|
).toThrowWithMessage(SyntaxError, "Label 'label' has already been declared");
|
|
});
|