Home | History | Annotate | Download | only in inspector
      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/inspector/v8-regex.h"
      6 
      7 #include <limits.h>
      8 
      9 #include "src/inspector/string-util.h"
     10 #include "src/inspector/v8-inspector-impl.h"
     11 
     12 #include "include/v8-inspector.h"
     13 
     14 namespace v8_inspector {
     15 
     16 V8Regex::V8Regex(V8InspectorImpl* inspector, const String16& pattern,
     17                  bool caseSensitive, bool multiline)
     18     : m_inspector(inspector) {
     19   v8::Isolate* isolate = m_inspector->isolate();
     20   v8::HandleScope handleScope(isolate);
     21   v8::Local<v8::Context> context = m_inspector->regexContext();
     22   v8::Context::Scope contextScope(context);
     23   v8::TryCatch tryCatch(isolate);
     24 
     25   unsigned flags = v8::RegExp::kNone;
     26   if (!caseSensitive) flags |= v8::RegExp::kIgnoreCase;
     27   if (multiline) flags |= v8::RegExp::kMultiline;
     28 
     29   v8::Local<v8::RegExp> regex;
     30   if (v8::RegExp::New(context, toV8String(isolate, pattern),
     31                       static_cast<v8::RegExp::Flags>(flags))
     32           .ToLocal(&regex))
     33     m_regex.Reset(isolate, regex);
     34   else if (tryCatch.HasCaught())
     35     m_errorMessage = toProtocolString(tryCatch.Message()->Get());
     36   else
     37     m_errorMessage = "Internal error";
     38 }
     39 
     40 int V8Regex::match(const String16& string, int startFrom,
     41                    int* matchLength) const {
     42   if (matchLength) *matchLength = 0;
     43 
     44   if (m_regex.IsEmpty() || string.isEmpty()) return -1;
     45 
     46   // v8 strings are limited to int.
     47   if (string.length() > INT_MAX) return -1;
     48 
     49   v8::Isolate* isolate = m_inspector->isolate();
     50   v8::HandleScope handleScope(isolate);
     51   v8::Local<v8::Context> context = m_inspector->regexContext();
     52   v8::MicrotasksScope microtasks(isolate,
     53                                  v8::MicrotasksScope::kDoNotRunMicrotasks);
     54   v8::TryCatch tryCatch(isolate);
     55 
     56   v8::Local<v8::RegExp> regex = m_regex.Get(isolate);
     57   v8::Local<v8::Value> exec;
     58   if (!regex->Get(context, toV8StringInternalized(isolate, "exec"))
     59            .ToLocal(&exec))
     60     return -1;
     61   v8::Local<v8::Value> argv[] = {
     62       toV8String(isolate, string.substring(startFrom))};
     63   v8::Local<v8::Value> returnValue;
     64   if (!exec.As<v8::Function>()
     65            ->Call(context, regex, arraysize(argv), argv)
     66            .ToLocal(&returnValue))
     67     return -1;
     68 
     69   // RegExp#exec returns null if there's no match, otherwise it returns an
     70   // Array of strings with the first being the whole match string and others
     71   // being subgroups. The Array also has some random properties tacked on like
     72   // "index" which is the offset of the match.
     73   //
     74   // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/exec
     75 
     76   DCHECK(!returnValue.IsEmpty());
     77   if (!returnValue->IsArray()) return -1;
     78 
     79   v8::Local<v8::Array> result = returnValue.As<v8::Array>();
     80   v8::Local<v8::Value> matchOffset;
     81   if (!result->Get(context, toV8StringInternalized(isolate, "index"))
     82            .ToLocal(&matchOffset))
     83     return -1;
     84   if (matchLength) {
     85     v8::Local<v8::Value> match;
     86     if (!result->Get(context, 0).ToLocal(&match)) return -1;
     87     *matchLength = match.As<v8::String>()->Length();
     88   }
     89 
     90   return matchOffset.As<v8::Int32>()->Value() + startFrom;
     91 }
     92 
     93 }  // namespace v8_inspector
     94