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 28function 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 42oneMatch(/b/); 43oneMatch(/b/g); 44 45"abcdabcd".replace(/b/g, function() { }); 46assertEquals("abcdabcd", RegExp.input); 47assertEquals("abcda", RegExp.leftContext); 48assertEquals("b", RegExp.lastMatch); 49assertEquals("", RegExp.lastParen); 50assertEquals(undefined, RegExp.lastIndex); 51assertEquals(undefined, RegExp.index); 52assertEquals("cd", RegExp.rightContext); 53for (var i = 1; i < 10; i++) { 54 assertEquals("", RegExp['$' + i]); 55} 56 57function 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 73captureMatch(/(b)(c)/); 74captureMatch(/(b)(c)/g); 75 76"abcdabcd".replace(/(b)(c)/g, function() { }); 77assertEquals("abcdabcd", RegExp.input); 78assertEquals("abcda", RegExp.leftContext); 79assertEquals("bc", RegExp.lastMatch); 80assertEquals("c", RegExp.lastParen); 81assertEquals(undefined, RegExp.lastIndex); 82assertEquals(undefined, RegExp.index); 83assertEquals("d", RegExp.rightContext); 84assertEquals('b', RegExp.$1); 85assertEquals('c', RegExp.$2); 86for (var i = 3; i < 10; i++) { 87 assertEquals("", RegExp['$' + i]); 88} 89 90 91function 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 99function 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 119var input = "bar.foo baz......"; 120var re_str = "(ba.).*?f"; 121TestOverride(input, "bar", "$1", re_str); 122 123input = "foo bar baz"; 124var re_str = "bar"; 125TestOverride(input, "bar", "$&", re_str); 126 127 128function 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 135no_last_match(function() { "foo".replace("f", ""); }); 136no_last_match(function() { "foo".replace("f", "f"); }); 137no_last_match(function() { "foo".split("o"); }); 138 139var base = "In the music. In the music. "; 140var cons = base + base + base + base; 141no_last_match(function() { cons.replace("x", "y"); }); 142no_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";}); 149assertEquals("bar", RegExp.$1); 150 151 152// A test that initially does a zero width match, but later does a non-zero 153// width match. 154var a = "foo bar baz".replace(/^|bar/g, ""); 155assertEquals("foo baz", a); 156 157a = "foo bar baz".replace(/^|bar/g, "*"); 158assertEquals("*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. 164function NoHang(re) { 165 "This is an ASCII string that could take forever".match(re); 166} 167 168NoHang(/(((.*)*)*x)Ā/); // Continuation after loop is filtered, so is loop. 169NoHang(/(((.*)*)*Ā)foo/); // Body of loop filtered. 170NoHang(/Ā(((.*)*)*x)/); // Everything after a filtered character is filtered. 171NoHang(/(((.*)*)*x)Ā/); // Everything before a filtered character is filtered. 172NoHang(/[ćăĀ](((.*)*)*x)/); // Everything after a filtered class is filtered. 173NoHang(/(((.*)*)*x)[ćăĀ]/); // Everything before a filtered class is filtered. 174NoHang(/[^\x00-\xff](((.*)*)*x)/); // After negated class. 175NoHang(/(((.*)*)*x)[^\x00-\xff]/); // Before negated class. 176NoHang(/(?!(((.*)*)*x)Ā)foo/); // Negative lookahead is filtered. 177NoHang(/(?!(((.*)*)*x))Ā/); // Continuation branch of negative lookahead. 178NoHang(/(?=(((.*)*)*x)Ā)foo/); // Positive lookahead is filtered. 179NoHang(/(?=(((.*)*)*x))Ā/); // Continuation branch of positive lookahead. 180NoHang(/(?=Ā)(((.*)*)*x)/); // Positive lookahead also prunes continuation. 181NoHang(/(æ|ø|Ā)(((.*)*)*x)/); // All branches of alternation are filtered. 182NoHang(/(a|b|(((.*)*)*x))Ā/); // 1 out of 3 branches pruned. 183NoHang(/(a|(((.*)*)*x)ă|(((.*)*)*x)Ā)/); // 2 out of 3 branches pruned. 184 185var s = "Don't prune based on a repetition of length 0"; 186assertEquals(null, s.match(/å{1,1}prune/)); 187assertEquals("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. 191var regex6 = /a*\u0100*\w/; 192var input0 = "a"; 193regex6.exec(input0); 194 195var re = "\u0100*\\w"; 196 197for (var i = 0; i < 200; i++) re = "a*" + re; 198 199var regex7 = new RegExp(re); 200regex7.exec(input0); 201 202var regex8 = new RegExp(re, "i"); 203regex8.exec(input0); 204 205re = "[\u0100]*\\w"; 206for (var i = 0; i < 200; i++) re = "a*" + re; 207 208var regex9 = new RegExp(re); 209regex9.exec(input0); 210 211var regex10 = new RegExp(re, "i"); 212regex10.exec(input0); 213 214var regex11 = /^(?:[^\u0000-\u0080]|[0-9a-z?,.!&\s#()])+$/i; 215regex11.exec(input0); 216 217var regex12 = /u(\xf0{8}?\D*?|( ? !)$h??(|)*?(||)+?\6((?:\W\B|--\d-*-|)?$){0, }?|^Y( ? !1)\d+)+a/; 218regex12.exec(""); 219