diff --git a/AK/Utf8View.h b/AK/Utf8View.h index 0f95268855..7b650ad0bf 100644 --- a/AK/Utf8View.h +++ b/AK/Utf8View.h @@ -46,6 +46,7 @@ public: u32 operator*() const; int codepoint_length_in_bytes() const; + bool done() const { return !m_length; } private: Utf8CodepointIterator(const unsigned char*, int); diff --git a/Libraries/LibJS/CMakeLists.txt b/Libraries/LibJS/CMakeLists.txt index 4b7f4d2af0..7b121cd146 100644 --- a/Libraries/LibJS/CMakeLists.txt +++ b/Libraries/LibJS/CMakeLists.txt @@ -63,6 +63,8 @@ set(SOURCES Runtime/ScriptFunction.cpp Runtime/Shape.cpp Runtime/StringConstructor.cpp + Runtime/StringIterator.cpp + Runtime/StringIteratorPrototype.cpp Runtime/StringObject.cpp Runtime/StringPrototype.cpp Runtime/Symbol.cpp diff --git a/Libraries/LibJS/Forward.h b/Libraries/LibJS/Forward.h index f5b432376d..936c2a89dc 100644 --- a/Libraries/LibJS/Forward.h +++ b/Libraries/LibJS/Forward.h @@ -69,7 +69,8 @@ #define JS_ENUMERATE_ITERATOR_PROTOTYPES \ __JS_ENUMERATE(Iterator, iterator) \ - __JS_ENUMERATE(ArrayIterator, array_iterator) + __JS_ENUMERATE(ArrayIterator, array_iterator) \ + __JS_ENUMERATE(StringIterator, string_iterator) #define JS_ENUMERATE_BUILTIN_TYPES \ JS_ENUMERATE_NATIVE_OBJECTS \ diff --git a/Libraries/LibJS/Runtime/ArrayIterator.cpp b/Libraries/LibJS/Runtime/ArrayIterator.cpp index 6c01af00ab..501492b5ad 100644 --- a/Libraries/LibJS/Runtime/ArrayIterator.cpp +++ b/Libraries/LibJS/Runtime/ArrayIterator.cpp @@ -24,7 +24,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include #include diff --git a/Libraries/LibJS/Runtime/ArrayIteratorPrototype.cpp b/Libraries/LibJS/Runtime/ArrayIteratorPrototype.cpp index f6f2c263a7..bf81141c87 100644 --- a/Libraries/LibJS/Runtime/ArrayIteratorPrototype.cpp +++ b/Libraries/LibJS/Runtime/ArrayIteratorPrototype.cpp @@ -41,8 +41,8 @@ ArrayIteratorPrototype::ArrayIteratorPrototype(GlobalObject& global_object) void ArrayIteratorPrototype::initialize(Interpreter& interpreter, GlobalObject& global_object) { Object::initialize(interpreter, global_object); - define_native_function("next", next, 0, Attribute::Writable | Attribute::Configurable); + define_native_function("next", next, 0, Attribute::Configurable | Attribute::Writable); define_property(interpreter.well_known_symbol_to_string_tag(), js_string(interpreter, "Array Iterator"), Attribute::Configurable); } diff --git a/Libraries/LibJS/Runtime/GlobalObject.cpp b/Libraries/LibJS/Runtime/GlobalObject.cpp index 6096eb1eb7..1aad9a5eb7 100644 --- a/Libraries/LibJS/Runtime/GlobalObject.cpp +++ b/Libraries/LibJS/Runtime/GlobalObject.cpp @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include diff --git a/Libraries/LibJS/Runtime/Object.h b/Libraries/LibJS/Runtime/Object.h index ff325b845b..79b5093940 100644 --- a/Libraries/LibJS/Runtime/Object.h +++ b/Libraries/LibJS/Runtime/Object.h @@ -123,6 +123,7 @@ public: virtual bool is_number_object() const { return false; } virtual bool is_symbol_object() const { return false; } virtual bool is_bigint_object() const { return false; } + virtual bool is_string_iterator_object() const { return false; } virtual bool is_array_iterator_object() const { return false; } virtual const char* class_name() const override { return "Object"; } diff --git a/Libraries/LibJS/Runtime/StringIterator.cpp b/Libraries/LibJS/Runtime/StringIterator.cpp new file mode 100644 index 0000000000..44df424217 --- /dev/null +++ b/Libraries/LibJS/Runtime/StringIterator.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020, Matthew Olsson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +namespace JS { + +StringIterator* StringIterator::create(GlobalObject& global_object, String string) +{ + return global_object.heap().allocate(global_object, *global_object.string_iterator_prototype(), move(string)); +} + +StringIterator::StringIterator(Object& prototype, String string) + : Object(prototype) + , m_string(move(string)) + , m_iterator(Utf8View(m_string).begin()) +{ +} + +StringIterator::~StringIterator() +{ +} + +} diff --git a/Libraries/LibJS/Runtime/StringIterator.h b/Libraries/LibJS/Runtime/StringIterator.h new file mode 100644 index 0000000000..14fe7dac0d --- /dev/null +++ b/Libraries/LibJS/Runtime/StringIterator.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020, Matthew Olsson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +namespace JS { + +class StringIterator final : public Object { + JS_OBJECT(StringIterator, Object); + +public: + static StringIterator* create(GlobalObject&, String string); + + explicit StringIterator(Object& prototype, String string); + virtual ~StringIterator() override; + + Utf8CodepointIterator& iterator() { return m_iterator; } + bool done() const { return m_done; } + +private: + friend class StringIteratorPrototype; + + virtual bool is_string_iterator_object() const override { return true; } + + String m_string; + Utf8CodepointIterator m_iterator; + bool m_done { false }; +}; + +} diff --git a/Libraries/LibJS/Runtime/StringIteratorPrototype.cpp b/Libraries/LibJS/Runtime/StringIteratorPrototype.cpp new file mode 100644 index 0000000000..c0c3fd3dbf --- /dev/null +++ b/Libraries/LibJS/Runtime/StringIteratorPrototype.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020, Matthew Olsson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +namespace JS { + +StringIteratorPrototype::StringIteratorPrototype(GlobalObject& global_object) + : Object(*global_object.iterator_prototype()) +{ +} + +void StringIteratorPrototype::initialize(Interpreter& interpreter, GlobalObject& global_object) +{ + Object::initialize(interpreter, global_object); + + define_native_function("next", next, 0, Attribute::Configurable | Attribute::Writable); + define_property(interpreter.well_known_symbol_to_string_tag(), js_string(interpreter, "String Iterator"), Attribute::Configurable); +} + +StringIteratorPrototype::~StringIteratorPrototype() +{ +} + +JS_DEFINE_NATIVE_FUNCTION(StringIteratorPrototype::next) +{ + auto this_value = interpreter.this_value(global_object); + if (!this_value.is_object() || !this_value.as_object().is_string_iterator_object()) + return interpreter.throw_exception(ErrorType::NotA, "String Iterator"); + + auto& this_object = this_value.as_object(); + auto& iterator = static_cast(this_object); + if (iterator.done()) + return create_iterator_result_object(interpreter, global_object, js_undefined(), true); + + auto& utf8_iterator = iterator.iterator(); + + if (utf8_iterator.done()) { + iterator.m_done = true; + return create_iterator_result_object(interpreter, global_object, js_undefined(), true); + } + + StringBuilder builder; + builder.append_codepoint(*utf8_iterator); + ++utf8_iterator; + + return create_iterator_result_object(interpreter, global_object, js_string(interpreter, builder.to_string()), false); +} + +} diff --git a/Libraries/LibJS/Runtime/StringIteratorPrototype.h b/Libraries/LibJS/Runtime/StringIteratorPrototype.h new file mode 100644 index 0000000000..03674909fb --- /dev/null +++ b/Libraries/LibJS/Runtime/StringIteratorPrototype.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020, Matthew Olsson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +namespace JS { + +class StringIteratorPrototype final : public Object { + JS_OBJECT(StringIteratorPrototype, Object) + +public: + StringIteratorPrototype(GlobalObject&); + virtual void initialize(Interpreter&, GlobalObject&) override; + virtual ~StringIteratorPrototype() override; + +private: + JS_DECLARE_NATIVE_FUNCTION(next); +}; + +} diff --git a/Libraries/LibJS/Runtime/StringPrototype.cpp b/Libraries/LibJS/Runtime/StringPrototype.cpp index 29f06b6161..0a2e01118b 100644 --- a/Libraries/LibJS/Runtime/StringPrototype.cpp +++ b/Libraries/LibJS/Runtime/StringPrototype.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -87,6 +88,7 @@ void StringPrototype::initialize(Interpreter& interpreter, GlobalObject& global_ define_native_function("includes", includes, 1, attr); define_native_function("slice", slice, 2, attr); define_native_function("lastIndexOf", last_index_of, 1, attr); + define_native_function(interpreter.well_known_symbol_iterator(), symbol_iterator, 0, attr); } StringPrototype::~StringPrototype() @@ -428,4 +430,16 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::last_index_of) return Value(-1); } +JS_DEFINE_NATIVE_FUNCTION(StringPrototype::symbol_iterator) +{ + auto this_object = interpreter.this_value(global_object); + if (this_object.is_undefined() || this_object.is_null()) + return interpreter.throw_exception(ErrorType::ToObjectNullOrUndef); + + auto string = this_object.to_string(interpreter); + if (interpreter.exception()) + return {}; + return StringIterator::create(global_object, string); +} + } diff --git a/Libraries/LibJS/Runtime/StringPrototype.h b/Libraries/LibJS/Runtime/StringPrototype.h index 841b41b301..e44b5140fb 100644 --- a/Libraries/LibJS/Runtime/StringPrototype.h +++ b/Libraries/LibJS/Runtime/StringPrototype.h @@ -59,6 +59,8 @@ private: JS_DECLARE_NATIVE_FUNCTION(includes); JS_DECLARE_NATIVE_FUNCTION(slice); JS_DECLARE_NATIVE_FUNCTION(last_index_of); + + JS_DECLARE_NATIVE_FUNCTION(symbol_iterator); }; }