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

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

Issue 2305573002: [regexp] Port RegExp getters and setters (Closed)
Patch Set: Format 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
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): Move to C++.
Benedikt Meurer 2016/09/01 10:22:34 This is C++?
jgruber 2016/09/01 10:36:39 The comment is about moving the RegExpLastMatchInf
250 static const int kNumberOfCapturesIndex = 0;
Benedikt Meurer 2016/09/01 10:22:33 Nit: You don't need static inside anonymous namesp
jgruber 2016/09/01 10:36:39 Done.
251 static const int kLastSubjectIndex = 1;
252 static const int kLastInputIndex = 2;
253 static const int kFirstCaptureIndex = 3;
254
255 Handle<Object> GetLastMatchField(Isolate* isolate, int index) {
256 Handle<JSFunction> global_regexp = isolate->regexp_function();
257 Handle<Object> last_match_info_obj = JSReceiver::GetDataProperty(
258 global_regexp, isolate->factory()->regexp_last_match_info_symbol());
259
260 Handle<JSReceiver> last_match_info =
261 Handle<JSReceiver>::cast(last_match_info_obj);
262 return JSReceiver::GetElement(isolate, last_match_info, index)
263 .ToHandleChecked();
264 }
265
266 void SetLastMatchField(Isolate* isolate, int index, Handle<Object> value) {
267 Handle<JSFunction> global_regexp = isolate->regexp_function();
268 Handle<Object> last_match_info_obj = JSReceiver::GetDataProperty(
269 global_regexp, isolate->factory()->regexp_last_match_info_symbol());
270
271 Handle<JSReceiver> last_match_info =
272 Handle<JSReceiver>::cast(last_match_info_obj);
273 JSReceiver::SetElement(isolate, last_match_info, index, value, SLOPPY)
274 .ToHandleChecked();
275 }
276
277 int GetLastMatchNumberOfCaptures(Isolate* isolate) {
278 Handle<Object> obj = GetLastMatchField(isolate, kNumberOfCapturesIndex);
279 return Handle<Smi>::cast(obj)->value();
280 }
281
282 Handle<String> GetLastMatchSubject(Isolate* isolate) {
283 return Handle<String>::cast(GetLastMatchField(isolate, kLastSubjectIndex));
284 }
285
286 Handle<Object> GetLastMatchInput(Isolate* isolate) {
287 return GetLastMatchField(isolate, kLastInputIndex);
288 }
289
290 int GetLastMatchCapture(Isolate* isolate, int i) {
291 Handle<Object> obj = GetLastMatchField(isolate, kFirstCaptureIndex + i);
292 return Handle<Smi>::cast(obj)->value();
293 }
294
295 Object* GenericCaptureGetter(Isolate* isolate, int capture) {
296 HandleScope scope(isolate);
297 const int index = capture * 2;
298 if (index >= GetLastMatchNumberOfCaptures(isolate)) {
299 return isolate->heap()->empty_string();
300 }
301
302 const int match_start = GetLastMatchCapture(isolate, index);
303 const int match_end = GetLastMatchCapture(isolate, index + 1);
304 if (match_start == -1 || match_end == -1) {
305 return isolate->heap()->empty_string();
306 }
307
308 Handle<String> last_subject = GetLastMatchSubject(isolate);
309 return *isolate->factory()->NewSubString(last_subject, match_start,
310 match_end);
311 }
312
313 } // namespace
314
315 // The properties $1..$9 are the first nine capturing substrings of the last
316 // successful match, or ''. The function RegExpMakeCaptureGetter will be
317 // called with indices from 1 to 9.
318 #define DEFINE_CAPTURE_GETTER(i) \
319 BUILTIN(RegExpPrototypeCapture##i##Getter) { \
320 HandleScope scope(isolate); \
321 return GenericCaptureGetter(isolate, i); \
322 }
323 DEFINE_CAPTURE_GETTER(1)
324 DEFINE_CAPTURE_GETTER(2)
325 DEFINE_CAPTURE_GETTER(3)
326 DEFINE_CAPTURE_GETTER(4)
327 DEFINE_CAPTURE_GETTER(5)
328 DEFINE_CAPTURE_GETTER(6)
329 DEFINE_CAPTURE_GETTER(7)
330 DEFINE_CAPTURE_GETTER(8)
331 DEFINE_CAPTURE_GETTER(9)
332 #undef DEFINE_CAPTURE_GETTER
333
334 // The properties `input` and `$_` are aliases for each other. When this
335 // value is set the value it is set to is coerced to a string.
336 // Getter and setter for the input.
337
338 BUILTIN(RegExpPrototypeInputGetter) {
339 HandleScope scope(isolate);
340 Handle<Object> obj = GetLastMatchInput(isolate);
341 return obj->IsUndefined(isolate) ? isolate->heap()->empty_string()
342 : String::cast(*obj);
343 }
344
345 BUILTIN(RegExpPrototypeInputSetter) {
346 HandleScope scope(isolate);
347 Handle<Object> value = args.atOrUndefined(isolate, 1);
348 Handle<String> str;
349 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, str,
350 Object::ToString(isolate, value));
351 SetLastMatchField(isolate, kLastInputIndex, str);
352 return isolate->heap()->undefined_value();
353 }
354
355 // Getters for the static properties lastMatch, lastParen, leftContext, and
356 // rightContext of the RegExp constructor. The properties are computed based
357 // on the captures array of the last successful match and the subject string
358 // of the last successful match.
359 BUILTIN(RegExpPrototypeLastMatchGetter) {
360 HandleScope scope(isolate);
361 return GenericCaptureGetter(isolate, 0);
362 }
363
364 BUILTIN(RegExpPrototypeLastParenGetter) {
365 HandleScope scope(isolate);
366 const int length = GetLastMatchNumberOfCaptures(isolate);
367 if (length <= 2) return isolate->heap()->empty_string(); // No captures.
368
369 DCHECK_EQ(0, length % 2);
370 const int last_capture = (length / 2) - 1;
371
372 // We match the SpiderMonkey behavior: return the substring defined by the
373 // last pair (after the first pair) of elements of the capture array even if
374 // it is empty.
375 return GenericCaptureGetter(isolate, last_capture);
376 }
377
378 BUILTIN(RegExpPrototypeLeftContextGetter) {
379 HandleScope scope(isolate);
380 const int start_index = GetLastMatchCapture(isolate, 0);
381 Handle<String> last_subject = GetLastMatchSubject(isolate);
382 return *isolate->factory()->NewSubString(last_subject, 0, start_index);
383 }
384
385 BUILTIN(RegExpPrototypeRightContextGetter) {
386 HandleScope scope(isolate);
387 const int start_index = GetLastMatchCapture(isolate, 1);
388 Handle<String> last_subject = GetLastMatchSubject(isolate);
389 const int len = last_subject->length();
390 return *isolate->factory()->NewSubString(last_subject, start_index, len);
391 }
392
151 } // namespace internal 393 } // namespace internal
152 } // namespace v8 394 } // namespace v8
OLDNEW
« src/accessors.cc ('K') | « src/builtins/builtins.h ('k') | src/heap-symbols.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698