| Age | Commit message (Collapse) | Author |
|
`Composer\Pcre\Preg` fills `$matches` through a by-ref parameter, and the
port mirrored that with a `&mut` (or `Option<&mut>`) out-param plus a
bool or count return. Callers had to declare an empty map one line ahead
of the call, and the type never said the map is only meaningful when the
call matched. Return the matches instead:
- match3/match4/is_match3/is_match4 -> Option<PregMatchedGroups>
- is_match_named -> Option<PregNamedGroups>
- match_all2/is_match_all -> PregMatchesAll
- is_match_all_with_offsets3 -> PregMatchesAllWithOffsets
Nothing is lost: the bool is `Option::is_some()`, and the occurrence
count is the length of any one column of a PREG_PATTERN_ORDER map, now
spelled `PregMatchesAll::occurrence_count()`. is_match() still answers
the bool question directly for callers that want no groups.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
PHP fills `$matches` through a by-ref parameter, which the port mirrored
with a `&mut` out-param plus a bool or count return. Every caller then
had to declare an empty binding one line ahead of the call, and nothing
in the type said the binding is only meaningful when the call succeeded.
Return the matches instead: preg_match() and preg_match2() hand back an
Option, and the three preg_match_all* functions hand back the collection
they used to fill.
The occurrence count the two map-shaped preg_match_all* functions used
to return is the length of any one of the map's columns, so it is not
lost -- Preg::match_all() and friends derive it via occurrence_count().
preg_replace2() keeps its `count: Option<&mut usize>`: that one is not
derivable from the replaced string, and callers that do not want it pay
nothing for passing None.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
preg_match_all() and preg_match_all_set_order() were the last preg_*
functions handing back a bare Vec<String>, where a group that did not
participate is indistinguishable from one that captured "". Hand back
Option<String> as the map-shaped functions already do; php_match_row(),
the last of the truncate-then-pad helpers, goes with them.
preg_split_delim_capture() keeps its Vec<String>. preg_split() accepts
no PREG_UNMATCHED_AS_NULL, so there is no null form to move it to, and
its result interleaves split segments -- which can never be absent --
with the captured delimiters.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
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<Match>, 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<String>, and now returns Vec<Option<String>>. 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<String> and keep the ""
form.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
The five IndexMap shapes that the preg_* functions and Preg fill in are
now distinct types generated by preg_match_map!, so a matches map no
longer interchanges with any other map of the same key and value type.
Index<usize> is kept alongside Index<&Q> because call sites such as
config_command and event_dispatcher reach for a group by its position in
the map rather than by its capture key.
|
|
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>
|
|
Each branch of the flag is now its own function. The PREG_UNMATCHED_AS_NULL
variant needs neither the trailing-group truncation nor the empty-string
fallback, so it loses the break condition and the last_participating scan.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Preg::match5() rejected PREG_OFFSET_CAPTURE and check_set_order() rejected
PREG_SET_ORDER, mirroring the PHP where those flags would change the type
of $matches. The Rust ports of both take a typed `matches` out-param
instead, so neither flag can reach them; check_set_order() already had no
caller. The three constants are unreferenced once the guards are gone.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
preg_split2()'s limit was always -1 and its flags were always either 0 or
PREG_SPLIT_DELIM_CAPTURE alone, so both arguments are gone: the shim now
exposes preg_split() and preg_split_delim_capture() over a shared
preg_split_impl(). That leaves Preg::split()/split4() as bare
pass-throughs, so callers use the shim functions directly and the wrappers
are dropped along with the now-unreferenced PREG_SPLIT_* constants.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
The two functions ran the same search and differed only in how they
reported a non-participating group: one as ("", 0) in a bespoke struct,
the other as (null, -1) in a capture-key map. Neither shape covered both
callers, because PHP reaches preg_match_all() with different flags from
each: Preg::matchAllWithOffsets() always ORs in PREG_UNMATCHED_AS_NULL,
while OutputFormatter::formatAndWrap() passes PREG_OFFSET_CAPTURE alone.
Keep the capture-key map, which also exposes named groups, and take the
flags that decide between null and "" for an unmatched group. The offset
is -1 either way, so the ("", 0) approximation is gone.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
The sole caller, Preg::match_all_with_offsets5(), always passed flags=0
and offset=0, so PREG_UNMATCHED_AS_NULL is now unconditional and the
subject is scanned from the beginning. That method is only reached from
Preg::match_all_with_offsets(), so it is no longer public either.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Every caller reached preg_match_all2() through Preg::match_all5(), which
always passed flags = PREG_UNMATCHED_AS_NULL and offset = 0. Inline those
constants and make match_all5() private, since the two public wrappers are
its only callers.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Callers had to build a temporary Vec<&str> at every call site to satisfy
the &[&str] parameter. Taking IntoIterator and yielding the matched items
lets them pass owned or borrowed strings directly.
The flags variant and PREG_GREP_INVERT go away with it: no caller passes
flags, and Composer's Preg::grep() has no such parameter either.
|
|
|
|
preg_replace_callback2 had one caller, Preg::replace_callback6, which
was itself reached only from Preg::replace_callback with the default
limit, count and flags. Fold the two shim functions into one and drop
those parameters along with replace_callback6.
The surviving callback takes callback2's IndexMap of matches: it can be
keyed by group name, and it omits trailing non-participating groups the
way PHP does, which is what the callbacks in Process and ProgressBar
test for.
|
|
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Retag every Shirabe-authored TODO comment to one of the fixed tags:
phase-c, phase-d, plugin, php-runtime, phase-e.
Upstream-authored TODO comments from Composer/Symfony are left
untouched to preserve the ported code shape.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
regex::Regex::clone() does not share the underlying meta engine's
search-cache pool, so every fresh clone pays a ~10us warmup cost on
its first use. Two changes together eliminate this across nearly all
preg_* call sites:
- A php_regex! macro resolves PHP-style patterns to a per-call-site
&'static regex::Regex (via regex-macro's LazyLock), applied at the
majority of call sites throughout the codebase.
- Call sites still passing dynamic pattern strings go through
PATTERN_CACHE, which now stores Arc<(Regex, bool)> and hands out
Arc::clone()s instead of cloning the Regex itself.
PregPattern::resolve() returns a ResolvedPattern enum (Arc or
'static reference) rather than an owned Regex, so neither path ever
clones the Regex proper.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
|
Composer's classmap generator re-issues the same PHP-derived pattern
string for every scanned file (and every token within it), relying on
PCRE's built-in compiled-pattern cache to make that free. shirabe had
no equivalent, so every Preg::* call recompiled the pattern from
scratch via regex::Regex::new(), making `composer create-project`
autoload generation ~130x slower than Composer on a fresh laravel/laravel
install (130s vs ~1s). Memoizing compiled patterns by their raw string
in compile_php_pattern closes that gap.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
|
|
|
Port autoload_generator (24), bitbucket (14), suggested_packages (11),
git_driver (6), archive_manager (3), and a bump command test. Fix the
ApplicationTester output-capture root cause (php://memory streams must be
readable regardless of fopen mode). Implement posix_getuid/geteuid, the PCRE
'A' anchored modifier, php_strip_whitespace, stream_get_wrappers, is_callable
scalars; fix preg_quote angle-bracket escaping and class-map parser regexes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
|
|
|
|
|
|
The optional matches output was always passed Some(&mut ...) at every
call site, so the Option wrapper added no value. Take &mut directly and
inline the former internal helpers.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
preg_match2 returns bool and the preg_match_all* helpers return usize
(the match count is never negative), matching how callers use them.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
preg_match can only return 1 or 0 now that compile failure panics, so
return bool and update all call sites accordingly.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
The preg_* shim helpers wrapped their results in Option/Result solely to
signal a regex that failed to compile. Composer never feeds a pattern
that fails at runtime, so such a failure is a programming error: panic
instead and drop the Option/Result wrappers, updating all callers.
preg_replace_callback keeps its Result return type since the callback
itself is fallible. preg_match_groups is removed in favor of preg_match
at its sole call site.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
The preg.rs shim had several near-duplicate functions: simple helpers
re-implementing logic already covered by their full-featured `2`
variants. Delegate or remove the redundant ones while preserving
behavior, and migrate the affected callers:
- preg_replace / preg_split now delegate to preg_replace2 / preg_split2
- preg_match_all_simple removed; its caller uses preg_match_all
- preg_split_chars removed; its caller uses a char-boundary iterator
- preg_match_offset removed; its callers use preg_match2 directly
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
The free preg_* functions, the CaptureKey type, and the PREG_* constants
move from the pcre crate into shirabe-php-shim, where the rest of the
PHP standard-library shims live. Colliding names take a 2 suffix
(preg_match2, preg_split2, etc.) since the shim already exposes
differently-shaped variants. Preg keeps its public API and delegates to
the relocated functions; CaptureKey is re-exported from composer::pcre
so consumers are unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|