From c7aa10384a2548167466b4c61f9eff29ed8611f6 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 17 Aug 2026 07:13:02 +0900 Subject: refactor(preg): report unmatched groups as null throughout The shim carried two reporting modes for the preg_* $matches maps: PHP's default (trailing unmatched groups dropped, interior ones ""), and the PREG_UNMATCHED_AS_NULL form, picked by calling a *_unmatched_as_null() variant. The regex crate hands out Option, which maps onto the null form directly, and no caller distinguished a dropped group from a null one -- preg_match() and preg_match_all2() already reported nulls unconditionally. Keep only the null form; the shim API no longer mirrors PHP's flag set, which is intended. Preg::is_match_with_indexed_captures() modelled PHP's "unset" as a truncated Vec, and now returns Vec>. That is what Composer actually does: Preg::isMatch() always sets PREG_UNMATCHED_AS_NULL, and its callers test groups with `!== null`. preg_match_all(), preg_match_all_set_order() and preg_split_delim_capture() still hand back Vec and keep the "" form. Co-Authored-By: Claude Opus 5 (1M context) --- crates/shirabe/src/util/hg.rs | 2 +- crates/shirabe/src/util/platform.rs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'crates/shirabe/src/util') diff --git a/crates/shirabe/src/util/hg.rs b/crates/shirabe/src/util/hg.rs index 8570af6d..d9e58623 100644 --- a/crates/shirabe/src/util/hg.rs +++ b/crates/shirabe/src/util/hg.rs @@ -158,7 +158,7 @@ impl Hg { &output, ) { - return matches.into_iter().nth(1); + return matches.into_iter().nth(1).flatten(); } None }) diff --git a/crates/shirabe/src/util/platform.rs b/crates/shirabe/src/util/platform.rs index 21ad869c..629854b6 100644 --- a/crates/shirabe/src/util/platform.rs +++ b/crates/shirabe/src/util/platform.rs @@ -95,14 +95,12 @@ impl Platform { // Regex pattern compatibility: // The original pattern uses a conditional subpattern to make the trailing `%` required // only for the `%VAR%` form. The Rust regex crate does not support conditionals, so the - // two forms are written as an explicit alternation: `$VAR` or `%VAR%`. The branch that did - // not participate is reported as an empty string, which `\w+` can never capture. + // two forms are written as an explicit alternation: `$VAR` or `%VAR%`. Preg::replace_callback( php_regex!(r"#^(?:\$(?P\w+)|%(?P\w+)%)(?P.*)#"), |matches: &PregMatchedGroups| -> String { let var = matches .get(&CaptureKey::ByName("dvar".to_string())) - .filter(|dvar| !dvar.is_empty()) .or_else(|| matches.get(&CaptureKey::ByName("pvar".to_string()))) .map(|s| s.as_str()) .unwrap_or(""); -- cgit v1.3.1-4-g156e