Skip to content

Implement string.gmatch iterator - #223

Open
evadne wants to merge 1 commit into
rvirding:developfrom
evadne:feature/string-gmatch
Open

Implement string.gmatch iterator#223
evadne wants to merge 1 commit into
rvirding:developfrom
evadne:feature/string-gmatch

Conversation

@evadne

@evadne evadne commented Feb 27, 2026

Copy link
Copy Markdown

Implements string.gmatch(s, pattern).

  • This was previously a stub that always raised badarg
  • This change implements the function using the existing pattern-matching engine.
  • The implementation is pre-computed:
    • Pre-compute all matches eagerly via gsub_match_loop/6
    • Store the match list in luerl private state under a unique ref
    • Return an erl_func iterator that pops from the match list on each call.
    • The iterator state is cleaned up when the match list is exhausted.
    • Use luerl:put_private, get_private and delete_private to thread iterator state through the luerl state record rather than the process dictionary, keeping the implementation pure.
  • The eager approach follows gsub, which also pre-computes all matches via gsub_match_loop/6, before processing replacements.
    • Both functions share the same match engine, so a future lazy stepper would benefit both equally.
  • Added 9 new tests in luerl_str_gmatch_tests.erl.

Handles

  • Basic iteration (word splitting, digit extraction)
  • Multiple captures (key=value patterns)
  • Single character matches
  • Anchored patterns (^)
  • No-match case (iterator immediately yields nil)
  • Empty input string
  • Multiple independent iterators
  • Typical Lua book pattern: building tables from key=value strings

Should fix #150

string.gmatch(s, pattern) was previously a stub that always raised
badarg. This implements it using the existing pattern matching engine.

Approach: pre-compute all matches eagerly via gsub_match_loop/6, store
the match list in luerl private state under a unique ref, return an
erl_func iterator that pops from the match list on each call. The
iterator state is cleaned up when the match list is exhausted.

Uses luerl:put_private/get_private/delete_private to thread iterator
state through the luerl state record rather than the process
dictionary, keeping the implementation pure.

The eager approach is consistent with gsub, which also pre-computes
all matches via gsub_match_loop/6 before processing replacements.
Both functions share the same match engine, so a future lazy stepper
would benefit both equally. Eager is simpler and makes each iterator
call O(1) — the right trade-off given that gmatch typically iterates
to completion.

Handles:
- Basic iteration (word splitting, digit extraction)
- Multiple captures (key=value patterns)
- Single character matches
- Anchored patterns (^)
- No-match case (iterator immediately yields nil)
- Empty input string
- Multiple independent iterators
- Typical Lua book pattern: building tables from key=value strings

9 new tests in luerl_str_gmatch_tests.erl.
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.

string.gmatch

1 participant