Pārlūkot izejas kodu

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

These will be used to parse StyleValues more intelligently.
Sam Atkins 2 gadi atpakaļ
vecāks
revīzija
9b61f79eae

+ 153 - 1
Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPropertyID.cpp

@@ -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())