mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 18:27:35 +00:00
LibJS: Bring JSON.parse slightly closer to the specification
This PR does not fix the main issue with our current implementation: The specification requires that we first check the JSON string for validity with an ECMA-404 compliant parser, and then evaluate it as if it was javascript code, of which we do neither at the moment.
This commit is contained in:
parent
f5e63f785a
commit
648b4c7d74
1 changed files with 19 additions and 25 deletions
|
@ -414,8 +414,6 @@ String JSONObject::quote_json_string(String string)
|
||||||
// 25.5.1 JSON.parse ( text [ , reviver ] ), https://tc39.es/ecma262/#sec-json.parse
|
// 25.5.1 JSON.parse ( text [ , reviver ] ), https://tc39.es/ecma262/#sec-json.parse
|
||||||
JS_DEFINE_NATIVE_FUNCTION(JSONObject::parse)
|
JS_DEFINE_NATIVE_FUNCTION(JSONObject::parse)
|
||||||
{
|
{
|
||||||
if (!vm.argument_count())
|
|
||||||
return js_undefined();
|
|
||||||
auto string = vm.argument(0).to_string(global_object);
|
auto string = vm.argument(0).to_string(global_object);
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
|
@ -426,16 +424,17 @@ JS_DEFINE_NATIVE_FUNCTION(JSONObject::parse)
|
||||||
vm.throw_exception<SyntaxError>(global_object, ErrorType::JsonMalformed);
|
vm.throw_exception<SyntaxError>(global_object, ErrorType::JsonMalformed);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
Value result = parse_json_value(global_object, json.value());
|
Value unfiltered = parse_json_value(global_object, json.value());
|
||||||
if (reviver.is_function()) {
|
if (reviver.is_function()) {
|
||||||
auto* root = Object::create(global_object, global_object.object_prototype());
|
auto* root = Object::create(global_object, global_object.object_prototype());
|
||||||
auto root_name = String::empty();
|
auto root_name = String::empty();
|
||||||
root->define_property(root_name, result);
|
root->define_property(root_name, unfiltered);
|
||||||
|
auto result = internalize_json_property(global_object, root, root_name, reviver.as_function());
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
return internalize_json_property(global_object, root, root_name, reviver.as_function());
|
return result;
|
||||||
}
|
}
|
||||||
return result;
|
return unfiltered;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value JSONObject::parse_json_value(GlobalObject& global_object, const JsonValue& value)
|
Value JSONObject::parse_json_value(GlobalObject& global_object, const JsonValue& value)
|
||||||
|
@ -480,43 +479,38 @@ Array* JSONObject::parse_json_array(GlobalObject& global_object, const JsonArray
|
||||||
Value JSONObject::internalize_json_property(GlobalObject& global_object, Object* holder, PropertyName const& name, FunctionObject& reviver)
|
Value JSONObject::internalize_json_property(GlobalObject& global_object, Object* holder, PropertyName const& name, FunctionObject& reviver)
|
||||||
{
|
{
|
||||||
auto& vm = global_object.vm();
|
auto& vm = global_object.vm();
|
||||||
auto value = holder->get(name);
|
auto value = holder->get(name).value_or(js_undefined());
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
if (value.is_object()) {
|
if (value.is_object()) {
|
||||||
auto& value_object = value.as_object();
|
auto is_array = value.is_array(global_object);
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto& value_object = value.as_object();
|
||||||
auto process_property = [&](const PropertyName& key) {
|
auto process_property = [&](const PropertyName& key) {
|
||||||
auto element = internalize_json_property(global_object, &value_object, key, reviver);
|
auto element = internalize_json_property(global_object, &value_object, key, reviver);
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return;
|
return;
|
||||||
if (element.is_undefined()) {
|
if (element.is_undefined())
|
||||||
value_object.delete_property(key);
|
value_object.delete_property(key);
|
||||||
} else {
|
else
|
||||||
value_object.define_property(key, element, default_attributes, false);
|
value_object.define_property(key, element, default_attributes);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (value_object.is_array()) {
|
if (is_array) {
|
||||||
auto length = length_of_array_like(global_object, value_object);
|
auto length = length_of_array_like(global_object, value_object);
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
for (size_t i = 0; i < length; ++i) {
|
for (size_t i = 0; i < length; ++i) {
|
||||||
process_property(i);
|
process_property(i);
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (auto& entry : value_object.indexed_properties()) {
|
auto property_list = value_object.get_enumerable_own_property_names(Object::PropertyKind::Key);
|
||||||
auto value_and_attributes = entry.value_and_attributes(&value_object);
|
for (auto& property_name : property_list) {
|
||||||
if (!value_and_attributes.attributes.is_enumerable())
|
process_property(property_name.as_string().string());
|
||||||
continue;
|
|
||||||
process_property(entry.index());
|
|
||||||
if (vm.exception())
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
for (auto& [key, metadata] : value_object.shape().property_table_ordered()) {
|
|
||||||
if (!metadata.attributes.is_enumerable())
|
|
||||||
continue;
|
|
||||||
process_property(key);
|
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue