summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy Flynn <trflynn89@pm.me>2021-09-05 23:05:16 -0400
committerLinus Groh <mail@linusgroh.de>2021-09-06 23:49:56 +0100
commit8e75e5fabba920de2e813677029a55eb79b1a06a (patch)
treedb7e93d1eb8dd9eef7e62f0dc20ec06ea468509d
parent4ad2159812014fafb94eb7978432a9df6f5cec90 (diff)
downloadserenity-8e75e5fabba920de2e813677029a55eb79b1a06a.zip
LibJS: Implement a nearly empty Intl.ListFormat object
This adds plumbing for the Intl.ListFormat object, constructor, and prototype.
-rw-r--r--Userland/Libraries/LibJS/CMakeLists.txt3
-rw-r--r--Userland/Libraries/LibJS/Forward.h1
-rw-r--r--Userland/Libraries/LibJS/Runtime/GlobalObject.cpp2
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/Intl.cpp2
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/ListFormat.cpp71
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/ListFormat.h53
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.cpp53
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.h28
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/ListFormatPrototype.cpp28
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/ListFormatPrototype.h22
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Intl/ListFormat/ListFormat.@@toStringTag.js3
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Intl/ListFormat/ListFormat.js13
12 files changed, 279 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/CMakeLists.txt b/Userland/Libraries/LibJS/CMakeLists.txt
index 7901a39830..831ec8ee90 100644
--- a/Userland/Libraries/LibJS/CMakeLists.txt
+++ b/Userland/Libraries/LibJS/CMakeLists.txt
@@ -77,6 +77,9 @@ set(SOURCES
Runtime/Intl/DisplayNamesConstructor.cpp
Runtime/Intl/DisplayNamesPrototype.cpp
Runtime/Intl/Intl.cpp
+ Runtime/Intl/ListFormat.cpp
+ Runtime/Intl/ListFormatConstructor.cpp
+ Runtime/Intl/ListFormatPrototype.cpp
Runtime/Intl/Locale.cpp
Runtime/Intl/LocaleConstructor.cpp
Runtime/Intl/LocalePrototype.cpp
diff --git a/Userland/Libraries/LibJS/Forward.h b/Userland/Libraries/LibJS/Forward.h
index a25a4eb32e..642cf47029 100644
--- a/Userland/Libraries/LibJS/Forward.h
+++ b/Userland/Libraries/LibJS/Forward.h
@@ -78,6 +78,7 @@
#define JS_ENUMERATE_INTL_OBJECTS \
__JS_ENUMERATE(DisplayNames, display_names, DisplayNamesPrototype, DisplayNamesConstructor) \
+ __JS_ENUMERATE(ListFormat, list_format, ListFormatPrototype, ListFormatConstructor) \
__JS_ENUMERATE(Locale, locale, LocalePrototype, LocaleConstructor)
#define JS_ENUMERATE_TEMPORAL_OBJECTS \
diff --git a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp
index 0eaf20a4f7..19ea8700aa 100644
--- a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp
+++ b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp
@@ -44,6 +44,8 @@
#include <LibJS/Runtime/Intl/DisplayNamesConstructor.h>
#include <LibJS/Runtime/Intl/DisplayNamesPrototype.h>
#include <LibJS/Runtime/Intl/Intl.h>
+#include <LibJS/Runtime/Intl/ListFormatConstructor.h>
+#include <LibJS/Runtime/Intl/ListFormatPrototype.h>
#include <LibJS/Runtime/Intl/LocaleConstructor.h>
#include <LibJS/Runtime/Intl/LocalePrototype.h>
#include <LibJS/Runtime/IteratorPrototype.h>
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/Intl.cpp b/Userland/Libraries/LibJS/Runtime/Intl/Intl.cpp
index e4d2873baf..325ab02c37 100644
--- a/Userland/Libraries/LibJS/Runtime/Intl/Intl.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Intl/Intl.cpp
@@ -9,6 +9,7 @@
#include <LibJS/Runtime/Intl/AbstractOperations.h>
#include <LibJS/Runtime/Intl/DisplayNamesConstructor.h>
#include <LibJS/Runtime/Intl/Intl.h>
+#include <LibJS/Runtime/Intl/ListFormatConstructor.h>
#include <LibJS/Runtime/Intl/LocaleConstructor.h>
namespace JS::Intl {
@@ -30,6 +31,7 @@ void Intl::initialize(GlobalObject& global_object)
u8 attr = Attribute::Writable | Attribute::Configurable;
define_direct_property(vm.names.DisplayNames, global_object.intl_display_names_constructor(), attr);
+ 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_native_function(vm.names.getCanonicalLocales, get_canonical_locales, 1, attr);
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/ListFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/ListFormat.cpp
new file mode 100644
index 0000000000..b03d74fa32
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Intl/ListFormat.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2021, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Runtime/Intl/ListFormat.h>
+
+namespace JS::Intl {
+
+// 13 ListFomat Objects, https://tc39.es/ecma402/#listformat-objects
+ListFormat::ListFormat(Object& prototype)
+ : Object(prototype)
+{
+}
+
+void ListFormat::set_type(StringView type)
+{
+ if (type == "conjunction"sv) {
+ m_type = Type::Conjunction;
+ } else if (type == "disjunction"sv) {
+ m_type = Type::Disjunction;
+ } else if (type == "unit"sv) {
+ m_type = Type::Unit;
+ } else {
+ VERIFY_NOT_REACHED();
+ }
+}
+
+StringView ListFormat::type_string() const
+{
+ switch (m_type) {
+ case Type::Conjunction:
+ return "conjunction"sv;
+ case Type::Disjunction:
+ return "disjunction"sv;
+ case Type::Unit:
+ return "unit"sv;
+ default:
+ VERIFY_NOT_REACHED();
+ }
+}
+
+void ListFormat::set_style(StringView style)
+{
+ if (style == "narrow"sv) {
+ m_style = Style::Narrow;
+ } else if (style == "short"sv) {
+ m_style = Style::Short;
+ } else if (style == "long"sv) {
+ m_style = Style::Long;
+ } else {
+ VERIFY_NOT_REACHED();
+ }
+}
+
+StringView ListFormat::style_string() const
+{
+ switch (m_style) {
+ case Style::Narrow:
+ return "narrow"sv;
+ case Style::Short:
+ return "short"sv;
+ case Style::Long:
+ return "long"sv;
+ default:
+ VERIFY_NOT_REACHED();
+ }
+}
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/ListFormat.h b/Userland/Libraries/LibJS/Runtime/Intl/ListFormat.h
new file mode 100644
index 0000000000..4224ba49ec
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Intl/ListFormat.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2021, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/String.h>
+#include <AK/StringView.h>
+#include <LibJS/Runtime/Object.h>
+
+namespace JS::Intl {
+
+class ListFormat final : public Object {
+ JS_OBJECT(ListFormat, Object);
+
+public:
+ enum class Type {
+ Invalid,
+ Conjunction,
+ Disjunction,
+ Unit,
+ };
+
+ enum class Style {
+ Invalid,
+ Narrow,
+ Short,
+ Long,
+ };
+
+ ListFormat(Object& prototype);
+ virtual ~ListFormat() override = default;
+
+ String const& locale() const { return m_locale; }
+ void set_locale(String locale) { m_locale = move(locale); }
+
+ Type type() const { return m_type; }
+ void set_type(StringView type);
+ StringView type_string() const;
+
+ Style style() const { return m_style; }
+ void set_style(StringView style);
+ StringView style_string() const;
+
+private:
+ String m_locale; // [[Locale]]
+ Type m_type { Type::Invalid }; // [[Type]]
+ Style m_style { Style::Invalid }; // [[Style]]
+};
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.cpp
new file mode 100644
index 0000000000..bca493f359
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2021, 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/ListFormat.h>
+#include <LibJS/Runtime/Intl/ListFormatConstructor.h>
+
+namespace JS::Intl {
+
+// 13.2 The Intl.ListFormat Constructor, https://tc39.es/ecma402/#sec-intl-listformat-constructor
+ListFormatConstructor::ListFormatConstructor(GlobalObject& global_object)
+ : NativeFunction(vm().names.ListFormat.as_string(), *global_object.function_prototype())
+{
+}
+
+void ListFormatConstructor::initialize(GlobalObject& global_object)
+{
+ NativeFunction::initialize(global_object);
+
+ auto& vm = this->vm();
+
+ // 13.3.1 Intl.ListFormat.prototype, https://tc39.es/ecma402/#sec-Intl.ListFormat.prototype
+ define_direct_property(vm.names.prototype, global_object.intl_list_format_prototype(), 0);
+ define_direct_property(vm.names.length, Value(0), Attribute::Configurable);
+}
+
+// 13.2.1 Intl.ListFormat ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-Intl.ListFormat
+Value ListFormatConstructor::call()
+{
+ // 1. If NewTarget is undefined, throw a TypeError exception.
+ vm().throw_exception<TypeError>(global_object(), ErrorType::ConstructorWithoutNew, "Intl.ListFormat");
+ return {};
+}
+
+// 13.2.1 Intl.ListFormat ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-Intl.ListFormat
+Value ListFormatConstructor::construct(FunctionObject& new_target)
+{
+ auto& vm = this->vm();
+ auto& global_object = this->global_object();
+
+ // 2. Let listFormat be ? OrdinaryCreateFromConstructor(NewTarget, "%ListFormat.prototype%", ยซ [[InitializedListFormat]], [[Locale]], [[Type]], [[Style]], [[Templates]] ยป).
+ auto* list_format = ordinary_create_from_constructor<ListFormat>(global_object, new_target, &GlobalObject::intl_list_format_prototype);
+ if (vm.exception())
+ return {};
+
+ return list_format;
+}
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.h b/Userland/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.h
new file mode 100644
index 0000000000..30703ed0e3
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Intl/ListFormatConstructor.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2021, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibJS/Runtime/NativeFunction.h>
+
+namespace JS::Intl {
+
+class ListFormatConstructor final : public NativeFunction {
+ JS_OBJECT(ListFormatConstructor, NativeFunction);
+
+public:
+ explicit ListFormatConstructor(GlobalObject&);
+ virtual void initialize(GlobalObject&) override;
+ virtual ~ListFormatConstructor() override = default;
+
+ virtual Value call() override;
+ virtual Value construct(FunctionObject& new_target) override;
+
+private:
+ virtual bool has_constructor() const override { return true; }
+};
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/ListFormatPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Intl/ListFormatPrototype.cpp
new file mode 100644
index 0000000000..6bde36f714
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Intl/ListFormatPrototype.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2021, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Runtime/GlobalObject.h>
+#include <LibJS/Runtime/Intl/ListFormatPrototype.h>
+
+namespace JS::Intl {
+
+// 13.4 Properties of the Intl.ListFormat Prototype Object, https://tc39.es/ecma402/#sec-properties-of-intl-listformat-prototype-object
+ListFormatPrototype::ListFormatPrototype(GlobalObject& global_object)
+ : Object(*global_object.object_prototype())
+{
+}
+
+void ListFormatPrototype::initialize(GlobalObject& global_object)
+{
+ Object::initialize(global_object);
+
+ auto& vm = this->vm();
+
+ // 13.4.2 Intl.ListFormat.prototype [ @@toStringTag ], https://tc39.es/ecma402/#sec-Intl.ListFormat.prototype-toStringTag
+ define_direct_property(*vm.well_known_symbol_to_string_tag(), js_string(vm, "Intl.ListFormat"), Attribute::Configurable);
+}
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/ListFormatPrototype.h b/Userland/Libraries/LibJS/Runtime/Intl/ListFormatPrototype.h
new file mode 100644
index 0000000000..6bcbe6cf2f
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/Intl/ListFormatPrototype.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2021, Tim Flynn <trflynn89@pm.me>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibJS/Runtime/Object.h>
+
+namespace JS::Intl {
+
+class ListFormatPrototype final : public Object {
+ JS_OBJECT(ListFormatPrototype, Object);
+
+public:
+ explicit ListFormatPrototype(GlobalObject&);
+ virtual void initialize(GlobalObject&) override;
+ virtual ~ListFormatPrototype() override = default;
+};
+
+}
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Intl/ListFormat/ListFormat.@@toStringTag.js b/Userland/Libraries/LibJS/Tests/builtins/Intl/ListFormat/ListFormat.@@toStringTag.js
new file mode 100644
index 0000000000..4a1c258316
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/builtins/Intl/ListFormat/ListFormat.@@toStringTag.js
@@ -0,0 +1,3 @@
+test("basic functionality", () => {
+ expect(Intl.ListFormat.prototype[Symbol.toStringTag]).toBe("Intl.ListFormat");
+});
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Intl/ListFormat/ListFormat.js b/Userland/Libraries/LibJS/Tests/builtins/Intl/ListFormat/ListFormat.js
new file mode 100644
index 0000000000..9f0ac10931
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/builtins/Intl/ListFormat/ListFormat.js
@@ -0,0 +1,13 @@
+describe("errors", () => {
+ test("called without new", () => {
+ expect(() => {
+ Intl.ListFormat();
+ }).toThrowWithMessage(TypeError, "Intl.ListFormat constructor must be called with 'new'");
+ });
+});
+
+describe("normal behavior", () => {
+ test("length is 0", () => {
+ expect(Intl.ListFormat).toHaveLength(0);
+ });
+});