diff --git a/src/parse.rs b/src/parse.rs index 05d7a75..aeb10c5 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -335,14 +335,14 @@ where '(' => { if self.try_consume_str("(?=") { // Positive lookahead. - quantifier_allowed = false; + quantifier_allowed = !self.flags.unicode; result.push(self.consume_lookaround_assertion(LookaroundParams { negate: false, backwards: false, })?); } else if self.try_consume_str("(?!") { // Negative lookahead. - quantifier_allowed = false; + quantifier_allowed = !self.flags.unicode; result.push(self.consume_lookaround_assertion(LookaroundParams { negate: true, backwards: false, diff --git a/tests/tests.rs b/tests/tests.rs index 17442d8..1c7b0d6 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1650,3 +1650,93 @@ fn test_class_invalid_control_character_tc(tc: TestConfig) { tc.test_match_succeeds("[\\c\u{0}]", "", "c"); tc.test_match_succeeds("[\\c\u{0}]", "", "\u{0}"); } + +#[test] +fn test_quantifiable_assertion_not_followed_by() { + test_with_configs(test_quantifiable_assertion_not_followed_by_tc) +} + +/// 262 test/annexB/language/literals/regexp/quantifiable-assertion-not-followed-by.js +fn test_quantifiable_assertion_not_followed_by_tc(tc: TestConfig) { + tc.compile(r#"[a-e](?!Z)*"#) + .match1f(r#"aZZZZ bZZZ cZZ dZ e"#) + .test_eq("a"); + tc.compile(r#"[a-e](?!Z)+"#) + .match1f(r#"aZZZZ bZZZ cZZ dZ e"#) + .test_eq("e"); + tc.compile(r#"[a-e](?!Z)?"#) + .match1f(r#"aZZZZ bZZZ cZZ dZ e"#) + .test_eq("a"); + tc.compile(r#"[a-e](?!Z){2}"#) + .match1f(r#"aZZZZ bZZZ cZZ dZ e"#) + .test_eq("e"); + tc.compile(r#"[a-e](?!Z){2,}"#) + .match1f(r#"aZZZZ bZZZ cZZ dZ e"#) + .test_eq("e"); + tc.compile(r#"[a-e](?!Z){2,3}"#) + .match1f(r#"aZZZZ bZZZ cZZ dZ e"#) + .test_eq("e"); + tc.compile(r#"[a-e](?!Z)*?"#) + .match1f(r#"aZZZZ bZZZ cZZ dZ e"#) + .test_eq("a"); + tc.compile(r#"[a-e](?!Z)+?"#) + .match1f(r#"aZZZZ bZZZ cZZ dZ e"#) + .test_eq("e"); + tc.compile(r#"[a-e](?!Z)??"#) + .match1f(r#"aZZZZ bZZZ cZZ dZ e"#) + .test_eq("a"); + tc.compile(r#"[a-e](?!Z){2}?"#) + .match1f(r#"aZZZZ bZZZ cZZ dZ e"#) + .test_eq("e"); + tc.compile(r#"[a-e](?!Z){2,}?"#) + .match1f(r#"aZZZZ bZZZ cZZ dZ e"#) + .test_eq("e"); + tc.compile(r#"[a-e](?!Z){2,3}?"#) + .match1f(r#"aZZZZ bZZZ cZZ dZ e"#) + .test_eq("e"); +} + +#[test] +fn test_quantifiable_assertion_followed_by() { + test_with_configs(test_quantifiable_assertion_followed_by_tc) +} + +/// 262 test/annexB/language/literals/regexp/quantifiable-assertion-followed-by.js +fn test_quantifiable_assertion_followed_by_tc(tc: TestConfig) { + tc.compile(r#".(?=Z)*"#) + .match1f(r#"a bZ cZZ dZZZ eZZZZ"#) + .test_eq("a"); + tc.compile(r#".(?=Z)+"#) + .match1f(r#"a bZ cZZ dZZZ eZZZZ"#) + .test_eq("b"); + tc.compile(r#".(?=Z)?"#) + .match1f(r#"a bZ cZZ dZZZ eZZZZ"#) + .test_eq("a"); + tc.compile(r#".(?=Z){2}"#) + .match1f(r#"a bZ cZZ dZZZ eZZZZ"#) + .test_eq("b"); + tc.compile(r#".(?=Z){2,}"#) + .match1f(r#"a bZ cZZ dZZZ eZZZZ"#) + .test_eq("b"); + tc.compile(r#".(?=Z){2,3}"#) + .match1f(r#"a bZ cZZ dZZZ eZZZZ"#) + .test_eq("b"); + tc.compile(r#".(?=Z)*?"#) + .match1f(r#"a bZ cZZ dZZZ eZZZZ"#) + .test_eq("a"); + tc.compile(r#".(?=Z)+?"#) + .match1f(r#"a bZ cZZ dZZZ eZZZZ"#) + .test_eq("b"); + tc.compile(r#".(?=Z)??"#) + .match1f(r#"a bZ cZZ dZZZ eZZZZ"#) + .test_eq("a"); + tc.compile(r#".(?=Z){2}?"#) + .match1f(r#"a bZ cZZ dZZZ eZZZZ"#) + .test_eq("b"); + tc.compile(r#".(?=Z){2,}?"#) + .match1f(r#"a bZ cZZ dZZZ eZZZZ"#) + .test_eq("b"); + tc.compile(r#".(?=Z){2,3}?"#) + .match1f(r#"a bZ cZZ dZZZ eZZZZ"#) + .test_eq("b"); +}