regexp-match-indices.js 4.07 KB
Newer Older
1 2 3 4
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
5 6 7
// Flags: --harmony-regexp-match-indices --allow-natives-syntax
// Flags: --expose-gc --stack-size=100
// Flags: --no-force-slow-path
8 9 10

// Sanity test.
{
11
  const re = /a+(?<Z>z)?/d;
12 13 14 15 16 17 18 19
  const m = re.exec("xaaaz");

  assertEquals(m.indices, [[1, 5], [4, 5]]);
  assertEquals(m.indices.groups, {'Z': [4, 5]})
}

// Capture groups that are not matched return `undefined`.
{
20
  const re = /a+(?<Z>z)?/d;
21 22 23 24 25 26 27 28
  const m = re.exec("xaaay");

  assertEquals(m.indices, [[1, 4], undefined]);
  assertEquals(m.indices.groups, {'Z': undefined});
}

// Two capture groups.
{
29
  const re = /a+(?<A>zz)?(?<B>ii)?/d;
30 31 32 33 34 35 36 37
  const m = re.exec("xaaazzii");

  assertEquals(m.indices, [[1, 8], [4, 6], [6, 8]]);
  assertEquals(m.indices.groups, {'A': [4, 6], 'B': [6, 8]});
}

// No capture groups.
{
38
  const re = /a+/d;
39 40
  const m = re.exec("xaaazzii");

41
  assertEquals(m.indices, [[1, 4]]);
42 43 44 45 46
  assertEquals(m.indices.groups, undefined);
}

// No match.
{
47
  const re = /a+/d;
48 49 50 51 52 53 54
  const m = re.exec("xzzii");

  assertEquals(null, m);
}

// Unnamed capture groups.
{
55 56
  const re = /a+(z)?/d;
  const m = re.exec("xaaaz");
57 58 59 60 61 62 63

  assertEquals(m.indices, [[1, 5], [4, 5]]);
  assertEquals(m.indices.groups, undefined)
}

// Named and unnamed capture groups.
{
64
  const re = /a+(z)?(?<Y>y)?/d;
65 66 67 68 69 70 71 72 73
  const m = re.exec("xaaazyy")

  assertEquals(m.indices, [[1, 6], [4, 5], [5, 6]]);
  assertEquals(m.indices.groups, {'Y': [5, 6]})
}


// Verify property overwrite.
{
74
  const re = /a+(?<Z>z)?/d;
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
  const m = re.exec("xaaaz");

  m.indices = null;
  assertEquals(null, m.indices);
}

// Mess with array prototype, we should still do the right thing.
{
  Object.defineProperty(Array.prototype, "groups", {
    get: () => {
      assertUnreachable();
      return null;
    },
    set: (x) => {
      assertUnreachable();
    }
  });

  Object.defineProperty(Array.prototype, "0", {
    get: () => {
      assertUnreachable();
      return null;
    },
    set: (x) => {
      assertUnreachable();
    }
  });

103
  const re = /a+(?<Z>z)?/d;
104 105 106 107
  const m = re.exec("xaaaz");

  assertEquals(m.indices.groups, {'Z': [4, 5]})
}
108

109 110
// Test atomic regexp.
{
111
  const m = (/undefined/d).exec();
112 113 114 115

  assertEquals(m.indices, [[0, 9]]);
}

116 117
// Test deleting unrelated fields does not break.
{
118
  const m = (/undefined/d).exec();
119 120 121 122
  delete m['index'];
  gc();
  assertEquals(m.indices, [[0, 9]]);
}
123 124 125

// Stack overflow.
{
126
  const re = /a+(?<Z>z)?/d;
127 128 129 130 131 132 133 134 135 136 137 138 139
  const m = re.exec("xaaaz");

  function rec() {
    try {
      return rec();
    } catch (e) {
      assertEquals(m.indices, [[1, 5], [4, 5]]);
      assertEquals(m.indices.groups, {'Z': [4, 5]})
      return true;
    }
  }
  assertTrue(rec());
}
140 141 142

// Match between matches.
{
143
  const re = /a+(?<A>zz)?(?<B>ii)?/d;
144 145 146 147 148
  const m = re.exec("xaaazzii");
  assertTrue(/b+(?<C>cccc)?/.test("llllllbbbbbbcccc"));
  assertEquals(m.indices, [[1, 8], [4, 6], [6, 8]]);
  assertEquals(m.indices.groups, {'A': [4, 6], 'B': [6, 8]});
}
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166

// Redefined hasIndices should reflect in flags.
{
  let re = /./;
  Object.defineProperty(re, "hasIndices", { get: function() { return true; } });
  assertEquals("d", re.flags);
}

{
  // The flags field of a regexp should be sorted.
  assertEquals("dgmsy", (/asdf/dymsg).flags);

  // The 'hasIndices' member should be set according to the hasIndices flag.
  assertTrue((/asdf/dymsg).hasIndices);
  assertFalse((/asdf/ymsg).hasIndices);

  // The new fields installed on the regexp prototype map shouldn't make
  // unmodified regexps slow.
167 168 169 170 171 172 173 174 175 176 177

  // TODO(v8:11248) Enabling v8_dict_property_const_tracking currently evokes
  // that the original fast mode prototype for regexes is converted to a
  // dictionary mode one, which makes %RegexpIsUnmodified fail. Once we support
  // directly creating the regex prototype in dictionary mode if
  // v8_dict_property_const_tracking is enabled, change %RegexpIsUnmodified to
  // know about the canonical dictionary mode prototype, too.
  if (!%IsDictPropertyConstTrackingEnabled()) {
    %RegexpIsUnmodified(/asdf/);
    %RegexpIsUnmodified(/asdf/d);
  }
178
}