1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 07:58:11 +00:00

LibJS: Integrate Symbols into objects as valid keys

This allows objects properties to be created for symbol keys in addition
to just plain strings/numbers
This commit is contained in:
Matthew Olsson 2020-07-07 21:38:46 -07:00 committed by Andreas Kling
parent 9783a4936c
commit 7a1d485b19
14 changed files with 424 additions and 154 deletions

View file

@ -65,6 +65,15 @@ static void update_function_name(Value& value, const FlyString& name)
}
}
static String get_function_name(Interpreter& interpreter, Value value)
{
if (value.is_symbol())
return String::format("[%s]", value.as_symbol().description().characters());
if (value.is_string())
return value.as_string().string();
return value.to_string(interpreter);
}
Value ScopeNode::execute(Interpreter& interpreter, GlobalObject& global_object) const
{
return interpreter.run(global_object, *this);
@ -106,7 +115,7 @@ CallExpression::ThisAndCallee CallExpression::compute_this_and_callee(Interprete
if (interpreter.exception())
return {};
if (is_super_property_lookup && (lookup_target.is_null() || lookup_target.is_undefined())) {
interpreter.throw_exception<TypeError>(ErrorType::ObjectPrototypeNullOrUndefinedOnSuperPropertyAccess, lookup_target.to_string_without_side_effects());
interpreter.throw_exception<TypeError>(ErrorType::ObjectPrototypeNullOrUndefinedOnSuperPropertyAccess, lookup_target.to_string_without_side_effects().characters());
return {};
}
@ -374,7 +383,7 @@ Value ForInStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
return {};
auto* object = rhs_result.to_object(interpreter, global_object);
while (object) {
auto property_names = object->get_own_properties(*object, Object::GetOwnPropertyMode::Key, true);
auto property_names = object->get_own_properties(*object, Object::GetOwnPropertyReturnMode::Key, true);
for (auto& property_name : property_names.as_object().indexed_properties()) {
interpreter.set_variable(variable_name, property_name.value_and_attributes(object).value, global_object);
if (interpreter.exception())
@ -735,23 +744,21 @@ Value ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_ob
auto& target = method.is_static() ? *class_constructor : class_prototype.as_object();
method_function.set_home_object(&target);
auto property_name = key.to_string(interpreter);
if (method.kind() == ClassMethod::Kind::Method) {
target.define_property(property_name, method_value);
target.define_property(StringOrSymbol::from_value(interpreter, key), method_value);
} else {
String accessor_name = [&] {
switch (method.kind()) {
case ClassMethod::Kind::Getter:
return String::format("get %s", property_name.characters());
return String::format("get %s", get_function_name(interpreter, key).characters());
case ClassMethod::Kind::Setter:
return String::format("set %s", property_name.characters());
return String::format("set %s", get_function_name(interpreter, key).characters());
default:
ASSERT_NOT_REACHED();
}
}();
update_function_name(method_value, accessor_name);
target.define_accessor(property_name, method_function, method.kind() == ClassMethod::Kind::Getter, Attribute::Configurable | Attribute::Enumerable);
target.define_accessor(StringOrSymbol::from_value(interpreter, key), method_function, method.kind() == ClassMethod::Kind::Getter, Attribute::Configurable | Attribute::Enumerable);
}
if (interpreter.exception())
return {};
@ -1286,7 +1293,7 @@ Value AssignmentExpression::execute(Interpreter& interpreter, GlobalObject& glob
if (reference.is_unresolvable())
return interpreter.throw_exception<ReferenceError>(ErrorType::InvalidLeftHandAssignment);
update_function_name(rhs_result, reference.name().as_string());
update_function_name(rhs_result, get_function_name(interpreter, reference.name().to_value(interpreter)));
reference.put(interpreter, global_object, rhs_result);
if (interpreter.exception())
@ -1488,20 +1495,20 @@ Value ObjectExpression::execute(Interpreter& interpreter, GlobalObject& global_o
{
auto* object = Object::create_empty(interpreter, global_object);
for (auto& property : m_properties) {
auto key_result = property.key().execute(interpreter, global_object);
auto key = property.key().execute(interpreter, global_object);
if (interpreter.exception())
return {};
if (property.type() == ObjectProperty::Type::Spread) {
if (key_result.is_array()) {
auto& array_to_spread = static_cast<Array&>(key_result.as_object());
if (key.is_array()) {
auto& array_to_spread = static_cast<Array&>(key.as_object());
for (auto& entry : array_to_spread.indexed_properties()) {
object->indexed_properties().append(entry.value_and_attributes(&array_to_spread).value);
if (interpreter.exception())
return {};
}
} else if (key_result.is_object()) {
auto& obj_to_spread = key_result.as_object();
} else if (key.is_object()) {
auto& obj_to_spread = key.as_object();
for (auto& it : obj_to_spread.shape().property_table_ordered()) {
if (it.value.attributes.is_enumerable()) {
@ -1510,8 +1517,8 @@ Value ObjectExpression::execute(Interpreter& interpreter, GlobalObject& global_o
return {};
}
}
} else if (key_result.is_string()) {
auto& str_to_spread = key_result.as_string().string();
} else if (key.is_string()) {
auto& str_to_spread = key.as_string().string();
for (size_t i = 0; i < str_to_spread.length(); i++) {
object->define_property(i, js_string(interpreter, str_to_spread.substring(i, 1)));
@ -1523,7 +1530,6 @@ Value ObjectExpression::execute(Interpreter& interpreter, GlobalObject& global_o
continue;
}
auto key = key_result.to_string(interpreter);
if (interpreter.exception())
return {};
auto value = property.value().execute(interpreter, global_object);
@ -1533,22 +1539,22 @@ Value ObjectExpression::execute(Interpreter& interpreter, GlobalObject& global_o
if (value.is_function() && property.is_method())
value.as_function().set_home_object(object);
String name = key;
String name = get_function_name(interpreter, key);
if (property.type() == ObjectProperty::Type::Getter) {
name = String::format("get %s", key.characters());
name = String::format("get %s", name.characters());
} else if (property.type() == ObjectProperty::Type::Setter) {
name = String::format("set %s", key.characters());
name = String::format("set %s", name.characters());
}
update_function_name(value, name);
if (property.type() == ObjectProperty::Type::Getter || property.type() == ObjectProperty::Type::Setter) {
ASSERT(value.is_function());
object->define_accessor(key, value.as_function(), property.type() == ObjectProperty::Type::Getter, Attribute::Configurable | Attribute::Enumerable);
object->define_accessor(PropertyName::from_value(interpreter, key), value.as_function(), property.type() == ObjectProperty::Type::Getter, Attribute::Configurable | Attribute::Enumerable);
if (interpreter.exception())
return {};
} else {
object->define_property(key, value);
object->define_property(PropertyName::from_value(interpreter, key), value);
if (interpreter.exception())
return {};
}
@ -1579,6 +1585,9 @@ PropertyName MemberExpression::computed_property_name(Interpreter& interpreter,
if (index.is_integer() && index.as_i32() >= 0)
return index.as_i32();
if (index.is_symbol())
return &index.as_symbol();
auto index_string = index.to_string(interpreter);
if (interpreter.exception())
return {};