Browse Source

LibJS: Implement a nearly empty Intl.PluralRules object

This adds plumbing for the Intl.PluralRules object, constructor, and
prototype.
Timothy Flynn 3 năm trước cách đây
mục cha
commit
0087804d10

+ 3 - 0
Userland/Libraries/LibJS/CMakeLists.txt

@@ -106,6 +106,9 @@ set(SOURCES
     Runtime/Intl/NumberFormatConstructor.cpp
     Runtime/Intl/NumberFormatFunction.cpp
     Runtime/Intl/NumberFormatPrototype.cpp
+    Runtime/Intl/PluralRules.cpp
+    Runtime/Intl/PluralRulesConstructor.cpp
+    Runtime/Intl/PluralRulesPrototype.cpp
     Runtime/Intl/RelativeTimeFormat.cpp
     Runtime/Intl/RelativeTimeFormatConstructor.cpp
     Runtime/Intl/RelativeTimeFormatPrototype.cpp

+ 1 - 0
Userland/Libraries/LibJS/Forward.h

@@ -73,6 +73,7 @@
     __JS_ENUMERATE(ListFormat, list_format, ListFormatPrototype, ListFormatConstructor)                  \
     __JS_ENUMERATE(Locale, locale, LocalePrototype, LocaleConstructor)                                   \
     __JS_ENUMERATE(NumberFormat, number_format, NumberFormatPrototype, NumberFormatConstructor)          \
+    __JS_ENUMERATE(PluralRules, plural_rules, PluralRulesPrototype, PluralRulesConstructor)              \
     __JS_ENUMERATE(RelativeTimeFormat, relative_time_format, RelativeTimeFormatPrototype, RelativeTimeFormatConstructor)
 
 #define JS_ENUMERATE_TEMPORAL_OBJECTS                                                                    \

+ 2 - 0
Userland/Libraries/LibJS/Runtime/GlobalObject.cpp

@@ -61,6 +61,8 @@
 #include <LibJS/Runtime/Intl/LocalePrototype.h>
 #include <LibJS/Runtime/Intl/NumberFormatConstructor.h>
 #include <LibJS/Runtime/Intl/NumberFormatPrototype.h>
+#include <LibJS/Runtime/Intl/PluralRulesConstructor.h>
+#include <LibJS/Runtime/Intl/PluralRulesPrototype.h>
 #include <LibJS/Runtime/Intl/RelativeTimeFormatConstructor.h>
 #include <LibJS/Runtime/Intl/RelativeTimeFormatPrototype.h>
 #include <LibJS/Runtime/IteratorPrototype.h>

+ 2 - 0
Userland/Libraries/LibJS/Runtime/Intl/Intl.cpp

@@ -13,6 +13,7 @@
 #include <LibJS/Runtime/Intl/ListFormatConstructor.h>
 #include <LibJS/Runtime/Intl/LocaleConstructor.h>
 #include <LibJS/Runtime/Intl/NumberFormatConstructor.h>
+#include <LibJS/Runtime/Intl/PluralRulesConstructor.h>
 #include <LibJS/Runtime/Intl/RelativeTimeFormatConstructor.h>
 
 namespace JS::Intl {
@@ -38,6 +39,7 @@ void Intl::initialize(GlobalObject& global_object)
     define_direct_property(vm.names.ListFormat, global_object.intl_list_format_constructor(), attr);
     define_direct_property(vm.names.Locale, global_object.intl_locale_constructor(), attr);
     define_direct_property(vm.names.NumberFormat, global_object.intl_number_format_constructor(), attr);
+    define_direct_property(vm.names.PluralRules, global_object.intl_plural_rules_constructor(), attr);
     define_direct_property(vm.names.RelativeTimeFormat, global_object.intl_relative_time_format_constructor(), attr);
 
     define_native_function(vm.names.getCanonicalLocales, get_canonical_locales, 1, attr);

+ 40 - 0
Userland/Libraries/LibJS/Runtime/Intl/PluralRules.cpp

@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Runtime/Intl/PluralRules.h>
+
+namespace JS::Intl {
+
+// 16 PluralRules Objects, https://tc39.es/ecma402/#pluralrules-objects
+PluralRules::PluralRules(Object& prototype)
+    : NumberFormatBase(prototype)
+{
+}
+
+void PluralRules::set_type(StringView type)
+{
+    if (type == "cardinal"sv) {
+        m_type = Type::Cardinal;
+    } else if (type == "ordinal"sv) {
+        m_type = Type::Ordinal;
+    } else {
+        VERIFY_NOT_REACHED();
+    }
+}
+
+StringView PluralRules::type_string() const
+{
+    switch (m_type) {
+    case Type::Cardinal:
+        return "cardinal"sv;
+    case Type::Ordinal:
+        return "ordinal"sv;
+    default:
+        VERIFY_NOT_REACHED();
+    }
+}
+
+}

+ 36 - 0
Userland/Libraries/LibJS/Runtime/Intl/PluralRules.h

@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2022, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/String.h>
+#include <AK/StringView.h>
+#include <LibJS/Runtime/Intl/NumberFormat.h>
+#include <LibJS/Runtime/Object.h>
+
+namespace JS::Intl {
+
+class PluralRules final : public NumberFormatBase {
+    JS_OBJECT(PluralRules, NumberFormatBase);
+
+public:
+    enum class Type {
+        Cardinal,
+        Ordinal,
+    };
+
+    PluralRules(Object& prototype);
+    virtual ~PluralRules() override = default;
+
+    Type type() const { return m_type; }
+    StringView type_string() const;
+    void set_type(StringView type);
+
+private:
+    Type m_type { Type::Cardinal }; // [[Type]]
+};
+
+}

+ 50 - 0
Userland/Libraries/LibJS/Runtime/Intl/PluralRulesConstructor.cpp

@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2022, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Runtime/AbstractOperations.h>
+#include <LibJS/Runtime/GlobalObject.h>
+#include <LibJS/Runtime/Intl/PluralRules.h>
+#include <LibJS/Runtime/Intl/PluralRulesConstructor.h>
+
+namespace JS::Intl {
+
+// 16.2 The Intl.PluralRules Constructor, https://tc39.es/ecma402/#sec-intl-pluralrules-constructor
+PluralRulesConstructor::PluralRulesConstructor(GlobalObject& global_object)
+    : NativeFunction(vm().names.PluralRules.as_string(), *global_object.function_prototype())
+{
+}
+
+void PluralRulesConstructor::initialize(GlobalObject& global_object)
+{
+    NativeFunction::initialize(global_object);
+
+    auto& vm = this->vm();
+
+    // 16.3.1 Intl.PluralRules.prototype, https://tc39.es/ecma402/#sec-intl.pluralrules.prototype
+    define_direct_property(vm.names.prototype, global_object.intl_plural_rules_prototype(), 0);
+    define_direct_property(vm.names.length, Value(0), Attribute::Configurable);
+}
+
+// 16.2.1 Intl.PluralRules ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-intl.pluralrules
+ThrowCompletionOr<Value> PluralRulesConstructor::call()
+{
+    // 1. If NewTarget is undefined, throw a TypeError exception.
+    return vm().throw_completion<TypeError>(global_object(), ErrorType::ConstructorWithoutNew, "Intl.PluralRules");
+}
+
+// 16.2.1 Intl.PluralRules ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-intl.pluralrules
+ThrowCompletionOr<Object*> PluralRulesConstructor::construct(FunctionObject& new_target)
+{
+    auto& global_object = this->global_object();
+
+    // 2. Let pluralRules be ? OrdinaryCreateFromConstructor(NewTarget, "%PluralRules.prototype%", « [[InitializedPluralRules]], [[Locale]], [[Type]], [[MinimumIntegerDigits]], [[MinimumFractionDigits]], [[MaximumFractionDigits]], [[MinimumSignificantDigits]], [[MaximumSignificantDigits]], [[RoundingType]] »).
+    auto* plural_rules = TRY(ordinary_create_from_constructor<PluralRules>(global_object, new_target, &GlobalObject::intl_plural_rules_prototype));
+
+    // 3. Return ? InitializePluralRules(pluralRules, locales, options).
+    return plural_rules;
+}
+
+}

+ 28 - 0
Userland/Libraries/LibJS/Runtime/Intl/PluralRulesConstructor.h

@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibJS/Runtime/NativeFunction.h>
+
+namespace JS::Intl {
+
+class PluralRulesConstructor final : public NativeFunction {
+    JS_OBJECT(PluralRulesConstructor, NativeFunction);
+
+public:
+    explicit PluralRulesConstructor(GlobalObject&);
+    virtual void initialize(GlobalObject&) override;
+    virtual ~PluralRulesConstructor() override = default;
+
+    virtual ThrowCompletionOr<Value> call() override;
+    virtual ThrowCompletionOr<Object*> construct(FunctionObject& new_target) override;
+
+private:
+    virtual bool has_constructor() const override { return true; }
+};
+
+}

+ 28 - 0
Userland/Libraries/LibJS/Runtime/Intl/PluralRulesPrototype.cpp

@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Runtime/GlobalObject.h>
+#include <LibJS/Runtime/Intl/PluralRulesPrototype.h>
+
+namespace JS::Intl {
+
+// 16.4 Properties of the Intl.PluralRules Prototype Object, https://tc39.es/ecma402/#sec-properties-of-intl-pluralrules-prototype-object
+PluralRulesPrototype::PluralRulesPrototype(GlobalObject& global_object)
+    : PrototypeObject(*global_object.object_prototype())
+{
+}
+
+void PluralRulesPrototype::initialize(GlobalObject& global_object)
+{
+    Object::initialize(global_object);
+
+    auto& vm = this->vm();
+
+    // 16.4.2 Intl.PluralRules.prototype [ @@toStringTag ], https://tc39.es/ecma402/#sec-intl.pluralrules.prototype-tostringtag
+    define_direct_property(*vm.well_known_symbol_to_string_tag(), js_string(vm, "Intl.PluralRules"sv), Attribute::Configurable);
+}
+
+}

+ 23 - 0
Userland/Libraries/LibJS/Runtime/Intl/PluralRulesPrototype.h

@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibJS/Runtime/Intl/PluralRules.h>
+#include <LibJS/Runtime/PrototypeObject.h>
+
+namespace JS::Intl {
+
+class PluralRulesPrototype final : public PrototypeObject<PluralRulesPrototype, PluralRules> {
+    JS_PROTOTYPE_OBJECT(PluralRulesPrototype, PluralRules, Intl.PluralRules);
+
+public:
+    explicit PluralRulesPrototype(GlobalObject&);
+    virtual void initialize(GlobalObject&) override;
+    virtual ~PluralRulesPrototype() override = default;
+};
+
+}

+ 3 - 0
Userland/Libraries/LibJS/Tests/builtins/Intl/PluralRules/PluralRules.@@toStringTag.js

@@ -0,0 +1,3 @@
+test("basic functionality", () => {
+    expect(Intl.PluralRules.prototype[Symbol.toStringTag]).toBe("Intl.PluralRules");
+});

+ 13 - 0
Userland/Libraries/LibJS/Tests/builtins/Intl/PluralRules/PluralRules.js

@@ -0,0 +1,13 @@
+describe("errors", () => {
+    test("called without new", () => {
+        expect(() => {
+            Intl.PluralRules();
+        }).toThrowWithMessage(TypeError, "Intl.PluralRules constructor must be called with 'new'");
+    });
+});
+
+describe("normal behavior", () => {
+    test("length is 0", () => {
+        expect(Intl.PluralRules).toHaveLength(0);
+    });
+});