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/builtins/builtins.h" |
| 6 #include "src/builtins/builtins-utils.h" |
| 7 |
| 8 #include "src/string-builder.h" |
| 9 |
| 10 namespace v8 { |
| 11 namespace internal { |
| 12 |
| 13 // ----------------------------------------------------------------------------- |
| 14 // ES6 section 21.2 RegExp Objects |
| 15 |
| 16 namespace { |
| 17 |
| 18 // ES#sec-isregexp IsRegExp ( argument ) |
| 19 Maybe<bool> IsRegExp(Isolate* isolate, Handle<Object> object) { |
| 20 if (!object->IsJSReceiver()) return Just(false); |
| 21 |
| 22 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object); |
| 23 |
| 24 Handle<Object> match; |
| 25 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 26 isolate, match, |
| 27 JSObject::GetProperty(receiver, isolate->factory()->match_symbol()), |
| 28 Nothing<bool>()); |
| 29 |
| 30 if (!match->IsUndefined(isolate)) return Just(match->BooleanValue()); |
| 31 return Just(object->IsJSRegExp()); |
| 32 } |
| 33 |
| 34 Handle<String> PatternFlags(Isolate* isolate, Handle<JSRegExp> regexp) { |
| 35 IncrementalStringBuilder builder(isolate); |
| 36 const JSRegExp::Flags flags = regexp->GetFlags(); |
| 37 |
| 38 if ((flags & JSRegExp::kGlobal) != 0) builder.AppendCharacter('g'); |
| 39 if ((flags & JSRegExp::kIgnoreCase) != 0) builder.AppendCharacter('i'); |
| 40 if ((flags & JSRegExp::kMultiline) != 0) builder.AppendCharacter('m'); |
| 41 if ((flags & JSRegExp::kUnicode) != 0) builder.AppendCharacter('u'); |
| 42 if ((flags & JSRegExp::kSticky) != 0) builder.AppendCharacter('y'); |
| 43 |
| 44 return builder.Finish().ToHandleChecked(); |
| 45 } |
| 46 |
| 47 // ES#sec-regexpinitialize |
| 48 // Runtime Semantics: RegExpInitialize ( obj, pattern, flags ) |
| 49 MaybeHandle<JSRegExp> RegExpInitialize(Isolate* isolate, |
| 50 Handle<JSRegExp> regexp, |
| 51 Handle<Object> pattern, |
| 52 Handle<Object> flags) { |
| 53 Handle<String> pattern_string; |
| 54 if (pattern->IsUndefined(isolate)) { |
| 55 pattern_string = isolate->factory()->empty_string(); |
| 56 } else { |
| 57 ASSIGN_RETURN_ON_EXCEPTION(isolate, pattern_string, |
| 58 Object::ToString(isolate, pattern), JSRegExp); |
| 59 } |
| 60 |
| 61 Handle<String> flags_string; |
| 62 if (flags->IsUndefined(isolate)) { |
| 63 flags_string = isolate->factory()->empty_string(); |
| 64 } else { |
| 65 ASSIGN_RETURN_ON_EXCEPTION(isolate, flags_string, |
| 66 Object::ToString(isolate, flags), JSRegExp); |
| 67 } |
| 68 |
| 69 // TODO(jgruber): We could avoid the flags back and forth conversions. |
| 70 RETURN_RESULT(isolate, |
| 71 JSRegExp::Initialize(regexp, pattern_string, flags_string), |
| 72 JSRegExp); |
| 73 } |
| 74 |
| 75 } // namespace |
| 76 |
| 77 // ES#sec-regexp-pattern-flags |
| 78 // RegExp ( pattern, flags ) |
| 79 BUILTIN(RegExpConstructor) { |
| 80 HandleScope scope(isolate); |
| 81 |
| 82 Handle<HeapObject> new_target = args.new_target(); |
| 83 Handle<Object> pattern = args.atOrUndefined(isolate, 1); |
| 84 Handle<Object> flags = args.atOrUndefined(isolate, 2); |
| 85 |
| 86 Handle<JSFunction> target = |
| 87 handle(isolate->native_context()->regexp_function(), isolate); |
| 88 |
| 89 bool pattern_is_regexp; |
| 90 { |
| 91 Maybe<bool> maybe_pattern_is_regexp = IsRegExp(isolate, pattern); |
| 92 if (maybe_pattern_is_regexp.IsNothing()) { |
| 93 DCHECK(isolate->has_pending_exception()); |
| 94 return isolate->heap()->exception(); |
| 95 } |
| 96 pattern_is_regexp = maybe_pattern_is_regexp.FromJust(); |
| 97 } |
| 98 |
| 99 if (new_target->IsUndefined(isolate)) { |
| 100 new_target = target; |
| 101 |
| 102 // ES6 section 21.2.3.1 step 3.b |
| 103 if (pattern_is_regexp && flags->IsUndefined(isolate)) { |
| 104 Handle<Object> pattern_constructor; |
| 105 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 106 isolate, pattern_constructor, |
| 107 Object::GetProperty(pattern, |
| 108 isolate->factory()->constructor_string())); |
| 109 |
| 110 if (*pattern_constructor == *new_target) { |
| 111 return *pattern; |
| 112 } |
| 113 } |
| 114 } else if (!new_target->IsJSReceiver()) { |
| 115 // TODO(jgruber): Better error message. |
| 116 THROW_NEW_ERROR_RETURN_FAILURE( |
| 117 isolate, NewTypeError(MessageTemplate::kCalledNonCallable, new_target)); |
| 118 } |
| 119 Handle<JSReceiver> new_target_receiver = Handle<JSReceiver>::cast(new_target); |
| 120 |
| 121 if (pattern->IsJSRegExp()) { |
| 122 Handle<JSRegExp> regexp_pattern = Handle<JSRegExp>::cast(pattern); |
| 123 |
| 124 if (flags->IsUndefined(isolate)) { |
| 125 flags = PatternFlags(isolate, regexp_pattern); |
| 126 } |
| 127 pattern = handle(regexp_pattern->source(), isolate); |
| 128 } else if (pattern_is_regexp) { |
| 129 Handle<Object> pattern_source; |
| 130 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 131 isolate, pattern_source, |
| 132 Object::GetProperty(pattern, isolate->factory()->source_string())); |
| 133 |
| 134 if (flags->IsUndefined(isolate)) { |
| 135 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 136 isolate, flags, |
| 137 Object::GetProperty(pattern, isolate->factory()->flags_string())); |
| 138 } |
| 139 pattern = pattern_source; |
| 140 } |
| 141 |
| 142 Handle<JSObject> object; |
| 143 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 144 isolate, object, JSObject::New(target, new_target_receiver)); |
| 145 Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(object); |
| 146 |
| 147 RETURN_RESULT_OR_FAILURE(isolate, |
| 148 RegExpInitialize(isolate, regexp, pattern, flags)); |
| 149 } |
| 150 |
| 151 } // namespace internal |
| 152 } // namespace v8 |
OLD | NEW |