@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.
Files changed (53) hide show
  1. package/LICENSE +48 -0
  2. package/README.md +13 -0
  3. package/dist/index.cjs +6781 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +2628 -0
  6. package/dist/index.d.cts.map +1 -0
  7. package/dist/index.d.mts +2628 -0
  8. package/dist/index.d.mts.map +1 -0
  9. package/dist/index.iife.js +6781 -0
  10. package/dist/index.iife.js.map +1 -0
  11. package/dist/index.mjs +6545 -0
  12. package/dist/index.mjs.map +1 -0
  13. package/package.json +77 -0
  14. package/src/error.ts +262 -0
  15. package/src/format.ts +375 -0
  16. package/src/index.ts +27 -0
  17. package/src/parse/index.ts +923 -0
  18. package/src/parse/token.ts +906 -0
  19. package/src/parse/utils.ts +339 -0
  20. package/src/pattern/index.ts +719 -0
  21. package/src/pattern/leaf/array-pattern.ts +273 -0
  22. package/src/pattern/leaf/bool-pattern.ts +140 -0
  23. package/src/pattern/leaf/byte-string-pattern.ts +172 -0
  24. package/src/pattern/leaf/cbor-pattern.ts +355 -0
  25. package/src/pattern/leaf/date-pattern.ts +178 -0
  26. package/src/pattern/leaf/index.ts +280 -0
  27. package/src/pattern/leaf/known-value-pattern.ts +192 -0
  28. package/src/pattern/leaf/map-pattern.ts +152 -0
  29. package/src/pattern/leaf/null-pattern.ts +110 -0
  30. package/src/pattern/leaf/number-pattern.ts +248 -0
  31. package/src/pattern/leaf/tagged-pattern.ts +228 -0
  32. package/src/pattern/leaf/text-pattern.ts +165 -0
  33. package/src/pattern/matcher.ts +88 -0
  34. package/src/pattern/meta/and-pattern.ts +109 -0
  35. package/src/pattern/meta/any-pattern.ts +81 -0
  36. package/src/pattern/meta/capture-pattern.ts +111 -0
  37. package/src/pattern/meta/group-pattern.ts +110 -0
  38. package/src/pattern/meta/index.ts +269 -0
  39. package/src/pattern/meta/not-pattern.ts +91 -0
  40. package/src/pattern/meta/or-pattern.ts +146 -0
  41. package/src/pattern/meta/search-pattern.ts +201 -0
  42. package/src/pattern/meta/traverse-pattern.ts +146 -0
  43. package/src/pattern/structure/assertions-pattern.ts +244 -0
  44. package/src/pattern/structure/digest-pattern.ts +225 -0
  45. package/src/pattern/structure/index.ts +272 -0
  46. package/src/pattern/structure/leaf-structure-pattern.ts +85 -0
  47. package/src/pattern/structure/node-pattern.ts +188 -0
  48. package/src/pattern/structure/object-pattern.ts +149 -0
  49. package/src/pattern/structure/obscured-pattern.ts +159 -0
  50. package/src/pattern/structure/predicate-pattern.ts +151 -0
  51. package/src/pattern/structure/subject-pattern.ts +152 -0
  52. package/src/pattern/structure/wrapped-pattern.ts +195 -0
  53. package/src/pattern/vm.ts +1021 -0
