From 80d32d1a47b4e599d0d2a5a0c80476da140e4060 Mon Sep 17 00:00:00 2001 From: graphemecluster Date: Thu, 28 Nov 2024 21:37:02 +0800 Subject: [PATCH] Add additional test cases for RegExp modifiers (#4321) --- ...ll-does-not-affect-alternatives-outside.js | 48 ++++++++++++++ .../RegExp/regexp-modifiers/add-dotAll.js | 14 +++++ ...se-does-not-affect-alternatives-outside.js | 48 ++++++++++++++ .../RegExp/regexp-modifiers/add-ignoreCase.js | 24 +++++++ ...ne-does-not-affect-alternatives-outside.js | 48 ++++++++++++++ .../RegExp/regexp-modifiers/add-multiline.js | 12 ++++ ...ll-does-not-affect-alternatives-outside.js | 62 +++++++++++++++++++ ...se-does-not-affect-alternatives-outside.js | 62 +++++++++++++++++++ ...ne-does-not-affect-alternatives-outside.js | 62 +++++++++++++++++++ ...remove-ignoreCase-within-add-ignoreCase.js | 12 ++-- ...ll-does-not-affect-alternatives-outside.js | 48 ++++++++++++++ .../RegExp/regexp-modifiers/remove-dotAll.js | 12 ++++ ...se-does-not-affect-alternatives-outside.js | 48 ++++++++++++++ .../regexp-modifiers/remove-ignoreCase.js | 28 +++++++++ ...ne-does-not-affect-alternatives-outside.js | 48 ++++++++++++++ .../regexp-modifiers/remove-multiline.js | 8 +++ 16 files changed, 578 insertions(+), 6 deletions(-) create mode 100644 test/built-ins/RegExp/regexp-modifiers/add-dotAll-does-not-affect-alternatives-outside.js create mode 100644 test/built-ins/RegExp/regexp-modifiers/add-ignoreCase-does-not-affect-alternatives-outside.js create mode 100644 test/built-ins/RegExp/regexp-modifiers/add-multiline-does-not-affect-alternatives-outside.js create mode 100644 test/built-ins/RegExp/regexp-modifiers/nesting-dotAll-does-not-affect-alternatives-outside.js create mode 100644 test/built-ins/RegExp/regexp-modifiers/nesting-ignoreCase-does-not-affect-alternatives-outside.js create mode 100644 test/built-ins/RegExp/regexp-modifiers/nesting-multiline-does-not-affect-alternatives-outside.js create mode 100644 test/built-ins/RegExp/regexp-modifiers/remove-dotAll-does-not-affect-alternatives-outside.js create mode 100644 test/built-ins/RegExp/regexp-modifiers/remove-ignoreCase-does-not-affect-alternatives-outside.js create mode 100644 test/built-ins/RegExp/regexp-modifiers/remove-multiline-does-not-affect-alternatives-outside.js diff --git a/test/built-ins/RegExp/regexp-modifiers/add-dotAll-does-not-affect-alternatives-outside.js b/test/built-ins/RegExp/regexp-modifiers/add-dotAll-does-not-affect-alternatives-outside.js new file mode 100644 index 0000000000..68ba660c09 --- /dev/null +++ b/test/built-ins/RegExp/regexp-modifiers/add-dotAll-does-not-affect-alternatives-outside.js @@ -0,0 +1,48 @@ +// Copyright 2024 Daniel Kwan. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Daniel Kwan +description: > + Adding dotAll (`s`) modifier should not affect alternatives outside. +info: | + Runtime Semantics: CompileAtom + The syntax-directed operation CompileAtom takes arguments direction (forward or backward) and modifiers (a Modifiers Record) and returns a Matcher. + + Atom :: `(` `?` RegularExpressionFlags `:` Disjunction `)` + 1. Let addModifiers be the source text matched by RegularExpressionFlags. + 2. Let removeModifiers be the empty String. + 3. Let newModifiers be UpdateModifiers(modifiers, CodePointsToString(addModifiers), removeModifiers). + 4. Return CompileSubpattern of Disjunction with arguments direction and newModifiers. + + UpdateModifiers ( modifiers, add, remove ) + The abstract operation UpdateModifiers takes arguments modifiers (a Modifiers Record), add (a String), and remove (a String) and returns a Modifiers. It performs the following steps when called: + + 1. Let dotAll be modifiers.[[DotAll]]. + 2. Let ignoreCase be modifiers.[[IgnoreCase]]. + 3. Let multiline be modifiers.[[Multiline]]. + 4. If add contains "s", set dotAll to true. + 5. If add contains "i", set ignoreCase to true. + 6. If add contains "m", set multiline to true. + 7. If remove contains "s", set dotAll to false. + 8. If remove contains "i", set ignoreCase to false. + 9. If remove contains "m", set multiline to false. + 10. Return the Modifiers Record { [[DotAll]]: dotAll, [[IgnoreCase]]: ignoreCase, [[Multiline]]: multiline }. + +esid: sec-compileatom +features: [regexp-modifiers] +---*/ + +var re1 = /a.a|b.b|(?s:c.c)|d.d|e.e/; +assert(!re1.test("a\na"), "Alternative `a.a` should not match newline"); +assert(!re1.test("b\nb"), "Alternative `b.b` should not match newline"); +assert(re1.test("c\nc"), "Alternative `(?s:c.c)` should match newline in modified group"); +assert(!re1.test("d\nd"), "Alternative `d.d` should not match newline"); +assert(!re1.test("e\ne"), "Alternative `e.e` should not match newline"); + +var re2 = /(a.a)|(?:b.b)|(?s:c.c)|(?:d.d)|(e.e)/; +assert(!re2.test("a\na"), "Alternative `(a.a)` should not match newline"); +assert(!re2.test("b\nb"), "Alternative `(?:b.b)` should not match newline"); +assert(re2.test("c\nc"), "Alternative `(?s:c.c)` should match newline in modified group"); +assert(!re2.test("d\nd"), "Alternative `(?:d.d)` should not match newline"); +assert(!re2.test("e\ne"), "Alternative `(e.e)` should not match newline"); diff --git a/test/built-ins/RegExp/regexp-modifiers/add-dotAll.js b/test/built-ins/RegExp/regexp-modifiers/add-dotAll.js index d0ca4fb20a..fed871fb64 100644 --- a/test/built-ins/RegExp/regexp-modifiers/add-dotAll.js +++ b/test/built-ins/RegExp/regexp-modifiers/add-dotAll.js @@ -100,3 +100,17 @@ assert(re4.test("\u2028"), "Pattern character '.' should match line terminators assert(re4.test("\u2029"), "Pattern character '.' should match line terminators in modified group"); assert(re4.test("\uD800"), "Pattern character '.' should match non-line terminators in modified group"); assert(re4.test("\uDFFF"), "Pattern character '.' should match non-line terminators in modified group"); + +var re5 = /a.(?s:b.b).c/; +assert(re5.test("a,b,b,c"), "Pattern character '.' should match non-line terminators in modified group"); +assert(re5.test("a,b\nb,c"), "Pattern character '.' should match line terminators in modified group"); +assert(!re5.test("a\nb\nb,c"), "Pattern character '.' should not match line terminators outside modified group"); +assert(!re5.test("a,b\nb\nc"), "Pattern character '.' should not match line terminators outside modified group"); +assert(!re5.test("a\nb\nb\nc"), "Pattern character '.' should not match line terminators outside modified group"); + +var re6 = new RegExp("a.(?s:b.b).c"); +assert(re6.test("a,b,b,c"), "Pattern character '.' should match non-line terminators in modified group"); +assert(re6.test("a,b\nb,c"), "Pattern character '.' should match line terminators in modified group"); +assert(!re6.test("a\nb\nb,c"), "Pattern character '.' should not match line terminators outside modified group"); +assert(!re6.test("a,b\nb\nc"), "Pattern character '.' should not match line terminators outside modified group"); +assert(!re6.test("a\nb\nb\nc"), "Pattern character '.' should not match line terminators outside modified group"); diff --git a/test/built-ins/RegExp/regexp-modifiers/add-ignoreCase-does-not-affect-alternatives-outside.js b/test/built-ins/RegExp/regexp-modifiers/add-ignoreCase-does-not-affect-alternatives-outside.js new file mode 100644 index 0000000000..90dd1da1b2 --- /dev/null +++ b/test/built-ins/RegExp/regexp-modifiers/add-ignoreCase-does-not-affect-alternatives-outside.js @@ -0,0 +1,48 @@ +// Copyright 2024 Daniel Kwan. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Daniel Kwan +description: > + Adding ignoreCase (`i`) modifier should not affect alternatives outside. +info: | + Runtime Semantics: CompileAtom + The syntax-directed operation CompileAtom takes arguments direction (forward or backward) and modifiers (a Modifiers Record) and returns a Matcher. + + Atom :: `(` `?` RegularExpressionFlags `:` Disjunction `)` + 1. Let addModifiers be the source text matched by RegularExpressionFlags. + 2. Let removeModifiers be the empty String. + 3. Let newModifiers be UpdateModifiers(modifiers, CodePointsToString(addModifiers), removeModifiers). + 4. Return CompileSubpattern of Disjunction with arguments direction and newModifiers. + + UpdateModifiers ( modifiers, add, remove ) + The abstract operation UpdateModifiers takes arguments modifiers (a Modifiers Record), add (a String), and remove (a String) and returns a Modifiers. It performs the following steps when called: + + 1. Let dotAll be modifiers.[[DotAll]]. + 2. Let ignoreCase be modifiers.[[IgnoreCase]]. + 3. Let multiline be modifiers.[[Multiline]]. + 4. If add contains "s", set dotAll to true. + 5. If add contains "i", set ignoreCase to true. + 6. If add contains "m", set multiline to true. + 7. If remove contains "s", set dotAll to false. + 8. If remove contains "i", set ignoreCase to false. + 9. If remove contains "m", set multiline to false. + 10. Return the Modifiers Record { [[DotAll]]: dotAll, [[IgnoreCase]]: ignoreCase, [[Multiline]]: multiline }. + +esid: sec-compileatom +features: [regexp-modifiers] +---*/ + +var re1 = /a|b|(?i:c)|d|e/; +assert(!re1.test("A"), "Alternative `a` should not match `A`"); +assert(!re1.test("B"), "Alternative `b` should not match `B`"); +assert(re1.test("C"), "Alternative `(?i:c)` should match `C` in modified group"); +assert(!re1.test("D"), "Alternative `d` should not match `D`"); +assert(!re1.test("E"), "Alternative `e` should not match `E`"); + +var re2 = /(a)|(?:b)|(?i:c)|(?:d)|(e)/; +assert(!re2.test("A"), "Alternative `(a)` should not match `A`"); +assert(!re2.test("B"), "Alternative `(?:b)` should not match `B`"); +assert(re2.test("C"), "Alternative `(?i:c)` should match `C` in modified group"); +assert(!re2.test("D"), "Alternative `(?:d)` should not match `D`"); +assert(!re2.test("E"), "Alternative `(e)` should not match `E`"); diff --git a/test/built-ins/RegExp/regexp-modifiers/add-ignoreCase.js b/test/built-ins/RegExp/regexp-modifiers/add-ignoreCase.js index 3f71a5dde0..ccee65f9e0 100644 --- a/test/built-ins/RegExp/regexp-modifiers/add-ignoreCase.js +++ b/test/built-ins/RegExp/regexp-modifiers/add-ignoreCase.js @@ -42,3 +42,27 @@ var re2 = new RegExp("(?i:a)b"); assert(!re2.test("AB"), "b should not match B in AB"); assert(re2.test("Ab"), "a should match A in AB"); assert(re2.test("ab"), "should match AB"); + +var re3 = /b(?i:a)/; +assert(!re3.test("BA"), "b should not match B in BA"); +assert(re3.test("bA"), "a should match A in BA"); +assert(re3.test("ba"), "should match BA"); + +var re4 = new RegExp("b(?i:a)"); +assert(!re4.test("BA"), "b should not match B in BA"); +assert(re4.test("bA"), "a should match A in BA"); +assert(re4.test("ba"), "should match BA"); + +var re5 = /a(?i:b)c/; +assert(re5.test("abc"), "b should match b in abc"); +assert(re5.test("aBc"), "B should match b in abc"); +assert(!re5.test("ABc"), "A should not match a in abc"); +assert(!re5.test("aBC"), "C should not match c in abc"); +assert(!re5.test("ABC"), "should not match abc"); + +var re6 = new RegExp("a(?i:b)c"); +assert(re6.test("abc"), "b should match b in abc"); +assert(re6.test("aBc"), "B should match b in abc"); +assert(!re6.test("ABc"), "A should not match a in abc"); +assert(!re6.test("aBC"), "C should not match c in abc"); +assert(!re6.test("ABC"), "should not match abc"); diff --git a/test/built-ins/RegExp/regexp-modifiers/add-multiline-does-not-affect-alternatives-outside.js b/test/built-ins/RegExp/regexp-modifiers/add-multiline-does-not-affect-alternatives-outside.js new file mode 100644 index 0000000000..a010aaf789 --- /dev/null +++ b/test/built-ins/RegExp/regexp-modifiers/add-multiline-does-not-affect-alternatives-outside.js @@ -0,0 +1,48 @@ +// Copyright 2024 Daniel Kwan. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Daniel Kwan +description: > + Adding multiline (`m`) modifier should not affect alternatives outside. +info: | + Runtime Semantics: CompileAtom + The syntax-directed operation CompileAtom takes arguments direction (forward or backward) and modifiers (a Modifiers Record) and returns a Matcher. + + Atom :: `(` `?` RegularExpressionFlags `:` Disjunction `)` + 1. Let addModifiers be the source text matched by RegularExpressionFlags. + 2. Let removeModifiers be the empty String. + 3. Let newModifiers be UpdateModifiers(modifiers, CodePointsToString(addModifiers), removeModifiers). + 4. Return CompileSubpattern of Disjunction with arguments direction and newModifiers. + + UpdateModifiers ( modifiers, add, remove ) + The abstract operation UpdateModifiers takes arguments modifiers (a Modifiers Record), add (a String), and remove (a String) and returns a Modifiers. It performs the following steps when called: + + 1. Let dotAll be modifiers.[[DotAll]]. + 2. Let ignoreCase be modifiers.[[IgnoreCase]]. + 3. Let multiline be modifiers.[[Multiline]]. + 4. If add contains "s", set dotAll to true. + 5. If add contains "i", set ignoreCase to true. + 6. If add contains "m", set multiline to true. + 7. If remove contains "s", set dotAll to false. + 8. If remove contains "i", set ignoreCase to false. + 9. If remove contains "m", set multiline to false. + 10. Return the Modifiers Record { [[DotAll]]: dotAll, [[IgnoreCase]]: ignoreCase, [[Multiline]]: multiline }. + +esid: sec-compileatom +features: [regexp-modifiers] +---*/ + +var re1 = /^a$|^b$|(?m:^c$)|^d$|^e$/; +assert(!re1.test("\na\n"), "Alternative `^a$` should not match newline"); +assert(!re1.test("\nb\n"), "Alternative `^b$` should not match newline"); +assert(re1.test("\nc\n"), "Alternative `(?m:^c$)` should match newline in modified group"); +assert(!re1.test("\nd\n"), "Alternative `^d$` should not match newline"); +assert(!re1.test("\ne\n"), "Alternative `^e$` should not match newline"); + +var re2 = /(^a$)|(?:^b$)|(?m:^c$)|(?:^d$)|(^e$)/; +assert(!re2.test("\na\n"), "Alternative `(^a$)` should not match newline"); +assert(!re2.test("\nb\n"), "Alternative `(?:^b$)` should not match newline"); +assert(re2.test("\nc\n"), "Alternative `(?m:^c$)` should match newline in modified group"); +assert(!re2.test("\nd\n"), "Alternative `(?:^d$)` should not match newline"); +assert(!re2.test("\ne\n"), "Alternative `(^e$)` should not match newline"); diff --git a/test/built-ins/RegExp/regexp-modifiers/add-multiline.js b/test/built-ins/RegExp/regexp-modifiers/add-multiline.js index faf922138f..fabedffaca 100644 --- a/test/built-ins/RegExp/regexp-modifiers/add-multiline.js +++ b/test/built-ins/RegExp/regexp-modifiers/add-multiline.js @@ -44,3 +44,15 @@ assert(re3.test("es\ns"), "$ should match newline in modified group"); var re4 = new RegExp("(?m-:es$)"); assert(re4.test("es\ns"), "$ should match newline in modified group"); + +var re5 = /^a\n(?m:^b$)\nc$/; +assert(re5.test("a\nb\nc"), "^ and $ should match newline in modified group"); +assert(!re5.test("\na\nb\nc"), "^ should not match newline outside modified group"); +assert(!re5.test("a\nb\nc\n"), "$ should not match newline outside modified group"); +assert(!re5.test("\na\nb\nc\n"), "^ and $ should not match newline outside modified group"); + +var re6 = new RegExp("^a\\n(?m:^b$)\\nc$"); +assert(re6.test("a\nb\nc"), "^ and $ should match newline in modified group"); +assert(!re6.test("\na\nb\nc"), "^ should not match newline outside modified group"); +assert(!re6.test("a\nb\nc\n"), "$ should not match newline outside modified group"); +assert(!re6.test("\na\nb\nc\n"), "^ and $ should not match newline outside modified group"); diff --git a/test/built-ins/RegExp/regexp-modifiers/nesting-dotAll-does-not-affect-alternatives-outside.js b/test/built-ins/RegExp/regexp-modifiers/nesting-dotAll-does-not-affect-alternatives-outside.js new file mode 100644 index 0000000000..9020fc5902 --- /dev/null +++ b/test/built-ins/RegExp/regexp-modifiers/nesting-dotAll-does-not-affect-alternatives-outside.js @@ -0,0 +1,62 @@ +// Copyright 2024 Daniel Kwan. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Daniel Kwan +description: > + Nesting dotAll (`s`) modifier should not affect alternatives outside. +info: | + Runtime Semantics: CompileAtom + The syntax-directed operation CompileAtom takes arguments direction (forward or backward) and modifiers (a Modifiers Record) and returns a Matcher. + + Atom :: `(` `?` RegularExpressionFlags `:` Disjunction `)` + 1. Let addModifiers be the source text matched by RegularExpressionFlags. + 2. Let removeModifiers be the empty String. + 3. Let newModifiers be UpdateModifiers(modifiers, CodePointsToString(addModifiers), removeModifiers). + 4. Return CompileSubpattern of Disjunction with arguments direction and newModifiers. + + Atom :: `(` `?` RegularExpressionFlags `-` RegularExpressionFlags `:` Disjunction `)` + 1. Let addModifiers be the source text matched by the first RegularExpressionFlags. + 2. Let removeModifiers be the source text matched by the second RegularExpressionFlags. + 3. Let newModifiers be UpdateModifiers(modifiers, CodePointsToString(addModifiers), CodePointsToString(removeModifiers)). + 4. Return CompileSubpattern of Disjunction with arguments direction and newModifiers. + + UpdateModifiers ( modifiers, add, remove ) + The abstract operation UpdateModifiers takes arguments modifiers (a Modifiers Record), add (a String), and remove (a String) and returns a Modifiers. It performs the following steps when called: + + 1. Let dotAll be modifiers.[[DotAll]]. + 2. Let ignoreCase be modifiers.[[IgnoreCase]]. + 3. Let multiline be modifiers.[[Multiline]]. + 4. If add contains "s", set dotAll to true. + 5. If add contains "i", set ignoreCase to true. + 6. If add contains "m", set multiline to true. + 7. If remove contains "s", set dotAll to false. + 8. If remove contains "i", set ignoreCase to false. + 9. If remove contains "m", set multiline to false. + 10. Return the Modifiers Record { [[DotAll]]: dotAll, [[IgnoreCase]]: ignoreCase, [[Multiline]]: multiline }. + +esid: sec-compileatom +features: [regexp-modifiers] +---*/ + +var re1 = /a.a|(?-s:b.b|(?s:c.c)|d.d|(?-s:e.e)|f.f)|g.g|(?s:h.h)|k.k/s; +assert(re1.test("a\na"), "`a.a` should match newline"); +assert(!re1.test("b\nb"), "`b.b` should not match newline"); +assert(re1.test("c\nc"), "`c.c` should match newline"); +assert(!re1.test("d\nd"), "`d.d` should not match newline"); +assert(!re1.test("e\ne"), "`e.e` should not match newline"); +assert(!re1.test("f\nf"), "`f.f` should not match newline"); +assert(re1.test("g\ng"), "`g.g` should match newline"); +assert(re1.test("h\nh"), "`h.h` should match newline"); +assert(re1.test("k\nk"), "`k.k` should match newline"); + +var re2 = /a.a|(?s:b.b|(?-s:c.c)|d.d|(?s:e.e)|f.f)|g.g|(?-s:h.h)|k.k/; +assert(!re2.test("a\na"), "`a.a` should not match newline"); +assert(re2.test("b\nb"), "`b.b` should match newline"); +assert(!re2.test("c\nc"), "`c.c` should not match newline"); +assert(re2.test("d\nd"), "`d.d` should match newline"); +assert(re2.test("e\ne"), "`e.e` should match newline"); +assert(re2.test("f\nf"), "`f.f` should match newline"); +assert(!re2.test("g\ng"), "`g.g` should not match newline"); +assert(!re2.test("h\nh"), "`h.h` should not match newline"); +assert(!re2.test("k\nk"), "`k.k` should not match newline"); diff --git a/test/built-ins/RegExp/regexp-modifiers/nesting-ignoreCase-does-not-affect-alternatives-outside.js b/test/built-ins/RegExp/regexp-modifiers/nesting-ignoreCase-does-not-affect-alternatives-outside.js new file mode 100644 index 0000000000..981dec4757 --- /dev/null +++ b/test/built-ins/RegExp/regexp-modifiers/nesting-ignoreCase-does-not-affect-alternatives-outside.js @@ -0,0 +1,62 @@ +// Copyright 2024 Daniel Kwan. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Daniel Kwan +description: > + Nesting ignoreCase (`i`) modifier should not affect alternatives outside. +info: | + Runtime Semantics: CompileAtom + The syntax-directed operation CompileAtom takes arguments direction (forward or backward) and modifiers (a Modifiers Record) and returns a Matcher. + + Atom :: `(` `?` RegularExpressionFlags `:` Disjunction `)` + 1. Let addModifiers be the source text matched by RegularExpressionFlags. + 2. Let removeModifiers be the empty String. + 3. Let newModifiers be UpdateModifiers(modifiers, CodePointsToString(addModifiers), removeModifiers). + 4. Return CompileSubpattern of Disjunction with arguments direction and newModifiers. + + Atom :: `(` `?` RegularExpressionFlags `-` RegularExpressionFlags `:` Disjunction `)` + 1. Let addModifiers be the source text matched by the first RegularExpressionFlags. + 2. Let removeModifiers be the source text matched by the second RegularExpressionFlags. + 3. Let newModifiers be UpdateModifiers(modifiers, CodePointsToString(addModifiers), CodePointsToString(removeModifiers)). + 4. Return CompileSubpattern of Disjunction with arguments direction and newModifiers. + + UpdateModifiers ( modifiers, add, remove ) + The abstract operation UpdateModifiers takes arguments modifiers (a Modifiers Record), add (a String), and remove (a String) and returns a Modifiers. It performs the following steps when called: + + 1. Let dotAll be modifiers.[[DotAll]]. + 2. Let ignoreCase be modifiers.[[IgnoreCase]]. + 3. Let multiline be modifiers.[[Multiline]]. + 4. If add contains "s", set dotAll to true. + 5. If add contains "i", set ignoreCase to true. + 6. If add contains "m", set multiline to true. + 7. If remove contains "s", set dotAll to false. + 8. If remove contains "i", set ignoreCase to false. + 9. If remove contains "m", set multiline to false. + 10. Return the Modifiers Record { [[DotAll]]: dotAll, [[IgnoreCase]]: ignoreCase, [[Multiline]]: multiline }. + +esid: sec-compileatom +features: [regexp-modifiers] +---*/ + +var re1 = /a|(?-i:b|(?i:c)|d|(?-i:e)|f)|g|(?i:h)|k/i; +assert(re1.test("A"), "`a` should match `A`"); +assert(!re1.test("B"), "`b` should not match `B`"); +assert(re1.test("C"), "`c` should match `C`"); +assert(!re1.test("D"), "`d` should not match `D`"); +assert(!re1.test("E"), "`e` should not match `E`"); +assert(!re1.test("F"), "`f` should not match `F`"); +assert(re1.test("G"), "`g` should match `G`"); +assert(re1.test("H"), "`h` should match `H`"); +assert(re1.test("K"), "`k` should match `K`"); + +var re2 = /a|(?i:b|(?-i:c)|d|(?i:e)|f)|g|(?-i:h)|k/; +assert(!re2.test("A"), "`a` should not match `A`"); +assert(re2.test("B"), "`b` should match `B`"); +assert(!re2.test("C"), "`c` should not match `C`"); +assert(re2.test("D"), "`d` should match `D`"); +assert(re2.test("E"), "`e` should match `E`"); +assert(re2.test("F"), "`f` should match `F`"); +assert(!re2.test("G"), "`g` should not match `G`"); +assert(!re2.test("H"), "`h` should not match `H`"); +assert(!re2.test("K"), "`k` should not match `K`"); diff --git a/test/built-ins/RegExp/regexp-modifiers/nesting-multiline-does-not-affect-alternatives-outside.js b/test/built-ins/RegExp/regexp-modifiers/nesting-multiline-does-not-affect-alternatives-outside.js new file mode 100644 index 0000000000..199a91660c --- /dev/null +++ b/test/built-ins/RegExp/regexp-modifiers/nesting-multiline-does-not-affect-alternatives-outside.js @@ -0,0 +1,62 @@ +// Copyright 2024 Daniel Kwan. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Daniel Kwan +description: > + Nesting multiline (`m`) modifier should not affect alternatives outside. +info: | + Runtime Semantics: CompileAtom + The syntax-directed operation CompileAtom takes arguments direction (forward or backward) and modifiers (a Modifiers Record) and returns a Matcher. + + Atom :: `(` `?` RegularExpressionFlags `:` Disjunction `)` + 1. Let addModifiers be the source text matched by RegularExpressionFlags. + 2. Let removeModifiers be the empty String. + 3. Let newModifiers be UpdateModifiers(modifiers, CodePointsToString(addModifiers), removeModifiers). + 4. Return CompileSubpattern of Disjunction with arguments direction and newModifiers. + + Atom :: `(` `?` RegularExpressionFlags `-` RegularExpressionFlags `:` Disjunction `)` + 1. Let addModifiers be the source text matched by the first RegularExpressionFlags. + 2. Let removeModifiers be the source text matched by the second RegularExpressionFlags. + 3. Let newModifiers be UpdateModifiers(modifiers, CodePointsToString(addModifiers), CodePointsToString(removeModifiers)). + 4. Return CompileSubpattern of Disjunction with arguments direction and newModifiers. + + UpdateModifiers ( modifiers, add, remove ) + The abstract operation UpdateModifiers takes arguments modifiers (a Modifiers Record), add (a String), and remove (a String) and returns a Modifiers. It performs the following steps when called: + + 1. Let dotAll be modifiers.[[DotAll]]. + 2. Let ignoreCase be modifiers.[[IgnoreCase]]. + 3. Let multiline be modifiers.[[Multiline]]. + 4. If add contains "s", set dotAll to true. + 5. If add contains "i", set ignoreCase to true. + 6. If add contains "m", set multiline to true. + 7. If remove contains "s", set dotAll to false. + 8. If remove contains "i", set ignoreCase to false. + 9. If remove contains "m", set multiline to false. + 10. Return the Modifiers Record { [[DotAll]]: dotAll, [[IgnoreCase]]: ignoreCase, [[Multiline]]: multiline }. + +esid: sec-compileatom +features: [regexp-modifiers] +---*/ + +var re1 = /^a$|(?-m:^b$|(?m:^c$)|^d$|(?-m:^e$)|^f$)|^g$|(?m:^h$)|^k$/m; +assert(re1.test("\na\n"), "`^a$` should match newline"); +assert(!re1.test("\nb\n"), "`^b$` should not match newline"); +assert(re1.test("\nc\n"), "`^c$` should match newline"); +assert(!re1.test("\nd\n"), "`^d$` should not match newline"); +assert(!re1.test("\ne\n"), "`^e$` should not match newline"); +assert(!re1.test("\nf\n"), "`^f$` should not match newline"); +assert(re1.test("\ng\n"), "`^g$` should match newline"); +assert(re1.test("\nh\n"), "`^h$` should match newline"); +assert(re1.test("\nk\n"), "`^k$` should match newline"); + +var re2 = /^a$|(?m:^b$|(?-m:^c$)|^d$|(?m:^e$)|^f$)|^g$|(?-m:^h$)|^k$/; +assert(!re2.test("\na\n"), "`^a$` should not match newline"); +assert(re2.test("\nb\n"), "`^b$` should match newline"); +assert(!re2.test("\nc\n"), "`^c$` should not match newline"); +assert(re2.test("\nd\n"), "`^d$` should match newline"); +assert(re2.test("\ne\n"), "`^e$` should match newline"); +assert(re2.test("\nf\n"), "`^f$` should match newline"); +assert(!re2.test("\ng\n"), "`^g$` should not match newline"); +assert(!re2.test("\nh\n"), "`^h$` should not match newline"); +assert(!re2.test("\nk\n"), "`^k$` should not match newline"); diff --git a/test/built-ins/RegExp/regexp-modifiers/nesting-remove-ignoreCase-within-add-ignoreCase.js b/test/built-ins/RegExp/regexp-modifiers/nesting-remove-ignoreCase-within-add-ignoreCase.js index 9bc50da4e8..ad17b71c40 100644 --- a/test/built-ins/RegExp/regexp-modifiers/nesting-remove-ignoreCase-within-add-ignoreCase.js +++ b/test/built-ins/RegExp/regexp-modifiers/nesting-remove-ignoreCase-within-add-ignoreCase.js @@ -33,10 +33,10 @@ esid: sec-compileatom features: [regexp-modifiers] ---*/ -var re1 = /(?-i:a(?i:b))c/i; -assert(!re1.test("ABC"), "a should not match A in ABC"); -assert(!re1.test("ABc"), "a should not match A in ABc"); -assert(!re1.test("Abc"), "a should not match A in Abc"); -assert(re1.test("aBc"), "b should match B in aBc"); -assert(re1.test("abC"), "c should match C in abC"); +var re1 = /(?i:a(?-i:b))c/; +assert(!re1.test("ABC"), "b should not match B in ABC"); +assert(!re1.test("ABc"), "b should not match B in ABc"); +assert(re1.test("Abc"), "a should match A in Abc"); +assert(!re1.test("aBc"), "b should not match B in aBc"); +assert(!re1.test("abC"), "c should not match C in abC"); assert(re1.test("abc"), "should match abc"); diff --git a/test/built-ins/RegExp/regexp-modifiers/remove-dotAll-does-not-affect-alternatives-outside.js b/test/built-ins/RegExp/regexp-modifiers/remove-dotAll-does-not-affect-alternatives-outside.js new file mode 100644 index 0000000000..a5fd9bc591 --- /dev/null +++ b/test/built-ins/RegExp/regexp-modifiers/remove-dotAll-does-not-affect-alternatives-outside.js @@ -0,0 +1,48 @@ +// Copyright 2024 Daniel Kwan. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Daniel Kwan +description: > + Removing dotAll (`s`) modifier should not affect alternatives outside. +info: | + Runtime Semantics: CompileAtom + The syntax-directed operation CompileAtom takes arguments direction (forward or backward) and modifiers (a Modifiers Record) and returns a Matcher. + + Atom :: `(` `?` RegularExpressionFlags `-` RegularExpressionFlags `:` Disjunction `)` + 1. Let addModifiers be the source text matched by the first RegularExpressionFlags. + 2. Let removeModifiers be the source text matched by the second RegularExpressionFlags. + 3. Let newModifiers be UpdateModifiers(modifiers, CodePointsToString(addModifiers), CodePointsToString(removeModifiers)). + 4. Return CompileSubpattern of Disjunction with arguments direction and newModifiers. + + UpdateModifiers ( modifiers, add, remove ) + The abstract operation UpdateModifiers takes arguments modifiers (a Modifiers Record), add (a String), and remove (a String) and returns a Modifiers. It performs the following steps when called: + + 1. Let dotAll be modifiers.[[DotAll]]. + 2. Let ignoreCase be modifiers.[[IgnoreCase]]. + 3. Let multiline be modifiers.[[Multiline]]. + 4. If add contains "s", set dotAll to true. + 5. If add contains "i", set ignoreCase to true. + 6. If add contains "m", set multiline to true. + 7. If remove contains "s", set dotAll to false. + 8. If remove contains "i", set ignoreCase to false. + 9. If remove contains "m", set multiline to false. + 10. Return the Modifiers Record { [[DotAll]]: dotAll, [[IgnoreCase]]: ignoreCase, [[Multiline]]: multiline }. + +esid: sec-compileatom +features: [regexp-modifiers] +---*/ + +var re1 = /a.a|b.b|(?-s:c.c)|d.d|e.e/s; +assert(re1.test("a\na"), "Alternative `a.a` should match newline"); +assert(re1.test("b\nb"), "Alternative `b.b` should match newline"); +assert(!re1.test("c\nc"), "Alternative `(?-s:c.c)` should not match newline in modified group"); +assert(re1.test("d\nd"), "Alternative `d.d` should match newline"); +assert(re1.test("e\ne"), "Alternative `e.e` should match newline"); + +var re2 = /(a.a)|(?:b.b)|(?-s:c.c)|(?:d.d)|(e.e)/s; +assert(re2.test("a\na"), "Alternative `(a.a)` should match newline"); +assert(re2.test("b\nb"), "Alternative `(?:b.b)` should match newline"); +assert(!re2.test("c\nc"), "Alternative `(?-s:c.c)` should not match newline in modified group"); +assert(re2.test("d\nd"), "Alternative `(?:d.d)` should match newline"); +assert(re2.test("e\ne"), "Alternative `(e.e)` should match newline"); diff --git a/test/built-ins/RegExp/regexp-modifiers/remove-dotAll.js b/test/built-ins/RegExp/regexp-modifiers/remove-dotAll.js index 2534c3292a..8be624b2e1 100644 --- a/test/built-ins/RegExp/regexp-modifiers/remove-dotAll.js +++ b/test/built-ins/RegExp/regexp-modifiers/remove-dotAll.js @@ -66,3 +66,15 @@ assert(!re2.test("\u2028"), "Pattern character '.' should not match '\\u2028' in assert(!re2.test("\u2029"), "Pattern character '.' should not match '\\u2029' in modified group"); assert(re2.test("\uD800"), "Pattern character '.' should match non-line terminators in modified group"); assert(re2.test("\uDFFF"), "Pattern character '.' should match non-line terminators in modified group"); + +var re3 = /a.(?-s:b.b).c/s; +assert(re3.test("a,b,b,c"), "Pattern character '.' should match non-line terminators in modified group"); +assert(re3.test("a\nb,b\nc"), "Pattern character '.' should match line terminators outside modified group"); +assert(!re3.test("a,b\nb,c"), "Pattern character '.' should not match line terminators in modified group"); +assert(!re3.test("a\nb\nb\nc"), "Pattern character '.' should not match line terminators in modified group"); + +var re4 = new RegExp("a.(?-s:b.b).c", "s"); +assert(re4.test("a,b,b,c"), "Pattern character '.' should match non-line terminators in modified group"); +assert(re4.test("a\nb,b\nc"), "Pattern character '.' should match line terminators outside modified group"); +assert(!re4.test("a,b\nb,c"), "Pattern character '.' should not match line terminators in modified group"); +assert(!re4.test("a\nb\nb\nc"), "Pattern character '.' should not match line terminators in modified group"); diff --git a/test/built-ins/RegExp/regexp-modifiers/remove-ignoreCase-does-not-affect-alternatives-outside.js b/test/built-ins/RegExp/regexp-modifiers/remove-ignoreCase-does-not-affect-alternatives-outside.js new file mode 100644 index 0000000000..39f4d97572 --- /dev/null +++ b/test/built-ins/RegExp/regexp-modifiers/remove-ignoreCase-does-not-affect-alternatives-outside.js @@ -0,0 +1,48 @@ +// Copyright 2024 Daniel Kwan. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Daniel Kwan +description: > + Removing ignoreCase (`i`) modifier should not affect alternatives outside. +info: | + Runtime Semantics: CompileAtom + The syntax-directed operation CompileAtom takes arguments direction (forward or backward) and modifiers (a Modifiers Record) and returns a Matcher. + + Atom :: `(` `?` RegularExpressionFlags `-` RegularExpressionFlags `:` Disjunction `)` + 1. Let addModifiers be the source text matched by the first RegularExpressionFlags. + 2. Let removeModifiers be the source text matched by the second RegularExpressionFlags. + 3. Let newModifiers be UpdateModifiers(modifiers, CodePointsToString(addModifiers), CodePointsToString(removeModifiers)). + 4. Return CompileSubpattern of Disjunction with arguments direction and newModifiers. + + UpdateModifiers ( modifiers, add, remove ) + The abstract operation UpdateModifiers takes arguments modifiers (a Modifiers Record), add (a String), and remove (a String) and returns a Modifiers. It performs the following steps when called: + + 1. Let dotAll be modifiers.[[DotAll]]. + 2. Let ignoreCase be modifiers.[[IgnoreCase]]. + 3. Let multiline be modifiers.[[Multiline]]. + 4. If add contains "s", set dotAll to true. + 5. If add contains "i", set ignoreCase to true. + 6. If add contains "m", set multiline to true. + 7. If remove contains "s", set dotAll to false. + 8. If remove contains "i", set ignoreCase to false. + 9. If remove contains "m", set multiline to false. + 10. Return the Modifiers Record { [[DotAll]]: dotAll, [[IgnoreCase]]: ignoreCase, [[Multiline]]: multiline }. + +esid: sec-compileatom +features: [regexp-modifiers] +---*/ + +var re1 = /a|b|(?-i:c)|d|e/i; +assert(re1.test("A"), "Alternative `a` should match `A`"); +assert(re1.test("B"), "Alternative `b` should match `B`"); +assert(!re1.test("C"), "Alternative `(?-i:c)` should not match `C` in modified group"); +assert(re1.test("D"), "Alternative `d` should match `D`"); +assert(re1.test("E"), "Alternative `e` should match `E`"); + +var re2 = /(a)|(?:b)|(?-i:c)|(?:d)|(e)/i; +assert(re2.test("A"), "Alternative `(a)` should match `A`"); +assert(re2.test("B"), "Alternative `(?:b)` should match `B`"); +assert(!re2.test("C"), "Alternative `(?-i:c)` should not match `C` in modified group"); +assert(re2.test("D"), "Alternative `(?:d)` should match `D`"); +assert(re2.test("E"), "Alternative `(e)` should match `E`"); diff --git a/test/built-ins/RegExp/regexp-modifiers/remove-ignoreCase.js b/test/built-ins/RegExp/regexp-modifiers/remove-ignoreCase.js index 65f6885c77..c951c5d5aa 100644 --- a/test/built-ins/RegExp/regexp-modifiers/remove-ignoreCase.js +++ b/test/built-ins/RegExp/regexp-modifiers/remove-ignoreCase.js @@ -44,3 +44,31 @@ assert(!re2.test("FOO"), "Pattern should not match as modified group does not ig assert(!re2.test("FOo"), "Pattern should not match as modified group does not ignore case"); assert(re2.test("foo"), "Pattern should not ignore case in modified group"); assert(re2.test("foO"), "Pattern should not ignore case in modified group"); + +var re3 = /b(?-i:ar)/i; +assert(!re3.test("BAR"), "Pattern should not match as modified group does not ignore case"); +assert(!re3.test("bAR"), "Pattern should not match as modified group does not ignore case"); +assert(re3.test("bar"), "Pattern should not ignore case in modified group"); +assert(re3.test("Bar"), "Pattern should not ignore case in modified group"); + +var re4 = new RegExp("b(?-i:ar)", "i"); +assert(!re4.test("BAR"), "Pattern should not match as modified group does not ignore case"); +assert(!re4.test("bAR"), "Pattern should not match as modified group does not ignore case"); +assert(re4.test("bar"), "Pattern should not ignore case in modified group"); +assert(re4.test("Bar"), "Pattern should not ignore case in modified group"); + +var re5 = /b(?-i:a)z/i; +assert(re5.test("baz"), "a should match a in baz"); +assert(!re5.test("bAz"), "A should not match a in baz"); +assert(re5.test("Baz"), "B should match b in baz"); +assert(re5.test("baZ"), "Z should match z in baz"); +assert(re5.test("BaZ"), "should match baz"); +assert(!re5.test("BAZ"), "should not match baz"); + +var re6 = new RegExp("b(?-i:a)z", "i"); +assert(re6.test("baz"), "a should match a in baz"); +assert(!re6.test("bAz"), "A should not match a in baz"); +assert(re6.test("Baz"), "B should match b in baz"); +assert(re6.test("baZ"), "Z should match z in baz"); +assert(re6.test("BaZ"), "should match baz"); +assert(!re6.test("BAZ"), "should not match baz"); diff --git a/test/built-ins/RegExp/regexp-modifiers/remove-multiline-does-not-affect-alternatives-outside.js b/test/built-ins/RegExp/regexp-modifiers/remove-multiline-does-not-affect-alternatives-outside.js new file mode 100644 index 0000000000..b7a9e482ce --- /dev/null +++ b/test/built-ins/RegExp/regexp-modifiers/remove-multiline-does-not-affect-alternatives-outside.js @@ -0,0 +1,48 @@ +// Copyright 2024 Daniel Kwan. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Daniel Kwan +description: > + Removing multiline (`m`) modifier should not affect alternatives outside. +info: | + Runtime Semantics: CompileAtom + The syntax-directed operation CompileAtom takes arguments direction (forward or backward) and modifiers (a Modifiers Record) and returns a Matcher. + + Atom :: `(` `?` RegularExpressionFlags `-` RegularExpressionFlags `:` Disjunction `)` + 1. Let addModifiers be the source text matched by the first RegularExpressionFlags. + 2. Let removeModifiers be the source text matched by the second RegularExpressionFlags. + 3. Let newModifiers be UpdateModifiers(modifiers, CodePointsToString(addModifiers), CodePointsToString(removeModifiers)). + 4. Return CompileSubpattern of Disjunction with arguments direction and newModifiers. + + UpdateModifiers ( modifiers, add, remove ) + The abstract operation UpdateModifiers takes arguments modifiers (a Modifiers Record), add (a String), and remove (a String) and returns a Modifiers. It performs the following steps when called: + + 1. Let dotAll be modifiers.[[DotAll]]. + 2. Let ignoreCase be modifiers.[[IgnoreCase]]. + 3. Let multiline be modifiers.[[Multiline]]. + 4. If add contains "s", set dotAll to true. + 5. If add contains "i", set ignoreCase to true. + 6. If add contains "m", set multiline to true. + 7. If remove contains "s", set dotAll to false. + 8. If remove contains "i", set ignoreCase to false. + 9. If remove contains "m", set multiline to false. + 10. Return the Modifiers Record { [[DotAll]]: dotAll, [[IgnoreCase]]: ignoreCase, [[Multiline]]: multiline }. + +esid: sec-compileatom +features: [regexp-modifiers] +---*/ + +var re1 = /^a$|^b$|(?-m:^c$)|^d$|^e$/m; +assert(re1.test("\na\n"), "Alternative `^a$` should match newline"); +assert(re1.test("\nb\n"), "Alternative `^b$` should match newline"); +assert(!re1.test("\nc\n"), "Alternative `(?-m:^c$)` should not match newline in modified group"); +assert(re1.test("\nd\n"), "Alternative `^d$` should match newline"); +assert(re1.test("\ne\n"), "Alternative `^e$` should match newline"); + +var re2 = /(^a$)|(?:^b$)|(?-m:^c$)|(?:^d$)|(^e$)/m; +assert(re2.test("\na\n"), "Alternative `(^a$)` should match newline"); +assert(re2.test("\nb\n"), "Alternative `(?:^b$)` should match newline"); +assert(!re2.test("\nc\n"), "Alternative `(?-m:^c$)` should not match newline in modified group"); +assert(re2.test("\nd\n"), "Alternative `(?:^d$)` should match newline"); +assert(re2.test("\ne\n"), "Alternative `(^e$)` should match newline"); diff --git a/test/built-ins/RegExp/regexp-modifiers/remove-multiline.js b/test/built-ins/RegExp/regexp-modifiers/remove-multiline.js index 1c414c252f..a618dc01fb 100644 --- a/test/built-ins/RegExp/regexp-modifiers/remove-multiline.js +++ b/test/built-ins/RegExp/regexp-modifiers/remove-multiline.js @@ -40,3 +40,11 @@ assert(re1.test("\nes"), "$ should match end of input in modified group"); var re2 = new RegExp("^(?-m:es$)", "m"); assert(!re2.test("\nes\ns"), "$ should not match newline in modified group"); assert(re2.test("\nes"), "$ should match end of input in modified group"); + +var re3 = /(?-m:^es)$/m; +assert(!re3.test("e\nes\n"), "^ should not match newline in modified group"); +assert(re3.test("es\n"), "^ should match start of input in modified group"); + +var re4 = new RegExp("(?-m:^es)$", "m"); +assert(!re4.test("e\nes\n"), "^ should not match newline in modified group"); +assert(re4.test("es\n"), "^ should match start of input in modified group");