// Copyright 2016 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/builtins/builtins-utils-inl.h" #include "src/builtins/builtins.h" #include "src/counters.h" #include "src/objects-inl.h" #include "src/regexp/jsregexp.h" #include "src/regexp/regexp-utils.h" #include "src/string-builder-inl.h" namespace v8 { namespace internal { // ----------------------------------------------------------------------------- // ES6 section 21.2 RegExp Objects BUILTIN(RegExpPrototypeToString) { HandleScope scope(isolate); CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.toString"); if (*recv == isolate->regexp_function()->prototype()) { isolate->CountUsage(v8::Isolate::kRegExpPrototypeToString); } IncrementalStringBuilder builder(isolate); builder.AppendCharacter('/'); { Handle source; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, source, JSReceiver::GetProperty(isolate, recv, isolate->factory()->source_string())); Handle source_str; ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, source_str, Object::ToString(isolate, source)); builder.AppendString(source_str); } builder.AppendCharacter('/'); { Handle flags; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, flags, JSReceiver::GetProperty(isolate, recv, isolate->factory()->flags_string())); Handle flags_str; ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, flags_str, Object::ToString(isolate, flags)); builder.AppendString(flags_str); } RETURN_RESULT_OR_FAILURE(isolate, builder.Finish()); } // The properties $1..$9 are the first nine capturing substrings of the last // successful match, or ''. The function RegExpMakeCaptureGetter will be // called with indices from 1 to 9. #define DEFINE_CAPTURE_GETTER(i) \ BUILTIN(RegExpCapture##i##Getter) { \ HandleScope scope(isolate); \ return *RegExpUtils::GenericCaptureGetter( \ isolate, isolate->regexp_last_match_info(), i); \ } DEFINE_CAPTURE_GETTER(1) DEFINE_CAPTURE_GETTER(2) DEFINE_CAPTURE_GETTER(3) DEFINE_CAPTURE_GETTER(4) DEFINE_CAPTURE_GETTER(5) DEFINE_CAPTURE_GETTER(6) DEFINE_CAPTURE_GETTER(7) DEFINE_CAPTURE_GETTER(8) DEFINE_CAPTURE_GETTER(9) #undef DEFINE_CAPTURE_GETTER // The properties `input` and `$_` are aliases for each other. When this // value is set, the value it is set to is coerced to a string. // Getter and setter for the input. BUILTIN(RegExpInputGetter) { HandleScope scope(isolate); Handle obj(isolate->regexp_last_match_info()->LastInput(), isolate); return obj->IsUndefined(isolate) ? ReadOnlyRoots(isolate).empty_string() : String::cast(*obj); } BUILTIN(RegExpInputSetter) { HandleScope scope(isolate); Handle value = args.atOrUndefined(isolate, 1); Handle str; ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, str, Object::ToString(isolate, value)); isolate->regexp_last_match_info()->SetLastInput(*str); return ReadOnlyRoots(isolate).undefined_value(); } // Getters for the static properties lastMatch, lastParen, leftContext, and // rightContext of the RegExp constructor. The properties are computed based // on the captures array of the last successful match and the subject string // of the last successful match. BUILTIN(RegExpLastMatchGetter) { HandleScope scope(isolate); return *RegExpUtils::GenericCaptureGetter( isolate, isolate->regexp_last_match_info(), 0); } BUILTIN(RegExpLastParenGetter) { HandleScope scope(isolate); Handle match_info = isolate->regexp_last_match_info(); const int length = match_info->NumberOfCaptureRegisters(); if (length <= 2) { return ReadOnlyRoots(isolate).empty_string(); // No captures. } DCHECK_EQ(0, length % 2); const int last_capture = (length / 2) - 1; // We match the SpiderMonkey behavior: return the substring defined by the // last pair (after the first pair) of elements of the capture array even if // it is empty. return *RegExpUtils::GenericCaptureGetter(isolate, match_info, last_capture); } BUILTIN(RegExpLeftContextGetter) { HandleScope scope(isolate); Handle match_info = isolate->regexp_last_match_info(); const int start_index = match_info->Capture(0); Handle last_subject(match_info->LastSubject(), isolate); return *isolate->factory()->NewSubString(last_subject, 0, start_index); } BUILTIN(RegExpRightContextGetter) { HandleScope scope(isolate); Handle match_info = isolate->regexp_last_match_info(); const int start_index = match_info->Capture(1); Handle last_subject(match_info->LastSubject(), isolate); const int len = last_subject->length(); return *isolate->factory()->NewSubString(last_subject, start_index, len); } } // namespace internal } // namespace v8