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 |