Skip to main content

Composing Patterns

Build complex patterns from reusable parts using >> (sequence), | (choice), and * (repeat).

PrerequisitesPattern Cookbook, DSL Reference
Operators>> sequence, `

Recipe 1: Sequence -- Setup then payoff

Chain two patterns with >>. The sharing clause forces ?char to bind the same node across both sub-patterns.

Loading playground...

Result: 1 match -- Alice promised then fulfilled. Bob promised but never fulfilled, so promise_kept does not fire for him. Without sharing(char), the two stages would be independent and any promise followed by any fulfillment would match.


Recipe 2: Choice -- Alternative resolutions

| creates a mutual-exclusion group. When one alternative completes, the engine kills active partial matches for the others. Each alternative becomes a separate pattern with a shared group name.

Loading playground...

Result: 2 matches -- crisis_famine for Westeros, crisis_war for Essos. The generated pattern names are crisis_war, crisis_famine, crisis_plague (group name + underscore + original name). All three share the exclusive group "crisis", so in incremental mode, once one fires for a given partial match, the others are killed.


Recipe 3: Exact repeat -- Three strikes

* N unrolls the pattern N times in sequence. Shared variables bind across all repetitions -- the same offender must commit all three offenses.

Loading playground...

Result: 1 match for Alice (three offenses). Bob has only one, so the pattern does not complete for him. The composed pattern has 3 stages with anchors rep0_e, rep1_e, rep2_e -- each repetition's non-shared variables get a repN_ prefix to prevent collisions.


Recipe 4: Repeat range -- Brute force (5-10 attempts)

* N..M uses repeat_range internally. The pattern completes at min repetitions and continues matching up to max. Use N.. for unbounded.

Loading playground...

Result: 1 match after 5 failures. The pattern will keep matching up to 10 total.

Variable bindings in range repeats:

BindingMeaning
first_eAnchor from the first iteration
last_eAnchor from the most recent iteration (updated on each new match)
accountShared variable -- same across all iterations
repetition_countNumber of matched repetitions (on the PartialMatch)

The first_ / last_ prefixes come from the two-copy layout: repeat_range generates a first_ copy and a last_ copy. The last_ stages loop, overwriting their bindings on each new repetition.


Recipe 5: Chaining compositions

A compose directive produces a named pattern. Use that name in subsequent compose directives to build deeper structures.

Loading playground...

Result: full_arc matches Alice's three-beat arc (promise, fulfill, reward). The intermediate setup_payoff also matches independently since it is registered as its own pattern.

When chaining, the second compose treats setup_payoff as a two-stage pattern. The >> appends aftermath's stage, producing a three-stage full_arc. Variable renaming applies at each level: full_arc has anchors a_a_e1, a_b_e2, b_e3 -- prefixes nest. The sharing(char) at each level keeps ?char unprefixed throughout.


How variable renaming works

Every compose renames non-shared variables to prevent collisions between sub-patterns:

OperatorPrefix scheme
A >> Ba_ for A's variables, b_ for B's
A * 3rep0_, rep1_, rep2_ per repetition
A * N..Mfirst_ for the initial copy, last_ for the looping copy
A | B | CNo renaming (each alternative is a separate pattern)

Variables listed in sharing(...) are exempt from renaming. Use sharing when the same entity must appear across sub-patterns (same character, same account, same region). Omit it when sub-patterns are independent.


Next steps