pub enum Pattern {
Show 16 variants
Empty,
Atom(Atom),
Bind(String, bool, Box<Pattern>),
Balanced(Option<BracketKind>, Box<Pattern>),
Guard(String, bool),
Assert(Box<Pattern>, bool, Look),
Anchor(AnchorKind),
Field(usize, Box<Pattern>),
Concat(Vec<Pattern>),
Alt(Vec<Pattern>, AltMode),
Star(Box<Pattern>, Greed),
Plus(Box<Pattern>, Greed),
Opt(Box<Pattern>, Greed),
Repeat(Box<Pattern>, usize, Option<usize>, Greed),
Atomic(Box<Pattern>),
Within(Vec<EditAtom>, u8),
}Expand description
A pattern node.
Variants§
Empty
Matches the empty token sequence.
Atom(Atom)
One token.
Bind(String, bool, Box<Pattern>)
P:name / P::name: match P and bind the matched span text to
name. The flag is scope: false (:name) binds for the rest of the
match; true (::name) is scoped to the enclosing balanced group, so
the binding is dropped when that group closes and a reference cannot
leak out of it.
Balanced(Option<BracketKind>, Box<Pattern>)
\B(P), \B[P], \B{P}, or bare \B: a balanced bracket
group whose interior matches P. None accepts any bracket
kind.
Guard(String, bool)
~"lit" / !~"lit": a zero-width assertion on lit in the
forward window. The flag is the negation: false asserts lit
occurs (~"lit"), true asserts it does not (!~"lit", a
negative lookahead that stays linear and ReDoS-free).
Assert(Box<Pattern>, bool, Look)
~(P) / !~(P) / ~<(P) / !~<(P): a zero-width assertion that P
matches at the current position, consuming nothing. The flag is the
negation. This is the sub-pattern generalisation of Self::Guard,
which asks only whether a literal occurs somewhere in the forward
window; the literal form is kept because a prefilter can answer it
without a positional scan.
Anchor(AnchorKind)
@seam (and future axis anchors): a zero-width assertion that the
current position sits at a boundary in a precomputed axis field. It
consumes no token; it filters the reachable set by position.
Field(usize, Box<Pattern>)
@k P: position at the k-th field, then match P.
Concat(Vec<Pattern>)
P Q ...: a sequence matched left to right.
Alt(Vec<Pattern>, AltMode)
P | Q ...: alternation, with the mode fixing how a branch is chosen.
Star(Box<Pattern>, Greed)
P* / P*?.
Plus(Box<Pattern>, Greed)
P+ / P+?.
Opt(Box<Pattern>, Greed)
P? / P??.
Repeat(Box<Pattern>, usize, Option<usize>, Greed)
P{m,n} / P{m,n}?; n is None for an open upper bound (P{m,}).
Atomic(Box<Pattern>)
(?>P), and the possessive quantifiers that expand to it: match P,
keep only the length P itself preferred, and never offer another.
In a backtracking engine this exists to stop catastrophic
backtracking. That reason does not apply here - neither engine
backtracks - so what is left is the meaning: (?>\W*) \W cannot
match, because the star takes every word and the atom is then offered
nothing, where \W* \W would hand back one.
It is a cut over lengths, as |> is a cut over branches, and it goes
to the same engine for the same reason: the single-pass engine’s
thread priority expresses a preference and has no way to discard the
alternatives it has already queued.
Within(Vec<EditAtom>, u8)
(A B C)~k: a run of tokens within k token edits of the atom
sequence, an edit being a token the run lacks, a token it has extra,
or a token that matches no atom in its place. The token-grain form of
Atom::LiteralWithin, which counts characters within one token.
Every run within k is offered, ranked by edit cost and then by
length, so what follows the group chooses among the alignments the
way it chooses among an alternation’s branches.
Implementations§
Source§impl Pattern
impl Pattern
Sourcepub fn boxed(self) -> Box<Pattern>
pub fn boxed(self) -> Box<Pattern>
Wrap a pattern in a box. Small helper to keep the parser terse.
Sourcepub fn reads_a_register(&self) -> bool
pub fn reads_a_register(&self) -> bool
Whether any atom reads a register back, as =name does.
This is what decides whether a binding can be erased without changing which spans match: a binding records what a match consumed and constrains nothing, so a pattern nothing reads back matches the same spans with every binding removed.
Sourcepub fn binds_anything(&self) -> bool
pub fn binds_anything(&self) -> bool
Whether the pattern binds anything at all.
Sourcepub fn without_bindings(&self) -> Option<Pattern>
pub fn without_bindings(&self) -> Option<Pattern>
The same pattern with every binding removed, or None where it binds
nothing or an atom reads a binding back.
The spans are the same, which is the whole of what a scan reports: the
routes are written against the shapes the language spells without
bindings, so \W:name "=" reaches the route \W "=" takes only once
its binding is off. A caller wanting the registers resolves them against
the original pattern over these spans.
Sourcepub fn starts_with_resume(&self) -> bool
pub fn starts_with_resume(&self) -> bool
Whether the pattern begins with \G, so its matches must form a
contiguous run rather than the leftmost non-overlapping selection.
Only the head position counts, and Pattern::resume_is_misplaced
rejects any other, so this is the whole of what the scan has to ask.
Sourcepub fn resume_is_misplaced(&self) -> bool
pub fn resume_is_misplaced(&self) -> bool
Whether \G appears anywhere it cannot mean anything: that is, at all
except the head of the pattern.
Sourcepub fn mentions_stream_end_anchor(&self) -> bool
pub fn mentions_stream_end_anchor(&self) -> bool
Whether an anchor reading the whole stream’s ends - \A or \z -
occurs anywhere in the pattern.
The two read whether any significant token precedes or follows the
one at hand, which a caller scanning a slice of the token stream
cannot answer: the slice’s first token looks like the input’s.
^ and $ are not here, reading the bytes either side of a token
rather than the stream, so a slice answers them as the whole does.
Sourcepub fn mentions_reset_start(&self) -> bool
pub fn mentions_reset_start(&self) -> bool
Whether \K occurs anywhere in the pattern.
Sourcepub fn contains_guard(&self) -> bool
pub fn contains_guard(&self) -> bool
Whether the pattern contains a content guard (~"lit") anywhere.
A guard’s forward window is unbounded, so a streaming or pipelined
scanner cannot finalize a match carrying one until the whole input
is seen.
Sourcepub fn contains_field(&self) -> bool
pub fn contains_field(&self) -> bool
Whether the pattern needs whole-input, non-droppable context: a field
anchor (@k, which counts commas from the input start) or a statistical
anchor (@seam, whose axis field is computed over the whole stream). In
either case a committed prefix cannot be dropped, so a streaming or
pipelined scanner must defer finalizing a match that carries one.
Sourcepub fn depends_on_whole_input(&self) -> bool
pub fn depends_on_whole_input(&self) -> bool
Whether a match’s outcome can depend on input outside its own span, so a chunked scanner must not commit it before the whole input is seen.
Three sources: a content guard reads an unbounded forward window; a field anchor counts commas from the input start; an axis atom or anchor reads a field computed over the whole stream, and truncating the input moves that reading. A new axis belongs in this predicate, which is the single place a chunked surface consults.
Sourcepub fn depends_on_more_than_its_lines(&self) -> bool
pub fn depends_on_more_than_its_lines(&self) -> bool
Whether a match’s outcome can depend on input beyond the lines it
spans, so a scanner that cuts its input only just after a newline
must not commit it before the whole input is seen:
Self::depends_on_whole_input less the line anchors, which read no
further than the newlines around the match, and less a lookbehind
that reads only tokens of the match itself.
Sourcepub fn looks_behind_its_match(&self) -> bool
pub fn looks_behind_its_match(&self) -> bool
Whether a lookbehind can read a token before its match’s start: one standing where the match may have taken fewer tokens than its sub-pattern can span, or one whose sub-pattern is unbounded.
Sourcepub fn min_tokens(&self) -> usize
pub fn min_tokens(&self) -> usize
The fewest tokens a match of the pattern can span. A lower bound: where the count is not known exactly it is too small, never too large, so a reader asking what a match has taken errs towards less.
Sourcepub fn reads_context_window(&self) -> bool
pub fn reads_context_window(&self) -> bool
Whether the pattern compares a token to the rolling window before it
(\N{>+1}), so the set engine folds the window field once per scan.
Whether the pattern reads a relation-admitted context or a phase
(\N{>+1:phase}, \N{>+1:k}, @phase:2), so the set engine builds
the related-context field once per scan.
Sourcepub fn context_uses(&self) -> ContextUses
pub fn context_uses(&self) -> ContextUses
Which contexts the pattern reads, so a scan builds each one’s inputs only when something asks for it.
Sourcepub fn reads_registers(&self) -> bool
pub fn reads_registers(&self) -> bool
Whether any atom in the pattern satisfies pred, class members
included.
Whether the pattern reads a register back, as =name and
=shape name do.
Distinct from Self::binds, which says only that a register is
written. A thread’s future depends on what it has bound only where
something reads it: with a back-reference, two threads at one counter
holding different bindings go on to match different tokens and are both
live. Without one, they match identically from here and the
higher-priority thread settles which captures are reported.
The engine’s thread list keys on this. Keying on a binding instead makes a pattern that only binds pay a hash of its whole save array per thread per step to keep threads apart that nothing can tell apart.
Sourcepub fn has_order(&self) -> bool
pub fn has_order(&self) -> bool
Whether the pattern orders timestamps against the one before them
(@order:asc / @order:desc), so the scan reads each timestamp once
and records which way it stands.
Sourcepub fn reads_whitespace(&self) -> bool
pub fn reads_whitespace(&self) -> bool
Whether the pattern reads a whitespace token itself (\S, or the
\s byte class), so a run of whitespace split at a cut would read
differently from the same run whole.
Sourcepub fn max_tokens(&self) -> Option<usize>
pub fn max_tokens(&self) -> Option<usize>
The most tokens a match of the pattern can span, or None when an
open repeat or a balanced group leaves it unbounded. A chunked
scanner commits a match of a bounded pattern once the input holds
that many tokens past the match’s start, since no alternative at
that start can reach further; an assertion consumes nothing, so it
spans nothing here, and the assertions that read past a match defer
every commit on their own.
Sourcepub fn takes_no_tokens(&self) -> bool
pub fn takes_no_tokens(&self) -> bool
Whether a match of the pattern can span no tokens at all.
The opening-kind route reads this. A pattern that can match nothing matches at every anchor, so it forces no opening kind; and inside a concatenation, a leading element that can take nothing leaves the match opening on whatever follows it, so the kinds it begins with are its own and the next element’s together.
Answering false for a pattern that can in fact take nothing is the
dangerous direction: the route would then refuse anchors where a
zero-width match begins. Every variant is matched rather than defaulted,
so a new one has to be decided rather than inheriting an answer.
Sourcepub fn has_rare(&self) -> bool
pub fn has_rare(&self) -> bool
Whether the pattern reads the rarity of a line’s template
(@shape:rare), so the scan mines the input’s templates once.
Sourcepub fn joins(&self) -> Vec<(Arc<OtherInput>, OrbitGroup)>
pub fn joins(&self) -> Vec<(Arc<OtherInput>, OrbitGroup)>
The second inputs the pattern’s join anchors read, each with the rung it is keyed at, once per distinct pair, so the scan keys each once.
Sourcepub fn widest_forward_window(&self) -> usize
pub fn widest_forward_window(&self) -> usize
The most significant tokens past a match’s own end that deciding the match can read, for the bounded assertions that read forward at all.
A ~>k(P) assertion tries P at each of k positions from where it
stands, and P itself can run on, so its reach is k plus P’s own
token length. Zero where the pattern has no such assertion.
A caller working from a prefix must hold this many tokens beyond a match before it can trust the verdict: reserving only the match’s own length leaves the assertion reading a stream the cut truncated, and that reports no match where the whole input has one.
~#{m,n}(P) reads to a closing bracket rather than a token count, so no
number here describes its reach and it contributes none. It is reported
by Self::has_assert instead, which declines the prefix outright.
Sourcepub fn has_assert(&self) -> bool
pub fn has_assert(&self) -> bool
Whether the pattern carries a zero-width sub-pattern assertion whose reach is not bounded. Such an assertion reads input outside the match span in either direction and as far as it needs to, so a chunked scanner cannot finalize a match carrying one.
A ~>k(P) assertion reads at most k significant tokens past the
position and is not counted here: its reach is part of the pattern, so
a scanner holding that many tokens beyond a match can finalize it.
~#{m,n}(P) is counted, because its reach is the enclosing bracket and
the input decides where that is. A cut falling inside the group leaves
the opening token with no mate, which reads as an empty region and a
count of zero - a verdict of no match on an input that has one.
Sourcepub fn reads_supertokens(&self) -> bool
pub fn reads_supertokens(&self) -> bool
Whether the pattern reads the supertoken tower, so a chunked scanner must not commit a match carrying it before the whole input is seen.
A unit is a run of tokens, so one cut by a chunk boundary is the same
hazard Self::depends_on_whole_input already declares for the other
whole-stream readings. This is covered there through
Self::contains_field, which answers true for every anchor rather
than enumerating them, and the test on this module pins that so the
coverage is not accidental.
Sourcepub fn has_seam(&self) -> bool
pub fn has_seam(&self) -> bool
Whether the pattern queries the seam axis (@seam) anywhere, so the
set engine builds the seam field once and threads it read-only.
Sourcepub fn has_seam_at(&self, grain: Grain) -> bool
pub fn has_seam_at(&self, grain: Grain) -> bool
Whether the pattern reads the seam axis at one particular grain, so only the streams a pattern names are segmented.
Sourcepub fn has_phase_in(&self) -> bool
pub fn has_phase_in(&self) -> bool
Whether any anchor counts a column against a named period
(@phase:k/p, @phase:k#n), so the live periods are read once.
Sourcepub fn has_gravity_at(&self, grain: Grain) -> bool
pub fn has_gravity_at(&self, grain: Grain) -> bool
Whether any anchor reads the pair field at grain (@strain,
@bound, @kin), so the field is learned only at the grains a
pattern names.
Sourcepub fn kin_examples(&self) -> Vec<(Grain, String)>
pub fn kin_examples(&self) -> Vec<(Grain, String)>
Every @kin anchor’s grain and example, each once, in the order met.
Sourcepub fn has_choice(&self) -> bool
pub fn has_choice(&self) -> bool
Whether this subtree makes a preference-bearing choice of its own: a leftmost-first alternation, or a quantifier.
A quantifier whose body answers false is fully described by how many
times it ran, so the set engine records one number for it. A body that
answers true made choices inside each iteration, and those have to be
comparable position by position against another derivation’s, so that
quantifier records one entry per iteration instead.
Sourcepub fn has_field_anchor(&self) -> bool
pub fn has_field_anchor(&self) -> bool
Whether the pattern carries a field anchor (@k), so the set engine
builds the per-token field index once. Narrower than
Self::contains_field, which also answers true for an axis anchor.
Sourcepub fn has_stress(&self) -> bool
pub fn has_stress(&self) -> bool
Whether the pattern queries the stress axis (@nested>k) anywhere, so
the set engine builds the stress field once and threads it read-only.
Sourcepub fn has_observation(&self) -> bool
pub fn has_observation(&self) -> bool
Whether the pattern queries the observation axis (@ambiguous)
anywhere, so the set engine builds the observation field once.
Sourcepub fn has_observation_at(&self, grain: Grain) -> bool
pub fn has_observation_at(&self, grain: Grain) -> bool
Whether the pattern reads the observation axis at one grain, so only the streams a pattern names are read.
Sourcepub fn has_echo(&self) -> bool
pub fn has_echo(&self) -> bool
Whether the pattern queries the echo axis (@novel / @echoed /
@echo...) anywhere, so the set engine builds the recurrence field.
Sourcepub fn echo_orbits(&self) -> Vec<OrbitGroup>
pub fn echo_orbits(&self) -> Vec<OrbitGroup>
The orbit rungs the pattern counts recurrence at, in the order they
first appear and each once. A scan builds one recurrence field per
rung; Identity is the rung @novel and @echoed read and the one
an @echo under no orbit scope reads.
Sourcepub fn has_super(&self) -> bool
pub fn has_super(&self) -> bool
Whether the pattern queries the supertoken tower (@super /
@super:role) anywhere, so the set engine builds the upper-grain
window once.
Sourcepub fn capture_names(&self) -> Vec<String>
pub fn capture_names(&self) -> Vec<String>
The capture names the pattern can bind (:name suffixes), in
first-seen order with duplicates removed. A rewrite template is
validated against this set so a reference to an unbound name is a
template error rather than a silent empty substitution.
Sourcepub fn nest_registers(&mut self, prefix: &str)
pub fn nest_registers(&mut self, prefix: &str)
Nest every register bound inside this pattern under prefix: each is
renamed prefix.name, and every reference to one of them inside the
pattern follows, so a back-reference, a typed relation, an edit
distance, a timestamp gap or a magnitude history keyed by the register
still reads it. A reference to a register bound outside is left as it
is.
Sourcepub fn list_registers(&self) -> Vec<String>
pub fn list_registers(&self) -> Vec<String>
The names bound under a repetition, in first-seen order: the registers that hold every binding a match made, in order, rather than the last.
Sourcepub fn has_list_registers(&self) -> bool
pub fn has_list_registers(&self) -> bool
Whether any register is bound under a repetition.
Sourcepub fn repetition_registers(&self) -> Vec<Vec<String>>
pub fn repetition_registers(&self) -> Vec<Vec<String>>
The registers bound inside each repetition, one list per repetition in the order they open, each in first-seen order; a repetition inside another gives its own list as well as adding to the outer’s.
Sourcepub fn capture_kinds(&self) -> Vec<(String, Option<TokenKind>)>
pub fn capture_kinds(&self) -> Vec<(String, Option<TokenKind>)>
The token kind each register binds, in the order
Pattern::capture_names reports, None where the register binds
anything but a single kind atom.
A register over a concatenation, an alternation or a repetition binds
text that may span several kinds, and there is no one typed value to
read from it, so it answers None rather than the first kind it
happens to contain. A magnitude or a predicate on the atom does not
change which kind it is, so those bind their kind like a bare one.
Sourcepub fn custom_kinds(&self) -> Vec<u8> ⓘ
pub fn custom_kinds(&self) -> Vec<u8> ⓘ
The ids of every declared or library kind the pattern names, each once, in order of first mention.
Sourcepub fn library_kinds(&self) -> Vec<u8> ⓘ
pub fn library_kinds(&self) -> Vec<u8> ⓘ
The ids of the shipped library’s kinds the pattern names, which a lex has to be told to produce.
Sourcepub fn has_byte_constraint(&self) -> bool
pub fn has_byte_constraint(&self) -> bool
Whether the pattern drops to the byte grain anywhere: a byte
pattern (`...`), a byte class (\d / \w / \s), or a
content guard (a byte-level forward-window assertion). This is the
sub-token byte constraint that the dual-grain split routes to the
byte grain.
Sourcepub fn has_spectral(&self) -> bool
pub fn has_spectral(&self) -> bool
Whether the pattern queries the spectral axis (\F{...}) anywhere.
Such a pattern routes to the set-reachability engine, which builds
the spectral field once and threads it read-only to the matcher.
Sourcepub fn spectral_needs(&self) -> Needs
pub fn spectral_needs(&self) -> Needs
The readings the pattern’s \F{...} atoms take, so a scan builds the
spectral field with those and no others.
The field is a step a byte over the whole input, so a reading nothing asks for is paid at every byte: an atom naming the entropy alone would otherwise also decay a filterbank, count a k-gram through a map and take a square root, at each of them.