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 testEscape(str, regex) { 29 assertEquals("foo:bar:baz", str.split(regex).join(":")); 30} 31 32testEscape("foo\nbar\nbaz", /\n/); 33testEscape("foo bar baz", /\s/); 34testEscape("foo\tbar\tbaz", /\s/); 35testEscape("foo-bar-baz", /\u002D/); 36 37// Test containing null char in regexp. 38var s = '[' + String.fromCharCode(0) + ']'; 39var re = new RegExp(s); 40assertEquals(s.match(re).length, 1); 41assertEquals(s.match(re)[0], String.fromCharCode(0)); 42 43// Test strings containing all line separators 44s = 'aA\nbB\rcC\r\ndD\u2028eE\u2029fF'; 45re = /^./gm; // any non-newline character at the beginning of a line 46var result = s.match(re); 47assertEquals(result.length, 6); 48assertEquals(result[0], 'a'); 49assertEquals(result[1], 'b'); 50assertEquals(result[2], 'c'); 51assertEquals(result[3], 'd'); 52assertEquals(result[4], 'e'); 53assertEquals(result[5], 'f'); 54 55re = /.$/gm; // any non-newline character at the end of a line 56result = s.match(re); 57assertEquals(result.length, 6); 58assertEquals(result[0], 'A'); 59assertEquals(result[1], 'B'); 60assertEquals(result[2], 'C'); 61assertEquals(result[3], 'D'); 62assertEquals(result[4], 'E'); 63assertEquals(result[5], 'F'); 64 65re = /^[^]/gm; // *any* character at the beginning of a line 66result = s.match(re); 67assertEquals(result.length, 7); 68assertEquals(result[0], 'a'); 69assertEquals(result[1], 'b'); 70assertEquals(result[2], 'c'); 71assertEquals(result[3], '\n'); 72assertEquals(result[4], 'd'); 73assertEquals(result[5], 'e'); 74assertEquals(result[6], 'f'); 75 76re = /[^]$/gm; // *any* character at the end of a line 77result = s.match(re); 78assertEquals(result.length, 7); 79assertEquals(result[0], 'A'); 80assertEquals(result[1], 'B'); 81assertEquals(result[2], 'C'); 82assertEquals(result[3], '\r'); 83assertEquals(result[4], 'D'); 84assertEquals(result[5], 'E'); 85assertEquals(result[6], 'F'); 86 87// Some tests from the Mozilla tests, where our behavior used to differ from 88// SpiderMonkey. 89// From ecma_3/RegExp/regress-334158.js 90assertTrue(/\ca/.test( "\x01" )); 91assertFalse(/\ca/.test( "\\ca" )); 92assertFalse(/\ca/.test( "ca" )); 93assertTrue(/\c[a/]/.test( "\\ca" )); 94assertTrue(/\c[a/]/.test( "\\c/" )); 95 96// Test \c in character class 97re = /^[\cM]$/; 98assertTrue(re.test("\r")); 99assertFalse(re.test("M")); 100assertFalse(re.test("c")); 101assertFalse(re.test("\\")); 102assertFalse(re.test("\x03")); // I.e., read as \cc 103 104re = /^[\c]]$/; 105assertTrue(re.test("c]")); 106assertTrue(re.test("\\]")); 107assertFalse(re.test("\x1d")); // ']' & 0x1f 108assertFalse(re.test("\x03]")); // I.e., read as \cc 109 110re = /^[\c1]$/; // Digit control characters are masked in character classes. 111assertTrue(re.test("\x11")); 112assertFalse(re.test("\\")); 113assertFalse(re.test("c")); 114assertFalse(re.test("1")); 115 116re = /^[\c_]$/; // Underscore control character is masked in character classes. 117assertTrue(re.test("\x1f")); 118assertFalse(re.test("\\")); 119assertFalse(re.test("c")); 120assertFalse(re.test("_")); 121 122re = /^[\c$]$/; // Other characters are interpreted literally. 123assertFalse(re.test("\x04")); 124assertTrue(re.test("\\")); 125assertTrue(re.test("c")); 126assertTrue(re.test("$")); 127 128assertTrue(/^[Z-\c-e]*$/.test("Z[\\cde")); 129 130// Test that we handle \s and \S correctly on special Unicode characters. 131re = /\s/; 132assertTrue(re.test("\u2028")); 133assertTrue(re.test("\u2029")); 134assertTrue(re.test("\uFEFF")); 135 136re = /\S/; 137assertFalse(re.test("\u2028")); 138assertFalse(re.test("\u2029")); 139assertFalse(re.test("\uFEFF")); 140 141// Test that we handle \s and \S correctly inside some bizarre 142// character classes. 143re = /[\s-:]/; 144assertTrue(re.test('-')); 145assertTrue(re.test(':')); 146assertTrue(re.test(' ')); 147assertTrue(re.test('\t')); 148assertTrue(re.test('\n')); 149assertFalse(re.test('a')); 150assertFalse(re.test('Z')); 151 152re = /[\S-:]/; 153assertTrue(re.test('-')); 154assertTrue(re.test(':')); 155assertFalse(re.test(' ')); 156assertFalse(re.test('\t')); 157assertFalse(re.test('\n')); 158assertTrue(re.test('a')); 159assertTrue(re.test('Z')); 160 161re = /[^\s-:]/; 162assertFalse(re.test('-')); 163assertFalse(re.test(':')); 164assertFalse(re.test(' ')); 165assertFalse(re.test('\t')); 166assertFalse(re.test('\n')); 167assertTrue(re.test('a')); 168assertTrue(re.test('Z')); 169 170re = /[^\S-:]/; 171assertFalse(re.test('-')); 172assertFalse(re.test(':')); 173assertTrue(re.test(' ')); 174assertTrue(re.test('\t')); 175assertTrue(re.test('\n')); 176assertFalse(re.test('a')); 177assertFalse(re.test('Z')); 178 179re = /[\s]/; 180assertFalse(re.test('-')); 181assertFalse(re.test(':')); 182assertTrue(re.test(' ')); 183assertTrue(re.test('\t')); 184assertTrue(re.test('\n')); 185assertFalse(re.test('a')); 186assertFalse(re.test('Z')); 187 188re = /[^\s]/; 189assertTrue(re.test('-')); 190assertTrue(re.test(':')); 191assertFalse(re.test(' ')); 192assertFalse(re.test('\t')); 193assertFalse(re.test('\n')); 194assertTrue(re.test('a')); 195assertTrue(re.test('Z')); 196 197re = /[\S]/; 198assertTrue(re.test('-')); 199assertTrue(re.test(':')); 200assertFalse(re.test(' ')); 201assertFalse(re.test('\t')); 202assertFalse(re.test('\n')); 203assertTrue(re.test('a')); 204assertTrue(re.test('Z')); 205 206re = /[^\S]/; 207assertFalse(re.test('-')); 208assertFalse(re.test(':')); 209assertTrue(re.test(' ')); 210assertTrue(re.test('\t')); 211assertTrue(re.test('\n')); 212assertFalse(re.test('a')); 213assertFalse(re.test('Z')); 214 215re = /[\s\S]/; 216assertTrue(re.test('-')); 217assertTrue(re.test(':')); 218assertTrue(re.test(' ')); 219assertTrue(re.test('\t')); 220assertTrue(re.test('\n')); 221assertTrue(re.test('a')); 222assertTrue(re.test('Z')); 223 224re = /[^\s\S]/; 225assertFalse(re.test('-')); 226assertFalse(re.test(':')); 227assertFalse(re.test(' ')); 228assertFalse(re.test('\t')); 229assertFalse(re.test('\n')); 230assertFalse(re.test('a')); 231assertFalse(re.test('Z')); 232 233// First - is treated as range operator, second as literal minus. 234// This follows the specification in parsing, but doesn't throw on 235// the \s at the beginning of the range. 236re = /[\s-0-9]/; 237assertTrue(re.test(' ')); 238assertTrue(re.test('\xA0')); 239assertTrue(re.test('-')); 240assertTrue(re.test('0')); 241assertTrue(re.test('9')); 242assertFalse(re.test('1')); 243 244// Test beginning and end of line assertions with or without the 245// multiline flag. 246re = /^\d+/; 247assertFalse(re.test("asdf\n123")); 248re = /^\d+/m; 249assertTrue(re.test("asdf\n123")); 250 251re = /\d+$/; 252assertFalse(re.test("123\nasdf")); 253re = /\d+$/m; 254assertTrue(re.test("123\nasdf")); 255 256// Test that empty matches are handled correctly for multiline global 257// regexps. 258re = /^(.*)/mg; 259assertEquals(3, "a\n\rb".match(re).length); 260assertEquals("*a\n*b\r*c\n*\r*d\r*\n*e", "a\nb\rc\n\rd\r\ne".replace(re, "*$1")); 261 262// Test that empty matches advance one character 263re = new RegExp("", "g"); 264assertEquals("xAx", "A".replace(re, "x")); 265assertEquals(3, String.fromCharCode(161).replace(re, "x").length); 266 267// Test that we match the KJS behavior with regard to undefined constructor 268// arguments: 269re = new RegExp(); 270// KJS actually shows this as '//'. Here we match the Firefox behavior (ie, 271// giving a syntactically legal regexp literal). 272assertEquals('/(?:)/', re.toString()); 273re = new RegExp(void 0); 274assertEquals('/(?:)/', re.toString()); 275re.compile(); 276assertEquals('/(?:)/', re.toString()); 277re.compile(void 0); 278assertEquals('/(?:)/', re.toString()); 279 280 281// Check for lazy RegExp literal creation 282function lazyLiteral(doit) { 283 if (doit) return "".replace(/foo(/gi, ""); 284 return true; 285} 286 287assertTrue(lazyLiteral(false)); 288assertThrows("lazyLiteral(true)"); 289 290// Check $01 and $10 291re = new RegExp("(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)"); 292assertEquals("t", "123456789t".replace(re, "$10"), "$10"); 293assertEquals("15", "123456789t".replace(re, "$15"), "$10"); 294assertEquals("1", "123456789t".replace(re, "$01"), "$01"); 295assertEquals("$001", "123456789t".replace(re, "$001"), "$001"); 296re = new RegExp("foo(.)"); 297assertEquals("bar$0", "foox".replace(re, "bar$0"), "$0"); 298assertEquals("bar$00", "foox".replace(re, "bar$00"), "$00"); 299assertEquals("bar$000", "foox".replace(re, "bar$000"), "$000"); 300assertEquals("barx", "foox".replace(re, "bar$01"), "$01 2"); 301assertEquals("barx5", "foox".replace(re, "bar$15"), "$15"); 302 303assertFalse(/()foo$\1/.test("football"), "football1"); 304assertFalse(/foo$(?=ball)/.test("football"), "football2"); 305assertFalse(/foo$(?!bar)/.test("football"), "football3"); 306assertTrue(/()foo$\1/.test("foo"), "football4"); 307assertTrue(/foo$(?=(ball)?)/.test("foo"), "football5"); 308assertTrue(/()foo$(?!bar)/.test("foo"), "football6"); 309assertFalse(/(x?)foo$\1/.test("football"), "football7"); 310assertFalse(/foo$(?=ball)/.test("football"), "football8"); 311assertFalse(/foo$(?!bar)/.test("football"), "football9"); 312assertTrue(/(x?)foo$\1/.test("foo"), "football10"); 313assertTrue(/foo$(?=(ball)?)/.test("foo"), "football11"); 314assertTrue(/foo$(?!bar)/.test("foo"), "football12"); 315 316// Check that the back reference has two successors. See 317// BackReferenceNode::PropagateForward. 318assertFalse(/f(o)\b\1/.test('foo')); 319assertTrue(/f(o)\B\1/.test('foo')); 320 321// Back-reference, ignore case: 322// ASCII 323assertEquals("xaAx,a", String(/x(a)\1x/i.exec("xaAx")), "backref-ASCII"); 324assertFalse(/x(...)\1/i.test("xaaaaa"), "backref-ASCII-short"); 325assertTrue(/x((?:))\1\1x/i.test("xx"), "backref-ASCII-empty"); 326assertTrue(/x(?:...|(...))\1x/i.test("xabcx"), "backref-ASCII-uncaptured"); 327assertTrue(/x(?:...|(...))\1x/i.test("xabcABCx"), "backref-ASCII-backtrack"); 328assertEquals("xaBcAbCABCx,aBc", 329 String(/x(...)\1\1x/i.exec("xaBcAbCABCx")), 330 "backref-ASCII-twice"); 331 332for (var i = 0; i < 128; i++) { 333 var testName = "backref-ASCII-char-" + i + "," + (i^0x20); 334 var test = /^(.)\1$/i.test(String.fromCharCode(i, i ^ 0x20)) 335 var c = String.fromCharCode(i); 336 if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')) { 337 assertTrue(test, testName); 338 } else { 339 assertFalse(test, testName); 340 } 341} 342 343assertFalse(/f(o)$\1/.test('foo'), "backref detects at_end"); 344 345// Check decimal escapes doesn't overflow. 346// (Note: \214 is interpreted as octal). 347assertArrayEquals(["\x8c7483648"], 348 /\2147483648/.exec("\x8c7483648"), 349 "Overflow decimal escape"); 350 351 352// Check numbers in quantifiers doesn't overflow and doesn't throw on 353// too large numbers. 354assertFalse(/a{111111111111111111111111111111111111111111111}/.test('b'), 355 "overlarge1"); 356assertFalse(/a{999999999999999999999999999999999999999999999}/.test('b'), 357 "overlarge2"); 358assertFalse(/a{1,111111111111111111111111111111111111111111111}/.test('b'), 359 "overlarge3"); 360assertFalse(/a{1,999999999999999999999999999999999999999999999}/.test('b'), 361 "overlarge4"); 362assertFalse(/a{2147483648}/.test('b'), 363 "overlarge5"); 364assertFalse(/a{21474836471}/.test('b'), 365 "overlarge6"); 366assertFalse(/a{1,2147483648}/.test('b'), 367 "overlarge7"); 368assertFalse(/a{1,21474836471}/.test('b'), 369 "overlarge8"); 370assertFalse(/a{2147483648,2147483648}/.test('b'), 371 "overlarge9"); 372assertFalse(/a{21474836471,21474836471}/.test('b'), 373 "overlarge10"); 374assertFalse(/a{2147483647}/.test('b'), 375 "overlarge11"); 376assertFalse(/a{1,2147483647}/.test('b'), 377 "overlarge12"); 378assertTrue(/a{1,2147483647}/.test('a'), 379 "overlarge13"); 380assertFalse(/a{2147483647,2147483647}/.test('a'), 381 "overlarge14"); 382 383 384// Check that we don't read past the end of the string. 385assertFalse(/f/.test('b')); 386assertFalse(/[abc]f/.test('x')); 387assertFalse(/[abc]f/.test('xa')); 388assertFalse(/[abc]</.test('x')); 389assertFalse(/[abc]</.test('xa')); 390assertFalse(/f/i.test('b')); 391assertFalse(/[abc]f/i.test('x')); 392assertFalse(/[abc]f/i.test('xa')); 393assertFalse(/[abc]</i.test('x')); 394assertFalse(/[abc]</i.test('xa')); 395assertFalse(/f[abc]/.test('x')); 396assertFalse(/f[abc]/.test('xa')); 397assertFalse(/<[abc]/.test('x')); 398assertFalse(/<[abc]/.test('xa')); 399assertFalse(/f[abc]/i.test('x')); 400assertFalse(/f[abc]/i.test('xa')); 401assertFalse(/<[abc]/i.test('x')); 402assertFalse(/<[abc]/i.test('xa')); 403 404// Test that merging of quick test masks gets it right. 405assertFalse(/x([0-7]%%x|[0-6]%%y)/.test('x7%%y'), 'qt'); 406assertFalse(/()x\1(y([0-7]%%%x|[0-6]%%%y)|dkjasldkas)/.test('xy7%%%y'), 'qt2'); 407assertFalse(/()x\1(y([0-7]%%%x|[0-6]%%%y)|dkjasldkas)/.test('xy%%%y'), 'qt3'); 408assertFalse(/()x\1y([0-7]%%%x|[0-6]%%%y)/.test('xy7%%%y'), 'qt4'); 409assertFalse(/()x\1(y([0-7]%%%x|[0-6]%%%y)|dkjasldkas)/.test('xy%%%y'), 'qt5'); 410assertFalse(/()x\1y([0-7]%%%x|[0-6]%%%y)/.test('xy7%%%y'), 'qt6'); 411assertFalse(/xy([0-7]%%%x|[0-6]%%%y)/.test('xy7%%%y'), 'qt7'); 412assertFalse(/x([0-7]%%%x|[0-6]%%%y)/.test('x7%%%y'), 'qt8'); 413 414 415// Don't hang on this one. 416/[^\xfe-\xff]*/.test(""); 417 418 419var long = "a"; 420for (var i = 0; i < 100000; i++) { 421 long = "a?" + long; 422} 423// Don't crash on this one, but maybe throw an exception. 424try { 425 RegExp(long).exec("a"); 426} catch (e) { 427 assertTrue(String(e).indexOf("Stack overflow") >= 0, "overflow"); 428} 429 430 431// Test that compile works on modified objects 432var re = /re+/; 433assertEquals("re+", re.source); 434assertFalse(re.global); 435assertFalse(re.ignoreCase); 436assertFalse(re.multiline); 437assertEquals(0, re.lastIndex); 438 439re.compile("ro+", "gim"); 440assertEquals("ro+", re.source); 441assertTrue(re.global); 442assertTrue(re.ignoreCase); 443assertTrue(re.multiline); 444assertEquals(0, re.lastIndex); 445 446re.lastIndex = 42; 447re.someOtherProperty = 42; 448re.someDeletableProperty = 42; 449re[37] = 37; 450re[42] = 42; 451 452re.compile("ra+", "i"); 453assertEquals("ra+", re.source); 454assertFalse(re.global); 455assertTrue(re.ignoreCase); 456assertFalse(re.multiline); 457assertEquals(0, re.lastIndex); 458 459assertEquals(42, re.someOtherProperty); 460assertEquals(42, re.someDeletableProperty); 461assertEquals(37, re[37]); 462assertEquals(42, re[42]); 463 464re.lastIndex = -1; 465re.someOtherProperty = 37; 466re[42] = 37; 467assertTrue(delete re[37]); 468assertTrue(delete re.someDeletableProperty); 469re.compile("ri+", "gm"); 470 471assertEquals("ri+", re.source); 472assertTrue(re.global); 473assertFalse(re.ignoreCase); 474assertTrue(re.multiline); 475assertEquals(0, re.lastIndex); 476assertEquals(37, re.someOtherProperty); 477assertEquals(37, re[42]); 478 479// Test boundary-checks. 480function assertRegExpTest(re, input, test) { 481 assertEquals(test, re.test(input), "test:" + re + ":" + input); 482} 483 484assertRegExpTest(/b\b/, "b", true); 485assertRegExpTest(/b\b$/, "b", true); 486assertRegExpTest(/\bb/, "b", true); 487assertRegExpTest(/^\bb/, "b", true); 488assertRegExpTest(/,\b/, ",", false); 489assertRegExpTest(/,\b$/, ",", false); 490assertRegExpTest(/\b,/, ",", false); 491assertRegExpTest(/^\b,/, ",", false); 492 493assertRegExpTest(/b\B/, "b", false); 494assertRegExpTest(/b\B$/, "b", false); 495assertRegExpTest(/\Bb/, "b", false); 496assertRegExpTest(/^\Bb/, "b", false); 497assertRegExpTest(/,\B/, ",", true); 498assertRegExpTest(/,\B$/, ",", true); 499assertRegExpTest(/\B,/, ",", true); 500assertRegExpTest(/^\B,/, ",", true); 501 502assertRegExpTest(/b\b/, "b,", true); 503assertRegExpTest(/b\b/, "ba", false); 504assertRegExpTest(/b\B/, "b,", false); 505assertRegExpTest(/b\B/, "ba", true); 506 507assertRegExpTest(/b\Bb/, "bb", true); 508assertRegExpTest(/b\bb/, "bb", false); 509 510assertRegExpTest(/b\b[,b]/, "bb", false); 511assertRegExpTest(/b\B[,b]/, "bb", true); 512assertRegExpTest(/b\b[,b]/, "b,", true); 513assertRegExpTest(/b\B[,b]/, "b,", false); 514 515assertRegExpTest(/[,b]\bb/, "bb", false); 516assertRegExpTest(/[,b]\Bb/, "bb", true); 517assertRegExpTest(/[,b]\bb/, ",b", true); 518assertRegExpTest(/[,b]\Bb/, ",b", false); 519 520assertRegExpTest(/[,b]\b[,b]/, "bb", false); 521assertRegExpTest(/[,b]\B[,b]/, "bb", true); 522assertRegExpTest(/[,b]\b[,b]/, ",b", true); 523assertRegExpTest(/[,b]\B[,b]/, ",b", false); 524assertRegExpTest(/[,b]\b[,b]/, "b,", true); 525assertRegExpTest(/[,b]\B[,b]/, "b,", false); 526 527// Test that caching of result doesn't share result objects. 528// More iterations increases the chance of hitting a GC. 529for (var i = 0; i < 100; i++) { 530 var re = /x(y)z/; 531 var res = re.exec("axyzb"); 532 assertTrue(!!res); 533 assertEquals(2, res.length); 534 assertEquals("xyz", res[0]); 535 assertEquals("y", res[1]); 536 assertEquals(1, res.index); 537 assertEquals("axyzb", res.input); 538 assertEquals(undefined, res.foobar); 539 540 res.foobar = "Arglebargle"; 541 res[3] = "Glopglyf"; 542 assertEquals("Arglebargle", res.foobar); 543} 544 545// Test that we perform the spec required conversions in the correct order. 546var log; 547var string = "the string"; 548var fakeLastIndex = { 549 valueOf: function() { 550 log.push("li"); 551 return 0; 552 } 553 }; 554var fakeString = { 555 toString: function() { 556 log.push("ts"); 557 return string; 558 }, 559 length: 0 560 }; 561 562var re = /str/; 563log = []; 564re.lastIndex = fakeLastIndex; 565var result = re.exec(fakeString); 566assertEquals(["str"], result); 567assertEquals(["ts", "li"], log); 568 569// Again, to check if caching interferes. 570log = []; 571re.lastIndex = fakeLastIndex; 572result = re.exec(fakeString); 573assertEquals(["str"], result); 574assertEquals(["ts", "li"], log); 575 576// And one more time, just to be certain. 577log = []; 578re.lastIndex = fakeLastIndex; 579result = re.exec(fakeString); 580assertEquals(["str"], result); 581assertEquals(["ts", "li"], log); 582 583// Now with a global regexp, where lastIndex is actually used. 584re = /str/g; 585log = []; 586re.lastIndex = fakeLastIndex; 587var result = re.exec(fakeString); 588assertEquals(["str"], result); 589assertEquals(["ts", "li"], log); 590 591// Again, to check if caching interferes. 592log = []; 593re.lastIndex = fakeLastIndex; 594result = re.exec(fakeString); 595assertEquals(["str"], result); 596assertEquals(["ts", "li"], log); 597 598// And one more time, just to be certain. 599log = []; 600re.lastIndex = fakeLastIndex; 601result = re.exec(fakeString); 602assertEquals(["str"], result); 603assertEquals(["ts", "li"], log); 604 605 606// Check that properties of RegExp have the correct permissions. 607var re = /x/g; 608var desc = Object.getOwnPropertyDescriptor(re.__proto__, "global"); 609assertInstanceof(desc.get, Function); 610assertEquals(true, desc.configurable); 611assertEquals(false, desc.enumerable); 612 613desc = Object.getOwnPropertyDescriptor(re.__proto__, "multiline"); 614assertInstanceof(desc.get, Function); 615assertEquals(true, desc.configurable); 616assertEquals(false, desc.enumerable); 617 618desc = Object.getOwnPropertyDescriptor(re.__proto__, "ignoreCase"); 619assertInstanceof(desc.get, Function); 620assertEquals(true, desc.configurable); 621assertEquals(false, desc.enumerable); 622 623desc = Object.getOwnPropertyDescriptor(re, "global"); 624assertEquals(undefined, desc); 625 626desc = Object.getOwnPropertyDescriptor(re, "multiline"); 627assertEquals(undefined, desc); 628 629desc = Object.getOwnPropertyDescriptor(re, "ignoreCase"); 630assertEquals(undefined, desc); 631 632desc = Object.getOwnPropertyDescriptor(re, "lastIndex"); 633assertEquals(0, desc.value); 634assertEquals(false, desc.configurable); 635assertEquals(false, desc.enumerable); 636assertEquals(true, desc.writable); 637 638 639// Check that end-anchored regexps are optimized correctly. 640var re = /(?:a|bc)g$/; 641assertTrue(re.test("ag")); 642assertTrue(re.test("bcg")); 643assertTrue(re.test("abcg")); 644assertTrue(re.test("zimbag")); 645assertTrue(re.test("zimbcg")); 646 647assertFalse(re.test("g")); 648assertFalse(re.test("")); 649 650// Global regexp (non-zero start). 651var re = /(?:a|bc)g$/g; 652assertTrue(re.test("ag")); 653re.lastIndex = 1; // Near start of string. 654assertTrue(re.test("zimbag")); 655re.lastIndex = 6; // At end of string. 656assertFalse(re.test("zimbag")); 657re.lastIndex = 5; // Near end of string. 658assertFalse(re.test("zimbag")); 659re.lastIndex = 4; 660assertTrue(re.test("zimbag")); 661 662// Anchored at both ends. 663var re = /^(?:a|bc)g$/g; 664assertTrue(re.test("ag")); 665re.lastIndex = 1; 666assertFalse(re.test("ag")); 667re.lastIndex = 1; 668assertFalse(re.test("zag")); 669 670// Long max_length of RegExp. 671var re = /VeryLongRegExp!{1,1000}$/; 672assertTrue(re.test("BahoolaVeryLongRegExp!!!!!!")); 673assertFalse(re.test("VeryLongRegExp")); 674assertFalse(re.test("!")); 675 676// End anchor inside disjunction. 677var re = /(?:a$|bc$)/; 678assertTrue(re.test("a")); 679assertTrue(re.test("bc")); 680assertTrue(re.test("abc")); 681assertTrue(re.test("zimzamzumba")); 682assertTrue(re.test("zimzamzumbc")); 683assertFalse(re.test("c")); 684assertFalse(re.test("")); 685 686// Only partially anchored. 687var re = /(?:a|bc$)/; 688assertTrue(re.test("a")); 689assertTrue(re.test("bc")); 690assertEquals(["a"], re.exec("abc")); 691assertEquals(4, re.exec("zimzamzumba").index); 692assertEquals(["bc"], re.exec("zimzomzumbc")); 693assertFalse(re.test("c")); 694assertFalse(re.test("")); 695 696// Valid syntax in ES5. 697re = RegExp("(?:x)*"); 698re = RegExp("(x)*"); 699 700// Syntax extension relative to ES5, for matching JSC (and ES3). 701// Shouldn't throw. 702re = RegExp("(?=x)*"); 703re = RegExp("(?!x)*"); 704 705// Should throw. Shouldn't hit asserts in debug mode. 706assertThrows("RegExp('(*)')"); 707assertThrows("RegExp('(?:*)')"); 708assertThrows("RegExp('(?=*)')"); 709assertThrows("RegExp('(?!*)')"); 710 711// Test trimmed regular expression for RegExp.test(). 712assertTrue(/.*abc/.test("abc")); 713assertFalse(/.*\d+/.test("q")); 714 715// Test that RegExp.prototype.toString() throws TypeError for 716// incompatible receivers (ES5 section 15.10.6 and 15.10.6.4). 717assertThrows("RegExp.prototype.toString.call(null)", TypeError); 718assertThrows("RegExp.prototype.toString.call(0)", TypeError); 719assertThrows("RegExp.prototype.toString.call('')", TypeError); 720assertThrows("RegExp.prototype.toString.call(false)", TypeError); 721assertThrows("RegExp.prototype.toString.call(true)", TypeError); 722assertThrows("RegExp.prototype.toString.call([])", TypeError); 723assertThrows("RegExp.prototype.toString.call({})", TypeError); 724assertThrows("RegExp.prototype.toString.call(function(){})", TypeError); 725 726// Test mutually recursive capture and backreferences. 727assertEquals(["b", "", ""], /(\2)b(\1)/.exec("aba")); 728assertEquals(["a", "", ""], /(\2).(\1)/.exec("aba")); 729assertEquals(["aba", "a", "a"], /(.\2).(\1)/.exec("aba")); 730assertEquals(["acbc", "c", "c"], /a(.\2)b(\1)$/.exec("acbc")); 731assertEquals(["acbc", "c", "c"], /a(.\2)b(\1)/.exec("aabcacbc")); 732