Pattern matcher

koskari.matcher

The pattern matcher behind the special forms, the macros and the match special: the patterns and the special-form composites a shape is declared with, the parsers of the explicit and case-pattern dialects, and the functions that build and try matchers

class koskari.matcher.APP(extern_name, sub=None)

Bases: Pattern

Apply the named extern callable to a single source element and match the inner pattern against the call’s result. The extern is invoked through the demand path at match time, so a plain koskari callable works directly; a genuine async suspension raises KoskariSyncViolation, and a raising extractor propagates as an error, not a no-match

lower(ctx)

Intern the extern, emit the inner pattern, then an APP node

koskari.matcher.BIND(slot)

Capture any single element into the named slot

class koskari.matcher.BINDING(slot)

Bases: Composite

Capture a single binding-shaped cell, (NAME EXPR) or (EXPR as: NAME). After a successful match captures[slot] is a dict (the GROUP’s captures) or DatumFrame with name and expr as produced by binding_inner_pattern. For KosPair-backed subjects the whole binding cell spine is .source on DatumFrame

class koskari.matcher.BINDINGS(slot)

Bases: Composite

Capture a binding-list cell: a single element which is either nil or a proper list of binding-shaped cells. The nonempty arm uses repeat_capture so captures[slot] is a bare Python list of per-cell frame dicts (same keys as BINDING: name, expr), not Datum-wrapped; the empty arm matches nil and binds captures[slot] = nil (a Datum in the usual CAPTURE sense). The two arms share an outer slot name through ONEOF’s per-branch capture scoping

class koskari.matcher.BODY(slot)

Bases: Pattern

Remainder capture of a slot holding the forms a body evaluates. Lowers to the same REST node as REST(slot, min_tail=1) (minimum one spine cell in the body tail); the spelling records the slot’s role

lower(ctx)

Emit REST with min_tail=1

class koskari.matcher.CALLEDBY(slot=None)

Bases: Composite

Capture the compile-head symbol into the called-by slot

class koskari.matcher.CAPTURE(slot, sub=None)

Bases: Pattern

Bind one matched element (or a sub-pattern result) into a named slot

lower(ctx)

Reserve the slot, lower the optional sub-pattern, and emit the CAPTURE node

class koskari.matcher.CLASS(type_extern, *fields)

Bases: Pattern

Match a single element which is an instance of the named extern type. Field children project named or positional attributes through sub-patterns

lower(ctx)

Emit each FIELD child then a CLASS node referencing them. Toggles ctx.in_class_fields so that nested CLASS/FIELD trees validate correctly. The CLASS extern is interned before recursing into fields so that the externs tuple reflects source declaration order

class koskari.matcher.DECL(slot)

Bases: Composite

Capture one element shaped as a declaration: a bare symbol, a one-element list naming the symbol, the (type as: name) form, or a (name . tail) form where tail captures the keyword attribute pairs verbatim. After a successful match captures[slot] is a dict (the GROUP’s captures) or DatumFrame for KosPair-backed subjects. Keys include name where applicable, type from the as-form, decl_tail from the dotted tail arm; other keys are omitted. The whole declaration cell spine is available as .source on DatumFrame results (not a dict key)

class koskari.matcher.DEFINE(slot)

Bases: Composite

Capture one element constrained to be a symbol. Used as the introduced-name slot for define-shaped specials

class koskari.matcher.FIELD(sub, *, name=None)

Bases: Pattern

Project a single attribute of a CLASS instance through an inner pattern. Positional when name is None, keyword otherwise

lower(ctx)

Emit a FIELD_POS or FIELD_KW node. Rejects emission outside a CLASS scope. Temporarily clears in_class_fields so that the sub-pattern can host its own CLASS/FIELD nesting

class koskari.matcher.FORM(sub)

Bases: Pattern

Descend into a single source element treated as a pair-tree and apply the inner pattern against its contents

lower(ctx)

Emit the inner pattern then a FORM node referencing it

class koskari.matcher.FORMALS(slot)

Bases: Composite

Capture one element shaped as a proper-list formals cell and decompose its structure into a nested capture dict. Improper-list formals are rejected because koskari does not allow them as a function-formals shape. After a successful match captures[slot] is a dict (the GROUP’s captures) or DatumFrame whose keys include:

  • ‘positionals’: bare Python list of frame dicts (one per positional formal)

  • ‘defaults’: bare Python list of frame dicts (one per default keyword/value)

  • ‘star’: the symbol after *: (or nil for the *: nil marker)

  • ‘kwonly’: bare Python list of frame dicts (one per kw-only entry)

  • ‘starstar’: the symbol after **:

Inner keys for phases that did not run are omitted from the group dict. For KosPair-backed subjects the whole formals list spine is .source on DatumFrame. Use one FORMALS per matcher

class koskari.matcher.GROUP(slot, *children)

