AK: JsonParser improvements

- Parsing invalid JSON no longer asserts
    Instead of asserting when coming across malformed JSON,
    JsonParser::parse now returns an Optional<JsonValue>.
- Disallow trailing commas in JSON objects and arrays
- No longer parse 'undefined', as that is a purely JS thing
- No longer allow non-whitespace after anything consumed by the initial
  parse() call. Examples of things that were valid and no longer are:
    - undefineddfz
    - {"foo": 1}abcd
    - [1,2,3]4
- JsonObject.for_each_member now iterates in original insertion order
This commit is contained in:
Matthew Olsson 2020-06-10 21:40:27 -07:00 committed by Andreas Kling
parent 39576b2238
commit e8e728454c
Notes: sideshowbarker 2024-07-19 05:40:46 +09:00
29 changed files with 189 additions and 118 deletions

View file

@ -41,26 +41,32 @@ public:
~JsonObject() {} ~JsonObject() {}
JsonObject(const JsonObject& other) JsonObject(const JsonObject& other)
: m_members(other.m_members) : m_order(other.m_order)
, m_members(other.m_members)
{ {
} }
JsonObject(JsonObject&& other) JsonObject(JsonObject&& other)
: m_members(move(other.m_members)) : m_order(move(other.m_order))
, m_members(move(other.m_members))
{ {
} }
JsonObject& operator=(const JsonObject& other) JsonObject& operator=(const JsonObject& other)
{ {
if (this != &other) if (this != &other) {
m_members = other.m_members; m_members = other.m_members;
m_order = other.m_order;
}
return *this; return *this;
} }
JsonObject& operator=(JsonObject&& other) JsonObject& operator=(JsonObject&& other)
{ {
if (this != &other) if (this != &other) {
m_members = move(other.m_members); m_members = move(other.m_members);
m_order = move(other.m_order);
}
return *this; return *this;
} }
@ -70,7 +76,7 @@ public:
JsonValue get(const String& key) const JsonValue get(const String& key) const
{ {
auto* value = get_ptr(key); auto* value = get_ptr(key);
return value ? *value : JsonValue(JsonValue::Type::Undefined); return value ? *value : JsonValue(JsonValue::Type::Null);
} }
JsonValue get_or(const String& key, JsonValue alternative) const JsonValue get_or(const String& key, JsonValue alternative) const
@ -94,14 +100,17 @@ public:
void set(const String& key, JsonValue value) void set(const String& key, JsonValue value)
{ {
m_order.append(key);
m_members.set(key, move(value)); m_members.set(key, move(value));
} }
template<typename Callback> template<typename Callback>
void for_each_member(Callback callback) const void for_each_member(Callback callback) const
{ {
for (auto& it : m_members) for (size_t i = 0; i < m_order.size(); ++i) {
callback(it.key, it.value); auto property = m_order[i];
callback(property, m_members.get(property).value());
}
} }
template<typename Builder> template<typename Builder>
@ -113,6 +122,7 @@ public:
String to_string() const { return serialized<StringBuilder>(); } String to_string() const { return serialized<StringBuilder>(); }
private: private:
Vector<String> m_order;
HashMap<String, JsonValue> m_members; HashMap<String, JsonValue> m_members;
}; };
@ -193,9 +203,6 @@ inline void JsonValue::serialize(Builder& builder) const
case Type::UnsignedInt64: case Type::UnsignedInt64:
builder.appendf("%llu", as_u64()); builder.appendf("%llu", as_u64());
break; break;
case Type::Undefined:
builder.append("undefined");
break;
case Type::Null: case Type::Null:
builder.append("null"); builder.append("null");
break; break;

View file

