Browse Source

LibUnicode: Create a nearly empty generator for relative-time formatting

This sets up the generator plumbing to create the relative-time data
files. This data could probably be included in the date-time generator,
but that generator is large enough that I'd rather put this tangentially
related data in its own file.
Timothy Flynn 3 years ago
parent
commit
27eda77c97

+ 17 - 0
Meta/CMake/unicode_data.cmake

@@ -117,6 +117,9 @@ if (ENABLE_UNICODE_DATABASE_DOWNLOAD)
     set(UNICODE_NUMBER_FORMAT_HEADER LibUnicode/UnicodeNumberFormat.h)
     set(UNICODE_NUMBER_FORMAT_IMPLEMENTATION LibUnicode/UnicodeNumberFormat.cpp)
 
+    set(UNICODE_RELATIVE_TIME_FORMAT_HEADER LibUnicode/UnicodeRelativeTimeFormat.h)
+    set(UNICODE_RELATIVE_TIME_FORMAT_IMPLEMENTATION LibUnicode/UnicodeRelativeTimeFormat.cpp)
+
     set(UNICODE_META_TARGET_PREFIX LibUnicode_)
 
     if (CMAKE_CURRENT_BINARY_DIR MATCHES ".*/LibUnicode") # Serenity build.
@@ -132,6 +135,9 @@ if (ENABLE_UNICODE_DATABASE_DOWNLOAD)
         set(UNICODE_NUMBER_FORMAT_HEADER UnicodeNumberFormat.h)
         set(UNICODE_NUMBER_FORMAT_IMPLEMENTATION UnicodeNumberFormat.cpp)
 
+        set(UNICODE_RELATIVE_TIME_FORMAT_HEADER UnicodeRelativeTimeFormat.h)
+        set(UNICODE_RELATIVE_TIME_FORMAT_IMPLEMENTATION UnicodeRelativeTimeFormat.cpp)
+
         set(UNICODE_META_TARGET_PREFIX "")
     endif()
 
@@ -171,6 +177,15 @@ if (ENABLE_UNICODE_DATABASE_DOWNLOAD)
         "${UNICODE_NUMBER_FORMAT_IMPLEMENTATION}"
         arguments -r "${CLDR_CORE_PATH}" -n "${CLDR_NUMBERS_PATH}" -u "${CLDR_UNITS_PATH}"
     )
+    invoke_generator(
+        "UnicodeRelativeTimeFormat"
+        Lagom::GenerateUnicodeRelativeTimeFormat
+        "${CLDR_VERSION_FILE}"
+        "${UNICODE_META_TARGET_PREFIX}"
+        "${UNICODE_RELATIVE_TIME_FORMAT_HEADER}"
+        "${UNICODE_RELATIVE_TIME_FORMAT_IMPLEMENTATION}"
+        arguments -d "${CLDR_DATES_PATH}"
+    )
 
     set(UNICODE_DATA_SOURCES
         ${UNICODE_DATA_HEADER}
@@ -181,5 +196,7 @@ if (ENABLE_UNICODE_DATABASE_DOWNLOAD)
         ${UNICODE_LOCALE_IMPLEMENTATION}
         ${UNICODE_NUMBER_FORMAT_HEADER}
         ${UNICODE_NUMBER_FORMAT_IMPLEMENTATION}
+        ${UNICODE_RELATIVE_TIME_FORMAT_HEADER}
+        ${UNICODE_RELATIVE_TIME_FORMAT_IMPLEMENTATION}
     )
 endif()

+ 1 - 0
Meta/Lagom/Tools/CodeGenerators/LibUnicode/CMakeLists.txt

@@ -2,3 +2,4 @@ lagom_tool(GenerateUnicodeData SOURCES GenerateUnicodeData.cpp LIBS LagomMain)
 lagom_tool(GenerateUnicodeDateTimeFormat SOURCES GenerateUnicodeDateTimeFormat.cpp LIBS LagomMain LagomTimeZone)
 lagom_tool(GenerateUnicodeLocale SOURCES GenerateUnicodeLocale.cpp LIBS LagomMain)
 lagom_tool(GenerateUnicodeNumberFormat SOURCES GenerateUnicodeNumberFormat.cpp LIBS LagomMain)
+lagom_tool(GenerateUnicodeRelativeTimeFormat SOURCES GenerateUnicodeRelativeTimeFormat.cpp LIBS LagomMain)

+ 133 - 0
Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeRelativeTimeFormat.cpp

