| // 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/logging/counters.h" |
| #include "src/objects/objects-inl.h" |
| #include "src/regexp/regexp-utils.h" |
| #include "src/regexp/regexp.h" |
| #include "src/strings/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<Object> source; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, source, |
| JSReceiver::GetProperty(isolate, recv, |
| isolate->factory()->source_string())); |
| Handle<String> source_str; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, source_str, |
| Object::ToString(isolate, source)); |
| builder.AppendString(source_str); |
| } |
| |
| builder.AppendCharacter('/'); |
| { |
| Handle<Object> flags; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, flags, |
| JSReceiver::GetProperty(isolate, recv, |
| isolate->factory()->flags_string())); |
| Handle<String> 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<Object> 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<Object> value = args.atOrUndefined(isolate, 1); |
| Handle<String> 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<RegExpMatchInfo> 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<RegExpMatchInfo> match_info = isolate->regexp_last_match_info(); |
| const int start_index = match_info->Capture(0); |
| Handle<String> last_subject(match_info->LastSubject(), isolate); |
| return *isolate->factory()->NewSubString(last_subject, 0, start_index); |
| } |
| |
| BUILTIN(RegExpRightContextGetter) { |
| HandleScope scope(isolate); |
| Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info(); |
| const int start_index = match_info->Capture(1); |
| Handle<String> 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 |