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