OLD | NEW |
(Empty) | |
| 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/regexp/regexp-utils.h" |
| 6 |
| 7 #include "src/factory.h" |
| 8 #include "src/isolate.h" |
| 9 #include "src/objects-inl.h" |
| 10 #include "src/regexp/jsregexp.h" |
| 11 |
| 12 namespace v8 { |
| 13 namespace internal { |
| 14 |
| 15 // Constants for accessing RegExpLastMatchInfo. |
| 16 // TODO(jgruber): Currently, RegExpLastMatchInfo is still a JSObject maintained |
| 17 // and accessed from JS. This is a crutch until all RegExp logic is ported, then |
| 18 // we can take care of RegExpLastMatchInfo. |
| 19 |
| 20 Handle<Object> RegExpUtils::GetLastMatchField(Isolate* isolate, |
| 21 Handle<JSObject> match_info, |
| 22 int index) { |
| 23 return JSReceiver::GetElement(isolate, match_info, index).ToHandleChecked(); |
| 24 } |
| 25 |
| 26 void RegExpUtils::SetLastMatchField(Isolate* isolate, |
| 27 Handle<JSObject> match_info, int index, |
| 28 Handle<Object> value) { |
| 29 JSReceiver::SetElement(isolate, match_info, index, value, SLOPPY) |
| 30 .ToHandleChecked(); |
| 31 } |
| 32 |
| 33 int RegExpUtils::GetLastMatchNumberOfCaptures(Isolate* isolate, |
| 34 Handle<JSObject> match_info) { |
| 35 Handle<Object> obj = |
| 36 GetLastMatchField(isolate, match_info, RegExpImpl::kLastCaptureCount); |
| 37 return Handle<Smi>::cast(obj)->value(); |
| 38 } |
| 39 |
| 40 Handle<String> RegExpUtils::GetLastMatchSubject(Isolate* isolate, |
| 41 Handle<JSObject> match_info) { |
| 42 return Handle<String>::cast( |
| 43 GetLastMatchField(isolate, match_info, RegExpImpl::kLastSubject)); |
| 44 } |
| 45 |
| 46 Handle<Object> RegExpUtils::GetLastMatchInput(Isolate* isolate, |
| 47 Handle<JSObject> match_info) { |
| 48 return GetLastMatchField(isolate, match_info, RegExpImpl::kLastInput); |
| 49 } |
| 50 |
| 51 int RegExpUtils::GetLastMatchCapture(Isolate* isolate, |
| 52 Handle<JSObject> match_info, int i) { |
| 53 Handle<Object> obj = |
| 54 GetLastMatchField(isolate, match_info, RegExpImpl::kFirstCapture + i); |
| 55 return Handle<Smi>::cast(obj)->value(); |
| 56 } |
| 57 |
| 58 Handle<String> RegExpUtils::GenericCaptureGetter(Isolate* isolate, |
| 59 Handle<JSObject> match_info, |
| 60 int capture, bool* ok) { |
| 61 const int index = capture * 2; |
| 62 if (index >= GetLastMatchNumberOfCaptures(isolate, match_info)) { |
| 63 if (ok != nullptr) *ok = false; |
| 64 return isolate->factory()->empty_string(); |
| 65 } |
| 66 |
| 67 const int match_start = GetLastMatchCapture(isolate, match_info, index); |
| 68 const int match_end = GetLastMatchCapture(isolate, match_info, index + 1); |
| 69 if (match_start == -1 || match_end == -1) { |
| 70 if (ok != nullptr) *ok = false; |
| 71 return isolate->factory()->empty_string(); |
| 72 } |
| 73 |
| 74 if (ok != nullptr) *ok = true; |
| 75 Handle<String> last_subject = GetLastMatchSubject(isolate, match_info); |
| 76 return isolate->factory()->NewSubString(last_subject, match_start, match_end); |
| 77 } |
| 78 |
| 79 namespace { |
| 80 |
| 81 V8_INLINE bool HasInitialRegExpMap(Isolate* isolate, Handle<JSReceiver> recv) { |
| 82 return recv->map() == isolate->regexp_function()->initial_map(); |
| 83 } |
| 84 |
| 85 } // namespace |
| 86 |
| 87 MaybeHandle<Object> RegExpUtils::SetLastIndex(Isolate* isolate, |
| 88 Handle<JSReceiver> recv, |
| 89 int value) { |
| 90 if (HasInitialRegExpMap(isolate, recv)) { |
| 91 JSRegExp::cast(*recv)->SetLastIndex(value); |
| 92 return recv; |
| 93 } else { |
| 94 return Object::SetProperty(recv, isolate->factory()->lastIndex_string(), |
| 95 handle(Smi::FromInt(value), isolate), STRICT); |
| 96 } |
| 97 } |
| 98 |
| 99 MaybeHandle<Object> RegExpUtils::GetLastIndex(Isolate* isolate, |
| 100 Handle<JSReceiver> recv) { |
| 101 if (HasInitialRegExpMap(isolate, recv)) { |
| 102 return handle(JSRegExp::cast(*recv)->LastIndex(), isolate); |
| 103 } else { |
| 104 return Object::GetProperty(recv, isolate->factory()->lastIndex_string()); |
| 105 } |
| 106 } |
| 107 |
| 108 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) |
| 109 // Also takes an optional exec method in case our caller |
| 110 // has already fetched exec. |
| 111 MaybeHandle<Object> RegExpUtils::RegExpExec(Isolate* isolate, |
| 112 Handle<JSReceiver> regexp, |
| 113 Handle<String> string, |
| 114 Handle<Object> exec) { |
| 115 if (exec->IsUndefined(isolate)) { |
| 116 ASSIGN_RETURN_ON_EXCEPTION( |
| 117 isolate, exec, |
| 118 Object::GetProperty( |
| 119 regexp, isolate->factory()->NewStringFromAsciiChecked("exec")), |
| 120 Object); |
| 121 } |
| 122 |
| 123 if (exec->IsCallable()) { |
| 124 const int argc = 1; |
| 125 ScopedVector<Handle<Object>> argv(argc); |
| 126 argv[0] = string; |
| 127 |
| 128 Handle<Object> result; |
| 129 ASSIGN_RETURN_ON_EXCEPTION( |
| 130 isolate, result, |
| 131 Execution::Call(isolate, exec, regexp, argc, argv.start()), Object); |
| 132 |
| 133 if (!result->IsJSReceiver() && !result->IsNull(isolate)) { |
| 134 THROW_NEW_ERROR(isolate, |
| 135 NewTypeError(MessageTemplate::kInvalidRegExpExecResult), |
| 136 Object); |
| 137 } |
| 138 return result; |
| 139 } |
| 140 |
| 141 if (!regexp->IsJSRegExp()) { |
| 142 THROW_NEW_ERROR(isolate, |
| 143 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, |
| 144 isolate->factory()->NewStringFromAsciiChecked( |
| 145 "RegExp.prototype.exec"), |
| 146 regexp), |
| 147 Object); |
| 148 } |
| 149 |
| 150 { |
| 151 Handle<JSFunction> regexp_exec = isolate->regexp_exec_function(); |
| 152 |
| 153 const int argc = 1; |
| 154 ScopedVector<Handle<Object>> argv(argc); |
| 155 argv[0] = string; |
| 156 |
| 157 return Execution::Call(isolate, exec, regexp_exec, argc, argv.start()); |
| 158 } |
| 159 } |
| 160 |
| 161 Maybe<bool> RegExpUtils::IsRegExp(Isolate* isolate, Handle<Object> object) { |
| 162 if (!object->IsJSReceiver()) return Just(false); |
| 163 |
| 164 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object); |
| 165 |
| 166 if (isolate->regexp_function()->initial_map() == receiver->map()) { |
| 167 // Fast-path for unmodified JSRegExp instances. |
| 168 // TODO(ishell): Adapt for new fast-path logic. |
| 169 return Just(true); |
| 170 } |
| 171 |
| 172 Handle<Object> match; |
| 173 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 174 isolate, match, |
| 175 JSObject::GetProperty(receiver, isolate->factory()->match_symbol()), |
| 176 Nothing<bool>()); |
| 177 |
| 178 if (!match->IsUndefined(isolate)) return Just(match->BooleanValue()); |
| 179 return Just(object->IsJSRegExp()); |
| 180 } |
| 181 |
| 182 bool RegExpUtils::IsBuiltinExec(Handle<Object> exec) { |
| 183 if (!exec->IsJSFunction()) return false; |
| 184 |
| 185 Code* code = Handle<JSFunction>::cast(exec)->code(); |
| 186 if (code == nullptr) return false; |
| 187 |
| 188 return (code->builtin_index() == Builtins::kRegExpPrototypeExec); |
| 189 } |
| 190 |
| 191 // ES#sec-advancestringindex |
| 192 // AdvanceStringIndex ( S, index, unicode ) |
| 193 int RegExpUtils::AdvanceStringIndex(Isolate* isolate, Handle<String> string, |
| 194 int index, bool unicode) { |
| 195 int increment = 1; |
| 196 |
| 197 if (unicode && index < string->length()) { |
| 198 const uint16_t first = string->Get(index); |
| 199 if (first >= 0xD800 && first <= 0xDBFF && string->length() > index + 1) { |
| 200 const uint16_t second = string->Get(index + 1); |
| 201 if (second >= 0xDC00 && second <= 0xDFFF) { |
| 202 increment = 2; |
| 203 } |
| 204 } |
| 205 } |
| 206 |
| 207 return increment; |
| 208 } |
| 209 |
| 210 MaybeHandle<Object> RegExpUtils::SetAdvancedStringIndex( |
| 211 Isolate* isolate, Handle<JSReceiver> regexp, Handle<String> string, |
| 212 bool unicode) { |
| 213 Handle<Object> last_index_obj; |
| 214 ASSIGN_RETURN_ON_EXCEPTION( |
| 215 isolate, last_index_obj, |
| 216 Object::GetProperty(regexp, isolate->factory()->lastIndex_string()), |
| 217 Object); |
| 218 |
| 219 ASSIGN_RETURN_ON_EXCEPTION(isolate, last_index_obj, |
| 220 Object::ToLength(isolate, last_index_obj), Object); |
| 221 |
| 222 const int last_index = Handle<Smi>::cast(last_index_obj)->value(); |
| 223 const int new_last_index = |
| 224 last_index + AdvanceStringIndex(isolate, string, last_index, unicode); |
| 225 |
| 226 return SetLastIndex(isolate, regexp, new_last_index); |
| 227 } |
| 228 |
| 229 } // namespace internal |
| 230 } // namespace v8 |
OLD | NEW |