Skip to content

fix(pattern): honour ^ anchor in gsub and literal caret in gmatch - #1

Merged
smn merged 1 commit into
mainfrom
fix-gsub-anchor
Jul 27, 2026
Merged

smn merged 1 commit into
mainfrom
fix-gsub-anchor

Conversation

@smn

@smn smn commented Jul 27, 2026

Copy link
Copy Markdown

Mirror of tv-labs#406.

Pattern.compile/1 returns an {anchored, elements} tuple, but only find/3 used the flag - gsub/4, gsub_stateful/5, and gmatch/2 discarded it. This routes gsub/gsub_stateful through an anchored branch and keeps a leading ^ literal in gmatch, matching PUC-Lua 5.3.6 semantics.

Upstream PR: tv-labs#406

Pattern.compile/1 returns an {anchored, elements} tuple, but only find/3
used the flag - gsub/4, gsub_stateful/5, and gmatch/2 discarded it.
Because compile strips the leading ^, those entry points matched the
remaining pattern at every position, so string.gsub("xax", "^x", "Y")
returned "YaY", 2 instead of "Yax", 1, silently corrupting the common
leading-trim idiom s:gsub("^%s+", "").

Route gsub and gsub_stateful through an anchored branch that tries the
match only at position 0 and replaces at most once, mirroring PUC-Lua
str_gsub's anchor flag. An n of 0 still suppresses the replacement, and
an empty anchored match (e.g. ^a* on "bbb") replaces once at the start.

gmatch needed the opposite treatment: per Lua 5.3 (and PUC-Lua's
gmatch_aux, which never strips the caret), a leading ^ in gmatch is not
an anchor but an ordinary literal character - so recompile the pattern
keeping the caret literal instead of dropping it.

Expected values in the regression tests are verified against PUC-Lua
5.3.6.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3LBtzmXgAMHA8QiGPa5Ek
@smn
smn merged commit f3a5cb6 into main Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants