Home | History | Annotate | Download | only in builtins
      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 
     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 
     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 
     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.
    103 BUILTIN(RegExpLastMatchGetter) {
    104   HandleScope scope(isolate);
    105   return *RegExpUtils::GenericCaptureGetter(
    106       isolate, isolate->regexp_last_match_info(), 0);
    107 }
    108 
    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 
    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 
    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