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/logging/counters.h"
8#include "src/objects/objects-inl.h"
9#include "src/regexp/regexp-utils.h"
10#include "src/regexp/regexp.h"
11#include "src/strings/string-builder-inl.h"
12
13namespace v8 {
14namespace internal {
15
16// -----------------------------------------------------------------------------
17// ES6 section 21.2 RegExp Objects
18
19BUILTIN(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  }
67DEFINE_CAPTURE_GETTER(1)
68DEFINE_CAPTURE_GETTER(2)
69DEFINE_CAPTURE_GETTER(3)
70DEFINE_CAPTURE_GETTER(4)
71DEFINE_CAPTURE_GETTER(5)
72DEFINE_CAPTURE_GETTER(6)
73DEFINE_CAPTURE_GETTER(7)
74DEFINE_CAPTURE_GETTER(8)
75DEFINE_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
82BUILTIN(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
89BUILTIN(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.
103BUILTIN(RegExpLastMatchGetter) {
104  HandleScope scope(isolate);
105  return *RegExpUtils::GenericCaptureGetter(
106      isolate, isolate->regexp_last_match_info(), 0);
107}
108
109BUILTIN(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
126BUILTIN(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
134BUILTIN(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