Bases: Pattern

Nested capture frame: inner captures go into a sub-dict. The GROUP node has no slot; when slot is a non-empty str this pattern lowers to CAPTURE(slot, GROUP(children...)) so naming stays on CAPTURE only. When slot is None the sub-dict is matched and then discarded unless a parent CAPTURE or REPEAT row collects it

lower(ctx)

Emit a slot-free GROUP node; when named, wrap with CAPTURE so the slot is claimed only on the outer CAPTURE

koskari.matcher.KEYWORD(slot)

Capture a keyword element into the named slot; keyword is a core type, tested with no extern

koskari.matcher.LIST(*specs, key=None)

Match a single source element which is a list whose contents satisfy the given specs in order. When key is given the matched sub-list is also captured into that slot

class koskari.matcher.LITERAL(value)

Bases: Pattern

Match a single element equal to the given literal value

lower(ctx)

Intern the literal in consts and emit a TEST/LITERAL node

koskari.matcher.LITERAL_KW(s)

Match a keyword equal to keyword(s)

koskari.matcher.LITERAL_SYM(s)

Match a symbol equal to symbol(s)

class koskari.matcher.MAP(*entries)

Bases: Pattern

Match a single element as a mapping (dict or collections.abc Mapping): every entry’s key must be present with a value matching the entry’s sub-pattern. Extra keys are ignored, per PEP 634 mapping-pattern semantics

lower(ctx)

Emit each entry then a MAP node chaining them

class koskari.matcher.MAP_ENTRY(key, sub=None, extern=False)

Bases: object

One mapping-pattern entry: a key plus an optional sub-pattern for the looked-up value. The key is a literal constant, or – when extern is true – an extern name resolved from the namespace at match time (the same channel as TYPE / CLASS names). Not a Pattern: only meaningful as a child of MAP

lower(ctx)

Intern the key, emit the sub-pattern, then a MAP_ENTRY node

class koskari.matcher.MATCH(*children)

Bases: Pattern

Sequential spine: match children in order in the current capture dict

lower(ctx)

Emit each child then a MATCH node listing them in order

class koskari.matcher.NOT(sub)

Bases: Pattern

Negative lookahead: succeed when the inner pattern does not match the current single element. Width 1 with no captures inside

lower(ctx)

Emit the inner pattern then a NOT node referencing it

class koskari.matcher.ONEOF(*branches)

Bases: Pattern

Disjunction: try each branch in order until one matches

lower(ctx)

Emit each branch then a ONEOF node listing them in order. Each branch gets its own capture scope so identical slot names across mutually exclusive arms remain valid

class koskari.matcher.OPTIONAL(sub)

Bases: Pattern

Match the inner pattern at most once. When the inner pattern does not match, any capture slots it would have bound are omitted from the result captures dict

lower(ctx)

Emit the inner pattern then an OPTIONAL node referencing it

koskari.matcher.PAIR(slot)

Capture a pair element into the named slot; pair is a core type, tested with no extern

class koskari.matcher.PREDICATE(extern_name)

Bases: Pattern

Match a single element for which the named extern callable returns a truthy value

lower(ctx)

Intern the extern and emit a TEST/PREDICATE node

class koskari.matcher.Pattern(*args, **kwargs)

Bases: Protocol

Structural base for matcher pattern builders. Implementations define lower(ctx); the compiler passes itself as ctx when lowering a root pattern. GROUP and ONEOF bracket nested lowering with begin_nested_claims and end_nested_claims. build lowers through TableBuilder and compiles the matcher function

build(externs=None)

Compile this pattern to its matcher function: one positional formal, the subject; the captures on a match, None on a miss. Its externs are closure names resolved in a namespace whose builtins are the externs mapping

Parameters:

externs – the extern names mapped to their values, or None

Raises:
  • TypeError – when a LITERAL value or a MAP entry key is not one the constant pool holds, or an extern the pattern declares is not given

  • ValueError – when the pattern is one the core refuses

Return type:

Function

lower(ctx)

Append nodes for this pattern into the compiler context and return the index of the resulting top node

class koskari.matcher.REPEAT(sub, min_count=0)

Bases: Pattern

Greedily match the inner pattern repeatedly; require at least min_count successful iterations (default 0: Kleene star)

lower(ctx)

Emit the inner pattern then a REPEAT node referencing it

class koskari.matcher.REST(slot=None, min_tail=0)

Bases: Pattern

Consume the remainder of the current spine subject. min_tail is the minimum number of spine cells this REST must take (default 0). When slot is set, lowering emits CAPTURE(slot, REST(...)) so only CAPTURE carries the slot

lower(ctx)

Emit REST with min_tail only; when named, wrap with CAPTURE

class koskari.matcher.SAME(slot, depth=0)

Bases: Pattern

