Module regex/node

regex/node
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. — stable modules only change additively; this one may still change.

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

RegexNode object
RegexNode

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

NameTypeDescription
kindNodeKind

Which node this is. Every other field is only meaningful for the kinds NodeKind lists it under.

childrenArrayList(<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.

codepointu32

Literal: the code point to match.

rangesArrayList(CharRange)

CharClass: the inclusive code-point ranges the class accepts. Not required to be sorted or disjoint.

negatedbool

CharClass: [^...] — accept anything OUTSIDE ranges. Lookahead/Lookbehind: the assertion is NEGATIVE ((?!, (?<!).

q_minusize

Quantifier: minimum repetitions, 0 for * and ?.

q_maxusize

Quantifier: maximum repetitions, where 0 means UNBOUNDED — the sentinel for *, + and {m,}. So q_max == 0 is not "match zero times"; {0,0} is not expressible here.

q_greedybool

Quantifier: greedy (a*) rather than lazy (a*?). Decides the order the compiler emits the two Split targets in, which is the whole of what greediness means to this engine.

group_indexusize

Group: the 1-based capture number. Backreference: the group number being referred back to.

anchorAnchorKind

Anchor: which assertion. Constructors leave it .Start for every other kind, so it is not a reliable "no anchor" signal — check kind.

impl(RegexNode, ...)
literal : (RegexNode) fn(cp : u32) -> RegexNode

A node matching exactly the code point cp.

Parameters

NameTypeNotes
cpu32

Returns: RegexNode

dot : (RegexNode) fn() -> RegexNode

A . 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) -> RegexNode

A [...] 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

NameTypeNotesDescription
rangesArrayList(CharRange)

CharClass: the inclusive code-point ranges the class accepts. Not required to be sorted or disjoint.

negatedbool

CharClass: [^...] — accept anything OUTSIDE ranges. Lookahead/Lookbehind: the assertion is NEGATIVE ((?!, (?<!).

Returns: RegexNode

anchor_node : (RegexNode) fn(kind : AnchorKind) -> RegexNode

A zero-width assertion node. Named anchor_node rather than anchor because the struct already has an anchor FIELD.

Parameters

NameTypeNotesDescription
kindAnchorKind

Which node this is. Every other field is only meaningful for the kinds NodeKind lists it under.

Returns: RegexNode

sequence : (RegexNode) fn(nodes : ArrayList(<struct:struct_decl_1053484_file____home_runner_work_Yo_Yo_std_regex_node_yo>)) -> RegexNode

A 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

NameTypeNotes
nodesArrayList(<struct:struct_decl_1053484_file____home_runner_work_Yo_Yo_std_regex_node_yo>)

Returns: RegexNode

alternation : (RegexNode) fn(left : RegexNode, right : RegexNode) -> RegexNode

A left|right node. Strictly binary: the parser folds a|b|c into nested alternations, and the compiler's Split lowering assumes exactly two children.

Parameters

NameTypeNotes
leftRegexNode
rightRegexNode

Returns: RegexNode

quantifier : (RegexNode) fn(child : RegexNode, min_val : usize, max_val : usize, greedy : bool) -> RegexNode

A 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

NameTypeNotes
childRegexNode
min_valusize
max_valusize
greedybool

Returns: RegexNode

group : (RegexNode) fn(child : RegexNode, index : usize) -> RegexNode

A 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

NameTypeNotesDescription
childRegexNode
indexusize

The 1-based capture-group number this name is an alias for, so named_group(n) and group(index) answer identically.

Returns: RegexNode

non_capturing_group : (RegexNode) fn(child : RegexNode) -> RegexNode

A (?:...) node — grouping for precedence only, consuming no capture number. Kept as a distinct kind rather than collapsed into its child so that a quantifier can wrap the group rather than the last atom in it.

Parameters

NameTypeNotes
childRegexNode

Returns: RegexNode

backreference : (RegexNode) fn(group_idx : usize) -> RegexNode

A \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

NameTypeNotes
group_idxusize

Returns: RegexNode

lookahead : (RegexNode) fn(child : RegexNode, positive : bool) -> RegexNode

A (?=...) (positive) or (?!...) (negative) node. positive is stored INVERTED, as the struct's negated field. Zero-width: the VM runs the child, keeps only the yes/no answer, and resumes where it started.

Parameters

NameTypeNotes
childRegexNode
positivebool

Returns: RegexNode

lookbehind : (RegexNode) fn(child : RegexNode, positive : bool) -> RegexNode

A (?<=...) (positive) or (?<!...) (negative) node — the same zero-width contract as lookahead, matched backwards from the current position. positive is stored inverted, as negated.

Parameters

NameTypeNotes
childRegexNode
positivebool

Returns: RegexNode

CharRange struct
CharRange

A range of characters for character classes, e.g. az.

Fields

NameTypeDescription
lowu32

First code point in the range, INCLUSIVE.

highu32

Last code point in the range, INCLUSIVE — so a single character is low == high, not an empty range.

GroupNameEntry

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

NameTypeDescription
nameString

The name as written, without the angle brackets. Compared for exact equality, case-sensitively.

indexusize

The 1-based capture-group number this name is an alias for, so named_group(n) and group(index) answer identically.