From cfddcad7cfebcb61ff2b8dd52d94cd5950d5347a Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Thu, 15 Jul 2021 08:58:27 -0400 Subject: LibJS: Implement the RegExpStringIterator object This implementation closely follows the StringIterator object in that the abstract closure meant to be created in CreateRegExpStringIterator is instead unrolled into RegExpStringIterator.prototype.next. --- Userland/Libraries/LibJS/Runtime/GlobalObject.cpp | 1 + .../LibJS/Runtime/RegExpStringIterator.cpp | 27 +++++++ .../Libraries/LibJS/Runtime/RegExpStringIterator.h | 38 +++++++++ .../Runtime/RegExpStringIteratorPrototype.cpp | 89 ++++++++++++++++++++++ .../LibJS/Runtime/RegExpStringIteratorPrototype.h | 26 +++++++ 5 files changed, 181 insertions(+) create mode 100644 Userland/Libraries/LibJS/Runtime/RegExpStringIterator.cpp create mode 100644 Userland/Libraries/LibJS/Runtime/RegExpStringIterator.h create mode 100644 Userland/Libraries/LibJS/Runtime/RegExpStringIteratorPrototype.cpp create mode 100644 Userland/Libraries/LibJS/Runtime/RegExpStringIteratorPrototype.h (limited to 'Userland/Libraries/LibJS/Runtime') diff --git a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp index 57011398d6..3a1fad31d9 100644 --- a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp @@ -59,6 +59,7 @@ #include #include #include +#include #include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/RegExpStringIterator.cpp b/Userland/Libraries/LibJS/Runtime/RegExpStringIterator.cpp new file mode 100644 index 0000000000..573e7bb32e --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/RegExpStringIterator.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace JS { + +// 22.2.7.1 CreateRegExpStringIterator ( R, S, global, fullUnicode ), https://tc39.es/ecma262/#sec-createregexpstringiterator +RegExpStringIterator* RegExpStringIterator::create(GlobalObject& global_object, Object& regexp_object, String string, bool global, bool unicode) +{ + return global_object.heap().allocate(global_object, *global_object.regexp_string_iterator_prototype(), regexp_object, move(string), global, unicode); +} + +RegExpStringIterator::RegExpStringIterator(Object& prototype, Object& regexp_object, String string, bool global, bool unicode) + : Object(prototype) + , m_regexp_object(regexp_object) + , m_string(move(string)) + , m_global(global) + , m_unicode(unicode) +{ +} + +} diff --git a/Userland/Libraries/LibJS/Runtime/RegExpStringIterator.h b/Userland/Libraries/LibJS/Runtime/RegExpStringIterator.h new file mode 100644 index 0000000000..876dd796a9 --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/RegExpStringIterator.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace JS { + +class RegExpStringIterator final : public Object { + JS_OBJECT(RegExpStringIterator, Object); + +public: + static RegExpStringIterator* create(GlobalObject&, Object& regexp_object, String string, bool global, bool unicode); + + explicit RegExpStringIterator(Object& prototype, Object& regexp_object, String string, bool global, bool unicode); + virtual ~RegExpStringIterator() override = default; + + Object& regexp_object() { return m_regexp_object; } + String const& string() const { return m_string; } + bool global() const { return m_global; } + bool unicode() const { return m_unicode; } + + bool done() const { return m_done; } + void set_done() { m_done = true; } + +private: + Object& m_regexp_object; + String m_string; + bool m_global { false }; + bool m_unicode { false }; + bool m_done { false }; +}; + +} diff --git a/Userland/Libraries/LibJS/Runtime/RegExpStringIteratorPrototype.cpp b/Userland/Libraries/LibJS/Runtime/RegExpStringIteratorPrototype.cpp new file mode 100644 index 0000000000..9b61656d20 --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/RegExpStringIteratorPrototype.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2021, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +namespace JS { + +RegExpStringIteratorPrototype::RegExpStringIteratorPrototype(GlobalObject& global_object) + : Object(*global_object.iterator_prototype()) +{ +} + +void RegExpStringIteratorPrototype::initialize(GlobalObject& global_object) +{ + Object::initialize(global_object); + auto& vm = this->vm(); + + u8 attr = Attribute::Writable | Attribute::Configurable; + define_native_function(vm.names.next, next, 0, attr); + + // 22.2.7.2.2 %RegExpStringIteratorPrototype% [ @@toStringTag ], https://tc39.es/ecma262/#sec-%regexpstringiteratorprototype%-@@tostringtag + define_direct_property(*vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), "RegExp String Iterator"), Attribute::Configurable); +} + +// 22.2.7.2.1 %RegExpStringIteratorPrototype%.next ( ), https://tc39.es/ecma262/#sec-%regexpstringiteratorprototype%.next +JS_DEFINE_NATIVE_FUNCTION(RegExpStringIteratorPrototype::next) +{ + // For details, see the 'closure' of: https://tc39.es/ecma262/#sec-createregexpstringiterator + auto this_value = vm.this_value(global_object); + if (!this_value.is_object() || !is(this_value.as_object())) { + vm.throw_exception(global_object, ErrorType::NotA, "RegExp String Iterator"); + return {}; + } + + auto& iterator = static_cast(this_value.as_object()); + if (iterator.done()) + return create_iterator_result_object(global_object, js_undefined(), true); + + auto match = regexp_exec(global_object, iterator.regexp_object(), iterator.string()); + if (vm.exception()) + return {}; + + if (match.is_null()) { + iterator.set_done(); + return create_iterator_result_object(global_object, js_undefined(), true); + } + + if (!iterator.global()) { + iterator.set_done(); + return create_iterator_result_object(global_object, match, false); + } + + auto* match_object = match.to_object(global_object); + if (!match_object) + return {}; + auto match_string_value = match_object->get(0); + if (vm.exception()) + return {}; + auto match_string = match_string_value.to_string(global_object); + if (vm.exception()) + return {}; + + if (match_string.is_empty()) { + auto last_index_value = iterator.regexp_object().get(vm.names.lastIndex); + if (vm.exception()) + return {}; + auto last_index = last_index_value.to_length(global_object); + if (vm.exception()) + return {}; + + // FIXME: Implement AdvanceStringIndex to take Unicode code points into account - https://tc39.es/ecma262/#sec-advancestringindex + ++last_index; + + iterator.regexp_object().set(vm.names.lastIndex, Value(last_index), true); + if (vm.exception()) + return {}; + } + + return create_iterator_result_object(global_object, match, false); +} + +} diff --git a/Userland/Libraries/LibJS/Runtime/RegExpStringIteratorPrototype.h b/Userland/Libraries/LibJS/Runtime/RegExpStringIteratorPrototype.h new file mode 100644 index 0000000000..075cffec74 --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/RegExpStringIteratorPrototype.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace JS { + +class RegExpStringIteratorPrototype final : public Object { + JS_OBJECT(RegExpStringIteratorPrototype, Object) + +public: + explicit RegExpStringIteratorPrototype(GlobalObject&); + virtual ~RegExpStringIteratorPrototype() override = default; + + virtual void initialize(GlobalObject&) override; + +private: + JS_DECLARE_NATIVE_FUNCTION(next); +}; + +} -- cgit v1.2.3