OLD | NEW |
---|---|
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/runtime/runtime-utils.h" | 5 #include "src/runtime/runtime-utils.h" |
6 | 6 |
7 #include <functional> | 7 #include <functional> |
8 | 8 |
9 #include "src/arguments.h" | 9 #include "src/arguments.h" |
10 #include "src/conversions-inl.h" | 10 #include "src/conversions-inl.h" |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
68 | 68 |
69 Zone* zone() const { return zone_; } | 69 Zone* zone() const { return zone_; } |
70 | 70 |
71 private: | 71 private: |
72 enum PartType { | 72 enum PartType { |
73 SUBJECT_PREFIX = 1, | 73 SUBJECT_PREFIX = 1, |
74 SUBJECT_SUFFIX, | 74 SUBJECT_SUFFIX, |
75 SUBJECT_CAPTURE, | 75 SUBJECT_CAPTURE, |
76 REPLACEMENT_SUBSTRING, | 76 REPLACEMENT_SUBSTRING, |
77 REPLACEMENT_STRING, | 77 REPLACEMENT_STRING, |
78 EMPTY, | |
jgruber
2017/04/03 08:35:33
The empty replacement for unmatched captures is ha
| |
79 NUMBER_OF_PART_TYPES | 78 NUMBER_OF_PART_TYPES |
80 }; | 79 }; |
81 | 80 |
82 struct ReplacementPart { | 81 struct ReplacementPart { |
83 static inline ReplacementPart SubjectMatch() { | 82 static inline ReplacementPart SubjectMatch() { |
84 return ReplacementPart(SUBJECT_CAPTURE, 0); | 83 return ReplacementPart(SUBJECT_CAPTURE, 0); |
85 } | 84 } |
86 static inline ReplacementPart SubjectCapture(int capture_index) { | 85 static inline ReplacementPart SubjectCapture(int capture_index) { |
87 return ReplacementPart(SUBJECT_CAPTURE, capture_index); | 86 return ReplacementPart(SUBJECT_CAPTURE, capture_index); |
88 } | 87 } |
89 static inline ReplacementPart SubjectPrefix() { | 88 static inline ReplacementPart SubjectPrefix() { |
90 return ReplacementPart(SUBJECT_PREFIX, 0); | 89 return ReplacementPart(SUBJECT_PREFIX, 0); |
91 } | 90 } |
92 static inline ReplacementPart SubjectSuffix(int subject_length) { | 91 static inline ReplacementPart SubjectSuffix(int subject_length) { |
93 return ReplacementPart(SUBJECT_SUFFIX, subject_length); | 92 return ReplacementPart(SUBJECT_SUFFIX, subject_length); |
94 } | 93 } |
95 static inline ReplacementPart ReplacementString() { | 94 static inline ReplacementPart ReplacementString() { |
96 return ReplacementPart(REPLACEMENT_STRING, 0); | 95 return ReplacementPart(REPLACEMENT_STRING, 0); |
97 } | 96 } |
98 static inline ReplacementPart ReplacementSubString(int from, int to) { | 97 static inline ReplacementPart ReplacementSubString(int from, int to) { |
99 DCHECK(from >= 0); | 98 DCHECK(from >= 0); |
100 DCHECK(to > from); | 99 DCHECK(to > from); |
101 return ReplacementPart(-from, to); | 100 return ReplacementPart(-from, to); |
102 } | 101 } |
103 static inline ReplacementPart Empty() { return ReplacementPart(EMPTY, 0); } | |
104 | 102 |
105 // If tag <= 0 then it is the negation of a start index of a substring of | 103 // If tag <= 0 then it is the negation of a start index of a substring of |
106 // the replacement pattern, otherwise it's a value from PartType. | 104 // the replacement pattern, otherwise it's a value from PartType. |
107 ReplacementPart(int tag, int data) : tag(tag), data(data) { | 105 ReplacementPart(int tag, int data) : tag(tag), data(data) { |
108 // Must be non-positive or a PartType value. | 106 // Must be non-positive or a PartType value. |
109 DCHECK(tag < NUMBER_OF_PART_TYPES); | 107 DCHECK(tag < NUMBER_OF_PART_TYPES); |
110 } | 108 } |
111 // Either a value of PartType or a non-positive number that is | 109 // Either a value of PartType or a non-positive number that is |
112 // the negation of an index into the replacement string. | 110 // the negation of an index into the replacement string. |
113 int tag; | 111 int tag; |
114 // The data value's interpretation depends on the value of tag: | 112 // The data value's interpretation depends on the value of tag: |
115 // tag == SUBJECT_PREFIX || | 113 // tag == SUBJECT_PREFIX || |
116 // tag == SUBJECT_SUFFIX || | 114 // tag == SUBJECT_SUFFIX: data is unused. |
117 // tag == EMPTY: data is unused. | |
118 // tag == SUBJECT_CAPTURE: data is the number of the capture. | 115 // tag == SUBJECT_CAPTURE: data is the number of the capture. |
119 // tag == REPLACEMENT_SUBSTRING || | 116 // tag == REPLACEMENT_SUBSTRING || |
120 // tag == REPLACEMENT_STRING: data is index into array of substrings | 117 // tag == REPLACEMENT_STRING: data is index into array of substrings |
121 // of the replacement string. | 118 // of the replacement string. |
122 // tag <= 0: Temporary representation of the substring of the replacement | 119 // tag <= 0: Temporary representation of the substring of the replacement |
123 // string ranging over -tag .. data. | 120 // string ranging over -tag .. data. |
124 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the | 121 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the |
125 // substring objects. | 122 // substring objects. |
126 int data; | 123 int data; |
127 }; | 124 }; |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
244 } | 241 } |
245 | 242 |
246 // Throw a SyntaxError for invalid replacement strings. | 243 // Throw a SyntaxError for invalid replacement strings. |
247 if (closing_bracket_index == -1) return Nothing<bool>(); | 244 if (closing_bracket_index == -1) return Nothing<bool>(); |
248 | 245 |
249 Vector<Char> requested_name = | 246 Vector<Char> requested_name = |
250 characters.SubVector(name_start_index, closing_bracket_index); | 247 characters.SubVector(name_start_index, closing_bracket_index); |
251 | 248 |
252 // Let capture be ? Get(namedCaptures, groupName). | 249 // Let capture be ? Get(namedCaptures, groupName). |
253 | 250 |
254 int capture_index = LookupNamedCapture( | 251 const int capture_index = LookupNamedCapture( |
255 [=](String* capture_name) { | 252 [=](String* capture_name) { |
256 return capture_name->IsEqualTo(requested_name); | 253 return capture_name->IsEqualTo(requested_name); |
257 }, | 254 }, |
258 capture_name_map); | 255 capture_name_map); |
259 | 256 |
257 // If ? HasProperty(_namedCaptures_, _groupName_) is *false*, throw | |
258 // a *SyntaxError* exception. | |
259 if (capture_index == -1) return Nothing<bool>(); | |
260 | |
260 // If capture is undefined, replace the text through the following | 261 // If capture is undefined, replace the text through the following |
261 // '>' with the empty string. | 262 // '>' with the empty string. |
262 // Otherwise, replace the text through the following '>' with | 263 // Otherwise, replace the text through the following '>' with |
263 // ? ToString(capture). | 264 // ? ToString(capture). |
264 | 265 |
265 DCHECK_IMPLIES( | 266 DCHECK(1 <= capture_index && capture_index <= capture_count); |
266 capture_index != -1, | |
267 1 <= capture_index && capture_index <= capture_count); | |
268 | |
269 ReplacementPart replacement = | |
270 (capture_index == -1) | |
271 ? ReplacementPart::Empty() | |
272 : ReplacementPart::SubjectCapture(capture_index); | |
273 | 267 |
274 if (i > last) { | 268 if (i > last) { |
275 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); | 269 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); |
276 } | 270 } |
277 parts->Add(replacement, zone); | 271 parts->Add(ReplacementPart::SubjectCapture(capture_index), zone); |
278 last = closing_bracket_index + 1; | 272 last = closing_bracket_index + 1; |
279 i = closing_bracket_index; | 273 i = closing_bracket_index; |
280 break; | 274 break; |
281 } | 275 } |
282 default: | 276 default: |
283 i = next_index; | 277 i = next_index; |
284 break; | 278 break; |
285 } | 279 } |
286 } | 280 } |
287 } | 281 } |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
379 int to = match[capture * 2 + 1]; | 373 int to = match[capture * 2 + 1]; |
380 if (from >= 0 && to > from) { | 374 if (from >= 0 && to > from) { |
381 builder->AddSubjectSlice(from, to); | 375 builder->AddSubjectSlice(from, to); |
382 } | 376 } |
383 break; | 377 break; |
384 } | 378 } |
385 case REPLACEMENT_SUBSTRING: | 379 case REPLACEMENT_SUBSTRING: |
386 case REPLACEMENT_STRING: | 380 case REPLACEMENT_STRING: |
387 builder->AddString(replacement_substrings_[part.data]); | 381 builder->AddString(replacement_substrings_[part.data]); |
388 break; | 382 break; |
389 case EMPTY: | |
390 break; | |
391 default: | 383 default: |
392 UNREACHABLE(); | 384 UNREACHABLE(); |
393 } | 385 } |
394 } | 386 } |
395 } | 387 } |
396 | 388 |
397 void FindOneByteStringIndices(Vector<const uint8_t> subject, uint8_t pattern, | 389 void FindOneByteStringIndices(Vector<const uint8_t> subject, uint8_t pattern, |
398 List<int>* indices, unsigned int limit) { | 390 List<int>* indices, unsigned int limit) { |
399 DCHECK(limit > 0); | 391 DCHECK(limit > 0); |
400 // Collect indices of pattern in subject using memchr. | 392 // Collect indices of pattern in subject using memchr. |
(...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1011 } | 1003 } |
1012 | 1004 |
1013 MaybeHandle<String> GetCapture(int i, bool* capture_exists) override { | 1005 MaybeHandle<String> GetCapture(int i, bool* capture_exists) override { |
1014 Handle<Object> capture_obj = RegExpUtils::GenericCaptureGetter( | 1006 Handle<Object> capture_obj = RegExpUtils::GenericCaptureGetter( |
1015 isolate_, match_info_, i, capture_exists); | 1007 isolate_, match_info_, i, capture_exists); |
1016 return (*capture_exists) ? Object::ToString(isolate_, capture_obj) | 1008 return (*capture_exists) ? Object::ToString(isolate_, capture_obj) |
1017 : isolate_->factory()->empty_string(); | 1009 : isolate_->factory()->empty_string(); |
1018 } | 1010 } |
1019 | 1011 |
1020 MaybeHandle<String> GetNamedCapture(Handle<String> name, | 1012 MaybeHandle<String> GetNamedCapture(Handle<String> name, |
1021 bool* capture_exists) override { | 1013 CaptureState* state) override { |
1022 DCHECK(has_named_captures_); | 1014 DCHECK(has_named_captures_); |
1023 const int capture_index = LookupNamedCapture( | 1015 const int capture_index = LookupNamedCapture( |
1024 [=](String* capture_name) { return capture_name->Equals(*name); }, | 1016 [=](String* capture_name) { return capture_name->Equals(*name); }, |
1025 *capture_name_map_); | 1017 *capture_name_map_); |
1026 | 1018 |
1027 if (capture_index == -1) { | 1019 if (capture_index == -1) { |
1028 *capture_exists = false; | 1020 *state = INVALID; |
1029 return name; // Arbitrary string handle. | 1021 return name; // Arbitrary string handle. |
1030 } | 1022 } |
1031 | 1023 |
1032 DCHECK(1 <= capture_index && capture_index <= CaptureCount()); | 1024 DCHECK(1 <= capture_index && capture_index <= CaptureCount()); |
1033 return GetCapture(capture_index, capture_exists); | 1025 |
1026 bool capture_exists; | |
1027 Handle<String> capture_value; | |
1028 ASSIGN_RETURN_ON_EXCEPTION(isolate_, capture_value, | |
1029 GetCapture(capture_index, &capture_exists), | |
1030 String); | |
1031 | |
1032 if (!capture_exists) { | |
1033 *state = UNMATCHED; | |
1034 return isolate_->factory()->empty_string(); | |
1035 } else { | |
1036 *state = MATCHED; | |
1037 return capture_value; | |
1038 } | |
1034 } | 1039 } |
1035 | 1040 |
1036 private: | 1041 private: |
1037 Isolate* isolate_; | 1042 Isolate* isolate_; |
1038 Handle<String> subject_; | 1043 Handle<String> subject_; |
1039 Handle<RegExpMatchInfo> match_info_; | 1044 Handle<RegExpMatchInfo> match_info_; |
1040 | 1045 |
1041 bool has_named_captures_; | 1046 bool has_named_captures_; |
1042 Handle<FixedArray> capture_name_map_; | 1047 Handle<FixedArray> capture_name_map_; |
1043 }; | 1048 }; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1079 Handle<Object> capture_obj = captures_->at(i); | 1084 Handle<Object> capture_obj = captures_->at(i); |
1080 if (capture_obj->IsUndefined(isolate_)) { | 1085 if (capture_obj->IsUndefined(isolate_)) { |
1081 *capture_exists = false; | 1086 *capture_exists = false; |
1082 return isolate_->factory()->empty_string(); | 1087 return isolate_->factory()->empty_string(); |
1083 } | 1088 } |
1084 *capture_exists = true; | 1089 *capture_exists = true; |
1085 return Object::ToString(isolate_, capture_obj); | 1090 return Object::ToString(isolate_, capture_obj); |
1086 } | 1091 } |
1087 | 1092 |
1088 MaybeHandle<String> GetNamedCapture(Handle<String> name, | 1093 MaybeHandle<String> GetNamedCapture(Handle<String> name, |
1089 bool* capture_exists) override { | 1094 CaptureState* state) override { |
1090 DCHECK(has_named_captures_); | 1095 DCHECK(has_named_captures_); |
1096 | |
1097 Maybe<bool> maybe_capture_exists = | |
1098 JSReceiver::HasProperty(groups_obj_, name); | |
1099 if (maybe_capture_exists.IsNothing()) return MaybeHandle<String>(); | |
1100 | |
1101 if (!maybe_capture_exists.FromJust()) { | |
1102 *state = INVALID; | |
1103 return name; // Arbitrary string handle. | |
1104 } | |
1105 | |
1091 Handle<Object> capture_obj; | 1106 Handle<Object> capture_obj; |
1092 ASSIGN_RETURN_ON_EXCEPTION(isolate_, capture_obj, | 1107 ASSIGN_RETURN_ON_EXCEPTION(isolate_, capture_obj, |
1093 Object::GetProperty(groups_obj_, name), String); | 1108 Object::GetProperty(groups_obj_, name), String); |
1094 if (capture_obj->IsUndefined(isolate_)) { | 1109 if (capture_obj->IsUndefined(isolate_)) { |
1095 *capture_exists = false; | 1110 *state = UNMATCHED; |
1096 return name; | 1111 return isolate_->factory()->empty_string(); |
1097 } else { | 1112 } else { |
1098 *capture_exists = true; | 1113 *state = MATCHED; |
1099 return Object::ToString(isolate_, capture_obj); | 1114 return Object::ToString(isolate_, capture_obj); |
1100 } | 1115 } |
1101 } | 1116 } |
1102 | 1117 |
1103 private: | 1118 private: |
1104 Isolate* isolate_; | 1119 Isolate* isolate_; |
1105 Handle<String> subject_; | 1120 Handle<String> subject_; |
1106 Handle<String> match_; | 1121 Handle<String> match_; |
1107 const int match_position_; | 1122 const int match_position_; |
1108 ZoneVector<Handle<Object>>* captures_; | 1123 ZoneVector<Handle<Object>>* captures_; |
(...skipping 776 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1885 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 1900 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
1886 isolate, replacement_obj, | 1901 isolate, replacement_obj, |
1887 Execution::Call(isolate, replace_obj, factory->undefined_value(), | 1902 Execution::Call(isolate, replace_obj, factory->undefined_value(), |
1888 argc, argv.start())); | 1903 argc, argv.start())); |
1889 | 1904 |
1890 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 1905 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
1891 isolate, replacement, Object::ToString(isolate, replacement_obj)); | 1906 isolate, replacement, Object::ToString(isolate, replacement_obj)); |
1892 } else { | 1907 } else { |
1893 DCHECK(!functional_replace); | 1908 DCHECK(!functional_replace); |
1894 if (!groups_obj->IsUndefined(isolate)) { | 1909 if (!groups_obj->IsUndefined(isolate)) { |
1895 // TODO(jgruber): Behavior in this case is not yet specced. | |
1896 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 1910 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
1897 isolate, groups_obj, JSReceiver::ToObject(isolate, groups_obj)); | 1911 isolate, groups_obj, JSReceiver::ToObject(isolate, groups_obj)); |
1898 } | 1912 } |
1899 VectorBackedMatch m(isolate, string, match, position, &captures, | 1913 VectorBackedMatch m(isolate, string, match, position, &captures, |
1900 groups_obj); | 1914 groups_obj); |
1901 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 1915 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
1902 isolate, replacement, String::GetSubstitution(isolate, &m, replace)); | 1916 isolate, replacement, String::GetSubstitution(isolate, &m, replace)); |
1903 } | 1917 } |
1904 | 1918 |
1905 if (position >= next_source_position) { | 1919 if (position >= next_source_position) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1942 | 1956 |
1943 RUNTIME_FUNCTION(Runtime_IsRegExp) { | 1957 RUNTIME_FUNCTION(Runtime_IsRegExp) { |
1944 SealHandleScope shs(isolate); | 1958 SealHandleScope shs(isolate); |
1945 DCHECK_EQ(1, args.length()); | 1959 DCHECK_EQ(1, args.length()); |
1946 CONVERT_ARG_CHECKED(Object, obj, 0); | 1960 CONVERT_ARG_CHECKED(Object, obj, 0); |
1947 return isolate->heap()->ToBoolean(obj->IsJSRegExp()); | 1961 return isolate->heap()->ToBoolean(obj->IsJSRegExp()); |
1948 } | 1962 } |
1949 | 1963 |
1950 } // namespace internal | 1964 } // namespace internal |
1951 } // namespace v8 | 1965 } // namespace v8 |
OLD | NEW |