mirror of
https://github.com/RGBCube/serenity
synced 2025-05-25 16:15:08 +00:00
LibJS: Implement correct object property ordering
This commit introduces a way to get an object's own properties in the correct order. The "correct order" for JS object properties is first all array-like index properties (numeric keys) sorted by insertion order, followed by all string properties sorted by insertion order. Objects also now print correctly in the repl! Before this commit: courage ~/js-tests $ js > ({ foo: 1, bar: 2, baz: 3 }) { bar: 2, foo: 1, baz: 3 } After: courage ~/js-tests $ js > ({ foo: 1, bar: 2, baz: 3 }) { foo: 1, bar: 2, baz: 3 }
This commit is contained in:
parent
58f6f50de4
commit
95abcc3722
9 changed files with 41 additions and 9 deletions
|
@ -1046,8 +1046,8 @@ Value ObjectExpression::execute(Interpreter& interpreter) const
|
||||||
} else if (key_result.is_object()) {
|
} else if (key_result.is_object()) {
|
||||||
auto& obj_to_spread = key_result.as_object();
|
auto& obj_to_spread = key_result.as_object();
|
||||||
|
|
||||||
for (auto& it : obj_to_spread.shape().property_table()) {
|
for (auto& it : obj_to_spread.shape().property_table_ordered()) {
|
||||||
if (obj_to_spread.has_own_property(it.key) && it.value.attributes & Attribute::Enumerable)
|
if (it.value.attributes & Attribute::Enumerable)
|
||||||
object->put(it.key, obj_to_spread.get(it.key));
|
object->put(it.key, obj_to_spread.get(it.key));
|
||||||
}
|
}
|
||||||
} else if (key_result.is_string()) {
|
} else if (key_result.is_string()) {
|
||||||
|
|
|
@ -56,6 +56,11 @@ Interpreter& Cell::interpreter()
|
||||||
return heap().interpreter();
|
return heap().interpreter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Interpreter& Cell::interpreter() const
|
||||||
|
{
|
||||||
|
return heap().interpreter();
|
||||||
|
}
|
||||||
|
|
||||||
const LogStream& operator<<(const LogStream& stream, const Cell* cell)
|
const LogStream& operator<<(const LogStream& stream, const Cell* cell)
|
||||||
{
|
{
|
||||||
if (!cell)
|
if (!cell)
|
||||||
|
|
|
@ -60,6 +60,7 @@ public:
|
||||||
|
|
||||||
Heap& heap() const;
|
Heap& heap() const;
|
||||||
Interpreter& interpreter();
|
Interpreter& interpreter();
|
||||||
|
Interpreter& interpreter() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Cell() {}
|
Cell() {}
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <LibJS/Runtime/NativeProperty.h>
|
#include <LibJS/Runtime/NativeProperty.h>
|
||||||
#include <LibJS/Runtime/Object.h>
|
#include <LibJS/Runtime/Object.h>
|
||||||
#include <LibJS/Runtime/Shape.h>
|
#include <LibJS/Runtime/Shape.h>
|
||||||
|
#include <LibJS/Runtime/StringObject.h>
|
||||||
#include <LibJS/Runtime/Value.h>
|
#include <LibJS/Runtime/Value.h>
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
|
@ -76,7 +76,7 @@ Value ObjectConstructor::get_own_property_names(Interpreter& interpreter)
|
||||||
result->elements().append(js_string(interpreter, String::number(i)));
|
result->elements().append(js_string(interpreter, String::number(i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& it : object->shape().property_table()) {
|
for (auto& it : object->shape().property_table_ordered()) {
|
||||||
result->elements().append(js_string(interpreter, it.key));
|
result->elements().append(js_string(interpreter, it.key));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -117,6 +117,18 @@ size_t Shape::property_count() const
|
||||||
return property_table().size();
|
return property_table().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<Shape::Property> Shape::property_table_ordered() const
|
||||||
|
{
|
||||||
|
auto vec = Vector<Shape::Property>();
|
||||||
|
vec.resize(property_table().size());
|
||||||
|
|
||||||
|
for (auto& it : property_table()) {
|
||||||
|
vec[it.value.offset] = { it.key, it.value };
|
||||||
|
}
|
||||||
|
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
void Shape::ensure_property_table() const
|
void Shape::ensure_property_table() const
|
||||||
{
|
{
|
||||||
if (m_property_table)
|
if (m_property_table)
|
||||||
|
|
|
@ -88,6 +88,13 @@ public:
|
||||||
const HashMap<FlyString, PropertyMetadata>& property_table() const;
|
const HashMap<FlyString, PropertyMetadata>& property_table() const;
|
||||||
size_t property_count() const;
|
size_t property_count() const;
|
||||||
|
|
||||||
|
struct Property {
|
||||||
|
FlyString key;
|
||||||
|
PropertyMetadata value;
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector<Property> property_table_ordered() const;
|
||||||
|
|
||||||
void set_prototype_without_transition(Object* new_prototype) { m_prototype = new_prototype; }
|
void set_prototype_without_transition(Object* new_prototype) { m_prototype = new_prototype; }
|
||||||
|
|
||||||
void remove_property_from_unique_shape(const FlyString&, size_t offset);
|
void remove_property_from_unique_shape(const FlyString&, size_t offset);
|
||||||
|
|
|
@ -1,13 +1,19 @@
|
||||||
load("test-common.js");
|
load("test-common.js");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var names = Object.getOwnPropertyNames([1, 2, 3]);
|
let names = Object.getOwnPropertyNames([1, 2, 3]);
|
||||||
|
|
||||||
assert(names.length === 4);
|
assert(names.length === 4);
|
||||||
assert(names[0] === '0');
|
assert(names[0] === "0");
|
||||||
assert(names[1] === '1');
|
assert(names[1] === "1");
|
||||||
assert(names[2] === '2');
|
assert(names[2] === "2");
|
||||||
assert(names[3] === 'length');
|
assert(names[3] === "length");
|
||||||
|
|
||||||
|
names = Object.getOwnPropertyNames({ foo: 1, bar: 2, baz: 3 });
|
||||||
|
assert(names.length === 3);
|
||||||
|
assert(names[0] === "foo");
|
||||||
|
assert(names[1] === "bar");
|
||||||
|
assert(names[2] === "baz");
|
||||||
|
|
||||||
console.log("PASS");
|
console.log("PASS");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -142,7 +142,7 @@ static void print_object(const JS::Object& object, HashTable<JS::Object*>& seen_
|
||||||
fputs(", ", stdout);
|
fputs(", ", stdout);
|
||||||
|
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
for (auto& it : object.shape().property_table()) {
|
for (auto& it : object.shape().property_table_ordered()) {
|
||||||
printf("\"\033[33;1m%s\033[0m\": ", it.key.characters());
|
printf("\"\033[33;1m%s\033[0m\": ", it.key.characters());
|
||||||
print_value(object.get_direct(it.value.offset), seen_objects);
|
print_value(object.get_direct(it.value.offset), seen_objects);
|
||||||
if (index != object.shape().property_count() - 1)
|
if (index != object.shape().property_count() - 1)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue