| // 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. |
| // |
| // Flags: --harmony-regexp-match-indices --expose-gc --stack-size=100 |
| |
| // Sanity test. |
| { |
| const re = /a+(?<Z>z)?/; |
| 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`. |
| { |
| const re = /a+(?<Z>z)?/; |
| const m = re.exec("xaaay"); |
| |
| assertEquals(m.indices, [[1, 4], undefined]); |
| assertEquals(m.indices.groups, {'Z': undefined}); |
| } |
| |
| // Two capture groups. |
| { |
| const re = /a+(?<A>zz)?(?<B>ii)?/; |
| 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. |
| { |
| const re = /a+/; |
| const m = re.exec("xaaazzii"); |
| |
| assertEquals(m.indices [[1, 4]]); |
| assertEquals(m.indices.groups, undefined); |
| } |
| |
| // No match. |
| { |
| const re = /a+/; |
| const m = re.exec("xzzii"); |
| |
| assertEquals(null, m); |
| } |
| |
| // Unnamed capture groups. |
| { |
| const re = /a+(z)?/; |
| const m = re.exec("xaaaz") |
| |
| assertEquals(m.indices, [[1, 5], [4, 5]]); |
| assertEquals(m.indices.groups, undefined) |
| } |
| |
| // Named and unnamed capture groups. |
| { |
| const re = /a+(z)?(?<Y>y)?/; |
| const m = re.exec("xaaazyy") |
| |
| assertEquals(m.indices, [[1, 6], [4, 5], [5, 6]]); |
| assertEquals(m.indices.groups, {'Y': [5, 6]}) |
| } |
| |
| |
| // Verify property overwrite. |
| { |
| const re = /a+(?<Z>z)?/; |
| 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(); |
| } |
| }); |
| |
| const re = /a+(?<Z>z)?/; |
| const m = re.exec("xaaaz"); |
| |
| assertEquals(m.indices.groups, {'Z': [4, 5]}) |
| } |
| |
| // Test atomic regexp. |
| { |
| const m = /undefined/.exec(); |
| |
| assertEquals(m.indices, [[0, 9]]); |
| } |
| |
| // Test deleting unrelated fields does not break. |
| { |
| const m = /undefined/.exec(); |
| delete m['index']; |
| gc(); |
| assertEquals(m.indices, [[0, 9]]); |
| } |
| |
| // Stack overflow. |
| { |
| const re = /a+(?<Z>z)?/; |
| 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()); |
| } |
| |
| // Match between matches. |
| { |
| const re = /a+(?<A>zz)?(?<B>ii)?/; |
| 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]}); |
| } |