mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 07:47:37 +00:00
LibJS: Allow CallExpression as left hand side of for-of/for-in loops
Although this will fail with a ReferenceError it should pass the parser and only fail if actually assigned to.
This commit is contained in:
parent
ce057115fc
commit
65bebb5241
4 changed files with 63 additions and 10 deletions
|
@ -865,7 +865,7 @@ struct ForInOfHeadState {
|
||||||
VERIFY(declaration.declarations().first().target().has<NonnullRefPtr<Identifier>>());
|
VERIFY(declaration.declarations().first().target().has<NonnullRefPtr<Identifier>>());
|
||||||
lhs_reference = TRY(declaration.declarations().first().target().get<NonnullRefPtr<Identifier>>()->to_reference(interpreter, global_object));
|
lhs_reference = TRY(declaration.declarations().first().target().get<NonnullRefPtr<Identifier>>()->to_reference(interpreter, global_object));
|
||||||
} else {
|
} else {
|
||||||
VERIFY(is<Identifier>(*expression_lhs) || is<MemberExpression>(*expression_lhs));
|
VERIFY(is<Identifier>(*expression_lhs) || is<MemberExpression>(*expression_lhs) || is<CallExpression>(*expression_lhs));
|
||||||
auto& expression = static_cast<Expression const&>(*expression_lhs);
|
auto& expression = static_cast<Expression const&>(*expression_lhs);
|
||||||
lhs_reference = TRY(expression.to_reference(interpreter, global_object));
|
lhs_reference = TRY(expression.to_reference(interpreter, global_object));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3492,7 +3492,7 @@ NonnullRefPtr<Statement> Parser::parse_for_in_of_statement(NonnullRefPtr<ASTNode
|
||||||
has_annexB_for_in_init_extension = true;
|
has_annexB_for_in_init_extension = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!lhs->is_identifier() && !is<MemberExpression>(*lhs)) {
|
} else if (!lhs->is_identifier() && !is<MemberExpression>(*lhs) && !is<CallExpression>(*lhs)) {
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
if (is<ObjectExpression>(*lhs) || is<ArrayExpression>(*lhs)) {
|
if (is<ObjectExpression>(*lhs) || is<ArrayExpression>(*lhs)) {
|
||||||
auto synthesized_binding_pattern = synthesize_binding_pattern(static_cast<Expression const&>(*lhs));
|
auto synthesized_binding_pattern = synthesize_binding_pattern(static_cast<Expression const&>(*lhs));
|
||||||
|
|
|
@ -67,8 +67,35 @@ test("allow binding patterns", () => {
|
||||||
expect(counter).toBe(3);
|
expect(counter).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("allow member expression as variable", () => {
|
describe("special left hand sides", () => {
|
||||||
|
test("allow member expression as variable", () => {
|
||||||
const f = {};
|
const f = {};
|
||||||
for (f.a in "abc");
|
for (f.a in "abc");
|
||||||
expect(f.a).toBe("2");
|
expect(f.a).toBe("2");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("allow member expression of function call", () => {
|
||||||
|
const b = {};
|
||||||
|
function f() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (f().a in "abc");
|
||||||
|
|
||||||
|
expect(f().a).toBe("2");
|
||||||
|
expect(b.a).toBe("2");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("call function is allowed in parsing but fails in runtime", () => {
|
||||||
|
function f() {
|
||||||
|
expect().fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does not fail since it does not iterate
|
||||||
|
expect("for (f() in []);").toEvalTo(undefined);
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
eval("for (f() in [0]) { expect().fail() }");
|
||||||
|
}).toThrowWithMessage(ReferenceError, "Invalid left-hand side in assignment");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -112,8 +112,34 @@ test("allow binding patterns", () => {
|
||||||
expect(counter).toBe(3);
|
expect(counter).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("allow member expression as variable", () => {
|
describe("special left hand sides", () => {
|
||||||
|
test("allow member expression as variable", () => {
|
||||||
const f = {};
|
const f = {};
|
||||||
for (f.a of "abc");
|
for (f.a of "abc");
|
||||||
expect(f.a).toBe("c");
|
expect(f.a).toBe("c");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("allow member expression of function call", () => {
|
||||||
|
const b = {};
|
||||||
|
function f() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (f().a of "abc");
|
||||||
|
|
||||||
|
expect(f().a).toBe("c");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("call function is allowed in parsing but fails in runtime", () => {
|
||||||
|
function f() {
|
||||||
|
expect().fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does not fail since it does not iterate but prettier does not like it so we use eval.
|
||||||
|
expect("for (f() of []);").toEvalTo(undefined);
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
eval("for (f() of [0]) { expect().fail() }");
|
||||||
|
}).toThrowWithMessage(ReferenceError, "Invalid left-hand side in assignment");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue