Commit 8c3a6dad authored by André Bargull's avatar André Bargull
Browse files

Bug 1784375: Call LocaleParser::TryParse() with a new, empty Locale....

Bug 1784375: Call LocaleParser::TryParse() with a new, empty Locale. r=platform-i18n-reviewers,dminor

For this to work, we need to add a move-constructor to `Locale`, so that it's
possible to write `loc = {}`. (We need move instead of copy semantics, because
`Locale` has UniquePtr members.) All other `Locale` members except for
`LanguageTagSubtag` already support move semantics. Add copy-constructors to
`LanguageTagSubtag`, so defaulted move-constructor/assignment works for `Locale`.
`LanguageTagSubtag` gets copy- instead of move-constructors, because there isn't
a good reason to disallow copying when moving is allowed.

Also add extra assertions and comments to document the requirement that `TryParse`
expects a new, empty `Locale`.

Differential Revision: https://phabricator.services.mozilla.com/D154496
parent 8c56e722
Loading
Loading
Loading
Loading
+34 −1
Original line number Diff line number Diff line
@@ -39,6 +39,39 @@ TEST(IntlLocale, LocaleSettersAndGetters)
  ASSERT_EQ(locale2.Variants().length(), 0UL);
}

TEST(IntlLocale, LocaleMove)
{
  Locale locale;
  ASSERT_TRUE(
      LocaleParser::TryParse(
          MakeStringSpan(
              "fr-Latn-CA-fonipa-u-ca-gregory-t-es-AR-h0-hybrid-x-private"),
          locale)
          .isOk());

  ASSERT_TRUE(locale.Language().EqualTo("fr"));
  ASSERT_TRUE(locale.Script().EqualTo("Latn"));
  ASSERT_TRUE(locale.Region().EqualTo("CA"));
  ASSERT_EQ(locale.Variants()[0], MakeStringSpan("fonipa"));
  ASSERT_EQ(locale.Extensions()[0], MakeStringSpan("u-ca-gregory"));
  ASSERT_EQ(locale.Extensions()[1], MakeStringSpan("t-es-AR-h0-hybrid"));
  ASSERT_EQ(locale.GetUnicodeExtension().value(),
            MakeStringSpan("u-ca-gregory"));
  ASSERT_EQ(locale.PrivateUse().value(), MakeStringSpan("x-private"));

  Locale locale2 = std::move(locale);

  ASSERT_TRUE(locale2.Language().EqualTo("fr"));
  ASSERT_TRUE(locale2.Script().EqualTo("Latn"));
  ASSERT_TRUE(locale2.Region().EqualTo("CA"));
  ASSERT_EQ(locale2.Variants()[0], MakeStringSpan("fonipa"));
  ASSERT_EQ(locale2.Extensions()[0], MakeStringSpan("u-ca-gregory"));
  ASSERT_EQ(locale2.Extensions()[1], MakeStringSpan("t-es-AR-h0-hybrid"));
  ASSERT_EQ(locale2.GetUnicodeExtension().value(),
            MakeStringSpan("u-ca-gregory"));
  ASSERT_EQ(locale2.PrivateUse().value(), MakeStringSpan("x-private"));
}

TEST(IntlLocale, LocaleParser)
{
  const char* tags[] = {
@@ -51,8 +84,8 @@ TEST(IntlLocale, LocaleParser)
      "tuq",         "sr-ME",       "ng",         "klx",        "kk-Arab",
      "en-Cyrl",     "und-Cyrl-UK", "und-Arab",   "und-Arab-FO"};

  Locale locale;
  for (const auto* tag : tags) {
    Locale locale;
    ASSERT_TRUE(LocaleParser::TryParse(MakeStringSpan(tag), locale).isOk());
  }
}
+16 −0
Original line number Diff line number Diff line
@@ -1148,6 +1148,14 @@ Result<Ok, LocaleParser::ParserError> LocaleParser::InternalParseBaseName(

Result<Ok, LocaleParser::ParserError> LocaleParser::TryParse(
    mozilla::Span<const char> aLocale, Locale& aTag) {
  // |aTag| must be a new, empty Locale.
  MOZ_ASSERT(aTag.Language().Missing());
  MOZ_ASSERT(aTag.Script().Missing());
  MOZ_ASSERT(aTag.Region().Missing());
  MOZ_ASSERT(aTag.Variants().empty());
  MOZ_ASSERT(aTag.Extensions().empty());
  MOZ_ASSERT(aTag.PrivateUse().isNothing());

  // unicode_locale_id = unicode_language_id
  //                     extensions*
  //                     pu_extensions? ;
@@ -1271,6 +1279,14 @@ Result<Ok, LocaleParser::ParserError> LocaleParser::TryParse(

Result<Ok, LocaleParser::ParserError> LocaleParser::TryParseBaseName(
    Span<const char> aLocale, Locale& aTag) {
  // |aTag| must be a new, empty Locale.
  MOZ_ASSERT(aTag.Language().Missing());
  MOZ_ASSERT(aTag.Script().Missing());
  MOZ_ASSERT(aTag.Region().Missing());
  MOZ_ASSERT(aTag.Variants().empty());
  MOZ_ASSERT(aTag.Extensions().empty());
  MOZ_ASSERT(aTag.PrivateUse().isNothing());

  LocaleParser ts(aLocale);
  Token tok = ts.NextToken();

+16 −2
Original line number Diff line number Diff line
@@ -128,8 +128,16 @@ class LanguageTagSubtag final {
 public:
  LanguageTagSubtag() = default;

  LanguageTagSubtag(const LanguageTagSubtag&) = delete;
  LanguageTagSubtag& operator=(const LanguageTagSubtag&) = delete;
  LanguageTagSubtag(const LanguageTagSubtag& aOther) {
    std::copy_n(aOther.mChars, SubtagLength, mChars);
    mLength = aOther.mLength;
  }

  LanguageTagSubtag& operator=(const LanguageTagSubtag& aOther) {
    std::copy_n(aOther.mChars, SubtagLength, mChars);
    mLength = aOther.mLength;
    return *this;
  }

  size_t Length() const { return mLength; }
  bool Missing() const { return mLength == 0; }
@@ -245,6 +253,8 @@ class MOZ_STACK_CLASS Locale final {
  Locale() = default;
  Locale(const Locale&) = delete;
  Locale& operator=(const Locale&) = delete;
  Locale(Locale&&) = default;
  Locale& operator=(Locale&&) = default;

  template <class Vec>
  class SubtagIterator {
@@ -735,11 +745,15 @@ class MOZ_STACK_CLASS LocaleParser final {

 public:
  // Parse the input string as a locale.
  //
  // NOTE: |aTag| must be a new, empty Locale.
  static Result<Ok, ParserError> TryParse(Span<const char> aLocale,
                                          Locale& aTag);

  // Parse the input string as the base-name parts (language, script, region,
  // variants) of a locale.
  //
  // NOTE: |aTag| must be a new, empty Locale.
  static Result<Ok, ParserError> TryParseBaseName(Span<const char> aLocale,
                                                  Locale& aTag);

+3 −0
Original line number Diff line number Diff line
@@ -195,6 +195,9 @@ nsStaticAtom* nsLanguageAtomService::GetUncachedLanguageGroup(
      // If so, fix it up and re-try parsing.
      if (langStr.Contains('_')) {
        langStr.ReplaceChar('_', '-');

        // Throw away the partially parsed locale and re-start parsing.
        loc = {};
        result = LocaleParser::TryParse(langStr, loc);
      }
    }
+1 −1
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ p + p {
// https://en.wikipedia.org/wiki/Han_unification).
const doingTest = (location.search != "?ref");
const testStr = "今令免入全关具刃化外情才抵次海直真示神空者草蔥角道雇骨";
["zh-CN", "zh-HK", "zh-TW", "ja-JP", "ko-KR"].forEach((lang) => {
["zh-CN", "zh-HK", "zh-TW", "ja-JP", "ko-KR", "ja-JP-alalc97"].forEach((lang) => {
  let div = document.createElement("div");
  document.body.appendChild(div);
  // Create two layers of text, red and then green. In the test rendering, one layer