@ -62,15 +62,16 @@ void JsonParser::consume_whitespace()
consume_while([](char ch) { return is_whitespace(ch); }); consume_while([](char ch) { return is_whitespace(ch); });
} }
void JsonParser::consume_specific(char expected_ch) bool JsonParser::consume_specific(char expected_ch)
{ {
char consumed_ch = consume(); char consumed_ch = consume();
ASSERT(consumed_ch == expected_ch); return consumed_ch == expected_ch;
} }
String JsonParser::consume_quoted_string() String JsonParser::consume_quoted_string()
{ {
consume_specific('"'); if (!consume_specific('"'))
return {};
Vector<char, 1024> buffer; Vector<char, 1024> buffer;
for (;;) { for (;;) {
@ -136,7 +137,8 @@ String JsonParser::consume_quoted_string()
break; break;
} }
} }
consume_specific('"'); if (!consume_specific('"'))
return {};
if (buffer.is_empty()) if (buffer.is_empty())
return String::empty(); return String::empty();
@ -151,55 +153,78 @@ String JsonParser::consume_quoted_string()
return last_string_starting_with_character; return last_string_starting_with_character;
} }
JsonObject JsonParser::parse_object() Optional<JsonValue> JsonParser::parse_object()
{ {
JsonObject object; JsonObject object;
consume_specific('{'); if (!consume_specific('{'))
return {};
for (;;) { for (;;) {
consume_whitespace(); consume_whitespace();
if (peek() == '}') if (peek() == '}')
break; break;
consume_whitespace(); consume_whitespace();
auto name = consume_quoted_string(); auto name = consume_quoted_string();
if (name.is_null())
return {};
consume_whitespace(); consume_whitespace();
consume_specific(':'); if (!consume_specific(':'))
return {};
consume_whitespace(); consume_whitespace();
auto value = parse(); auto value = parse_helper();
object.set(name, move(value)); if (!value.has_value())
return {};
object.set(name, move(value.value()));
consume_whitespace(); consume_whitespace();
if (peek() == '}') if (peek() == '}')
break; break;
consume_specific(','); if (!consume_specific(','))
return {};
consume_whitespace();
if (peek() == '}')
return {};
} }
consume_specific('}'); if (!consume_specific('}'))
return {};
return object; return object;
} }
JsonArray JsonParser::parse_array() Optional<JsonValue> JsonParser::parse_array()
{ {
JsonArray array; JsonArray array;
consume_specific('['); if (!consume_specific('['))
return {};
for (;;) { for (;;) {
consume_whitespace(); consume_whitespace();
if (peek() == ']') if (peek() == ']')
break; break;
array.append(parse()); auto element = parse_helper();
if (!element.has_value())
return {};
array.append(element.value());
consume_whitespace(); consume_whitespace();
if (peek() == ']') if (peek() == ']')
break; break;
consume_specific(','); if (!consume_specific(','))
return {};
consume_whitespace();
if (peek() == ']')
return {};
} }
consume_whitespace(); consume_whitespace();
consume_specific(']'); if (!consume_specific(']'))
return {};
return array; return array;
} }
JsonValue JsonParser::parse_string() Optional<JsonValue> JsonParser::parse_string()
{ {
return consume_quoted_string(); auto result = consume_quoted_string();
if (result.is_null())
return {};
return JsonValue(result);
} }
JsonValue JsonParser::parse_number() Optional<JsonValue> JsonParser::parse_number()
{ {
JsonValue value; JsonValue value;
Vector<char, 128> number_buffer; Vector<char, 128> number_buffer;
@ -235,7 +260,10 @@ JsonValue JsonParser::parse_number()
if (to_signed_result.has_value()) { if (to_signed_result.has_value()) {
whole = to_signed_result.value(); whole = to_signed_result.value();
} else { } else {
whole = number_string.to_int().value(); auto number = number_string.to_int();
if (!number.has_value())
return {};
whole = number.value();
} }
int fraction = fraction_string.to_uint().value(); int fraction = fraction_string.to_uint().value();
@ -252,7 +280,10 @@ JsonValue JsonParser::parse_number()
if (to_unsigned_result.has_value()) { if (to_unsigned_result.has_value()) {
value = JsonValue(to_unsigned_result.value()); value = JsonValue(to_unsigned_result.value());
} else { } else {
value = JsonValue(number_string.to_int().value()); auto number = number_string.to_int();
if (!number.has_value())
return {};
value = JsonValue(number.value());
} }
#ifndef KERNEL #ifndef KERNEL
} }
@ -261,37 +292,37 @@ JsonValue JsonParser::parse_number()
return value; return value;
} }
void JsonParser::consume_string(const char* str) bool JsonParser::consume_string(const char* str)
{ {
for (size_t i = 0, length = strlen(str); i < length; ++i) for (size_t i = 0, length = strlen(str); i < length; ++i) {
consume_specific(str[i]); if (!consume_specific(str[i]))
return false;
}
return true;
} }
JsonValue JsonParser::parse_true() Optional<JsonValue> JsonParser::parse_true()
{ {
consume_string("true"); if (!consume_string("true"))
return {};
return JsonValue(true); return JsonValue(true);
} }
JsonValue JsonParser::parse_false() Optional<JsonValue> JsonParser::parse_false()
{ {
consume_string("false"); if (!consume_string("false"))
return {};
return JsonValue(false); return JsonValue(false);
} }
JsonValue JsonParser::parse_null() Optional<JsonValue> JsonParser::parse_null()
{ {
consume_string("null"); if (!consume_string("null"))
return {};
return JsonValue(JsonValue::Type::Null); return JsonValue(JsonValue::Type::Null);
} }
JsonValue JsonParser::parse_undefined() Optional<JsonValue> JsonParser::parse_helper()
{
consume_string("undefined");
return JsonValue(JsonValue::Type::Undefined);
}
JsonValue JsonParser::parse()
{ {
consume_whitespace(); consume_whitespace();
auto type_hint = peek(); auto type_hint = peek();
@ -320,10 +351,19 @@ JsonValue JsonParser::parse()
return parse_true(); return parse_true();
case 'n': case 'n':
return parse_null(); return parse_null();
case 'u':
return parse_undefined();
} }
return JsonValue(); return {};
} }
Optional<JsonValue> JsonParser::parse() {
auto result = parse_helper();
if (!result.has_value())
return {};
consume_whitespace();
if (m_index != m_input.length())
return {};
return result;
}
} }

