mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-22 09:12:13 -05:00
LibJS: Use correct this value for tagged template literals with members
Required by creepjs, which does Date().split` `[3] to get the current year.
This commit is contained in:
parent
5f33383a7b
commit
a588756105
Notes:
github-actions[bot]
2025-01-17 16:16:08 +00:00
Author: https://github.com/Lubrsi Commit: https://github.com/LadybirdBrowser/ladybird/commit/a5887561056 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3277
2 changed files with 119 additions and 3 deletions
|
@ -2469,10 +2469,24 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> TemplateLiteral::genera
|
|||
return dst;
|
||||
}
|
||||
|
||||
struct TagAndThisValue {
|
||||
ScopedOperand tag;
|
||||
ScopedOperand this_value;
|
||||
};
|
||||
|
||||
Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> TaggedTemplateLiteral::generate_bytecode(Bytecode::Generator& generator, Optional<ScopedOperand> preferred_dst) const
|
||||
{
|
||||
Bytecode::Generator::SourceLocationScope scope(generator, *this);
|
||||
auto tag = TRY(m_tag->generate_bytecode(generator)).value();
|
||||
auto [tag, this_value] = TRY([&]() -> CodeGenerationErrorOr<TagAndThisValue> {
|
||||
if (is<MemberExpression>(*m_tag)) {
|
||||
auto& member_expression = static_cast<MemberExpression const&>(*m_tag);
|
||||
auto base_and_value = TRY(get_base_and_value_from_member_expression(generator, member_expression));
|
||||
return TagAndThisValue { .tag = base_and_value.value, .this_value = base_and_value.base };
|
||||
}
|
||||
|
||||
auto tag = TRY(m_tag->generate_bytecode(generator)).value();
|
||||
return TagAndThisValue { .tag = tag, .this_value = generator.add_constant(js_undefined()) };
|
||||
}());
|
||||
|
||||
// FIXME: Follow
|
||||
// 13.2.8.3 GetTemplateObject ( templateLiteral ), https://tc39.es/ecma262/#sec-gettemplateobject
|
||||
|
@ -2539,7 +2553,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> TaggedTemplateLiteral::
|
|||
generator.emit<Bytecode::Op::NewArray>(arguments);
|
||||
|
||||
auto dst = choose_dst(generator, preferred_dst);
|
||||
generator.emit<Bytecode::Op::CallWithArgumentArray>(Bytecode::Op::CallType::Call, dst, tag, generator.add_constant(js_undefined()), arguments);
|
||||
generator.emit<Bytecode::Op::CallWithArgumentArray>(Bytecode::Op::CallType::Call, dst, tag, this_value, arguments);
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ describe("tagged template literal functionality", () => {
|
|||
expect(firstResult).toBe(secondResult);
|
||||
});
|
||||
|
||||
test.xfail("this value of call comes from reference", () => {
|
||||
test("this value of call comes from reference for non-computed, non-super property", () => {
|
||||
let thisValue = null;
|
||||
const obj = {
|
||||
func() {
|
||||
|
@ -176,4 +176,106 @@ describe("tagged template literal functionality", () => {
|
|||
|
||||
expect(thisValue).toBe(obj);
|
||||
});
|
||||
|
||||
test("this value of call comes from reference for computed, non-super property", () => {
|
||||
let thisValue = null;
|
||||
const obj = {
|
||||
func() {
|
||||
thisValue = this;
|
||||
},
|
||||
};
|
||||
|
||||
obj["func"]``;
|
||||
|
||||
expect(thisValue).toBe(obj);
|
||||
});
|
||||
|
||||
test("this value of call comes from reference for private property", () => {
|
||||
let thisValue = null;
|
||||
const obj = new (class A {
|
||||
#func = () => {
|
||||
thisValue = this;
|
||||
};
|
||||
|
||||
constructor() {
|
||||
this.#func``;
|
||||
}
|
||||
})();
|
||||
|
||||
expect(thisValue).toBe(obj);
|
||||
});
|
||||
|
||||
test("this value of call comes from reference for non-computed super call property", () => {
|
||||
let thisValue = null;
|
||||
|
||||
class A {
|
||||
func() {
|
||||
thisValue = this;
|
||||
}
|
||||
}
|
||||
|
||||
const obj = new (class B extends A {
|
||||
constructor() {
|
||||
super().func``;
|
||||
}
|
||||
})();
|
||||
|
||||
expect(thisValue).toBe(obj);
|
||||
});
|
||||
|
||||
test("this value of call comes from reference for computed super call property", () => {
|
||||
let thisValue = null;
|
||||
|
||||
class A {
|
||||
func() {
|
||||
thisValue = this;
|
||||
}
|
||||
}
|
||||
|
||||
const obj = new (class B extends A {
|
||||
constructor() {
|
||||
super()["func"]``;
|
||||
}
|
||||
})();
|
||||
|
||||
expect(thisValue).toBe(obj);
|
||||
});
|
||||
|
||||
test("this value of call comes from reference for non-computed super property", () => {
|
||||
let thisValue = null;
|
||||
|
||||
class A {
|
||||
func() {
|
||||
thisValue = this;
|
||||
}
|
||||
}
|
||||
|
||||
const obj = new (class B extends A {
|
||||
constructor() {
|
||||
super();
|
||||
super.func``;
|
||||
}
|
||||
})();
|
||||
|
||||
expect(thisValue).toBe(obj);
|
||||
});
|
||||
|
||||
test("this value of call comes from reference for computed super property", () => {
|
||||
let thisValue = null;
|
||||
|
||||
class A {
|
||||
func() {
|
||||
thisValue = this;
|
||||
}
|
||||
}
|
||||
|
||||
const obj = new (class B extends A {
|
||||
constructor() {
|
||||
super();
|
||||
super["func"]``;
|
||||
}
|
||||
})();
|
||||
|
||||
expect(thisValue).toBe(obj);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue