Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/js/src/builtin/intl/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 15 kB image not shown  

Quelle  PluralRules.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


/* Implementation of the Intl.PluralRules proposal. */

#include "builtin/intl/PluralRules.h"

#include "mozilla/Assertions.h"
#include "mozilla/Casting.h"
#include "mozilla/intl/PluralRules.h"

#include "builtin/Array.h"
#include "builtin/intl/CommonFunctions.h"
#include "gc/GCContext.h"
#include "js/PropertySpec.h"
#include "vm/GlobalObject.h"
#include "vm/JSContext.h"
#include "vm/PlainObject.h"  // js::PlainObject
#include "vm/StringType.h"

#include "vm/JSObject-inl.h"
#include "vm/NativeObject-inl.h"

using namespace js;

using mozilla::AssertedCast;

const JSClassOps PluralRulesObject::classOps_ = {
    nullptr,                      // addProperty
    nullptr,                      // delProperty
    nullptr,                      // enumerate
    nullptr,                      // newEnumerate
    nullptr,                      // resolve
    nullptr,                      // mayResolve
    PluralRulesObject::finalize,  // finalize
    nullptr,                      // call
    nullptr,                      // construct
    nullptr,                      // trace
};

const JSClass PluralRulesObject::class_ = {
    "Intl.PluralRules",
    JSCLASS_HAS_RESERVED_SLOTS(PluralRulesObject::SLOT_COUNT) |
        JSCLASS_HAS_CACHED_PROTO(JSProto_PluralRules) |
        JSCLASS_FOREGROUND_FINALIZE,
    &PluralRulesObject::classOps_,
    &PluralRulesObject::classSpec_,
};

const JSClass& PluralRulesObject::protoClass_ = PlainObject::class_;

static bool pluralRules_toSource(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  args.rval().setString(cx->names().PluralRules);
  return true;
}

static const JSFunctionSpec pluralRules_static_methods[] = {
    JS_SELF_HOSTED_FN("supportedLocalesOf",
                      "Intl_PluralRules_supportedLocalesOf", 1, 0),
    JS_FS_END,
};

static const JSFunctionSpec pluralRules_methods[] = {
    JS_SELF_HOSTED_FN("resolvedOptions""Intl_PluralRules_resolvedOptions", 0,
                      0),
    JS_SELF_HOSTED_FN("select""Intl_PluralRules_select", 1, 0),
    JS_SELF_HOSTED_FN("selectRange""Intl_PluralRules_selectRange", 2, 0),
    JS_FN("toSource", pluralRules_toSource, 0, 0),
    JS_FS_END,
};

static const JSPropertySpec pluralRules_properties[] = {
    JS_STRING_SYM_PS(toStringTag, "Intl.PluralRules", JSPROP_READONLY),
    JS_PS_END,
};

static bool PluralRules(JSContext* cx, unsigned argc, Value* vp);

const ClassSpec PluralRulesObject::classSpec_ = {
    GenericCreateConstructor<PluralRules, 0, gc::AllocKind::FUNCTION>,
    GenericCreatePrototype<PluralRulesObject>,
    pluralRules_static_methods,
    nullptr,
    pluralRules_methods,
    pluralRules_properties,
    nullptr,
    ClassSpec::DontDefineConstructor,
};

/**
 * 16.1.1 Intl.PluralRules ( [ locales [ , options ] ] )
 *
 * ES2024 Intl draft rev 74ca7099f103d143431b2ea422ae640c6f43e3e6
 */

static bool PluralRules(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);

  // Step 1.
  if (!ThrowIfNotConstructing(cx, args, "Intl.PluralRules")) {
    return false;
  }

  // Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
  RootedObject proto(cx);
  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_PluralRules,
                                          &proto)) {
    return false;
  }

  Rooted<PluralRulesObject*> pluralRules(cx);
  pluralRules = NewObjectWithClassProto<PluralRulesObject>(cx, proto);
  if (!pluralRules) {
    return false;
  }

  HandleValue locales = args.get(0);
  HandleValue options = args.get(1);

  // Step 3.
  if (!intl::InitializeObject(cx, pluralRules,
                              cx->names().InitializePluralRules, locales,
                              options)) {
    return false;
  }

  args.rval().setObject(*pluralRules);
  return true;
}

void js::PluralRulesObject::finalize(JS::GCContext* gcx, JSObject* obj) {
  MOZ_ASSERT(gcx->onMainThread());

  auto* pluralRules = &obj->as<PluralRulesObject>();
  if (mozilla::intl::PluralRules* pr = pluralRules->getPluralRules()) {
    intl::RemoveICUCellMemory(
        gcx, obj, PluralRulesObject::UPluralRulesEstimatedMemoryUse);
    delete pr;
  }
}

static JSString* KeywordToString(mozilla::intl::PluralRules::Keyword keyword,
                                 JSContext* cx) {
  using Keyword = mozilla::intl::PluralRules::Keyword;
  switch (keyword) {
    case Keyword::Zero: {
      return cx->names().zero;
    }
    case Keyword::One: {
      return cx->names().one;
    }
    case Keyword::Two: {
      return cx->names().two;
    }
    case Keyword::Few: {
      return cx->names().few;
    }
    case Keyword::Many: {
      return cx->names().many;
    }
    case Keyword::Other: {
      return cx->names().other;
    }
  }
  MOZ_CRASH("Unexpected PluralRules keyword");
}

/**
 * Returns a new intl::PluralRules with the locale and type options of the given
 * PluralRules.
 */

static mozilla::intl::PluralRules* NewPluralRules(
    JSContext* cx, Handle<PluralRulesObject*> pluralRules) {
  RootedObject internals(cx, intl::GetInternalsObject(cx, pluralRules));
  if (!internals) {
    return nullptr;
  }

  RootedValue value(cx);

  if (!GetProperty(cx, internals, internals, cx->names().locale, &value)) {
    return nullptr;
  }
  UniqueChars locale = intl::EncodeLocale(cx, value.toString());
  if (!locale) {
    return nullptr;
  }

  using PluralRules = mozilla::intl::PluralRules;
  mozilla::intl::PluralRulesOptions options;

  if (!GetProperty(cx, internals, internals, cx->names().type, &value)) {
    return nullptr;
  }

  {
    JSLinearString* type = value.toString()->ensureLinear(cx);
    if (!type) {
      return nullptr;
    }

    if (StringEqualsLiteral(type, "ordinal")) {
      options.mPluralType = PluralRules::Type::Ordinal;
    } else {
      MOZ_ASSERT(StringEqualsLiteral(type, "cardinal"));
      options.mPluralType = PluralRules::Type::Cardinal;
    }
  }

  bool hasMinimumSignificantDigits;
  if (!HasProperty(cx, internals, cx->names().minimumSignificantDigits,
                   &hasMinimumSignificantDigits)) {
    return nullptr;
  }

  if (hasMinimumSignificantDigits) {
    if (!GetProperty(cx, internals, internals,
                     cx->names().minimumSignificantDigits, &value)) {
      return nullptr;
    }
    uint32_t minimumSignificantDigits = AssertedCast<uint32_t>(value.toInt32());

    if (!GetProperty(cx, internals, internals,
                     cx->names().maximumSignificantDigits, &value)) {
      return nullptr;
    }
    uint32_t maximumSignificantDigits = AssertedCast<uint32_t>(value.toInt32());

    options.mSignificantDigits = mozilla::Some(
        std::make_pair(minimumSignificantDigits, maximumSignificantDigits));
  }

  bool hasMinimumFractionDigits;
  if (!HasProperty(cx, internals, cx->names().minimumFractionDigits,
                   &hasMinimumFractionDigits)) {
    return nullptr;
  }

  if (hasMinimumFractionDigits) {
    if (!GetProperty(cx, internals, internals,
                     cx->names().minimumFractionDigits, &value)) {
      return nullptr;
    }
    uint32_t minimumFractionDigits = AssertedCast<uint32_t>(value.toInt32());

    if (!GetProperty(cx, internals, internals,
                     cx->names().maximumFractionDigits, &value)) {
      return nullptr;
    }
    uint32_t maximumFractionDigits = AssertedCast<uint32_t>(value.toInt32());

    options.mFractionDigits = mozilla::Some(
        std::make_pair(minimumFractionDigits, maximumFractionDigits));
  }

  if (!GetProperty(cx, internals, internals, cx->names().roundingPriority,
                   &value)) {
    return nullptr;
  }

  {
    JSLinearString* roundingPriority = value.toString()->ensureLinear(cx);
    if (!roundingPriority) {
      return nullptr;
    }

    using RoundingPriority =
        mozilla::intl::PluralRulesOptions::RoundingPriority;

    RoundingPriority priority;
    if (StringEqualsLiteral(roundingPriority, "auto")) {
      priority = RoundingPriority::Auto;
    } else if (StringEqualsLiteral(roundingPriority, "morePrecision")) {
      priority = RoundingPriority::MorePrecision;
    } else {
      MOZ_ASSERT(StringEqualsLiteral(roundingPriority, "lessPrecision"));
      priority = RoundingPriority::LessPrecision;
    }

    options.mRoundingPriority = priority;
  }

  if (!GetProperty(cx, internals, internals, cx->names().minimumIntegerDigits,
                   &value)) {
    return nullptr;
  }
  options.mMinIntegerDigits =
      mozilla::Some(AssertedCast<uint32_t>(value.toInt32()));

  if (!GetProperty(cx, internals, internals, cx->names().roundingIncrement,
                   &value)) {
    return nullptr;
  }
  options.mRoundingIncrement = AssertedCast<uint32_t>(value.toInt32());

  if (!GetProperty(cx, internals, internals, cx->names().roundingMode,
                   &value)) {
    return nullptr;
  }

  {
    JSLinearString* roundingMode = value.toString()->ensureLinear(cx);
    if (!roundingMode) {
      return nullptr;
    }

    using RoundingMode = mozilla::intl::PluralRulesOptions::RoundingMode;

    RoundingMode rounding;
    if (StringEqualsLiteral(roundingMode, "halfExpand")) {
      // "halfExpand" is the default mode, so we handle it first.
      rounding = RoundingMode::HalfExpand;
    } else if (StringEqualsLiteral(roundingMode, "ceil")) {
      rounding = RoundingMode::Ceil;
    } else if (StringEqualsLiteral(roundingMode, "floor")) {
      rounding = RoundingMode::Floor;
    } else if (StringEqualsLiteral(roundingMode, "expand")) {
      rounding = RoundingMode::Expand;
    } else if (StringEqualsLiteral(roundingMode, "trunc")) {
      rounding = RoundingMode::Trunc;
    } else if (StringEqualsLiteral(roundingMode, "halfCeil")) {
      rounding = RoundingMode::HalfCeil;
    } else if (StringEqualsLiteral(roundingMode, "halfFloor")) {
      rounding = RoundingMode::HalfFloor;
    } else if (StringEqualsLiteral(roundingMode, "halfTrunc")) {
      rounding = RoundingMode::HalfTrunc;
    } else {
      MOZ_ASSERT(StringEqualsLiteral(roundingMode, "halfEven"));
      rounding = RoundingMode::HalfEven;
    }

    options.mRoundingMode = rounding;
  }

  if (!GetProperty(cx, internals, internals, cx->names().trailingZeroDisplay,
                   &value)) {
    return nullptr;
  }

  {
    JSLinearString* trailingZeroDisplay = value.toString()->ensureLinear(cx);
    if (!trailingZeroDisplay) {
      return nullptr;
    }

    if (StringEqualsLiteral(trailingZeroDisplay, "auto")) {
      options.mStripTrailingZero = false;
    } else {
      MOZ_ASSERT(StringEqualsLiteral(trailingZeroDisplay, "stripIfInteger"));
      options.mStripTrailingZero = true;
    }
  }

  auto result = PluralRules::TryCreate(locale.get(), options);
  if (result.isErr()) {
    intl::ReportInternalError(cx, result.unwrapErr());
    return nullptr;
  }

  return result.unwrap().release();
}

