aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-17 06:03:41 +0900
committernsfisis <nsfisis@gmail.com>2026-08-17 06:03:41 +0900
commitc81e9f89d9e4388f36a4427bbaa95eced659d2ce (patch)
treecd35eedf6741347e791e6909ec604b89d5e0cff7 /crates
parentea39e2301824435d45db88f95867dbe692aaf21e (diff)
downloadphp-shirabe-c81e9f89d9e4388f36a4427bbaa95eced659d2ce.tar.gz
php-shirabe-c81e9f89d9e4388f36a4427bbaa95eced659d2ce.tar.zst
php-shirabe-c81e9f89d9e4388f36a4427bbaa95eced659d2ce.zip
refactor(preg): split the PREG_UNMATCHED_AS_NULL preg_* by flag
preg_match2() and preg_match_all_offset_capture() each become a pair over a shared private impl, and their flags arguments are gone: no caller passed anything but 0 or PREG_UNMATCHED_AS_NULL. Preg::match5()/is_match5() lose their own flags argument for the same reason -- both call sites passed 0, and the value had nowhere left to go -- so they are renumbered to match4()/is_match4(). PREG_UNMATCHED_AS_NULL itself is now unreferenced. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates')
-rw-r--r--crates/shirabe-class-map-generator/src/php_file_cleaner.rs5
-rw-r--r--crates/shirabe-pcre/src/preg.rs32
-rw-r--r--crates/shirabe-php-shim/src/preg.rs51
-rw-r--r--crates/shirabe-symfony-console/src/formatter/output_formatter.rs1
-rw-r--r--crates/shirabe-symfony-console/src/input/string_input.rs5
-rw-r--r--crates/shirabe/src/console/application.rs1
6 files changed, 56 insertions, 39 deletions
diff --git a/crates/shirabe-class-map-generator/src/php_file_cleaner.rs b/crates/shirabe-class-map-generator/src/php_file_cleaner.rs
index eb2b84e4..c5952389 100644
--- a/crates/shirabe-class-map-generator/src/php_file_cleaner.rs
+++ b/crates/shirabe-class-map-generator/src/php_file_cleaner.rs
@@ -145,11 +145,10 @@ impl PhpFileCleaner {
if end <= self.len && self.contents[self.index..end] == entry.name {
let offset = if self.index > 0 { self.index - 1 } else { 0 };
let mut r#match: IndexMap<CaptureKey, String> = IndexMap::new();
- if Preg::is_match5(
+ if Preg::is_match4(
&entry.pattern,
&self.contents,
Some(&mut r#match),
- 0,
offset,
) {
return clean
@@ -294,6 +293,6 @@ impl PhpFileCleaner {
}
fn r#match(&self, regex: &str, r#match: Option<&mut IndexMap<CaptureKey, String>>) -> bool {
- Preg::is_match5(regex, &self.contents, r#match, 0, self.index)
+ Preg::is_match4(regex, &self.contents, r#match, self.index)
}
}
diff --git a/crates/shirabe-pcre/src/preg.rs b/crates/shirabe-pcre/src/preg.rs
index fb71c63b..0448f81a 100644
--- a/crates/shirabe-pcre/src/preg.rs
+++ b/crates/shirabe-pcre/src/preg.rs
@@ -14,8 +14,8 @@
use indexmap::IndexMap;
pub use shirabe_php_shim::CaptureKey;
use shirabe_php_shim::{
- PREG_UNMATCHED_AS_NULL, PregPattern, preg_grep, preg_match_all_offset_capture, preg_match_all2,
- preg_match2, preg_replace_callback, preg_replace2,
+ PregPattern, preg_grep, preg_match_all_offset_capture_unmatched_as_null, preg_match_all2,
+ preg_match2, preg_match2_unmatched_as_null, preg_replace_callback, preg_replace2,
};
#[derive(Debug)]
@@ -27,24 +27,17 @@ impl Preg {
subject: &str,
matches: Option<&mut IndexMap<CaptureKey, String>>,
) -> bool {
- Self::match5(pattern, subject, matches, 0, 0)
+ Self::match4(pattern, subject, matches, 0)
}
- pub fn match5(
+ pub fn match4(
pattern: impl PregPattern,
subject: &str,
matches: Option<&mut IndexMap<CaptureKey, String>>,
- flags: i64,
offset: usize,
) -> bool {
let mut internal: IndexMap<CaptureKey, Option<String>> = IndexMap::new();
- let result = preg_match2(
- pattern,
- subject,
- &mut internal,
- flags | PREG_UNMATCHED_AS_NULL,
- offset,
- );
+ let result = preg_match2_unmatched_as_null(pattern, subject, &mut internal, offset);
if let Some(out) = matches {
*out = drop_null_matches(internal);
@@ -73,7 +66,7 @@ impl Preg {
) -> usize {
let mut internal: IndexMap<CaptureKey, Vec<(Option<String>, i64)>> = IndexMap::new();
let result =
- preg_match_all_offset_capture(pattern, subject, &mut internal, PREG_UNMATCHED_AS_NULL);
+ preg_match_all_offset_capture_unmatched_as_null(pattern, subject, &mut internal);
if let Some(out) = matches {
*out = internal;
@@ -125,7 +118,7 @@ impl Preg {
}
pub fn is_match(pattern: impl PregPattern, subject: &str) -> bool {
- Self::match5(pattern, subject, None, 0, 0)
+ Self::match4(pattern, subject, None, 0)
}
pub fn is_match3(
@@ -133,17 +126,16 @@ impl Preg {
subject: &str,
matches: Option<&mut IndexMap<CaptureKey, String>>,
) -> bool {
- Self::match5(pattern, subject, matches, 0, 0)
+ Self::match4(pattern, subject, matches, 0)
}
- pub fn is_match5(
+ pub fn is_match4(
pattern: impl PregPattern,
subject: &str,
matches: Option<&mut IndexMap<CaptureKey, String>>,
- flags: i64,
offset: usize,
) -> bool {
- Self::match5(pattern, subject, matches, flags, offset)
+ Self::match4(pattern, subject, matches, offset)
}
pub fn is_match_named(
@@ -152,7 +144,7 @@ impl Preg {
matches: &mut IndexMap<String, String>,
) -> bool {
let mut internal: IndexMap<CaptureKey, Option<String>> = IndexMap::new();
- let result = preg_match2(pattern, subject, &mut internal, PREG_UNMATCHED_AS_NULL, 0);
+ let result = preg_match2_unmatched_as_null(pattern, subject, &mut internal, 0);
matches.clear();
for (key, value) in internal {
@@ -171,7 +163,7 @@ impl Preg {
// Classic preg_match semantics (no PREG_UNMATCHED_AS_NULL): trailing
// unmatched groups are truncated, interior unmatched groups become "".
let mut internal: IndexMap<CaptureKey, Option<String>> = IndexMap::new();
- let result = preg_match2(pattern, subject, &mut internal, 0, 0);
+ let result = preg_match2(pattern, subject, &mut internal, 0);
if !result {
return None;
diff --git a/crates/shirabe-php-shim/src/preg.rs b/crates/shirabe-php-shim/src/preg.rs
index 1156129a..0d6a3231 100644
--- a/crates/shirabe-php-shim/src/preg.rs
+++ b/crates/shirabe-php-shim/src/preg.rs
@@ -1,8 +1,6 @@
use indexmap::IndexMap;
use std::sync::{Arc, LazyLock, Mutex};
-pub const PREG_UNMATCHED_AS_NULL: i64 = 512;
-
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub enum CaptureKey {
ByIndex(usize),
@@ -51,18 +49,35 @@ pub fn preg_match(
}
}
-// Returns whether the pattern matched. Unmatched groups are reported as None
-// (PREG_UNMATCHED_AS_NULL).
+// Returns whether the pattern matched, reporting the groups as single_match_map() does.
pub fn preg_match2(
pattern: impl PregPattern,
subject: &str,
matches: &mut indexmap::IndexMap<CaptureKey, Option<String>>,
- flags: i64,
offset: usize,
) -> bool {
+ preg_match2_impl(pattern, subject, matches, offset, false)
+}
+
+// PREG_UNMATCHED_AS_NULL counterpart of preg_match2().
+pub fn preg_match2_unmatched_as_null(
+ pattern: impl PregPattern,
+ subject: &str,
+ matches: &mut indexmap::IndexMap<CaptureKey, Option<String>>,
+ offset: usize,
+) -> bool {
+ preg_match2_impl(pattern, subject, matches, offset, true)
+}
+
+fn preg_match2_impl(
+ pattern: impl PregPattern,
+ subject: &str,
+ matches: &mut indexmap::IndexMap<CaptureKey, Option<String>>,
+ offset: usize,
+ unmatched_as_null: bool,
+) -> bool {
let __resolved = pattern.resolve();
let (re, anchored) = __resolved.parts();
- let unmatched_as_null = flags & PREG_UNMATCHED_AS_NULL != 0;
// An anchored (`A`) pattern must match starting exactly at `offset`; the `regex` crate cannot
// anchor a `captures_at` search, so search the sub-slice beginning at `offset` and require the
// match to start at its head.
@@ -155,15 +170,33 @@ pub fn preg_match_all_set_order(
count
}
+// A non-participating group is reported at offset -1, holding "".
pub fn preg_match_all_offset_capture(
pattern: impl PregPattern,
subject: &str,
matches: &mut indexmap::IndexMap<CaptureKey, Vec<(Option<String>, i64)>>,
- flags: i64,
+) -> usize {
+ preg_match_all_offset_capture_impl(pattern, subject, matches, false)
+}
+
+// PREG_UNMATCHED_AS_NULL counterpart of preg_match_all_offset_capture(): a
+// non-participating group holds null instead of "".
+pub fn preg_match_all_offset_capture_unmatched_as_null(
+ pattern: impl PregPattern,
+ subject: &str,
+ matches: &mut indexmap::IndexMap<CaptureKey, Vec<(Option<String>, i64)>>,
+) -> usize {
+ preg_match_all_offset_capture_impl(pattern, subject, matches, true)
+}
+
+fn preg_match_all_offset_capture_impl(
+ pattern: impl PregPattern,
+ subject: &str,
+ matches: &mut indexmap::IndexMap<CaptureKey, Vec<(Option<String>, i64)>>,
+ unmatched_as_null: bool,
) -> usize {
let __resolved = pattern.resolve();
let (re, _anchored) = __resolved.parts();
- let unmatched_as_null = flags & PREG_UNMATCHED_AS_NULL != 0;
let group_count = re.captures_len();
let names: Vec<Option<&str>> = re.capture_names().collect();
@@ -172,8 +205,6 @@ pub fn preg_match_all_offset_capture(
for caps in re.captures_iter(subject) {
count += 1;
for (g, column) in groups.iter_mut().enumerate() {
- // A non-participating group is reported at offset -1, holding "" or,
- // with PREG_UNMATCHED_AS_NULL, null.
let entry = match caps.get(g) {
Some(m) => (Some(m.as_str().to_string()), m.start() as i64),
None if unmatched_as_null => (None, -1),
diff --git a/crates/shirabe-symfony-console/src/formatter/output_formatter.rs b/crates/shirabe-symfony-console/src/formatter/output_formatter.rs
index 6ce96875..1a3de217 100644
--- a/crates/shirabe-symfony-console/src/formatter/output_formatter.rs
+++ b/crates/shirabe-symfony-console/src/formatter/output_formatter.rs
@@ -296,7 +296,6 @@ impl WrappableOutputFormatterInterface for OutputFormatter {
format!("#<(({open_tag_regex}) | /({close_tag_regex})?)>#ix"),
message,
&mut matches,
- 0,
);
let full_matches = matches
.get(&CaptureKey::ByIndex(0))
diff --git a/crates/shirabe-symfony-console/src/input/string_input.rs b/crates/shirabe-symfony-console/src/input/string_input.rs
index 1ec6e853..d6794957 100644
--- a/crates/shirabe-symfony-console/src/input/string_input.rs
+++ b/crates/shirabe-symfony-console/src/input/string_input.rs
@@ -58,7 +58,7 @@ impl StringInput {
}
let mut m: IndexMap<CaptureKey, Option<String>> = IndexMap::new();
- if preg_match2(php_regex!(r"/\s+/A"), input, &mut m, 0, cursor as usize) {
+ if preg_match2(php_regex!(r"/\s+/A"), input, &mut m, cursor as usize) {
if token.is_some() {
tokens.push(token.take().unwrap());
}
@@ -68,7 +68,6 @@ impl StringInput {
format!(r#"/([^="'\s]+?)(=?)({}+)/A"#, Self::REGEX_QUOTED_STRING),
input,
&mut m,
- 0,
cursor as usize,
) {
let inner = shirabe_php_shim::substr(
@@ -91,7 +90,6 @@ impl StringInput {
format!(r"/{}/A", Self::REGEX_QUOTED_STRING),
input,
&mut m,
- 0,
cursor as usize,
) {
token = Some(format!(
@@ -109,7 +107,6 @@ impl StringInput {
format!(r"/{}/A", Self::REGEX_UNQUOTED_STRING),
input,
&mut m,
- 0,
cursor as usize,
) {
token = Some(format!(
diff --git a/crates/shirabe/src/console/application.rs b/crates/shirabe/src/console/application.rs
index b55b9e68..e818823e 100644
--- a/crates/shirabe/src/console/application.rs
+++ b/crates/shirabe/src/console/application.rs
@@ -1796,7 +1796,6 @@ impl Application {
php_regex!(r"/.{1,10000}/u"),
&utf8_string,
&mut m,
- 0,
offset as usize,
) {
let m0 = m[&shirabe_php_shim::CaptureKey::ByIndex(0)]