Chromium Code Reviews| Index: src/builtins/builtins-regexp.cc |
| diff --git a/src/builtins/builtins-regexp.cc b/src/builtins/builtins-regexp.cc |
| index 5f62efabfe6830f15737139f4a652a86ec3a2c9b..2ed4fd9de269351a6c7374e734127a9eb1cabb16 100644 |
| --- a/src/builtins/builtins-regexp.cc |
| +++ b/src/builtins/builtins-regexp.cc |
| @@ -7,10 +7,152 @@ |
| #include "src/code-factory.h" |
| #include "src/regexp/jsregexp.h" |
| +#include "src/string-builder.h" |
| 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) { |
| + IncrementalStringBuilder builder(isolate); |
|
Yang
2016/10/05 07:40:34
Using the IncrementalStringBuilder is a bit overki
jgruber
2016/10/05 08:37:03
Good point, done. We could improve this even more
|
| + const JSRegExp::Flags flags = regexp->GetFlags(); |
| + |
| + if ((flags & JSRegExp::kGlobal) != 0) builder.AppendCharacter('g'); |
| + if ((flags & JSRegExp::kIgnoreCase) != 0) builder.AppendCharacter('i'); |
| + if ((flags & JSRegExp::kMultiline) != 0) builder.AppendCharacter('m'); |
| + if ((flags & JSRegExp::kUnicode) != 0) builder.AppendCharacter('u'); |
| + if ((flags & JSRegExp::kSticky) != 0) builder.AppendCharacter('y'); |
| + |
| + return builder.Finish().ToHandleChecked(); |
| +} |
| + |
| +// 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, |