View file

@ -40,23 +40,24 @@ public:
{ {
} }
JsonValue parse(); Optional<JsonValue> parse();
private: private:
Optional<JsonValue> parse_helper();
char peek() const; char peek() const;
char consume(); char consume();
void consume_whitespace(); void consume_whitespace();
void consume_specific(char expected_ch); bool consume_specific(char expected_ch);
void consume_string(const char*); bool consume_string(const char*);
String consume_quoted_string(); String consume_quoted_string();
JsonArray parse_array(); Optional<JsonValue> parse_array();
JsonObject parse_object(); Optional<JsonValue> parse_object();
JsonValue parse_number(); Optional<JsonValue> parse_number();
JsonValue parse_string(); Optional<JsonValue> parse_string();
JsonValue parse_false(); Optional<JsonValue> parse_false();
JsonValue parse_true(); Optional<JsonValue> parse_true();
JsonValue parse_null(); Optional<JsonValue> parse_null();
JsonValue parse_undefined();
template<typename C> template<typename C>
void consume_while(C); void consume_while(C);

View file

@ -75,7 +75,7 @@ void JsonValue::copy_from(const JsonValue& other)
JsonValue::JsonValue(JsonValue&& other) JsonValue::JsonValue(JsonValue&& other)
{ {
m_type = exchange(other.m_type, Type::Undefined); m_type = exchange(other.m_type, Type::Null);
m_value.as_string = exchange(other.m_value.as_string, nullptr); m_value.as_string = exchange(other.m_value.as_string, nullptr);
} }
@ -83,7 +83,7 @@ JsonValue& JsonValue::operator=(JsonValue&& other)
{ {
if (this != &other) { if (this != &other) {
clear(); clear();
m_type = exchange(other.m_type, Type::Undefined); m_type = exchange(other.m_type, Type::Null);
m_value.as_string = exchange(other.m_value.as_string, nullptr); m_value.as_string = exchange(other.m_value.as_string, nullptr);
} }
return *this; return *this;
@ -247,11 +247,11 @@ void JsonValue::clear()
default: default:
break; break;
} }
m_type = Type::Undefined; m_type = Type::Null;
m_value.as_string = nullptr; m_value.as_string = nullptr;
} }
JsonValue JsonValue::from_string(const StringView& input) Optional<JsonValue> JsonValue::from_string(const StringView& input)
{ {
return JsonParser(input).parse(); return JsonParser(input).parse();
} }

