@bcts/envelope-pattern 1.0.0-alpha.15 → 1.0.0-alpha.17
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 +485 -485
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +93 -29
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +93 -29
- package/dist/index.d.mts.map +1 -1
- package/dist/index.iife.js +485 -485
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +504 -504
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -9
- package/src/format.ts +9 -9
- package/src/parse/token.ts +55 -55
- package/src/pattern/leaf/array-pattern.ts +25 -25
- package/src/pattern/leaf/bool-pattern.ts +11 -11
- package/src/pattern/leaf/byte-string-pattern.ts +14 -14
- package/src/pattern/leaf/cbor-pattern.ts +29 -29
- package/src/pattern/leaf/date-pattern.ts +8 -8
- package/src/pattern/leaf/known-value-pattern.ts +17 -17
- package/src/pattern/leaf/map-pattern.ts +13 -13
- package/src/pattern/leaf/null-pattern.ts +7 -7
- package/src/pattern/leaf/number-pattern.ts +19 -19
- package/src/pattern/leaf/tagged-pattern.ts +20 -20
- package/src/pattern/leaf/text-pattern.ts +13 -13
- package/src/pattern/meta/and-pattern.ts +11 -11
- package/src/pattern/meta/capture-pattern.ts +14 -14
- package/src/pattern/meta/group-pattern.ts +13 -13
- package/src/pattern/meta/not-pattern.ts +7 -7
- package/src/pattern/meta/or-pattern.ts +15 -15
- package/src/pattern/meta/search-pattern.ts +15 -15
- package/src/pattern/meta/traverse-pattern.ts +15 -15
- package/src/pattern/structure/assertions-pattern.ts +28 -28
- package/src/pattern/structure/digest-pattern.ts +23 -23
- package/src/pattern/structure/node-pattern.ts +17 -17
- package/src/pattern/structure/object-pattern.ts +13 -13
- package/src/pattern/structure/obscured-pattern.ts +7 -7
- package/src/pattern/structure/predicate-pattern.ts +13 -13
- package/src/pattern/structure/subject-pattern.ts +15 -15
- package/src/pattern/structure/wrapped-pattern.ts +15 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bcts/envelope-pattern",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.17",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Pattern matching for Gordian Envelope structures",
|
|
6
6
|
"license": "BSD-2-Clause-Patent",
|
|
@@ -60,16 +60,16 @@
|
|
|
60
60
|
"@bcts/eslint": "^0.1.0",
|
|
61
61
|
"@bcts/tsconfig": "^0.1.0",
|
|
62
62
|
"eslint": "^9.39.2",
|
|
63
|
-
"tsdown": "^0.
|
|
64
|
-
"typedoc": "^0.28.
|
|
63
|
+
"tsdown": "^0.20.1",
|
|
64
|
+
"typedoc": "^0.28.16",
|
|
65
65
|
"typescript": "^5.9.3",
|
|
66
|
-
"vitest": "^4.0.
|
|
66
|
+
"vitest": "^4.0.18"
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
|
-
"@bcts/dcbor": "^1.0.0-alpha.
|
|
70
|
-
"@bcts/dcbor-parse": "^1.0.0-alpha.
|
|
71
|
-
"@bcts/dcbor-pattern": "^1.0.0-alpha.
|
|
72
|
-
"@bcts/envelope": "^1.0.0-alpha.
|
|
73
|
-
"@bcts/known-values": "^1.0.0-alpha.
|
|
69
|
+
"@bcts/dcbor": "^1.0.0-alpha.17",
|
|
70
|
+
"@bcts/dcbor-parse": "^1.0.0-alpha.17",
|
|
71
|
+
"@bcts/dcbor-pattern": "^1.0.0-alpha.17",
|
|
72
|
+
"@bcts/envelope": "^1.0.0-alpha.17",
|
|
73
|
+
"@bcts/known-values": "^1.0.0-alpha.17"
|
|
74
74
|
}
|
|
75
75
|
}
|
package/src/format.ts
CHANGED
|
@@ -97,15 +97,15 @@ export function defaultFormatPathsOpts(): FormatPathsOpts {
|
|
|
97
97
|
* Builder for FormatPathsOpts.
|
|
98
98
|
*/
|
|
99
99
|
export class FormatPathsOptsBuilder {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
private _indent = true;
|
|
101
|
+
private _elementFormat: PathElementFormat = defaultPathElementFormat();
|
|
102
|
+
private _lastElementOnly = false;
|
|
103
103
|
|
|
104
104
|
/**
|
|
105
105
|
* Sets whether to indent each path element.
|
|
106
106
|
*/
|
|
107
107
|
indent(indent: boolean): this {
|
|
108
|
-
this
|
|
108
|
+
this._indent = indent;
|
|
109
109
|
return this;
|
|
110
110
|
}
|
|
111
111
|
|
|
@@ -113,7 +113,7 @@ export class FormatPathsOptsBuilder {
|
|
|
113
113
|
* Sets the format for each path element.
|
|
114
114
|
*/
|
|
115
115
|
elementFormat(format: PathElementFormat): this {
|
|
116
|
-
this
|
|
116
|
+
this._elementFormat = format;
|
|
117
117
|
return this;
|
|
118
118
|
}
|
|
119
119
|
|
|
@@ -121,7 +121,7 @@ export class FormatPathsOptsBuilder {
|
|
|
121
121
|
* Sets whether to format only the last element of each path.
|
|
122
122
|
*/
|
|
123
123
|
lastElementOnly(lastElementOnly: boolean): this {
|
|
124
|
-
this
|
|
124
|
+
this._lastElementOnly = lastElementOnly;
|
|
125
125
|
return this;
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -130,9 +130,9 @@ export class FormatPathsOptsBuilder {
|
|
|
130
130
|
*/
|
|
131
131
|
build(): FormatPathsOpts {
|
|
132
132
|
return {
|
|
133
|
-
indent: this
|
|
134
|
-
elementFormat: this
|
|
135
|
-
lastElementOnly: this
|
|
133
|
+
indent: this._indent,
|
|
134
|
+
elementFormat: this._elementFormat,
|
|
135
|
+
lastElementOnly: this._lastElementOnly,
|
|
136
136
|
};
|
|
137
137
|
}
|
|
138
138
|
}
|
package/src/parse/token.ts
CHANGED
|
@@ -183,31 +183,31 @@ function isHexDigit(ch: string): boolean {
|
|
|
183
183
|
* Lexer for Gordian Envelope pattern syntax.
|
|
184
184
|
*/
|
|
185
185
|
export class Lexer {
|
|
186
|
-
readonly
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
186
|
+
private readonly _source: string;
|
|
187
|
+
private _position = 0;
|
|
188
|
+
private _tokenStart = 0;
|
|
189
|
+
private _peekedToken: { token: Token; span: Span } | undefined = undefined;
|
|
190
190
|
|
|
191
191
|
constructor(source: string) {
|
|
192
|
-
this
|
|
192
|
+
this._source = source;
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
/**
|
|
196
196
|
* Gets the current position in the source.
|
|
197
197
|
*/
|
|
198
198
|
get position(): number {
|
|
199
|
-
return this
|
|
199
|
+
return this._position;
|
|
200
200
|
}
|
|
201
201
|
|
|
202
202
|
/**
|
|
203
203
|
* Peeks at the next token without consuming it.
|
|
204
204
|
*/
|
|
205
205
|
peekToken(): { token: Token; span: Span } | undefined {
|
|
206
|
-
if (this
|
|
207
|
-
return this
|
|
206
|
+
if (this._peekedToken !== undefined) {
|
|
207
|
+
return this._peekedToken;
|
|
208
208
|
}
|
|
209
209
|
const result = this.next();
|
|
210
|
-
this
|
|
210
|
+
this._peekedToken = result;
|
|
211
211
|
return result;
|
|
212
212
|
}
|
|
213
213
|
|
|
@@ -215,51 +215,51 @@ export class Lexer {
|
|
|
215
215
|
* Gets the current span (from token start to current position).
|
|
216
216
|
*/
|
|
217
217
|
span(): Span {
|
|
218
|
-
return { start: this
|
|
218
|
+
return { start: this._tokenStart, end: this._position };
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
/**
|
|
222
222
|
* Gets the remaining source string.
|
|
223
223
|
*/
|
|
224
224
|
remainder(): string {
|
|
225
|
-
return this
|
|
225
|
+
return this._source.slice(this._position);
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
/**
|
|
229
229
|
* Peeks at the current character without consuming it.
|
|
230
230
|
*/
|
|
231
231
|
peek(): string | undefined {
|
|
232
|
-
if (this
|
|
232
|
+
if (this._position >= this._source.length) {
|
|
233
233
|
return undefined;
|
|
234
234
|
}
|
|
235
|
-
return this
|
|
235
|
+
return this._source[this._position];
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
/**
|
|
239
239
|
* Peeks at the next character without consuming current.
|
|
240
240
|
*/
|
|
241
241
|
peekNext(): string | undefined {
|
|
242
|
-
if (this
|
|
242
|
+
if (this._position + 1 >= this._source.length) {
|
|
243
243
|
return undefined;
|
|
244
244
|
}
|
|
245
|
-
return this
|
|
245
|
+
return this._source[this._position + 1];
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
/**
|
|
249
249
|
* Advances the position by n characters.
|
|
250
250
|
*/
|
|
251
251
|
bump(n = 1): void {
|
|
252
|
-
this
|
|
252
|
+
this._position = Math.min(this._position + n, this._source.length);
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
/**
|
|
256
256
|
* Skips whitespace.
|
|
257
257
|
*/
|
|
258
|
-
|
|
259
|
-
while (this
|
|
260
|
-
const ch = this
|
|
258
|
+
private _skipWhitespace(): void {
|
|
259
|
+
while (this._position < this._source.length) {
|
|
260
|
+
const ch = this._source[this._position];
|
|
261
261
|
if (ch !== undefined && isWhitespace(ch)) {
|
|
262
|
-
this
|
|
262
|
+
this._position++;
|
|
263
263
|
} else {
|
|
264
264
|
break;
|
|
265
265
|
}
|
|
@@ -269,7 +269,7 @@ export class Lexer {
|
|
|
269
269
|
/**
|
|
270
270
|
* Parses a string literal (after the opening quote).
|
|
271
271
|
*/
|
|
272
|
-
|
|
272
|
+
private _parseStringLiteral(): Result<string> {
|
|
273
273
|
const src = this.remainder();
|
|
274
274
|
let escape = false;
|
|
275
275
|
let content = "";
|
|
@@ -323,7 +323,7 @@ export class Lexer {
|
|
|
323
323
|
/**
|
|
324
324
|
* Parses a regex pattern (after the opening slash).
|
|
325
325
|
*/
|
|
326
|
-
|
|
326
|
+
private _parseRegex(): Result<string> {
|
|
327
327
|
const src = this.remainder();
|
|
328
328
|
let escape = false;
|
|
329
329
|
|
|
@@ -358,7 +358,7 @@ export class Lexer {
|
|
|
358
358
|
/**
|
|
359
359
|
* Parses a hex pattern (after h').
|
|
360
360
|
*/
|
|
361
|
-
|
|
361
|
+
private _parseHexPattern(): Result<Uint8Array> {
|
|
362
362
|
const src = this.remainder();
|
|
363
363
|
|
|
364
364
|
for (let i = 0; i < src.length; i++) {
|
|
@@ -397,7 +397,7 @@ export class Lexer {
|
|
|
397
397
|
/**
|
|
398
398
|
* Parses a hex binary regex (after h'/).
|
|
399
399
|
*/
|
|
400
|
-
|
|
400
|
+
private _parseHexBinaryRegex(): Result<string> {
|
|
401
401
|
const src = this.remainder();
|
|
402
402
|
let escape = false;
|
|
403
403
|
|
|
@@ -436,7 +436,7 @@ export class Lexer {
|
|
|
436
436
|
/**
|
|
437
437
|
* Parses a date pattern (after date').
|
|
438
438
|
*/
|
|
439
|
-
|
|
439
|
+
private _parseDatePattern(): Result<string> {
|
|
440
440
|
const src = this.remainder();
|
|
441
441
|
|
|
442
442
|
for (let i = 0; i < src.length; i++) {
|
|
@@ -455,7 +455,7 @@ export class Lexer {
|
|
|
455
455
|
/**
|
|
456
456
|
* Parses a range pattern (after {).
|
|
457
457
|
*/
|
|
458
|
-
|
|
458
|
+
private _parseRange(): Result<Quantifier> {
|
|
459
459
|
const src = this.remainder();
|
|
460
460
|
let pos = 0;
|
|
461
461
|
|
|
@@ -554,7 +554,7 @@ export class Lexer {
|
|
|
554
554
|
/**
|
|
555
555
|
* Parses a single quoted pattern (after ').
|
|
556
556
|
*/
|
|
557
|
-
|
|
557
|
+
private _parseSingleQuotedPattern(): Result<string> {
|
|
558
558
|
const src = this.remainder();
|
|
559
559
|
|
|
560
560
|
for (let i = 0; i < src.length; i++) {
|
|
@@ -573,7 +573,7 @@ export class Lexer {
|
|
|
573
573
|
/**
|
|
574
574
|
* Parses a single quoted regex (after '/).
|
|
575
575
|
*/
|
|
576
|
-
|
|
576
|
+
private _parseSingleQuotedRegex(): Result<string> {
|
|
577
577
|
const src = this.remainder();
|
|
578
578
|
let escape = false;
|
|
579
579
|
|
|
@@ -612,8 +612,8 @@ export class Lexer {
|
|
|
612
612
|
/**
|
|
613
613
|
* Parses a number (integer or float).
|
|
614
614
|
*/
|
|
615
|
-
|
|
616
|
-
const startPos = this
|
|
615
|
+
private _parseNumber(): Token {
|
|
616
|
+
const startPos = this._position;
|
|
617
617
|
let isFloat = false;
|
|
618
618
|
let isNegative = false;
|
|
619
619
|
|
|
@@ -662,7 +662,7 @@ export class Lexer {
|
|
|
662
662
|
}
|
|
663
663
|
}
|
|
664
664
|
|
|
665
|
-
const numStr = this
|
|
665
|
+
const numStr = this._source.slice(startPos, this._position);
|
|
666
666
|
|
|
667
667
|
if (isFloat) {
|
|
668
668
|
const value = parseFloat(numStr);
|
|
@@ -688,25 +688,25 @@ export class Lexer {
|
|
|
688
688
|
*/
|
|
689
689
|
next(): { token: Token; span: Span } | undefined {
|
|
690
690
|
// Return peeked token if available
|
|
691
|
-
if (this
|
|
692
|
-
const peeked = this
|
|
693
|
-
this
|
|
691
|
+
if (this._peekedToken !== undefined) {
|
|
692
|
+
const peeked = this._peekedToken;
|
|
693
|
+
this._peekedToken = undefined;
|
|
694
694
|
return peeked;
|
|
695
695
|
}
|
|
696
696
|
|
|
697
|
-
this
|
|
698
|
-
this
|
|
697
|
+
this._skipWhitespace();
|
|
698
|
+
this._tokenStart = this._position;
|
|
699
699
|
|
|
700
|
-
if (this
|
|
700
|
+
if (this._position >= this._source.length) {
|
|
701
701
|
return undefined;
|
|
702
702
|
}
|
|
703
703
|
|
|
704
|
-
const ch = this
|
|
704
|
+
const ch = this._source[this._position];
|
|
705
705
|
if (ch === undefined) return undefined;
|
|
706
706
|
|
|
707
707
|
// Check for two-character operators first
|
|
708
|
-
const twoChar = this
|
|
709
|
-
const threeChar = this
|
|
708
|
+
const twoChar = this._source.slice(this._position, this._position + 2);
|
|
709
|
+
const threeChar = this._source.slice(this._position, this._position + 3);
|
|
710
710
|
|
|
711
711
|
// Check for ... (ellipsis)
|
|
712
712
|
if (threeChar === "...") {
|
|
@@ -715,7 +715,7 @@ export class Lexer {
|
|
|
715
715
|
}
|
|
716
716
|
|
|
717
717
|
// Check for -Infinity
|
|
718
|
-
if (this
|
|
718
|
+
if (this._source.slice(this._position, this._position + 9) === "-Infinity") {
|
|
719
719
|
this.bump(9);
|
|
720
720
|
return { token: { type: "NegativeInfinity" }, span: this.span() };
|
|
721
721
|
}
|
|
@@ -755,16 +755,16 @@ export class Lexer {
|
|
|
755
755
|
if (this.peek() === "/") {
|
|
756
756
|
this.bump(1);
|
|
757
757
|
return {
|
|
758
|
-
token: { type: "HexBinaryRegex", value: this
|
|
758
|
+
token: { type: "HexBinaryRegex", value: this._parseHexBinaryRegex() },
|
|
759
759
|
span: this.span(),
|
|
760
760
|
};
|
|
761
761
|
}
|
|
762
|
-
return { token: { type: "HexPattern", value: this
|
|
762
|
+
return { token: { type: "HexPattern", value: this._parseHexPattern() }, span: this.span() };
|
|
763
763
|
}
|
|
764
764
|
case "'/":
|
|
765
765
|
this.bump(2);
|
|
766
766
|
return {
|
|
767
|
-
token: { type: "SingleQuotedRegex", value: this
|
|
767
|
+
token: { type: "SingleQuotedRegex", value: this._parseSingleQuotedRegex() },
|
|
768
768
|
span: this.span(),
|
|
769
769
|
};
|
|
770
770
|
}
|
|
@@ -813,25 +813,25 @@ export class Lexer {
|
|
|
813
813
|
case '"':
|
|
814
814
|
this.bump(1);
|
|
815
815
|
return {
|
|
816
|
-
token: { type: "StringLiteral", value: this
|
|
816
|
+
token: { type: "StringLiteral", value: this._parseStringLiteral() },
|
|
817
817
|
span: this.span(),
|
|
818
818
|
};
|
|
819
819
|
case "/":
|
|
820
820
|
this.bump(1);
|
|
821
|
-
return { token: { type: "Regex", value: this
|
|
821
|
+
return { token: { type: "Regex", value: this._parseRegex() }, span: this.span() };
|
|
822
822
|
case "{":
|
|
823
823
|
this.bump(1);
|
|
824
|
-
return { token: { type: "Range", value: this
|
|
824
|
+
return { token: { type: "Range", value: this._parseRange() }, span: this.span() };
|
|
825
825
|
case "'":
|
|
826
826
|
this.bump(1);
|
|
827
827
|
return {
|
|
828
|
-
token: { type: "SingleQuotedPattern", value: this
|
|
828
|
+
token: { type: "SingleQuotedPattern", value: this._parseSingleQuotedPattern() },
|
|
829
829
|
span: this.span(),
|
|
830
830
|
};
|
|
831
831
|
case "@": {
|
|
832
832
|
// Group name
|
|
833
833
|
this.bump(1);
|
|
834
|
-
const start = this
|
|
834
|
+
const start = this._position;
|
|
835
835
|
let gc = this.peek();
|
|
836
836
|
if (gc !== undefined && isIdentStart(gc)) {
|
|
837
837
|
gc = this.peek();
|
|
@@ -839,7 +839,7 @@ export class Lexer {
|
|
|
839
839
|
this.bump(1);
|
|
840
840
|
gc = this.peek();
|
|
841
841
|
}
|
|
842
|
-
const name = this
|
|
842
|
+
const name = this._source.slice(start, this._position);
|
|
843
843
|
return { token: { type: "GroupName", name }, span: this.span() };
|
|
844
844
|
}
|
|
845
845
|
// Invalid group name, return as error token
|
|
@@ -848,26 +848,26 @@ export class Lexer {
|
|
|
848
848
|
}
|
|
849
849
|
|
|
850
850
|
// Check for date' pattern
|
|
851
|
-
if (this
|
|
851
|
+
if (this._source.slice(this._position, this._position + 5) === "date'") {
|
|
852
852
|
this.bump(5);
|
|
853
|
-
return { token: { type: "DatePattern", value: this
|
|
853
|
+
return { token: { type: "DatePattern", value: this._parseDatePattern() }, span: this.span() };
|
|
854
854
|
}
|
|
855
855
|
|
|
856
856
|
// Check for number (including negative)
|
|
857
857
|
const nextChar = this.peekNext();
|
|
858
858
|
if (isDigit(ch) || (ch === "-" && nextChar !== undefined && isDigit(nextChar))) {
|
|
859
|
-
return { token: this
|
|
859
|
+
return { token: this._parseNumber(), span: this.span() };
|
|
860
860
|
}
|
|
861
861
|
|
|
862
862
|
// Check for identifier/keyword
|
|
863
863
|
if (isIdentStart(ch)) {
|
|
864
|
-
const start = this
|
|
864
|
+
const start = this._position;
|
|
865
865
|
let ic = this.peek();
|
|
866
866
|
while (ic !== undefined && isIdentContinue(ic)) {
|
|
867
867
|
this.bump(1);
|
|
868
868
|
ic = this.peek();
|
|
869
869
|
}
|
|
870
|
-
const ident = this
|
|
870
|
+
const ident = this._source.slice(start, this._position);
|
|
871
871
|
|
|
872
872
|
// Check for keywords
|
|
873
873
|
const keyword = KEYWORDS.get(ident);
|
|
@@ -44,10 +44,10 @@ export type ArrayPatternType =
|
|
|
44
44
|
* Corresponds to the Rust `ArrayPattern` struct in array_pattern.rs
|
|
45
45
|
*/
|
|
46
46
|
export class ArrayPattern implements Matcher {
|
|
47
|
-
readonly
|
|
47
|
+
private readonly _pattern: ArrayPatternType;
|
|
48
48
|
|
|
49
49
|
private constructor(pattern: ArrayPatternType) {
|
|
50
|
-
this
|
|
50
|
+
this._pattern = pattern;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/**
|
|
@@ -93,7 +93,7 @@ export class ArrayPattern implements Matcher {
|
|
|
93
93
|
* Gets the pattern type.
|
|
94
94
|
*/
|
|
95
95
|
get pattern(): ArrayPatternType {
|
|
96
|
-
return this
|
|
96
|
+
return this._pattern;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
|
|
@@ -109,13 +109,13 @@ export class ArrayPattern implements Matcher {
|
|
|
109
109
|
return [[], new Map<string, Path[]>()];
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
switch (this
|
|
112
|
+
switch (this._pattern.type) {
|
|
113
113
|
case "Any":
|
|
114
114
|
return [[[haystack]], new Map<string, Path[]>()];
|
|
115
115
|
|
|
116
116
|
case "Interval": {
|
|
117
117
|
const length = array.length;
|
|
118
|
-
if (this
|
|
118
|
+
if (this._pattern.interval.contains(length)) {
|
|
119
119
|
return [[[haystack]], new Map<string, Path[]>()];
|
|
120
120
|
}
|
|
121
121
|
return [[], new Map<string, Path[]>()];
|
|
@@ -124,7 +124,7 @@ export class ArrayPattern implements Matcher {
|
|
|
124
124
|
case "DCBORPattern": {
|
|
125
125
|
// Delegate to dcbor-pattern for matching
|
|
126
126
|
const { paths: dcborPaths, captures: dcborCaptures } = dcborPatternPathsWithCaptures(
|
|
127
|
-
this
|
|
127
|
+
this._pattern.pattern,
|
|
128
128
|
cbor,
|
|
129
129
|
);
|
|
130
130
|
|
|
@@ -167,7 +167,7 @@ export class ArrayPattern implements Matcher {
|
|
|
167
167
|
case "WithPatterns":
|
|
168
168
|
// For envelope patterns, match if array length equals patterns count
|
|
169
169
|
// Full element-by-element matching would require additional implementation
|
|
170
|
-
if (array.length === this
|
|
170
|
+
if (array.length === this._pattern.patterns.length) {
|
|
171
171
|
return [[[haystack]], new Map<string, Path[]>()];
|
|
172
172
|
}
|
|
173
173
|
return [[], new Map<string, Path[]>()];
|
|
@@ -194,15 +194,15 @@ export class ArrayPattern implements Matcher {
|
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
toString(): string {
|
|
197
|
-
switch (this
|
|
197
|
+
switch (this._pattern.type) {
|
|
198
198
|
case "Any":
|
|
199
199
|
return "[*]";
|
|
200
200
|
case "Interval":
|
|
201
|
-
return `[{${this
|
|
201
|
+
return `[{${this._pattern.interval.toString()}}]`;
|
|
202
202
|
case "DCBORPattern":
|
|
203
|
-
return dcborPatternDisplay(this
|
|
203
|
+
return dcborPatternDisplay(this._pattern.pattern);
|
|
204
204
|
case "WithPatterns":
|
|
205
|
-
return `[${this
|
|
205
|
+
return `[${this._pattern.patterns.map(String).join(", ")}]`;
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
|
|
@@ -210,30 +210,30 @@ export class ArrayPattern implements Matcher {
|
|
|
210
210
|
* Equality comparison.
|
|
211
211
|
*/
|
|
212
212
|
equals(other: ArrayPattern): boolean {
|
|
213
|
-
if (this
|
|
213
|
+
if (this._pattern.type !== other._pattern.type) {
|
|
214
214
|
return false;
|
|
215
215
|
}
|
|
216
|
-
switch (this
|
|
216
|
+
switch (this._pattern.type) {
|
|
217
217
|
case "Any":
|
|
218
218
|
return true;
|
|
219
219
|
case "Interval":
|
|
220
|
-
return this
|
|
221
|
-
(other
|
|
220
|
+
return this._pattern.interval.equals(
|
|
221
|
+
(other._pattern as { type: "Interval"; interval: Interval }).interval,
|
|
222
222
|
);
|
|
223
223
|
case "DCBORPattern":
|
|
224
224
|
// Compare using display representation
|
|
225
225
|
return (
|
|
226
|
-
dcborPatternDisplay(this
|
|
226
|
+
dcborPatternDisplay(this._pattern.pattern) ===
|
|
227
227
|
dcborPatternDisplay(
|
|
228
|
-
(other
|
|
228
|
+
(other._pattern as { type: "DCBORPattern"; pattern: DCBORPattern }).pattern,
|
|
229
229
|
)
|
|
230
230
|
);
|
|
231
231
|
case "WithPatterns": {
|
|
232
|
-
const otherPatterns = (other
|
|
232
|
+
const otherPatterns = (other._pattern as { type: "WithPatterns"; patterns: Pattern[] })
|
|
233
233
|
.patterns;
|
|
234
|
-
if (this
|
|
235
|
-
for (let i = 0; i < this
|
|
236
|
-
if (this
|
|
234
|
+
if (this._pattern.patterns.length !== otherPatterns.length) return false;
|
|
235
|
+
for (let i = 0; i < this._pattern.patterns.length; i++) {
|
|
236
|
+
if (this._pattern.patterns[i] !== otherPatterns[i]) return false;
|
|
237
237
|
}
|
|
238
238
|
return true;
|
|
239
239
|
}
|
|
@@ -244,17 +244,17 @@ export class ArrayPattern implements Matcher {
|
|
|
244
244
|
* Hash code for use in Maps/Sets.
|
|
245
245
|
*/
|
|
246
246
|
hashCode(): number {
|
|
247
|
-
switch (this
|
|
247
|
+
switch (this._pattern.type) {
|
|
248
248
|
case "Any":
|
|
249
249
|
return 0;
|
|
250
250
|
case "Interval":
|
|
251
251
|
// Simple hash based on min/max
|
|
252
|
-
return this
|
|
252
|
+
return this._pattern.interval.min() * 31 + (this._pattern.interval.max() ?? 0);
|
|
253
253
|
case "DCBORPattern":
|
|
254
254
|
// Simple hash based on display string
|
|
255
|
-
return simpleStringHash(dcborPatternDisplay(this
|
|
255
|
+
return simpleStringHash(dcborPatternDisplay(this._pattern.pattern));
|
|
256
256
|
case "WithPatterns":
|
|
257
|
-
return this
|
|
257
|
+
return this._pattern.patterns.length;
|
|
258
258
|
}
|
|
259
259
|
}
|
|
260
260
|
}
|
|
@@ -36,10 +36,10 @@ export function registerBoolPatternFactory(factory: (pattern: BoolPattern) => Pa
|
|
|
36
36
|
* Corresponds to the Rust `BoolPattern` struct in bool_pattern.rs
|
|
37
37
|
*/
|
|
38
38
|
export class BoolPattern implements Matcher {
|
|
39
|
-
readonly
|
|
39
|
+
private readonly _inner: DCBORBoolPattern;
|
|
40
40
|
|
|
41
41
|
private constructor(inner: DCBORBoolPattern) {
|
|
42
|
-
this
|
|
42
|
+
this._inner = inner;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/**
|
|
@@ -67,7 +67,7 @@ export class BoolPattern implements Matcher {
|
|
|
67
67
|
* Gets the underlying dcbor-pattern BoolPattern.
|
|
68
68
|
*/
|
|
69
69
|
get inner(): DCBORBoolPattern {
|
|
70
|
-
return this
|
|
70
|
+
return this._inner;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
|
|
@@ -75,7 +75,7 @@ export class BoolPattern implements Matcher {
|
|
|
75
75
|
const cbor = haystack.asLeaf();
|
|
76
76
|
if (cbor !== undefined) {
|
|
77
77
|
// Delegate to dcbor-pattern for CBOR matching
|
|
78
|
-
const dcborPaths = dcborBoolPatternPaths(this
|
|
78
|
+
const dcborPaths = dcborBoolPatternPaths(this._inner, cbor);
|
|
79
79
|
|
|
80
80
|
// For simple leaf patterns, if dcbor-pattern found matches, return the envelope
|
|
81
81
|
if (dcborPaths.length > 0) {
|
|
@@ -109,7 +109,7 @@ export class BoolPattern implements Matcher {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
toString(): string {
|
|
112
|
-
return boolPatternDisplay(this
|
|
112
|
+
return boolPatternDisplay(this._inner);
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
/**
|
|
@@ -117,11 +117,11 @@ export class BoolPattern implements Matcher {
|
|
|
117
117
|
*/
|
|
118
118
|
equals(other: BoolPattern): boolean {
|
|
119
119
|
// Compare by variant and value
|
|
120
|
-
if (this
|
|
120
|
+
if (this._inner.variant !== other._inner.variant) {
|
|
121
121
|
return false;
|
|
122
122
|
}
|
|
123
|
-
if (this
|
|
124
|
-
return this
|
|
123
|
+
if (this._inner.variant === "Value" && other._inner.variant === "Value") {
|
|
124
|
+
return this._inner.value === other._inner.value;
|
|
125
125
|
}
|
|
126
126
|
return true;
|
|
127
127
|
}
|
|
@@ -131,9 +131,9 @@ export class BoolPattern implements Matcher {
|
|
|
131
131
|
*/
|
|
132
132
|
hashCode(): number {
|
|
133
133
|
// Simple hash based on variant and value
|
|
134
|
-
let hash = this
|
|
135
|
-
if (this
|
|
136
|
-
hash = hash * 31 + (this
|
|
134
|
+
let hash = this._inner.variant === "Any" ? 0 : 1;
|
|
135
|
+
if (this._inner.variant === "Value") {
|
|
136
|
+
hash = hash * 31 + (this._inner.value ? 1 : 0);
|
|
137
137
|
}
|
|
138
138
|
return hash;
|
|
139
139
|
}
|