static mozilla::intl::PluralRules* GetOrCreatePluralRules(
    JSContext* cx, Handle<PluralRulesObject*> pluralRules) {
  // Obtain a cached PluralRules object.
  mozilla::intl::PluralRules* pr = pluralRules->getPluralRules();
  if (pr) {
    return pr;
  }

  pr = NewPluralRules(cx, pluralRules);
  if (!pr) {
    return nullptr;
  }
  pluralRules->setPluralRules(pr);

  intl::AddICUCellMemory(pluralRules,
                         PluralRulesObject::UPluralRulesEstimatedMemoryUse);
  return pr;
}

/**
 * 16.5.3 ResolvePlural ( pluralRules, n )
 * 16.5.2 PluralRuleSelect ( locale, type, n, operands )
 *
 * ES2024 Intl draft rev 74ca7099f103d143431b2ea422ae640c6f43e3e6
 */

bool js::intl_SelectPluralRule(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  MOZ_ASSERT(args.length() == 2);

  // Steps 1-2.
  Rooted<PluralRulesObject*> pluralRules(
      cx, &args[0].toObject().as<PluralRulesObject>());

  // Step 3.
  double x = args[1].toNumber();

  // Steps 4-11.
  using PluralRules = mozilla::intl::PluralRules;
  PluralRules* pr = GetOrCreatePluralRules(cx, pluralRules);
  if (!pr) {
    return false;
  }

  auto keywordResult = pr->Select(x);
  if (keywordResult.isErr()) {
    intl::ReportInternalError(cx, keywordResult.unwrapErr());
    return false;
  }

  JSString* str = KeywordToString(keywordResult.unwrap(), cx);
  MOZ_ASSERT(str);

  args.rval().setString(str);
  return true;
}

