LibGUI: Make the GML parser a bit more fault-tolerant
It will now fail and whine in the debug log instead of asserting.
This commit is contained in:
parent
64ba41ea13
commit
6e0976d858
Notes:
sideshowbarker
2024-07-19 00:43:50 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/6e0976d8589
2 changed files with 46 additions and 18 deletions
|
@ -47,22 +47,26 @@ static void swallow_whitespace(GenericLexer& scanner)
|
|||
scanner.consume_while([](auto ch) { return isspace(ch); });
|
||||
}
|
||||
|
||||
static JsonValue parse_core_object(GenericLexer& scanner)
|
||||
static Optional<JsonValue> parse_core_object(GenericLexer& scanner)
|
||||
{
|
||||
JsonObject object;
|
||||
JsonArray children;
|
||||
|
||||
// '@Foo' means new Core::Object of class Foo
|
||||
if (!scanner.consume_specific('@'))
|
||||
ASSERT_NOT_REACHED();
|
||||
if (!scanner.consume_specific('@')) {
|
||||
dbgln("Expected '@'");
|
||||
return {};
|
||||
}
|
||||
|
||||
auto class_name = scanner.consume_while([](auto ch) { return is_valid_class_name_character(ch); });
|
||||
object.set("class", JsonValue(class_name));
|
||||
|
||||
swallow_whitespace(scanner);
|
||||
|
||||
if (!scanner.consume_specific('{'))
|
||||
ASSERT_NOT_REACHED();
|
||||
if (!scanner.consume_specific('{')) {
|
||||
dbgln("Expected '{{'");
|
||||
return {};
|
||||
}
|
||||
|
||||
swallow_whitespace(scanner);
|
||||
|
||||
|
@ -77,34 +81,57 @@ static JsonValue parse_core_object(GenericLexer& scanner)
|
|||
if (scanner.peek() == '@') {
|
||||
// It's a child object.
|
||||
auto value = parse_core_object(scanner);
|
||||
ASSERT(value.is_object());
|
||||
children.append(move(value));
|
||||
if (!value.has_value())
|
||||
return {};
|
||||
if (!value.value().is_object()) {
|
||||
dbgln("Expected child to be Core::Object");
|
||||
return {};
|
||||
}
|
||||
children.append(value.release_value());
|
||||
} else {
|
||||
// It's a property.
|
||||
auto property_name = scanner.consume_while([](auto ch) { return is_valid_property_name_character(ch); });
|
||||
swallow_whitespace(scanner);
|
||||
|
||||
ASSERT(!property_name.is_empty());
|
||||
if (property_name.is_empty()) {
|
||||
dbgln("Expected non-empty property name");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!scanner.consume_specific(':'))
|
||||
ASSERT_NOT_REACHED();
|
||||
if (!scanner.consume_specific(':')) {
|
||||
dbgln("Expected ':'");
|
||||
return {};
|
||||
}
|
||||
|
||||
swallow_whitespace(scanner);
|
||||
|
||||
JsonValue value;
|
||||
if (scanner.peek() == '@') {
|
||||
value = parse_core_object(scanner);
|
||||
ASSERT(value.is_object());
|
||||
auto parsed_value = parse_core_object(scanner);
|
||||
if (!parsed_value.has_value())
|
||||
return {};
|
||||
if (!parsed_value.value().is_object()) {
|
||||
dbgln("Expected property to be Core::Object");
|
||||
return {};
|
||||
}
|
||||
value = parsed_value.release_value();
|
||||
} else {
|
||||
auto value_string = scanner.consume_line();
|
||||
value = JsonValue::from_string(value_string).release_value();
|
||||
auto parsed_value = JsonValue::from_string(value_string);
|
||||
if (!parsed_value.has_value()) {
|
||||
dbgln("Expected property to be JSON value");
|
||||
return {};
|
||||
}
|
||||
value = parsed_value.release_value();
|
||||
}
|
||||
object.set(property_name, move(value));
|
||||
}
|
||||
}
|
||||
|
||||
if (!scanner.consume_specific('}'))
|
||||
ASSERT_NOT_REACHED();
|
||||
if (!scanner.consume_specific('}')) {
|
||||
dbgln("Expected '}'");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!children.is_empty())
|
||||
object.set("children", move(children));
|
||||
|
@ -117,10 +144,10 @@ JsonValue parse_gml(const StringView& string)
|
|||
GenericLexer scanner(string);
|
||||
auto root = parse_core_object(scanner);
|
||||
|
||||
if (root.is_null())
|
||||
if (!root.has_value())
|
||||
return JsonValue();
|
||||
|
||||
return root;
|
||||
return root.release_value();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -936,7 +936,8 @@ void Widget::set_override_cursor(Gfx::StandardCursor cursor)
|
|||
bool Widget::load_from_gml(const StringView& gml_string)
|
||||
{
|
||||
auto value = parse_gml(gml_string);
|
||||
ASSERT(value.is_object());
|
||||
if (!value.is_object())
|
||||
return false;
|
||||
return load_from_json(value.as_object());
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue