Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(181)

Side by Side Diff: src/builtins/builtins-regexp.cc

Issue 2305573002: [regexp] Port RegExp getters and setters (Closed)
Patch Set: Fix for layout test expectations Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/builtins/builtins.h ('k') | src/heap-symbols.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/builtins/builtins.h" 5 #include "src/builtins/builtins.h"
6 #include "src/builtins/builtins-utils.h" 6 #include "src/builtins/builtins-utils.h"
7 7
8 #include "src/string-builder.h" 8 #include "src/string-builder.h"
9 9
10 namespace v8 { 10 namespace v8 {
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 141
142 Handle<JSObject> object; 142 Handle<JSObject> object;
143 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 143 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
144 isolate, object, JSObject::New(target, new_target_receiver)); 144 isolate, object, JSObject::New(target, new_target_receiver));
145 Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(object); 145 Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(object);
146 146
147 RETURN_RESULT_OR_FAILURE(isolate, 147 RETURN_RESULT_OR_FAILURE(isolate,
148 RegExpInitialize(isolate, regexp, pattern, flags)); 148 RegExpInitialize(isolate, regexp, pattern, flags));
149 } 149 }
150 150
151 #define APPEND_CHAR_FOR_FLAG(flag, c) \
152 do { \
153 Handle<Object> property; \
154 Handle<Name> name = isolate->factory()->flag##_string(); \
155 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, property, \
156 JSReceiver::GetProperty(recv, name)); \
157 if (property->BooleanValue()) { \
158 builder.AppendCharacter(c); \
159 } \
160 } while (false);
161
162 // ES6 21.2.5.3.
163 BUILTIN(RegExpPrototypeFlagsGetter) {
164 HandleScope scope(isolate);
165 CHECK_RECEIVER(JSReceiver, recv, "get RegExp.prototype.flags");
166
167 IncrementalStringBuilder builder(isolate);
168
169 APPEND_CHAR_FOR_FLAG(global, 'g');
170 APPEND_CHAR_FOR_FLAG(ignoreCase, 'i');
171 APPEND_CHAR_FOR_FLAG(multiline, 'm');
172 APPEND_CHAR_FOR_FLAG(unicode, 'u');
173 APPEND_CHAR_FOR_FLAG(sticky, 'y');
174
175 RETURN_RESULT_OR_FAILURE(isolate, builder.Finish());
176 }
177
178 #undef APPEND_CHAR_FOR_FLAG
179
180 // ES6 21.2.5.10.
181 BUILTIN(RegExpPrototypeSourceGetter) {
182 HandleScope scope(isolate);
183
184 Handle<Object> recv = args.receiver();
185 if (!recv->IsJSRegExp()) {
186 // TODO(littledan): Remove this RegExp compat workaround
187 Handle<JSFunction> regexp_fun = isolate->regexp_function();
188 if (*recv == regexp_fun->prototype()) {
189 isolate->CountUsage(v8::Isolate::kRegExpPrototypeSourceGetter);
190 return *isolate->factory()->NewStringFromAsciiChecked("(?:)");
191 }
192 THROW_NEW_ERROR_RETURN_FAILURE(
193 isolate, NewTypeError(MessageTemplate::kRegExpNonRegExp,
194 isolate->factory()->NewStringFromAsciiChecked(
195 "RegExp.prototype.source")));
196 }
197
198 Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(recv);
199 return regexp->source();
200 }
201
202 // ES6 21.2.4.2.
203 BUILTIN(RegExpPrototypeSpeciesGetter) {
204 HandleScope scope(isolate);
205 return *args.receiver();
206 }
207
208 #define REGEXP_FLAG_GETTER(name, counter, getter) \
209 BUILTIN(RegExpPrototype##name##Getter) { \
210 HandleScope scope(isolate); \
211 Handle<Object> recv = args.receiver(); \
212 if (!recv->IsJSRegExp()) { \
213 /* TODO(littledan): Remove this RegExp compat workaround */ \
214 Handle<JSFunction> regexp_fun = isolate->regexp_function(); \
215 if (*recv == regexp_fun->prototype()) { \
216 isolate->CountUsage(v8::Isolate::kRegExpPrototype##counter##Getter); \
217 return isolate->heap()->undefined_value(); \
218 } \
219 THROW_NEW_ERROR_RETURN_FAILURE( \
220 isolate, NewTypeError(MessageTemplate::kRegExpNonRegExp, \
221 isolate->factory()->NewStringFromAsciiChecked( \
222 getter))); \
223 } \
224 Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(recv); \
225 const bool ret = (regexp->GetFlags() & JSRegExp::k##name) != 0; \
226 return *isolate->factory()->ToBoolean(ret); \
227 }
228
229 // ES6 21.2.5.4.
230 REGEXP_FLAG_GETTER(Global, OldFlag, "RegExp.prototype.global")
231
232 // ES6 21.2.5.5.
233 REGEXP_FLAG_GETTER(IgnoreCase, OldFlag, "RegExp.prototype.ignoreCase")
234
235 // ES6 21.2.5.7.
236 REGEXP_FLAG_GETTER(Multiline, OldFlag, "RegExp.prototype.multiline")
237
238 // ES6 21.2.5.12.
239 REGEXP_FLAG_GETTER(Sticky, Sticky, "RegExp.prototype.sticky")
240
241 // ES6 21.2.5.15.
242 REGEXP_FLAG_GETTER(Unicode, Unicode, "RegExp.prototype.unicode")
243
244 #undef REGEXP_FLAG_GETTER
245
246 namespace {
247
248 // Constants for accessing RegExpLastMatchInfo.
249 // TODO(jgruber): Currently, RegExpLastMatchInfo is still a JSObject maintained
250 // and accessed from JS. This is a crutch until all RegExp logic is ported, then
251 // we can take care of RegExpLastMatchInfo.
252 const int kNumberOfCapturesIndex = 0;
253 const int kLastSubjectIndex = 1;
254 const int kLastInputIndex = 2;
255 const int kFirstCaptureIndex = 3;
256
257 Handle<Object> GetLastMatchField(Isolate* isolate, int index) {
258 Handle<JSFunction> global_regexp = isolate->regexp_function();
259 Handle<Object> last_match_info_obj = JSReceiver::GetDataProperty(
260 global_regexp, isolate->factory()->regexp_last_match_info_symbol());
261
262 Handle<JSReceiver> last_match_info =
263 Handle<JSReceiver>::cast(last_match_info_obj);
264 return JSReceiver::GetElement(isolate, last_match_info, index)
265 .ToHandleChecked();
266 }
267
268 void SetLastMatchField(Isolate* isolate, int index, Handle<Object> value) {
269 Handle<JSFunction> global_regexp = isolate->regexp_function();
270 Handle<Object> last_match_info_obj = JSReceiver::GetDataProperty(
271 global_regexp, isolate->factory()->regexp_last_match_info_symbol());
272
273 Handle<JSReceiver> last_match_info =
274 Handle<JSReceiver>::cast(last_match_info_obj);
275 JSReceiver::SetElement(isolate, last_match_info, index, value, SLOPPY)
276 .ToHandleChecked();
277 }
278
279 int GetLastMatchNumberOfCaptures(Isolate* isolate) {
280 Handle<Object> obj = GetLastMatchField(isolate, kNumberOfCapturesIndex);
281 return Handle<Smi>::cast(obj)->value();
282 }
283
284 Handle<String> GetLastMatchSubject(Isolate* isolate) {
285 return Handle<String>::cast(GetLastMatchField(isolate, kLastSubjectIndex));
286 }
287
288 Handle<Object> GetLastMatchInput(Isolate* isolate) {
289 return GetLastMatchField(isolate, kLastInputIndex);
290 }
291
292 int GetLastMatchCapture(Isolate* isolate, int i) {
293 Handle<Object> obj = GetLastMatchField(isolate, kFirstCaptureIndex + i);
294 return Handle<Smi>::cast(obj)->value();
295 }
296
297 Object* GenericCaptureGetter(Isolate* isolate, int capture) {
298 HandleScope scope(isolate);
299 const int index = capture * 2;
300 if (index >= GetLastMatchNumberOfCaptures(isolate)) {
301 return isolate->heap()->empty_string();
302 }
303
304 const int match_start = GetLastMatchCapture(isolate, index);
305 const int match_end = GetLastMatchCapture(isolate, index + 1);
306 if (match_start == -1 || match_end == -1) {
307 return isolate->heap()->empty_string();
308 }
309
310 Handle<String> last_subject = GetLastMatchSubject(isolate);
311 return *isolate->factory()->NewSubString(last_subject, match_start,
312 match_end);
313 }
314
315 } // namespace
316
317 // The properties $1..$9 are the first nine capturing substrings of the last
318 // successful match, or ''. The function RegExpMakeCaptureGetter will be
319 // called with indices from 1 to 9.
320 #define DEFINE_CAPTURE_GETTER(i) \
321 BUILTIN(RegExpPrototypeCapture##i##Getter) { \
322 HandleScope scope(isolate); \
323 return GenericCaptureGetter(isolate, i); \
324 }
325 DEFINE_CAPTURE_GETTER(1)
326 DEFINE_CAPTURE_GETTER(2)
327 DEFINE_CAPTURE_GETTER(3)
328 DEFINE_CAPTURE_GETTER(4)
329 DEFINE_CAPTURE_GETTER(5)
330 DEFINE_CAPTURE_GETTER(6)
331 DEFINE_CAPTURE_GETTER(7)
332 DEFINE_CAPTURE_GETTER(8)
333 DEFINE_CAPTURE_GETTER(9)
334 #undef DEFINE_CAPTURE_GETTER
335
336 // The properties `input` and `$_` are aliases for each other. When this
337 // value is set the value it is set to is coerced to a string.
338 // Getter and setter for the input.
339
340 BUILTIN(RegExpPrototypeInputGetter) {
341 HandleScope scope(isolate);
342 Handle<Object> obj = GetLastMatchInput(isolate);
343 return obj->IsUndefined(isolate) ? isolate->heap()->empty_string()
344 : String::cast(*obj);
345 }
346
347 BUILTIN(RegExpPrototypeInputSetter) {
348 HandleScope scope(isolate);
349 Handle<Object> value = args.atOrUndefined(isolate, 1);
350 Handle<String> str;
351 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, str,
352 Object::ToString(isolate, value));
353 SetLastMatchField(isolate, kLastInputIndex, str);
354 return isolate->heap()->undefined_value();
355 }
356
357 // Getters for the static properties lastMatch, lastParen, leftContext, and
358 // rightContext of the RegExp constructor. The properties are computed based
359 // on the captures array of the last successful match and the subject string
360 // of the last successful match.
361 BUILTIN(RegExpPrototypeLastMatchGetter) {
362 HandleScope scope(isolate);
363 return GenericCaptureGetter(isolate, 0);
364 }
365
366 BUILTIN(RegExpPrototypeLastParenGetter) {
367 HandleScope scope(isolate);
368 const int length = GetLastMatchNumberOfCaptures(isolate);
369 if (length <= 2) return isolate->heap()->empty_string(); // No captures.
370
371 DCHECK_EQ(0, length % 2);
372 const int last_capture = (length / 2) - 1;
373
374 // We match the SpiderMonkey behavior: return the substring defined by the
375 // last pair (after the first pair) of elements of the capture array even if
376 // it is empty.
377 return GenericCaptureGetter(isolate, last_capture);
378 }
379
380 BUILTIN(RegExpPrototypeLeftContextGetter) {
381 HandleScope scope(isolate);
382 const int start_index = GetLastMatchCapture(isolate, 0);
383 Handle<String> last_subject = GetLastMatchSubject(isolate);
384 return *isolate->factory()->NewSubString(last_subject, 0, start_index);
385 }
386
387 BUILTIN(RegExpPrototypeRightContextGetter) {
388 HandleScope scope(isolate);
389 const int start_index = GetLastMatchCapture(isolate, 1);
390 Handle<String> last_subject = GetLastMatchSubject(isolate);
391 const int len = last_subject->length();
392 return *isolate->factory()->NewSubString(last_subject, start_index, len);
393 }
394
151 } // namespace internal 395 } // namespace internal
152 } // namespace v8 396 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins.h ('k') | src/heap-symbols.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698