@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2022, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "GeneratorUtil.h"
+#include <AK/Format.h>
+#include <AK/HashMap.h>
+#include <AK/JsonObject.h>
+#include <AK/JsonParser.h>
+#include <AK/JsonValue.h>
+#include <AK/LexicalPath.h>
+#include <AK/SourceGenerator.h>
+#include <AK/String.h>
+#include <AK/StringBuilder.h>
+#include <LibCore/ArgsParser.h>
+#include <LibCore/DirIterator.h>
+#include <LibCore/File.h>
+
+using StringIndexType = u16;
+constexpr auto s_string_index_type = "u16"sv;
+
+struct Locale {
+};
+
+struct UnicodeLocaleData {
+    UniqueStringStorage<StringIndexType> unique_strings;
+    HashMap<String, Locale> locales;
+};
+
+static ErrorOr<void> parse_all_locales(String dates_path, UnicodeLocaleData& locale_data)
+{
+    auto dates_iterator = TRY(path_to_dir_iterator(move(dates_path)));
+
+    auto remove_variants_from_path = [&](String path) -> ErrorOr<String> {
+        auto parsed_locale = TRY(CanonicalLanguageID<StringIndexType>::parse(locale_data.unique_strings, LexicalPath::basename(path)));
+
+        StringBuilder builder;
+        builder.append(locale_data.unique_strings.get(parsed_locale.language));
+        if (auto script = locale_data.unique_strings.get(parsed_locale.script); !script.is_empty())
+            builder.appendff("-{}", script);
+        if (auto region = locale_data.unique_strings.get(parsed_locale.region); !region.is_empty())
+            builder.appendff("-{}", region);
+
+        return builder.build();
+    };
+
+    while (dates_iterator.has_next()) {
+        auto dates_path = TRY(next_path_from_dir_iterator(dates_iterator));
+        auto language = TRY(remove_variants_from_path(dates_path));
+
+        [[maybe_unused]] auto& locale = locale_data.locales.ensure(language);
+    }
+
+    return {};
+}
+
+static void generate_unicode_locale_header(Core::File& file, UnicodeLocaleData&)
+{
+    StringBuilder builder;
+    SourceGenerator generator { builder };
+
+    generator.append(R"~~~(
+#pragma once
+
+#include <LibUnicode/Forward.h>
+
+namespace Unicode {
+)~~~");
+
+    generator.append(R"~~~(
+}
+)~~~");
+
+    VERIFY(file.write(generator.as_string_view()));
+}
+
+static void generate_unicode_locale_implementation(Core::File& file, UnicodeLocaleData& locale_data)
+{
+    StringBuilder builder;
+    SourceGenerator generator { builder };
+    generator.set("string_index_type"sv, s_string_index_type);
+
+    generator.append(R"~~~(
+#include <AK/Array.h>
+#include <AK/StringView.h>
+#include <LibUnicode/UnicodeRelativeTimeFormat.h>
+
+namespace Unicode {
+)~~~");
+
+    locale_data.unique_strings.generate(generator);
+
+    generator.append(R"~~~(
+}
+)~~~");
+
+    VERIFY(file.write(generator.as_string_view()));
+}
+
+ErrorOr<int> serenity_main(Main::Arguments arguments)
+{
+    StringView generated_header_path;
+    StringView generated_implementation_path;
+    StringView dates_path;
+
+    Core::ArgsParser args_parser;
+    args_parser.add_option(generated_header_path, "Path to the Unicode locale header file to generate", "generated-header-path", 'h', "generated-header-path");
+    args_parser.add_option(generated_implementation_path, "Path to the Unicode locale implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path");
+    args_parser.add_option(dates_path, "Path to cldr-dates directory", "dates-path", 'd', "dates-path");
+    args_parser.parse(arguments);
+
+    auto open_file = [&](StringView path) -> ErrorOr<NonnullRefPtr<Core::File>> {
+        if (path.is_empty()) {
+            args_parser.print_usage(stderr, arguments.argv[0]);
+            return Error::from_string_literal("Must provide all command line options"sv);
+        }
+
+        return Core::File::open(path, Core::OpenMode::ReadWrite);
+    };
+
+    auto generated_header_file = TRY(open_file(generated_header_path));
+    auto generated_implementation_file = TRY(open_file(generated_implementation_path));
+
+    UnicodeLocaleData locale_data;
+    TRY(parse_all_locales(dates_path, locale_data));
+
+    generate_unicode_locale_header(generated_header_file, locale_data);
+    generate_unicode_locale_implementation(generated_implementation_file, locale_data);
+
+    return 0;
+}