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.
This commit is contained in:
Timothy Flynn 2021-07-15 08:58:27 -04:00 committed by Linus Groh
parent 6cf64d0f09
commit cfddcad7cf
Notes: sideshowbarker 2024-07-18 08:56:22 +09:00
7 changed files with 189 additions and 5 deletions

View file

@ -106,6 +106,8 @@ set(SOURCES
Runtime/RegExpConstructor.cpp
Runtime/RegExpObject.cpp
Runtime/RegExpPrototype.cpp
Runtime/RegExpStringIterator.cpp
Runtime/RegExpStringIteratorPrototype.cpp
Runtime/Set.cpp
Runtime/SetConstructor.cpp
Runtime/SetIterator.cpp

View file

@ -82,11 +82,12 @@
__JS_ENUMERATE(Instant, instant, InstantPrototype, InstantConstructor) \
__JS_ENUMERATE(TimeZone, time_zone, TimeZonePrototype, TimeZoneConstructor)
#define JS_ENUMERATE_ITERATOR_PROTOTYPES \
__JS_ENUMERATE(Iterator, iterator) \
__JS_ENUMERATE(ArrayIterator, array_iterator) \
__JS_ENUMERATE(MapIterator, map_iterator) \
__JS_ENUMERATE(SetIterator, set_iterator) \
#define JS_ENUMERATE_ITERATOR_PROTOTYPES \
__JS_ENUMERATE(Iterator, iterator) \
__JS_ENUMERATE(ArrayIterator, array_iterator) \
__JS_ENUMERATE(MapIterator, map_iterator) \
__JS_ENUMERATE(RegExpStringIterator, regexp_string_iterator) \
__JS_ENUMERATE(SetIterator, set_iterator) \
__JS_ENUMERATE(StringIterator, string_iterator)
#define JS_ENUMERATE_BUILTIN_TYPES \

View file

@ -59,6 +59,7 @@
#include <LibJS/Runtime/ReflectObject.h>
#include <LibJS/Runtime/RegExpConstructor.h>
#include <LibJS/Runtime/RegExpPrototype.h>
#include <LibJS/Runtime/RegExpStringIteratorPrototype.h>
#include <LibJS/Runtime/SetConstructor.h>
#include <LibJS/Runtime/SetIteratorPrototype.h>
#include <LibJS/Runtime/SetPrototype.h>

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2021, Tim Flynn <trflynn89@pm.me>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/RegExpStringIterator.h>
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<RegExpStringIterator>(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)
{
}
}

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2021, Tim Flynn <trflynn89@pm.me>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibJS/Runtime/Object.h>
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 };
};
}

View file

@ -0,0 +1,89 @@
/*
* Copyright (c) 2021, Tim Flynn <trflynn89@pm.me>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorOperations.h>
#include <LibJS/Runtime/RegExpPrototype.h>
#include <LibJS/Runtime/RegExpStringIterator.h>
#include <LibJS/Runtime/RegExpStringIteratorPrototype.h>
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<RegExpStringIterator>(this_value.as_object())) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotA, "RegExp String Iterator");
return {};
}
auto& iterator = static_cast<RegExpStringIterator&>(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);
}
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2021, Tim Flynn <trflynn89@pm.me>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibJS/Runtime/Object.h>
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);
};
}