Match one element equal to an earlier capture of this frame: the root, or the GROUP or REPEAT iteration the SAME sits in, at depth 0; the enclosing frame at depth 1

lower(ctx)

Emit a SAME node referencing an existing slot index

koskari.matcher.SYMBOL(slot)

Capture a symbol element into the named slot; symbol is a core type, tested with no extern

class koskari.matcher.TEST_ANY

Bases: Pattern

Match any single element

lower(ctx)

Emit the TEST_ANY node tuple

class koskari.matcher.TYPE(extern_name)

Bases: Pattern

Match a single element which is an instance of the named type: a core type by its ordinal, any other name as an extern, a variable of the code the pattern runs in

lower(ctx)

Emit a TEST/CORE node for a core type, else intern the extern and emit a TEST/TYPE node

class koskari.matcher.USING(slot)

Bases: Composite

Capture one element shaped as a using-form. Four inner shapes are recognised through an ordered ONEOF; first match wins:

  1. (EXPR as: NAME) – as form, captures expr and name

  2. ((PATTERN…) EXPR) – unpack form, captures lhs and expr

  3. (NAME EXPR) – named binding, captures name and expr

  4. (EXPR) – bare expression, captures expr only

The as form comes first: a two-element shape is committed to once it matches, and the as form’s three elements skip it on a two-element cell

After a successful match captures[slot] is a dict (the GROUP’s captures) or DatumFrame with whichever of lhs, name, expr the winning arm binds. For KosPair-backed subjects the whole cell spine is .source on DatumFrame

class koskari.matcher.USING_UNPACK(slot)

Bases: Composite

Capture ((PATTERN...) EXPR) for unpack bindings (e.g. for-each). After a successful match captures[slot] is a dict (the GROUP’s captures) or DatumFrame with lhs and expr. For KosPair-backed subjects the whole cell spine is .source on DatumFrame

class koskari.matcher.VALUE(slot)

Bases: Pattern

Single-element capture of a slot holding an expression the form evaluates. Lowers to the same CAPTURE node as BIND(slot); the spelling records the slot’s role

lower(ctx)

Emit CAPTURE

koskari.matcher.check_pattern_arg(arg, what)

Validate that arg is a Pattern instance and raise a clear TypeError when it is not

koskari.matcher.first_match(subject, callables)
koskari.matcher.frame_formal_name(fr)

Resolve one positional formal frame to (name, by_ref).

The binding symbol lives under ‘ref_name’ for the (ref x) and (ref x) by-ref shapes. Otherwise it lives under ‘name’; a ‘name’ carrying a leading & is the reader-disabled by-ref fallback and is stripped. A keyword-headed cell such as (y: 1 :: int) names the parameter under ‘kw’ and the symbol that keyword spells is returned; a leading & on the keyword marks it by-ref. The returned name is the raw symbol (Datum-unwrapped) or None

koskari.matcher.make_matcher(pattern, externs=None)

Compile a pattern AST to its matcher function, as Pattern.build() does

Parameters:
  • pattern – a matcher pattern object

  • externs – the extern names mapped to their values, or None

Raises:

TypeError – when pattern is not a matcher pattern

Return type:

Function

koskari.matcher.parse_case_pattern(content)

Lower the content of one match/case clause delimiter to a matcher pattern object. The delimiter ([[PATTERN] BODY…]) holds either a single pattern form, or the multi-token spelling of a marked typed pattern (x :: int); a bare multi-token content is an error – it is never a silent sequence

Parameters:

content – the delimiter list (pair-tree)

Return type:

Pattern

koskari.matcher.parse_explicit_rule_pattern(form, source_ctx=None)

Lower MATCH-dialect pattern source (a cons tree) to a matcher Pattern.

Distinct from parse_matcher(), which lowers a single META element. This walks a rule-level spine: either a registered declaration (HEAD slot . opts) when HEAD is in MATCHER_REGISTRY and slot is a symbol, or a sequential MATCH of per-cell patterns.

Parameters:
  • form – koskari pattern datum

  • source_ctx – optional value appended to error messages

Returns:

Pattern instance (often MATCH wrapping a sequence)

Raises:

ValueError – on ellipsis, improper lists, empty cells, or factory failures

koskari.matcher.pattern_slot_names(pattern)

Top-level macro lambda formals for pattern in declaration order

Slots nested inside anonymous GROUP / REPEAT row frames are omitted; ONEOF branch captures and spine MATCH slots are included

koskari.matcher.repeat_capture(slot, inner)

Capture the results of repeating inner across successive subject elements. captures[slot] is a Python list: each element is one iteration result (often a dict for a GROUP row dict, or a sparse change dict / Datum when inner does not use that shape)

Parameters:
  • slot – outer slot receiving the list of per-iteration values

  • inner – pattern run once per repetition (often FORM around a MATCH of captures)

Return type:

CAPTURE