LibWeb: Generate property_accepts_[identifier/type]() functions

These will be used to parse StyleValues more intelligently.
This commit is contained in:
Sam Atkins 2023-05-10 17:28:15 +01:00 committed by Andreas Kling
parent 6f3e48db57
commit 9b61f79eae

View file

@ -1,11 +1,12 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021-2022, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "GeneratorUtil.h"
#include <AK/GenericShorthands.h>
#include <AK/SourceGenerator.h>
#include <AK/StringBuilder.h>
#include <LibCore/ArgsParser.h>
@ -14,6 +15,11 @@
ErrorOr<void> generate_header_file(JsonObject& properties, Core::File& file);
ErrorOr<void> generate_implementation_file(JsonObject& properties, Core::File& file);
static bool type_name_is_enum(StringView type_name)
{
return !AK::first_is_one_of(type_name, "angle"sv, "color"sv, "frequency"sv, "image"sv, "integer"sv, "length"sv, "number"sv, "percentage"sv, "rect"sv, "resolution"sv, "string"sv, "time"sv, "url"sv);
}
ErrorOr<int> serenity_main(Main::Arguments arguments)
{
StringView generated_header_path;
@ -109,6 +115,26 @@ StringView string_from_property_id(PropertyID);
bool is_inherited_property(PropertyID);
ErrorOr<NonnullRefPtr<StyleValue>> property_initial_value(JS::Realm&, PropertyID);
enum class ValueType {
Angle,
Color,
FilterValueList,
Frequency,
Image,
Integer,
Length,
Number,
Paint,
Percentage,
Position,
Rect,
Resolution,
String,
Time,
Url,
};
bool property_accepts_type(PropertyID, ValueType);
bool property_accepts_identifier(PropertyID, ValueID);
bool property_accepts_value(PropertyID, StyleValue&);
size_t property_maximum_value_count(PropertyID);
@ -403,6 +429,132 @@ bool property_has_quirk(PropertyID property_id, Quirk quirk)
}
}
bool property_accepts_type(PropertyID property_id, ValueType value_type)
{
switch (property_id) {
)~~~");
properties.for_each_member([&](auto& name, auto& value) {
VERIFY(value.is_object());
auto& object = value.as_object();
if (auto maybe_valid_types = object.get_array("valid-types"sv); maybe_valid_types.has_value() && !maybe_valid_types->is_empty()) {
auto& valid_types = maybe_valid_types.value();
auto property_generator = generator.fork();
property_generator.set("name:titlecase", title_casify(name));
property_generator.append(R"~~~(
case PropertyID::@name:titlecase@: {
switch (value_type) {
)~~~");
bool did_output_accepted_type = false;
for (auto& type : valid_types.values()) {
VERIFY(type.is_string());
auto type_name = type.as_string().split_view(' ').first();
if (type_name_is_enum(type_name))
continue;
if (type_name == "angle") {
property_generator.appendln(" case ValueType::Angle:");
} else if (type_name == "color") {
property_generator.appendln(" case ValueType::Color:");
} else if (type_name == "frequency") {
property_generator.appendln(" case ValueType::Frequency:");
} else if (type_name == "image") {
property_generator.appendln(" case ValueType::Image:");
} else if (type_name == "integer") {
property_generator.appendln(" case ValueType::Integer:");
} else if (type_name == "length") {
property_generator.appendln(" case ValueType::Length:");
} else if (type_name == "number") {
property_generator.appendln(" case ValueType::Number:");
} else if (type_name == "percentage") {
property_generator.appendln(" case ValueType::Percentage:");
} else if (type_name == "rect") {
property_generator.appendln(" case ValueType::Rect:");
} else if (type_name == "resolution") {
property_generator.appendln(" case ValueType::Resolution:");
} else if (type_name == "string") {
property_generator.appendln(" case ValueType::String:");
} else if (type_name == "time") {
property_generator.appendln(" case ValueType::Time:");
} else if (type_name == "url") {
property_generator.appendln(" case ValueType::Url:");
} else {
VERIFY_NOT_REACHED();
}
did_output_accepted_type = true;
}
if (did_output_accepted_type)
property_generator.appendln(" return true;");
property_generator.append(R"~~~(
default:
return false;
}
}
)~~~");
}
});
generator.append(R"~~~(
default:
return false;
}
}
bool property_accepts_identifier(PropertyID property_id, ValueID identifier)
{
switch (property_id) {
)~~~");
properties.for_each_member([&](auto& name, auto& value) {
VERIFY(value.is_object());
auto& object = value.as_object();
auto property_generator = generator.fork();
property_generator.set("name:titlecase", title_casify(name));
property_generator.appendln(" case PropertyID::@name:titlecase@: {");
if (auto maybe_valid_identifiers = object.get_array("valid-identifiers"sv); maybe_valid_identifiers.has_value() && !maybe_valid_identifiers->is_empty()) {
property_generator.appendln(" switch (identifier) {");
auto& valid_identifiers = maybe_valid_identifiers.value();
for (auto& identifier : valid_identifiers.values()) {
auto identifier_generator = generator.fork();
identifier_generator.set("identifier:titlecase", title_casify(identifier.as_string()));
identifier_generator.appendln(" case ValueID::@identifier:titlecase@:");
}
property_generator.append(R"~~~(
return true;
default:
break;
}
)~~~");
}
if (auto maybe_valid_types = object.get_array("valid-types"sv); maybe_valid_types.has_value() && !maybe_valid_types->is_empty()) {
auto& valid_types = maybe_valid_types.value();
for (auto& valid_type : valid_types.values()) {
auto type_name = valid_type.as_string().split_view(' ').first();
if (!type_name_is_enum(type_name))
continue;
auto type_generator = generator.fork();
type_generator.set("type_name:snakecase", snake_casify(type_name));
type_generator.append(R"~~~(
if (value_id_to_@type_name:snakecase@(identifier).has_value())
return true;
)~~~");
}
}
property_generator.append(R"~~~(
return false;
}
)~~~");
});
generator.append(R"~~~(
default:
return false;
}
}
bool property_accepts_value(PropertyID property_id, StyleValue& style_value)
{
if (style_value.is_builtin())