@bcts/envelope-pattern 1.0.0-alpha.16 → 1.0.0-alpha.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +1 -1
  2. package/dist/index.cjs +1992 -1714
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +147 -31
  5. package/dist/index.d.cts.map +1 -1
  6. package/dist/index.d.mts +147 -31
  7. package/dist/index.d.mts.map +1 -1
  8. package/dist/index.iife.js +1984 -1707
  9. package/dist/index.iife.js.map +1 -1
  10. package/dist/index.mjs +1966 -1698
  11. package/dist/index.mjs.map +1 -1
  12. package/package.json +9 -9
  13. package/src/format.ts +32 -13
  14. package/src/parse/index.ts +138 -5
  15. package/src/parse/token.ts +59 -58
  16. package/src/pattern/index.ts +110 -2
  17. package/src/pattern/leaf/array-pattern.ts +26 -26
  18. package/src/pattern/leaf/bool-pattern.ts +12 -12
  19. package/src/pattern/leaf/byte-string-pattern.ts +15 -15
  20. package/src/pattern/leaf/cbor-pattern.ts +31 -31
  21. package/src/pattern/leaf/date-pattern.ts +9 -9
  22. package/src/pattern/leaf/index.ts +1 -2
  23. package/src/pattern/leaf/known-value-pattern.ts +21 -20
  24. package/src/pattern/leaf/map-pattern.ts +14 -14
  25. package/src/pattern/leaf/null-pattern.ts +8 -8
  26. package/src/pattern/leaf/number-pattern.ts +20 -20
  27. package/src/pattern/leaf/tagged-pattern.ts +20 -20
  28. package/src/pattern/leaf/text-pattern.ts +14 -14
  29. package/src/pattern/matcher.ts +88 -3
  30. package/src/pattern/meta/and-pattern.ts +19 -18
  31. package/src/pattern/meta/capture-pattern.ts +16 -17
  32. package/src/pattern/meta/group-pattern.ts +20 -17
  33. package/src/pattern/meta/not-pattern.ts +9 -8
  34. package/src/pattern/meta/or-pattern.ts +30 -25
  35. package/src/pattern/meta/search-pattern.ts +17 -17
  36. package/src/pattern/meta/traverse-pattern.ts +42 -18
  37. package/src/pattern/structure/assertions-pattern.ts +31 -32
  38. package/src/pattern/structure/digest-pattern.ts +23 -23
  39. package/src/pattern/structure/index.ts +1 -0
  40. package/src/pattern/structure/node-pattern.ts +17 -17
  41. package/src/pattern/structure/object-pattern.ts +14 -15
  42. package/src/pattern/structure/obscured-pattern.ts +7 -7
  43. package/src/pattern/structure/predicate-pattern.ts +14 -15
  44. package/src/pattern/structure/subject-pattern.ts +16 -17
  45. package/src/pattern/structure/wrapped-pattern.ts +40 -19
  46. package/src/pattern/vm.ts +12 -11
@@ -88,14 +88,23 @@ export function compileAsAtomic(
88
88
  }
89
89
 
90
90
  // ============================================================================
91
- // Pattern Match Registry
91
+ // Pattern Dispatch Registry
92
92
  // ============================================================================
93
93
 
94
94
  /**
95
- * Registry for pattern matching function to break circular dependencies.
96
- * This allows meta patterns to match child patterns without importing from index.ts.
95
+ * Registry for pattern dispatch functions to break circular dependencies.
96
+ * This allows meta patterns to dispatch to child patterns without importing from index.ts.
97
97
  */
98
98
  let patternMatchFn: ((pattern: Pattern, haystack: Envelope) => boolean) | undefined;
99
+ let patternPathsWithCapturesFn:
100
+ | ((pattern: Pattern, haystack: Envelope) => [Path[], Map<string, Path[]>])
101
+ | undefined;
102
+ let patternPathsFn: ((pattern: Pattern, haystack: Envelope) => Path[]) | undefined;
103
+ let patternCompileFn:
104
+ | ((pattern: Pattern, code: Instr[], literals: Pattern[], captures: string[]) => void)
105
+ | undefined;
106
+ let patternIsComplexFn: ((pattern: Pattern) => boolean) | undefined;
107
+ let patternToStringFn: ((pattern: Pattern) => string) | undefined;
99
108
 
