Index: src/regexp/regexp-utils.cc |
diff --git a/src/regexp/regexp-utils.cc b/src/regexp/regexp-utils.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8de904b72b7883192463c502a2c56d1245c285ca |
--- /dev/null |
+++ b/src/regexp/regexp-utils.cc |
@@ -0,0 +1,230 @@ |
+// 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/regexp/regexp-utils.h" |
+ |
+#include "src/factory.h" |
+#include "src/isolate.h" |
+#include "src/objects-inl.h" |
+#include "src/regexp/jsregexp.h" |
+ |
+namespace v8 { |
+namespace internal { |
+ |
+// Constants for accessing RegExpLastMatchInfo. |
+// TODO(jgruber): Currently, RegExpLastMatchInfo is still a JSObject maintained |
+// and accessed from JS. This is a crutch until all RegExp logic is ported, then |
+// we can take care of RegExpLastMatchInfo. |
+ |
+Handle<Object> RegExpUtils::GetLastMatchField(Isolate* isolate, |
+ Handle<JSObject> match_info, |
+ int index) { |
+ return JSReceiver::GetElement(isolate, match_info, index).ToHandleChecked(); |
+} |
+ |
+void RegExpUtils::SetLastMatchField(Isolate* isolate, |
+ Handle<JSObject> match_info, int index, |
+ Handle<Object> value) { |
+ JSReceiver::SetElement(isolate, match_info, index, value, SLOPPY) |
+ .ToHandleChecked(); |
+} |
+ |
+int RegExpUtils::GetLastMatchNumberOfCaptures(Isolate* isolate, |
+ Handle<JSObject> match_info) { |
+ Handle<Object> obj = |
+ GetLastMatchField(isolate, match_info, RegExpImpl::kLastCaptureCount); |
+ return Handle<Smi>::cast(obj)->value(); |
+} |
+ |
+Handle<String> RegExpUtils::GetLastMatchSubject(Isolate* isolate, |
+ Handle<JSObject> match_info) { |
+ return Handle<String>::cast( |
+ GetLastMatchField(isolate, match_info, RegExpImpl::kLastSubject)); |
+} |
+ |
+Handle<Object> RegExpUtils::GetLastMatchInput(Isolate* isolate, |
+ Handle<JSObject> match_info) { |
+ return GetLastMatchField(isolate, match_info, RegExpImpl::kLastInput); |
+} |
+ |
+int RegExpUtils::GetLastMatchCapture(Isolate* isolate, |
+ Handle<JSObject> match_info, int i) { |
+ Handle<Object> obj = |
+ GetLastMatchField(isolate, match_info, RegExpImpl::kFirstCapture + i); |
+ return Handle<Smi>::cast(obj)->value(); |
+} |
+ |
+Handle<String> RegExpUtils::GenericCaptureGetter(Isolate* isolate, |
+ Handle<JSObject> match_info, |
+ int capture, bool* ok) { |
+ const int index = capture * 2; |
+ if (index >= GetLastMatchNumberOfCaptures(isolate, match_info)) { |
+ if (ok != nullptr) *ok = false; |
+ return isolate->factory()->empty_string(); |
+ } |
+ |
+ const int match_start = GetLastMatchCapture(isolate, match_info, index); |
+ const int match_end = GetLastMatchCapture(isolate, match_info, index + 1); |
+ if (match_start == -1 || match_end == -1) { |
+ if (ok != nullptr) *ok = false; |
+ return isolate->factory()->empty_string(); |
+ } |
+ |
+ if (ok != nullptr) *ok = true; |
+ Handle<String> last_subject = GetLastMatchSubject(isolate, match_info); |
+ return isolate->factory()->NewSubString(last_subject, match_start, match_end); |
+} |
+ |
+namespace { |
+ |
+V8_INLINE bool HasInitialRegExpMap(Isolate* isolate, Handle<JSReceiver> recv) { |
+ return recv->map() == isolate->regexp_function()->initial_map(); |
+} |
+ |
+} // namespace |
+ |
+MaybeHandle<Object> RegExpUtils::SetLastIndex(Isolate* isolate, |
+ Handle<JSReceiver> recv, |
+ int value) { |
+ if (HasInitialRegExpMap(isolate, recv)) { |
+ JSRegExp::cast(*recv)->SetLastIndex(value); |
+ return recv; |
+ } else { |
+ return Object::SetProperty(recv, isolate->factory()->lastIndex_string(), |
+ handle(Smi::FromInt(value), isolate), STRICT); |
+ } |
+} |
+ |
+MaybeHandle<Object> RegExpUtils::GetLastIndex(Isolate* isolate, |
+ Handle<JSReceiver> recv) { |
+ if (HasInitialRegExpMap(isolate, recv)) { |
+ return handle(JSRegExp::cast(*recv)->LastIndex(), isolate); |
+ } else { |
+ return Object::GetProperty(recv, isolate->factory()->lastIndex_string()); |
+ } |
+} |
+ |
+// ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) |
+// Also takes an optional exec method in case our caller |
+// has already fetched exec. |
+MaybeHandle<Object> RegExpUtils::RegExpExec(Isolate* isolate, |
+ Handle<JSReceiver> regexp, |
+ Handle<String> string, |
+ Handle<Object> exec) { |
+ if (exec->IsUndefined(isolate)) { |
+ ASSIGN_RETURN_ON_EXCEPTION( |
+ isolate, exec, |
+ Object::GetProperty( |
+ regexp, isolate->factory()->NewStringFromAsciiChecked("exec")), |
+ Object); |
+ } |
+ |
+ if (exec->IsCallable()) { |
+ const int argc = 1; |
+ ScopedVector<Handle<Object>> argv(argc); |
+ argv[0] = string; |
+ |
+ Handle<Object> result; |
+ ASSIGN_RETURN_ON_EXCEPTION( |
+ isolate, result, |
+ Execution::Call(isolate, exec, regexp, argc, argv.start()), Object); |
+ |
+ if (!result->IsJSReceiver() && !result->IsNull(isolate)) { |
+ THROW_NEW_ERROR(isolate, |
+ NewTypeError(MessageTemplate::kInvalidRegExpExecResult), |
+ Object); |
+ } |
+ return result; |
+ } |
+ |
+ if (!regexp->IsJSRegExp()) { |
+ THROW_NEW_ERROR(isolate, |
+ NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, |
+ isolate->factory()->NewStringFromAsciiChecked( |
+ "RegExp.prototype.exec"), |
+ regexp), |
+ Object); |
+ } |
+ |
+ { |
+ Handle<JSFunction> regexp_exec = isolate->regexp_exec_function(); |
+ |
+ const int argc = 1; |
+ ScopedVector<Handle<Object>> argv(argc); |
+ argv[0] = string; |
+ |
+ return Execution::Call(isolate, exec, regexp_exec, argc, argv.start()); |
+ } |
+} |
+ |
+Maybe<bool> RegExpUtils::IsRegExp(Isolate* isolate, Handle<Object> object) { |
+ if (!object->IsJSReceiver()) return Just(false); |
+ |
+ Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object); |
+ |
+ if (isolate->regexp_function()->initial_map() == receiver->map()) { |
+ // Fast-path for unmodified JSRegExp instances. |
+ // TODO(ishell): Adapt for new fast-path logic. |
+ return Just(true); |
+ } |
+ |
+ Handle<Object> match; |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
+ isolate, match, |
+ JSObject::GetProperty(receiver, isolate->factory()->match_symbol()), |
+ Nothing<bool>()); |
+ |
+ if (!match->IsUndefined(isolate)) return Just(match->BooleanValue()); |
+ return Just(object->IsJSRegExp()); |
+} |
+ |
+bool RegExpUtils::IsBuiltinExec(Handle<Object> exec) { |
+ if (!exec->IsJSFunction()) return false; |
+ |
+ Code* code = Handle<JSFunction>::cast(exec)->code(); |
+ if (code == nullptr) return false; |
+ |
+ return (code->builtin_index() == Builtins::kRegExpPrototypeExec); |
+} |
+ |
+// ES#sec-advancestringindex |
+// AdvanceStringIndex ( S, index, unicode ) |
+int RegExpUtils::AdvanceStringIndex(Isolate* isolate, Handle<String> string, |
+ int index, bool unicode) { |
+ int increment = 1; |
+ |
+ if (unicode && index < string->length()) { |
+ const uint16_t first = string->Get(index); |
+ if (first >= 0xD800 && first <= 0xDBFF && string->length() > index + 1) { |
+ const uint16_t second = string->Get(index + 1); |
+ if (second >= 0xDC00 && second <= 0xDFFF) { |
+ increment = 2; |
+ } |
+ } |
+ } |
+ |
+ return increment; |
+} |
+ |
+MaybeHandle<Object> RegExpUtils::SetAdvancedStringIndex( |
+ Isolate* isolate, Handle<JSReceiver> regexp, Handle<String> string, |
+ bool unicode) { |
+ Handle<Object> last_index_obj; |
+ ASSIGN_RETURN_ON_EXCEPTION( |
+ isolate, last_index_obj, |
+ Object::GetProperty(regexp, isolate->factory()->lastIndex_string()), |
+ Object); |
+ |
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, last_index_obj, |
+ Object::ToLength(isolate, last_index_obj), Object); |
+ |
+ const int last_index = Handle<Smi>::cast(last_index_obj)->value(); |
+ const int new_last_index = |
+ last_index + AdvanceStringIndex(isolate, string, last_index, unicode); |
+ |
+ return SetLastIndex(isolate, regexp, new_last_index); |
+} |
+ |
+} // namespace internal |
+} // namespace v8 |