2020-06-03 23:05:49 +00:00
/*
2021-04-22 23:53:07 +00:00
* Copyright ( c ) 2020 , Matthew Olsson < mattco @ serenityos . org >
2020-06-03 23:05:49 +00:00
*
2021-04-22 08:24:48 +00:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-06-03 23:05:49 +00:00
*/
# include <LibJS/Runtime/Error.h>
# include <LibJS/Runtime/GlobalObject.h>
# include <LibJS/Runtime/RegExpConstructor.h>
# include <LibJS/Runtime/RegExpObject.h>
2022-10-17 00:59:27 +00:00
# include <LibJS/Runtime/Value.h>
2020-06-03 23:05:49 +00:00
namespace JS {
2024-11-14 15:01:23 +00:00
GC_DEFINE_ALLOCATOR ( RegExpConstructor ) ;
2023-11-19 08:45:05 +00:00
2022-08-15 23:20:49 +00:00
RegExpConstructor : : RegExpConstructor ( Realm & realm )
2023-04-12 22:47:15 +00:00
: NativeFunction ( realm . vm ( ) . names . RegExp . as_string ( ) , realm . intrinsics ( ) . function_prototype ( ) )
2020-06-03 23:05:49 +00:00
{
2020-06-20 13:40:48 +00:00
}
2023-08-07 06:41:28 +00:00
void RegExpConstructor : : initialize ( Realm & realm )
2020-06-20 13:40:48 +00:00
{
2020-10-13 21:49:19 +00:00
auto & vm = this - > vm ( ) ;
2023-08-07 06:41:28 +00:00
Base : : initialize ( realm ) ;
2021-06-18 23:38:41 +00:00
2023-06-23 14:05:38 +00:00
// 22.2.5.1 RegExp.prototype, https://tc39.es/ecma262/#sec-regexp.prototype
2022-08-26 23:54:55 +00:00
define_direct_property ( vm . names . prototype , realm . intrinsics ( ) . regexp_prototype ( ) , 0 ) ;
2021-06-18 23:38:41 +00:00
2023-04-12 23:14:45 +00:00
define_native_accessor ( realm , vm . well_known_symbol_species ( ) , symbol_species_getter , { } , Attribute : : Configurable ) ;
2021-07-07 23:49:53 +00:00
define_direct_property ( vm . names . length , Value ( 2 ) , Attribute : : Configurable ) ;
2022-10-17 00:59:27 +00:00
// Additional properties of the RegExp constructor, https://github.com/tc39/proposal-regexp-legacy-features#additional-properties-of-the-regexp-constructor
define_native_accessor ( realm , vm . names . input , input_getter , input_setter , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . inputAlias , input_alias_getter , input_alias_setter , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . lastMatch , last_match_getter , { } , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . lastMatchAlias , last_match_alias_getter , { } , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . lastParen , last_paren_getter , { } , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . lastParenAlias , last_paren_alias_getter , { } , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . leftContext , left_context_getter , { } , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . leftContextAlias , left_context_alias_getter , { } , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . rightContext , right_context_getter , { } , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . rightContextAlias , right_context_alias_getter , { } , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . $ 1 , group_1_getter , { } , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . $ 2 , group_2_getter , { } , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . $ 3 , group_3_getter , { } , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . $ 4 , group_4_getter , { } , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . $ 5 , group_5_getter , { } , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . $ 6 , group_6_getter , { } , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . $ 7 , group_7_getter , { } , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . $ 8 , group_8_getter , { } , Attribute : : Configurable ) ;
define_native_accessor ( realm , vm . names . $ 9 , group_9_getter , { } , Attribute : : Configurable ) ;
2020-06-03 23:05:49 +00:00
}
2023-06-23 14:05:38 +00:00
// 22.2.4.1 RegExp ( pattern, flags ), https://tc39.es/ecma262/#sec-regexp-pattern-flags
2021-10-20 20:16:30 +00:00
ThrowCompletionOr < Value > RegExpConstructor : : call ( )
2020-06-03 23:05:49 +00:00
{
2021-07-08 17:36:09 +00:00
auto & vm = this - > vm ( ) ;
auto pattern = vm . argument ( 0 ) ;
auto flags = vm . argument ( 1 ) ;
2022-10-16 13:05:48 +00:00
// 1. Let patternIsRegExp be ? IsRegExp(pattern).
2022-08-21 13:00:56 +00:00
bool pattern_is_regexp = TRY ( pattern . is_regexp ( vm ) ) ;
2021-07-08 17:36:09 +00:00
2022-10-16 13:05:48 +00:00
// 2. If NewTarget is undefined, then
// a. Let newTarget be the active function object.
auto & new_target = * this ;
// b. If patternIsRegExp is true and flags is undefined, then
2021-07-08 17:36:09 +00:00
if ( pattern_is_regexp & & flags . is_undefined ( ) ) {
2022-10-16 13:05:48 +00:00
// i. Let patternConstructor be ? Get(pattern, "constructor").
2021-10-20 20:16:30 +00:00
auto pattern_constructor = TRY ( pattern . as_object ( ) . get ( vm . names . constructor ) ) ;
2022-10-16 13:05:48 +00:00
// ii. If SameValue(newTarget, patternConstructor) is true, return pattern.
if ( same_value ( & new_target , pattern_constructor ) )
2021-07-08 17:36:09 +00:00
return pattern ;
}
2022-10-16 13:05:48 +00:00
return TRY ( construct ( new_target ) ) ;
2020-06-03 23:05:49 +00:00
}
2023-06-23 14:05:38 +00:00
// 22.2.4.1 RegExp ( pattern, flags ), https://tc39.es/ecma262/#sec-regexp-pattern-flags
2024-11-14 15:01:23 +00:00
ThrowCompletionOr < GC : : Ref < Object > > RegExpConstructor : : construct ( FunctionObject & new_target )
2020-06-03 23:05:49 +00:00
{
2020-09-27 16:36:49 +00:00
auto & vm = this - > vm ( ) ;
2021-07-08 17:36:09 +00:00
auto pattern = vm . argument ( 0 ) ;
auto flags = vm . argument ( 1 ) ;
2022-10-16 13:05:48 +00:00
// 1. Let patternIsRegExp be ? IsRegExp(pattern).
2022-08-21 13:00:56 +00:00
bool pattern_is_regexp = TRY ( pattern . is_regexp ( vm ) ) ;
2021-07-08 17:36:09 +00:00
2022-10-16 13:05:48 +00:00
// NOTE: Step 2 is handled in call() above.
// 3. Else, let newTarget be NewTarget.
2021-07-08 17:36:09 +00:00
Value pattern_value ;
Value flags_value ;
2022-10-16 13:05:48 +00:00
// 4. If pattern is an Object and pattern has a [[RegExpMatcher]] internal slot, then
2021-07-08 17:36:09 +00:00
if ( pattern . is_object ( ) & & is < RegExpObject > ( pattern . as_object ( ) ) ) {
2022-10-16 13:05:48 +00:00
// a. Let P be pattern.[[OriginalSource]].
2021-07-08 17:36:09 +00:00
auto & regexp_pattern = static_cast < RegExpObject & > ( pattern . as_object ( ) ) ;
2022-12-06 22:17:27 +00:00
pattern_value = PrimitiveString : : create ( vm , regexp_pattern . pattern ( ) ) ;
2021-07-08 17:36:09 +00:00
2022-10-16 13:05:48 +00:00
// b. If flags is undefined, let F be pattern.[[OriginalFlags]].
2021-07-08 17:36:09 +00:00
if ( flags . is_undefined ( ) )
2022-12-06 22:17:27 +00:00
flags_value = PrimitiveString : : create ( vm , regexp_pattern . flags ( ) ) ;
2022-10-16 13:05:48 +00:00
// c. Else, let F be flags.
2021-07-08 17:36:09 +00:00
else
flags_value = flags ;
2022-10-16 13:05:48 +00:00
}
// 5. Else if patternIsRegExp is true, then
else if ( pattern_is_regexp ) {
// a. Let P be ? Get(pattern, "source").
2021-10-20 20:16:30 +00:00
pattern_value = TRY ( pattern . as_object ( ) . get ( vm . names . source ) ) ;
2021-07-08 17:36:09 +00:00
2022-10-16 13:05:48 +00:00
// b. If flags is undefined, then
2021-07-08 17:36:09 +00:00
if ( flags . is_undefined ( ) ) {
2022-10-16 13:05:48 +00:00
// i. Let F be ? Get(pattern, "flags").
2021-10-20 20:16:30 +00:00
flags_value = TRY ( pattern . as_object ( ) . get ( vm . names . flags ) ) ;
2022-10-16 13:05:48 +00:00
}
// c. Else, let F be flags.
else {
2021-07-08 17:36:09 +00:00
flags_value = flags ;
}
2022-10-16 13:05:48 +00:00
}
// 6. Else,
else {
// a. Let P be pattern.
2021-07-08 17:36:09 +00:00
pattern_value = pattern ;
2022-10-16 13:05:48 +00:00
// b. Let F be flags.
2021-07-08 17:36:09 +00:00
flags_value = flags ;
}
2022-10-16 13:05:48 +00:00
// 7. Let O be ? RegExpAlloc(newTarget).
2022-10-16 12:57:29 +00:00
auto regexp_object = TRY ( regexp_alloc ( vm , new_target ) ) ;
2022-10-16 13:05:48 +00:00
// 8. Return ? RegExpInitialize(O, P, F).
2022-12-14 19:18:10 +00:00
return TRY ( regexp_object - > regexp_initialize ( vm , pattern_value , flags_value ) ) ;
2020-06-03 23:05:49 +00:00
}
2023-06-23 14:05:38 +00:00
// 22.2.5.2 get RegExp [ @@species ], https://tc39.es/ecma262/#sec-get-regexp-@@species
2021-10-23 00:52:55 +00:00
JS_DEFINE_NATIVE_FUNCTION ( RegExpConstructor : : symbol_species_getter )
2021-06-07 16:31:32 +00:00
{
2022-10-16 13:05:48 +00:00
// 1. Return the this value.
2022-08-20 08:48:43 +00:00
return vm . this_value ( ) ;
2021-06-07 16:31:32 +00:00
}
2022-10-17 00:59:27 +00:00
// get RegExp.input, https://github.com/tc39/proposal-regexp-legacy-features#get-regexpinput
JS_DEFINE_NATIVE_FUNCTION ( RegExpConstructor : : input_getter )
{
2023-04-12 22:47:15 +00:00
auto regexp_constructor = vm . current_realm ( ) - > intrinsics ( ) . regexp_constructor ( ) ;
2022-10-17 00:59:27 +00:00
// 1. Return ? GetLegacyRegExpStaticProperty(%RegExp%, this value, [[RegExpInput]]).
auto property_getter = & RegExpLegacyStaticProperties : : input ;
2023-04-12 22:47:15 +00:00
return TRY ( get_legacy_regexp_static_property ( vm , regexp_constructor , vm . this_value ( ) , property_getter ) ) ;
2022-10-17 00:59:27 +00:00
}
// get RegExp.$_, https://github.com/tc39/proposal-regexp-legacy-features#get-regexp_
JS_DEFINE_NATIVE_FUNCTION ( RegExpConstructor : : input_alias_getter )
{
// Keep the same implementation with `get RegExp.input`
return input_getter ( vm ) ;
}
// set RegExp.input, https://github.com/tc39/proposal-regexp-legacy-features#set-regexpinput--val
JS_DEFINE_NATIVE_FUNCTION ( RegExpConstructor : : input_setter )
{
2023-04-12 22:47:15 +00:00
auto regexp_constructor = vm . current_realm ( ) - > intrinsics ( ) . regexp_constructor ( ) ;
2022-10-17 00:59:27 +00:00
// 1. Perform ? SetLegacyRegExpStaticProperty(%RegExp%, this value, [[RegExpInput]], val).
auto property_setter = & RegExpLegacyStaticProperties : : set_input ;
2023-04-12 22:47:15 +00:00
TRY ( set_legacy_regexp_static_property ( vm , regexp_constructor , vm . this_value ( ) , property_setter , vm . argument ( 0 ) ) ) ;
2022-10-17 00:59:27 +00:00
return js_undefined ( ) ;
}
// set RegExp.$_, https://github.com/tc39/proposal-regexp-legacy-features#set-regexp_---val
JS_DEFINE_NATIVE_FUNCTION ( RegExpConstructor : : input_alias_setter )
{
// Keep the same implementation with `set RegExp.input`
return input_setter ( vm ) ;
}
// get RegExp.lastMatch, https://github.com/tc39/proposal-regexp-legacy-features#get-regexplastmatch
JS_DEFINE_NATIVE_FUNCTION ( RegExpConstructor : : last_match_getter )
{
2023-04-12 22:47:15 +00:00
auto regexp_constructor = vm . current_realm ( ) - > intrinsics ( ) . regexp_constructor ( ) ;
2022-10-17 00:59:27 +00:00
// 1. Return ? GetLegacyRegExpStaticProperty(%RegExp%, this value, [[RegExpLastMatch]]).
auto property_getter = & RegExpLegacyStaticProperties : : last_match ;
2023-04-12 22:47:15 +00:00
return TRY ( get_legacy_regexp_static_property ( vm , regexp_constructor , vm . this_value ( ) , property_getter ) ) ;
2022-10-17 00:59:27 +00:00
}
// get RegExp.$&, https://github.com/tc39/proposal-regexp-legacy-features#get-regexp
JS_DEFINE_NATIVE_FUNCTION ( RegExpConstructor : : last_match_alias_getter )
{
// Keep the same implementation with `get RegExp.lastMatch`
return last_match_getter ( vm ) ;
}
// get RegExp.lastParen, https://github.com/tc39/proposal-regexp-legacy-features#get-regexplastparen
JS_DEFINE_NATIVE_FUNCTION ( RegExpConstructor : : last_paren_getter )
{
2023-04-12 22:47:15 +00:00
auto regexp_constructor = vm . current_realm ( ) - > intrinsics ( ) . regexp_constructor ( ) ;
2022-10-17 00:59:27 +00:00
// 1. Return ? GetLegacyRegExpStaticProperty(%RegExp%, this value, [[RegExpLastParen]]).
auto property_getter = & RegExpLegacyStaticProperties : : last_paren ;
2023-04-12 22:47:15 +00:00
return TRY ( get_legacy_regexp_static_property ( vm , regexp_constructor , vm . this_value ( ) , property_getter ) ) ;
2022-10-17 00:59:27 +00:00
}
// get RegExp.$+, https://github.com/tc39/proposal-regexp-legacy-features#get-regexp-1
JS_DEFINE_NATIVE_FUNCTION ( RegExpConstructor : : last_paren_alias_getter )
{
// Keep the same implementation with `get RegExp.lastParen`
return last_paren_getter ( vm ) ;
}
// get RegExp.leftContext, https://github.com/tc39/proposal-regexp-legacy-features#get-regexpleftcontext
JS_DEFINE_NATIVE_FUNCTION ( RegExpConstructor : : left_context_getter )
{
2023-04-12 22:47:15 +00:00
auto regexp_constructor = vm . current_realm ( ) - > intrinsics ( ) . regexp_constructor ( ) ;
2022-10-17 00:59:27 +00:00
// 1. Return ? GetLegacyRegExpStaticProperty(%RegExp%, this value, [[RegExpLeftContext]]).
auto property_getter = & RegExpLegacyStaticProperties : : left_context ;
2023-04-12 22:47:15 +00:00
return TRY ( get_legacy_regexp_static_property ( vm , regexp_constructor , vm . this_value ( ) , property_getter ) ) ;
2022-10-17 00:59:27 +00:00
}
// get RegExp.$`, https://github.com/tc39/proposal-regexp-legacy-features#get-regexp-2
JS_DEFINE_NATIVE_FUNCTION ( RegExpConstructor : : left_context_alias_getter )
{
// Keep the same implementation with `get RegExp.leftContext`
return left_context_getter ( vm ) ;
}
// get RegExp.rightContext, https://github.com/tc39/proposal-regexp-legacy-features#get-regexprightcontext
JS_DEFINE_NATIVE_FUNCTION ( RegExpConstructor : : right_context_getter )
{
2023-04-12 22:47:15 +00:00
auto regexp_constructor = vm . current_realm ( ) - > intrinsics ( ) . regexp_constructor ( ) ;
2022-10-17 00:59:27 +00:00
// 1. Return ? GetLegacyRegExpStaticProperty(%RegExp%, this value, [[RegExpRightContext]]).
auto property_getter = & RegExpLegacyStaticProperties : : right_context ;
2023-04-12 22:47:15 +00:00
return TRY ( get_legacy_regexp_static_property ( vm , regexp_constructor , vm . this_value ( ) , property_getter ) ) ;
2022-10-17 00:59:27 +00:00
}
// get RegExp.$', https://github.com/tc39/proposal-regexp-legacy-features#get-regexp-3
JS_DEFINE_NATIVE_FUNCTION ( RegExpConstructor : : right_context_alias_getter )
{
// Keep the same implementation with `get RegExp.rightContext`
return right_context_getter ( vm ) ;
}
2023-04-12 22:47:15 +00:00
# define DEFINE_REGEXP_GROUP_GETTER(n) \
JS_DEFINE_NATIVE_FUNCTION ( RegExpConstructor : : group_ # # n # # _getter ) \
{ \
auto regexp_constructor = vm . current_realm ( ) - > intrinsics ( ) . regexp_constructor ( ) ; \
\
/* 1. Return ? GetLegacyRegExpStaticProperty(%RegExp%, this value, [[RegExpParen##n##]]).*/ \
auto property_getter = & RegExpLegacyStaticProperties : : $ # # n ; \
return TRY ( get_legacy_regexp_static_property ( vm , regexp_constructor , vm . this_value ( ) , property_getter ) ) ; \
2022-10-17 00:59:27 +00:00
}
// get RegExp.$1, https://github.com/tc39/proposal-regexp-legacy-features#get-regexp1
DEFINE_REGEXP_GROUP_GETTER ( 1 ) ;
// get RegExp.$2, https://github.com/tc39/proposal-regexp-legacy-features#get-regexp2
DEFINE_REGEXP_GROUP_GETTER ( 2 ) ;
// get RegExp.$3, https://github.com/tc39/proposal-regexp-legacy-features#get-regexp3
DEFINE_REGEXP_GROUP_GETTER ( 3 ) ;
// get RegExp.$4, https://github.com/tc39/proposal-regexp-legacy-features#get-regexp4
DEFINE_REGEXP_GROUP_GETTER ( 4 ) ;
// get RegExp.$5, https://github.com/tc39/proposal-regexp-legacy-features#get-regexp5
DEFINE_REGEXP_GROUP_GETTER ( 5 ) ;
// get RegExp.$6, https://github.com/tc39/proposal-regexp-legacy-features#get-regexp6
DEFINE_REGEXP_GROUP_GETTER ( 6 ) ;
// get RegExp.$7, https://github.com/tc39/proposal-regexp-legacy-features#get-regexp7
DEFINE_REGEXP_GROUP_GETTER ( 7 ) ;
// get RegExp.$8, https://github.com/tc39/proposal-regexp-legacy-features#get-regexp8
DEFINE_REGEXP_GROUP_GETTER ( 8 ) ;
// get RegExp.$9, https://github.com/tc39/proposal-regexp-legacy-features#get-regexp9
DEFINE_REGEXP_GROUP_GETTER ( 9 ) ;
# undef DEFINE_REGEXP_GROUP_GETTER
2020-06-03 23:05:49 +00:00
}