100
109
  /**
101
110
  * Registers the pattern match function.
@@ -107,6 +116,24 @@ export function registerPatternMatchFn(
107
116
  patternMatchFn = fn;
108
117
  }
109
118
 
119
+ /**
120
+ * Registers all pattern dispatch functions.
121
+ * Called from index.ts after all patterns are defined.
122
+ */
123
+ export function registerPatternDispatchFns(fns: {
124
+ pathsWithCaptures: (pattern: Pattern, haystack: Envelope) => [Path[], Map<string, Path[]>];
125
+ paths: (pattern: Pattern, haystack: Envelope) => Path[];
126
+ compile: (pattern: Pattern, code: Instr[], literals: Pattern[], captures: string[]) => void;
127
+ isComplex: (pattern: Pattern) => boolean;
128
+ toString: (pattern: Pattern) => string;
129
+ }): void {
130
+ patternPathsWithCapturesFn = fns.pathsWithCaptures;
131
+ patternPathsFn = fns.paths;
132
+ patternCompileFn = fns.compile;
133
+ patternIsComplexFn = fns.isComplex;
134
+ patternToStringFn = fns.toString;
135
+ }
136
+
110
137
  /**
111
138
  * Match a pattern against an envelope using the registered match function.
112
139
  * Used by meta patterns to match child patterns.
@@ -117,3 +144,61 @@ export function matchPattern(pattern: Pattern, haystack: Envelope): boolean {
117
144
  }
118
145
  return patternMatchFn(pattern, haystack);
119
146
  }
147
+
148
+ /**
149
+ * Dispatch pathsWithCaptures on a Pattern.
150
+ */
151
+ export function dispatchPathsWithCaptures(
152
+ pattern: Pattern,
153
+ haystack: Envelope,
154
+ ): [Path[], Map<string, Path[]>] {
155
+ if (patternPathsWithCapturesFn === undefined) {
156
+ throw new Error("Pattern dispatch functions not registered");
157
+ }
158
+ return patternPathsWithCapturesFn(pattern, haystack);
159
+ }
160
+
161
+ /**
162
+ * Dispatch paths on a Pattern.
163
+ */
164
+ export function dispatchPaths(pattern: Pattern, haystack: Envelope): Path[] {
165
+ if (patternPathsFn === undefined) {
166
+ throw new Error("Pattern dispatch functions not registered");
167
+ }
168
+ return patternPathsFn(pattern, haystack);
169
+ }
170
+
171
+ /**
172
+ * Dispatch compile on a Pattern.
173
+ */
174
+ export function dispatchCompile(
175
+ pattern: Pattern,
176
+ code: Instr[],
177
+ literals: Pattern[],
178
+ captures: string[],
179
+ ): void {
180
+ if (patternCompileFn === undefined) {
181
+ throw new Error("Pattern dispatch functions not registered");
182
+ }
183
+ patternCompileFn(pattern, code, literals, captures);
184
+ }
185
+
186
+ /**
187
+ * Dispatch isComplex on a Pattern.
188
+ */
189
+ export function dispatchIsComplex(pattern: Pattern): boolean {
190
+ if (patternIsComplexFn === undefined) {
191
+ throw new Error("Pattern dispatch functions not registered");
192
+ }
193
+ return patternIsComplexFn(pattern);
194
+ }
195
+
196
+ /**
197
+ * Dispatch toString on a Pattern.
198
+ */
199
+ export function dispatchPatternToString(pattern: Pattern): string {
200
+ if (patternToStringFn === undefined) {
201
+ throw new Error("Pattern dispatch functions not registered");
202
+ }
203
+ return patternToStringFn(pattern);
204
+ }
@@ -8,9 +8,15 @@
8
8
 
9
9
  import type { Envelope } from "@bcts/envelope";
10
10
  import type { Path } from "../../format";
11
- import { type Matcher, matchPattern } from "../matcher";
11
+ import {
12
+ matchPattern,
13
+ dispatchCompile,
14
+ dispatchIsComplex,
15
+ dispatchPatternToString,
16
+ } from "../matcher";
12
17
  import type { Instr } from "../vm";
13
18
  import type { Pattern } from "../index";
19
+ import type { Matcher } from "../matcher";
14
20
 
