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/counters.h" 8 #include "src/objects-inl.h" 9 #include "src/regexp/jsregexp.h" 10 #include "src/regexp/regexp-utils.h" 11 #include "src/string-builder-inl.h" 12 13 namespace v8 { 14 namespace internal { 15 16 // ----------------------------------------------------------------------------- 17 // ES6 section 21.2 RegExp Objects 18 19 BUILTIN(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 } 67 DEFINE_CAPTURE_GETTER(1) 68 DEFINE_CAPTURE_GETTER(2) 69 DEFINE_CAPTURE_GETTER(3) 70 DEFINE_CAPTURE_GETTER(4) 71 DEFINE_CAPTURE_GETTER(5) 72 DEFINE_CAPTURE_GETTER(6) 73 DEFINE_CAPTURE_GETTER(7) 74 DEFINE_CAPTURE_GETTER(8) 75 DEFINE_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 82 BUILTIN(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 89 BUILTIN(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. 103 BUILTIN(RegExpLastMatchGetter) { 104 HandleScope scope(isolate); 105 return *RegExpUtils::GenericCaptureGetter( 106 isolate, isolate->regexp_last_match_info(), 0); 107 } 108 109 BUILTIN(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 126 BUILTIN(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 134 BUILTIN(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