1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 function oneMatch(re) { 29 "abcd".replace(re, function() { }); 30 assertEquals("abcd", RegExp.input); 31 assertEquals("a", RegExp.leftContext); 32 assertEquals("b", RegExp.lastMatch); 33 assertEquals("", RegExp.lastParen); 34 assertEquals(undefined, RegExp.lastIndex); 35 assertEquals(undefined, RegExp.index); 36 assertEquals("cd", RegExp.rightContext); 37 for (var i = 1; i < 10; i++) { 38 assertEquals("", RegExp['$' + i]); 39 } 40 } 41 42 oneMatch(/b/); 43 oneMatch(/b/g); 44 45 "abcdabcd".replace(/b/g, function() { }); 46 assertEquals("abcdabcd", RegExp.input); 47 assertEquals("abcda", RegExp.leftContext); 48 assertEquals("b", RegExp.lastMatch); 49 assertEquals("", RegExp.lastParen); 50 assertEquals(undefined, RegExp.lastIndex); 51 assertEquals(undefined, RegExp.index); 52 assertEquals("cd", RegExp.rightContext); 53 for (var i = 1; i < 10; i++) { 54 assertEquals("", RegExp['$' + i]); 55 } 56 57 function captureMatch(re) { 58 "abcd".replace(re, function() { }); 59 assertEquals("abcd", RegExp.input); 60 assertEquals("a", RegExp.leftContext); 61 assertEquals("bc", RegExp.lastMatch); 62 assertEquals("c", RegExp.lastParen); 63 assertEquals(undefined, RegExp.lastIndex); 64 assertEquals(undefined, RegExp.index); 65 assertEquals("d", RegExp.rightContext); 66 assertEquals('b', RegExp.$1); 67 assertEquals('c', RegExp.$2); 68 for (var i = 3; i < 10; i++) { 69 assertEquals("", RegExp['$' + i]); 70 } 71 } 72 73 captureMatch(/(b)(c)/); 74 captureMatch(/(b)(c)/g); 75 76 "abcdabcd".replace(/(b)(c)/g, function() { }); 77 assertEquals("abcdabcd", RegExp.input); 78 assertEquals("abcda", RegExp.leftContext); 79 assertEquals("bc", RegExp.lastMatch); 80 assertEquals("c", RegExp.lastParen); 81 assertEquals(undefined, RegExp.lastIndex); 82 assertEquals(undefined, RegExp.index); 83 assertEquals("d", RegExp.rightContext); 84 assertEquals('b', RegExp.$1); 85 assertEquals('c', RegExp.$2); 86 for (var i = 3; i < 10; i++) { 87 assertEquals("", RegExp['$' + i]); 88 } 89 90 91 function Override() { 92 // Set the internal lastMatchInfoOverride. After calling this we do a normal 93 // match and verify the override was cleared and that we record the new 94 // captures. 95 "abcdabcd".replace(/(b)(c)/g, function() { }); 96 } 97 98 99 function TestOverride(input, expect, property, re_src) { 100 var re = new RegExp(re_src); 101 var re_g = new RegExp(re_src, "g"); 102 103 function OverrideCase(fn) { 104 Override(); 105 fn(); 106 assertEquals(expect, RegExp[property]); 107 } 108 109 OverrideCase(function() { return input.replace(re, "x"); }); 110 OverrideCase(function() { return input.replace(re_g, "x"); }); 111 OverrideCase(function() { return input.replace(re, ""); }); 112 OverrideCase(function() { return input.replace(re_g, ""); }); 113 OverrideCase(function() { return input.match(re); }); 114 OverrideCase(function() { return input.match(re_g); }); 115 OverrideCase(function() { return re.test(input); }); 116 OverrideCase(function() { return re_g.test(input); }); 117 } 118 119 var input = "bar.foo baz......"; 120 var re_str = "(ba.).*?f"; 121 TestOverride(input, "bar", "$1", re_str); 122 123 input = "foo bar baz"; 124 var re_str = "bar"; 125 TestOverride(input, "bar", "$&", re_str); 126 127 128 function no_last_match(fn) { 129 fn(); 130 assertEquals("hestfisk", RegExp.$1); 131 } 132 133 /(hestfisk)/.test("There's no such thing as a hestfisk!"); 134 135 no_last_match(function() { "foo".replace("f", ""); }); 136 no_last_match(function() { "foo".replace("f", "f"); }); 137 no_last_match(function() { "foo".split("o"); }); 138 139 var base = "In the music. In the music. "; 140 var cons = base + base + base + base; 141 no_last_match(function() { cons.replace("x", "y"); }); 142 no_last_match(function() { cons.replace("e", "E"); }); 143 144 145 // Here's one that matches once, then tries to match again, but fails. 146 // Verify that the last match info is from the last match, not from the 147 // failure that came after. 148 "bar.foo baz......".replace(/(ba.).*?f/g, function() { return "x";}); 149 assertEquals("bar", RegExp.$1); 150 151 152 // A test that initially does a zero width match, but later does a non-zero 153 // width match. 154 var a = "foo bar baz".replace(/^|bar/g, ""); 155 assertEquals("foo baz", a); 156 157 a = "foo bar baz".replace(/^|bar/g, "*"); 158 assertEquals("*foo * baz", a); 159 160 // We test FilterASCII using regexps that will backtrack forever. Since 161 // a regexp with a non-ASCII character in it can never match an ASCII 162 // string we can test that the relevant node is removed by verifying that 163 // there is no hang. 164 function NoHang(re) { 165 "This is an ASCII string that could take forever".match(re); 166 } 167 168 NoHang(/(((.*)*)*x)/); // Continuation after loop is filtered, so is loop. 169 NoHang(/(((.*)*)*)foo/); // Body of loop filtered. 170 NoHang(/(((.*)*)*x)/); // Everything after a filtered character is filtered. 171 NoHang(/(((.*)*)*x)/); // Everything before a filtered character is filtered. 172 NoHang(/[](((.*)*)*x)/); // Everything after a filtered class is filtered. 173 NoHang(/(((.*)*)*x)[]/); // Everything before a filtered class is filtered. 174 NoHang(/[^\x00-\xff](((.*)*)*x)/); // After negated class. 175 NoHang(/(((.*)*)*x)[^\x00-\xff]/); // Before negated class. 176 NoHang(/(?!(((.*)*)*x))foo/); // Negative lookahead is filtered. 177 NoHang(/(?!(((.*)*)*x))/); // Continuation branch of negative lookahead. 178 NoHang(/(?=(((.*)*)*x))foo/); // Positive lookahead is filtered. 179 NoHang(/(?=(((.*)*)*x))/); // Continuation branch of positive lookahead. 180 NoHang(/(?=)(((.*)*)*x)/); // Positive lookahead also prunes continuation. 181 NoHang(/(||)(((.*)*)*x)/); // All branches of alternation are filtered. 182 NoHang(/(a|b|(((.*)*)*x))/); // 1 out of 3 branches pruned. 183 NoHang(/(a|(((.*)*)*x)|(((.*)*)*x))/); // 2 out of 3 branches pruned. 184 185 var s = "Don't prune based on a repetition of length 0"; 186 assertEquals(null, s.match(/{1,1}prune/)); 187 assertEquals("prune", (s.match(/{0,0}prune/)[0])); 188 189 // Some very deep regexps where FilterASCII gives up in order not to make the 190 // stack overflow. 191 var regex6 = /a*\u0100*\w/; 192 var input0 = "a"; 193 regex6.exec(input0); 194 195 var re = "\u0100*\\w"; 196 197 for (var i = 0; i < 200; i++) re = "a*" + re; 198 199 var regex7 = new RegExp(re); 200 regex7.exec(input0); 201 202 var regex8 = new RegExp(re, "i"); 203 regex8.exec(input0); 204 205 re = "[\u0100]*\\w"; 206 for (var i = 0; i < 200; i++) re = "a*" + re; 207 208 var regex9 = new RegExp(re); 209 regex9.exec(input0); 210 211 var regex10 = new RegExp(re, "i"); 212 regex10.exec(input0); 213 214 var regex11 = /^(?:[^\u0000-\u0080]|[0-9a-z?,.!&\s#()])+$/i; 215 regex11.exec(input0); 216 217 var regex12 = /u(\xf0{8}?\D*?|( ? !)$h??(|)*?(||)+?\6((?:\W\B|--\d-*-|)?$){0, }?|^Y( ? !1)\d+)+a/; 218 regex12.exec(""); 219