diff --git a/Meta/CMake/libweb_generators.cmake b/Meta/CMake/libweb_generators.cmake index db81b101285..bd5159114f4 100644 --- a/Meta/CMake/libweb_generators.cmake +++ b/Meta/CMake/libweb_generators.cmake @@ -95,9 +95,9 @@ function (generate_css_implementation) arguments -j "${LIBWEB_INPUT_FOLDER}/CSS/Units.json" ) - invoke_cpp_generator( + invoke_py_generator( "Keyword.cpp" - Lagom::GenerateCSSKeyword + "generate_libweb_css_keyword.py" "${LIBWEB_INPUT_FOLDER}/CSS/Keywords.json" "CSS/Keyword.h" "CSS/Keyword.cpp" diff --git a/Meta/Generators/generate_libweb_css_keyword.py b/Meta/Generators/generate_libweb_css_keyword.py new file mode 100644 index 00000000000..197888169e4 --- /dev/null +++ b/Meta/Generators/generate_libweb_css_keyword.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2020, Andreas Kling +# Copyright (c) 2022-2026, Sam Atkins +# Copyright (c) 2026-present, the Ladybird developers. +# +# SPDX-License-Identifier: BSD-2-Clause + +import argparse +import json +import sys + +from pathlib import Path +from typing import TextIO + +sys.path.append(str(Path(__file__).resolve().parent.parent)) + +from Utils.utils import title_casify +from Utils.utils import underlying_type_for_enum + + +def keyword_name(dashy_name: str) -> str: + if dashy_name == "-infinity": + return "NegativeInfinity" + return title_casify(dashy_name) + + +def write_header_file(out: TextIO, keyword_data: list) -> None: + underlying_type = underlying_type_for_enum(len(keyword_data)) + out.write(f""" +#pragma once + +#include +#include +#include + +namespace Web::CSS {{ + +enum class Keyword : {underlying_type} {{ + Invalid, +""") + + for name in keyword_data: + out.write(f""" + {keyword_name(name)}, +""") + + out.write(""" +}; + +WEB_API Optional keyword_from_string(StringView); +StringView string_from_keyword(Keyword); + +// https://www.w3.org/TR/css-values-4/#common-keywords +// https://drafts.csswg.org/css-cascade-4/#valdef-all-revert +inline bool is_css_wide_keyword(StringView name) +{ + return name.equals_ignoring_ascii_case("inherit"sv) + || name.equals_ignoring_ascii_case("initial"sv) + || name.equals_ignoring_ascii_case("revert"sv) + || name.equals_ignoring_ascii_case("revert-layer"sv) + || name.equals_ignoring_ascii_case("unset"sv); +} + +} + +""") + + +def write_implementation_file(out: TextIO, keyword_data: list) -> None: + out.write(""" +#include +#include +#include + +namespace Web::CSS { + +HashMap g_stringview_to_keyword_map { +""") + + for name in keyword_data: + out.write(f""" + {{"{name}"sv, Keyword::{keyword_name(name)}}}, +""") + + out.write(""" +}; + +Optional keyword_from_string(StringView string) +{ + return g_stringview_to_keyword_map.get(string); +} + +StringView string_from_keyword(Keyword keyword) { + switch (keyword) { +""") + + for name in keyword_data: + out.write(f""" + case Keyword::{keyword_name(name)}: + return "{name}"sv; + """) + + out.write(""" + default: + return "(invalid CSS::Keyword)"sv; + } +} + +} // namespace Web::CSS +""") + + +def main(): + parser = argparse.ArgumentParser(description="Generate CSS Keyword", add_help=False) + parser.add_argument("--help", action="help", help="Show this help message and exit") + parser.add_argument("-h", "--header", required=True, help="Path to the Keyword header file to generate") + parser.add_argument( + "-c", "--implementation", required=True, help="Path to the Keyword implementation file to generate" + ) + parser.add_argument("-j", "--json", required=True, help="Path to the JSON file to read from") + args = parser.parse_args() + + with open(args.json, "r", encoding="utf-8") as input_file: + keyword_data = json.load(input_file) + + with open(args.header, "w", encoding="utf-8") as output_file: + write_header_file(output_file, keyword_data) + + with open(args.implementation, "w", encoding="utf-8") as output_file: + write_implementation_file(output_file, keyword_data) + + +if __name__ == "__main__": + main() diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/CMakeLists.txt b/Meta/Lagom/Tools/CodeGenerators/LibWeb/CMakeLists.txt index f1b590aff92..1fbfc06bfc4 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/CMakeLists.txt +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/CMakeLists.txt @@ -1,7 +1,6 @@ set(SOURCES "") # avoid pulling SOURCES from parent scope lagom_tool(GenerateCSSDescriptors SOURCES GenerateCSSDescriptors.cpp LIBS LibMain) -lagom_tool(GenerateCSSKeyword SOURCES GenerateCSSKeyword.cpp LIBS LibMain) lagom_tool(GenerateCSSMathFunctions SOURCES GenerateCSSMathFunctions.cpp LIBS LibMain) lagom_tool(GenerateCSSMediaFeatureID SOURCES GenerateCSSMediaFeatureID.cpp LIBS LibMain) lagom_tool(GenerateCSSNumericFactoryMethods SOURCES GenerateCSSNumericFactoryMethods.cpp LIBS LibMain) diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSKeyword.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSKeyword.cpp deleted file mode 100644 index 0b52357caf5..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSKeyword.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2020, Andreas Kling - * Copyright (c) 2022-2024, Sam Atkins - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "GeneratorUtil.h" -#include -#include -#include -#include - -ErrorOr generate_header_file(JsonArray& keyword_data, Core::File& file); -ErrorOr generate_implementation_file(JsonArray& keyword_data, Core::File& file); - -ErrorOr ladybird_main(Main::Arguments arguments) -{ - StringView generated_header_path; - StringView generated_implementation_path; - StringView json_path; - - Core::ArgsParser args_parser; - args_parser.add_option(generated_header_path, "Path to the Keyword header file to generate", "generated-header-path", 'h', "generated-header-path"); - args_parser.add_option(generated_implementation_path, "Path to the Keyword implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path"); - args_parser.add_option(json_path, "Path to the JSON file to read from", "json-path", 'j', "json-path"); - args_parser.parse(arguments); - - auto json = TRY(read_entire_file_as_json(json_path)); - VERIFY(json.is_array()); - auto keyword_data = json.as_array(); - - auto generated_header_file = TRY(Core::File::open(generated_header_path, Core::File::OpenMode::Write)); - auto generated_implementation_file = TRY(Core::File::open(generated_implementation_path, Core::File::OpenMode::Write)); - - TRY(generate_header_file(keyword_data, *generated_header_file)); - TRY(generate_implementation_file(keyword_data, *generated_implementation_file)); - - return 0; -} - -static String keyword_name(String const& dashy_name) -{ - if (dashy_name == "-infinity"sv) - return "NegativeInfinity"_string; - return title_casify(dashy_name); -} - -ErrorOr generate_header_file(JsonArray& keyword_data, Core::File& file) -{ - StringBuilder builder; - SourceGenerator generator { builder }; - generator.set("keyword_underlying_type", underlying_type_for_enum(keyword_data.size())); - generator.append(R"~~~( -#pragma once - -#include -#include -#include - -namespace Web::CSS { - -enum class Keyword : @keyword_underlying_type@ { - Invalid, -)~~~"); - - keyword_data.for_each([&](auto& name) { - auto member_generator = generator.fork(); - member_generator.set("name:titlecase", keyword_name(name.as_string())); - - member_generator.append(R"~~~( - @name:titlecase@, -)~~~"); - }); - - generator.append(R"~~~( -}; - -WEB_API Optional keyword_from_string(StringView); -StringView string_from_keyword(Keyword); - -// https://www.w3.org/TR/css-values-4/#common-keywords -// https://drafts.csswg.org/css-cascade-4/#valdef-all-revert -inline bool is_css_wide_keyword(StringView name) -{ - return name.equals_ignoring_ascii_case("inherit"sv) - || name.equals_ignoring_ascii_case("initial"sv) - || name.equals_ignoring_ascii_case("revert"sv) - || name.equals_ignoring_ascii_case("revert-layer"sv) - || name.equals_ignoring_ascii_case("unset"sv); -} - -} - -)~~~"); - - TRY(file.write_until_depleted(generator.as_string_view().bytes())); - return {}; -} - -ErrorOr generate_implementation_file(JsonArray& keyword_data, Core::File& file) -{ - StringBuilder builder; - SourceGenerator generator { builder }; - - generator.append(R"~~~( -#include -#include -#include - -namespace Web::CSS { - -HashMap g_stringview_to_keyword_map { -)~~~"); - - keyword_data.for_each([&](auto& name) { - auto member_generator = generator.fork(); - member_generator.set("name", name.as_string()); - member_generator.set("name:titlecase", keyword_name(name.as_string())); - member_generator.append(R"~~~( - {"@name@"sv, Keyword::@name:titlecase@}, -)~~~"); - }); - - generator.append(R"~~~( -}; - -Optional keyword_from_string(StringView string) -{ - return g_stringview_to_keyword_map.get(string); -} - -StringView string_from_keyword(Keyword keyword) { - switch (keyword) { -)~~~"); - - keyword_data.for_each([&](auto& name) { - auto member_generator = generator.fork(); - member_generator.set("name", name.as_string()); - member_generator.set("name:titlecase", keyword_name(name.as_string())); - member_generator.append(R"~~~( - case Keyword::@name:titlecase@: - return "@name@"sv; - )~~~"); - }); - - generator.append(R"~~~( - default: - return "(invalid CSS::Keyword)"sv; - } -} - -} // namespace Web::CSS -)~~~"); - - TRY(file.write_until_depleted(generator.as_string_view().bytes())); - return {}; -}