View file

@ -37,7 +37,6 @@ namespace AK {
class JsonValue { class JsonValue {
public: public:
enum class Type { enum class Type {
Undefined,
Null, Null,
Int32, Int32,
UnsignedInt32, UnsignedInt32,
@ -52,7 +51,7 @@ public:
Object, Object,
}; };
static JsonValue from_string(const StringView&); static Optional<JsonValue> from_string(const StringView&);
explicit JsonValue(Type = Type::Null); explicit JsonValue(Type = Type::Null);
~JsonValue() { clear(); } ~JsonValue() { clear(); }
@ -188,7 +187,6 @@ public:
} }
bool is_null() const { return m_type == Type::Null; } bool is_null() const { return m_type == Type::Null; }
bool is_undefined() const { return m_type == Type::Undefined; }
bool is_bool() const { return m_type == Type::Bool; } bool is_bool() const { return m_type == Type::Bool; }
bool is_string() const { return m_type == Type::String; } bool is_string() const { return m_type == Type::String; }
bool is_i32() const { return m_type == Type::Int32; } bool is_i32() const { return m_type == Type::Int32; }
@ -246,7 +244,7 @@ private:
void clear(); void clear();
void copy_from(const JsonValue&); void copy_from(const JsonValue&);
Type m_type { Type::Undefined }; Type m_type { Type::Null };
union { union {
StringImpl* as_string { nullptr }; StringImpl* as_string { nullptr };

View file

@ -48,7 +48,7 @@ TEST_CASE(load_form)
fclose(fp); fclose(fp);
JsonValue form_json = JsonValue::from_string(builder.to_string()); JsonValue form_json = JsonValue::from_string(builder.to_string()).value();
EXPECT(form_json.is_object()); EXPECT(form_json.is_object());
@ -87,14 +87,14 @@ BENCHMARK_CASE(load_4chan_catalog)
auto json_string = builder.to_string(); auto json_string = builder.to_string();
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
JsonValue form_json = JsonValue::from_string(json_string); JsonValue form_json = JsonValue::from_string(json_string).value();
EXPECT(form_json.is_array()); EXPECT(form_json.is_array());
} }
} }
TEST_CASE(json_empty_string) TEST_CASE(json_empty_string)
{ {
auto json = JsonValue::from_string("\"\""); auto json = JsonValue::from_string("\"\"").value();
EXPECT_EQ(json.type(), JsonValue::Type::String); EXPECT_EQ(json.type(), JsonValue::Type::String);
EXPECT_EQ(json.as_string().is_null(), false); EXPECT_EQ(json.as_string().is_null(), false);
EXPECT_EQ(json.as_string().is_empty(), true); EXPECT_EQ(json.as_string().is_empty(), true);
@ -102,7 +102,7 @@ TEST_CASE(json_empty_string)
TEST_CASE(json_utf8_character) TEST_CASE(json_utf8_character)
{ {
auto json = JsonValue::from_string("\"\xc3\x84\""); auto json = JsonValue::from_string("\"\xc3\x84\"").value();
EXPECT_EQ(json.type(), JsonValue::Type::String); EXPECT_EQ(json.type(), JsonValue::Type::String);
EXPECT_EQ(json.as_string().is_null(), false); EXPECT_EQ(json.as_string().is_null(), false);
EXPECT_EQ(json.as_string().length(), size_t { 2 }); EXPECT_EQ(json.as_string().length(), size_t { 2 });

View file

@ -127,10 +127,11 @@ void DevicesModel::update()
if (!proc_devices->open(Core::IODevice::OpenMode::ReadOnly)) if (!proc_devices->open(Core::IODevice::OpenMode::ReadOnly))
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
auto json = JsonValue::from_string(proc_devices->read_all()).as_array(); auto json = JsonValue::from_string(proc_devices->read_all());
ASSERT(json.has_value());
m_devices.clear(); m_devices.clear();
json.for_each([this](auto& value) { json.value().as_array().for_each([this](auto& value) {
JsonObject device = value.as_object(); JsonObject device = value.as_object();
DeviceInfo device_info; DeviceInfo device_info;

View file

@ -98,7 +98,9 @@ void MemoryStatsWidget::refresh()
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
auto file_contents = proc_memstat->read_all(); auto file_contents = proc_memstat->read_all();
auto json = JsonValue::from_string(file_contents).as_object(); auto json_result = JsonValue::from_string(file_contents);
ASSERT(json_result.has_value());
auto json = json_result.value().as_object();
unsigned kmalloc_eternal_allocated = json.get("kmalloc_eternal_allocated").to_u32(); unsigned kmalloc_eternal_allocated = json.get("kmalloc_eternal_allocated").to_u32();
(void)kmalloc_eternal_allocated; (void)kmalloc_eternal_allocated;

View file

@ -46,7 +46,9 @@ int main(int argc, char** argv)
} }
auto file_contents = file->read_all(); auto file_contents = file->read_all();
auto json = JsonValue::from_string(file_contents); auto json_result = JsonValue::from_string(file_contents);
ASSERT(json_result.has_value());
auto json = json_result.value();
if (!json.is_object()) { if (!json.is_object()) {
fprintf(stderr, "Malformed input\n"); fprintf(stderr, "Malformed input\n");

View file

@ -167,11 +167,12 @@ void RemoteProcess::update()
dbg() << "Got data size " << length << " and read that many bytes"; dbg() << "Got data size " << length << " and read that many bytes";
auto json_value = JsonValue::from_string(data); auto json_value = JsonValue::from_string(data);
ASSERT(json_value.is_object()); ASSERT(json_value.has_value());
ASSERT(json_value.value().is_object());
dbg() << "Got JSON response " << json_value.to_string(); dbg() << "Got JSON response " << json_value.value().to_string();
auto& response = json_value.as_object(); auto& response = json_value.value().as_object();
auto response_type = response.get("type").as_string_or({}); auto response_type = response.get("type").as_string_or({});
if (response_type.is_null()) if (response_type.is_null())

View file

@ -172,12 +172,13 @@ OwnPtr<Profile> Profile::load_from_perfcore_file(const StringView& path)
} }
auto json = JsonValue::from_string(file->read_all()); auto json = JsonValue::from_string(file->read_all());
if (!json.is_object()) { ASSERT(json.has_value());
if (!json.value().is_object()) {
fprintf(stderr, "Invalid perfcore format (not a JSON object)\n"); fprintf(stderr, "Invalid perfcore format (not a JSON object)\n");
return nullptr; return nullptr;
} }
auto& object = json.as_object(); auto& object = json.value().as_object();
auto executable_path = object.get("executable").to_string(); auto executable_path = object.get("executable").to_string();
MappedFile elf_file(executable_path); MappedFile elf_file(executable_path);

View file

@ -389,14 +389,15 @@ void VBForm::load_from_file(const String& path)
auto file_contents = file->read_all(); auto file_contents = file->read_all();
auto form_json = JsonValue::from_string(file_contents); auto form_json = JsonValue::from_string(file_contents);
ASSERT(form_json.has_value());
if (!form_json.is_object()) { if (!form_json.value().is_object()) {
GUI::MessageBox::show(String::format("Could not parse '%s'", path.characters()), "Error", GUI::MessageBox::Type::Error, GUI::MessageBox::InputType::OK, window()); GUI::MessageBox::show(String::format("Could not parse '%s'", path.characters()), "Error", GUI::MessageBox::Type::Error, GUI::MessageBox::InputType::OK, window());
return; return;
} }
m_name = form_json.as_object().get("name").to_string(); m_name = form_json.value().as_object().get("name").to_string();
auto widgets = form_json.as_object().get("widgets").as_array(); auto widgets = form_json.value().as_object().get("widgets").as_array();
widgets.for_each([&](const JsonValue& widget_value) { widgets.for_each([&](const JsonValue& widget_value) {
auto& widget_object = widget_value.as_object(); auto& widget_object = widget_value.as_object();

View file

@ -105,13 +105,13 @@ public:
auto request = m_socket->read(length); auto request = m_socket->read(length);
auto request_json = JsonValue::from_string(request); auto request_json = JsonValue::from_string(request);
if (!request_json.is_object()) { if (!request_json.has_value() || !request_json.value().is_object()) {
dbg() << "RPC client sent invalid request"; dbg() << "RPC client sent invalid request";
shutdown(); shutdown();
return; return;
} }
handle_request(request_json.as_object()); handle_request(request_json.value().as_object());
}; };
} }
virtual ~RPCClient() override virtual ~RPCClient() override

View file

@ -48,7 +48,8 @@ HashMap<pid_t, Core::ProcessStatistics> ProcessStatisticsReader::get_all()
auto file_contents = file->read_all(); auto file_contents = file->read_all();
auto json = JsonValue::from_string(file_contents); auto json = JsonValue::from_string(file_contents);
json.as_array().for_each([&](auto& value) { ASSERT(json.has_value());
json.value().as_array().for_each([&](auto& value) {
const JsonObject& process_object = value.as_object(); const JsonObject& process_object = value.as_object();
Core::ProcessStatistics process; Core::ProcessStatistics process;

View file

@ -42,8 +42,9 @@ void JsonArrayModel::update()
auto json = JsonValue::from_string(file->read_all()); auto json = JsonValue::from_string(file->read_all());
ASSERT(json.is_array()); ASSERT(json.has_value());
m_array = json.as_array(); ASSERT(json.value().is_array());
m_array = json.value().as_array();
did_update(); did_update();
} }

View file

@ -48,7 +48,9 @@ Optional<CharacterMapData> CharacterMapFile::load_from_file(const String& file_n
} }
auto file_contents = file->read_all(); auto file_contents = file->read_all();
auto json = JsonValue::from_string(file_contents).as_object(); auto json_result = JsonValue::from_string(file_contents);
ASSERT(json_result.has_value());
auto json = json_result.value().as_object();
ByteBuffer map = read_map(json, "map"); ByteBuffer map = read_map(json, "map");
ByteBuffer shift_map = read_map(json, "shift_map"); ByteBuffer shift_map = read_map(json, "shift_map");

View file

@ -56,7 +56,8 @@ int main(int argc, char** argv)
return 1; return 1;
auto json = JsonValue::from_string(file->read_all()); auto json = JsonValue::from_string(file->read_all());
ASSERT(json.is_object()); ASSERT(json.has_value());
ASSERT(json.value().is_object());
out() << "#include <AK/Assertions.h>"; out() << "#include <AK/Assertions.h>";
out() << "#include <LibWeb/CSS/PropertyID.h>"; out() << "#include <LibWeb/CSS/PropertyID.h>";
@ -65,7 +66,7 @@ int main(int argc, char** argv)
out() << "PropertyID property_id_from_string(const StringView& string) {"; out() << "PropertyID property_id_from_string(const StringView& string) {";
json.as_object().for_each_member([&](auto& name, auto& value) { json.value().as_object().for_each_member([&](auto& name, auto& value) {
ASSERT(value.is_object()); ASSERT(value.is_object());
out() << " if (string.equals_ignoring_case(\"" << name << "\"))"; out() << " if (string.equals_ignoring_case(\"" << name << "\"))";
out() << " return PropertyID::" << title_casify(name) << ";"; out() << " return PropertyID::" << title_casify(name) << ";";
@ -77,7 +78,7 @@ int main(int argc, char** argv)
out() << "const char* string_from_property_id(PropertyID property_id) {"; out() << "const char* string_from_property_id(PropertyID property_id) {";
out() << " switch (property_id) {"; out() << " switch (property_id) {";
json.as_object().for_each_member([&](auto& name, auto& value) { json.value().as_object().for_each_member([&](auto& name, auto& value) {
ASSERT(value.is_object()); ASSERT(value.is_object());
out() << " case PropertyID::" << title_casify(name) << ":"; out() << " case PropertyID::" << title_casify(name) << ":";
out() << " return \"" << name << "\";"; out() << " return \"" << name << "\";";

View file

@ -56,7 +56,8 @@ int main(int argc, char** argv)
return 1; return 1;
auto json = JsonValue::from_string(file->read_all()); auto json = JsonValue::from_string(file->read_all());
ASSERT(json.is_object()); ASSERT(json.has_value());
ASSERT(json.value().is_object());
out() << "#pragma once"; out() << "#pragma once";
out() << "#include <AK/StringView.h>"; out() << "#include <AK/StringView.h>";
@ -67,7 +68,7 @@ int main(int argc, char** argv)
out() << "enum class PropertyID {"; out() << "enum class PropertyID {";
out() << " Invalid,"; out() << " Invalid,";
json.as_object().for_each_member([&](auto& name, auto& value) { json.value().as_object().for_each_member([&](auto& name, auto& value) {
ASSERT(value.is_object()); ASSERT(value.is_object());
out() << " " << title_casify(name) << ","; out() << " " << title_casify(name) << ",";
}); });

View file

@ -140,9 +140,10 @@ private:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
auto file_contents = proc_memstat->read_all(); auto file_contents = proc_memstat->read_all();
auto json = JsonValue::from_string(file_contents).as_object(); auto json = JsonValue::from_string(file_contents);
unsigned user_physical_allocated = json.get("user_physical_allocated").to_u32(); ASSERT(json.has_value());
unsigned user_physical_available = json.get("user_physical_available").to_u32(); unsigned user_physical_allocated = json.value().as_object().get("user_physical_allocated").to_u32();
unsigned user_physical_available = json.value().as_object().get("user_physical_available").to_u32();
allocated = (user_physical_allocated * 4096) / 1024; allocated = (user_physical_allocated * 4096) / 1024;
available = (user_physical_available * 4096) / 1024; available = (user_physical_available * 4096) / 1024;
} }

View file

@ -31,7 +31,8 @@
int main(int, char**) int main(int, char**)
{ {
auto value = JsonValue::from_string("{\"property\": \"value\"}"); auto value = JsonValue::from_string("{\"property\": \"value\"}");
printf("parsed: _%s_\n", value.to_string().characters()); ASSERT(value.has_value());
printf("object.property = '%s'\n", value.as_object().get("property").to_string().characters()); printf("parsed: _%s_\n", value.value().to_string().characters());
printf("object.property = '%s'\n", value.value().as_object().get("property").to_string().characters());
return 0; return 0;
} }

View file

@ -77,9 +77,10 @@ int main(int argc, char** argv)
} }
auto file_contents = file->read_all(); auto file_contents = file->read_all();
auto json = JsonValue::from_string(file_contents).as_array(); auto json = JsonValue::from_string(file_contents);
ASSERT(json.has_value());
Vector<InterfaceDescriptor> ifnames; Vector<InterfaceDescriptor> ifnames;
json.for_each([&ifnames](auto& value) { json.value().as_array().for_each([&ifnames](auto& value) {
auto if_object = value.as_object(); auto if_object = value.as_object();
if (if_object.get("class_name").to_string() == "LoopbackAdapter") if (if_object.get("class_name").to_string() == "LoopbackAdapter")

View file

@ -39,8 +39,9 @@ int main()
printf("Address HWaddress\n"); printf("Address HWaddress\n");
auto file_contents = file->read_all(); auto file_contents = file->read_all();
auto json = JsonValue::from_string(file_contents).as_array(); auto json = JsonValue::from_string(file_contents);
json.for_each([](auto& value) { ASSERT(json.has_value());
json.value().as_array().for_each([](auto& value) {
auto if_object = value.as_object(); auto if_object = value.as_object();
auto ip_address = if_object.get("ip_address").to_string(); auto ip_address = if_object.get("ip_address").to_string();

View file

@ -86,7 +86,9 @@ int main(int argc, char** argv)
} }
auto file_contents = file->read_all(); auto file_contents = file->read_all();
auto json = JsonValue::from_string(file_contents).as_array(); auto json_result = JsonValue::from_string(file_contents);
ASSERT(json_result.has_value());
auto json = json_result.value().as_array();
json.for_each([](auto& value) { json.for_each([](auto& value) {
auto fs_object = value.as_object(); auto fs_object = value.as_object();
auto fs = fs_object.get("class_name").to_string(); auto fs = fs_object.get("class_name").to_string();

View file

@ -74,6 +74,7 @@ int main(int argc, char** argv)
auto file_contents = file->read_all(); auto file_contents = file->read_all();
auto json = JsonValue::from_string(file_contents); auto json = JsonValue::from_string(file_contents);
ASSERT(json.has_value());
if (use_color) { if (use_color) {
color_name = "\033[33;1m"; color_name = "\033[33;1m";
@ -86,7 +87,7 @@ int main(int argc, char** argv)
} }
Vector<String> trail; Vector<String> trail;
print("json", json, trail); print("json", json.value(), trail);
return 0; return 0;
} }
@ -116,7 +117,6 @@ static void print(const String& name, const JsonValue& value, Vector<String>& tr
} }
switch (value.type()) { switch (value.type()) {
case JsonValue::Type::Null: case JsonValue::Type::Null:
case JsonValue::Type::Undefined:
printf("%s", color_null); printf("%s", color_null);
break; break;
case JsonValue::Type::Bool: case JsonValue::Type::Bool:

View file

@ -72,8 +72,9 @@ int main(int argc, char** argv)
} }
auto file_contents = file->read_all(); auto file_contents = file->read_all();
auto json = JsonValue::from_string(file_contents).as_array(); auto json = JsonValue::from_string(file_contents);
json.for_each([](auto& value) { ASSERT(json.has_value());
json.value().as_array().for_each([](auto& value) {
auto if_object = value.as_object(); auto if_object = value.as_object();
auto name = if_object.get("name").to_string(); auto name = if_object.get("name").to_string();

View file

@ -63,8 +63,9 @@ int main(int argc, char** argv)
auto file_contents = file->read_all(); auto file_contents = file->read_all();
auto json = JsonValue::from_string(file_contents); auto json = JsonValue::from_string(file_contents);
ASSERT(json.has_value());
print(json); print(json.value());
printf("\n"); printf("\n");
return 0; return 0;
@ -101,7 +102,7 @@ void print(const JsonValue& value, int indent)
printf("\033[35;1m"); printf("\033[35;1m");
else if (value.is_bool()) else if (value.is_bool())
printf("\033[32;1m"); printf("\033[32;1m");
else if (value.is_null() || value.is_undefined()) else if (value.is_null())
printf("\033[34;1m"); printf("\033[34;1m");
if (value.is_string()) if (value.is_string())
putchar('"'); putchar('"');

View file

@ -60,8 +60,9 @@ int main(int argc, char** argv)
printf("%4s %-10s\n", " ", "CPU0"); printf("%4s %-10s\n", " ", "CPU0");
auto file_contents = proc_interrupts->read_all(); auto file_contents = proc_interrupts->read_all();
auto json = JsonValue::from_string(file_contents).as_array(); auto json = JsonValue::from_string(file_contents);
json.for_each([](auto& value) { ASSERT(json.has_value());
json.value().as_array().for_each([](auto& value) {
auto handler = value.as_object(); auto handler = value.as_object();
auto purpose = handler.get("purpose").to_string(); auto purpose = handler.get("purpose").to_string();
auto interrupt = handler.get("interrupt_line").to_string(); auto interrupt = handler.get("interrupt_line").to_string();

View file

@ -69,8 +69,9 @@ int main(int argc, char** argv)
} }
auto file_contents = proc_pci->read_all(); auto file_contents = proc_pci->read_all();
auto json = JsonValue::from_string(file_contents).as_array(); auto json = JsonValue::from_string(file_contents);
json.for_each([db](auto& value) { ASSERT(json.has_value());
json.value().as_array().for_each([db](auto& value) {
auto dev = value.as_object(); auto dev = value.as_object();
auto seg = dev.get("seg").to_u32(); auto seg = dev.get("seg").to_u32();
auto bus = dev.get("bus").to_u32(); auto bus = dev.get("bus").to_u32();

View file

@ -149,9 +149,10 @@ bool print_mounts()
} }
auto content = df->read_all(); auto content = df->read_all();
auto json = JsonValue::from_string(content).as_array(); auto json = JsonValue::from_string(content);
ASSERT(json.has_value());
json.for_each([](auto& value) { json.value().as_array().for_each([](auto& value) {
auto fs_object = value.as_object(); auto fs_object = value.as_object();
auto class_name = fs_object.get("class_name").to_string(); auto class_name = fs_object.get("class_name").to_string();
auto mount_point = fs_object.get("mount_point").to_string(); auto mount_point = fs_object.get("mount_point").to_string();