15
21
  // Forward declaration for Pattern factory (used for late binding)
16
22
  export let createMetaAndPattern: ((pattern: AndPattern) => Pattern) | undefined;
@@ -25,10 +31,10 @@ export function registerAndPatternFactory(factory: (pattern: AndPattern) => Patt
25
31
  * Corresponds to the Rust `AndPattern` struct in and_pattern.rs
26
32
  */
27
33
  export class AndPattern implements Matcher {
28
- readonly #patterns: Pattern[];
34
+ private readonly _patterns: Pattern[];
29
35
 
30
36
  private constructor(patterns: Pattern[]) {
31
- this.#patterns = patterns;
37
+ this._patterns = patterns;
32
38
  }
33
39
 
34
40
  /**
@@ -42,11 +48,11 @@ export class AndPattern implements Matcher {
42
48
  * Gets the patterns.
43
49
  */
44
50
  patterns(): Pattern[] {
45
- return this.#patterns;
51
+ return this._patterns;
46
52
  }
47
53
 
48
54
  pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
49
- const allMatch = this.#patterns.every((pattern) => matchPattern(pattern, haystack));
55
+ const allMatch = this._patterns.every((pattern) => matchPattern(pattern, haystack));
50
56
 
51
57
  const paths = allMatch ? [[haystack]] : [];
52
58
  return [paths, new Map<string, Path[]>()];
@@ -62,35 +68,30 @@ export class AndPattern implements Matcher {
62
68
 
63
69
  compile(code: Instr[], literals: Pattern[], captures: string[]): void {
64
70
  // Each pattern must match at this position
65
- for (const pattern of this.#patterns) {
66
- const matcher = pattern as unknown as Matcher;
67
- matcher.compile(code, literals, captures);
71
+ for (const pattern of this._patterns) {
72
+ dispatchCompile(pattern, code, literals, captures);
68
73
  }
69
74
  }
70
75
 
71
76
  isComplex(): boolean {
72
77
  // The pattern is complex if it contains more than one pattern, or if
73
78
  // the one pattern is complex itself.
74
- return (
75
- this.#patterns.length > 1 || this.#patterns.some((p) => (p as unknown as Matcher).isComplex())
76
- );
79
+ return this._patterns.length > 1 || this._patterns.some((p) => dispatchIsComplex(p));
77
80
  }
78
81
 
79
82
  toString(): string {
80
- return this.#patterns
81
- .map((p) => (p as unknown as { toString(): string }).toString())
82
- .join(" & ");
83
+ return this._patterns.map((p) => dispatchPatternToString(p)).join(" & ");
83
84
  }
84
85
 
85
86
  /**
86
87
  * Equality comparison.
87
88
  */
88
89
  equals(other: AndPattern): boolean {
89
- if (this.#patterns.length !== other.#patterns.length) {
90
+ if (this._patterns.length !== other._patterns.length) {
90
91
  return false;
91
92
  }
92
- for (let i = 0; i < this.#patterns.length; i++) {
93
- if (this.#patterns[i] !== other.#patterns[i]) {
93
+ for (let i = 0; i < this._patterns.length; i++) {
94
+ if (this._patterns[i] !== other._patterns[i]) {
94
95
  return false;
95
96
  }
96
97
  }
@@ -101,6 +102,6 @@ export class AndPattern implements Matcher {
101
102
  * Hash code for use in Maps/Sets.
102
103
  */
103
104
  hashCode(): number {
104
- return this.#patterns.length;
105
+ return this._patterns.length;
105
106
  }
106
107
  }
@@ -8,9 +8,10 @@
8
8
 
9
9
  import type { Envelope } from "@bcts/envelope";
10
10
  import type { Path } from "../../format";
11
- import type { Matcher } from "../matcher";
11
+ import { dispatchPathsWithCaptures, dispatchCompile, dispatchPatternToString } from "../matcher";
12
12
  import type { Instr } from "../vm";
13
13
  import type { Pattern } from "../index";
14
+ import type { Matcher } from "../matcher";
14
15
 
15
16
  // Forward declaration for Pattern factory (used for late binding)
16
17
  export let createMetaCapturePattern: ((pattern: CapturePattern) => Pattern) | undefined;
@@ -25,12 +26,12 @@ export function registerCapturePatternFactory(factory: (pattern: CapturePattern)
25
26
  * Corresponds to the Rust `CapturePattern` struct in capture_pattern.rs
26
27
  */
27
28
  export class CapturePattern implements Matcher {
28
- readonly #name: string;
29
- readonly #pattern: Pattern;
29
+ private readonly _name: string;
30
+ private readonly _pattern: Pattern;
30
31
 
31
32
  private constructor(name: string, pattern: Pattern) {
32
- this.#name = name;
33
- this.#pattern = pattern;
33
+ this._name = name;
34
+ this._pattern = pattern;
34
35
  }
35
36
 
36
37
  /**
@@ -44,23 +45,22 @@ export class CapturePattern implements Matcher {
44
45
  * Gets the name of the capture.
45
46
  */
46
47
  name(): string {
47
- return this.#name;
48
+ return this._name;
48
49
  }
49
50
 
50
51
  /**
51
52
  * Gets the inner pattern.
52
53
  */
53
54
  pattern(): Pattern {
54
- return this.#pattern;
55
+ return this._pattern;
55
56
  }
56
57
 
57
58
  pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
58
- const matcher = this.#pattern as unknown as Matcher;
59
- const [paths, caps] = matcher.pathsWithCaptures(haystack);
59
+ const [paths, caps] = dispatchPathsWithCaptures(this._pattern, haystack);
60
60
 
61
61
  if (paths.length > 0) {
62
- const existing = caps.get(this.#name) ?? [];
63
- caps.set(this.#name, [...existing, ...paths]);
62
+ const existing = caps.get(this._name) ?? [];
63
+ caps.set(this._name, [...existing, ...paths]);
64
64
  }
65
65
 
66
66
  return [paths, caps];
@@ -76,10 +76,9 @@ export class CapturePattern implements Matcher {
76
76
 
77
77
  compile(code: Instr[], literals: Pattern[], captures: string[]): void {
78
78
  const id = captures.length;
79
- captures.push(this.#name);
79
+ captures.push(this._name);
80
80
  code.push({ type: "CaptureStart", captureIndex: id });
81
- const matcher = this.#pattern as unknown as Matcher;
82
- matcher.compile(code, literals, captures);
81
+ dispatchCompile(this._pattern, code, literals, captures);
83
82
  code.push({ type: "CaptureEnd", captureIndex: id });
84
83
  }
85
84
 
@@ -88,14 +87,14 @@ export class CapturePattern implements Matcher {
88
87
  }
89
88
 
90
89
  toString(): string {
91
- return `@${this.#name}(${(this.#pattern as unknown as { toString(): string }).toString()})`;
90
+ return `@${this._name}(${dispatchPatternToString(this._pattern)})`;
92
91
  }
93
92
 
94
93
  /**
95
94
  * Equality comparison.
96
95
  */
97
96
  equals(other: CapturePattern): boolean {
98
- return this.#name === other.#name && this.#pattern === other.#pattern;
97
+ return this._name === other._name && this._pattern === other._pattern;
99
98
  }
100
99
 
101
100
  /**
@@ -103,7 +102,7 @@ export class CapturePattern implements Matcher {
103
102
  */
104
103
  hashCode(): number {
105
104
  let hash = 0;
106
- for (const char of this.#name) {
105
+ for (const char of this._name) {
107
106
  hash = (hash * 31 + char.charCodeAt(0)) | 0;
108
107
  }
109
108
  return hash;
@@ -9,9 +9,10 @@
9
9
  import type { Envelope } from "@bcts/envelope";
10
10
  import { Quantifier } from "@bcts/dcbor-pattern";
11
11
  import type { Path } from "../../format";
12
- import type { Matcher } from "../matcher";
12
+ import { matchPattern, dispatchPathsWithCaptures, dispatchPatternToString } from "../matcher";
13
13
  import type { Instr } from "../vm";
14
14
  import type { Pattern } from "../index";
15
+ import type { Matcher } from "../matcher";
15
16
 
16
17
  // Forward declaration for Pattern factory (used for late binding)
17
18
  export let createMetaGroupPattern: ((pattern: GroupPattern) => Pattern) | undefined;
@@ -26,12 +27,12 @@ export function registerGroupPatternFactory(factory: (pattern: GroupPattern) =>
26
27
  * Corresponds to the Rust `GroupPattern` struct in repeat_pattern.rs
27
28
  */
28
29
  export class GroupPattern implements Matcher {
29
- readonly #pattern: Pattern;
30
- readonly #quantifier: Quantifier;
30
+ private readonly _pattern: Pattern;
31
+ private readonly _quantifier: Quantifier;
31
32
 
32
33
  private constructor(pattern: Pattern, quantifier: Quantifier) {
33
- this.#pattern = pattern;
34
- this.#quantifier = quantifier;
34
+ this._pattern = pattern;
35
+ this._quantifier = quantifier;
35
36
  }
36
37
 
37
38
  /**
@@ -52,17 +53,21 @@ export class GroupPattern implements Matcher {
52
53
  * Gets the sub-pattern of this group pattern.
53
54
  */
54
55
  pattern(): Pattern {
55
- return this.#pattern;
56
+ return this._pattern;
56
57
  }
57
58
 
58
59
  /**
59
60
  * Gets the quantifier of this group pattern.
60
61
  */
61
62
  quantifier(): Quantifier {
62
- return this.#quantifier;
63
+ return this._quantifier;
63
64
  }
64
65
 
65
- pathsWithCaptures(_haystack: Envelope): [Path[], Map<string, Path[]>] {
66
+ pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
67
+ // For simple grouping (exactly 1), delegate to the inner pattern
68
+ if (this._quantifier.min() === 1 && this._quantifier.max() === 1) {
69
+ return dispatchPathsWithCaptures(this._pattern, haystack);
70
+ }
66
71
  throw new Error(
67
72
  "GroupPattern does not support pathsWithCaptures directly; use compile instead",
68
73
  );
@@ -73,15 +78,13 @@ export class GroupPattern implements Matcher {
73
78
  }
74
79
 
75
80
  matches(haystack: Envelope): boolean {
76
- // GroupPattern needs VM execution
77
- const matcher = this.#pattern as unknown as Matcher;
78
- return matcher.matches(haystack);
81
+ return matchPattern(this._pattern, haystack);
79
82
  }
80
83
 
81
84
  compile(code: Instr[], literals: Pattern[], _captures: string[]): void {
82
85
  const idx = literals.length;
83
- literals.push(this.#pattern);
84
- code.push({ type: "Repeat", patternIndex: idx, quantifier: this.#quantifier });
86
+ literals.push(this._pattern);
87
+ code.push({ type: "Repeat", patternIndex: idx, quantifier: this._quantifier });
85
88
  }
86
89
 
87
90
  isComplex(): boolean {
@@ -89,15 +92,15 @@ export class GroupPattern implements Matcher {
89
92
  }
90
93
 
91
94
  toString(): string {
92
- const formattedRange = this.#quantifier.toString();
93
- return `(${(this.#pattern as unknown as { toString(): string }).toString()})${formattedRange}`;
95
+ const formattedRange = this._quantifier.toString();
96
+ return `(${dispatchPatternToString(this._pattern)})${formattedRange}`;
94
97
  }
95
98
 
96
99
  /**
97
100
  * Equality comparison.
98
101
  */
99
102
  equals(other: GroupPattern): boolean {
100
- return this.#pattern === other.#pattern && this.#quantifier.equals(other.#quantifier);
103
+ return this._pattern === other._pattern && this._quantifier.equals(other._quantifier);
101
104
  }
102
105
 
103
106
  /**
@@ -105,6 +108,6 @@ export class GroupPattern implements Matcher {
105
108
  */
106
109
  hashCode(): number {
107
110
  // Simple hash based on quantifier min/max
108
- return this.#quantifier.min() * 31 + (this.#quantifier.max() ?? 0);
111
+ return this._quantifier.min() * 31 + (this._quantifier.max() ?? 0);
109
112
  }
110
113
  }
@@ -8,9 +8,10 @@
8
8
 
9
9
  import type { Envelope } from "@bcts/envelope";
10
10
  import type { Path } from "../../format";
11
- import { type Matcher, matchPattern } from "../matcher";
11
+ import { matchPattern, dispatchPatternToString } from "../matcher";
12
12
  import type { Instr } from "../vm";
13
13
  import type { Pattern } from "../index";
14
+ import type { Matcher } from "../matcher";
14
15
 
15
16
  // Forward declaration for Pattern factory (used for late binding)
16
17
  export let createMetaNotPattern: ((pattern: NotPattern) => Pattern) | undefined;
@@ -25,10 +26,10 @@ export function registerNotPatternFactory(factory: (pattern: NotPattern) => Patt
25
26
  * Corresponds to the Rust `NotPattern` struct in not_pattern.rs
26
27
  */
27
28
  export class NotPattern implements Matcher {
28
- readonly #pattern: Pattern;
29
+ private readonly _pattern: Pattern;
29
30
 
30
31
  private constructor(pattern: Pattern) {
31
- this.#pattern = pattern;
32
+ this._pattern = pattern;
32
33
  }
33
34
 
34
35
  /**
@@ -42,12 +43,12 @@ export class NotPattern implements Matcher {
42
43
  * Gets the inner pattern.
43
44
  */
44
45
  pattern(): Pattern {
45
- return this.#pattern;
46
+ return this._pattern;
46
47
  }
47
48
 
48
49
  pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
49
50
  // If the inner pattern doesn't match, then we return the current envelope as a match
50
- const paths = !matchPattern(this.#pattern, haystack) ? [[haystack]] : [];
51
+ const paths = !matchPattern(this._pattern, haystack) ? [[haystack]] : [];
51
52
  return [paths, new Map<string, Path[]>()];
52
53
  }
53
54
 
@@ -62,7 +63,7 @@ export class NotPattern implements Matcher {
62
63
  compile(code: Instr[], literals: Pattern[], _captures: string[]): void {
63
64
  // NOT = check that pattern doesn't match
64
65
  const idx = literals.length;
65
- literals.push(this.#pattern);
66
+ literals.push(this._pattern);
66
67
  code.push({ type: "NotMatch", patternIndex: idx });
67
68
  }
68
69
 
@@ -71,14 +72,14 @@ export class NotPattern implements Matcher {
71
72
  }
72
73
 
73
74
  toString(): string {
74
- return `!${(this.#pattern as unknown as { toString(): string }).toString()}`;
75
+ return `!${dispatchPatternToString(this._pattern)}`;
75
76
  }
76
77
 
77
78
  /**
78
79
  * Equality comparison.
79
80
  */
80
81
  equals(other: NotPattern): boolean {
81
- return this.#pattern === other.#pattern;
82
+ return this._pattern === other._pattern;
82
83
  }
83
84
 
84
85
  /**
@@ -8,9 +8,15 @@
8
8
 
9
9
  import type { Envelope } from "@bcts/envelope";
10
10
  import type { Path } from "../../format";
11
- import { type Matcher, matchPattern } from "../matcher";
11
+ import {
12
+ dispatchPathsWithCaptures,
13
+ dispatchCompile,
14
+ dispatchIsComplex,
15
+ dispatchPatternToString,
16
+ } from "../matcher";
12
17
  import type { Instr } from "../vm";
13
18
  import type { Pattern } from "../index";
19
+ import type { Matcher } from "../matcher";
14
20
 
15
21
  // Forward declaration for Pattern factory (used for late binding)
16
22
  export let createMetaOrPattern: ((pattern: OrPattern) => Pattern) | undefined;
@@ -25,10 +31,10 @@ export function registerOrPatternFactory(factory: (pattern: OrPattern) => Patter
25
31
  * Corresponds to the Rust `OrPattern` struct in or_pattern.rs
26
32
  */
27
33
  export class OrPattern implements Matcher {
28
- readonly #patterns: Pattern[];
34
+ private readonly _patterns: Pattern[];
29
35
 
30
36
  private constructor(patterns: Pattern[]) {
31
- this.#patterns = patterns;
37
+ this._patterns = patterns;
32
38
  }
33
39
 
34
40
  /**
@@ -42,14 +48,18 @@ export class OrPattern implements Matcher {
42
48
  * Gets the patterns.
43
49
  */
44
50
  patterns(): Pattern[] {
45
- return this.#patterns;
51
+ return this._patterns;
46
52
  }
47
53
 
48
54
  pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
49
- const anyMatch = this.#patterns.some((pattern) => matchPattern(pattern, haystack));
50
-
51
- const paths = anyMatch ? [[haystack]] : [];
52
- return [paths, new Map<string, Path[]>()];
55
+ // Try each pattern and return paths+captures from the first match
56
+ for (const pattern of this._patterns) {
57
+ const [paths, captures] = dispatchPathsWithCaptures(pattern, haystack);
58
+ if (paths.length > 0) {
59
+ return [paths, captures];
60
+ }
61
+ }
62
+ return [[], new Map<string, Path[]>()];
53
63
  }
54
64
 
55
65
  paths(haystack: Envelope): Path[] {
@@ -61,7 +71,7 @@ export class OrPattern implements Matcher {
61
71
  }
62
72
 
63
73
  compile(code: Instr[], literals: Pattern[], captures: string[]): void {
64
- if (this.#patterns.length === 0) {
74
+ if (this._patterns.length === 0) {
65
75
  return;
66
76
  }
67
77
 
@@ -69,7 +79,7 @@ export class OrPattern implements Matcher {
69
79
  const splits: number[] = [];
70
80
 
71
81
  // Generate splits for all but the last pattern
72
- for (let i = 0; i < this.#patterns.length - 1; i++) {
82
+ for (let i = 0; i < this._patterns.length - 1; i++) {
73
83
  splits.push(code.length);
74
84
  code.push({ type: "Split", a: 0, b: 0 }); // Placeholder
75
85
  }
@@ -78,13 +88,12 @@ export class OrPattern implements Matcher {
78
88
  const jumps: number[] = [];
79
89
 
80
90
  // Now fill in the actual split targets
81
- for (let i = 0; i < this.#patterns.length; i++) {
91
+ for (let i = 0; i < this._patterns.length; i++) {
82
92
  const patternStart = code.length;
83
93
 
84
94
  // Compile this pattern
85
- const pattern = this.#patterns[i];
86
- const matcher = pattern as unknown as Matcher;
87
- matcher.compile(code, literals, captures);
95
+ const pattern = this._patterns[i];
96
+ dispatchCompile(pattern, code, literals, captures);
88
97
 
89
98
  // This pattern will jump to the end if it matches
90
99
  const jumpPastAll = code.length;
@@ -92,7 +101,7 @@ export class OrPattern implements Matcher {
92
101
  jumps.push(jumpPastAll);
93
102
 
94
103
  // If there's a next pattern, update the split to point here
95
- if (i < this.#patterns.length - 1) {
104
+ if (i < this._patterns.length - 1) {
96
105
  const nextPattern = code.length;
97
106
  code[splits[i]] = { type: "Split", a: patternStart, b: nextPattern };
98
107
  }
@@ -108,26 +117,22 @@ export class OrPattern implements Matcher {
108
117
  isComplex(): boolean {
109
118
  // The pattern is complex if it contains more than one pattern, or if
110
119
  // the one pattern is complex itself.
111
- return (
112
- this.#patterns.length > 1 || this.#patterns.some((p) => (p as unknown as Matcher).isComplex())
113
- );
120
+ return this._patterns.length > 1 || this._patterns.some((p) => dispatchIsComplex(p));
114
121
  }
115
122
 
116
123
  toString(): string {
117
- return this.#patterns
118
- .map((p) => (p as unknown as { toString(): string }).toString())
119
- .join(" | ");
124
+ return this._patterns.map((p) => dispatchPatternToString(p)).join(" | ");
120
125
  }
121
126
 
122
127
  /**
123
128
  * Equality comparison.
124
129
  */
125
130
  equals(other: OrPattern): boolean {
126
- if (this.#patterns.length !== other.#patterns.length) {
131
+ if (this._patterns.length !== other._patterns.length) {
127
132
  return false;
128
133
  }
129
- for (let i = 0; i < this.#patterns.length; i++) {
130
- if (this.#patterns[i] !== other.#patterns[i]) {
134
+ for (let i = 0; i < this._patterns.length; i++) {
135
+ if (this._patterns[i] !== other._patterns[i]) {
131
136
  return false;
132
137
  }
133
138
  }
@@ -138,6 +143,6 @@ export class OrPattern implements Matcher {
138
143
  * Hash code for use in Maps/Sets.
139
144
  */
140
145
  hashCode(): number {
141
- return this.#patterns.length;
146
+ return this._patterns.length;
142
147
  }
143
148
  }