Home | History | Annotate | Download | only in harmony
      1 // Copyright 2015 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 // Flags: --harmony-regexp-lookbehind
      6 
      7 // Simple fixed-length matches.
      8 assertEquals(["a"], "a".match(/^.(?<=a)/));
      9 assertNull("b".match(/^.(?<=a)/));
     10 assertEquals(["foo"], "foo1".match(/^f..(?<=.oo)/));
     11 assertEquals(["foo"], "foo2".match(/^f\w\w(?<=\woo)/));
     12 assertNull("boo".match(/^f\w\w(?<=\woo)/));
     13 assertNull("fao".match(/^f\w\w(?<=\woo)/));
     14 assertNull("foa".match(/^f\w\w(?<=\woo)/));
     15 assertEquals(["def"], "abcdef".match(/(?<=abc)\w\w\w/));
     16 assertEquals(["def"], "abcdef".match(/(?<=a.c)\w\w\w/));
     17 assertEquals(["def"], "abcdef".match(/(?<=a\wc)\w\w\w/));
     18 assertEquals(["cde"], "abcdef".match(/(?<=a[a-z])\w\w\w/));
     19 assertEquals(["def"], "abcdef".match(/(?<=a[a-z][a-z])\w\w\w/));
     20 assertEquals(["def"], "abcdef".match(/(?<=a[a-z]{2})\w\w\w/));
     21 assertEquals(["bcd"], "abcdef".match(/(?<=a{1})\w\w\w/));
     22 assertEquals(["cde"], "abcdef".match(/(?<=a{1}b{1})\w\w\w/));
     23 assertEquals(["def"], "abcdef".match(/(?<=a{1}[a-z]{2})\w\w\w/));
     24 
     25 // Variable-length matches.
     26 assertEquals(["def"], "abcdef".match(/(?<=[a|b|c]*)[^a|b|c]{3}/));
     27 assertEquals(["def"], "abcdef".match(/(?<=\w*)[^a|b|c]{3}/));
     28 
     29 // Start of line matches.
     30 assertEquals(["def"], "abcdef".match(/(?<=^abc)def/));
     31 assertEquals(["def"], "abcdef".match(/(?<=^[a-c]{3})def/));
     32 assertEquals(["def"], "xyz\nabcdef".match(/(?<=^[a-c]{3})def/m));
     33 assertEquals(["ab", "cd", "efg"], "ab\ncd\nefg".match(/(?<=^)\w+/gm));
     34 assertEquals(["ab", "cd", "efg"], "ab\ncd\nefg".match(/\w+(?<=$)/gm));
     35 assertEquals(["ab", "cd", "efg"], "ab\ncd\nefg".match(/(?<=^)\w+(?<=$)/gm));
     36 assertNull("abcdef".match(/(?<=^[^a-c]{3})def/));
     37 assertNull("foooo".match(/"^foooo(?<=^o+)$/));
     38 assertNull("foooo".match(/"^foooo(?<=^o*)$/));
     39 assertEquals(["foo"], "foo".match(/^foo(?<=^fo+)$/));
     40 assertEquals(["foooo"], "foooo".match(/^foooo(?<=^fo*)/));
     41 assertEquals(["foo", "f"], "foo".match(/^(f)oo(?<=^\1o+)$/));
     42 assertEquals(["foo", "f"], "foo".match(/^(f)oo(?<=^\1o+)$/i));
     43 assertEquals(["foo\u1234", "f"], "foo\u1234".match(/^(f)oo(?<=^\1o+).$/i));
     44 assertEquals(["def"], "abcdefdef".match(/(?<=^\w+)def/));
     45 assertEquals(["def", "def"], "abcdefdef".match(/(?<=^\w+)def/g));
     46 
     47 // Word boundary matches.
     48 assertEquals(["def"], "abc def".match(/(?<=\b)[d-f]{3}/));
     49 assertEquals(["def"], "ab cdef".match(/(?<=\B)\w{3}/));
     50 assertEquals(["def"], "ab cdef".match(/(?<=\B)(?<=c(?<=\w))\w{3}/));
     51 assertNull("abcdef".match(/(?<=\b)[d-f]{3}/));
     52 
     53 // Negative lookbehind.
     54 assertEquals(["abc"], "abcdef".match(/(?<!abc)\w\w\w/));
     55 assertEquals(["abc"], "abcdef".match(/(?<!a.c)\w\w\w/));
     56 assertEquals(["abc"], "abcdef".match(/(?<!a\wc)\w\w\w/));
     57 assertEquals(["abc"], "abcdef".match(/(?<!a[a-z])\w\w\w/));
     58 assertEquals(["abc"], "abcdef".match(/(?<!a[a-z]{2})\w\w\w/));
     59 assertNull("abcdef".match(/(?<!abc)def/));
     60 assertNull("abcdef".match(/(?<!a.c)def/));
     61 assertNull("abcdef".match(/(?<!a\wc)def/));
     62 assertNull("abcdef".match(/(?<!a[a-z][a-z])def/));
     63 assertNull("abcdef".match(/(?<!a[a-z]{2})def/));
     64 assertNull("abcdef".match(/(?<!a{1}b{1})cde/));
     65 assertNull("abcdef".match(/(?<!a{1}[a-z]{2})def/));
     66 
     67 // Capturing matches.
     68 assertEquals(["def", "c"], "abcdef".match(/(?<=(c))def/));
     69 assertEquals(["def", "bc"], "abcdef".match(/(?<=(\w{2}))def/));
     70 assertEquals(["def", "bc", "c"], "abcdef".match(/(?<=(\w(\w)))def/));
     71 assertEquals(["def", "a"], "abcdef".match(/(?<=(\w){3})def/));
     72 assertEquals(["d", "bc", undefined], "abcdef".match(/(?<=(bc)|(cd))./));
     73 assertEquals(["c", "a", undefined],
     74              "abcdef".match(/(?<=([ab]{1,2})\D|(abc))\w/));
     75 assertEquals(["ab", "a", "b"], "abcdef".match(/\D(?<=([ab]+))(\w)/));
     76 assertEquals(["c", "d"], "abcdef".match(/(?<=b|c)\w/g));
     77 assertEquals(["cd", "ef"], "abcdef".match(/(?<=[b-e])\w{2}/g));
     78 
     79 // Captures inside negative lookbehind. (They never capture.)
     80 assertEquals(["de", undefined], "abcdef".match(/(?<!(^|[ab]))\w{2}/));
     81 
     82 // Nested lookaround.
     83 assertEquals(["ef"], "abcdef".match(/(?<=ab(?=c)\wd)\w\w/));
     84 assertEquals(["ef", "bc"], "abcdef".match(/(?<=a(?=([^a]{2})d)\w{3})\w\w/));
     85 assertEquals(["ef", "bc"],
     86              "abcdef".match(/(?<=a(?=([bc]{2}(?<!a{2}))d)\w{3})\w\w/));
     87 assertNull("abcdef".match(/(?<=a(?=([bc]{2}(?<!a*))d)\w{3})\w\w/));
     88 assertEquals(["faaa"], "faaao".match(/^faaao?(?<=^f[oa]+(?=o))/));
     89 
     90 // Back references.
     91 assertEquals(["b", "b", "bb"], "abb".match(/(.)(?<=(\1\1))/));
     92 assertEquals(["B", "B", "bB"], "abB".match(/(.)(?<=(\1\1))/i));
     93 assertEquals(["aB", "aB", "a"], "aabAaBa".match(/((\w)\w)(?<=\1\2\1)/i));
     94 assertEquals(["Ba", "Ba", "a"], "aabAaBa".match(/(\w(\w))(?<=\1\2\1)/i));
     95 assertEquals(["b", "b", "B"], "abaBbAa".match(/(?=(\w))(?<=(\1))./i));
     96 assertEquals(["foo", "'", "foo"], "  'foo'  ".match(/(?<=(.))(\w+)(?=\1)/));
     97 assertEquals(["foo", "\"", "foo"], "  \"foo\"  ".match(/(?<=(.))(\w+)(?=\1)/));
     98 assertNull("  .foo\"  ".match(/(?<=(.))(\w+)(?=\1)/));
     99 assertNull("ab".match(/(.)(?<=\1\1\1)/));
    100 assertNull("abb".match(/(.)(?<=\1\1\1)/));
    101 assertEquals(["b", "b"], "abbb".match(/(.)(?<=\1\1\1)/));
    102 assertNull("ab".match(/(..)(?<=\1\1\1)/));
    103 assertNull("abb".match(/(..)(?<=\1\1\1)/));
    104 assertNull("aabb".match(/(..)(?<=\1\1\1)/));
    105 assertNull("abab".match(/(..)(?<=\1\1\1)/));
    106 assertNull("fabxbab".match(/(..)(?<=\1\1\1)/));
    107 assertNull("faxabab".match(/(..)(?<=\1\1\1)/));
    108 assertEquals(["ab", "ab"], "fababab".match(/(..)(?<=\1\1\1)/));
    109 
    110 // Back references to captures inside the lookbehind.
    111 assertEquals(["d", "C"], "abcCd".match(/(?<=\1(\w))d/i));
    112 assertEquals(["d", "x"], "abxxd".match(/(?<=\1([abx]))d/));
    113 assertEquals(["c", "ab"], "ababc".match(/(?<=\1(\w+))c/));
    114 assertEquals(["c", "b"], "ababbc".match(/(?<=\1(\w+))c/));
    115 assertNull("ababdc".match(/(?<=\1(\w+))c/));
    116 assertEquals(["c", "abab"], "ababc".match(/(?<=(\w+)\1)c/));
    117 
    118 // Alternations are tried left to right,
    119 // and we do not backtrack into a lookbehind.
    120 assertEquals(["xabcd", "cd", ""], "xabcd".match(/.*(?<=(..|...|....))(.*)/));
    121 assertEquals(["xabcd", "bcd", ""], "xabcd".match(/.*(?<=(xx|...|....))(.*)/));
    122 assertEquals(["xxabcd", "bcd", ""], "xxabcd".match(/.*(?<=(xx|...))(.*)/));
    123 assertEquals(["xxabcd", "xx", "abcd"], "xxabcd".match(/.*(?<=(xx|xxx))(.*)/));
    124 
    125 // We do not backtrack into a lookbehind.
    126 // The lookbehind captures "abc" so that \1 does not match. We do not backtrack
    127 // to capture only "bc" in the lookbehind.
    128 assertNull("abcdbc".match(/(?<=([abc]+)).\1/));
    129 
    130 // Greedy loop.
    131 assertEquals(["c", "bbbbbb"], "abbbbbbc".match(/(?<=(b+))c/));
    132 assertEquals(["c", "b1234"], "ab1234c".match(/(?<=(b\d+))c/));
    133 assertEquals(["c", "b12b23b34"], "ab12b23b34c".match(/(?<=((?:b\d{2})+))c/));
    134 
    135 // Sticky
    136 var re1 = /(?<=^(\w+))def/g;
    137 assertEquals(["def", "abc"], re1.exec("abcdefdef"));
    138 assertEquals(["def", "abcdef"], re1.exec("abcdefdef"));
    139 var re2 = /\Bdef/g;
    140 assertEquals(["def"], re2.exec("abcdefdef"));
    141 assertEquals(["def"], re2.exec("abcdefdef"));
    142 
    143 // Misc
    144 assertNull("abcdef".match(/(?<=$abc)def/));
    145 assertEquals(["foo"], "foo".match(/^foo(?<=foo)$/));
    146 assertEquals(["foo"], "foo".match(/^f.o(?<=foo)$/));
    147 assertNull("fno".match(/^f.o(?<=foo)$/));
    148 assertNull("foo".match(/^foo(?<!foo)$/));
    149 assertNull("foo".match(/^f.o(?<!foo)$/));
    150 assertEquals(["fno"], "fno".match(/^f.o(?<!foo)$/));
    151 assertEquals(["foooo"], "foooo".match(/^foooo(?<=fo+)$/));
    152 assertEquals(["foooo"], "foooo".match(/^foooo(?<=fo*)$/));
    153 assertEquals(["abc", "abc"], /(abc\1)/.exec("abc"));
    154 assertEquals(["abc", "abc"], /(abc\1)/.exec("abc\u1234"));
    155 assertEquals(["abc", "abc"], /(abc\1)/i.exec("abc"));
    156 assertEquals(["abc", "abc"], /(abc\1)/i.exec("abc\u1234"));
    157 var oob_subject = "abcdefghijklmnabcdefghijklmn".substr(14);
    158 assertNull(oob_subject.match(/(?=(abcdefghijklmn))(?<=\1)a/i));
    159 assertNull(oob_subject.match(/(?=(abcdefghijklmn))(?<=\1)a/));
    160 
    161 // Mutual recursive capture/back references
    162 assertEquals(["cacb", "a", ""], /(?<=a(.\2)b(\1)).{4}/.exec("aabcacbc"));
    163 assertEquals(["b", "ac", "ac"], /(?<=a(\2)b(..\1))b/.exec("aacbacb"));
    164 assertEquals(["x", "aa"], /(?<=(?:\1b)(aa))./.exec("aabaax"));
    165 assertEquals(["x", "aa"], /(?<=(?:\1|b)(aa))./.exec("aaaax"));
    166