• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-utils-inl.h"
6 #include "src/builtins/builtins.h"
7 #include "src/counters.h"
8 #include "src/objects-inl.h"
9 #include "src/regexp/jsregexp.h"
10 #include "src/regexp/regexp-utils.h"
11 #include "src/string-builder-inl.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 // -----------------------------------------------------------------------------
17 // ES6 section 21.2 RegExp Objects
18 
BUILTIN(RegExpPrototypeToString)19 BUILTIN(RegExpPrototypeToString) {
20   HandleScope scope(isolate);
21   CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.toString");
22 
23   if (*recv == isolate->regexp_function()->prototype()) {
24     isolate->CountUsage(v8::Isolate::kRegExpPrototypeToString);
25   }
26 
27   IncrementalStringBuilder builder(isolate);
28 
29   builder.AppendCharacter('/');
30   {
31     Handle<Object> source;
32     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
33         isolate, source,
34         JSReceiver::GetProperty(isolate, recv,
35                                 isolate->factory()->source_string()));
36     Handle<String> source_str;
37     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, source_str,
38                                        Object::ToString(isolate, source));
39     builder.AppendString(source_str);
40   }
41 
42   builder.AppendCharacter('/');
43   {
44     Handle<Object> flags;
45     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
46         isolate, flags,
47         JSReceiver::GetProperty(isolate, recv,
48                                 isolate->factory()->flags_string()));
49     Handle<String> flags_str;
50     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, flags_str,
51                                        Object::ToString(isolate, flags));
52     builder.AppendString(flags_str);
53   }
54 
55   RETURN_RESULT_OR_FAILURE(isolate, builder.Finish());
56 }
57 
58 // The properties $1..$9 are the first nine capturing substrings of the last
59 // successful match, or ''.  The function RegExpMakeCaptureGetter will be
60 // called with indices from 1 to 9.
61 #define DEFINE_CAPTURE_GETTER(i)                        \
62   BUILTIN(RegExpCapture##i##Getter) {                   \
63     HandleScope scope(isolate);                         \
64     return *RegExpUtils::GenericCaptureGetter(          \
65         isolate, isolate->regexp_last_match_info(), i); \
66   }
67 DEFINE_CAPTURE_GETTER(1)
68 DEFINE_CAPTURE_GETTER(2)
69 DEFINE_CAPTURE_GETTER(3)
70 DEFINE_CAPTURE_GETTER(4)
71 DEFINE_CAPTURE_GETTER(5)
72 DEFINE_CAPTURE_GETTER(6)
73 DEFINE_CAPTURE_GETTER(7)
74 DEFINE_CAPTURE_GETTER(8)
75 DEFINE_CAPTURE_GETTER(9)
76 #undef DEFINE_CAPTURE_GETTER
77 
78 // The properties `input` and `$_` are aliases for each other.  When this
79 // value is set, the value it is set to is coerced to a string.
80 // Getter and setter for the input.
81 
BUILTIN(RegExpInputGetter)82 BUILTIN(RegExpInputGetter) {
83   HandleScope scope(isolate);
84   Handle<Object> obj(isolate->regexp_last_match_info()->LastInput(), isolate);
85   return obj->IsUndefined(isolate) ? ReadOnlyRoots(isolate).empty_string()
86                                    : String::cast(*obj);
87 }
88 
BUILTIN(RegExpInputSetter)89 BUILTIN(RegExpInputSetter) {
90   HandleScope scope(isolate);
91   Handle<Object> value = args.atOrUndefined(isolate, 1);
92   Handle<String> str;
93   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, str,
94                                      Object::ToString(isolate, value));
95   isolate->regexp_last_match_info()->SetLastInput(*str);
96   return ReadOnlyRoots(isolate).undefined_value();
97 }
98 
99 // Getters for the static properties lastMatch, lastParen, leftContext, and
100 // rightContext of the RegExp constructor.  The properties are computed based
101 // on the captures array of the last successful match and the subject string
102 // of the last successful match.
BUILTIN(RegExpLastMatchGetter)103 BUILTIN(RegExpLastMatchGetter) {
104   HandleScope scope(isolate);
105   return *RegExpUtils::GenericCaptureGetter(
106       isolate, isolate->regexp_last_match_info(), 0);
107 }
108 
BUILTIN(RegExpLastParenGetter)109 BUILTIN(RegExpLastParenGetter) {
110   HandleScope scope(isolate);
111   Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info();
112   const int length = match_info->NumberOfCaptureRegisters();
113   if (length <= 2) {
114     return ReadOnlyRoots(isolate).empty_string();  // No captures.
115   }
116 
117   DCHECK_EQ(0, length % 2);
118   const int last_capture = (length / 2) - 1;
119 
120   // We match the SpiderMonkey behavior: return the substring defined by the
121   // last pair (after the first pair) of elements of the capture array even if
122   // it is empty.
123   return *RegExpUtils::GenericCaptureGetter(isolate, match_info, last_capture);
124 }
125 
BUILTIN(RegExpLeftContextGetter)126 BUILTIN(RegExpLeftContextGetter) {
127   HandleScope scope(isolate);
128   Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info();
129   const int start_index = match_info->Capture(0);
130   Handle<String> last_subject(match_info->LastSubject(), isolate);
131   return *isolate->factory()->NewSubString(last_subject, 0, start_index);
132 }
133 
BUILTIN(RegExpRightContextGetter)134 BUILTIN(RegExpRightContextGetter) {
135   HandleScope scope(isolate);
136   Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info();
137   const int start_index = match_info->Capture(1);
138   Handle<String> last_subject(match_info->LastSubject(), isolate);
139   const int len = last_subject->length();
140   return *isolate->factory()->NewSubString(last_subject, start_index, len);
141 }
142 
143 }  // namespace internal
144 }  // namespace v8
145