@@ -0,0 +1,159 @@
1
+ /**
2
+ * @bcts/envelope-pattern - Obscured pattern matching
3
+ *
4
+ * This is a 1:1 TypeScript port of bc-envelope-pattern-rust obscured_pattern.rs
5
+ *
6
+ * @module envelope-pattern/pattern/structure/obscured-pattern
7
+ */
8
+
9
+ import type { Envelope } from "@bcts/envelope";
10
+ import type { Path } from "../../format";
11
+ import type { Matcher } from "../matcher";
12
+ import { compileAsAtomic } from "../matcher";
13
+ import type { Instr } from "../vm";
14
+ import type { Pattern } from "../index";
15
+
16
+ // Forward declaration for Pattern factory
17
+ let createStructureObscuredPattern: ((pattern: ObscuredPattern) => Pattern) | undefined;
18
+
19
+ export function registerObscuredPatternFactory(
20
+ factory: (pattern: ObscuredPattern) => Pattern,
21
+ ): void {
22
+ createStructureObscuredPattern = factory;
23
+ }
24
+
25
+ /**
26
+ * Pattern type for obscured pattern matching.
27
+ *
28
+ * Corresponds to the Rust `ObscuredPattern` enum in obscured_pattern.rs
29
+ */
30
+ export type ObscuredPatternType =
31
+ | { readonly type: "Any" }
32
+ | { readonly type: "Elided" }
33
+ | { readonly type: "Encrypted" }
34
+ | { readonly type: "Compressed" };
35
+
36
+ /**
37
+ * Pattern for matching obscured elements.
38
+ *
39
+ * Corresponds to the Rust `ObscuredPattern` enum in obscured_pattern.rs
40
+ */
41
+ export class ObscuredPattern implements Matcher {
42
+ readonly #pattern: ObscuredPatternType;
43
+
44
+ private constructor(pattern: ObscuredPatternType) {
45
+ this.#pattern = pattern;
46
+ }
47
+
48
+ /**
49
+ * Creates a new ObscuredPattern that matches any obscured element.
50
+ */
51
+ static any(): ObscuredPattern {
52
+ return new ObscuredPattern({ type: "Any" });
53
+ }
54
+
55
+ /**
56
+ * Creates a new ObscuredPattern that matches any elided element.
57
+ */
58
+ static elided(): ObscuredPattern {
59
+ return new ObscuredPattern({ type: "Elided" });
60
+ }
61
+
62
+ /**
63
+ * Creates a new ObscuredPattern that matches any encrypted element.
64
+ */
65
+ static encrypted(): ObscuredPattern {
66
+ return new ObscuredPattern({ type: "Encrypted" });
67
+ }
68
+
69
+ /**
70
+ * Creates a new ObscuredPattern that matches any compressed element.
71
+ */
72
+ static compressed(): ObscuredPattern {
73
+ return new ObscuredPattern({ type: "Compressed" });
74
+ }
75
+
76
+ /**
77
+ * Gets the pattern type.
78
+ */
79
+ get patternType(): ObscuredPatternType {
80
+ return this.#pattern;
81
+ }
82
+
83
+ pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
84
+ let isHit = false;
85
+
86
+ switch (this.#pattern.type) {
87
+ case "Any":
88
+ isHit = haystack.isObscured();
89
+ break;
90
+ case "Elided":
91
+ isHit = haystack.isElided();
92
+ break;
93
+ case "Encrypted":
94
+ isHit = haystack.isEncrypted();
95
+ break;
96
+ case "Compressed":
97
+ isHit = haystack.isCompressed();
98
+ break;
99
+ }
100
+
101
+ const paths = isHit ? [[haystack]] : [];
102
+ return [paths, new Map<string, Path[]>()];
103
+ }
104
+
105
+ paths(haystack: Envelope): Path[] {
106
+ return this.pathsWithCaptures(haystack)[0];
107
+ }
108
+
109
+ matches(haystack: Envelope): boolean {
110
+ return this.paths(haystack).length > 0;
111
+ }
112
+
113
+ compile(code: Instr[], literals: Pattern[], captures: string[]): void {
114
+ if (createStructureObscuredPattern === undefined) {
115
+ throw new Error("ObscuredPattern factory not registered");
116
+ }
117
+ compileAsAtomic(createStructureObscuredPattern(this), code, literals, captures);
118
+ }
119
+
120
+ isComplex(): boolean {
121
+ return false;
122
+ }
123
+
124
+ toString(): string {
125
+ switch (this.#pattern.type) {
126
+ case "Any":
127
+ return "obscured";
128
+ case "Elided":
129
+ return "elided";
130
+ case "Encrypted":
131
+ return "encrypted";
132
+ case "Compressed":
133
+ return "compressed";
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Equality comparison.
139
+ */
140
+ equals(other: ObscuredPattern): boolean {
141
+ return this.#pattern.type === other.#pattern.type;
142
+ }
143
+
144
+ /**
145
+ * Hash code for use in Maps/Sets.
146
+ */
147
+ hashCode(): number {
148
+ switch (this.#pattern.type) {
149
+ case "Any":
150
+ return 0;
151
+ case "Elided":
152
+ return 1;
153
+ case "Encrypted":
154
+ return 2;
155
+ case "Compressed":
156
+ return 3;
157
+ }
158
+ }
159
+ }
@@ -0,0 +1,151 @@
1
+ /**
2
+ * @bcts/envelope-pattern - Predicate pattern matching
3
+ *
4
+ * This is a 1:1 TypeScript port of bc-envelope-pattern-rust predicate_pattern.rs
5
+ *
6
+ * @module envelope-pattern/pattern/structure/predicate-pattern
7
+ */
8
+
9
+ import type { Envelope } from "@bcts/envelope";
10
+ import type { Path } from "../../format";
11
+ import type { Matcher } from "../matcher";
12
+ import type { Instr } from "../vm";
13
+ import type { Pattern } from "../index";
14
+
15
+ // Forward declaration for Pattern factory
16
+ let createStructurePredicatePattern: ((pattern: PredicatePattern) => Pattern) | undefined;
17
+
18
+ export function registerPredicatePatternFactory(
19
+ factory: (pattern: PredicatePattern) => Pattern,
20
+ ): void {
21
+ createStructurePredicatePattern = factory;
22
+ }
23
+
24
+ /**
25
+ * Pattern type for predicate pattern matching.
26
+ *
27
+ * Corresponds to the Rust `PredicatePattern` enum in predicate_pattern.rs
28
+ */
29
+ export type PredicatePatternType =
30
+ | { readonly type: "Any" }
31
+ | { readonly type: "Pattern"; readonly pattern: Pattern };
32
+
33
+ /**
34
+ * Pattern for matching predicates in envelopes.
35
+ *
36
+ * Corresponds to the Rust `PredicatePattern` enum in predicate_pattern.rs
37
+ */
38
+ export class PredicatePattern implements Matcher {
39
+ readonly #pattern: PredicatePatternType;
40
+
41
+ private constructor(pattern: PredicatePatternType) {
42
+ this.#pattern = pattern;
43
+ }
44
+
45
+ /**
46
+ * Creates a new PredicatePattern that matches any predicate.
47
+ */
48
+ static any(): PredicatePattern {
49
+ return new PredicatePattern({ type: "Any" });
50
+ }
51
+
52
+ /**
53
+ * Creates a new PredicatePattern that matches predicates matching the given pattern.
54
+ */
55
+ static pattern(pattern: Pattern): PredicatePattern {
56
+ return new PredicatePattern({ type: "Pattern", pattern });
57
+ }
58
+
59
+ /**
60
+ * Gets the pattern type.
61
+ */
62
+ get patternType(): PredicatePatternType {
63
+ return this.#pattern;
64
+ }
65
+
66
+ /**
67
+ * Gets the inner pattern if this is a Pattern type, undefined otherwise.
68
+ */
69
+ innerPattern(): Pattern | undefined {
70
+ return this.#pattern.type === "Pattern" ? this.#pattern.pattern : undefined;
71
+ }
72
+
73
+ pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
74
+ const predicate = haystack.asPredicate?.();
75
+
76
+ if (predicate === undefined) {
77
+ return [[], new Map<string, Path[]>()];
78
+ }
79
+
80
+ let paths: Path[];
81
+
82
+ switch (this.#pattern.type) {
83
+ case "Any":
84
+ paths = [[predicate]];
85
+ break;
86
+ case "Pattern": {
87
+ const innerMatcher = this.#pattern.pattern as unknown as Matcher;
88
+ if (innerMatcher.matches(predicate)) {
89
+ paths = [[predicate]];
90
+ } else {
91
+ paths = [];
92
+ }
93
+ break;
94
+ }
95
+ }
96
+
97
+ return [paths, new Map<string, Path[]>()];
98
+ }
99
+
100
+ paths(haystack: Envelope): Path[] {
101
+ return this.pathsWithCaptures(haystack)[0];
102
+ }
103
+
104
+ matches(haystack: Envelope): boolean {
105
+ return this.paths(haystack).length > 0;
106
+ }
107
+
108
+ compile(code: Instr[], literals: Pattern[], _captures: string[]): void {
109
+ if (createStructurePredicatePattern === undefined) {
110
+ throw new Error("PredicatePattern factory not registered");
111
+ }
112
+ const idx = literals.length;
113
+ literals.push(createStructurePredicatePattern(this));
114
+ code.push({ type: "MatchStructure", literalIndex: idx });
115
+ }
116
+
117
+ isComplex(): boolean {
118
+ return false;
119
+ }
120
+
121
+ toString(): string {
122
+ switch (this.#pattern.type) {
123
+ case "Any":
124
+ return "pred";
125
+ case "Pattern":
126
+ return `pred(${(this.#pattern.pattern as unknown as { toString(): string }).toString()})`;
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Equality comparison.
132
+ */
133
+ equals(other: PredicatePattern): boolean {
134
+ if (this.#pattern.type !== other.#pattern.type) {
135
+ return false;
136
+ }
137
+ if (this.#pattern.type === "Any") {
138
+ return true;
139
+ }
140
+ const thisPattern = (this.#pattern as { type: "Pattern"; pattern: Pattern }).pattern;
141
+ const otherPattern = (other.#pattern as { type: "Pattern"; pattern: Pattern }).pattern;
142
+ return thisPattern === otherPattern;
143
+ }
144
+
145
+ /**
146
+ * Hash code for use in Maps/Sets.
147
+ */
148
+ hashCode(): number {
149
+ return this.#pattern.type === "Any" ? 0 : 1;
150
+ }
151
+ }
@@ -0,0 +1,152 @@
1
+ /**
2
+ * @bcts/envelope-pattern - Subject pattern matching
3
+ *
4
+ * This is a 1:1 TypeScript port of bc-envelope-pattern-rust subject_pattern.rs
5
+ *
6
+ * @module envelope-pattern/pattern/structure/subject-pattern
7
+ */
8
+
9
+ import type { Envelope } from "@bcts/envelope";
10
+ import type { Path } from "../../format";
11
+ import type { Matcher } from "../matcher";
12
+ import type { Instr } from "../vm";
13
+ import type { Pattern } from "../index";
14
+
15
+ // Forward declaration for Pattern factory (used for late binding)
16
+ export let createStructureSubjectPattern: ((pattern: SubjectPattern) => Pattern) | undefined;
17
+
18
+ export function registerSubjectPatternFactory(factory: (pattern: SubjectPattern) => Pattern): void {
19
+ createStructureSubjectPattern = factory;
20
+ }
21
+
22
+ /**
23
+ * Pattern type for subject pattern matching.
24
+ *
25
+ * Corresponds to the Rust `SubjectPattern` enum in subject_pattern.rs
26
+ */
27
+ export type SubjectPatternType =
28
+ | { readonly type: "Any" }
29
+ | { readonly type: "Pattern"; readonly pattern: Pattern };
30
+
31
+ /**
32
+ * Pattern for matching subjects in envelopes.
33
+ *
34
+ * Corresponds to the Rust `SubjectPattern` enum in subject_pattern.rs
35
+ */
36
+ export class SubjectPattern implements Matcher {
37
+ readonly #pattern: SubjectPatternType;
38
+
39
+ private constructor(pattern: SubjectPatternType) {
40
+ this.#pattern = pattern;
41
+ }
42
+
43
+ /**
44
+ * Creates a new SubjectPattern that matches any subject.
45
+ */
46
+ static any(): SubjectPattern {
47
+ return new SubjectPattern({ type: "Any" });
48
+ }
49
+
50
+ /**
51
+ * Creates a new SubjectPattern that matches subjects matching the given pattern.
52
+ */
53
+ static pattern(pattern: Pattern): SubjectPattern {
54
+ return new SubjectPattern({ type: "Pattern", pattern });
55
+ }
56
+
57
+ /**
58
+ * Gets the pattern type.
59
+ */
60
+ get patternType(): SubjectPatternType {
61
+ return this.#pattern;
62
+ }
63
+
64
+ /**
65
+ * Gets the inner pattern if this is a Pattern type, undefined otherwise.
66
+ */
67
+ innerPattern(): Pattern | undefined {
68
+ return this.#pattern.type === "Pattern" ? this.#pattern.pattern : undefined;
69
+ }
70
+
71
+ pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
72
+ const subject = haystack.subject();
73
+ let paths: Path[];
74
+
75
+ switch (this.#pattern.type) {
76
+ case "Any":
77
+ paths = [[subject]];
78
+ break;
79
+ case "Pattern": {
80
+ const innerMatcher = this.#pattern.pattern as unknown as Matcher;
81
+ if (innerMatcher.matches(subject)) {
82
+ paths = [[subject]];
83
+ } else {
84
+ paths = [];
85
+ }
86
+ break;
87
+ }
88
+ }
89
+
90
+ return [paths, new Map<string, Path[]>()];
91
+ }
92
+
93
+ paths(haystack: Envelope): Path[] {
94
+ return this.pathsWithCaptures(haystack)[0];
95
+ }
96
+
97
+ matches(haystack: Envelope): boolean {
98
+ return this.paths(haystack).length > 0;
99
+ }
100
+
101
+ compile(code: Instr[], literals: Pattern[], captures: string[]): void {
102
+ switch (this.#pattern.type) {
103
+ case "Any":
104
+ code.push({ type: "NavigateSubject" });
105
+ break;
106
+ case "Pattern":
107
+ // Navigate to the subject first
108
+ code.push({ type: "NavigateSubject" });
109
+ // Save the path and run the inner pattern relative to the subject
110
+ code.push({ type: "ExtendTraversal" });
111
+ (this.#pattern.pattern as unknown as Matcher).compile(code, literals, captures);
112
+ code.push({ type: "CombineTraversal" });
113
+ break;
114
+ }
115
+ }
116
+
117
+ isComplex(): boolean {
118
+ return false;
119
+ }
120
+
121
+ toString(): string {
122
+ switch (this.#pattern.type) {
123
+ case "Any":
124
+ return "subj";
125
+ case "Pattern":
126
+ return `subj(${(this.#pattern.pattern as unknown as { toString(): string }).toString()})`;
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Equality comparison.
132
+ */
133
+ equals(other: SubjectPattern): boolean {
134
+ if (this.#pattern.type !== other.#pattern.type) {
135
+ return false;
136
+ }
137
+ if (this.#pattern.type === "Any") {
138
+ return true;
139
+ }
140
+ // For Pattern type, compare the inner patterns
141
+ const thisPattern = (this.#pattern as { type: "Pattern"; pattern: Pattern }).pattern;
142
+ const otherPattern = (other.#pattern as { type: "Pattern"; pattern: Pattern }).pattern;
143
+ return thisPattern === otherPattern; // Reference equality for now
144
+ }
145
+
146
+ /**
147
+ * Hash code for use in Maps/Sets.
148
+ */
149
+ hashCode(): number {
150
+ return this.#pattern.type === "Any" ? 0 : 1;
151
+ }
152
+ }
@@ -0,0 +1,195 @@
1
+ /**
2
+ * @bcts/envelope-pattern - Wrapped pattern matching
3
+ *
4
+ * This is a 1:1 TypeScript port of bc-envelope-pattern-rust wrapped_pattern.rs
5
+ *
6
+ * @module envelope-pattern/pattern/structure/wrapped-pattern
7
+ */
8
+
9
+ import type { Envelope } from "@bcts/envelope";
10
+ import type { Path } from "../../format";
11
+ import type { Matcher } from "../matcher";
12
+ import type { Instr, Axis } from "../vm";
13
+ import type { Pattern } from "../index";
14
+
15
+ // Forward declaration for Pattern factory
16
+ let createStructureWrappedPattern: ((pattern: WrappedPattern) => Pattern) | undefined;
17
+
18
+ export function registerWrappedPatternFactory(factory: (pattern: WrappedPattern) => Pattern): void {
19
+ createStructureWrappedPattern = factory;
20
+ }
21
+
22
+ /**
23
+ * Pattern type for wrapped pattern matching.
24
+ *
25
+ * Corresponds to the Rust `WrappedPattern` enum in wrapped_pattern.rs
26
+ */
27
+ export type WrappedPatternType =
28
+ | { readonly type: "Any" }
29
+ | { readonly type: "Unwrap"; readonly pattern: Pattern };
30
+
31
+ /**
32
+ * Represents patterns for matching wrapped envelopes.
33
+ *
34
+ * Corresponds to the Rust `WrappedPattern` enum in wrapped_pattern.rs
35
+ */
36
+ export class WrappedPattern implements Matcher {
37
+ readonly #pattern: WrappedPatternType;
38
+
39
+ private constructor(pattern: WrappedPatternType) {
40
+ this.#pattern = pattern;
41
+ }
42
+
43
+ /**
44
+ * Creates a new WrappedPattern that matches any wrapped envelope without descending.
45
+ */
46
+ static new(): WrappedPattern {
47
+ return new WrappedPattern({ type: "Any" });
48
+ }
49
+
50
+ /**
51
+ * Creates a new WrappedPattern that matches a wrapped envelope and also matches
52
+ * on its unwrapped content.
53
+ */
54
+ static unwrapMatching(pattern: Pattern): WrappedPattern {
55
+ return new WrappedPattern({ type: "Unwrap", pattern });
56
+ }
57
+
58
+ /**
59
+ * Creates a new WrappedPattern that matches any wrapped envelope and descends into it.
60
+ * Note: This requires Pattern.any() to be available, so it's set up during registration.
61
+ */
62
+ static unwrap(): WrappedPattern {
63
+ // This will be filled in when Pattern.any() is available
64
+ // For now, create a placeholder that will be replaced
65
+ return new WrappedPattern({ type: "Any" }); // Will be overwritten
66
+ }
67
+
68
+ /**
69
+ * Gets the pattern type.
70
+ */
71
+ get patternType(): WrappedPatternType {
72
+ return this.#pattern;
73
+ }
74
+
75
+ /**
76
+ * Gets the inner pattern if this is an Unwrap type, undefined otherwise.
77
+ */
78
+ innerPattern(): Pattern | undefined {
79
+ return this.#pattern.type === "Unwrap" ? this.#pattern.pattern : undefined;
80
+ }
81
+
82
+ pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
83
+ const subject = haystack.subject();
84
+
85
+ if (!subject.isWrapped()) {
86
+ return [[], new Map<string, Path[]>()];
87
+ }
88
+
89
+ let paths: Path[];
90
+
91
+ switch (this.#pattern.type) {
92
+ case "Any":
93
+ // Just match the wrapped envelope itself, don't descend
94
+ paths = [[haystack]];
95
+ break;
96
+ case "Unwrap": {
97
+ // Match the content of the wrapped envelope
98
+ const unwrapped = subject.tryUnwrap?.();
99
+ if (unwrapped !== undefined) {
100
+ const innerMatcher = this.#pattern.pattern as unknown as Matcher;
101
+ const innerPaths = innerMatcher.paths(unwrapped);
102
+ paths = innerPaths.map((path) => {
103
+ // Add the current envelope to the path
104
+ return [haystack, ...path];
105
+ });
106
+ } else {
107
+ paths = [];
108
+ }
109
+ break;
110
+ }
111
+ }
112
+
113
+ return [paths, new Map<string, Path[]>()];
114
+ }
115
+
116
+ paths(haystack: Envelope): Path[] {
117
+ return this.pathsWithCaptures(haystack)[0];
118
+ }
119
+
120
+ matches(haystack: Envelope): boolean {
121
+ return this.paths(haystack).length > 0;
122
+ }
123
+
124
+ compile(code: Instr[], literals: Pattern[], captures: string[]): void {
125
+ if (createStructureWrappedPattern === undefined) {
126
+ throw new Error("WrappedPattern factory not registered");
127
+ }
128
+
129
+ switch (this.#pattern.type) {
130
+ case "Any": {
131
+ // Just match the wrapped envelope itself, don't descend
132
+ const idx = literals.length;
133
+ literals.push(createStructureWrappedPattern(this));
134
+ code.push({ type: "MatchStructure", literalIndex: idx });
135
+ break;
136
+ }
137
+ case "Unwrap": {
138
+ // First match that it's wrapped
139
+ const idx = literals.length;
140
+ literals.push(createStructureWrappedPattern(WrappedPattern.new()));
141
+ code.push({ type: "MatchStructure", literalIndex: idx });
142
+
143
+ // Then move into inner envelope
144
+ const axis: Axis = "Wrapped";
145
+ code.push({ type: "PushAxis", axis });
146
+
147
+ // Then match the pattern
148
+ const innerMatcher = this.#pattern.pattern as unknown as Matcher;
149
+ innerMatcher.compile(code, literals, captures);
150
+ break;
151
+ }
152
+ }
153
+ }
154
+
155
+ isComplex(): boolean {
156
+ return false;
157
+ }
158
+
159
+ toString(): string {
160
+ switch (this.#pattern.type) {
161
+ case "Any":
162
+ return "wrapped";
163
+ case "Unwrap": {
164
+ // Check if it's the "any" pattern by string comparison
165
+ const patternStr = (this.#pattern.pattern as unknown as { toString(): string }).toString();
166
+ if (patternStr === "*") {
167
+ return "unwrap";
168
+ }
169
+ return `unwrap(${patternStr})`;
170
+ }
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Equality comparison.
176
+ */
177
+ equals(other: WrappedPattern): boolean {
178
+ if (this.#pattern.type !== other.#pattern.type) {
179
+ return false;
180
+ }
181
+ if (this.#pattern.type === "Any") {
182
+ return true;
183
+ }
184
+ const thisPattern = (this.#pattern as { type: "Unwrap"; pattern: Pattern }).pattern;
185
+ const otherPattern = (other.#pattern as { type: "Unwrap"; pattern: Pattern }).pattern;
186
+ return thisPattern === otherPattern;
187
+ }
188
+
189
+ /**
190
+ * Hash code for use in Maps/Sets.
191
+ */
192
+ hashCode(): number {
193
+ return this.#pattern.type === "Any" ? 0 : 1;
194
+ }
195
+ }