1// Copyright 2016 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/builtins/builtins-utils-inl.h" 6#include "src/builtins/builtins.h" 7#include "src/logging/counters.h" 8#include "src/objects/objects-inl.h" 9#include "src/regexp/regexp-utils.h" 10#include "src/regexp/regexp.h" 11#include "src/strings/string-builder-inl.h" 12 13namespace v8 { 14namespace internal { 15 16// ----------------------------------------------------------------------------- 17// ES6 section 21.2 RegExp Objects 18 19BUILTIN(RegExpPrototypeToString) { 20 HandleScope scope(isolate); 21 CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.toString"); 22 23 if (*recv == isolate->regexp_function()->prototype()) { 24 isolate->CountUsage(v8::Isolate::kRegExpPrototypeToString); 25 } 26 27 IncrementalStringBuilder builder(isolate); 28 29 builder.AppendCharacter('/'); 30 { 31 Handle<Object> source; 32 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 33 isolate, source, 34 JSReceiver::GetProperty(isolate, recv, 35 isolate->factory()->source_string())); 36 Handle<String> source_str; 37 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, source_str, 38 Object::ToString(isolate, source)); 39 builder.AppendString(source_str); 40 } 41 42 builder.AppendCharacter('/'); 43 { 44 Handle<Object> flags; 45 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 46 isolate, flags, 47 JSReceiver::GetProperty(isolate, recv, 48 isolate->factory()->flags_string())); 49 Handle<String> flags_str; 50 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, flags_str, 51 Object::ToString(isolate, flags)); 52 builder.AppendString(flags_str); 53 } 54 55 RETURN_RESULT_OR_FAILURE(isolate, builder.Finish()); 56} 57 58// The properties $1..$9 are the first nine capturing substrings of the last 59// successful match, or ''. The function RegExpMakeCaptureGetter will be 60// called with indices from 1 to 9. 61#define DEFINE_CAPTURE_GETTER(i) \ 62 BUILTIN(RegExpCapture##i##Getter) { \ 63 HandleScope scope(isolate); \ 64 return *RegExpUtils::GenericCaptureGetter( \ 65 isolate, isolate->regexp_last_match_info(), i); \ 66 } 67DEFINE_CAPTURE_GETTER(1) 68DEFINE_CAPTURE_GETTER(2) 69DEFINE_CAPTURE_GETTER(3) 70DEFINE_CAPTURE_GETTER(4) 71DEFINE_CAPTURE_GETTER(5) 72DEFINE_CAPTURE_GETTER(6) 73DEFINE_CAPTURE_GETTER(7) 74DEFINE_CAPTURE_GETTER(8) 75DEFINE_CAPTURE_GETTER(9) 76#undef DEFINE_CAPTURE_GETTER 77 78// The properties `input` and `$_` are aliases for each other. When this 79// value is set, the value it is set to is coerced to a string. 80// Getter and setter for the input. 81 82BUILTIN(RegExpInputGetter) { 83 HandleScope scope(isolate); 84 Handle<Object> obj(isolate->regexp_last_match_info()->LastInput(), isolate); 85 return obj->IsUndefined(isolate) ? ReadOnlyRoots(isolate).empty_string() 86 : String::cast(*obj); 87} 88 89BUILTIN(RegExpInputSetter) { 90 HandleScope scope(isolate); 91 Handle<Object> value = args.atOrUndefined(isolate, 1); 92 Handle<String> str; 93 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, str, 94 Object::ToString(isolate, value)); 95 isolate->regexp_last_match_info()->SetLastInput(*str); 96 return ReadOnlyRoots(isolate).undefined_value(); 97} 98 99// Getters for the static properties lastMatch, lastParen, leftContext, and 100// rightContext of the RegExp constructor. The properties are computed based 101// on the captures array of the last successful match and the subject string 102// of the last successful match. 103BUILTIN(RegExpLastMatchGetter) { 104 HandleScope scope(isolate); 105 return *RegExpUtils::GenericCaptureGetter( 106 isolate, isolate->regexp_last_match_info(), 0); 107} 108 109BUILTIN(RegExpLastParenGetter) { 110 HandleScope scope(isolate); 111 Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info(); 112 const int length = match_info->NumberOfCaptureRegisters(); 113 if (length <= 2) { 114 return ReadOnlyRoots(isolate).empty_string(); // No captures. 115 } 116 117 DCHECK_EQ(0, length % 2); 118 const int last_capture = (length / 2) - 1; 119 120 // We match the SpiderMonkey behavior: return the substring defined by the 121 // last pair (after the first pair) of elements of the capture array even if 122 // it is empty. 123 return *RegExpUtils::GenericCaptureGetter(isolate, match_info, last_capture); 124} 125 126BUILTIN(RegExpLeftContextGetter) { 127 HandleScope scope(isolate); 128 Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info(); 129 const int start_index = match_info->Capture(0); 130 Handle<String> last_subject(match_info->LastSubject(), isolate); 131 return *isolate->factory()->NewSubString(last_subject, 0, start_index); 132} 133 134BUILTIN(RegExpRightContextGetter) { 135 HandleScope scope(isolate); 136 Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info(); 137 const int start_index = match_info->Capture(1); 138 Handle<String> last_subject(match_info->LastSubject(), isolate); 139 const int len = last_subject->length(); 140 return *isolate->factory()->NewSubString(last_subject, start_index, len); 141} 142 143} // namespace internal 144} // namespace v8 145