Index: src/builtins/builtins-regexp.cc |
diff --git a/src/builtins/builtins-regexp.cc b/src/builtins/builtins-regexp.cc |
index d720bbed011dd2e67f8be57550b6b9f518f832f9..371221fa70a8d0d49c83e2c38bd2e37ddbc77668 100644 |
--- a/src/builtins/builtins-regexp.cc |
+++ b/src/builtins/builtins-regexp.cc |
@@ -11,6 +11,153 @@ |
namespace v8 { |
namespace internal { |
+// ----------------------------------------------------------------------------- |
+// ES6 section 21.2 RegExp Objects |
+ |
+namespace { |
+ |
+// ES#sec-isregexp IsRegExp ( argument ) |
+Maybe<bool> 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. |
+ 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()); |
+} |
+ |
+Handle<String> PatternFlags(Isolate* isolate, Handle<JSRegExp> regexp) { |
+ static const int kMaxFlagsLength = 5 + 1; // 5 flags and '\0'; |
+ char flags_string[kMaxFlagsLength]; |
+ int i = 0; |
+ |
+ const JSRegExp::Flags flags = regexp->GetFlags(); |
+ |
+ if ((flags & JSRegExp::kGlobal) != 0) flags_string[i++] = 'g'; |
+ if ((flags & JSRegExp::kIgnoreCase) != 0) flags_string[i++] = 'i'; |
+ if ((flags & JSRegExp::kMultiline) != 0) flags_string[i++] = 'm'; |
+ if ((flags & JSRegExp::kUnicode) != 0) flags_string[i++] = 'u'; |
+ if ((flags & JSRegExp::kSticky) != 0) flags_string[i++] = 'y'; |
+ |
+ DCHECK_LT(i, kMaxFlagsLength); |
+ memset(&flags_string[i], '\0', kMaxFlagsLength - i); |
+ |
+ return isolate->factory()->NewStringFromAsciiChecked(flags_string); |
+} |
+ |
+// ES#sec-regexpinitialize |
+// Runtime Semantics: RegExpInitialize ( obj, pattern, flags ) |
+MaybeHandle<JSRegExp> RegExpInitialize(Isolate* isolate, |
+ Handle<JSRegExp> regexp, |
+ Handle<Object> pattern, |
+ Handle<Object> flags) { |
+ Handle<String> pattern_string; |
+ if (pattern->IsUndefined(isolate)) { |
+ pattern_string = isolate->factory()->empty_string(); |
+ } else { |
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, pattern_string, |
+ Object::ToString(isolate, pattern), JSRegExp); |
+ } |
+ |
+ Handle<String> flags_string; |
+ if (flags->IsUndefined(isolate)) { |
+ flags_string = isolate->factory()->empty_string(); |
+ } else { |
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, flags_string, |
+ Object::ToString(isolate, flags), JSRegExp); |
+ } |
+ |
+ // TODO(jgruber): We could avoid the flags back and forth conversions. |
+ RETURN_RESULT(isolate, |
+ JSRegExp::Initialize(regexp, pattern_string, flags_string), |
+ JSRegExp); |
+} |
+ |
+} // namespace |
+ |
+// ES#sec-regexp-pattern-flags |
+// RegExp ( pattern, flags ) |
+BUILTIN(RegExpConstructor) { |
+ HandleScope scope(isolate); |
+ |
+ Handle<HeapObject> new_target = args.new_target(); |
+ Handle<Object> pattern = args.atOrUndefined(isolate, 1); |
+ Handle<Object> flags = args.atOrUndefined(isolate, 2); |
+ |
+ Handle<JSFunction> target = isolate->regexp_function(); |
+ |
+ bool pattern_is_regexp; |
+ { |
+ Maybe<bool> maybe_pattern_is_regexp = IsRegExp(isolate, pattern); |
+ if (maybe_pattern_is_regexp.IsNothing()) { |
+ DCHECK(isolate->has_pending_exception()); |
+ return isolate->heap()->exception(); |
+ } |
+ pattern_is_regexp = maybe_pattern_is_regexp.FromJust(); |
+ } |
+ |
+ if (new_target->IsUndefined(isolate)) { |
+ new_target = target; |
+ |
+ // ES6 section 21.2.3.1 step 3.b |
+ if (pattern_is_regexp && flags->IsUndefined(isolate)) { |
+ Handle<Object> pattern_constructor; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, pattern_constructor, |
+ Object::GetProperty(pattern, |
+ isolate->factory()->constructor_string())); |
+ |
+ if (pattern_constructor.is_identical_to(new_target)) { |
+ return *pattern; |
+ } |
+ } |
+ } |
+ |
+ if (pattern->IsJSRegExp()) { |
+ Handle<JSRegExp> regexp_pattern = Handle<JSRegExp>::cast(pattern); |
+ |
+ if (flags->IsUndefined(isolate)) { |
+ flags = PatternFlags(isolate, regexp_pattern); |
+ } |
+ pattern = handle(regexp_pattern->source(), isolate); |
+ } else if (pattern_is_regexp) { |
+ Handle<Object> pattern_source; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, pattern_source, |
+ Object::GetProperty(pattern, isolate->factory()->source_string())); |
+ |
+ if (flags->IsUndefined(isolate)) { |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, flags, |
+ Object::GetProperty(pattern, isolate->factory()->flags_string())); |
+ } |
+ pattern = pattern_source; |
+ } |
+ |
+ Handle<JSReceiver> new_target_receiver = Handle<JSReceiver>::cast(new_target); |
+ |
+ // TODO(jgruber): Fast-path for target == new_target == unmodified JSRegExp. |
+ |
+ Handle<JSObject> object; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, object, JSObject::New(target, new_target_receiver)); |
+ Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(object); |
+ |
+ RETURN_RESULT_OR_FAILURE(isolate, |
+ RegExpInitialize(isolate, regexp, pattern, flags)); |
+} |
+ |
namespace { |
compiler::Node* LoadLastIndex(CodeStubAssembler* a, compiler::Node* context, |