ruby/ruby
Regexp (Onigmo)
Ruby's regular expression engine is Onigmo — a fork of the Oniguruma library, vendored in this repo as regcomp.c/regexec.c/regparse.c/regenc.c and friends. It's a Perl-compatible NFA backtracker with explicit support for Ruby's M17N encodings.
Purpose
- Compile
Regexpobjects from source patterns. - Match patterns against
Strings while respecting their encoding. - Provide
MatchDatawith named groups, captures, and pre/post strings. - Support every Ruby regex feature: lookahead, lookbehind, character classes, named captures, backreferences, atomic groups, possessive quantifiers,
\K,\g, conditional patterns.
Files
| File | Purpose |
|---|---|
regcomp.c |
Compiles a parsed regex into an internal bytecode. ~167 KB. |
regexec.c |
Runs the bytecode against an input. ~152 KB. |
regparse.c |
Parses regex source into a tree. ~173 KB. |
regparse.h |
Parser AST and helpers. |
regenc.c |
Generic encoding helpers used by the engine. |
regenc.h |
Encoding interface for the engine. |
regerror.c |
Error message formatting. |
regsyntax.c |
The regex syntax/dialect tables (Ruby, Perl, GNU, POSIX). |
regint.h |
Internal types and macros (~34 KB header). |
re.c |
Ruby-level Regexp and MatchData classes. ~137 KB. |
enc/<name>.c |
Per-encoding character classification tables consumed by the engine. |
Architecture
graph LR
src["/.../ pattern"] -->|regparse| ast[Regex AST]
ast -->|regcomp| ops["Onigmo bytecode\n(opcode + operand stream)"]
ops -->|regexec| match["Match against String\n+ encoding"]
match --> result["OnigRegion → rb_match_t → MatchData"]Parse
regparse.c::onig_parse_make_tree consumes the pattern source byte-by-byte, dispatching on metacharacters and producing a tree of Nodes (alternation, repetition, group, character class, anchor, backref, etc.). Encoding-aware character class decoding (e.g., \p{Hiragana}) consults the tables from enc/<name>.c.
Compile
regcomp.c::onig_compile walks the AST and emits a packed bytecode (OnigOpType enum in regint.h). Sample opcodes:
OP_ANYCHAR_STAR— greedy.*OP_PUSH— set up an alternativeOP_REPEAT— repetition with min/maxOP_BACKREF1toOP_BACKREF_MULTI— backreferencesOP_LOOK_BEHIND— lookbehindOP_FAIL— backtrack
The compiler also computes:
- The anchor map (start anchor, end anchor, line anchor, etc.).
- The must-match byte set: characters that must appear in any match. Used by the optimiser to fail fast on impossible inputs.
- The prefix if the regex starts with a literal — accelerates Boyer-Moore-like skip.
Execute
regexec.c::onig_match runs the bytecode against the input. The engine is an NFA backtracker:
- A stack of choice points (
STK_REPEAT,STK_ALT,STK_LOOK_BEHIND, ...). - A linear bytecode pointer that advances on match.
- On
OP_FAIL, pop the most recent choice point and rewind.
To prevent runaway backtracking on adversarial patterns, the engine has:
- A search limit (env var:
RUBY_RE_TIMEOUTfrom Ruby 3.2+) that aborts a match after a timeout. - Inline caching of repetition counts to detect catastrophic backtracking earlier.
Encoding awareness
Every Regexp is constructed with an Encoding:
/abc/u # UTF-8
/abc/n # ASCII-8BIT
/abc/s # Windows-31J
/abc/e # EUC-JP
/abc/ # depends on source file encoding (UTF-8 by default)Compilation builds character class bitmaps using the encoding's UCD tables. Execution decodes the input using the encoding's mbc_to_code callback. Mismatched encodings raise Encoding::CompatibilityError at match time.
Ruby-level surface
re.c wraps the engine for Ruby:
Regexp.new(src, opts)→ callsonig_compile.Regexp#match(str)→ callsonig_searchand wraps the resulting region asMatchData.String#=~,String#scan,String#sub,String#gsub,String#split— all route to the engine.Regexp.last_match,$~,$1...$9,$&,$``,$'— pseudo-globals backed byMatchData`.
In Ruby 4.x, all Regexp instances are frozen by default (see NEWS.md). Subclasses of Regexp remain mutable for backward compatibility.
Timeout protection
Regexp.timeout = 1.0 # seconds
"a" * 30000 =~ /(a+)+b/ # would otherwise hang
# raises Regexp::TimeoutError after 1sre.c::rb_reg_timeout_p checks the deadline at every backtrack. The default is nil (no timeout); set globally via Regexp.timeout= or per-instance via Regexp.new(src, timeout: 1.0).
Optimisations
- Boyer-Moore prefix search for patterns with a literal prefix.
- Memoization of repetition states to detect duplicate work.
- Fast paths for common ASCII patterns that bypass full encoding decode.
- Cache of compiled regexes inside literals (each
/foo/literal compiles once per source location).
Origin and divergence
Onigmo (Onigmo ≈ Oniguruma + "Mo" for Mathematics or extra power) forked from Oniguruma around 2010 to add Ruby-specific features:
\g<name>named subroutine calls.(?<name>...)named groups (Oniguruma also supports this).(?(cond)yes|no)conditional patterns.- Atomic groups, possessive quantifiers.
The bundled copy is occasionally synced from upstream; local edits are mostly bug fixes plus the Ruby integration shim in re.c.
Entry points for modification
- New regex feature: extend
regparse.cto recognise the syntax,regcomp.cto emit bytecode,regexec.cto interpret it. Add tests totest/ruby/test_regexp.rbandspec/ruby/core/regexp/. - Performance fix in matching:
regexec.c::match_atis the inner loop. Profile with--yjit-statsand the regex benchmarks underbenchmark/regex/. - Encoding-related bug:
enc/<name>.cfor the table;regparse.c::fetch_tokenfor tokenisation.
See encoding.md for M17N background and core-classes/string-and-symbol.md for String#=~ etc.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.