Module regex/node
Regex AST node types.
Internal to std/regex. Nothing here is public API: import
std/regex and use Regex. This module's shape changes freely.
The parser produces a tree of RegexNode objects representing the
structure of a regex pattern. Nodes are reference-counted objects
since they form a recursive tree.
RegexNode is ONE WIDE STRUCT, not an enum with per-variant payloads: it
carries every field any node kind could need, and kind says which of them
mean anything. So a Literal has a meaningful codepoint and junk in
ranges/q_min/group_index, and a reader of a field must check kind
first. The shape buys recursion without Box (children are an
ArrayList(Self) on a reference-counted struct) at the cost of that
discipline. The thirteen RegexNode.* constructors are the only sanctioned
way to build one — each fills all ten fields explicitly, so no node is ever
partially initialised.
The tree is consumed exactly once, by compiler.yo, which lowers it to a
flat NFA program. Nothing traverses it twice and nothing mutates it after
the parser hands it over.
Stability
unstable, and deliberately not public — the module header says the shape
changes freely, and this is the module that means it: every syntax the
parser learns adds a NodeKind variant and usually a field to the wide
struct, and both are breaking for anything that matched exhaustively or
constructed a node literally. Only compiler.yo and parser.yo may depend
on it (plus CharRange, which unicode.yo builds, and GroupNameEntry,
which reaches RegexMatch). It has no freeze condition because it is not
meant to freeze.
Types
One node of the pattern AST.
Reference-counted (ref(struct(...))) so children : ArrayList(Self) can
close the recursion without a Box — the same trick LinkedList's node
uses. Which fields carry information depends entirely on kind; see
NodeKind, which documents that per variant, and the module header for why
it is one wide struct instead of an enum.
Fields
| Name | Type | Description |
|---|---|---|
kind | NodeKind | Which node this is. Every other field is only meaningful for the kinds
|
children | ArrayList(<struct:struct_decl_1053484_file____home_runner_work_Yo_Yo_std_regex_node_yo>) | Sub-patterns, in source order: none for the leaf kinds, one for a quantifier / group / lookaround, two for an alternation, any number for a sequence. |
codepoint | u32 |
|
ranges | ArrayList(CharRange) |
|
negated | bool |
|
q_min | usize |
|
q_max | usize |
|
q_greedy | bool |
|
group_index | usize |
|
anchor | AnchorKind |
|
impl(RegexNode, ...)
literal : (RegexNode) fn(cp : u32) -> RegexNodedot : (RegexNode) fn() -> RegexNodeA . node. Whether it matches \n is decided at MATCH time by the s
flag, not here, so one AST serves both modes.
Returns: RegexNode
char_class : (RegexNode) fn(ranges : ArrayList(CharRange), negated : bool) -> RegexNodeA [...] node over ranges, negated when negated. Takes ownership of
the list as given — no sorting, merging or validation, so an empty
ranges with negated : false is a class that can never match, and the
parser is responsible for not building one.
Parameters
| Name | Type | Notes | Description |
|---|---|---|---|
ranges | ArrayList(CharRange) |
| |
negated | bool |
|
Returns: RegexNode
anchor_node : (RegexNode) fn(kind : AnchorKind) -> RegexNodeA zero-width assertion node. Named anchor_node rather than anchor
because the struct already has an anchor FIELD.
Parameters
| Name | Type | Notes | Description |
|---|---|---|---|
kind | AnchorKind | Which node this is. Every other field is only meaningful for the kinds
|
Returns: RegexNode
sequence : (RegexNode) fn(nodes : ArrayList(<struct:struct_decl_1053484_file____home_runner_work_Yo_Yo_std_regex_node_yo>)) -> RegexNodeA concatenation of nodes, matched left to right. Takes the list as
given, including an empty one — which is how the empty pattern and the
empty side of a| are represented.
Parameters
| Name | Type | Notes |
|---|---|---|
nodes | ArrayList(<struct:struct_decl_1053484_file____home_runner_work_Yo_Yo_std_regex_node_yo>) |
Returns: RegexNode
alternation : (RegexNode) fn(left : RegexNode, right : RegexNode) -> RegexNodequantifier : (RegexNode) fn(child : RegexNode, min_val : usize, max_val : usize, greedy : bool) -> RegexNodeA repetition node around child.
max_val == 0 means UNBOUNDED — that is the sentinel for *, + and
{m,}, so it does not mean "zero times". greedy : false is the ?
suffix (a*?), which only reorders the alternatives the compiler emits.
Parameters
| Name | Type | Notes |
|---|---|---|
child | RegexNode | |
min_val | usize | |
max_val | usize | |
greedy | bool |
Returns: RegexNode
group : (RegexNode) fn(child : RegexNode, index : usize) -> RegexNodeA capturing (...) node. index is the 1-based capture number the
parser assigned by opening-parenthesis order, which is what \1, $1
and RegexMatch.group(i) all count in.
Parameters
| Name | Type | Notes | Description |
|---|---|---|---|
child | RegexNode | ||
index | usize | The 1-based capture-group number this name is an alias for, so
|
Returns: RegexNode
non_capturing_group : (RegexNode) fn(child : RegexNode) -> RegexNodebackreference : (RegexNode) fn(group_idx : usize) -> RegexNodeA \1 / \k<name> node re-matching whatever group group_idx
captured. Names are already resolved to numbers by the parser, so this
takes an index either way, and the parser has already rejected an index
with no such group (InvalidBackreference / UnknownGroupName).
Parameters
| Name | Type | Notes |
|---|---|---|
group_idx | usize |
Returns: RegexNode
lookahead : (RegexNode) fn(child : RegexNode, positive : bool) -> RegexNodelookbehind : (RegexNode) fn(child : RegexNode, positive : bool) -> RegexNodeA range of characters for character classes, e.g. a–z.
Fields
| Name | Type | Description |
|---|---|---|
low | u32 | First code point in the range, INCLUSIVE. |
high | u32 | Last code point in the range, INCLUSIVE — so a single character is
|
One (?<name>...) declaration: the name and the group number it refers
to. The parser collects these in declaration order and they travel all the
way out to RegexMatch.named_group, which scans the list linearly.
Fields
| Name | Type | Description |
|---|---|---|
name | String | The name as written, without the angle brackets. Compared for exact equality, case-sensitively. |
index | usize | The 1-based capture-group number this name is an alias for, so
|