mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 04:58:13 +00:00
LibJS: Add support for SpreadExpressions in array literals for bytecode
For this it adds another opcode `Append $lhs` which appends the accumulator to the Array in $lhs, optionally spreading it.
This commit is contained in:
parent
4235b2020f
commit
ae52ae8f9f
4 changed files with 109 additions and 27 deletions
|
@ -182,6 +182,46 @@ ThrowCompletionOr<void> NewArray::execute_impl(Bytecode::Interpreter& interprete
|
|||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> Append::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
// Note: This OpCode is used to construct array literals containing at least one spread element,
|
||||
// Iterating over such a spread element to unpack it has to be visible by
|
||||
// the user courtesy of
|
||||
// https://tc39.es/ecma262/#sec-runtime-semantics-arrayaccumulation
|
||||
// SpreadElement : ... AssignmentExpression
|
||||
// 1. Let spreadRef be ? Evaluation of AssignmentExpression.
|
||||
// 2. Let spreadObj be ? GetValue(spreadRef).
|
||||
// 3. Let iteratorRecord be ? GetIterator(spreadObj).
|
||||
// 4. Repeat,
|
||||
// a. Let next be ? IteratorStep(iteratorRecord).
|
||||
// b. If next is false, return nextIndex.
|
||||
// c. Let nextValue be ? IteratorValue(next).
|
||||
// d. Perform ! CreateDataPropertyOrThrow(array, ! ToString(𝔽(nextIndex)), nextValue).
|
||||
// e. Set nextIndex to nextIndex + 1.
|
||||
|
||||
auto& vm = interpreter.vm();
|
||||
|
||||
// Note: We know from codegen, that lhs is a plain array with only indexed properties
|
||||
auto& lhs = interpreter.reg(m_lhs).as_array();
|
||||
auto lhs_size = lhs.indexed_properties().array_like_size();
|
||||
|
||||
auto rhs = interpreter.accumulator();
|
||||
|
||||
if (m_is_spread) {
|
||||
// ...rhs
|
||||
size_t i = lhs_size;
|
||||
TRY(get_iterator_values(vm, rhs, [&i, &lhs](Value iterator_value) -> Optional<Completion> {
|
||||
lhs.indexed_properties().put(i, iterator_value, default_attributes);
|
||||
++i;
|
||||
return {};
|
||||
}));
|
||||
} else {
|
||||
lhs.indexed_properties().put(lhs_size, rhs, default_attributes);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// FIXME: Since the accumulator is a Value, we store an object there and have to convert back and forth between that an Iterator records. Not great.
|
||||
// Make sure to put this into the accumulator before the iterator object disappears from the stack to prevent the members from being GC'd.
|
||||
static Object* iterator_to_object(VM& vm, Iterator iterator)
|
||||
|
@ -943,6 +983,13 @@ String NewArray::to_string_impl(Bytecode::Executable const&) const
|
|||
return builder.to_string();
|
||||
}
|
||||
|
||||
String Append::to_string_impl(Bytecode::Executable const&) const
|
||||
{
|
||||
if (m_is_spread)
|
||||
return String::formatted("Append lhs: **{}", m_lhs);
|
||||
return String::formatted("Append lhs: {}", m_lhs);
|
||||
}
|
||||
|
||||
String IteratorToArray::to_string_impl(Bytecode::Executable const&) const
|
||||
{
|
||||
return "IteratorToArray";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue