summaryrefslogtreecommitdiff
path: root/Libraries/LibJS/Runtime/JSONObject.cpp
diff options
context:
space:
mode:
authorMatthew Olsson <matthewcolsson@gmail.com>2020-06-10 23:30:36 -0700
committerAndreas Kling <kling@serenityos.org>2020-06-13 12:43:22 +0200
commitb155e64b67e555c44226c715d537ecf6c34e49f0 (patch)
tree50b55dee5733f104b04c642b281f800face9affb /Libraries/LibJS/Runtime/JSONObject.cpp
parente8e728454c5d436a02eaa1d24bc3afe357090c52 (diff)
downloadserenity-b155e64b67e555c44226c715d537ecf6c34e49f0.zip
LibJS: Add JSON.parse
Diffstat (limited to 'Libraries/LibJS/Runtime/JSONObject.cpp')
-rw-r--r--Libraries/LibJS/Runtime/JSONObject.cpp119
1 files changed, 116 insertions, 3 deletions
diff --git a/Libraries/LibJS/Runtime/JSONObject.cpp b/Libraries/LibJS/Runtime/JSONObject.cpp
index dae2b5af5f..f5747085c2 100644
--- a/Libraries/LibJS/Runtime/JSONObject.cpp
+++ b/Libraries/LibJS/Runtime/JSONObject.cpp
@@ -24,6 +24,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <AK/JsonParser.h>
+#include <AK/JsonObject.h>
+#include <AK/JsonArray.h>
#include <AK/StringBuilder.h>
#include <LibJS/Interpreter.h>
#include <LibJS/Runtime/Array.h>
@@ -39,7 +42,7 @@ JSONObject::JSONObject()
{
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function("stringify", stringify, 3, attr);
- define_native_function("parse", parse, 1, attr);
+ define_native_function("parse", parse, 2, attr);
}
JSONObject::~JSONObject()
@@ -365,9 +368,119 @@ String JSONObject::quote_json_string(String string)
return builder.to_string();
}
-Value JSONObject::parse(Interpreter&)
+Value JSONObject::parse(Interpreter& interpreter)
{
- return js_undefined();
+ if (!interpreter.argument_count())
+ return js_undefined();
+ auto string = interpreter.argument(0).to_string(interpreter);
+ if (interpreter.exception())
+ return {};
+ auto reviver = interpreter.argument(1);
+
+ auto json = JsonValue::from_string(string);
+ if (!json.has_value()) {
+ interpreter.throw_exception<SyntaxError>(ErrorType::JsonMalformed);
+ return {};
+ }
+ Value result = parse_json_value(interpreter, json.value());
+ if (reviver.is_function()) {
+ auto* holder_object = Object::create_empty(interpreter, interpreter.global_object());
+ holder_object->define_property(String::empty(), result);
+ if (interpreter.exception())
+ return {};
+ return internalize_json_property(interpreter, holder_object, String::empty(), reviver.as_function());
+ }
+ return result;
+}
+
+Value JSONObject::parse_json_value(Interpreter& interpreter, const JsonValue& value)
+{
+ if (value.is_object())
+ return Value(parse_json_object(interpreter, value.as_object()));
+ if (value.is_array())
+ return Value(parse_json_array(interpreter, value.as_array()));
+ if (value.is_null())
+ return js_null();
+#if !defined(KERNEL)
+ if (value.is_double())
+ return Value(value.as_double());
+#endif
+ if (value.is_number())
+ return Value(value.to_i32(0));
+ if (value.is_string())
+ return js_string(interpreter, value.to_string());
+ if (value.is_bool())
+ return Value(static_cast<bool>(value.as_bool()));
+ ASSERT_NOT_REACHED();
+}
+
+Object* JSONObject::parse_json_object(Interpreter& interpreter, const JsonObject& json_object)
+{
+ auto* object = Object::create_empty(interpreter, interpreter.global_object());
+ json_object.for_each_member([&object, &interpreter](String key, JsonValue value) {
+ object->put(key, parse_json_value(interpreter, value));
+ });
+ return object;
+}
+
+Array* JSONObject::parse_json_array(Interpreter& interpreter, const JsonArray& json_array)
+{
+ auto* array = Array::create(interpreter.global_object());
+ size_t index = 0;
+ json_array.for_each([&array, &interpreter, &index](JsonValue value) {
+ array->put(index++, parse_json_value(interpreter, value));
+ });
+ return array;
+}
+
+Value JSONObject::internalize_json_property(Interpreter& interpreter, Object* holder, const PropertyName& name, Function& reviver)
+{
+ auto value = holder->get(name);
+ if (interpreter.exception())
+ return {};
+ if (value.is_object()) {
+ auto& value_object = value.as_object();
+
+ auto process_property = [&](const PropertyName& key) {
+ auto element = internalize_json_property(interpreter, &value_object, key, reviver);
+ if (interpreter.exception())
+ return;
+ if (element.is_undefined()) {
+ value_object.delete_property(key);
+ } else {
+ value_object.define_property(key, element, default_attributes, false);
+ }
+ };
+
+ if (value_object.is_array()) {
+ auto length = length_of_array_like(interpreter, value);
+ for (size_t i = 0; i < length; ++i) {
+ process_property(i);
+ if (interpreter.exception())
+ return {};
+ }
+ } else {
+ for (auto& entry : value_object.indexed_properties()) {
+ auto value_and_attributes = entry.value_and_attributes(&value_object);
+ if (!value_and_attributes.attributes.is_enumerable())
+ continue;
+ process_property(entry.index());
+ if (interpreter.exception())
+ return {};
+ }
+ for (auto& [key, metadata] : value_object.shape().property_table_ordered()) {
+ if (!metadata.attributes.is_enumerable())
+ continue;
+ process_property(key);
+ if (interpreter.exception())
+ return {};
+ }
+ }
+ }
+ MarkedValueList arguments(interpreter.heap());
+ arguments.values().append(js_string(interpreter, name.to_string()));
+ arguments.values().append(value);
+ return interpreter.call(reviver, Value(holder), move(arguments));
}
}