@bcts/envelope-pattern 1.0.0-alpha.12
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/LICENSE +48 -0
- package/README.md +13 -0
- package/dist/index.cjs +6781 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2628 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +2628 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.iife.js +6781 -0
- package/dist/index.iife.js.map +1 -0
- package/dist/index.mjs +6545 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +77 -0
- package/src/error.ts +262 -0
- package/src/format.ts +375 -0
- package/src/index.ts +27 -0
- package/src/parse/index.ts +923 -0
- package/src/parse/token.ts +906 -0
- package/src/parse/utils.ts +339 -0
- package/src/pattern/index.ts +719 -0
- package/src/pattern/leaf/array-pattern.ts +273 -0
- package/src/pattern/leaf/bool-pattern.ts +140 -0
- package/src/pattern/leaf/byte-string-pattern.ts +172 -0
- package/src/pattern/leaf/cbor-pattern.ts +355 -0
- package/src/pattern/leaf/date-pattern.ts +178 -0
- package/src/pattern/leaf/index.ts +280 -0
- package/src/pattern/leaf/known-value-pattern.ts +192 -0
- package/src/pattern/leaf/map-pattern.ts +152 -0
- package/src/pattern/leaf/null-pattern.ts +110 -0
- package/src/pattern/leaf/number-pattern.ts +248 -0
- package/src/pattern/leaf/tagged-pattern.ts +228 -0
- package/src/pattern/leaf/text-pattern.ts +165 -0
- package/src/pattern/matcher.ts +88 -0
- package/src/pattern/meta/and-pattern.ts +109 -0
- package/src/pattern/meta/any-pattern.ts +81 -0
- package/src/pattern/meta/capture-pattern.ts +111 -0
- package/src/pattern/meta/group-pattern.ts +110 -0
- package/src/pattern/meta/index.ts +269 -0
- package/src/pattern/meta/not-pattern.ts +91 -0
- package/src/pattern/meta/or-pattern.ts +146 -0
- package/src/pattern/meta/search-pattern.ts +201 -0
- package/src/pattern/meta/traverse-pattern.ts +146 -0
- package/src/pattern/structure/assertions-pattern.ts +244 -0
- package/src/pattern/structure/digest-pattern.ts +225 -0
- package/src/pattern/structure/index.ts +272 -0
- package/src/pattern/structure/leaf-structure-pattern.ts +85 -0
- package/src/pattern/structure/node-pattern.ts +188 -0
- package/src/pattern/structure/object-pattern.ts +149 -0
- package/src/pattern/structure/obscured-pattern.ts +159 -0
- package/src/pattern/structure/predicate-pattern.ts +151 -0
- package/src/pattern/structure/subject-pattern.ts +152 -0
- package/src/pattern/structure/wrapped-pattern.ts +195 -0
- package/src/pattern/vm.ts +1021 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @bcts/envelope-pattern - Null pattern matching
|
|
3
|
+
*
|
|
4
|
+
* This is a 1:1 TypeScript port of bc-envelope-pattern-rust null_pattern.rs
|
|
5
|
+
*
|
|
6
|
+
* @module envelope-pattern/pattern/leaf/null-pattern
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Envelope } from "@bcts/envelope";
|
|
10
|
+
import {
|
|
11
|
+
type NullPattern as DCBORNullPattern,
|
|
12
|
+
nullPatternPaths as dcborNullPatternPaths,
|
|
13
|
+
nullPatternDisplay,
|
|
14
|
+
} from "@bcts/dcbor-pattern";
|
|
15
|
+
import type { Path } from "../../format";
|
|
16
|
+
import type { Matcher } from "../matcher";
|
|
17
|
+
import { compileAsAtomic } from "../matcher";
|
|
18
|
+
import type { Instr } from "../vm";
|
|
19
|
+
import type { Pattern } from "../index";
|
|
20
|
+
|
|
21
|
+
// Forward declaration for Pattern factory
|
|
22
|
+
let createLeafNullPattern: ((pattern: NullPattern) => Pattern) | undefined;
|
|
23
|
+
|
|
24
|
+
export function registerNullPatternFactory(factory: (pattern: NullPattern) => Pattern): void {
|
|
25
|
+
createLeafNullPattern = factory;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Pattern for matching null values.
|
|
30
|
+
*
|
|
31
|
+
* This is a wrapper around dcbor_pattern::NullPattern that provides
|
|
32
|
+
* envelope-specific functionality.
|
|
33
|
+
*
|
|
34
|
+
* Corresponds to the Rust `NullPattern` struct in null_pattern.rs
|
|
35
|
+
*/
|
|
36
|
+
export class NullPattern implements Matcher {
|
|
37
|
+
readonly #inner: DCBORNullPattern;
|
|
38
|
+
static readonly #instance = new NullPattern();
|
|
39
|
+
|
|
40
|
+
private constructor() {
|
|
41
|
+
// Create the NullPattern directly - it's just { variant: "Null" }
|
|
42
|
+
this.#inner = { variant: "Null" };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Creates a new NullPattern (returns singleton).
|
|
47
|
+
*/
|
|
48
|
+
static new(): NullPattern {
|
|
49
|
+
return NullPattern.#instance;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Gets the underlying dcbor-pattern NullPattern.
|
|
54
|
+
*/
|
|
55
|
+
get inner(): DCBORNullPattern {
|
|
56
|
+
return this.#inner;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
|
|
60
|
+
// For leaf envelopes, extract the CBOR and delegate to dcbor-pattern
|
|
61
|
+
const cbor = haystack.asLeaf();
|
|
62
|
+
if (cbor !== undefined) {
|
|
63
|
+
// Delegate to dcbor-pattern for CBOR matching
|
|
64
|
+
const dcborPaths = dcborNullPatternPaths(this.#inner, cbor);
|
|
65
|
+
|
|
66
|
+
if (dcborPaths.length > 0) {
|
|
67
|
+
return [[[haystack]], new Map<string, Path[]>()];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return [[], new Map<string, Path[]>()];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
paths(haystack: Envelope): Path[] {
|
|
75
|
+
return this.pathsWithCaptures(haystack)[0];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
matches(haystack: Envelope): boolean {
|
|
79
|
+
return this.paths(haystack).length > 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
compile(code: Instr[], literals: Pattern[], captures: string[]): void {
|
|
83
|
+
if (createLeafNullPattern === undefined) {
|
|
84
|
+
throw new Error("NullPattern factory not registered");
|
|
85
|
+
}
|
|
86
|
+
compileAsAtomic(createLeafNullPattern(this), code, literals, captures);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
isComplex(): boolean {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
toString(): string {
|
|
94
|
+
return nullPatternDisplay(this.#inner);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Equality comparison.
|
|
99
|
+
*/
|
|
100
|
+
equals(other: NullPattern): boolean {
|
|
101
|
+
return other instanceof NullPattern;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Hash code for use in Maps/Sets.
|
|
106
|
+
*/
|
|
107
|
+
hashCode(): number {
|
|
108
|
+
return 0; // All NullPatterns are equal
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @bcts/envelope-pattern - Number pattern matching
|
|
3
|
+
*
|
|
4
|
+
* This is a 1:1 TypeScript port of bc-envelope-pattern-rust number_pattern.rs
|
|
5
|
+
*
|
|
6
|
+
* @module envelope-pattern/pattern/leaf/number-pattern
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Envelope } from "@bcts/envelope";
|
|
10
|
+
import {
|
|
11
|
+
type NumberPattern as DCBORNumberPattern,
|
|
12
|
+
numberPatternAny,
|
|
13
|
+
numberPatternValue,
|
|
14
|
+
numberPatternRange,
|
|
15
|
+
numberPatternGreaterThan,
|
|
16
|
+
numberPatternGreaterThanOrEqual,
|
|
17
|
+
numberPatternLessThan,
|
|
18
|
+
numberPatternLessThanOrEqual,
|
|
19
|
+
numberPatternNaN,
|
|
20
|
+
numberPatternInfinity,
|
|
21
|
+
numberPatternNegInfinity,
|
|
22
|
+
numberPatternPaths as dcborNumberPatternPaths,
|
|
23
|
+
numberPatternDisplay,
|
|
24
|
+
} from "@bcts/dcbor-pattern";
|
|
25
|
+
import type { Path } from "../../format";
|
|
26
|
+
import type { Matcher } from "../matcher";
|
|
27
|
+
import { compileAsAtomic } from "../matcher";
|
|
28
|
+
import type { Instr } from "../vm";
|
|
29
|
+
import type { Pattern } from "../index";
|
|
30
|
+
|
|
31
|
+
// Forward declaration for Pattern factory
|
|
32
|
+
let createLeafNumberPattern: ((pattern: NumberPattern) => Pattern) | undefined;
|
|
33
|
+
|
|
34
|
+
export function registerNumberPatternFactory(factory: (pattern: NumberPattern) => Pattern): void {
|
|
35
|
+
createLeafNumberPattern = factory;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Pattern for matching number values.
|
|
40
|
+
*
|
|
41
|
+
* This is a wrapper around dcbor_pattern::NumberPattern that provides
|
|
42
|
+
* envelope-specific integration.
|
|
43
|
+
*
|
|
44
|
+
* Corresponds to the Rust `NumberPattern` struct in number_pattern.rs
|
|
45
|
+
*/
|
|
46
|
+
export class NumberPattern implements Matcher {
|
|
47
|
+
readonly #inner: DCBORNumberPattern;
|
|
48
|
+
|
|
49
|
+
private constructor(inner: DCBORNumberPattern) {
|
|
50
|
+
this.#inner = inner;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Creates a new NumberPattern that matches any number.
|
|
55
|
+
*/
|
|
56
|
+
static any(): NumberPattern {
|
|
57
|
+
return new NumberPattern(numberPatternAny());
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Creates a new NumberPattern that matches the exact number.
|
|
62
|
+
*/
|
|
63
|
+
static exact(value: number): NumberPattern {
|
|
64
|
+
return new NumberPattern(numberPatternValue(value));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Creates a new NumberPattern that matches numbers within the specified range.
|
|
69
|
+
*/
|
|
70
|
+
static range(min: number, max: number): NumberPattern {
|
|
71
|
+
return new NumberPattern(numberPatternRange(min, max));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Creates a new NumberPattern that matches numbers greater than the specified value.
|
|
76
|
+
*/
|
|
77
|
+
static greaterThan(value: number): NumberPattern {
|
|
78
|
+
return new NumberPattern(numberPatternGreaterThan(value));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Creates a new NumberPattern that matches numbers greater than or equal to the specified value.
|
|
83
|
+
*/
|
|
84
|
+
static greaterThanOrEqual(value: number): NumberPattern {
|
|
85
|
+
return new NumberPattern(numberPatternGreaterThanOrEqual(value));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Creates a new NumberPattern that matches numbers less than the specified value.
|
|
90
|
+
*/
|
|
91
|
+
static lessThan(value: number): NumberPattern {
|
|
92
|
+
return new NumberPattern(numberPatternLessThan(value));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Creates a new NumberPattern that matches numbers less than or equal to the specified value.
|
|
97
|
+
*/
|
|
98
|
+
static lessThanOrEqual(value: number): NumberPattern {
|
|
99
|
+
return new NumberPattern(numberPatternLessThanOrEqual(value));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Creates a new NumberPattern that matches NaN values.
|
|
104
|
+
*/
|
|
105
|
+
static nan(): NumberPattern {
|
|
106
|
+
return new NumberPattern(numberPatternNaN());
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Creates a new NumberPattern that matches positive infinity.
|
|
111
|
+
*/
|
|
112
|
+
static infinity(): NumberPattern {
|
|
113
|
+
return new NumberPattern(numberPatternInfinity());
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Creates a new NumberPattern that matches negative infinity.
|
|
118
|
+
*/
|
|
119
|
+
static negInfinity(): NumberPattern {
|
|
120
|
+
return new NumberPattern(numberPatternNegInfinity());
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Creates a new NumberPattern from a dcbor-pattern NumberPattern.
|
|
125
|
+
*/
|
|
126
|
+
static fromDcborPattern(dcborPattern: DCBORNumberPattern): NumberPattern {
|
|
127
|
+
return new NumberPattern(dcborPattern);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Gets the underlying dcbor-pattern NumberPattern.
|
|
132
|
+
*/
|
|
133
|
+
get inner(): DCBORNumberPattern {
|
|
134
|
+
return this.#inner;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
|
|
138
|
+
// For leaf envelopes, extract the CBOR and delegate to dcbor-pattern
|
|
139
|
+
const cbor = haystack.asLeaf();
|
|
140
|
+
if (cbor !== undefined) {
|
|
141
|
+
// Delegate to dcbor-pattern for CBOR matching
|
|
142
|
+
const dcborPaths = dcborNumberPatternPaths(this.#inner, cbor);
|
|
143
|
+
|
|
144
|
+
// For simple leaf patterns, if dcbor-pattern found matches, return the envelope
|
|
145
|
+
if (dcborPaths.length > 0) {
|
|
146
|
+
const envelopePaths: Path[] = [[haystack]];
|
|
147
|
+
return [envelopePaths, new Map<string, Path[]>()];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return [[], new Map<string, Path[]>()];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
paths(haystack: Envelope): Path[] {
|
|
155
|
+
return this.pathsWithCaptures(haystack)[0];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
matches(haystack: Envelope): boolean {
|
|
159
|
+
return this.paths(haystack).length > 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
compile(code: Instr[], literals: Pattern[], captures: string[]): void {
|
|
163
|
+
if (createLeafNumberPattern === undefined) {
|
|
164
|
+
throw new Error("NumberPattern factory not registered");
|
|
165
|
+
}
|
|
166
|
+
compileAsAtomic(createLeafNumberPattern(this), code, literals, captures);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
isComplex(): boolean {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
toString(): string {
|
|
174
|
+
return numberPatternDisplay(this.#inner);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Equality comparison.
|
|
179
|
+
*/
|
|
180
|
+
equals(other: NumberPattern): boolean {
|
|
181
|
+
// Compare by variant and values
|
|
182
|
+
if (this.#inner.variant !== other.#inner.variant) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
switch (this.#inner.variant) {
|
|
186
|
+
case "Any":
|
|
187
|
+
case "NaN":
|
|
188
|
+
case "Infinity":
|
|
189
|
+
case "NegInfinity":
|
|
190
|
+
return true;
|
|
191
|
+
case "Value":
|
|
192
|
+
case "GreaterThan":
|
|
193
|
+
case "GreaterThanOrEqual":
|
|
194
|
+
case "LessThan":
|
|
195
|
+
case "LessThanOrEqual":
|
|
196
|
+
return (
|
|
197
|
+
(this.#inner as { value: number }).value === (other.#inner as { value: number }).value
|
|
198
|
+
);
|
|
199
|
+
case "Range":
|
|
200
|
+
return (
|
|
201
|
+
(this.#inner as { min: number; max: number }).min ===
|
|
202
|
+
(other.#inner as { min: number; max: number }).min &&
|
|
203
|
+
(this.#inner as { min: number; max: number }).max ===
|
|
204
|
+
(other.#inner as { min: number; max: number }).max
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Hash code for use in Maps/Sets.
|
|
211
|
+
*/
|
|
212
|
+
hashCode(): number {
|
|
213
|
+
let hash = 0;
|
|
214
|
+
switch (this.#inner.variant) {
|
|
215
|
+
case "Any":
|
|
216
|
+
hash = 1;
|
|
217
|
+
break;
|
|
218
|
+
case "Value":
|
|
219
|
+
hash = 2 * 31 + (this.#inner as { value: number }).value;
|
|
220
|
+
break;
|
|
221
|
+
case "Range":
|
|
222
|
+
hash = 3 * 31 + (this.#inner as { min: number }).min + (this.#inner as { max: number }).max;
|
|
223
|
+
break;
|
|
224
|
+
case "GreaterThan":
|
|
225
|
+
hash = 4 * 31 + (this.#inner as { value: number }).value;
|
|
226
|
+
break;
|
|
227
|
+
case "GreaterThanOrEqual":
|
|
228
|
+
hash = 5 * 31 + (this.#inner as { value: number }).value;
|
|
229
|
+
break;
|
|
230
|
+
case "LessThan":
|
|
231
|
+
hash = 6 * 31 + (this.#inner as { value: number }).value;
|
|
232
|
+
break;
|
|
233
|
+
case "LessThanOrEqual":
|
|
234
|
+
hash = 7 * 31 + (this.#inner as { value: number }).value;
|
|
235
|
+
break;
|
|
236
|
+
case "NaN":
|
|
237
|
+
hash = 8;
|
|
238
|
+
break;
|
|
239
|
+
case "Infinity":
|
|
240
|
+
hash = 9;
|
|
241
|
+
break;
|
|
242
|
+
case "NegInfinity":
|
|
243
|
+
hash = 10;
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
return hash;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @bcts/envelope-pattern - Tagged pattern matching
|
|
3
|
+
*
|
|
4
|
+
* This is a 1:1 TypeScript port of bc-envelope-pattern-rust tagged_pattern.rs
|
|
5
|
+
*
|
|
6
|
+
* @module envelope-pattern/pattern/leaf/tagged-pattern
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Envelope } from "@bcts/envelope";
|
|
10
|
+
import type { Tag, Cbor } from "@bcts/dcbor";
|
|
11
|
+
import {
|
|
12
|
+
type TaggedPattern as DCBORTaggedPattern,
|
|
13
|
+
type Pattern as DCBORPattern,
|
|
14
|
+
taggedPatternAny,
|
|
15
|
+
taggedPatternWithTag,
|
|
16
|
+
taggedPatternWithName,
|
|
17
|
+
taggedPatternWithRegex,
|
|
18
|
+
taggedPatternPathsWithCaptures,
|
|
19
|
+
taggedPatternDisplay,
|
|
20
|
+
patternDisplay,
|
|
21
|
+
} from "@bcts/dcbor-pattern";
|
|
22
|
+
import type { Path } from "../../format";
|
|
23
|
+
import type { Matcher } from "../matcher";
|
|
24
|
+
import { compileAsAtomic } from "../matcher";
|
|
25
|
+
import type { Instr } from "../vm";
|
|
26
|
+
import type { Pattern } from "../index";
|
|
27
|
+
|
|
28
|
+
// Forward declaration for Pattern factory
|
|
29
|
+
let createLeafTaggedPattern: ((pattern: TaggedPattern) => Pattern) | undefined;
|
|
30
|
+
|
|
31
|
+
export function registerTaggedPatternFactory(factory: (pattern: TaggedPattern) => Pattern): void {
|
|
32
|
+
createLeafTaggedPattern = factory;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Pattern for matching tagged CBOR values.
|
|
37
|
+
*
|
|
38
|
+
* This is a wrapper around dcbor_pattern::TaggedPattern that provides
|
|
39
|
+
* envelope-specific integration.
|
|
40
|
+
*
|
|
41
|
+
* Corresponds to the Rust `TaggedPattern` struct in tagged_pattern.rs
|
|
42
|
+
*/
|
|
43
|
+
export class TaggedPattern implements Matcher {
|
|
44
|
+
readonly #inner: DCBORTaggedPattern;
|
|
45
|
+
|
|
46
|
+
private constructor(inner: DCBORTaggedPattern) {
|
|
47
|
+
this.#inner = inner;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Creates a new TaggedPattern that matches any tagged value.
|
|
52
|
+
*/
|
|
53
|
+
static any(): TaggedPattern {
|
|
54
|
+
return new TaggedPattern(taggedPatternAny());
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Creates a new TaggedPattern with a specific tag and content pattern.
|
|
59
|
+
*/
|
|
60
|
+
static withTag(tag: Tag, pattern: DCBORPattern): TaggedPattern {
|
|
61
|
+
return new TaggedPattern(taggedPatternWithTag(tag, pattern));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Creates a new TaggedPattern with a specific tag name and content pattern.
|
|
66
|
+
*/
|
|
67
|
+
static withName(name: string, pattern: DCBORPattern): TaggedPattern {
|
|
68
|
+
return new TaggedPattern(taggedPatternWithName(name, pattern));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Creates a new TaggedPattern with a tag name matching regex and content pattern.
|
|
73
|
+
*/
|
|
74
|
+
static withRegex(regex: RegExp, pattern: DCBORPattern): TaggedPattern {
|
|
75
|
+
return new TaggedPattern(taggedPatternWithRegex(regex, pattern));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Creates a new TaggedPattern from a dcbor-pattern TaggedPattern.
|
|
80
|
+
*/
|
|
81
|
+
static fromDcborPattern(dcborPattern: DCBORTaggedPattern): TaggedPattern {
|
|
82
|
+
return new TaggedPattern(dcborPattern);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Gets the underlying dcbor-pattern TaggedPattern.
|
|
87
|
+
*/
|
|
88
|
+
get inner(): DCBORTaggedPattern {
|
|
89
|
+
return this.#inner;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
|
|
93
|
+
// Try to extract CBOR from the envelope
|
|
94
|
+
const subject = haystack.subject();
|
|
95
|
+
const cbor = subject.asLeaf();
|
|
96
|
+
|
|
97
|
+
if (cbor !== undefined) {
|
|
98
|
+
// Delegate to dcbor-pattern for CBOR matching
|
|
99
|
+
const [dcborPaths, dcborCaptures] = taggedPatternPathsWithCaptures(this.#inner, cbor);
|
|
100
|
+
|
|
101
|
+
if (dcborPaths.length > 0) {
|
|
102
|
+
// Convert dcbor paths to envelope paths
|
|
103
|
+
const envelopePaths: Path[] = dcborPaths.map((dcborPath: Cbor[]) => {
|
|
104
|
+
const envPath: Path = [haystack];
|
|
105
|
+
// Skip the first element (root) and convert rest to envelopes
|
|
106
|
+
for (let i = 1; i < dcborPath.length; i++) {
|
|
107
|
+
const elem = dcborPath[i];
|
|
108
|
+
if (elem !== undefined) {
|
|
109
|
+
envPath.push(Envelope.newLeaf(elem));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return envPath;
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Convert dcbor captures to envelope captures
|
|
116
|
+
const envelopeCaptures = new Map<string, Path[]>();
|
|
117
|
+
for (const [name, paths] of dcborCaptures) {
|
|
118
|
+
const envCapturePaths: Path[] = paths.map((dcborPath: Cbor[]) => {
|
|
119
|
+
const envPath: Path = [haystack];
|
|
120
|
+
for (let i = 1; i < dcborPath.length; i++) {
|
|
121
|
+
const elem = dcborPath[i];
|
|
122
|
+
if (elem !== undefined) {
|
|
123
|
+
envPath.push(Envelope.newLeaf(elem));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return envPath;
|
|
127
|
+
});
|
|
128
|
+
envelopeCaptures.set(name, envCapturePaths);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return [envelopePaths, envelopeCaptures];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return [[], new Map<string, Path[]>()];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
paths(haystack: Envelope): Path[] {
|
|
139
|
+
return this.pathsWithCaptures(haystack)[0];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
matches(haystack: Envelope): boolean {
|
|
143
|
+
return this.paths(haystack).length > 0;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
compile(code: Instr[], literals: Pattern[], captures: string[]): void {
|
|
147
|
+
if (createLeafTaggedPattern === undefined) {
|
|
148
|
+
throw new Error("TaggedPattern factory not registered");
|
|
149
|
+
}
|
|
150
|
+
compileAsAtomic(createLeafTaggedPattern(this), code, literals, captures);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
isComplex(): boolean {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
toString(): string {
|
|
158
|
+
return taggedPatternDisplay(this.#inner, patternDisplay);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Equality comparison.
|
|
163
|
+
*/
|
|
164
|
+
equals(other: TaggedPattern): boolean {
|
|
165
|
+
// Compare by variant type and values
|
|
166
|
+
if (this.#inner.variant !== other.#inner.variant) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
switch (this.#inner.variant) {
|
|
170
|
+
case "Any":
|
|
171
|
+
return true;
|
|
172
|
+
case "Tag": {
|
|
173
|
+
const otherTag = other.#inner as { variant: "Tag"; tag: Tag; pattern: DCBORPattern };
|
|
174
|
+
return (
|
|
175
|
+
this.#inner.tag.value === otherTag.tag.value &&
|
|
176
|
+
patternDisplay(this.#inner.pattern) === patternDisplay(otherTag.pattern)
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
case "Name": {
|
|
180
|
+
const otherName = other.#inner as { variant: "Name"; name: string; pattern: DCBORPattern };
|
|
181
|
+
return (
|
|
182
|
+
this.#inner.name === otherName.name &&
|
|
183
|
+
patternDisplay(this.#inner.pattern) === patternDisplay(otherName.pattern)
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
case "Regex": {
|
|
187
|
+
const otherRegex = other.#inner as {
|
|
188
|
+
variant: "Regex";
|
|
189
|
+
regex: RegExp;
|
|
190
|
+
pattern: DCBORPattern;
|
|
191
|
+
};
|
|
192
|
+
return (
|
|
193
|
+
this.#inner.regex.source === otherRegex.regex.source &&
|
|
194
|
+
patternDisplay(this.#inner.pattern) === patternDisplay(otherRegex.pattern)
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Hash code for use in Maps/Sets.
|
|
202
|
+
*/
|
|
203
|
+
hashCode(): number {
|
|
204
|
+
switch (this.#inner.variant) {
|
|
205
|
+
case "Any":
|
|
206
|
+
return 0;
|
|
207
|
+
case "Tag":
|
|
208
|
+
return Number(BigInt(this.#inner.tag.value) & BigInt(0xffffffff));
|
|
209
|
+
case "Name":
|
|
210
|
+
return simpleStringHash(this.#inner.name);
|
|
211
|
+
case "Regex":
|
|
212
|
+
return simpleStringHash(this.#inner.regex.source);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Simple string hash function for hashCode implementations.
|
|
219
|
+
*/
|
|
220
|
+
function simpleStringHash(str: string): number {
|
|
221
|
+
let hash = 0;
|
|
222
|
+
for (let i = 0; i < str.length; i++) {
|
|
223
|
+
const char = str.charCodeAt(i);
|
|
224
|
+
hash = (hash << 5) - hash + char;
|
|
225
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
226
|
+
}
|
|
227
|
+
return hash;
|
|
228
|
+
}
|