diff options
Diffstat (limited to 'Userland')
6 files changed, 102 insertions, 7 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/SegmentIterator.cpp b/Userland/Libraries/LibJS/Runtime/Intl/SegmentIterator.cpp index 2d848e8adb..ff67e68dba 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/SegmentIterator.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/SegmentIterator.cpp @@ -6,11 +6,12 @@ #include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/Intl/SegmentIterator.h> +#include <LibJS/Runtime/Intl/Segments.h> namespace JS::Intl { // 18.6.1 CreateSegmentIterator ( segmenter, string ), https://tc39.es/ecma402/#sec-createsegmentsobject -SegmentIterator* SegmentIterator::create(GlobalObject& global_object, Segmenter& segmenter, Utf16View const& string) +SegmentIterator* SegmentIterator::create(GlobalObject& global_object, Segmenter& segmenter, Utf16View const& string, Segments const& segments) { // 1. Let internalSlotsList be ยซ [[IteratingSegmenter]], [[IteratedString]], [[IteratedStringNextSegmentCodeUnitIndex]] ยป. // 2. Let iterator be ! OrdinaryObjectCreate(%SegmentIteratorPrototype%, internalSlotsList). @@ -18,14 +19,15 @@ SegmentIterator* SegmentIterator::create(GlobalObject& global_object, Segmenter& // 4. Set iterator.[[IteratedString]] to string. // 5. Set iterator.[[IteratedStringNextSegmentCodeUnitIndex]] to 0. // 6. Return iterator. - return global_object.heap().allocate<SegmentIterator>(global_object, global_object, segmenter, move(string)); + return global_object.heap().allocate<SegmentIterator>(global_object, global_object, segmenter, move(string), segments); } // 18.6 Segment Iterator Objects, https://tc39.es/ecma402/#sec-segment-iterator-objects -SegmentIterator::SegmentIterator(GlobalObject& global_object, Segmenter& segmenter, Utf16View const& string) +SegmentIterator::SegmentIterator(GlobalObject& global_object, Segmenter& segmenter, Utf16View const& string, Segments const& segments) : Object(*global_object.intl_segment_iterator_prototype()) , m_iterating_segmenter(segmenter) , m_iterated_string(string) + , m_segments(segments) { } @@ -33,6 +35,7 @@ void SegmentIterator::visit_edges(Cell::Visitor& visitor) { Base::visit_edges(visitor); visitor.visit(&m_iterating_segmenter); + visitor.visit(&m_segments); } } diff --git a/Userland/Libraries/LibJS/Runtime/Intl/SegmentIterator.h b/Userland/Libraries/LibJS/Runtime/Intl/SegmentIterator.h index 953141b352..6ee75de691 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/SegmentIterator.h +++ b/Userland/Libraries/LibJS/Runtime/Intl/SegmentIterator.h @@ -16,14 +16,17 @@ class SegmentIterator final : public Object { JS_OBJECT(SegmentIterator, Object); public: - static SegmentIterator* create(GlobalObject&, Segmenter&, Utf16View const&); + static SegmentIterator* create(GlobalObject&, Segmenter&, Utf16View const&, Segments const&); - SegmentIterator(GlobalObject&, Segmenter&, Utf16View const&); + SegmentIterator(GlobalObject&, Segmenter&, Utf16View const&, Segments const&); virtual ~SegmentIterator() override = default; Segmenter const& iterating_segmenter() const { return m_iterating_segmenter; } Utf16View const& iterated_string() const { return m_iterated_string; } size_t iterated_string_next_segment_code_unit_index() const { return m_iterated_string_next_segment_code_unit_index; } + void set_iterated_string_next_segment_code_unit_index(size_t index) { m_iterated_string_next_segment_code_unit_index = index; } + + Segments const& segments() { return m_segments; } private: virtual void visit_edges(Cell::Visitor&) override; @@ -31,6 +34,8 @@ private: Segmenter& m_iterating_segmenter; // [[IteratingSegmenter]] Utf16View m_iterated_string; // [[IteratedString]] size_t m_iterated_string_next_segment_code_unit_index { 0 }; // [[IteratedStringNextSegmentCodeUnitIndex]] + + Segments const& m_segments; }; } diff --git a/Userland/Libraries/LibJS/Runtime/Intl/SegmentIteratorPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Intl/SegmentIteratorPrototype.cpp index fc81407f0c..079874d437 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/SegmentIteratorPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/SegmentIteratorPrototype.cpp @@ -4,9 +4,11 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include <AK/Utf16View.h> #include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/Intl/SegmentIteratorPrototype.h> #include <LibJS/Runtime/Intl/Segments.h> +#include <LibJS/Runtime/IteratorOperations.h> namespace JS::Intl { @@ -24,6 +26,44 @@ void SegmentIteratorPrototype::initialize(GlobalObject& global_object) // 18.6.2.2 %SegmentIteratorPrototype% [ @@toStringTag ], https://tc39.es/ecma402/#sec-%segmentiteratorprototype%.@@tostringtag define_direct_property(*vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), "Segmenter String Iterator"), Attribute::Configurable); + + u8 attr = Attribute::Writable | Attribute::Configurable; + define_native_function(vm.names.next, next, 0, attr); +} + +// 18.6.2.1 %SegmentIteratorPrototype%.next ( ), https://tc39.es/ecma402/#sec-%segmentiteratorprototype%.next +JS_DEFINE_NATIVE_FUNCTION(SegmentIteratorPrototype::next) +{ + // 1. Let iterator be the this value. + // 2. Perform ? RequireInternalSlot(iterator, [[IteratingSegmenter]]). + auto* iterator = TRY(typed_this_object(global_object)); + + // 3. Let segmenter be iterator.[[IteratingSegmenter]]. + auto const& segmenter = iterator->iterating_segmenter(); + + // 4. Let string be iterator.[[IteratedString]]. + auto const& string = iterator->iterated_string(); + + // 5. Let startIndex be iterator.[[IteratedStringNextSegmentCodeUnitIndex]]. + auto start_index = iterator->iterated_string_next_segment_code_unit_index(); + + // 6. Let endIndex be ! FindBoundary(segmenter, string, startIndex, after). + auto end_index = find_boundary(segmenter, string, start_index, Direction::After, iterator->segments().boundaries_cache()); + + // 7. If endIndex is not finite, then + if (!Value(end_index).is_finite_number()) { + // a. Return ! CreateIterResultObject(undefined, true). + return create_iterator_result_object(global_object, js_undefined(), true); + } + + // 8. Set iterator.[[IteratedStringNextSegmentCodeUnitIndex]] to endIndex. + iterator->set_iterated_string_next_segment_code_unit_index(end_index); + + // 9. Let segmentData be ! CreateSegmentDataObject(segmenter, string, startIndex, endIndex). + auto* segment_data = create_segment_data_object(global_object, segmenter, string, start_index, end_index); + + // 10. Return ! CreateIterResultObject(segmentData, false). + return create_iterator_result_object(global_object, segment_data, false); } } diff --git a/Userland/Libraries/LibJS/Runtime/Intl/SegmentIteratorPrototype.h b/Userland/Libraries/LibJS/Runtime/Intl/SegmentIteratorPrototype.h index 1ac12ef7bc..333ffc814e 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/SegmentIteratorPrototype.h +++ b/Userland/Libraries/LibJS/Runtime/Intl/SegmentIteratorPrototype.h @@ -18,6 +18,9 @@ public: explicit SegmentIteratorPrototype(GlobalObject&); virtual void initialize(GlobalObject&) override; virtual ~SegmentIteratorPrototype() override = default; + +private: + JS_DECLARE_NATIVE_FUNCTION(next); }; } diff --git a/Userland/Libraries/LibJS/Runtime/Intl/SegmentsPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Intl/SegmentsPrototype.cpp index e48cdfb46e..c238c9a924 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/SegmentsPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/SegmentsPrototype.cpp @@ -75,7 +75,7 @@ JS_DEFINE_NATIVE_FUNCTION(SegmentsPrototype::symbol_iterator) auto string = segments->segments_string(); // 5. Return ! CreateSegmentIterator(segmenter, string). - return SegmentIterator::create(global_object, segmenter, string); + return SegmentIterator::create(global_object, segmenter, string, *segments); } } diff --git a/Userland/Libraries/LibJS/Tests/builtins/Intl/Segmenter/Segmenter.prototype.segment.js b/Userland/Libraries/LibJS/Tests/builtins/Intl/Segmenter/Segmenter.prototype.segment.js index 4c415c672b..3db51e4e46 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Intl/Segmenter/Segmenter.prototype.segment.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Intl/Segmenter/Segmenter.prototype.segment.js @@ -53,10 +53,54 @@ describe("correct behavior", () => { }); test("returns segments object segment iterator", () => { + const string = "hello friends!"; const segmenter = new Intl.Segmenter(); - const segments = segmenter.segment("hello friends!"); + const segments = segmenter.segment(string); expect(Object.getPrototypeOf(segments[Symbol.iterator]())[Symbol.toStringTag]).toBe( "Segmenter String Iterator" ); + + const graphemeSegmenter = new Intl.Segmenter("en", { granularity: "grapheme" }); + const graphemeSegments = graphemeSegmenter.segment(string); + let index = 0; + for (const segment of graphemeSegments) { + expect(segment.segment).toBe(string[index]); + expect(segment.index).toBe(index); + expect(segment.input).toBe(string); + expect(segment.isWordLike).toBeUndefined(); + index++; + } + expect(index).toBe(string.length); + + const wordSegmenter = new Intl.Segmenter("en", { granularity: "word" }); + const wordSegments = wordSegmenter.segment(string); + const expectedSegments = [ + { segment: "hello", index: 0, isWordLike: true }, + { segment: " ", index: 5, isWordLike: false }, + { segment: "friends", index: 6, isWordLike: true }, + { segment: "!", index: 13, isWordLike: false }, + ]; + index = 0; + for (const segment of wordSegments) { + console.log(JSON.stringify(segment)); + expect(segment.segment).toBe(expectedSegments[index].segment); + expect(segment.index).toBe(expectedSegments[index].index); + expect(segment.input).toBe(string); + // FIXME: expect(segment.isWordLike).toBe(expectedSegments[index].isWordLike); + index++; + } + expect(index).toBe(expectedSegments.length); + + const sentenceSegmenter = new Intl.Segmenter("en", { granularity: "sentence" }); + const sentenceSegments = sentenceSegmenter.segment(string); + index = 0; + for (const segment of sentenceSegments) { + expect(segment.segment).toBe(string); + expect(segment.index).toBe(0); + expect(segment.input).toBe(string); + expect(segment.isWordLike).toBeUndefined(); + index++; + } + expect(index).toBe(1); }); }); |