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

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:
Andreas Kling 2020-12-20 14:28:41 +01:00
parent 64ba41ea13
commit 6e0976d858
2 changed files with 46 additions and 18 deletions

View file

@ -47,22 +47,26 @@ static void swallow_whitespace(GenericLexer& scanner)
scanner.consume_while([](auto ch) { return isspace(ch); }); 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; JsonObject object;
JsonArray children; JsonArray children;
// '@Foo' means new Core::Object of class Foo // '@Foo' means new Core::Object of class Foo
if (!scanner.consume_specific('@')) if (!scanner.consume_specific('@')) {
ASSERT_NOT_REACHED(); dbgln("Expected '@'");
return {};
}
auto class_name = scanner.consume_while([](auto ch) { return is_valid_class_name_character(ch); }); auto class_name = scanner.consume_while([](auto ch) { return is_valid_class_name_character(ch); });
object.set("class", JsonValue(class_name)); object.set("class", JsonValue(class_name));
swallow_whitespace(scanner); swallow_whitespace(scanner);
if (!scanner.consume_specific('{')) if (!scanner.consume_specific('{')) {
ASSERT_NOT_REACHED(); dbgln("Expected '{{'");
return {};
}
swallow_whitespace(scanner); swallow_whitespace(scanner);
@ -77,34 +81,57 @@ static JsonValue parse_core_object(GenericLexer& scanner)
if (scanner.peek() == '@') { if (scanner.peek() == '@') {
// It's a child object. // It's a child object.
auto value = parse_core_object(scanner); auto value = parse_core_object(scanner);
ASSERT(value.is_object()); if (!value.has_value())
children.append(move(value)); return {};
if (!value.value().is_object()) {
dbgln("Expected child to be Core::Object");
return {};
}
children.append(value.release_value());
} else { } else {
// It's a property. // It's a property.
auto property_name = scanner.consume_while([](auto ch) { return is_valid_property_name_character(ch); }); auto property_name = scanner.consume_while([](auto ch) { return is_valid_property_name_character(ch); });
swallow_whitespace(scanner); swallow_whitespace(scanner);
ASSERT(!property_name.is_empty()); if (property_name.is_empty()) {
dbgln("Expected non-empty property name");
return {};
}
if (!scanner.consume_specific(':')) if (!scanner.consume_specific(':')) {
ASSERT_NOT_REACHED(); dbgln("Expected ':'");
return {};
}
swallow_whitespace(scanner); swallow_whitespace(scanner);
JsonValue value; JsonValue value;
if (scanner.peek() == '@') { if (scanner.peek() == '@') {
value = parse_core_object(scanner); auto parsed_value = parse_core_object(scanner);
ASSERT(value.is_object()); 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 { } else {
auto value_string = scanner.consume_line(); 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)); object.set(property_name, move(value));
} }
} }
if (!scanner.consume_specific('}')) if (!scanner.consume_specific('}')) {
ASSERT_NOT_REACHED(); dbgln("Expected '}'");
return {};
}
if (!children.is_empty()) if (!children.is_empty())
object.set("children", move(children)); object.set("children", move(children));
@ -117,10 +144,10 @@ JsonValue parse_gml(const StringView& string)
GenericLexer scanner(string); GenericLexer scanner(string);
auto root = parse_core_object(scanner); auto root = parse_core_object(scanner);
if (root.is_null()) if (!root.has_value())
return JsonValue(); return JsonValue();
return root; return root.release_value();
} }
} }

View file

@ -936,7 +936,8 @@ void Widget::set_override_cursor(Gfx::StandardCursor cursor)
bool Widget::load_from_gml(const StringView& gml_string) bool Widget::load_from_gml(const StringView& gml_string)
{ {
auto value = parse_gml(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()); return load_from_json(value.as_object());
} }