@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.
- package/README.md +1 -1
- package/dist/index.cjs +1992 -1714
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +147 -31
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +147 -31
- package/dist/index.d.mts.map +1 -1
- package/dist/index.iife.js +1984 -1707
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +1966 -1698
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -9
- package/src/format.ts +32 -13
- package/src/parse/index.ts +138 -5
- package/src/parse/token.ts +59 -58
- package/src/pattern/index.ts +110 -2
- package/src/pattern/leaf/array-pattern.ts +26 -26
- package/src/pattern/leaf/bool-pattern.ts +12 -12
- package/src/pattern/leaf/byte-string-pattern.ts +15 -15
- package/src/pattern/leaf/cbor-pattern.ts +31 -31
- package/src/pattern/leaf/date-pattern.ts +9 -9
- package/src/pattern/leaf/index.ts +1 -2
- package/src/pattern/leaf/known-value-pattern.ts +21 -20
- package/src/pattern/leaf/map-pattern.ts +14 -14
- package/src/pattern/leaf/null-pattern.ts +8 -8
- package/src/pattern/leaf/number-pattern.ts +20 -20
- package/src/pattern/leaf/tagged-pattern.ts +20 -20
- package/src/pattern/leaf/text-pattern.ts +14 -14
- package/src/pattern/matcher.ts +88 -3
- package/src/pattern/meta/and-pattern.ts +19 -18
- package/src/pattern/meta/capture-pattern.ts +16 -17
- package/src/pattern/meta/group-pattern.ts +20 -17
- package/src/pattern/meta/not-pattern.ts +9 -8
- package/src/pattern/meta/or-pattern.ts +30 -25
- package/src/pattern/meta/search-pattern.ts +17 -17
- package/src/pattern/meta/traverse-pattern.ts +42 -18
- package/src/pattern/structure/assertions-pattern.ts +31 -32
- package/src/pattern/structure/digest-pattern.ts +23 -23
- package/src/pattern/structure/index.ts +1 -0
- package/src/pattern/structure/node-pattern.ts +17 -17
- package/src/pattern/structure/object-pattern.ts +14 -15
- package/src/pattern/structure/obscured-pattern.ts +7 -7
- package/src/pattern/structure/predicate-pattern.ts +14 -15
- package/src/pattern/structure/subject-pattern.ts +16 -17
- package/src/pattern/structure/wrapped-pattern.ts +40 -19
- package/src/pattern/vm.ts +12 -11
package/src/pattern/matcher.ts
CHANGED
|
@@ -88,14 +88,23 @@ export function compileAsAtomic(
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
// ============================================================================
|
|
91
|
-
// Pattern
|
|
91
|
+
// Pattern Dispatch Registry
|
|
92
92
|
// ============================================================================
|
|
93
93
|
|
|
94
94
|
/**
|
|
95
|
-
* Registry for pattern
|
|
96
|
-
* This allows meta patterns to
|
|
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 {
|
|
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
|
|
34
|
+
private readonly _patterns: Pattern[];
|
|
29
35
|
|
|
30
36
|
private constructor(patterns: Pattern[]) {
|
|
31
|
-
this
|
|
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
|
|
51
|
+
return this._patterns;
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
|
|
49
|
-
const allMatch = this
|
|
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
|
|
66
|
-
|
|
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
|
|
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
|
|
90
|
+
if (this._patterns.length !== other._patterns.length) {
|
|
90
91
|
return false;
|
|
91
92
|
}
|
|
92
|
-
for (let i = 0; i < this
|
|
93
|
-
if (this
|
|
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
|
|
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
|
|
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
|
|
29
|
-
readonly
|
|
29
|
+
private readonly _name: string;
|
|
30
|
+
private readonly _pattern: Pattern;
|
|
30
31
|
|
|
31
32
|
private constructor(name: string, pattern: Pattern) {
|
|
32
|
-
this
|
|
33
|
-
this
|
|
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
|
|
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
|
|
55
|
+
return this._pattern;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
|
|
58
|
-
const
|
|
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
|
|
63
|
-
caps.set(this
|
|
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
|
|
79
|
+
captures.push(this._name);
|
|
80
80
|
code.push({ type: "CaptureStart", captureIndex: id });
|
|
81
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
30
|
-
readonly
|
|
30
|
+
private readonly _pattern: Pattern;
|
|
31
|
+
private readonly _quantifier: Quantifier;
|
|
31
32
|
|
|
32
33
|
private constructor(pattern: Pattern, quantifier: Quantifier) {
|
|
33
|
-
this
|
|
34
|
-
this
|
|
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
|
|
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
|
|
63
|
+
return this._quantifier;
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
pathsWithCaptures(
|
|
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
|
-
|
|
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
|
|
84
|
-
code.push({ type: "Repeat", patternIndex: idx, quantifier: this
|
|
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
|
|
93
|
-
return `(${(this
|
|
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
|
|
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
|
|
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 {
|
|
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
|
|
29
|
+
private readonly _pattern: Pattern;
|
|
29
30
|
|
|
30
31
|
private constructor(pattern: Pattern) {
|
|
31
|
-
this
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 {
|
|
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
|
|
34
|
+
private readonly _patterns: Pattern[];
|
|
29
35
|
|
|
30
36
|
private constructor(patterns: Pattern[]) {
|
|
31
|
-
this
|
|
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
|
|
51
|
+
return this._patterns;
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
86
|
-
|
|
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
|
|
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
|
|
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
|
|
131
|
+
if (this._patterns.length !== other._patterns.length) {
|
|
127
132
|
return false;
|
|
128
133
|
}
|
|
129
|
-
for (let i = 0; i < this
|
|
130
|
-
if (this
|
|
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
|
|
146
|
+
return this._patterns.length;
|
|
142
147
|
}
|
|
143
148
|
}
|