/**
 * 16.5.5 ResolvePluralRange ( pluralRules, x, y )
 * 16.5.4 PluralRuleSelectRange ( locale, type, xp, yp )
 *
 * ES2024 Intl draft rev 74ca7099f103d143431b2ea422ae640c6f43e3e6
 */

bool js::intl_SelectPluralRuleRange(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  MOZ_ASSERT(args.length() == 3);

  // Steps 1-2.
  Rooted<PluralRulesObject*> pluralRules(
      cx, &args[0].toObject().as<PluralRulesObject>());

  // Steps 3-4.
  double x = args[1].toNumber();
  double y = args[2].toNumber();

  // Step 5.
  if (std::isnan(x)) {
    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                              JSMSG_NAN_NUMBER_RANGE, "start""PluralRules",
                              "selectRange");
    return false;
  }
  if (std::isnan(y)) {
    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                              JSMSG_NAN_NUMBER_RANGE, "end""PluralRules",
                              "selectRange");
    return false;
  }

  using PluralRules = mozilla::intl::PluralRules;
  PluralRules* pr = GetOrCreatePluralRules(cx, pluralRules);
  if (!pr) {
    return false;
  }

  // Steps 6-11.
  auto keywordResult = pr->SelectRange(x, y);
  if (keywordResult.isErr()) {
    intl::ReportInternalError(cx, keywordResult.unwrapErr());
    return false;
  }

  JSString* str = KeywordToString(keywordResult.unwrap(), cx);
  MOZ_ASSERT(str);

  args.rval().setString(str);
  return true;
}

bool js::intl_GetPluralCategories(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  MOZ_ASSERT(args.length() == 1);

  Rooted<PluralRulesObject*> pluralRules(
      cx, &args[0].toObject().as<PluralRulesObject>());

  using PluralRules = mozilla::intl::PluralRules;
  PluralRules* pr = GetOrCreatePluralRules(cx, pluralRules);
  if (!pr) {
    return false;
  }

  auto categoriesResult = pr->Categories();
  if (categoriesResult.isErr()) {
    intl::ReportInternalError(cx, categoriesResult.unwrapErr());
    return false;
  }
  auto categories = categoriesResult.unwrap();

  ArrayObject* res = NewDenseFullyAllocatedArray(cx, categories.size());
  if (!res) {
    return false;
  }
  res->setDenseInitializedLength(categories.size());

  size_t index = 0;
  for (auto keyword : {
           PluralRules::Keyword::Zero,
           PluralRules::Keyword::One,
           PluralRules::Keyword::Two,
           PluralRules::Keyword::Few,
           PluralRules::Keyword::Many,
           PluralRules::Keyword::Other,
       }) {
    if (categories.contains(keyword)) {
      JSString* str = KeywordToString(keyword, cx);
      MOZ_ASSERT(str);

      res->initDenseElement(index++, StringValue(str));
    }
  }
  MOZ_ASSERT(index == categories.size());

  args.rval().setObject(*res);
  return true;
}

Messung V0.5
C=94 H=97 G=95

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.